зеркало из https://github.com/mozilla/pjs.git
Named arguments
This commit is contained in:
Родитель
81c812ca20
Коммит
29c3f3caa8
|
@ -537,6 +537,16 @@ GenericBranch *ICodeGenerator::branchFalse(Label *label, TypedRegister condition
|
|||
return instr;
|
||||
}
|
||||
|
||||
GenericBranch *ICodeGenerator::branchInitialized(Label *label, TypedRegister condition)
|
||||
{
|
||||
GenericBranch *instr = new GenericBranch(BRANCH_INITIALIZED, label, condition);
|
||||
iCode->push_back(instr);
|
||||
return instr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void ICodeGenerator::returnStmt(TypedRegister r)
|
||||
{
|
||||
iCode->push_back(new Return(r));
|
||||
|
@ -1620,9 +1630,20 @@ ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor
|
|||
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()));
|
||||
TypedRegister p = icg.genExpr(v->name);
|
||||
if (v->initializer) { // might be NULL when we get to the restParameter
|
||||
TypedRegister p = icg.genExpr(v->name);
|
||||
Label *l = icg.getLabel();
|
||||
icg.branchInitialized(l, p);
|
||||
icg.move(p, icg.genExpr(v->initializer));
|
||||
icg.setLabel(l);
|
||||
}
|
||||
else { // an un-initialized rest parameter is still an empty array
|
||||
if (v == f->function.restParameter) {
|
||||
Label *l = icg.getLabel();
|
||||
icg.branchInitialized(l, p);
|
||||
icg.move(p, icg.newArray());
|
||||
icg.setLabel(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
v = v->next;
|
||||
|
|
|
@ -187,6 +187,7 @@ namespace ICG {
|
|||
void branch(Label *label);
|
||||
GenericBranch *branchTrue(Label *label, TypedRegister condition);
|
||||
GenericBranch *branchFalse(Label *label, TypedRegister condition);
|
||||
GenericBranch *branchInitialized(Label *label, TypedRegister condition);
|
||||
|
||||
void beginTry(Label *catchLabel, Label *finallyLabel)
|
||||
{ iCode->push_back(new Tryin(catchLabel, finallyLabel)); }
|
||||
|
|
|
@ -105,7 +105,11 @@ struct Activation : public gc_base {
|
|||
const JSValues& params = caller->mRegisters;
|
||||
for (ArgumentList::const_iterator src = list.begin(),
|
||||
end = list.end(); src != end; ++src, ++dest) {
|
||||
*dest = params[(*src).first.first];
|
||||
Register r = (*src).first.first;
|
||||
if (r != NotARegister)
|
||||
*dest = params[r];
|
||||
else
|
||||
*dest = JSValue(JSValue::uninitialized_tag);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -692,56 +696,89 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
|||
else {
|
||||
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);
|
||||
}
|
||||
// mParameterCount includes 'this' and also 1 for a named rest parameter
|
||||
//
|
||||
uint32 pCount = icm->mParameterCount - 1;
|
||||
ArgumentList callArgs(pCount, Argument(TypedRegister(NotARegister, &Null_Type), NULL));
|
||||
if (icm->mHasNamedRestParameter) pCount--;
|
||||
|
||||
|
||||
// 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;
|
||||
uint32 i;
|
||||
for (i = 0; i < args.size(); i++) {
|
||||
if (args[i].second) { // a named argument
|
||||
VariableList::iterator vi = icm->itsVariables->find(*(args[i].second));
|
||||
bool isParameter = false;
|
||||
if (vi != icm->itsVariables->end()) { // we found the name in the target's list of variables
|
||||
TypedRegister r = (*vi).second;
|
||||
if (r.first < 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)...
|
||||
callArgs[r.first - 1] = Argument(args[i].first, NULL); // no need to copy the name through?
|
||||
isParameter = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
newArgs[a] = args[a];
|
||||
}
|
||||
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;
|
||||
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]);
|
||||
|
||||
}
|
||||
// else just throw it away
|
||||
}
|
||||
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, we just ignore the other arguments
|
||||
}
|
||||
else {
|
||||
if (argCount > icm->mParameterCount)
|
||||
throw new JSException("Too many arguments in call");
|
||||
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");
|
||||
}
|
||||
callArgs[i] = args[i]; // it's a positional, just slap it in place
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (argCount < icm->mParameterCount)
|
||||
pOffset = icm->mParameterInit[argCount - icm->mNonOptionalParameterCount];
|
||||
uint32 contiguousArgs = 0;
|
||||
for (i = 0; i < args.size(); i++) {
|
||||
Argument &arg = args[i];
|
||||
if (arg.first.first == NotARegister) break;
|
||||
contiguousArgs++;
|
||||
}
|
||||
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], args);
|
||||
mActivation = new Activation(icm, mActivation, (*registers)[op3(call).first], callArgs);
|
||||
registers = &mActivation->mRegisters;
|
||||
mPC = mActivation->mICode->its_iCode->begin() + pOffset;
|
||||
mPC = mActivation->mICode->its_iCode->begin();
|
||||
endPC = mActivation->mICode->its_iCode->end();
|
||||
continue;
|
||||
}
|
||||
|
@ -1036,6 +1073,16 @@ using JSString throughout.
|
|||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_INITIALIZED:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc).first].isInitialized()) {
|
||||
mPC = mActivation->mICode->its_iCode->begin() + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GENERIC_BINARY_OP:
|
||||
{
|
||||
GenericBinaryOP* gbo = static_cast<GenericBinaryOP*>(instruction);
|
||||
|
|
|
@ -504,7 +504,7 @@ Formatter& operator<<(Formatter& f, const JSValue& value)
|
|||
if (i < (a->length() - 1))
|
||||
f << ", ";
|
||||
}
|
||||
f << "]";
|
||||
f << "] {" << *(static_cast<JSObject*>(value.array)) << "}";
|
||||
// printFormat(f, "Array @ 0x%08X", value.array);
|
||||
}
|
||||
break;
|
||||
|
@ -524,6 +524,9 @@ Formatter& operator<<(Formatter& f, const JSValue& value)
|
|||
printFormat(f, "Type @ 0x%08X\n", value.type);
|
||||
f << *value.type;
|
||||
break;
|
||||
case JSValue::uninitialized_tag:
|
||||
f << "uninitialized";
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED("Bad tag");
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ namespace JSTypes {
|
|||
NoHint
|
||||
};
|
||||
|
||||
enum {
|
||||
typedef enum {
|
||||
i8_tag, u8_tag,
|
||||
i16_tag, u16_tag,
|
||||
i32_tag, u32_tag,
|
||||
|
@ -105,8 +105,10 @@ namespace JSTypes {
|
|||
f32_tag, f64_tag,
|
||||
integer_tag,
|
||||
object_tag, array_tag, function_tag, string_tag, boolean_tag, type_tag,
|
||||
undefined_tag
|
||||
} tag;
|
||||
undefined_tag,
|
||||
uninitialized_tag
|
||||
} Tag;
|
||||
Tag tag;
|
||||
|
||||
JSValue() : f64(0.0), tag(undefined_tag) {}
|
||||
explicit JSValue(int32 i32) : i32(i32), tag(i32_tag) {}
|
||||
|
@ -118,6 +120,7 @@ namespace JSTypes {
|
|||
explicit JSValue(JSString* string) : string(string), tag(string_tag) {}
|
||||
explicit JSValue(bool boolean) : boolean(boolean), tag(boolean_tag) {}
|
||||
explicit JSValue(JSType* type) : type(type), tag(type_tag) {}
|
||||
explicit JSValue(Tag tag) : tag(tag) {}
|
||||
|
||||
int32& operator=(int32 i32) { return (tag = i32_tag, this->i32 = i32); }
|
||||
uint32& operator=(uint32 u32) { return (tag = u32_tag, this->u32 = u32); }
|
||||
|
@ -139,6 +142,7 @@ namespace JSTypes {
|
|||
will have to be converted (to doubles?) anyway because
|
||||
we can't have overflow happening in generic arithmetic */
|
||||
|
||||
bool isInitialized() const { return (tag != uninitialized_tag); }
|
||||
bool isUndefined() const { return (tag == undefined_tag); }
|
||||
bool isNull() const { return ((tag == object_tag) && (this->object == NULL)); }
|
||||
bool isNaN() const;
|
||||
|
@ -330,14 +334,15 @@ namespace JSTypes {
|
|||
*/
|
||||
class JSArray : public JSObject {
|
||||
JSValues elements;
|
||||
uint32 top;
|
||||
public:
|
||||
JSArray() : elements(1) {}
|
||||
JSArray(uint32 size) : elements(size) {}
|
||||
JSArray() : elements(1) { top = 0; }
|
||||
JSArray(uint32 size) : elements(size) { top = size; }
|
||||
JSArray(const JSValues &v) : elements(v) {}
|
||||
|
||||
|
||||
uint32 length()
|
||||
{
|
||||
return elements.size();
|
||||
return top;
|
||||
}
|
||||
|
||||
JSValue& operator[](const JSValue& index)
|
||||
|
@ -347,6 +352,7 @@ namespace JSTypes {
|
|||
// obviously, a sparse representation might be better.
|
||||
uint32 size = elements.size();
|
||||
if (n >= size) expand(n, size);
|
||||
markHiEnd(n);
|
||||
return elements[n];
|
||||
}
|
||||
|
||||
|
@ -355,15 +361,23 @@ namespace JSTypes {
|
|||
// obviously, a sparse representation might be better.
|
||||
uint32 size = elements.size();
|
||||
if (n >= size) expand(n, size);
|
||||
markHiEnd(n);
|
||||
return elements[n];
|
||||
}
|
||||
|
||||
void resize(uint32 size)
|
||||
{
|
||||
elements.resize(size);
|
||||
top = size;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void markHiEnd(uint32 index)
|
||||
{
|
||||
if ((index + 1) > top) top = index + 1;
|
||||
}
|
||||
|
||||
void expand(uint32 n, uint32 size)
|
||||
{
|
||||
do {
|
||||
|
|
|
@ -207,13 +207,13 @@ namespace VM {
|
|||
|
||||
virtual Formatter& print(Formatter& f)
|
||||
{
|
||||
f << opcodeNames[mOpcode] << "\tR" << mOp1.first << ", R" << mOp2.first << ", R" << mOp3.first;
|
||||
f << opcodeNames[mOpcode] << "\t" << mOp1 << ", " << mOp2 << ", " << mOp3;
|
||||
return f;
|
||||
}
|
||||
|
||||
virtual Formatter& printOperands(Formatter& f, const JSValues& registers)
|
||||
{
|
||||
f << "R" << mOp1.first << '=' << registers[mOp1.first] << ", " << "R" << mOp2.first << '=' << registers[mOp2.first] << ", " << "R" << mOp3.first << '=' << registers[mOp3.first];
|
||||
f << getRegisterValue(registers, mOp1.first) << ", " << getRegisterValue(registers, mOp2.first) << ", " << getRegisterValue(registers, mOp3.first);
|
||||
return f;
|
||||
}
|
||||
};
|
||||
|
@ -223,13 +223,13 @@ namespace VM {
|
|||
Unary(ICodeOp aOpcode, TypedRegister aDest, TypedRegister aSrc) :
|
||||
Instruction_2<TypedRegister, TypedRegister>(aOpcode, aDest, aSrc) {}
|
||||
virtual Formatter& print (Formatter& f) {
|
||||
f << opcodeNames[mOpcode] << "\tR" << mOp1.first << ", R" << mOp2.first;
|
||||
f << opcodeNames[mOpcode] << "\t" << mOp1 << ", " << mOp2;
|
||||
return f;
|
||||
}
|
||||
|
||||
virtual Formatter& printOperands(Formatter& f, const JSValues& registers)
|
||||
{
|
||||
f << "R" << mOp1.first << '=' << registers[mOp1.first] << ", " << "R" << mOp2.first << '=' << registers[mOp2.first];
|
||||
f << getRegisterValue(registers, mOp1.first) << ", " << getRegisterValue(registers, mOp2.first);
|
||||
return f;
|
||||
}
|
||||
};
|
||||
|
@ -240,19 +240,13 @@ namespace VM {
|
|||
TypedRegister aR = TypedRegister(NotARegister, &Any_Type) ) :
|
||||
Instruction_2<Label*, TypedRegister>(aOpcode, aLabel, aR) {}
|
||||
virtual Formatter& print (Formatter& f) {
|
||||
f << opcodeNames[mOpcode] << "\tOffset " << mOp1->mOffset;
|
||||
if (mOp2.first == NotARegister) {
|
||||
f << ", R~";
|
||||
} else {
|
||||
f << ", R" << mOp2.first;
|
||||
}
|
||||
f << opcodeNames[mOpcode] << "\tOffset " << mOp1->mOffset << ", " << mOp2;
|
||||
return f;
|
||||
}
|
||||
|
||||
virtual Formatter& printOperands(Formatter& f, const JSValues& registers)
|
||||
{
|
||||
if (mOp2.first != NotARegister)
|
||||
f << "R" << mOp2.first << '=' << registers[mOp2.first];
|
||||
f << getRegisterValue(registers, mOp2.first);
|
||||
return f;
|
||||
}
|
||||
|
||||
|
|
|
@ -537,6 +537,16 @@ GenericBranch *ICodeGenerator::branchFalse(Label *label, TypedRegister condition
|
|||
return instr;
|
||||
}
|
||||
|
||||
GenericBranch *ICodeGenerator::branchInitialized(Label *label, TypedRegister condition)
|
||||
{
|
||||
GenericBranch *instr = new GenericBranch(BRANCH_INITIALIZED, label, condition);
|
||||
iCode->push_back(instr);
|
||||
return instr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void ICodeGenerator::returnStmt(TypedRegister r)
|
||||
{
|
||||
iCode->push_back(new Return(r));
|
||||
|
@ -1620,9 +1630,20 @@ ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor
|
|||
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()));
|
||||
TypedRegister p = icg.genExpr(v->name);
|
||||
if (v->initializer) { // might be NULL when we get to the restParameter
|
||||
TypedRegister p = icg.genExpr(v->name);
|
||||
Label *l = icg.getLabel();
|
||||
icg.branchInitialized(l, p);
|
||||
icg.move(p, icg.genExpr(v->initializer));
|
||||
icg.setLabel(l);
|
||||
}
|
||||
else { // an un-initialized rest parameter is still an empty array
|
||||
if (v == f->function.restParameter) {
|
||||
Label *l = icg.getLabel();
|
||||
icg.branchInitialized(l, p);
|
||||
icg.move(p, icg.newArray());
|
||||
icg.setLabel(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
v = v->next;
|
||||
|
|
|
@ -187,6 +187,7 @@ namespace ICG {
|
|||
void branch(Label *label);
|
||||
GenericBranch *branchTrue(Label *label, TypedRegister condition);
|
||||
GenericBranch *branchFalse(Label *label, TypedRegister condition);
|
||||
GenericBranch *branchInitialized(Label *label, TypedRegister condition);
|
||||
|
||||
void beginTry(Label *catchLabel, Label *finallyLabel)
|
||||
{ iCode->push_back(new Tryin(catchLabel, finallyLabel)); }
|
||||
|
|
|
@ -105,7 +105,11 @@ struct Activation : public gc_base {
|
|||
const JSValues& params = caller->mRegisters;
|
||||
for (ArgumentList::const_iterator src = list.begin(),
|
||||
end = list.end(); src != end; ++src, ++dest) {
|
||||
*dest = params[(*src).first.first];
|
||||
Register r = (*src).first.first;
|
||||
if (r != NotARegister)
|
||||
*dest = params[r];
|
||||
else
|
||||
*dest = JSValue(JSValue::uninitialized_tag);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -692,56 +696,89 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
|||
else {
|
||||
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);
|
||||
}
|
||||
// mParameterCount includes 'this' and also 1 for a named rest parameter
|
||||
//
|
||||
uint32 pCount = icm->mParameterCount - 1;
|
||||
ArgumentList callArgs(pCount, Argument(TypedRegister(NotARegister, &Null_Type), NULL));
|
||||
if (icm->mHasNamedRestParameter) pCount--;
|
||||
|
||||
|
||||
// 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;
|
||||
uint32 i;
|
||||
for (i = 0; i < args.size(); i++) {
|
||||
if (args[i].second) { // a named argument
|
||||
VariableList::iterator vi = icm->itsVariables->find(*(args[i].second));
|
||||
bool isParameter = false;
|
||||
if (vi != icm->itsVariables->end()) { // we found the name in the target's list of variables
|
||||
TypedRegister r = (*vi).second;
|
||||
if (r.first < 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)...
|
||||
callArgs[r.first - 1] = Argument(args[i].first, NULL); // no need to copy the name through?
|
||||
isParameter = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
newArgs[a] = args[a];
|
||||
}
|
||||
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;
|
||||
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]);
|
||||
|
||||
}
|
||||
// else just throw it away
|
||||
}
|
||||
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, we just ignore the other arguments
|
||||
}
|
||||
else {
|
||||
if (argCount > icm->mParameterCount)
|
||||
throw new JSException("Too many arguments in call");
|
||||
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");
|
||||
}
|
||||
callArgs[i] = args[i]; // it's a positional, just slap it in place
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (argCount < icm->mParameterCount)
|
||||
pOffset = icm->mParameterInit[argCount - icm->mNonOptionalParameterCount];
|
||||
uint32 contiguousArgs = 0;
|
||||
for (i = 0; i < args.size(); i++) {
|
||||
Argument &arg = args[i];
|
||||
if (arg.first.first == NotARegister) break;
|
||||
contiguousArgs++;
|
||||
}
|
||||
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], args);
|
||||
mActivation = new Activation(icm, mActivation, (*registers)[op3(call).first], callArgs);
|
||||
registers = &mActivation->mRegisters;
|
||||
mPC = mActivation->mICode->its_iCode->begin() + pOffset;
|
||||
mPC = mActivation->mICode->its_iCode->begin();
|
||||
endPC = mActivation->mICode->its_iCode->end();
|
||||
continue;
|
||||
}
|
||||
|
@ -1036,6 +1073,16 @@ using JSString throughout.
|
|||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_INITIALIZED:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc).first].isInitialized()) {
|
||||
mPC = mActivation->mICode->its_iCode->begin() + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GENERIC_BINARY_OP:
|
||||
{
|
||||
GenericBinaryOP* gbo = static_cast<GenericBinaryOP*>(instruction);
|
||||
|
|
|
@ -504,7 +504,7 @@ Formatter& operator<<(Formatter& f, const JSValue& value)
|
|||
if (i < (a->length() - 1))
|
||||
f << ", ";
|
||||
}
|
||||
f << "]";
|
||||
f << "] {" << *(static_cast<JSObject*>(value.array)) << "}";
|
||||
// printFormat(f, "Array @ 0x%08X", value.array);
|
||||
}
|
||||
break;
|
||||
|
@ -524,6 +524,9 @@ Formatter& operator<<(Formatter& f, const JSValue& value)
|
|||
printFormat(f, "Type @ 0x%08X\n", value.type);
|
||||
f << *value.type;
|
||||
break;
|
||||
case JSValue::uninitialized_tag:
|
||||
f << "uninitialized";
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED("Bad tag");
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ namespace JSTypes {
|
|||
NoHint
|
||||
};
|
||||
|
||||
enum {
|
||||
typedef enum {
|
||||
i8_tag, u8_tag,
|
||||
i16_tag, u16_tag,
|
||||
i32_tag, u32_tag,
|
||||
|
@ -105,8 +105,10 @@ namespace JSTypes {
|
|||
f32_tag, f64_tag,
|
||||
integer_tag,
|
||||
object_tag, array_tag, function_tag, string_tag, boolean_tag, type_tag,
|
||||
undefined_tag
|
||||
} tag;
|
||||
undefined_tag,
|
||||
uninitialized_tag
|
||||
} Tag;
|
||||
Tag tag;
|
||||
|
||||
JSValue() : f64(0.0), tag(undefined_tag) {}
|
||||
explicit JSValue(int32 i32) : i32(i32), tag(i32_tag) {}
|
||||
|
@ -118,6 +120,7 @@ namespace JSTypes {
|
|||
explicit JSValue(JSString* string) : string(string), tag(string_tag) {}
|
||||
explicit JSValue(bool boolean) : boolean(boolean), tag(boolean_tag) {}
|
||||
explicit JSValue(JSType* type) : type(type), tag(type_tag) {}
|
||||
explicit JSValue(Tag tag) : tag(tag) {}
|
||||
|
||||
int32& operator=(int32 i32) { return (tag = i32_tag, this->i32 = i32); }
|
||||
uint32& operator=(uint32 u32) { return (tag = u32_tag, this->u32 = u32); }
|
||||
|
@ -139,6 +142,7 @@ namespace JSTypes {
|
|||
will have to be converted (to doubles?) anyway because
|
||||
we can't have overflow happening in generic arithmetic */
|
||||
|
||||
bool isInitialized() const { return (tag != uninitialized_tag); }
|
||||
bool isUndefined() const { return (tag == undefined_tag); }
|
||||
bool isNull() const { return ((tag == object_tag) && (this->object == NULL)); }
|
||||
bool isNaN() const;
|
||||
|
@ -330,14 +334,15 @@ namespace JSTypes {
|
|||
*/
|
||||
class JSArray : public JSObject {
|
||||
JSValues elements;
|
||||
uint32 top;
|
||||
public:
|
||||
JSArray() : elements(1) {}
|
||||
JSArray(uint32 size) : elements(size) {}
|
||||
JSArray() : elements(1) { top = 0; }
|
||||
JSArray(uint32 size) : elements(size) { top = size; }
|
||||
JSArray(const JSValues &v) : elements(v) {}
|
||||
|
||||
|
||||
uint32 length()
|
||||
{
|
||||
return elements.size();
|
||||
return top;
|
||||
}
|
||||
|
||||
JSValue& operator[](const JSValue& index)
|
||||
|
@ -347,6 +352,7 @@ namespace JSTypes {
|
|||
// obviously, a sparse representation might be better.
|
||||
uint32 size = elements.size();
|
||||
if (n >= size) expand(n, size);
|
||||
markHiEnd(n);
|
||||
return elements[n];
|
||||
}
|
||||
|
||||
|
@ -355,15 +361,23 @@ namespace JSTypes {
|
|||
// obviously, a sparse representation might be better.
|
||||
uint32 size = elements.size();
|
||||
if (n >= size) expand(n, size);
|
||||
markHiEnd(n);
|
||||
return elements[n];
|
||||
}
|
||||
|
||||
void resize(uint32 size)
|
||||
{
|
||||
elements.resize(size);
|
||||
top = size;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void markHiEnd(uint32 index)
|
||||
{
|
||||
if ((index + 1) > top) top = index + 1;
|
||||
}
|
||||
|
||||
void expand(uint32 n, uint32 size)
|
||||
{
|
||||
do {
|
||||
|
|
|
@ -207,13 +207,13 @@ namespace VM {
|
|||
|
||||
virtual Formatter& print(Formatter& f)
|
||||
{
|
||||
f << opcodeNames[mOpcode] << "\tR" << mOp1.first << ", R" << mOp2.first << ", R" << mOp3.first;
|
||||
f << opcodeNames[mOpcode] << "\t" << mOp1 << ", " << mOp2 << ", " << mOp3;
|
||||
return f;
|
||||
}
|
||||
|
||||
virtual Formatter& printOperands(Formatter& f, const JSValues& registers)
|
||||
{
|
||||
f << "R" << mOp1.first << '=' << registers[mOp1.first] << ", " << "R" << mOp2.first << '=' << registers[mOp2.first] << ", " << "R" << mOp3.first << '=' << registers[mOp3.first];
|
||||
f << getRegisterValue(registers, mOp1.first) << ", " << getRegisterValue(registers, mOp2.first) << ", " << getRegisterValue(registers, mOp3.first);
|
||||
return f;
|
||||
}
|
||||
};
|
||||
|
@ -223,13 +223,13 @@ namespace VM {
|
|||
Unary(ICodeOp aOpcode, TypedRegister aDest, TypedRegister aSrc) :
|
||||
Instruction_2<TypedRegister, TypedRegister>(aOpcode, aDest, aSrc) {}
|
||||
virtual Formatter& print (Formatter& f) {
|
||||
f << opcodeNames[mOpcode] << "\tR" << mOp1.first << ", R" << mOp2.first;
|
||||
f << opcodeNames[mOpcode] << "\t" << mOp1 << ", " << mOp2;
|
||||
return f;
|
||||
}
|
||||
|
||||
virtual Formatter& printOperands(Formatter& f, const JSValues& registers)
|
||||
{
|
||||
f << "R" << mOp1.first << '=' << registers[mOp1.first] << ", " << "R" << mOp2.first << '=' << registers[mOp2.first];
|
||||
f << getRegisterValue(registers, mOp1.first) << ", " << getRegisterValue(registers, mOp2.first);
|
||||
return f;
|
||||
}
|
||||
};
|
||||
|
@ -240,19 +240,13 @@ namespace VM {
|
|||
TypedRegister aR = TypedRegister(NotARegister, &Any_Type) ) :
|
||||
Instruction_2<Label*, TypedRegister>(aOpcode, aLabel, aR) {}
|
||||
virtual Formatter& print (Formatter& f) {
|
||||
f << opcodeNames[mOpcode] << "\tOffset " << mOp1->mOffset;
|
||||
if (mOp2.first == NotARegister) {
|
||||
f << ", R~";
|
||||
} else {
|
||||
f << ", R" << mOp2.first;
|
||||
}
|
||||
f << opcodeNames[mOpcode] << "\tOffset " << mOp1->mOffset << ", " << mOp2;
|
||||
return f;
|
||||
}
|
||||
|
||||
virtual Formatter& printOperands(Formatter& f, const JSValues& registers)
|
||||
{
|
||||
if (mOp2.first != NotARegister)
|
||||
f << "R" << mOp2.first << '=' << registers[mOp2.first];
|
||||
f << getRegisterValue(registers, mOp2.first);
|
||||
return f;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче