mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 00:01:50 +00:00
Named parameter work.
This commit is contained in:
parent
f0d64921df
commit
ddf915e607
@ -75,16 +75,14 @@ Formatter& operator<<(Formatter &f, ICodeModule &i)
|
||||
|
||||
ICodeGenerator::ICodeGenerator(Context *cx, JSClass *aClass, ICodeGeneratorFlags flags)
|
||||
: mTopRegister(0),
|
||||
mParameterCount(0),
|
||||
mExceptionRegister(TypedRegister(NotARegister, &None_Type)),
|
||||
variableList(new VariableList()),
|
||||
parameterList(new ParameterList()),
|
||||
mContext(cx),
|
||||
mInstructionMap(new InstructionMap()),
|
||||
mClass(aClass),
|
||||
mFlags(flags),
|
||||
pLabels(NULL),
|
||||
mHasRestParameter(false),
|
||||
mHasNamedRestParameter(false),
|
||||
mInitName(cx->getWorld().identifiers["__init__"])
|
||||
{
|
||||
iCode = new InstructionStream();
|
||||
@ -106,7 +104,7 @@ JSType *ICodeGenerator::findType(const StringAtom& typeName)
|
||||
-Theoretically, mPermanentRegister[n] can be become false when a scope ends and
|
||||
the registers allocated to contained variables are then available for re-use.
|
||||
-Mostly the need is to handle overlapping allocation of temps & permanents as the
|
||||
variables declarations are encountered. This wouldn't be necessary if a function
|
||||
variables' declarations are encountered. This wouldn't be necessary if a function
|
||||
presented a list of all variables, or a pre-pass executed to discover same.
|
||||
*/
|
||||
TypedRegister ICodeGenerator::allocateRegister(const StringAtom& name, JSType *type)
|
||||
@ -122,27 +120,11 @@ TypedRegister ICodeGenerator::allocateRegister(const StringAtom& name, JSType *t
|
||||
mPermanentRegister[r] = true;
|
||||
|
||||
TypedRegister result(r, type);
|
||||
variableList->add(name, result);
|
||||
mTopRegister = ++r;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
TypedRegister ICodeGenerator::allocateVariable(const StringAtom& name, const StringAtom& typeName)
|
||||
{
|
||||
return allocateRegister(name, findType(typeName));
|
||||
}
|
||||
|
||||
TypedRegister ICodeGenerator::allocateVariable(const StringAtom& name)
|
||||
{
|
||||
return allocateRegister(name, &Any_Type);
|
||||
}
|
||||
|
||||
TypedRegister ICodeGenerator::allocateVariable(const StringAtom& name, JSType *type)
|
||||
{
|
||||
return allocateRegister(name, type);
|
||||
}
|
||||
|
||||
ICodeModule *ICodeGenerator::complete(JSType *resultType)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
@ -188,16 +170,13 @@ ICodeModule *ICodeGenerator::complete(JSType *resultType)
|
||||
*/
|
||||
ICodeModule* module = new ICodeModule(iCode,
|
||||
variableList,
|
||||
parameterList,
|
||||
mPermanentRegister.size(),
|
||||
mParameterCount,
|
||||
mInstructionMap,
|
||||
mHasRestParameter,
|
||||
mHasNamedRestParameter,
|
||||
resultType);
|
||||
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;
|
||||
@ -742,6 +721,8 @@ ICodeGenerator::LValueKind ICodeGenerator::resolveIdentifier(const StringAtom &n
|
||||
{
|
||||
if (!isWithinWith()) {
|
||||
v = variableList->findVariable(name);
|
||||
if (v.first == NotARegister)
|
||||
v = parameterList->findVariable(name);
|
||||
if (v.first != NotARegister)
|
||||
return Var;
|
||||
else {
|
||||
@ -1218,12 +1199,11 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
|
||||
if (p->field && (p->field->getKind() == ExprNode::string))
|
||||
args->push_back(Argument(genExpr(p->value), &mContext->getWorld().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), &mContext->getWorld().identifiers[s] ));
|
||||
s.clear();
|
||||
*/
|
||||
args->push_back(Argument(genExpr(p->value), NULL ));
|
||||
|
||||
// args->push_back(Argument(genExpr(p->value), NULL ));
|
||||
}
|
||||
count++;
|
||||
p = p->next;
|
||||
@ -1561,15 +1541,16 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
|
||||
}
|
||||
break;
|
||||
|
||||
case ExprNode::functionLiteral:
|
||||
case ExprNode::functionLiteral: // XXX FIXME!! This needs to handled by calling genFunction !!!
|
||||
// - the parameter handling is all wrong
|
||||
{
|
||||
FunctionExprNode *f = static_cast<FunctionExprNode *>(p);
|
||||
ICodeGenerator icg(mContext);
|
||||
icg.allocateParameter(mContext->getWorld().identifiers["this"]); // always parameter #0
|
||||
icg.allocateParameter(mContext->getWorld().identifiers["this"], false); // 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);
|
||||
icg.allocateParameter((static_cast<IdentifierExprNode *>(v->name))->name, false, &Any_Type);
|
||||
v = v->next;
|
||||
}
|
||||
icg.genStmt(f->function.body);
|
||||
@ -1649,21 +1630,54 @@ ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor
|
||||
ICodeGeneratorFlags flags = (isStatic) ? kIsStaticMethod : kNoFlags;
|
||||
|
||||
ICodeGenerator icg(mContext, mClass, flags);
|
||||
icg.allocateParameter(mContext->getWorld().identifiers["this"], (mClass) ? mClass : &Any_Type); // always parameter #0
|
||||
icg.allocateParameter(mContext->getWorld().identifiers["this"], false, (mClass) ? mClass : &Any_Type); // always parameter #0
|
||||
VariableBinding *v = f->function.parameters;
|
||||
bool unnamed = true;
|
||||
uint32 positionalCount = 0;
|
||||
StringFormatter s;
|
||||
while (v) {
|
||||
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);
|
||||
if (unnamed && (v == f->function.namedParameters)) { // Track when we hit the first named parameter.
|
||||
icg.parameterList->setPositionalCount(positionalCount);
|
||||
unnamed = false;
|
||||
}
|
||||
positionalCount++;
|
||||
|
||||
// The rest parameter is ignored in this processing - we push it to the end of the list.
|
||||
// But we need to track whether it comes before or after the |
|
||||
if (v == f->function.restParameter) {
|
||||
icg.parameterList->setRestParameter( (unnamed) ? ParameterList::HasRestParameterBeforeBar : ParameterList::HasRestParameterAfterBar );
|
||||
}
|
||||
else {
|
||||
if (v->name && (v->name->getKind() == ExprNode::identifier)) {
|
||||
JSType *pType = extractType(v->type);
|
||||
TypedRegister r = icg.allocateParameter((static_cast<IdentifierExprNode *>(v->name))->name, (v->initializer != NULL), pType);
|
||||
IdentifierList *a = v->aliases;
|
||||
while (a) {
|
||||
icg.parameterList->add(a->name, r, (v->initializer != NULL));
|
||||
a = a->next;
|
||||
}
|
||||
// every unnamed parameter is also named with it's positional name
|
||||
if (unnamed) {
|
||||
s << r.first - 1; // the first positional parameter is '0'
|
||||
icg.parameterList->add(mContext->getWorld().identifiers[s], r, (v->initializer != NULL));
|
||||
s.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
NOT_REACHED("qualified or un-named parameters not handled; bugger off.");
|
||||
v = v->next;
|
||||
}
|
||||
|
||||
// now allocate the rest parameter
|
||||
if (f->function.restParameter) {
|
||||
v = f->function.restParameter;
|
||||
JSType *pType = (v->type == NULL) ? &Array_Type : extractType(v->type);
|
||||
if (v->name && (v->name->getKind() == ExprNode::identifier))
|
||||
icg.allocateParameter((static_cast<IdentifierExprNode *>(v->name))->name, (v->initializer != NULL), pType);
|
||||
else
|
||||
icg.parameterList->setRestParameter(ParameterList::HasUnnamedRestParameter);
|
||||
}
|
||||
|
||||
// generate the code for optional initializers
|
||||
v = f->function.optParameters;
|
||||
if (v) {
|
||||
while (v) { // include the rest parameter, as it may have an initializer
|
||||
@ -1689,13 +1703,7 @@ ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor
|
||||
}
|
||||
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
|
||||
@ -1851,7 +1859,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||
// constructor code generator. Slot variable
|
||||
// initializers get added to this function.
|
||||
ccg = new ICodeGenerator(classContext, thisClass, kNoFlags);
|
||||
ccg->allocateParameter(mContext->getWorld().identifiers["this"], thisClass); // always parameter #0
|
||||
ccg->allocateParameter(mContext->getWorld().identifiers["this"], false, thisClass); // always parameter #0
|
||||
}
|
||||
|
||||
ICodeGenerator scg(classContext, thisClass, kIsStaticMethod); // static initializer code generator.
|
||||
@ -1939,7 +1947,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||
TypedRegister thisValue = TypedRegister(0, thisClass);
|
||||
ArgumentList *args = new ArgumentList();
|
||||
ICodeGenerator icg(classContext, thisClass, kIsStaticMethod);
|
||||
icg.allocateParameter(mContext->getWorld().identifiers["this"], thisClass); // always parameter #0
|
||||
icg.allocateParameter(mContext->getWorld().identifiers["this"], false, thisClass); // always parameter #0
|
||||
if (superclass)
|
||||
icg.call(icg.getStatic(superclass, superclass->getName()), thisValue, args);
|
||||
if (thisClass->hasStatic(mInitName))
|
||||
@ -2325,7 +2333,6 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||
// Bind the incoming exception ...
|
||||
if (mExceptionRegister.first == NotABanana)
|
||||
mExceptionRegister = allocateRegister(mContext->getWorld().identifiers["__exceptionObject__"], &Any_Type);
|
||||
variableList->setRegisterForVariable(c->name, mExceptionRegister);
|
||||
|
||||
genStmt(c->stmt);
|
||||
if (finallyLabel)
|
||||
@ -2419,7 +2426,7 @@ void ICodeGenerator::readICode(const char *fileName)
|
||||
Context *classContext = new Context(mContext->getWorld(), thisScope);
|
||||
ICodeGenerator scg(classContext, thisClass, kIsStaticMethod);
|
||||
ICodeGenerator ccg(classContext, thisClass, kNoFlags);
|
||||
ccg.allocateParameter(mContext->getWorld().identifiers["this"], thisClass);
|
||||
ccg.allocateParameter(mContext->getWorld().identifiers["this"], false, thisClass);
|
||||
thisClass->defineStatic(mInitName, &Function_Type);
|
||||
|
||||
mContext->getGlobalObject()->defineVariable(className, &Type_Type, JSValue(thisClass));
|
||||
@ -2433,8 +2440,8 @@ void ICodeGenerator::readICode(const char *fileName)
|
||||
String methodName, resultTypeName;
|
||||
element->getValue(widenCString("name"), methodName);
|
||||
element->getValue(widenCString("type"), resultTypeName);
|
||||
VariableList *theVariableList = new VariableList();
|
||||
theVariableList->add(mContext->getWorld().identifiers["this"], TypedRegister(0, thisClass));
|
||||
ParameterList *theParameterList = new ParameterList();
|
||||
theParameterList->add(mContext->getWorld().identifiers["this"], TypedRegister(0, thisClass), false);
|
||||
uint32 pCount = 1;
|
||||
XMLNodeList ¶meters = element->children();
|
||||
for (XMLNodeList::const_iterator k = parameters.begin(); k != parameters.end(); k++) {
|
||||
@ -2445,7 +2452,7 @@ void ICodeGenerator::readICode(const char *fileName)
|
||||
element->getValue(widenCString("name"), parameterName);
|
||||
element->getValue(widenCString("type"), parameterTypeName);
|
||||
JSType *parameterType = findType(mContext->getWorld().identifiers[parameterTypeName]);
|
||||
theVariableList->add(mContext->getWorld().identifiers[parameterName], TypedRegister(pCount++, parameterType));
|
||||
theParameterList->add(mContext->getWorld().identifiers[parameterName], TypedRegister(pCount++, parameterType), false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2461,12 +2468,10 @@ void ICodeGenerator::readICode(const char *fileName)
|
||||
icp.ParseSourceFromString(str);
|
||||
|
||||
ICodeModule *icm = new ICodeModule(icp.mInstructions,
|
||||
theVariableList, /* VariableList *variables */
|
||||
NULL, /* VariableList *variables */
|
||||
theParameterList, /* ParameterList *parameters */
|
||||
icp.mMaxRegister,
|
||||
pCount, /* uint32 maxParameter, */
|
||||
NULL, /* InstructionMap *instructionMap */
|
||||
false, /* bool hasRestParameter, */
|
||||
false, /* bool hasNamedRestParameter */
|
||||
resultType);
|
||||
thisClass->defineMethod(methodName, new JSFunction(icm));
|
||||
}
|
||||
@ -2493,7 +2498,7 @@ void ICodeGenerator::readICode(const char *fileName)
|
||||
TypedRegister thisValue = TypedRegister(0, thisClass);
|
||||
ArgumentList *args = new ArgumentList(0);
|
||||
ICodeGenerator icg(mContext, thisClass, kIsStaticMethod);
|
||||
icg.allocateParameter(mContext->getWorld().identifiers["this"], thisClass); // always parameter #0
|
||||
icg.allocateParameter(mContext->getWorld().identifiers["this"], false, thisClass); // always parameter #0
|
||||
if (superclass)
|
||||
icg.call(icg.getStatic(superclass, superclass->getName()), thisValue, args);
|
||||
if (thisClass->hasStatic(mInitName))
|
||||
|
@ -51,59 +51,92 @@ namespace ICG {
|
||||
using namespace JSClasses;
|
||||
|
||||
|
||||
struct VariableList {
|
||||
struct VariableList { // Maps from variable (parameter) name to a TypedRegister.
|
||||
// But because we also want to map from a register number to
|
||||
// it's type, we keep the TypedRegsters in a separate array and
|
||||
// just store the index in the name map.
|
||||
|
||||
typedef std::map<String, uint32, std::less<String> > VariableMap;
|
||||
typedef VariableMap::value_type MapValue;
|
||||
|
||||
VariableMap variableMap;
|
||||
|
||||
std::vector<TypedRegister> registerMap;
|
||||
std::vector<TypedRegister> registerList;
|
||||
|
||||
void setRegisterForVariable(const StringAtom& name, TypedRegister r)
|
||||
{
|
||||
VariableMap::iterator i = variableMap.find(name);
|
||||
ASSERT(i != variableMap.end());
|
||||
registerMap[(*i).second] = r;
|
||||
}
|
||||
|
||||
TypedRegister findVariable(const StringAtom& name)
|
||||
{
|
||||
VariableMap::iterator i = variableMap.find(name);
|
||||
return (i == variableMap.end()) ? TypedRegister(NotARegister, &None_Type) : registerMap[(*i).second];
|
||||
return (i == variableMap.end())
|
||||
? TypedRegister(NotARegister, &None_Type)
|
||||
: registerList[i->second];
|
||||
}
|
||||
|
||||
void add(const StringAtom& name, TypedRegister r)
|
||||
{
|
||||
variableMap[name] = r.first;
|
||||
registerMap.resize(r.first + 1);
|
||||
registerMap[r.first] = r;
|
||||
variableMap.insert(MapValue(name, r.first));
|
||||
registerList.resize(r.first + 1);
|
||||
registerList[r.first] = r;
|
||||
}
|
||||
|
||||
TypedRegister getRegister(uint32 i)
|
||||
{
|
||||
ASSERT(i < registerMap.size());
|
||||
return registerMap[i];
|
||||
ASSERT(i < registerList.size());
|
||||
return registerList[i];
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
struct ParameterList : public VariableList {
|
||||
typedef enum {
|
||||
NoRestParameter,
|
||||
HasRestParameterBeforeBar,
|
||||
HasRestParameterAfterBar,
|
||||
HasUnnamedRestParameter
|
||||
} RestParameterStatus;
|
||||
|
||||
|
||||
|
||||
std::vector<bool> mOptionalParameters; // whether or not a parameter has an optional value
|
||||
// ordered by lexical ordering === register number.
|
||||
RestParameterStatus mRestParameter;
|
||||
uint32 mPositionalCount; // number of positional parameters
|
||||
|
||||
|
||||
|
||||
|
||||
ParameterList() : mRestParameter(NoRestParameter), mPositionalCount(0) { }
|
||||
|
||||
void add(const StringAtom& name, TypedRegister r, bool isOptional)
|
||||
{
|
||||
VariableList::add(name, r);
|
||||
mOptionalParameters.resize(r.first + 1);
|
||||
mOptionalParameters[r.first] = isOptional;
|
||||
}
|
||||
|
||||
uint32 size() { return registerList.size(); } // the variableMap may be larger since it contains aliases
|
||||
|
||||
bool isOptional(uint32 i) { ASSERT(i < mOptionalParameters.size()); return mOptionalParameters[i]; }
|
||||
|
||||
void setRestParameter(RestParameterStatus rs) { mRestParameter = rs; }
|
||||
void setPositionalCount(uint32 x) { mPositionalCount = x; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
typedef std::map<uint32, uint32, std::less<uint32> > InstructionMap;
|
||||
|
||||
|
||||
class ICodeModule {
|
||||
public:
|
||||
ICodeModule(InstructionStream *iCode, VariableList *variables,
|
||||
uint32 maxRegister, uint32 maxParameter,
|
||||
ParameterList *parameters,
|
||||
uint32 maxRegister,
|
||||
InstructionMap *instructionMap,
|
||||
bool hasRestParameter, bool hasNamedRestParameter,
|
||||
JSType *resultType) :
|
||||
its_iCode(iCode), itsVariables(variables),
|
||||
mParameterCount(maxParameter), itsMaxRegister(maxRegister),
|
||||
its_iCode(iCode), itsVariables(variables), itsParameters(parameters),
|
||||
itsMaxRegister(maxRegister),
|
||||
mID(++sMaxID), mInstructionMap(instructionMap),
|
||||
mParameterInit(NULL),
|
||||
mNonOptionalParameterCount(maxParameter),
|
||||
mEntryPoint(0),
|
||||
mHasRestParameter(hasRestParameter),
|
||||
mHasNamedRestParameter(hasNamedRestParameter),
|
||||
mResultType(resultType)
|
||||
{
|
||||
}
|
||||
@ -122,16 +155,13 @@ namespace ICG {
|
||||
|
||||
InstructionStream *its_iCode;
|
||||
VariableList *itsVariables;
|
||||
uint32 mParameterCount;
|
||||
ParameterList *itsParameters;
|
||||
uint32 itsMaxRegister;
|
||||
uint32 mID;
|
||||
InstructionMap *mInstructionMap;
|
||||
String mFileName;
|
||||
uint32 *mParameterInit;
|
||||
uint32 mNonOptionalParameterCount;
|
||||
uint32 mEntryPoint;
|
||||
bool mHasRestParameter;
|
||||
bool mHasNamedRestParameter;
|
||||
JSType *mResultType;
|
||||
|
||||
static uint32 sMaxID;
|
||||
@ -172,10 +202,10 @@ namespace ICG {
|
||||
LabelList labels;
|
||||
|
||||
Register mTopRegister; // highest (currently) allocated register
|
||||
uint32 mParameterCount; // number of parameters declared for the function
|
||||
// these must come before any variables declared.
|
||||
TypedRegister mExceptionRegister; // reserved to carry the exception object.
|
||||
VariableList *variableList; // name|register pair for each variable
|
||||
ParameterList *parameterList; // name|register pair for each parameter
|
||||
// (with #0 reserved for 'this' regardless of scope)
|
||||
|
||||
Context *mContext; // the world and global object
|
||||
LabelStack mLabelStack; // stack of LabelEntry objects, one per nested looping construct
|
||||
@ -185,8 +215,6 @@ 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
|
||||
|
||||
const StringAtom &mInitName;
|
||||
|
||||
@ -204,7 +232,7 @@ namespace ICG {
|
||||
return mTopRegister++;
|
||||
}
|
||||
|
||||
void resetTopRegister() { mTopRegister = mParameterCount; }
|
||||
void resetTopRegister() { mTopRegister = 0; }
|
||||
void resetStatement() { resetTopRegister(); }
|
||||
|
||||
TypedRegister allocateRegister(const StringAtom& name, JSType *type);
|
||||
@ -280,15 +308,40 @@ namespace ICG {
|
||||
void throwStmt(TypedRegister r) { iCode->push_back(new Throw(r)); }
|
||||
void debuggerStmt() { iCode->push_back(new Debugger()); }
|
||||
|
||||
TypedRegister allocateVariable(const StringAtom& name);
|
||||
TypedRegister allocateVariable(const StringAtom& name, const StringAtom& typeName);
|
||||
TypedRegister allocateVariable(const StringAtom& name, JSType *type) ;
|
||||
TypedRegister allocateVariable(const StringAtom& name)
|
||||
{
|
||||
return allocateVariable(name, &Any_Type);
|
||||
}
|
||||
|
||||
TypedRegister allocateParameter(const StringAtom& name) { mParameterCount++; return allocateRegister(name, &Any_Type); }
|
||||
TypedRegister allocateParameter(const StringAtom& name, const StringAtom& typeName)
|
||||
{ mParameterCount++; return allocateRegister(name, findType(typeName)); }
|
||||
TypedRegister allocateParameter(const StringAtom& name, JSType *type)
|
||||
{ mParameterCount++; return allocateRegister(name, type); }
|
||||
TypedRegister allocateVariable(const StringAtom& name, const StringAtom& typeName)
|
||||
{
|
||||
return allocateVariable(name, findType(typeName));
|
||||
}
|
||||
|
||||
TypedRegister allocateVariable(const StringAtom& name, JSType *type)
|
||||
{
|
||||
TypedRegister r = allocateRegister(name, type);
|
||||
variableList->add(name, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
TypedRegister allocateParameter(const StringAtom& name, bool isOptional)
|
||||
{
|
||||
return allocateParameter(name, isOptional, &Any_Type);
|
||||
}
|
||||
|
||||
TypedRegister allocateParameter(const StringAtom& name, bool isOptional, const StringAtom& typeName)
|
||||
{
|
||||
return allocateParameter(name, isOptional, findType(typeName));
|
||||
}
|
||||
|
||||
TypedRegister allocateParameter(const StringAtom& name, bool isOptional, JSType *type)
|
||||
{
|
||||
TypedRegister r = allocateRegister(name, type);
|
||||
parameterList->add(name, r, isOptional);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
Formatter& print(Formatter& f);
|
||||
|
||||
|
@ -160,11 +160,11 @@ ICodeModule* Context::compileFunction(const String &source)
|
||||
ICodeGenerator icg(this);
|
||||
ASSERT(e->getKind() == ExprNode::functionLiteral);
|
||||
FunctionExprNode* f = static_cast<FunctionExprNode*>(e);
|
||||
icg.allocateParameter(getWorld().identifiers["this"]); // always parameter #0
|
||||
icg.allocateParameter(getWorld().identifiers["this"], false); // 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);
|
||||
icg.allocateParameter((static_cast<IdentifierExprNode*>(v->name))->name, false);
|
||||
v = v->next;
|
||||
}
|
||||
icg.genStmt(f->function.body);
|
||||
@ -719,97 +719,85 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
||||
ICodeModule *icm = target->getICode();
|
||||
ArgumentList *args = op4(call);
|
||||
|
||||
// mParameterCount includes 'this' and also 1 for a named rest parameter
|
||||
// the parameter count includes 'this' and any named rest parameter
|
||||
//
|
||||
uint32 pCount = icm->mParameterCount - 1;
|
||||
uint32 pCount = icm->itsParameters->size() - 1; // we won't be passing 'this' via the arg list array
|
||||
// callArgs will be the actual args passed to the target, put into correct register order.
|
||||
// It has room for the rest parameter.
|
||||
ArgumentList *callArgs = new ArgumentList(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
|
||||
JSArray *restArg = NULL;
|
||||
uint32 restIndex = 0;
|
||||
// don't want to count the rest parameter while processing the others
|
||||
if (icm->itsParameters->mRestParameter != ParameterList::NoRestParameter) pCount--;
|
||||
|
||||
|
||||
uint32 i;
|
||||
JSArray *restArg = NULL;
|
||||
|
||||
// first match all named arguments with their intended target locations
|
||||
for (i = 0; i < args->size(); i++) {
|
||||
if ((*args)[i].second) { // a named argument
|
||||
TypedRegister r = icm->itsVariables->findVariable(*((*args)[i].second));
|
||||
bool isParameter = false;
|
||||
if (r.first != NotABanana) { // we found the name in the target's list of variables
|
||||
if (r.first < icm->mParameterCount) { // make sure we didn't match a local var
|
||||
ASSERT(r.first <= callArgs->size());
|
||||
// the named argument is arriving in slot i, but needs to be r instead
|
||||
// r.first is the intended target register, we subtract 1 since the callArgs array doesn't include 'this'
|
||||
// here's where we could detect over-writing a positional arg with a named one if that is illegal
|
||||
// if (callArgs[r.first - 1].first.first != NotARegister)...
|
||||
(*registers)[(*args)[i].first.first] = (*registers)[(*args)[i].first.first].convert(r.second);
|
||||
(*callArgs)[r.first - 1] = Argument((*args)[i].first, NULL); // no need to copy the name through?
|
||||
isParameter = true;
|
||||
}
|
||||
}
|
||||
if (!isParameter) { // wasn't a parameter, make it a property of the rest parameter (if there is one)
|
||||
if (icm->mHasRestParameter) {
|
||||
if (icm->mHasNamedRestParameter) {
|
||||
if (restArg == NULL) {
|
||||
restArg = new JSArray();
|
||||
restArg->setProperty(*(*args)[i].second, (*registers)[(*args)[i].first.first]);
|
||||
(*registers)[(*args)[i].first.first] = restArg;
|
||||
(*callArgs)[pCount] = Argument(TypedRegister((*args)[i].first.first, &Array_Type), NULL);
|
||||
}
|
||||
else
|
||||
restArg->setProperty(*(*args)[i].second, (*registers)[(*args)[i].first.first]);
|
||||
|
||||
const StringAtom *argName = (*args)[i].second;
|
||||
|
||||
TypedRegister parameter = icm->itsParameters->findVariable(*argName);
|
||||
if (parameter.first == NotARegister) {
|
||||
// arg name doesn't match any parameter name, it's a candidate
|
||||
// for the rest parameter (if there is one)
|
||||
if (icm->itsParameters->mRestParameter == ParameterList::NoRestParameter)
|
||||
throw new JSException("Named argument doesn't match parameter name in call with no rest parameter");
|
||||
else {
|
||||
if (icm->itsParameters->mRestParameter != ParameterList::HasUnnamedRestParameter) {
|
||||
// if the name is a numeric literal >= 0, use it as an array index
|
||||
// otherwise just set the named property.
|
||||
const char16 *c = argName->c_str();
|
||||
const char16 *end;
|
||||
double d = stringToDouble(c, c + argName->length(), end);
|
||||
|
||||
if ((d != d) || (d < 0) || (d != (int)d)) { // a non-numeric or negative value
|
||||
if (icm->itsParameters->mRestParameter == ParameterList::HasRestParameterBeforeBar)
|
||||
throw new JSException("Non-numeric or negative argument name for positional rest parameter");
|
||||
}
|
||||
// else just throw it away
|
||||
else { // shift the index value down by the number of positional parameters
|
||||
StringFormatter s;
|
||||
s << ((int)d - icm->itsParameters->mPositionalCount);
|
||||
argName = &mWorld.identifiers[s];
|
||||
}
|
||||
|
||||
TypedRegister argument = (*args)[i].first; // this is the argument whose name didn't match
|
||||
|
||||
if (restArg == NULL) {
|
||||
// allocate the rest argument and then subvert the register being used for the
|
||||
// argument under consideration to hold the newly created rest argument.
|
||||
restArg = new JSArray();
|
||||
restArg->setProperty(*argName, (*registers)[argument.first]); // put it into the rest argument
|
||||
(*registers)[argument.first] = restArg;
|
||||
// The callArgs for the rest parameter position gets loaded from that slot
|
||||
(*callArgs)[pCount] = Argument(TypedRegister(argument.first, &Array_Type), NULL);
|
||||
}
|
||||
else
|
||||
restArg->setProperty(*argName, (*registers)[argument.first]);
|
||||
}
|
||||
else
|
||||
throw new JSException("Named argument doesn't match parameter name in call with no rest parameter");
|
||||
// what about matching the named rest parameter ? aaarrggh!
|
||||
// else just throw it away
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (i >= pCount) { // more args than expected
|
||||
if (icm->mHasRestParameter) {
|
||||
if (icm->mHasNamedRestParameter) {
|
||||
if (restArg == NULL) {
|
||||
restArg = new JSArray();
|
||||
(*restArg)[restIndex++] = (*registers)[(*args)[i].first.first];
|
||||
(*registers)[(*args)[i].first.first] = restArg;
|
||||
(*callArgs)[pCount] = Argument(TypedRegister((*args)[i].first.first, &Array_Type), NULL);
|
||||
}
|
||||
else
|
||||
(*restArg)[restIndex++] = (*registers)[(*args)[i].first.first];
|
||||
}
|
||||
// else just throw it away
|
||||
}
|
||||
else
|
||||
throw new JSException("Too many arguments in call");
|
||||
}
|
||||
else {
|
||||
TypedRegister r = icm->itsVariables->getRegister(i + 1); // the variable list includes 'this'
|
||||
(*registers)[(*args)[i].first.first] = (*registers)[(*args)[i].first.first].convert(r.second);
|
||||
(*callArgs)[i] = (*args)[i]; // it's a positional, just slap it in place
|
||||
}
|
||||
uint32 targetIndex = parameter.first - 1; // this is the register number we're targetting
|
||||
TypedRegister targetParameter = (*callArgs)[targetIndex].first;
|
||||
if (targetParameter.first != NotARegister) // uh oh, some other argument wants this parameter
|
||||
throw new JSException("Two (or more) arguments have the same name");
|
||||
(*callArgs)[targetIndex] = (*args)[i];
|
||||
}
|
||||
}
|
||||
uint32 contiguousArgs = 0;
|
||||
for (i = 0; i < args->size(); i++) {
|
||||
Argument &arg = (*args)[i];
|
||||
if (arg.first.first == NotARegister) break;
|
||||
contiguousArgs++;
|
||||
|
||||
|
||||
// make sure that all non-optional parameters have values
|
||||
for (i = 0; i < pCount; i++) {
|
||||
TypedRegister parameter = (*callArgs)[i].first;
|
||||
if (parameter.first == NotARegister) { // doesn't have an assigned argument
|
||||
if (!icm->itsParameters->isOptional(i + 1)) // and parameter (allowing for 'this') doesn't have an optional value
|
||||
throw new JSException("No argument supplied for non-optional parameter");
|
||||
}
|
||||
}
|
||||
if ((contiguousArgs + 1) < icm->mNonOptionalParameterCount) // there's always a 'this' in R0 (even though it might be null)
|
||||
throw new JSException("Too few arguments in call");
|
||||
|
||||
|
||||
mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, op1(call));
|
||||
mActivation = new Activation(icm, mActivation, (*registers)[op3(call).first], callArgs);
|
||||
registers = &mActivation->mRegisters;
|
||||
|
@ -63,7 +63,7 @@ public:
|
||||
XMLTag(String name) : mName(name), mFlag(Tag) { }
|
||||
|
||||
void addAttribute(const String &name, const String &value) { mAttributeList.insert(AttributeValue(name, value) ); }
|
||||
bool getValue(const String &name, String &value);
|
||||
bool getValue(const String &name, String &value); // returns the value of the most newly inserted attribute 'name'.
|
||||
bool hasAttribute(const String &name) { return (mAttributeList.find(name) != mAttributeList.end()); }
|
||||
|
||||
String &name() { return mName; }
|
||||
|
@ -75,16 +75,14 @@ Formatter& operator<<(Formatter &f, ICodeModule &i)
|
||||
|
||||
ICodeGenerator::ICodeGenerator(Context *cx, JSClass *aClass, ICodeGeneratorFlags flags)
|
||||
: mTopRegister(0),
|
||||
mParameterCount(0),
|
||||
mExceptionRegister(TypedRegister(NotARegister, &None_Type)),
|
||||
variableList(new VariableList()),
|
||||
parameterList(new ParameterList()),
|
||||
mContext(cx),
|
||||
mInstructionMap(new InstructionMap()),
|
||||
mClass(aClass),
|
||||
mFlags(flags),
|
||||
pLabels(NULL),
|
||||
mHasRestParameter(false),
|
||||
mHasNamedRestParameter(false),
|
||||
mInitName(cx->getWorld().identifiers["__init__"])
|
||||
{
|
||||
iCode = new InstructionStream();
|
||||
@ -106,7 +104,7 @@ JSType *ICodeGenerator::findType(const StringAtom& typeName)
|
||||
-Theoretically, mPermanentRegister[n] can be become false when a scope ends and
|
||||
the registers allocated to contained variables are then available for re-use.
|
||||
-Mostly the need is to handle overlapping allocation of temps & permanents as the
|
||||
variables declarations are encountered. This wouldn't be necessary if a function
|
||||
variables' declarations are encountered. This wouldn't be necessary if a function
|
||||
presented a list of all variables, or a pre-pass executed to discover same.
|
||||
*/
|
||||
TypedRegister ICodeGenerator::allocateRegister(const StringAtom& name, JSType *type)
|
||||
@ -122,27 +120,11 @@ TypedRegister ICodeGenerator::allocateRegister(const StringAtom& name, JSType *t
|
||||
mPermanentRegister[r] = true;
|
||||
|
||||
TypedRegister result(r, type);
|
||||
variableList->add(name, result);
|
||||
mTopRegister = ++r;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
TypedRegister ICodeGenerator::allocateVariable(const StringAtom& name, const StringAtom& typeName)
|
||||
{
|
||||
return allocateRegister(name, findType(typeName));
|
||||
}
|
||||
|
||||
TypedRegister ICodeGenerator::allocateVariable(const StringAtom& name)
|
||||
{
|
||||
return allocateRegister(name, &Any_Type);
|
||||
}
|
||||
|
||||
TypedRegister ICodeGenerator::allocateVariable(const StringAtom& name, JSType *type)
|
||||
{
|
||||
return allocateRegister(name, type);
|
||||
}
|
||||
|
||||
ICodeModule *ICodeGenerator::complete(JSType *resultType)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
@ -188,16 +170,13 @@ ICodeModule *ICodeGenerator::complete(JSType *resultType)
|
||||
*/
|
||||
ICodeModule* module = new ICodeModule(iCode,
|
||||
variableList,
|
||||
parameterList,
|
||||
mPermanentRegister.size(),
|
||||
mParameterCount,
|
||||
mInstructionMap,
|
||||
mHasRestParameter,
|
||||
mHasNamedRestParameter,
|
||||
resultType);
|
||||
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;
|
||||
@ -742,6 +721,8 @@ ICodeGenerator::LValueKind ICodeGenerator::resolveIdentifier(const StringAtom &n
|
||||
{
|
||||
if (!isWithinWith()) {
|
||||
v = variableList->findVariable(name);
|
||||
if (v.first == NotARegister)
|
||||
v = parameterList->findVariable(name);
|
||||
if (v.first != NotARegister)
|
||||
return Var;
|
||||
else {
|
||||
@ -1218,12 +1199,11 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
|
||||
if (p->field && (p->field->getKind() == ExprNode::string))
|
||||
args->push_back(Argument(genExpr(p->value), &mContext->getWorld().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), &mContext->getWorld().identifiers[s] ));
|
||||
s.clear();
|
||||
*/
|
||||
args->push_back(Argument(genExpr(p->value), NULL ));
|
||||
|
||||
// args->push_back(Argument(genExpr(p->value), NULL ));
|
||||
}
|
||||
count++;
|
||||
p = p->next;
|
||||
@ -1561,15 +1541,16 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
|
||||
}
|
||||
break;
|
||||
|
||||
case ExprNode::functionLiteral:
|
||||
case ExprNode::functionLiteral: // XXX FIXME!! This needs to handled by calling genFunction !!!
|
||||
// - the parameter handling is all wrong
|
||||
{
|
||||
FunctionExprNode *f = static_cast<FunctionExprNode *>(p);
|
||||
ICodeGenerator icg(mContext);
|
||||
icg.allocateParameter(mContext->getWorld().identifiers["this"]); // always parameter #0
|
||||
icg.allocateParameter(mContext->getWorld().identifiers["this"], false); // 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);
|
||||
icg.allocateParameter((static_cast<IdentifierExprNode *>(v->name))->name, false, &Any_Type);
|
||||
v = v->next;
|
||||
}
|
||||
icg.genStmt(f->function.body);
|
||||
@ -1649,21 +1630,54 @@ ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor
|
||||
ICodeGeneratorFlags flags = (isStatic) ? kIsStaticMethod : kNoFlags;
|
||||
|
||||
ICodeGenerator icg(mContext, mClass, flags);
|
||||
icg.allocateParameter(mContext->getWorld().identifiers["this"], (mClass) ? mClass : &Any_Type); // always parameter #0
|
||||
icg.allocateParameter(mContext->getWorld().identifiers["this"], false, (mClass) ? mClass : &Any_Type); // always parameter #0
|
||||
VariableBinding *v = f->function.parameters;
|
||||
bool unnamed = true;
|
||||
uint32 positionalCount = 0;
|
||||
StringFormatter s;
|
||||
while (v) {
|
||||
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);
|
||||
if (unnamed && (v == f->function.namedParameters)) { // Track when we hit the first named parameter.
|
||||
icg.parameterList->setPositionalCount(positionalCount);
|
||||
unnamed = false;
|
||||
}
|
||||
positionalCount++;
|
||||
|
||||
// The rest parameter is ignored in this processing - we push it to the end of the list.
|
||||
// But we need to track whether it comes before or after the |
|
||||
if (v == f->function.restParameter) {
|
||||
icg.parameterList->setRestParameter( (unnamed) ? ParameterList::HasRestParameterBeforeBar : ParameterList::HasRestParameterAfterBar );
|
||||
}
|
||||
else {
|
||||
if (v->name && (v->name->getKind() == ExprNode::identifier)) {
|
||||
JSType *pType = extractType(v->type);
|
||||
TypedRegister r = icg.allocateParameter((static_cast<IdentifierExprNode *>(v->name))->name, (v->initializer != NULL), pType);
|
||||
IdentifierList *a = v->aliases;
|
||||
while (a) {
|
||||
icg.parameterList->add(a->name, r, (v->initializer != NULL));
|
||||
a = a->next;
|
||||
}
|
||||
// every unnamed parameter is also named with it's positional name
|
||||
if (unnamed) {
|
||||
s << r.first - 1; // the first positional parameter is '0'
|
||||
icg.parameterList->add(mContext->getWorld().identifiers[s], r, (v->initializer != NULL));
|
||||
s.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
NOT_REACHED("qualified or un-named parameters not handled; bugger off.");
|
||||
v = v->next;
|
||||
}
|
||||
|
||||
// now allocate the rest parameter
|
||||
if (f->function.restParameter) {
|
||||
v = f->function.restParameter;
|
||||
JSType *pType = (v->type == NULL) ? &Array_Type : extractType(v->type);
|
||||
if (v->name && (v->name->getKind() == ExprNode::identifier))
|
||||
icg.allocateParameter((static_cast<IdentifierExprNode *>(v->name))->name, (v->initializer != NULL), pType);
|
||||
else
|
||||
icg.parameterList->setRestParameter(ParameterList::HasUnnamedRestParameter);
|
||||
}
|
||||
|
||||
// generate the code for optional initializers
|
||||
v = f->function.optParameters;
|
||||
if (v) {
|
||||
while (v) { // include the rest parameter, as it may have an initializer
|
||||
@ -1689,13 +1703,7 @@ ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor
|
||||
}
|
||||
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
|
||||
@ -1851,7 +1859,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||
// constructor code generator. Slot variable
|
||||
// initializers get added to this function.
|
||||
ccg = new ICodeGenerator(classContext, thisClass, kNoFlags);
|
||||
ccg->allocateParameter(mContext->getWorld().identifiers["this"], thisClass); // always parameter #0
|
||||
ccg->allocateParameter(mContext->getWorld().identifiers["this"], false, thisClass); // always parameter #0
|
||||
}
|
||||
|
||||
ICodeGenerator scg(classContext, thisClass, kIsStaticMethod); // static initializer code generator.
|
||||
@ -1939,7 +1947,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||
TypedRegister thisValue = TypedRegister(0, thisClass);
|
||||
ArgumentList *args = new ArgumentList();
|
||||
ICodeGenerator icg(classContext, thisClass, kIsStaticMethod);
|
||||
icg.allocateParameter(mContext->getWorld().identifiers["this"], thisClass); // always parameter #0
|
||||
icg.allocateParameter(mContext->getWorld().identifiers["this"], false, thisClass); // always parameter #0
|
||||
if (superclass)
|
||||
icg.call(icg.getStatic(superclass, superclass->getName()), thisValue, args);
|
||||
if (thisClass->hasStatic(mInitName))
|
||||
@ -2325,7 +2333,6 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||
// Bind the incoming exception ...
|
||||
if (mExceptionRegister.first == NotABanana)
|
||||
mExceptionRegister = allocateRegister(mContext->getWorld().identifiers["__exceptionObject__"], &Any_Type);
|
||||
variableList->setRegisterForVariable(c->name, mExceptionRegister);
|
||||
|
||||
genStmt(c->stmt);
|
||||
if (finallyLabel)
|
||||
@ -2419,7 +2426,7 @@ void ICodeGenerator::readICode(const char *fileName)
|
||||
Context *classContext = new Context(mContext->getWorld(), thisScope);
|
||||
ICodeGenerator scg(classContext, thisClass, kIsStaticMethod);
|
||||
ICodeGenerator ccg(classContext, thisClass, kNoFlags);
|
||||
ccg.allocateParameter(mContext->getWorld().identifiers["this"], thisClass);
|
||||
ccg.allocateParameter(mContext->getWorld().identifiers["this"], false, thisClass);
|
||||
thisClass->defineStatic(mInitName, &Function_Type);
|
||||
|
||||
mContext->getGlobalObject()->defineVariable(className, &Type_Type, JSValue(thisClass));
|
||||
@ -2433,8 +2440,8 @@ void ICodeGenerator::readICode(const char *fileName)
|
||||
String methodName, resultTypeName;
|
||||
element->getValue(widenCString("name"), methodName);
|
||||
element->getValue(widenCString("type"), resultTypeName);
|
||||
VariableList *theVariableList = new VariableList();
|
||||
theVariableList->add(mContext->getWorld().identifiers["this"], TypedRegister(0, thisClass));
|
||||
ParameterList *theParameterList = new ParameterList();
|
||||
theParameterList->add(mContext->getWorld().identifiers["this"], TypedRegister(0, thisClass), false);
|
||||
uint32 pCount = 1;
|
||||
XMLNodeList ¶meters = element->children();
|
||||
for (XMLNodeList::const_iterator k = parameters.begin(); k != parameters.end(); k++) {
|
||||
@ -2445,7 +2452,7 @@ void ICodeGenerator::readICode(const char *fileName)
|
||||
element->getValue(widenCString("name"), parameterName);
|
||||
element->getValue(widenCString("type"), parameterTypeName);
|
||||
JSType *parameterType = findType(mContext->getWorld().identifiers[parameterTypeName]);
|
||||
theVariableList->add(mContext->getWorld().identifiers[parameterName], TypedRegister(pCount++, parameterType));
|
||||
theParameterList->add(mContext->getWorld().identifiers[parameterName], TypedRegister(pCount++, parameterType), false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2461,12 +2468,10 @@ void ICodeGenerator::readICode(const char *fileName)
|
||||
icp.ParseSourceFromString(str);
|
||||
|
||||
ICodeModule *icm = new ICodeModule(icp.mInstructions,
|
||||
theVariableList, /* VariableList *variables */
|
||||
NULL, /* VariableList *variables */
|
||||
theParameterList, /* ParameterList *parameters */
|
||||
icp.mMaxRegister,
|
||||
pCount, /* uint32 maxParameter, */
|
||||
NULL, /* InstructionMap *instructionMap */
|
||||
false, /* bool hasRestParameter, */
|
||||
false, /* bool hasNamedRestParameter */
|
||||
resultType);
|
||||
thisClass->defineMethod(methodName, new JSFunction(icm));
|
||||
}
|
||||
@ -2493,7 +2498,7 @@ void ICodeGenerator::readICode(const char *fileName)
|
||||
TypedRegister thisValue = TypedRegister(0, thisClass);
|
||||
ArgumentList *args = new ArgumentList(0);
|
||||
ICodeGenerator icg(mContext, thisClass, kIsStaticMethod);
|
||||
icg.allocateParameter(mContext->getWorld().identifiers["this"], thisClass); // always parameter #0
|
||||
icg.allocateParameter(mContext->getWorld().identifiers["this"], false, thisClass); // always parameter #0
|
||||
if (superclass)
|
||||
icg.call(icg.getStatic(superclass, superclass->getName()), thisValue, args);
|
||||
if (thisClass->hasStatic(mInitName))
|
||||
|
@ -51,59 +51,92 @@ namespace ICG {
|
||||
using namespace JSClasses;
|
||||
|
||||
|
||||
struct VariableList {
|
||||
struct VariableList { // Maps from variable (parameter) name to a TypedRegister.
|
||||
// But because we also want to map from a register number to
|
||||
// it's type, we keep the TypedRegsters in a separate array and
|
||||
// just store the index in the name map.
|
||||
|
||||
typedef std::map<String, uint32, std::less<String> > VariableMap;
|
||||
typedef VariableMap::value_type MapValue;
|
||||
|
||||
VariableMap variableMap;
|
||||
|
||||
std::vector<TypedRegister> registerMap;
|
||||
std::vector<TypedRegister> registerList;
|
||||
|
||||
void setRegisterForVariable(const StringAtom& name, TypedRegister r)
|
||||
{
|
||||
VariableMap::iterator i = variableMap.find(name);
|
||||
ASSERT(i != variableMap.end());
|
||||
registerMap[(*i).second] = r;
|
||||
}
|
||||
|
||||
TypedRegister findVariable(const StringAtom& name)
|
||||
{
|
||||
VariableMap::iterator i = variableMap.find(name);
|
||||
return (i == variableMap.end()) ? TypedRegister(NotARegister, &None_Type) : registerMap[(*i).second];
|
||||
return (i == variableMap.end())
|
||||
? TypedRegister(NotARegister, &None_Type)
|
||||
: registerList[i->second];
|
||||
}
|
||||
|
||||
void add(const StringAtom& name, TypedRegister r)
|
||||
{
|
||||
variableMap[name] = r.first;
|
||||
registerMap.resize(r.first + 1);
|
||||
registerMap[r.first] = r;
|
||||
variableMap.insert(MapValue(name, r.first));
|
||||
registerList.resize(r.first + 1);
|
||||
registerList[r.first] = r;
|
||||
}
|
||||
|
||||
TypedRegister getRegister(uint32 i)
|
||||
{
|
||||
ASSERT(i < registerMap.size());
|
||||
return registerMap[i];
|
||||
ASSERT(i < registerList.size());
|
||||
return registerList[i];
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
struct ParameterList : public VariableList {
|
||||
typedef enum {
|
||||
NoRestParameter,
|
||||
HasRestParameterBeforeBar,
|
||||
HasRestParameterAfterBar,
|
||||
HasUnnamedRestParameter
|
||||
} RestParameterStatus;
|
||||
|
||||
|
||||
|
||||
std::vector<bool> mOptionalParameters; // whether or not a parameter has an optional value
|
||||
// ordered by lexical ordering === register number.
|
||||
RestParameterStatus mRestParameter;
|
||||
uint32 mPositionalCount; // number of positional parameters
|
||||
|
||||
|
||||
|
||||
|
||||
ParameterList() : mRestParameter(NoRestParameter), mPositionalCount(0) { }
|
||||
|
||||
void add(const StringAtom& name, TypedRegister r, bool isOptional)
|
||||
{
|
||||
VariableList::add(name, r);
|
||||
mOptionalParameters.resize(r.first + 1);
|
||||
mOptionalParameters[r.first] = isOptional;
|
||||
}
|
||||
|
||||
uint32 size() { return registerList.size(); } // the variableMap may be larger since it contains aliases
|
||||
|
||||
bool isOptional(uint32 i) { ASSERT(i < mOptionalParameters.size()); return mOptionalParameters[i]; }
|
||||
|
||||
void setRestParameter(RestParameterStatus rs) { mRestParameter = rs; }
|
||||
void setPositionalCount(uint32 x) { mPositionalCount = x; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
typedef std::map<uint32, uint32, std::less<uint32> > InstructionMap;
|
||||
|
||||
|
||||
class ICodeModule {
|
||||
public:
|
||||
ICodeModule(InstructionStream *iCode, VariableList *variables,
|
||||
uint32 maxRegister, uint32 maxParameter,
|
||||
ParameterList *parameters,
|
||||
uint32 maxRegister,
|
||||
InstructionMap *instructionMap,
|
||||
bool hasRestParameter, bool hasNamedRestParameter,
|
||||
JSType *resultType) :
|
||||
its_iCode(iCode), itsVariables(variables),
|
||||
mParameterCount(maxParameter), itsMaxRegister(maxRegister),
|
||||
its_iCode(iCode), itsVariables(variables), itsParameters(parameters),
|
||||
itsMaxRegister(maxRegister),
|
||||
mID(++sMaxID), mInstructionMap(instructionMap),
|
||||
mParameterInit(NULL),
|
||||
mNonOptionalParameterCount(maxParameter),
|
||||
mEntryPoint(0),
|
||||
mHasRestParameter(hasRestParameter),
|
||||
mHasNamedRestParameter(hasNamedRestParameter),
|
||||
mResultType(resultType)
|
||||
{
|
||||
}
|
||||
@ -122,16 +155,13 @@ namespace ICG {
|
||||
|
||||
InstructionStream *its_iCode;
|
||||
VariableList *itsVariables;
|
||||
uint32 mParameterCount;
|
||||
ParameterList *itsParameters;
|
||||
uint32 itsMaxRegister;
|
||||
uint32 mID;
|
||||
InstructionMap *mInstructionMap;
|
||||
String mFileName;
|
||||
uint32 *mParameterInit;
|
||||
uint32 mNonOptionalParameterCount;
|
||||
uint32 mEntryPoint;
|
||||
bool mHasRestParameter;
|
||||
bool mHasNamedRestParameter;
|
||||
JSType *mResultType;
|
||||
|
||||
static uint32 sMaxID;
|
||||
@ -172,10 +202,10 @@ namespace ICG {
|
||||
LabelList labels;
|
||||
|
||||
Register mTopRegister; // highest (currently) allocated register
|
||||
uint32 mParameterCount; // number of parameters declared for the function
|
||||
// these must come before any variables declared.
|
||||
TypedRegister mExceptionRegister; // reserved to carry the exception object.
|
||||
VariableList *variableList; // name|register pair for each variable
|
||||
ParameterList *parameterList; // name|register pair for each parameter
|
||||
// (with #0 reserved for 'this' regardless of scope)
|
||||
|
||||
Context *mContext; // the world and global object
|
||||
LabelStack mLabelStack; // stack of LabelEntry objects, one per nested looping construct
|
||||
@ -185,8 +215,6 @@ 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
|
||||
|
||||
const StringAtom &mInitName;
|
||||
|
||||
@ -204,7 +232,7 @@ namespace ICG {
|
||||
return mTopRegister++;
|
||||
}
|
||||
|
||||
void resetTopRegister() { mTopRegister = mParameterCount; }
|
||||
void resetTopRegister() { mTopRegister = 0; }
|
||||
void resetStatement() { resetTopRegister(); }
|
||||
|
||||
TypedRegister allocateRegister(const StringAtom& name, JSType *type);
|
||||
@ -280,15 +308,40 @@ namespace ICG {
|
||||
void throwStmt(TypedRegister r) { iCode->push_back(new Throw(r)); }
|
||||
void debuggerStmt() { iCode->push_back(new Debugger()); }
|
||||
|
||||
TypedRegister allocateVariable(const StringAtom& name);
|
||||
TypedRegister allocateVariable(const StringAtom& name, const StringAtom& typeName);
|
||||
TypedRegister allocateVariable(const StringAtom& name, JSType *type) ;
|
||||
TypedRegister allocateVariable(const StringAtom& name)
|
||||
{
|
||||
return allocateVariable(name, &Any_Type);
|
||||
}
|
||||
|
||||
TypedRegister allocateParameter(const StringAtom& name) { mParameterCount++; return allocateRegister(name, &Any_Type); }
|
||||
TypedRegister allocateParameter(const StringAtom& name, const StringAtom& typeName)
|
||||
{ mParameterCount++; return allocateRegister(name, findType(typeName)); }
|
||||
TypedRegister allocateParameter(const StringAtom& name, JSType *type)
|
||||
{ mParameterCount++; return allocateRegister(name, type); }
|
||||
TypedRegister allocateVariable(const StringAtom& name, const StringAtom& typeName)
|
||||
{
|
||||
return allocateVariable(name, findType(typeName));
|
||||
}
|
||||
|
||||
TypedRegister allocateVariable(const StringAtom& name, JSType *type)
|
||||
{
|
||||
TypedRegister r = allocateRegister(name, type);
|
||||
variableList->add(name, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
TypedRegister allocateParameter(const StringAtom& name, bool isOptional)
|
||||
{
|
||||
return allocateParameter(name, isOptional, &Any_Type);
|
||||
}
|
||||
|
||||
TypedRegister allocateParameter(const StringAtom& name, bool isOptional, const StringAtom& typeName)
|
||||
{
|
||||
return allocateParameter(name, isOptional, findType(typeName));
|
||||
}
|
||||
|
||||
TypedRegister allocateParameter(const StringAtom& name, bool isOptional, JSType *type)
|
||||
{
|
||||
TypedRegister r = allocateRegister(name, type);
|
||||
parameterList->add(name, r, isOptional);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
Formatter& print(Formatter& f);
|
||||
|
||||
|
@ -160,11 +160,11 @@ ICodeModule* Context::compileFunction(const String &source)
|
||||
ICodeGenerator icg(this);
|
||||
ASSERT(e->getKind() == ExprNode::functionLiteral);
|
||||
FunctionExprNode* f = static_cast<FunctionExprNode*>(e);
|
||||
icg.allocateParameter(getWorld().identifiers["this"]); // always parameter #0
|
||||
icg.allocateParameter(getWorld().identifiers["this"], false); // 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);
|
||||
icg.allocateParameter((static_cast<IdentifierExprNode*>(v->name))->name, false);
|
||||
v = v->next;
|
||||
}
|
||||
icg.genStmt(f->function.body);
|
||||
@ -719,97 +719,85 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
||||
ICodeModule *icm = target->getICode();
|
||||
ArgumentList *args = op4(call);
|
||||
|
||||
// mParameterCount includes 'this' and also 1 for a named rest parameter
|
||||
// the parameter count includes 'this' and any named rest parameter
|
||||
//
|
||||
uint32 pCount = icm->mParameterCount - 1;
|
||||
uint32 pCount = icm->itsParameters->size() - 1; // we won't be passing 'this' via the arg list array
|
||||
// callArgs will be the actual args passed to the target, put into correct register order.
|
||||
// It has room for the rest parameter.
|
||||
ArgumentList *callArgs = new ArgumentList(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
|
||||
JSArray *restArg = NULL;
|
||||
uint32 restIndex = 0;
|
||||
// don't want to count the rest parameter while processing the others
|
||||
if (icm->itsParameters->mRestParameter != ParameterList::NoRestParameter) pCount--;
|
||||
|
||||
|
||||
uint32 i;
|
||||
JSArray *restArg = NULL;
|
||||
|
||||
// first match all named arguments with their intended target locations
|
||||
for (i = 0; i < args->size(); i++) {
|
||||
if ((*args)[i].second) { // a named argument
|
||||
TypedRegister r = icm->itsVariables->findVariable(*((*args)[i].second));
|
||||
bool isParameter = false;
|
||||
if (r.first != NotABanana) { // we found the name in the target's list of variables
|
||||
if (r.first < icm->mParameterCount) { // make sure we didn't match a local var
|
||||
ASSERT(r.first <= callArgs->size());
|
||||
// the named argument is arriving in slot i, but needs to be r instead
|
||||
// r.first is the intended target register, we subtract 1 since the callArgs array doesn't include 'this'
|
||||
// here's where we could detect over-writing a positional arg with a named one if that is illegal
|
||||
// if (callArgs[r.first - 1].first.first != NotARegister)...
|
||||
(*registers)[(*args)[i].first.first] = (*registers)[(*args)[i].first.first].convert(r.second);
|
||||
(*callArgs)[r.first - 1] = Argument((*args)[i].first, NULL); // no need to copy the name through?
|
||||
isParameter = true;
|
||||
}
|
||||
}
|
||||
if (!isParameter) { // wasn't a parameter, make it a property of the rest parameter (if there is one)
|
||||
if (icm->mHasRestParameter) {
|
||||
if (icm->mHasNamedRestParameter) {
|
||||
if (restArg == NULL) {
|
||||
restArg = new JSArray();
|
||||
restArg->setProperty(*(*args)[i].second, (*registers)[(*args)[i].first.first]);
|
||||
(*registers)[(*args)[i].first.first] = restArg;
|
||||
(*callArgs)[pCount] = Argument(TypedRegister((*args)[i].first.first, &Array_Type), NULL);
|
||||
}
|
||||
else
|
||||
restArg->setProperty(*(*args)[i].second, (*registers)[(*args)[i].first.first]);
|
||||
|
||||
const StringAtom *argName = (*args)[i].second;
|
||||
|
||||
TypedRegister parameter = icm->itsParameters->findVariable(*argName);
|
||||
if (parameter.first == NotARegister) {
|
||||
// arg name doesn't match any parameter name, it's a candidate
|
||||
// for the rest parameter (if there is one)
|
||||
if (icm->itsParameters->mRestParameter == ParameterList::NoRestParameter)
|
||||
throw new JSException("Named argument doesn't match parameter name in call with no rest parameter");
|
||||
else {
|
||||
if (icm->itsParameters->mRestParameter != ParameterList::HasUnnamedRestParameter) {
|
||||
// if the name is a numeric literal >= 0, use it as an array index
|
||||
// otherwise just set the named property.
|
||||
const char16 *c = argName->c_str();
|
||||
const char16 *end;
|
||||
double d = stringToDouble(c, c + argName->length(), end);
|
||||
|
||||
if ((d != d) || (d < 0) || (d != (int)d)) { // a non-numeric or negative value
|
||||
if (icm->itsParameters->mRestParameter == ParameterList::HasRestParameterBeforeBar)
|
||||
throw new JSException("Non-numeric or negative argument name for positional rest parameter");
|
||||
}
|
||||
// else just throw it away
|
||||
else { // shift the index value down by the number of positional parameters
|
||||
StringFormatter s;
|
||||
s << ((int)d - icm->itsParameters->mPositionalCount);
|
||||
argName = &mWorld.identifiers[s];
|
||||
}
|
||||
|
||||
TypedRegister argument = (*args)[i].first; // this is the argument whose name didn't match
|
||||
|
||||
if (restArg == NULL) {
|
||||
// allocate the rest argument and then subvert the register being used for the
|
||||
// argument under consideration to hold the newly created rest argument.
|
||||
restArg = new JSArray();
|
||||
restArg->setProperty(*argName, (*registers)[argument.first]); // put it into the rest argument
|
||||
(*registers)[argument.first] = restArg;
|
||||
// The callArgs for the rest parameter position gets loaded from that slot
|
||||
(*callArgs)[pCount] = Argument(TypedRegister(argument.first, &Array_Type), NULL);
|
||||
}
|
||||
else
|
||||
restArg->setProperty(*argName, (*registers)[argument.first]);
|
||||
}
|
||||
else
|
||||
throw new JSException("Named argument doesn't match parameter name in call with no rest parameter");
|
||||
// what about matching the named rest parameter ? aaarrggh!
|
||||
// else just throw it away
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (i >= pCount) { // more args than expected
|
||||
if (icm->mHasRestParameter) {
|
||||
if (icm->mHasNamedRestParameter) {
|
||||
if (restArg == NULL) {
|
||||
restArg = new JSArray();
|
||||
(*restArg)[restIndex++] = (*registers)[(*args)[i].first.first];
|
||||
(*registers)[(*args)[i].first.first] = restArg;
|
||||
(*callArgs)[pCount] = Argument(TypedRegister((*args)[i].first.first, &Array_Type), NULL);
|
||||
}
|
||||
else
|
||||
(*restArg)[restIndex++] = (*registers)[(*args)[i].first.first];
|
||||
}
|
||||
// else just throw it away
|
||||
}
|
||||
else
|
||||
throw new JSException("Too many arguments in call");
|
||||
}
|
||||
else {
|
||||
TypedRegister r = icm->itsVariables->getRegister(i + 1); // the variable list includes 'this'
|
||||
(*registers)[(*args)[i].first.first] = (*registers)[(*args)[i].first.first].convert(r.second);
|
||||
(*callArgs)[i] = (*args)[i]; // it's a positional, just slap it in place
|
||||
}
|
||||
uint32 targetIndex = parameter.first - 1; // this is the register number we're targetting
|
||||
TypedRegister targetParameter = (*callArgs)[targetIndex].first;
|
||||
if (targetParameter.first != NotARegister) // uh oh, some other argument wants this parameter
|
||||
throw new JSException("Two (or more) arguments have the same name");
|
||||
(*callArgs)[targetIndex] = (*args)[i];
|
||||
}
|
||||
}
|
||||
uint32 contiguousArgs = 0;
|
||||
for (i = 0; i < args->size(); i++) {
|
||||
Argument &arg = (*args)[i];
|
||||
if (arg.first.first == NotARegister) break;
|
||||
contiguousArgs++;
|
||||
|
||||
|
||||
// make sure that all non-optional parameters have values
|
||||
for (i = 0; i < pCount; i++) {
|
||||
TypedRegister parameter = (*callArgs)[i].first;
|
||||
if (parameter.first == NotARegister) { // doesn't have an assigned argument
|
||||
if (!icm->itsParameters->isOptional(i + 1)) // and parameter (allowing for 'this') doesn't have an optional value
|
||||
throw new JSException("No argument supplied for non-optional parameter");
|
||||
}
|
||||
}
|
||||
if ((contiguousArgs + 1) < icm->mNonOptionalParameterCount) // there's always a 'this' in R0 (even though it might be null)
|
||||
throw new JSException("Too few arguments in call");
|
||||
|
||||
|
||||
mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, op1(call));
|
||||
mActivation = new Activation(icm, mActivation, (*registers)[op3(call).first], callArgs);
|
||||
registers = &mActivation->mRegisters;
|
||||
|
@ -63,7 +63,7 @@ public:
|
||||
XMLTag(String name) : mName(name), mFlag(Tag) { }
|
||||
|
||||
void addAttribute(const String &name, const String &value) { mAttributeList.insert(AttributeValue(name, value) ); }
|
||||
bool getValue(const String &name, String &value);
|
||||
bool getValue(const String &name, String &value); // returns the value of the most newly inserted attribute 'name'.
|
||||
bool hasAttribute(const String &name) { return (mAttributeList.find(name) != mAttributeList.end()); }
|
||||
|
||||
String &name() { return mName; }
|
||||
|
Loading…
Reference in New Issue
Block a user