зеркало из https://github.com/mozilla/gecko-dev.git
Fixed parameter handling to match new syntax.
This commit is contained in:
Родитель
58605d70d3
Коммит
3f2aa66262
|
@ -602,7 +602,7 @@ void ByteCodeGen::genCodeForFunction(FunctionDefinition &f, size_t pos, JSFuncti
|
|||
// Make sure there's a default constructor with 0 (required) parameters
|
||||
JSFunction *superConstructor = superClass->getDefaultConstructor();
|
||||
if (superConstructor) {
|
||||
if (superConstructor->getRequiredArgumentCount() > 0)
|
||||
if (superConstructor->getRequiredParameterCount() > 0)
|
||||
m_cx->reportError(Exception::typeError, "Super class default constructor must be called explicitly - it has required parameters that must be specified", pos);
|
||||
addOp(LoadThisOp);
|
||||
addOp(LoadFunctionOp);
|
||||
|
@ -641,7 +641,7 @@ void ByteCodeGen::genCodeForFunction(FunctionDefinition &f, size_t pos, JSFuncti
|
|||
if (v->initializer) {
|
||||
// this code gets executed if the function is called without
|
||||
// an argument for this parameter.
|
||||
fnc->setArgumentInitializer(index, currentOffset());
|
||||
fnc->setParameterInitializer(index, currentOffset());
|
||||
genExpr(v->initializer);
|
||||
addOpSetDepth(ReturnOp, 0);
|
||||
}
|
||||
|
@ -2269,7 +2269,7 @@ BinaryOpEquals:
|
|||
uint32 reqArgCount = 0;
|
||||
uint32 optArgCount = 0;
|
||||
uint32 namedArgCount = 0;
|
||||
|
||||
/*
|
||||
VariableBinding *b = f->function.parameters;
|
||||
while (b != f->function.optParameters) {
|
||||
reqArgCount++;
|
||||
|
@ -2286,8 +2286,11 @@ BinaryOpEquals:
|
|||
}
|
||||
fnc->setArgCounts(m_cx, reqArgCount, optArgCount, namedArgCount,
|
||||
f->function.restParameter != f->function.namedParameters, f->function.restIsNamed);
|
||||
*/
|
||||
fnc->countParameters(m_cx, f->function);
|
||||
|
||||
if (mScopeChain->isPossibleUncheckedFunction(&f->function))
|
||||
|
||||
if (mScopeChain->isPossibleUncheckedFunction(f->function))
|
||||
fnc->setIsPrototype(true);
|
||||
|
||||
m_cx->buildRuntimeForFunction(f->function, fnc);
|
||||
|
|
|
@ -275,116 +275,144 @@ JSValue Context::interpret(JS2Runtime::ByteCodeModule *bcm, int offset, ScopeCha
|
|||
return result;
|
||||
}
|
||||
|
||||
// Assumes arguments are on the top of stack.
|
||||
// Assumes arguments are on the top of stack. argCount is the number that were pushed by user code
|
||||
JSValue *Context::buildArgumentBlock(JSFunction *target, uint32 &argCount)
|
||||
{
|
||||
JSValue *argBase;
|
||||
uint32 maxExpectedArgCount = target->getRequiredArgumentCount() + target->getOptionalArgumentCount();
|
||||
uint32 maxExpectedParameterCount = target->getRequiredParameterCount() + target->getOptionalParameterCount() + target->getNamedParameterCount();
|
||||
if (target->isChecked()) {
|
||||
if (argCount < target->getRequiredArgumentCount())
|
||||
if (argCount < target->getRequiredParameterCount())
|
||||
reportError(Exception::referenceError, "Insufficient quantity of arguments");
|
||||
|
||||
if ((argCount > maxExpectedArgCount) && !target->hasRestParameter())
|
||||
if ((argCount > maxExpectedParameterCount) && !target->hasRestParameter())
|
||||
reportError(Exception::referenceError, "Oversufficient quantity of arguments");
|
||||
}
|
||||
|
||||
uint32 i;
|
||||
uint32 argBlockSize = max(argCount, maxExpectedArgCount) + (target->hasRestParameter() ? 1 : 0);
|
||||
// room for all required & optional arguments
|
||||
uint32 argBlockSize = max(argCount, maxExpectedParameterCount) + (target->hasRestParameter() ? 1 : 0);
|
||||
// room for all required,optional & named arguments
|
||||
// plus the rest parameter if it exists.
|
||||
argBase = new JSValue[argBlockSize];
|
||||
|
||||
/*
|
||||
* If the first parameter is required and no positional argument has been supplied for it, then raise an error unless the function
|
||||
* is unchecked, in which case let undefined be the first parameter’s value.
|
||||
*
|
||||
* If the first parameter is optional and there is a positional argument remaining, use the value of the positional argument
|
||||
* and raise an error if there is also a named argument with a matching argument name. If there are no remaining positional
|
||||
* arguments, then if there is a named argument with a matching argument name, use the value of that named argument. Otherwise,
|
||||
* evaluate the first parameter’s AssignmentExpression and let it be the first parameter’s value.
|
||||
*
|
||||
* Implicitly coerce the argument (or default) value to type t and bind the parameter’s Identifier to the result.
|
||||
*/
|
||||
uint32 inArgIndex = 0;
|
||||
uint32 argStart = stackSize() - argCount;
|
||||
bool *argUsed = new bool[argCount];
|
||||
for (i = 0; i < argCount; i++)
|
||||
argUsed[i] = false;
|
||||
uint32 argStart = stackSize() - argCount;
|
||||
uint32 argIndex = 0; // the index into argBase, the resolved outgoing arguments
|
||||
uint32 posArgIndex = 0; // next positional arg from the incoming set
|
||||
for (i = 0; i < argCount; i++) { // find the first positional (i.e. non-named arg)
|
||||
JSValue v = getValue(i + argStart);
|
||||
if (!v.isObject() || (v.object->mType != NamedArgument_Type)) {
|
||||
posArgIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// for each parameter - see if there's a named arg that matches
|
||||
// otherwise take the next non-named argument. (unless the parameter
|
||||
// is an optional one)
|
||||
while (argIndex < maxExpectedArgCount) {
|
||||
bool foundNamedArg = false;
|
||||
// find a matching named argument
|
||||
for (uint32 i = 0; i < argCount; i++) {
|
||||
JSValue v = getValue(i + argStart);
|
||||
if (v.isObject() && (v.object->mType == NamedArgument_Type)) {
|
||||
NamedArgument *arg = static_cast<NamedArgument *>(v.object);
|
||||
if (target->findParameterName(arg->mName) == argIndex) {
|
||||
// mark this arg has having been used
|
||||
argUsed[i] = true;
|
||||
foundNamedArg = true;
|
||||
argBase[argIndex] = arg->mValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!foundNamedArg) {
|
||||
if (target->argHasInitializer(argIndex)) {
|
||||
argBase[argIndex] = target->runArgInitializer(this, argIndex, mThis, argBase, maxExpectedArgCount);
|
||||
}
|
||||
else {
|
||||
if (posArgIndex < argCount) {
|
||||
argUsed[posArgIndex] = true;
|
||||
argBase[argIndex] = getValue(posArgIndex++ + argStart);
|
||||
argUsed[i] = false;
|
||||
uint32 restParameterIndex;
|
||||
|
||||
uint32 pCount = maxExpectedParameterCount + (target->hasRestParameter() ? 1 : 0);
|
||||
for (uint32 pIndex = 0; pIndex < pCount; pIndex++) {
|
||||
bool needDefault = true;
|
||||
if (target->parameterIsRequired(pIndex)) {
|
||||
if (inArgIndex < argCount) {
|
||||
JSValue v = getValue(inArgIndex + argStart);
|
||||
bool isPositionalArg = !(v.isObject() && (v.object->mType == NamedArgument_Type));
|
||||
// if the next argument is named, then we've run out of positional args
|
||||
if (!isPositionalArg) {
|
||||
if (!target->isChecked())
|
||||
needDefault = false; // the undefined value is already assigned in the arg block
|
||||
}
|
||||
else {
|
||||
if (target->isChecked())
|
||||
reportError(Exception::referenceError, "Missing positional argument");
|
||||
else
|
||||
argBase[argIndex] = kUndefinedValue;
|
||||
argBase[pIndex] = getValue(inArgIndex + argStart);
|
||||
argUsed[inArgIndex++] = true;
|
||||
needDefault = false;
|
||||
}
|
||||
}
|
||||
if (needDefault)
|
||||
reportError(Exception::referenceError, "missing required argument");
|
||||
}
|
||||
argIndex++;
|
||||
else {
|
||||
if (target->parameterIsOptional(pIndex)) {
|
||||
bool tookPositionalArg = false;
|
||||
if (inArgIndex < argCount) {
|
||||
JSValue v = getValue(inArgIndex + argStart);
|
||||
if (!(v.isObject() && (v.object->mType == NamedArgument_Type))) {
|
||||
argBase[pIndex] = v;
|
||||
argUsed[inArgIndex++] = true;
|
||||
needDefault = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (target->parameterIsNamed(pIndex)) {
|
||||
const String *parameterName = target->getParameterName(pIndex);
|
||||
for (uint32 i = inArgIndex; i < argCount; i++) {
|
||||
if (!argUsed[i]) {
|
||||
JSValue v = getValue(i + argStart);
|
||||
if (v.isObject() && (v.object->mType == NamedArgument_Type)) {
|
||||
NamedArgument *arg = static_cast<NamedArgument *>(v.object);
|
||||
if (arg->mName == parameterName) {
|
||||
argBase[pIndex] = arg->mValue;
|
||||
argUsed[i] = true;
|
||||
needDefault = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
restParameterIndex = pIndex;
|
||||
}
|
||||
}
|
||||
if (needDefault)
|
||||
if (target->parameterHasInitializer(pIndex))
|
||||
argBase[pIndex] = target->runParameterInitializer(this, pIndex, mThis, argBase, maxExpectedParameterCount);
|
||||
}
|
||||
|
||||
// now find a place for any left-overs:
|
||||
/*
|
||||
* If there is a RestParameter with a type that does not allow the dynamic addition of named properties and one or more of the
|
||||
* remaining arguments is named, raise an error.
|
||||
*
|
||||
* If there is a RestParameter with an Identifier, bind that Identifier to an array of the remaining positional and/or named
|
||||
* arguments. The remaining positional arguments are assigned indices starting from 0.
|
||||
*
|
||||
* If there is no RestParameter and any arguments remain, raise an error unless the function is unchecked.
|
||||
*/
|
||||
|
||||
JSValue restArgument;
|
||||
if (target->hasRestParameter() && target->getRestParameterName()) {
|
||||
restArgument = target->getRestParameterType()->newInstance(this);
|
||||
argBase[maxExpectedArgCount] = JSValue(restArgument);
|
||||
bool haveRestArg = false;
|
||||
|
||||
if (target->hasRestParameter() && target->getParameterName(restParameterIndex)) {
|
||||
restArgument = target->getParameterType(restParameterIndex)->newInstance(this);
|
||||
argBase[restParameterIndex] = JSValue(restArgument);
|
||||
haveRestArg = true;
|
||||
}
|
||||
posArgIndex = 0; // re-number the non-named arguments that end up in the rest arg
|
||||
// now find a place for any left-overs
|
||||
inArgIndex = 0; // re-number the non-named arguments that end up in the rest arg
|
||||
for (i = 0; i < argCount; i++) {
|
||||
if (!argUsed[i]) {
|
||||
JSValue v = getValue(i + argStart);
|
||||
if (v.isObject() && (v.object->mType == NamedArgument_Type)) {
|
||||
bool isNamedArg = v.isObject() && (v.object->mType == NamedArgument_Type);
|
||||
if (isNamedArg) {
|
||||
NamedArgument *arg = static_cast<NamedArgument *>(v.object);
|
||||
// if this argument matches a parameter name, that's bad because
|
||||
// it's a duplicate case
|
||||
if (target->findParameterName(arg->mName) != NotABanana)
|
||||
reportError(Exception::referenceError, "Duplicate named argument");
|
||||
else {
|
||||
if (target->hasRestParameter()) {
|
||||
if (!restArgument.isUndefined())
|
||||
// XXX is it an error to have duplicate named rest properties?
|
||||
restArgument.object->setProperty(this, *arg->mName, (NamespaceList *)(NULL), arg->mValue);
|
||||
}
|
||||
else
|
||||
reportError(Exception::referenceError, "Unknown named argument, no rest argument");
|
||||
}
|
||||
if (haveRestArg)
|
||||
restArgument.object->setProperty(this, *arg->mName, (NamespaceList *)(NULL), arg->mValue);
|
||||
else
|
||||
reportError(Exception::referenceError, "Unused named argument, no rest argument");
|
||||
}
|
||||
else {
|
||||
if (target->hasRestParameter()) {
|
||||
if (!restArgument.isUndefined()) {
|
||||
const String *id = numberToString(posArgIndex++);
|
||||
restArgument.object->setProperty(this, *id, (NamespaceList *)(NULL), v);
|
||||
}
|
||||
if (haveRestArg) {
|
||||
const String *id = numberToString(inArgIndex++);
|
||||
restArgument.object->setProperty(this, *id, (NamespaceList *)(NULL), v);
|
||||
}
|
||||
else {
|
||||
if (target->isChecked())
|
||||
reportError(Exception::referenceError, "Extra argument, no rest argument");
|
||||
else {
|
||||
JSValue v = getValue(i + argStart);
|
||||
if (v.isObject() && (v.object->mType == NamedArgument_Type)) {
|
||||
if (isNamedArg) {
|
||||
NamedArgument *arg = static_cast<NamedArgument *>(v.object);
|
||||
argBase[i] = arg->mValue;
|
||||
}
|
||||
|
@ -395,6 +423,7 @@ JSValue *Context::buildArgumentBlock(JSFunction *target, uint32 &argCount)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
argCount = argBlockSize;
|
||||
return argBase;
|
||||
}
|
||||
|
|
|
@ -350,7 +350,7 @@ Reference *JSObject::genReference(bool hasBase, const String& name, NamespaceLis
|
|||
return new GetterFunctionReference(prop->mData.fPair.getterF, prop->mAttributes);
|
||||
else {
|
||||
JSFunction *f = prop->mData.fPair.setterF;
|
||||
return new SetterFunctionReference(f, f->getArgType(0), prop->mAttributes);
|
||||
return new SetterFunctionReference(f, f->getParameterType(0), prop->mAttributes);
|
||||
}
|
||||
default:
|
||||
NOT_REACHED("bad storage kind");
|
||||
|
@ -948,15 +948,15 @@ JS2Runtime::ByteCodeModule *Context::genCode(StmtNode *p, const String &/*source
|
|||
the function does not have a declared return type;
|
||||
the function is not a getter or setter.
|
||||
*/
|
||||
bool ScopeChain::isPossibleUncheckedFunction(FunctionDefinition *f)
|
||||
bool ScopeChain::isPossibleUncheckedFunction(FunctionDefinition &f)
|
||||
{
|
||||
bool result = false;
|
||||
if ((f->resultType == NULL)
|
||||
&& (f->optParameters == NULL)
|
||||
&& (f->prefix == FunctionName::normal)
|
||||
if ((f.resultType == NULL)
|
||||
&& (f.optParameters == NULL)
|
||||
&& (f.prefix == FunctionName::normal)
|
||||
&& (topClass() == NULL)) {
|
||||
result = true;
|
||||
VariableBinding *b = f->parameters;
|
||||
VariableBinding *b = f.parameters;
|
||||
while (b) {
|
||||
if (b->type != NULL) {
|
||||
result = false;
|
||||
|
@ -968,6 +968,29 @@ bool ScopeChain::isPossibleUncheckedFunction(FunctionDefinition *f)
|
|||
return result;
|
||||
}
|
||||
|
||||
void JSFunction::countParameters(Context *cx, FunctionDefinition &f)
|
||||
{
|
||||
uint32 requiredParameterCount = 0;
|
||||
uint32 optionalParameterCount = 0;
|
||||
uint32 namedParameterCount = 0;
|
||||
|
||||
VariableBinding *b = f.parameters;
|
||||
while (b != f.optParameters) {
|
||||
requiredParameterCount++;
|
||||
b = b->next;
|
||||
}
|
||||
while (b != f.restParameter) {
|
||||
optionalParameterCount++;
|
||||
b = b->next;
|
||||
}
|
||||
b = f.namedParameters;
|
||||
while (b) {
|
||||
namedParameterCount++;
|
||||
b = b->next;
|
||||
}
|
||||
setParameterCounts(cx, requiredParameterCount, optionalParameterCount, namedParameterCount, f.restParameter != f.namedParameters);
|
||||
}
|
||||
|
||||
// The first pass over the tree - it just installs the names of each declaration
|
||||
void ScopeChain::collectNames(StmtNode *p)
|
||||
{
|
||||
|
@ -1094,36 +1117,17 @@ void ScopeChain::collectNames(StmtNode *p)
|
|||
*/
|
||||
if (!isPrototype
|
||||
&& (!isOperator)
|
||||
&& isPossibleUncheckedFunction(&f->function)) {
|
||||
&& isPossibleUncheckedFunction(f->function)) {
|
||||
isPrototype = true;
|
||||
fnc->setIsUnchecked();
|
||||
}
|
||||
|
||||
fnc->setIsPrototype(isPrototype);
|
||||
fnc->setIsConstructor(isConstructor);
|
||||
fnc->setFunctionName(&f->function);
|
||||
fnc->setFunctionName(f->function);
|
||||
f->mFunction = fnc;
|
||||
|
||||
uint32 reqArgCount = 0;
|
||||
uint32 optArgCount = 0;
|
||||
uint32 namedArgCount = 0;
|
||||
|
||||
VariableBinding *b = f->function.parameters;
|
||||
while (b != f->function.optParameters) {
|
||||
reqArgCount++;
|
||||
b = b->next;
|
||||
}
|
||||
while (b != f->function.restParameter) {
|
||||
optArgCount++;
|
||||
b = b->next;
|
||||
}
|
||||
b = f->function.namedParameters;
|
||||
while (b) {
|
||||
namedArgCount++;
|
||||
b = b->next;
|
||||
}
|
||||
fnc->setArgCounts(m_cx, reqArgCount, optArgCount, namedArgCount,
|
||||
f->function.restParameter != f->function.namedParameters, f->function.restIsNamed);
|
||||
fnc->countParameters(m_cx, f->function);
|
||||
|
||||
if (isOperator) {
|
||||
// no need to do anything yet, all operators are 'pre-declared'
|
||||
|
@ -1203,7 +1207,7 @@ void ScopeChain::collectNames(StmtNode *p)
|
|||
// make a function into a const declaration, but only if any types
|
||||
// have been specified - otherwise it's a 1.5 atyle definition and
|
||||
// duplicates are allowed
|
||||
if (!isPossibleUncheckedFunction(&f->function))
|
||||
if (!isPossibleUncheckedFunction(f->function))
|
||||
f->attributeValue->mTrueFlags |= Property::Const;
|
||||
if (isStatic)
|
||||
defineStaticMethod(m_cx, name, f, fnc);
|
||||
|
@ -1400,7 +1404,7 @@ Reference *JSType::genReference(bool hasBase, const String& name, NamespaceList
|
|||
return new GetterFunctionReference(prop->mData.fPair.getterF, prop->mAttributes);
|
||||
else {
|
||||
JSFunction *f = prop->mData.fPair.setterF;
|
||||
return new SetterFunctionReference(f, f->getArgType(0), prop->mAttributes);
|
||||
return new SetterFunctionReference(f, f->getParameterType(0), prop->mAttributes);
|
||||
}
|
||||
case ValuePointer:
|
||||
return new StaticFieldReference(name, acc, this, prop->mType, prop->mAttributes);
|
||||
|
@ -1410,7 +1414,7 @@ Reference *JSType::genReference(bool hasBase, const String& name, NamespaceList
|
|||
return new GetterMethodReference(prop->mData.iPair.getterI, this, prop->mType, prop->mAttributes);
|
||||
else {
|
||||
JSFunction *f = mMethods[prop->mData.iPair.setterI];
|
||||
return new SetterMethodReference(prop->mData.iPair.setterI, this, f->getArgType(0), prop->mAttributes);
|
||||
return new SetterMethodReference(prop->mData.iPair.setterI, this, f->getParameterType(0), prop->mAttributes);
|
||||
}
|
||||
case Slot:
|
||||
return new FieldReference(prop->mData.index, acc, prop->mType, prop->mAttributes);
|
||||
|
@ -1679,9 +1683,18 @@ void Context::buildRuntimeForStmt(StmtNode *p)
|
|||
|
||||
VariableBinding *v = f->function.parameters;
|
||||
uint32 parameterCount = 0;
|
||||
JSFunction::ParameterFlag flag = JSFunction::RequiredParameter;
|
||||
while (v) {
|
||||
// XXX if no type is specified for the rest parameter - is it Array?
|
||||
fnc->setArgument(parameterCount++, v->name, mScopeChain->extractType(v->type));
|
||||
if (v == f->function.optParameters)
|
||||
flag = JSFunction::OptionalParameter;
|
||||
else
|
||||
if (v == f->function.restParameter)
|
||||
flag = JSFunction::RestParameter;
|
||||
else
|
||||
if (v == f->function.namedParameters)
|
||||
flag = JSFunction::NamedParameter;
|
||||
fnc->setParameter(parameterCount++, v->name, mScopeChain->extractType(v->type), flag);
|
||||
v = v->next;
|
||||
}
|
||||
|
||||
|
@ -1926,28 +1939,10 @@ static JSValue Function_Constructor(Context *cx, const JSValue& thisValue, JSVal
|
|||
|
||||
fnc = new JSFunction(cx, NULL, cx->mScopeChain);
|
||||
|
||||
uint32 reqArgCount = 0;
|
||||
uint32 optArgCount = 0;
|
||||
uint32 namedArgCount = 0;
|
||||
fnc->countParameters(cx, f->function);
|
||||
|
||||
VariableBinding *b = f->function.parameters;
|
||||
while (b != f->function.optParameters) {
|
||||
reqArgCount++;
|
||||
b = b->next;
|
||||
}
|
||||
while (b != f->function.restParameter) {
|
||||
optArgCount++;
|
||||
b = b->next;
|
||||
}
|
||||
b = f->function.namedParameters;
|
||||
while (b) {
|
||||
namedArgCount++;
|
||||
b = b->next;
|
||||
}
|
||||
fnc->setArgCounts(cx, reqArgCount, optArgCount, namedArgCount,
|
||||
f->function.restParameter != f->function.namedParameters, f->function.restIsNamed);
|
||||
|
||||
if (cx->mScopeChain->isPossibleUncheckedFunction(&f->function)) {
|
||||
if (cx->mScopeChain->isPossibleUncheckedFunction(f->function)) {
|
||||
fnc->setIsPrototype(true);
|
||||
fnc->setIsUnchecked();
|
||||
}
|
||||
|
@ -2463,15 +2458,15 @@ JSFunction::JSFunction(Context *, JSType *resultType, ScopeChain *scopeChain)
|
|||
mByteCode(NULL),
|
||||
mCode(NULL),
|
||||
mResultType(resultType),
|
||||
mRequiredArgs(0),
|
||||
mOptionalArgs(0),
|
||||
mArguments(NULL),
|
||||
mRequiredParameters(0),
|
||||
mOptionalParameters(0),
|
||||
mNamedParameters(0),
|
||||
mParameters(NULL),
|
||||
mScopeChain(NULL),
|
||||
mIsPrototype(false),
|
||||
mIsConstructor(false),
|
||||
mIsChecked(true),
|
||||
mHasRestParameter(false),
|
||||
mRestParameterName(NULL),
|
||||
mClass(NULL),
|
||||
mFunctionName(NULL)
|
||||
{
|
||||
|
@ -2490,15 +2485,15 @@ JSFunction::JSFunction(Context *, NativeCode *code, JSType *resultType)
|
|||
mByteCode(NULL),
|
||||
mCode(code),
|
||||
mResultType(resultType),
|
||||
mRequiredArgs(0),
|
||||
mOptionalArgs(0),
|
||||
mArguments(NULL),
|
||||
mRequiredParameters(0),
|
||||
mOptionalParameters(0),
|
||||
mNamedParameters(0),
|
||||
mParameters(NULL),
|
||||
mScopeChain(NULL),
|
||||
mIsPrototype(false),
|
||||
mIsConstructor(false),
|
||||
mIsChecked(false), // native functions aren't checked (?)
|
||||
mHasRestParameter(false),
|
||||
mRestParameterName(NULL),
|
||||
mClass(NULL),
|
||||
mFunctionName(NULL)
|
||||
{
|
||||
|
@ -2507,34 +2502,24 @@ JSFunction::JSFunction(Context *, NativeCode *code, JSType *resultType)
|
|||
mActivation.mContainer = this;
|
||||
}
|
||||
|
||||
JSValue JSFunction::runArgInitializer(Context *cx, uint32 a, const JSValue& thisValue, JSValue *argv, uint32 argc)
|
||||
JSValue JSFunction::runParameterInitializer(Context *cx, uint32 a, const JSValue& thisValue, JSValue *argv, uint32 argc)
|
||||
{
|
||||
ASSERT(mArguments && (a < (mRequiredArgs + mOptionalArgs)));
|
||||
return cx->interpret(getByteCode(), (int32)mArguments[a].mInitializer, getScopeChain(), thisValue, argv, argc);
|
||||
ASSERT(mParameters && (a < maxParameterIndex()));
|
||||
return cx->interpret(getByteCode(), (int32)mParameters[a].mInitializer, getScopeChain(), thisValue, argv, argc);
|
||||
}
|
||||
|
||||
void JSFunction::setArgCounts(Context *cx, uint32 r, uint32 o, uint32 n, bool hasRest, bool restIsNamed)
|
||||
void JSFunction::setParameterCounts(Context *cx, uint32 r, uint32 o, uint32 n, bool hasRest)
|
||||
{
|
||||
mHasRestParameter = hasRest;
|
||||
mRestIsNamed = restIsNamed;
|
||||
mRequiredArgs = r;
|
||||
mOptionalArgs = o;
|
||||
mNamedArgs = n;
|
||||
mArguments = new ArgumentData[mRequiredArgs + mOptionalArgs + ((hasRest) ? 1 : 0)];
|
||||
defineVariable(cx, cx->Length_StringAtom, (NamespaceList *)NULL, Property::DontDelete | Property::ReadOnly, Number_Type, JSValue((float64)mRequiredArgs));
|
||||
mRequiredParameters = r;
|
||||
mOptionalParameters = o;
|
||||
mNamedParameters = n;
|
||||
mParameters = new ParameterData[mRequiredParameters + mOptionalParameters + + mNamedParameters + ((hasRest) ? 1 : 0)];
|
||||
defineVariable(cx, cx->Length_StringAtom, (NamespaceList *)NULL, Property::DontDelete | Property::ReadOnly, Number_Type, JSValue((float64)mRequiredParameters));
|
||||
}
|
||||
|
||||
|
||||
uint32 JSFunction::findParameterName(const String *name)
|
||||
{
|
||||
uint32 maxArgs = mRequiredArgs + mOptionalArgs + ((mHasRestParameter) ? 1 : 0);
|
||||
ASSERT(mArguments || (maxArgs == 0));
|
||||
for (uint32 i = 0; i < maxArgs; i++) {
|
||||
if (mArguments[i].mName->compare(*name) == 0)
|
||||
return i;
|
||||
}
|
||||
return NotABanana;
|
||||
}
|
||||
|
||||
|
||||
void Context::assureStackSpace(uint32 s)
|
||||
{
|
||||
|
@ -2568,7 +2553,7 @@ void Context::initClass(JSType *type, ClassDef *cdef, PrototypeFunctions *pdef)
|
|||
// fun->setClass(type); don't do this, it makes the function a method
|
||||
StringAtom *name = &mWorld.identifiers[widenCString(pdef->mDef[i].name)];
|
||||
fun->setFunctionName(name);
|
||||
fun->setArgCounts(this, pdef->mDef[i].length, 0, 0, false, false);
|
||||
fun->setParameterCounts(this, pdef->mDef[i].length, 0, 0, false);
|
||||
type->mPrototypeObject->defineVariable(this, *name,
|
||||
(NamespaceList *)(NULL),
|
||||
Property::NoAttribute,
|
||||
|
@ -2978,7 +2963,7 @@ Context::Context(JSObject **global, World &world, Arena &a, Pragma::Flags flags)
|
|||
|
||||
for (i = 0; i < (sizeof(globalObjectFunctions) / sizeof(ProtoFunDef)); i++) {
|
||||
x = new JSFunction(this, globalObjectFunctions[i].imp, globalObjectFunctions[i].result);
|
||||
x->setArgCounts(this, globalObjectFunctions[i].length, 0, 0, false, false);
|
||||
x->setParameterCounts(this, globalObjectFunctions[i].length, 0, 0, false);
|
||||
x->setIsPrototype(true);
|
||||
getGlobalObject()->defineVariable(this, widenCString(globalObjectFunctions[i].name), (NamespaceList *)(NULL), Property::NoAttribute, globalObjectFunctions[i].result, JSValue(x));
|
||||
}
|
||||
|
|
|
@ -1129,7 +1129,7 @@ XXX ...couldn't get this to work...
|
|||
return obj->isNestedFunction();
|
||||
}
|
||||
|
||||
bool isPossibleUncheckedFunction(FunctionDefinition *f);
|
||||
bool isPossibleUncheckedFunction(FunctionDefinition &f);
|
||||
|
||||
void defineTempVariable(Context *cx, Reference *&readRef, Reference *&writeRef, JSType *type)
|
||||
{
|
||||
|
@ -1187,12 +1187,15 @@ XXX ...couldn't get this to work...
|
|||
JSFunction() : JSObject(Function_Type), mActivation() { mActivation.mContainer = this; mPrototype = Function_Type->mPrototypeObject; } // for JSBoundFunction (XXX ask Patrick about this structure)
|
||||
public:
|
||||
|
||||
class ArgumentData {
|
||||
typedef enum { Invalid, RequiredParameter, OptionalParameter, RestParameter, NamedParameter } ParameterFlag;
|
||||
|
||||
class ParameterData {
|
||||
public:
|
||||
ArgumentData() : mName(NULL), mType(NULL), mInitializer((uint32)(-1)) { }
|
||||
ParameterData() : mName(NULL), mType(NULL), mInitializer((uint32)(-1)), mFlag(Invalid) { }
|
||||
const String *mName;
|
||||
JSType *mType;
|
||||
uint32 mInitializer;
|
||||
ParameterFlag mFlag;
|
||||
};
|
||||
|
||||
|
||||
|
@ -1210,18 +1213,22 @@ XXX ...couldn't get this to work...
|
|||
void operator delete(void* t) { trace_release("JSFunction", t); STD::free(t); }
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
uint32 maxParameterIndex() { return mRequiredParameters + mOptionalParameters + mNamedParameters + ((mHasRestParameter) ? 1 : 0); }
|
||||
#endif
|
||||
void setByteCode(ByteCodeModule *b) { ASSERT(!isNative()); mByteCode = b; }
|
||||
void setResultType(JSType *r) { mResultType = r; }
|
||||
void setArgCounts(Context *cx, uint32 r, uint32 o, uint32 n, bool hasRest, bool restIsNamed);
|
||||
void setArgument(uint32 index, const String *n, JSType *t)
|
||||
{ ASSERT(mArguments && (index < (mRequiredArgs + mOptionalArgs + ((mHasRestParameter) ? 1 : 0) ))); mArguments[index].mType = t; mArguments[index].mName = n; }
|
||||
void setArgumentInitializer(uint32 index, uint32 offset)
|
||||
{ ASSERT(mArguments && (index < (mRequiredArgs + mOptionalArgs + ((mHasRestParameter) ? 1 : 0) ))); mArguments[index].mInitializer = offset; }
|
||||
void setParameterCounts(Context *cx, uint32 r, uint32 o, uint32 n, bool hasRest);
|
||||
void setParameter(uint32 index, const String *n, JSType *t, ParameterFlag flag)
|
||||
{ ASSERT(mParameters && (index < maxParameterIndex()));
|
||||
mParameters[index].mType = t; mParameters[index].mName = n; mParameters[index].mFlag = flag; }
|
||||
void setParameterInitializer(uint32 index, uint32 offset)
|
||||
{ ASSERT(mParameters && (index < maxParameterIndex())); mParameters[index].mInitializer = offset; }
|
||||
|
||||
void setIsPrototype(bool i) { mIsPrototype = i; }
|
||||
void setIsConstructor(bool i) { mIsConstructor = i; }
|
||||
void setIsUnchecked() { mIsChecked = false; }
|
||||
void setFunctionName(FunctionName *n) { mFunctionName = new FunctionName(); mFunctionName->prefix = n->prefix; mFunctionName->name = n->name; }
|
||||
void setFunctionName(FunctionName &n) { mFunctionName = new FunctionName(); mFunctionName->prefix = n.prefix; mFunctionName->name = n.name; }
|
||||
void setFunctionName(const StringAtom *n)
|
||||
{ mFunctionName = new FunctionName(); mFunctionName->name = n; }
|
||||
void setClass(JSType *c) { mClass = c; }
|
||||
|
@ -1237,47 +1244,61 @@ XXX ...couldn't get this to work...
|
|||
{ return mParameterBarrel; }
|
||||
virtual Activation *getActivation() { return &mActivation; }
|
||||
|
||||
virtual JSType *getResultType() { return mResultType; }
|
||||
virtual JSType *getArgType(uint32 a) { ASSERT(mArguments && (a < (mRequiredArgs + mOptionalArgs))); return mArguments[a].mType; }
|
||||
virtual bool argHasInitializer(uint32 a){ ASSERT(mArguments && (a < (mRequiredArgs + mOptionalArgs))); return (mArguments[a].mInitializer != (uint32)(-1)); }
|
||||
virtual JSValue runArgInitializer(Context *cx, uint32 a, const JSValue& thisValue, JSValue *argv, uint32 argc);
|
||||
virtual ScopeChain *getScopeChain() { return mScopeChain; }
|
||||
virtual JSValue getThisValue() { return kNullValue; }
|
||||
virtual JSType *getClass() { return mClass; }
|
||||
virtual FunctionName *getFunctionName() { return mFunctionName; }
|
||||
virtual uint32 findParameterName(const String *name);
|
||||
virtual uint32 getRequiredArgumentCount()
|
||||
{ return mRequiredArgs; }
|
||||
virtual uint32 getOptionalArgumentCount()
|
||||
{ return mOptionalArgs; }
|
||||
virtual bool hasOptionalArguments() { return (mOptionalArgs > 0); }
|
||||
|
||||
virtual bool isChecked() { return mIsChecked; }
|
||||
|
||||
virtual JSType *getResultType() { return mResultType; }
|
||||
virtual JSType *getParameterType(uint32 a)
|
||||
{ ASSERT(mParameters && (a < maxParameterIndex())); return mParameters[a].mType; }
|
||||
virtual bool parameterHasInitializer(uint32 a)
|
||||
{ ASSERT(mParameters && (a < maxParameterIndex())); return (mParameters[a].mInitializer != (uint32)(-1)); }
|
||||
virtual JSValue runParameterInitializer(Context *cx, uint32 a, const JSValue& thisValue, JSValue *argv, uint32 argc);
|
||||
|
||||
virtual uint32 getRequiredParameterCount()
|
||||
{ return mRequiredParameters; }
|
||||
virtual uint32 getOptionalParameterCount()
|
||||
{ return mOptionalParameters; }
|
||||
virtual uint32 getNamedParameterCount() { return mNamedParameters; }
|
||||
virtual bool hasOptionalParameters() { return (mOptionalParameters > 0); }
|
||||
virtual bool parameterIsRequired(uint32 index)
|
||||
{ ASSERT(mParameters && (index < maxParameterIndex())); return (mParameters[index].mFlag == RequiredParameter); }
|
||||
virtual bool parameterIsOptional(uint32 index)
|
||||
{ ASSERT(mParameters && (index < maxParameterIndex())); return (mParameters[index].mFlag == OptionalParameter); }
|
||||
virtual bool parameterIsNamed(uint32 index)
|
||||
{ ASSERT(mParameters && (index < maxParameterIndex())); return (mParameters[index].mFlag == NamedParameter); }
|
||||
virtual uint32 getRestParameterIndex() { ASSERT(mHasRestParameter); return (mRequiredParameters + mOptionalParameters); }
|
||||
|
||||
virtual const String *getParameterName(uint32 index)
|
||||
{ ASSERT(mParameters && (index < maxParameterIndex())); return mParameters[index].mName; }
|
||||
virtual bool hasRestParameter() { return mHasRestParameter; }
|
||||
virtual const String *getRestParameterName()
|
||||
{ ASSERT(mHasRestParameter); return mArguments[(mRequiredArgs + mOptionalArgs)].mName; }
|
||||
virtual JSType *getRestParameterType() { ASSERT(mHasRestParameter); return mArguments[(mRequiredArgs + mOptionalArgs)].mType; }
|
||||
|
||||
virtual JSFunction *getFunction() { return this; }
|
||||
bool isEqual(JSFunction *f) { return (getFunction() == f->getFunction()); }
|
||||
|
||||
void countParameters(Context *cx, FunctionDefinition &f);
|
||||
|
||||
|
||||
ParameterBarrel *mParameterBarrel;
|
||||
Activation mActivation; // not used during execution (XXX so maybe we should handle it differently, hmmm?)
|
||||
|
||||
|
||||
private:
|
||||
ByteCodeModule *mByteCode;
|
||||
NativeCode *mCode;
|
||||
JSType *mResultType;
|
||||
uint32 mRequiredArgs; // total # parameters
|
||||
uint32 mOptionalArgs;
|
||||
uint32 mNamedArgs;
|
||||
ArgumentData *mArguments;
|
||||
uint32 mRequiredParameters;
|
||||
uint32 mOptionalParameters;
|
||||
uint32 mNamedParameters;
|
||||
ParameterData *mParameters;
|
||||
ScopeChain *mScopeChain;
|
||||
bool mIsPrototype; // set for functions with prototype attribute
|
||||
bool mIsConstructor;
|
||||
bool mIsChecked;
|
||||
bool mHasRestParameter;
|
||||
bool mRestIsNamed;
|
||||
const String *mRestParameterName;
|
||||
JSType *mClass; // pointer to owning class if this function is a method
|
||||
FunctionName *mFunctionName;
|
||||
};
|
||||
|
@ -1303,26 +1324,32 @@ XXX ...couldn't get this to work...
|
|||
{ return mFunction->mParameterBarrel; }
|
||||
Activation *getActivation() { return &mFunction->mActivation; }
|
||||
JSType *getResultType() { return mFunction->getResultType(); }
|
||||
JSType *getArgType(uint32 a) { return mFunction->getArgType(a); }
|
||||
bool argHasInitializer(uint32 a){ return mFunction->argHasInitializer(a); }
|
||||
JSValue runArgInitializer(Context *cx, uint32 a, const JSValue& thisValue, JSValue *argv, uint32 argc)
|
||||
{ return mFunction->runArgInitializer(cx, a, thisValue, argv, argc); }
|
||||
JSType *getParameterType(uint32 a) { return mFunction->getParameterType(a); }
|
||||
bool parameterHasInitializer(uint32 a){ return mFunction->parameterHasInitializer(a); }
|
||||
JSValue runParameterInitializer(Context *cx, uint32 a, const JSValue& thisValue, JSValue *argv, uint32 argc)
|
||||
{ return mFunction->runParameterInitializer(cx, a, thisValue, argv, argc); }
|
||||
ScopeChain *getScopeChain() { return mFunction->getScopeChain(); }
|
||||
JSValue getThisValue() { return (mThis) ? JSValue(mThis) : kNullValue; }
|
||||
JSType *getClass() { return mFunction->getClass(); }
|
||||
FunctionName *getFunctionName() { return mFunction->getFunctionName(); }
|
||||
uint32 findParameterName(const String *name)
|
||||
{ return mFunction->findParameterName(name); }
|
||||
uint32 getRequiredArgumentCount()
|
||||
{ return mFunction->getRequiredArgumentCount(); }
|
||||
uint32 getOptionalArgumentCount()
|
||||
{ return mFunction->getOptionalArgumentCount(); }
|
||||
bool hasOptionalArguments() { return mFunction->hasOptionalArguments(); }
|
||||
|
||||
uint32 getRequiredParameterCount()
|
||||
{ return mFunction->getRequiredParameterCount(); }
|
||||
uint32 getOptionalParameterCount()
|
||||
{ return mFunction->getOptionalParameterCount(); }
|
||||
uint32 getNamedParameterCount() { return mFunction->getNamedParameterCount(); }
|
||||
virtual bool parameterIsRequired(uint32 index)
|
||||
{ return mFunction->parameterIsRequired(index); }
|
||||
virtual bool parameterIsOptional(uint32 index)
|
||||
{ return mFunction->parameterIsOptional(index); }
|
||||
virtual bool parameterIsNamed(uint32 index)
|
||||
{ return mFunction->parameterIsNamed(index); }
|
||||
virtual uint32 getRestParameterIndex()
|
||||
{ return mFunction->getRestParameterIndex(); }
|
||||
virtual const String *getParameterName(uint32 index)
|
||||
{ return mFunction->getParameterName(index); }
|
||||
bool isChecked() { return mFunction->isChecked(); }
|
||||
bool hasRestParameter() { return mFunction->hasRestParameter(); }
|
||||
const String *getRestParameterName()
|
||||
{ return mFunction->getRestParameterName(); }
|
||||
JSType *getRestParameterType() { return mFunction->getRestParameterType(); }
|
||||
|
||||
void getProperty(Context *cx, const String &name, NamespaceList *names)
|
||||
{ mFunction->getProperty(cx, name, names); }
|
||||
|
|
|
@ -256,7 +256,7 @@ void initMathObject(Context *cx, JSObject *mathObj)
|
|||
|
||||
for (i = 0; i < sizeof(MathObjectFunctions) / sizeof(MathObjectFunctionDef); i++) {
|
||||
JSFunction *f = new JSFunction(cx, MathObjectFunctions[i].imp, Number_Type);
|
||||
f->setArgCounts(cx, MathObjectFunctions[i].length, 0, 0, false, false);
|
||||
f->setParameterCounts(cx, MathObjectFunctions[i].length, 0, 0, false);
|
||||
mathObj->defineVariable(cx, widenCString(MathObjectFunctions[i].name),
|
||||
(NamespaceList *)(NULL), Property::ReadOnly | Property::DontDelete,
|
||||
Number_Type, JSValue(f));
|
||||
|
|
|
@ -41,7 +41,7 @@ RSC=rc.exe
|
|||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
|
||||
# ADD CPP /nologo /GX /O2 /Ob2 /D "_LIB" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "XP_PC" /YX /FD /c
|
||||
# ADD CPP /nologo /GR /GX /O2 /Ob2 /D "_LIB" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "XP_PC" /YX /FD /c
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
|
|
Загрузка…
Ссылка в новой задаче