Added Function.call/apply. Fixed bug in exception handling clean-up of

activation stack.
This commit is contained in:
rogerl%netscape.com 2001-11-06 19:45:04 +00:00
Родитель cfa922c672
Коммит 143454c6bd
2 изменённых файлов: 131 добавлений и 36 удалений

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

@ -188,8 +188,10 @@ JSValue Context::invokeFunction(JSFunction *target, const JSValue& thisValue, JS
JSValue Context::interpret(JS2Runtime::ByteCodeModule *bcm, int offset, ScopeChain *scopeChain, const JSValue& thisValue, JSValue *argv, uint32 /*argc*/)
{
mActivationStack.push(new Activation(mLocals, mStack, mStackTop, mScopeChain,
mArgumentBase, mThis, NULL, mCurModule)); // use NULL pc value to force interpret loop to exit
Activation *prev = new Activation(mLocals, mStack, mStackTop, mScopeChain,
mArgumentBase, mThis, NULL, mCurModule); // use NULL pc value to force interpret loop to exit
uint32 activationHeight = mActivationStack.size();
mActivationStack.push(prev);
mThis = thisValue;
if (scopeChain)
mScopeChain = scopeChain;
@ -215,14 +217,18 @@ JSValue Context::interpret(JS2Runtime::ByteCodeModule *bcm, int offset, ScopeCha
try {
result = interpret(pc, endPC);
}
catch (Exception &x) {
Activation *prev = mActivationStack.top();
mActivationStack.pop();
catch (Exception &jsx) {
while (mActivationStack.size() != activationHeight)
mActivationStack.pop();
// the following (delete's) are a bit iffy - depends on whether
// a closure capturing the contents has come along...
// if (mThis.isObject())
// mScopeChain->popScope();
JSValue x;
if (jsx.hasKind(Exception::userException))
x = popValue();
delete[] mStack;
delete[] mLocals;
if (scopeChain == NULL)
@ -230,7 +236,11 @@ JSValue Context::interpret(JS2Runtime::ByteCodeModule *bcm, int offset, ScopeCha
mCurModule = prev->mModule;
mStack = prev->mStack;
mStackTop = prev->mStackTop;
mStackTop = 0; // we're processing an exception, no need to preserve the stack
if (jsx.hasKind(Exception::userException))
pushValue(x);
if (mCurModule)
mStackMax = mCurModule->mStackDepth;
mLocals = prev->mLocals;
@ -238,9 +248,9 @@ JSValue Context::interpret(JS2Runtime::ByteCodeModule *bcm, int offset, ScopeCha
mThis = prev->mThis;
mScopeChain = prev->mScopeChain;
delete prev;
throw x;
throw jsx;
}
Activation *prev = mActivationStack.top();
ASSERT(prev == mActivationStack.top());
mActivationStack.pop();
// the following (delete's) are a bit iffy - depends on whether
@ -1013,6 +1023,18 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
const String *name = index.toString(this).string;
obj->getProperty(this, *name, CURRENT_ATTR);
}
// if the result is a method of some kind, bind
// the base object to it
JSValue result = topValue();
if (result.isFunction()) {
popValue();
if (result.function->isConstructor())
// A constructor has to be called with a NULL 'this' in order to prompt it
// to construct the instance object.
pushValue(JSValue((JSFunction *)(new JSBoundFunction(result.function, NULL))));
else
pushValue(JSValue((JSFunction *)(new JSBoundFunction(result.function, obj))));
}
}
break;
case SetElementOp:
@ -1627,6 +1649,34 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
Activation *curAct = (mActivationStack.size() > 0) ? mActivationStack.top() : NULL;
JSValue x;
if (curAct != hndlr->mActivation) {
ASSERT(mActivationStack.size() > 0);
Activation *prev;// = mActivationStack.top();
do {
prev = curAct;
if (prev->mPC == NULL) {
// Yikes! the exception is getting thrown across a re-invocation
// of the interpreter loop.
throw jsx;
}
mActivationStack.pop();
curAct = mActivationStack.top();
} while (hndlr->mActivation != curAct);
if (jsx.hasKind(Exception::userException)) // snatch the exception before the stack gets clobbered
x = popValue();
mCurModule = prev->mModule;
endPC = mCurModule->mCodeBase + mCurModule->mLength;
mLocals = prev->mLocals;
mStack = prev->mStack;
mStackMax = mCurModule->mStackDepth;
mArgumentBase = prev->mArgumentBase;
mThis = prev->mThis;
}
else {
if (jsx.hasKind(Exception::userException))
x = popValue();
}
// make sure there's a JS object for the catch clause to work with
if (!jsx.hasKind(Exception::userException)) {
JSValue argv[1];
@ -1649,32 +1699,7 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
break;
}
}
else {
x = popValue();
}
if (curAct != hndlr->mActivation) {
ASSERT(mActivationStack.size() > 0);
Activation *prev;// = mActivationStack.top();
do {
prev = curAct;
if (prev->mPC == NULL) {
// Yikes! the exception is getting thrown across a re-invocation
// of the interpreter loop.
throw jsx;
}
mActivationStack.pop();
curAct = mActivationStack.top();
} while (hndlr->mActivation != curAct);
mCurModule = prev->mModule;
endPC = mCurModule->mCodeBase + mCurModule->mLength;
mLocals = prev->mLocals;
mStack = prev->mStack;
mStackMax = mCurModule->mStackDepth;
mArgumentBase = prev->mArgumentBase;
mThis = prev->mThis;
}
resizeStack(hndlr->mStackSize);
pc = hndlr->mPC;
pushValue(x);
@ -2059,7 +2084,7 @@ static JSValue objectSpittingImage(Context * /*cx*/, const JSValue& /*thisValue*
JSType *t1 = r1.getType();
JSType *t2 = r2.getType();
if (t1 != t2) {
if ((t1 != t2) || (r1.isObject() != r2.isObject())) {
return kFalseValue;
}
else {

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

@ -1788,7 +1788,7 @@ static JSValue Object_Constructor(Context *cx, const JSValue& thisValue, JSValue
return thatValue;
}
static JSValue Object_toString(Context *, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/)
static JSValue Object_toString(Context * /* cx */, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/)
{
if (thisValue.isObject())
return JSValue(new String(widenCString("[object ") + *thisValue.object->getType()->mClassName + widenCString("]")));
@ -1804,6 +1804,11 @@ static JSValue Object_toString(Context *, const JSValue& thisValue, JSValue * /*
}
}
static JSValue Object_valueOf(Context * /* cx */, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/)
{
return thisValue;
}
struct IteratorDongle {
JSObject *obj;
PropertyIterator it;
@ -1976,6 +1981,68 @@ static JSValue Function_hasInstance(Context *cx, const JSValue& thisValue, JSVal
return kFalseValue;
}
static JSValue Function_call(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
if (!thisValue.isFunction())
cx->reportError(Exception::typeError, "Non-callable object for Function.call");
JSValue thisArg;
if (argc == 0)
thisArg = JSValue(cx->getGlobalObject());
else {
if (argv[0].isUndefined() || argv[0].isNull())
thisArg = JSValue(cx->getGlobalObject());
else
thisArg = JSValue(argv[0].toObject(cx));
--argc;
++argv;
}
return cx->invokeFunction(thisValue.function, thisArg, argv, argc);
}
static JSValue Function_apply(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
if (!thisValue.isFunction())
cx->reportError(Exception::typeError, "Non-callable object for Function.call");
ContextStackReplacement csr(cx);
JSValue thisArg;
if (argc == 0)
thisArg = JSValue(cx->getGlobalObject());
else {
if (argv[0].isUndefined() || argv[0].isNull())
thisArg = JSValue(cx->getGlobalObject());
else
thisArg = JSValue(argv[0].toObject(cx));
}
if (argc <= 1) {
argv = NULL;
argc = 0;
}
else {
if (argv[1].getType() != Array_Type)
cx->reportError(Exception::typeError, "Function.apply must have Array type argument list");
ASSERT(argv[1].isObject());
JSObject *argsObj = argv[1].object;
argsObj->getProperty(cx, cx->Length_StringAtom, CURRENT_ATTR);
JSValue result = cx->popValue();
argc = (uint32)(result.toUInt32(cx).f64);
argv = new JSValue[argc];
for (uint32 i = 0; i < argc; i++) {
const String *id = numberToString(i);
argsObj->getProperty(cx, *id, CURRENT_ATTR);
argv[i] = cx->popValue();
delete id;
}
}
return cx->invokeFunction(thisValue.function, thisArg, argv, argc);
}
static JSValue Number_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
JSValue v = thisValue;
@ -2609,6 +2676,7 @@ void Context::initBuiltins()
{ "forin", Object_Type, 0, Object_forin },
{ "next", Object_Type, 0, Object_next },
{ "done", Object_Type, 0, Object_done },
{ "valueOf", Object_Type, 0, Object_valueOf },
{ NULL }
};
ProtoFunDef functionProtos[] =
@ -2616,6 +2684,8 @@ void Context::initBuiltins()
{ "toString", String_Type, 0, Function_toString },
{ "toSource", String_Type, 0, Function_toString },
{ "hasInstance", Boolean_Type, 1, Function_hasInstance },
{ "call", Object_Type, 1, Function_call },
{ "apply", Object_Type, 2, Function_apply },
{ NULL }
};
ProtoFunDef numberProtos[] =