Fixed passing wrong environment to function call.
git-svn-id: svn://10.0.0.236/trunk@139296 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
7307191534
commit
d9a6dcdb17
@ -64,9 +64,9 @@ namespace JavaScript {
|
||||
namespace MetaData {
|
||||
|
||||
// Begin execution of a bytecodeContainer
|
||||
js2val JS2Engine::interpret(Phase execPhase, BytecodeContainer *targetbCon)
|
||||
js2val JS2Engine::interpret(Phase execPhase, BytecodeContainer *targetbCon, Environment *env)
|
||||
{
|
||||
jsr(execPhase, targetbCon, sp - execStack, JS2VAL_VOID);
|
||||
jsr(execPhase, targetbCon, sp - execStack, JS2VAL_VOID, env);
|
||||
ActivationFrame *f = activationStackTop;
|
||||
js2val result;
|
||||
try {
|
||||
@ -218,6 +218,14 @@ namespace MetaData {
|
||||
return new (p) String(*s);
|
||||
}
|
||||
|
||||
String *JS2Engine::concatStrings(const String *s1, const String *s2)
|
||||
{
|
||||
String *p = (String *)(JS2Object::alloc(sizeof(String)));
|
||||
String *result = new (p) String(*s1);
|
||||
result->append(*s2);
|
||||
return result;
|
||||
}
|
||||
|
||||
// if the argument can be stored as an integer value, do so
|
||||
// otherwise get a double value
|
||||
js2val JS2Engine::allocNumber(float64 x)
|
||||
@ -830,15 +838,16 @@ namespace MetaData {
|
||||
|
||||
// Save current engine state (pc, environment top) and
|
||||
// jump to start of new bytecodeContainer
|
||||
void JS2Engine::jsr(Phase execPhase, BytecodeContainer *new_bCon, uint32 stackBase, js2val returnVal)
|
||||
void JS2Engine::jsr(Phase execPhase, BytecodeContainer *new_bCon, uint32 stackBase, js2val returnVal, Environment *env)
|
||||
{
|
||||
ASSERT(activationStackTop < (activationStack + MAX_ACTIVATION_STACK));
|
||||
activationStackTop->bCon = bCon;
|
||||
activationStackTop->pc = pc;
|
||||
activationStackTop->phase = phase;
|
||||
activationStackTop->topFrame = meta->env->getTopFrame();
|
||||
// activationStackTop->topFrame = meta->env->getTopFrame();
|
||||
activationStackTop->execStackBase = stackBase;
|
||||
activationStackTop->retval = returnVal;
|
||||
activationStackTop->env = meta->env;
|
||||
activationStackTop++;
|
||||
bCon = new_bCon;
|
||||
if ((int32)bCon->getMaxStack() >= (execStackLimit - sp)) {
|
||||
@ -852,7 +861,7 @@ namespace MetaData {
|
||||
}
|
||||
pc = new_bCon->getCodeStart();
|
||||
phase = execPhase;
|
||||
|
||||
meta->env = env;
|
||||
}
|
||||
|
||||
// Return to previously saved execution state
|
||||
@ -864,8 +873,9 @@ namespace MetaData {
|
||||
bCon = activationStackTop->bCon;
|
||||
pc = activationStackTop->pc;
|
||||
phase = activationStackTop->phase;
|
||||
while (meta->env->getTopFrame() != activationStackTop->topFrame)
|
||||
meta->env->removeTopFrame();
|
||||
meta->env = activationStackTop->env;
|
||||
// while (meta->env->getTopFrame() != activationStackTop->topFrame)
|
||||
// meta->env->removeTopFrame();
|
||||
sp = execStack + activationStackTop->execStackBase;
|
||||
if (!JS2VAL_IS_VOID(activationStackTop->retval)) // XXX might need an actual 'returnValue' flag instead
|
||||
retval = activationStackTop->retval;
|
||||
@ -878,7 +888,7 @@ namespace MetaData {
|
||||
if (bCon)
|
||||
bCon->mark();
|
||||
for (ActivationFrame *f = activationStack; (f < activationStackTop); f++) {
|
||||
GCMARKOBJECT(f->topFrame);
|
||||
GCMARKOBJECT(f->env);
|
||||
if (f->bCon)
|
||||
f->bCon->mark();
|
||||
}
|
||||
@ -929,6 +939,57 @@ namespace MetaData {
|
||||
delete hndlr;
|
||||
}
|
||||
|
||||
js2val JS2Engine::typeofString(js2val a)
|
||||
{
|
||||
if (JS2VAL_IS_UNDEFINED(a))
|
||||
a = STRING_TO_JS2VAL(undefined_StringAtom);
|
||||
else
|
||||
if (JS2VAL_IS_BOOLEAN(a))
|
||||
a = allocString("boolean");
|
||||
else
|
||||
if (JS2VAL_IS_NUMBER(a))
|
||||
a = allocString("number");
|
||||
else
|
||||
if (JS2VAL_IS_STRING(a))
|
||||
a = allocString("string");
|
||||
else {
|
||||
ASSERT(JS2VAL_IS_OBJECT(a));
|
||||
if (JS2VAL_IS_NULL(a))
|
||||
a = STRING_TO_JS2VAL(object_StringAtom);
|
||||
else {
|
||||
JS2Object *obj = JS2VAL_TO_OBJECT(a);
|
||||
switch (obj->kind) {
|
||||
case MultinameKind:
|
||||
a = allocString("namespace");
|
||||
break;
|
||||
case AttributeObjectKind:
|
||||
a = allocString("attribute");
|
||||
break;
|
||||
case ClassKind:
|
||||
case MethodClosureKind:
|
||||
a = STRING_TO_JS2VAL(Function_StringAtom);
|
||||
break;
|
||||
case PrototypeInstanceKind:
|
||||
if (checked_cast<PrototypeInstance *>(obj)->type == meta->functionClass)
|
||||
a = STRING_TO_JS2VAL(Function_StringAtom);
|
||||
else
|
||||
a = STRING_TO_JS2VAL(object_StringAtom);
|
||||
break;
|
||||
case PackageKind:
|
||||
case GlobalObjectKind:
|
||||
a = STRING_TO_JS2VAL(object_StringAtom);
|
||||
break;
|
||||
case SimpleInstanceKind:
|
||||
a = STRING_TO_JS2VAL(checked_cast<SimpleInstance *>(obj)->type->getName());
|
||||
break;
|
||||
default:
|
||||
ASSERT(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
//
|
||||
// XXX Only scanning dynamic properties
|
||||
|
||||
@ -163,8 +163,8 @@ enum JS2Op {
|
||||
|
||||
|
||||
class Frame;
|
||||
|
||||
class ParameterFrame;
|
||||
class Environment;
|
||||
|
||||
class JS2Object;
|
||||
class JS2Metadata;
|
||||
@ -179,7 +179,7 @@ public:
|
||||
|
||||
JS2Engine(World &world);
|
||||
|
||||
js2val interpret(Phase execPhase, BytecodeContainer *targetbCon);
|
||||
js2val interpret(Phase execPhase, BytecodeContainer *targetbCon, Environment *env);
|
||||
js2val interpreterLoop();
|
||||
|
||||
// Use the pc map in the current bytecode container to get a source offset
|
||||
@ -211,6 +211,7 @@ public:
|
||||
js2val allocString(const char *s) { return STRING_TO_JS2VAL(allocStringPtr(s)); }
|
||||
String *allocStringPtr(const String *s);
|
||||
String *allocStringPtr(const char *s);
|
||||
String *concatStrings(const String *s1, const String *s2);
|
||||
|
||||
String *numberToString(float64 *number); // non-static since they need access to meta
|
||||
String *numberToString(int32 i);
|
||||
@ -266,17 +267,18 @@ public:
|
||||
struct ActivationFrame {
|
||||
uint8 *pc;
|
||||
BytecodeContainer *bCon;
|
||||
Frame *topFrame;
|
||||
Phase phase;
|
||||
js2val retval;
|
||||
uint32 execStackBase;
|
||||
Environment *env;
|
||||
};
|
||||
void jsr(Phase execPhase, BytecodeContainer *bCon, uint32 stackBase, js2val returnVal);
|
||||
void jsr(Phase execPhase, BytecodeContainer *bCon, uint32 stackBase, js2val returnVal, Environment *env);
|
||||
bool activationStackEmpty() { return (activationStackTop == activationStack); }
|
||||
void rts();
|
||||
ActivationFrame *activationStack;
|
||||
ActivationFrame *activationStackTop;
|
||||
|
||||
js2val typeofString(js2val a);
|
||||
|
||||
// The execution stack for expression evaluation, should be empty
|
||||
// between statements.
|
||||
|
||||
@ -153,7 +153,7 @@ void initErrorObject(JS2Metadata *meta)
|
||||
PrototypeFunction *pf = &errorProtos[0];
|
||||
while (pf->name) {
|
||||
SimpleInstance *fInst = new SimpleInstance(meta->functionClass);
|
||||
fInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_INACCESSIBLE, true), pf->code);
|
||||
fInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_INACCESSIBLE, true), pf->code, meta->env);
|
||||
|
||||
InstanceMember *m = new InstanceMethod(fInst);
|
||||
meta->defineInstanceMember(meta->errorClass, &meta->cxt, &meta->world.identifiers[pf->name], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, m, 0);
|
||||
|
||||
@ -149,7 +149,7 @@ namespace MetaData {
|
||||
bCon->emitOp(eReturnVoid, lastPos);
|
||||
uint8 *savePC = engine->pc;
|
||||
engine->pc = NULL;
|
||||
js2val retval = engine->interpret(phase, bCon);
|
||||
js2val retval = engine->interpret(phase, bCon, env);
|
||||
engine->pc = savePC;
|
||||
return retval;
|
||||
}
|
||||
@ -170,7 +170,7 @@ namespace MetaData {
|
||||
bCon->emitOp(eReturn, p->pos);
|
||||
savePC = engine->pc;
|
||||
engine->pc = NULL;
|
||||
retval = engine->interpret(phase, bCon);
|
||||
retval = engine->interpret(phase, bCon, env);
|
||||
}
|
||||
catch (Exception &x) {
|
||||
engine->pc = savePC;
|
||||
@ -282,7 +282,7 @@ namespace MetaData {
|
||||
bCon->emitOp(eReturn, 0);
|
||||
savePC = engine->pc;
|
||||
engine->pc = NULL;
|
||||
retval = engine->interpret(RunPhase, bCon);
|
||||
retval = engine->interpret(RunPhase, bCon, env);
|
||||
}
|
||||
catch (Exception &x) {
|
||||
engine->pc = savePC;
|
||||
@ -333,7 +333,7 @@ namespace MetaData {
|
||||
try {
|
||||
savePC = engine->pc;
|
||||
engine->pc = NULL;
|
||||
result = engine->interpret(RunPhase, bCon);
|
||||
result = engine->interpret(RunPhase, bCon, env);
|
||||
}
|
||||
catch (Exception &x) {
|
||||
engine->pc = savePC;
|
||||
|
||||
@ -85,7 +85,7 @@ namespace MetaData {
|
||||
else { // construct an empty function wrapper
|
||||
js2val thatValue = OBJECT_TO_JS2VAL(new FunctionInstance(meta, meta->functionClass->prototype, meta->functionClass));
|
||||
FunctionInstance *fnInst = checked_cast<FunctionInstance *>(JS2VAL_TO_OBJECT(thatValue));
|
||||
fnInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_INACCESSIBLE, true));
|
||||
fnInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_INACCESSIBLE, true), meta->env);
|
||||
fnInst->fWrap->bCon->emitOp(eReturnVoid, meta->engine->errorPos());
|
||||
fnInst->writeProperty(meta, meta->engine->length_StringAtom, INT_TO_JS2VAL(0), DynamicPropertyValue::READONLY);
|
||||
return thatValue;
|
||||
|
||||
@ -341,7 +341,7 @@ void initMathObject(JS2Metadata *meta)
|
||||
FunctionData *pf = &prototypeFunctions[0];
|
||||
while (pf->name) {
|
||||
SimpleInstance *callInst = new SimpleInstance(meta->functionClass);
|
||||
callInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_INACCESSIBLE, true), pf->code);
|
||||
callInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_INACCESSIBLE, true), pf->code, meta->env);
|
||||
Variable *v = new Variable(meta->functionClass, OBJECT_TO_JS2VAL(callInst), true);
|
||||
meta->defineLocalMember(meta->env, &meta->world.identifiers[pf->name], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
|
||||
|
||||
|
||||
@ -92,13 +92,13 @@ namespace MetaData {
|
||||
|
||||
if (prototype) {
|
||||
FunctionInstance *fInst = new FunctionInstance(this, functionClass->prototype, functionClass);
|
||||
fInst->fWrap = new FunctionWrapper(unchecked, compileFrame);
|
||||
fInst->fWrap = new FunctionWrapper(unchecked, compileFrame, env);
|
||||
fnDef->fWrap = fInst->fWrap;
|
||||
result = fInst;
|
||||
}
|
||||
else {
|
||||
SimpleInstance *sInst = new SimpleInstance(functionClass);
|
||||
sInst->fWrap = new FunctionWrapper(unchecked, compileFrame);
|
||||
sInst->fWrap = new FunctionWrapper(unchecked, compileFrame, env);
|
||||
fnDef->fWrap = sInst->fWrap;
|
||||
result = sInst;
|
||||
}
|
||||
@ -2272,7 +2272,12 @@ doUnary:
|
||||
{
|
||||
InvokeExprNode *i = checked_cast<InvokeExprNode *>(p);
|
||||
Reference *rVal = SetupExprNode(env, phase, i->op, exprType);
|
||||
if (rVal) rVal->emitReadForInvokeBytecode(bCon, p->pos);
|
||||
if (rVal)
|
||||
rVal->emitReadForInvokeBytecode(bCon, p->pos);
|
||||
else /* a call doesn't have to have an lValue to execute on,
|
||||
* but we use the value as it's own 'this' in that case.
|
||||
*/
|
||||
bCon->emitOp(eDup, p->pos);
|
||||
ExprPairList *args = i->pairs;
|
||||
uint16 argCount = 0;
|
||||
while (args) {
|
||||
@ -3162,7 +3167,7 @@ static const uint8 urlCharType[256] =
|
||||
void JS2Metadata::addGlobalObjectFunction(char *name, NativeCode *code, uint32 length)
|
||||
{
|
||||
SimpleInstance *fInst = new SimpleInstance(functionClass);
|
||||
fInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_VOID, true), code);
|
||||
fInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_VOID, true), code, env);
|
||||
writeDynamicProperty(glob, new Multiname(&world.identifiers[name], publicNamespace), true, OBJECT_TO_JS2VAL(fInst), RunPhase);
|
||||
fInst->writeProperty(this, engine->length_StringAtom, INT_TO_JS2VAL(length), DynamicPropertyValue::READONLY);
|
||||
}
|
||||
@ -3284,7 +3289,7 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
|
||||
|
||||
// Adding 'toString' to the Object.prototype XXX Or make this a static class member?
|
||||
FunctionInstance *fInst = new FunctionInstance(this, functionClass->prototype, functionClass);
|
||||
fInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_VOID, true), Object_toString);
|
||||
fInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_VOID, true), Object_toString, env);
|
||||
objectClass->prototype->writeProperty(this, engine->toString_StringAtom, OBJECT_TO_JS2VAL(fInst), 0);
|
||||
fInst->writeProperty(this, engine->length_StringAtom, INT_TO_JS2VAL(0), DynamicPropertyValue::READONLY);
|
||||
|
||||
@ -4331,7 +4336,7 @@ deleteClassProperty:
|
||||
if (pf) {
|
||||
while (pf->name) {
|
||||
SimpleInstance *callInst = new SimpleInstance(functionClass);
|
||||
callInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_INACCESSIBLE, true), pf->code);
|
||||
callInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_INACCESSIBLE, true), pf->code, env);
|
||||
v = new Variable(functionClass, OBJECT_TO_JS2VAL(callInst), true);
|
||||
defineLocalMember(env, &world.identifiers[pf->name], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
|
||||
writeDynamicProperty(callInst, new Multiname(engine->length_StringAtom, publicNamespace), true, INT_TO_JS2VAL(pf->length), RunPhase);
|
||||
@ -4344,14 +4349,14 @@ deleteClassProperty:
|
||||
// Add "constructor" as a dynamic property of the prototype
|
||||
FunctionInstance *fInst = new FunctionInstance(this, functionClass->prototype, functionClass);
|
||||
writeDynamicProperty(fInst, new Multiname(engine->length_StringAtom, publicNamespace), true, INT_TO_JS2VAL(1), RunPhase);
|
||||
fInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_INACCESSIBLE, true), construct);
|
||||
fInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_INACCESSIBLE, true), construct, env);
|
||||
writeDynamicProperty(builtinClass->prototype, new Multiname(&world.identifiers["constructor"], publicNamespace), true, OBJECT_TO_JS2VAL(fInst), RunPhase);
|
||||
|
||||
pf = protoFunctions;
|
||||
if (pf) {
|
||||
while (pf->name) {
|
||||
SimpleInstance *callInst = new SimpleInstance(functionClass);
|
||||
callInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_INACCESSIBLE, true), pf->code);
|
||||
callInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_INACCESSIBLE, true), pf->code, env);
|
||||
/*
|
||||
XXX not prototype object function properties, like ECMA3
|
||||
writeDynamicProperty(dateClass->prototype, new Multiname(world.identifiers[pf->name], publicNamespace), true, OBJECT_TO_JS2VAL(fInst), RunPhase);
|
||||
@ -4486,6 +4491,7 @@ deleteClassProperty:
|
||||
GCMARKOBJECT(type)
|
||||
if (fWrap) {
|
||||
GCMARKOBJECT(fWrap->compileFrame);
|
||||
GCMARKOBJECT(fWrap->env);
|
||||
if (fWrap->bCon)
|
||||
fWrap->bCon->mark();
|
||||
}
|
||||
@ -4580,6 +4586,7 @@ deleteClassProperty:
|
||||
{
|
||||
PrototypeInstance::markChildren();
|
||||
if (fWrap) {
|
||||
GCMARKOBJECT(fWrap->env);
|
||||
GCMARKOBJECT(fWrap->compileFrame);
|
||||
if (fWrap->bCon)
|
||||
fWrap->bCon->mark();
|
||||
|
||||
@ -163,7 +163,7 @@ public:
|
||||
Pond *nextPond;
|
||||
};
|
||||
|
||||
#define GCMARKOBJECT(n) if ((n) && !(n)->isMarked()) { (n)->mark(); (n)->markChildren(); }
|
||||
#define GCMARKOBJECT(n) if ((n) && !(n)->isMarked()) { (n)->markObject(); (n)->markChildren(); }
|
||||
#define GCMARKVALUE(v) JS2Object::markJS2Value(v)
|
||||
|
||||
class JS2Object {
|
||||
@ -193,7 +193,7 @@ public:
|
||||
|
||||
virtual void markChildren() { }
|
||||
bool isMarked() { return ((PondScum *)this)[-1].isMarked(); }
|
||||
void mark() { ((PondScum *)this)[-1].mark(); }
|
||||
void markObject() { ((PondScum *)this)[-1].mark(); }
|
||||
|
||||
static void mark(const void *p) { ((PondScum *)p)[-1].mark(); }
|
||||
static void markJS2Value(js2val v);
|
||||
@ -496,6 +496,16 @@ public:
|
||||
|
||||
};
|
||||
|
||||
class WithFrame : public Frame {
|
||||
public:
|
||||
WithFrame(JS2Object *b) : Frame(WithFrameKind), obj(b) { }
|
||||
virtual ~WithFrame() { }
|
||||
|
||||
virtual void markChildren() { GCMARKOBJECT(obj); }
|
||||
|
||||
JS2Object *obj;
|
||||
};
|
||||
|
||||
class NonWithFrame : public Frame {
|
||||
public:
|
||||
|
||||
@ -516,16 +526,57 @@ public:
|
||||
virtual ~NonWithFrame() { }
|
||||
};
|
||||
|
||||
class WithFrame : public Frame {
|
||||
// The top-level frame containing predefined constants, functions, and classes.
|
||||
class SystemFrame : public NonWithFrame {
|
||||
public:
|
||||
WithFrame(JS2Object *b) : Frame(WithFrameKind), obj(b) { }
|
||||
virtual ~WithFrame() { }
|
||||
|
||||
virtual void markChildren() { GCMARKOBJECT(obj); }
|
||||
|
||||
JS2Object *obj;
|
||||
SystemFrame() : NonWithFrame(SystemKind) { }
|
||||
virtual ~SystemFrame() { }
|
||||
};
|
||||
|
||||
|
||||
// Environments contain the bindings that are visible from a given point in the source code. An ENVIRONMENT is
|
||||
// a list of two or more frames. Each frame corresponds to a scope. More specific frames are listed first
|
||||
// -each frame's scope is directly contained in the following frame's scope. The last frame is always the
|
||||
// SYSTEMFRAME. The next-to-last frame is always a PACKAGE or GLOBAL frame.
|
||||
typedef std::deque<Frame *> FrameList;
|
||||
typedef FrameList::iterator FrameListIterator;
|
||||
|
||||
// Deriving from JS2Object for gc sake only
|
||||
class Environment : public JS2Object {
|
||||
public:
|
||||
Environment(SystemFrame *systemFrame, Frame *nextToLast) : JS2Object(EnvironmentKind) { frameList.push_back(nextToLast); frameList.push_back(systemFrame); }
|
||||
virtual ~Environment() { }
|
||||
|
||||
Environment(Environment *e) : JS2Object(EnvironmentKind), frameList(e->frameList) { }
|
||||
|
||||
JS2Class *getEnclosingClass();
|
||||
FrameListIterator getRegionalFrame();
|
||||
Frame *getTopFrame() { return frameList.front(); }
|
||||
FrameListIterator getBegin() { return frameList.begin(); }
|
||||
FrameListIterator getEnd() { return frameList.end(); }
|
||||
Frame *getPackageOrGlobalFrame();
|
||||
SystemFrame *getSystemFrame() { return checked_cast<SystemFrame *>(frameList.back()); }
|
||||
|
||||
void setTopFrame(Frame *f) { while (frameList.front() != f) frameList.pop_front(); }
|
||||
|
||||
void addFrame(Frame *f) { frameList.push_front(f); }
|
||||
void removeTopFrame() { frameList.pop_front(); }
|
||||
|
||||
js2val findThis(bool allowPrototypeThis);
|
||||
js2val lexicalRead(JS2Metadata *meta, Multiname *multiname, Phase phase);
|
||||
void lexicalWrite(JS2Metadata *meta, Multiname *multiname, js2val newValue, bool createIfMissing, Phase phase);
|
||||
void lexicalInit(JS2Metadata *meta, Multiname *multiname, js2val newValue);
|
||||
bool lexicalDelete(JS2Metadata *meta, Multiname *multiname, Phase phase);
|
||||
|
||||
void instantiateFrame(NonWithFrame *pluralFrame, NonWithFrame *singularFrame);
|
||||
|
||||
void markChildren();
|
||||
|
||||
private:
|
||||
FrameList frameList;
|
||||
};
|
||||
|
||||
|
||||
class JS2Class : public NonWithFrame {
|
||||
public:
|
||||
JS2Class(JS2Class *super, JS2Object *proto, Namespace *privateNamespace, bool dynamic, bool allowNull, bool final, const String *name);
|
||||
@ -591,15 +642,16 @@ class ParameterFrame;
|
||||
|
||||
class FunctionWrapper {
|
||||
public:
|
||||
FunctionWrapper(bool unchecked, ParameterFrame *compileFrame)
|
||||
: bCon(new BytecodeContainer()), code(NULL), unchecked(unchecked), compileFrame(compileFrame) { }
|
||||
FunctionWrapper(bool unchecked, ParameterFrame *compileFrame, NativeCode *code)
|
||||
: bCon(NULL), code(code), unchecked(unchecked), compileFrame(compileFrame) { }
|
||||
FunctionWrapper(bool unchecked, ParameterFrame *compileFrame, Environment *env)
|
||||
: bCon(new BytecodeContainer()), code(NULL), unchecked(unchecked), compileFrame(compileFrame), env(new Environment(env)) { }
|
||||
FunctionWrapper(bool unchecked, ParameterFrame *compileFrame, NativeCode *code, Environment *env)
|
||||
: bCon(NULL), code(code), unchecked(unchecked), compileFrame(compileFrame), env(new Environment(env)) { }
|
||||
|
||||
BytecodeContainer *bCon;
|
||||
NativeCode *code;
|
||||
bool unchecked; // true if the function is untyped, non-method, normal
|
||||
ParameterFrame *compileFrame;
|
||||
Environment *env;
|
||||
};
|
||||
|
||||
|
||||
@ -930,13 +982,6 @@ public:
|
||||
};
|
||||
|
||||
|
||||
// The top-level frame containing predefined constants, functions, and classes.
|
||||
class SystemFrame : public NonWithFrame {
|
||||
public:
|
||||
SystemFrame() : NonWithFrame(SystemKind) { }
|
||||
virtual ~SystemFrame() { }
|
||||
};
|
||||
|
||||
// Frames holding bindings for invoked functions
|
||||
class ParameterFrame : public NonWithFrame {
|
||||
public:
|
||||
@ -981,46 +1026,6 @@ public:
|
||||
js2val thisObject;
|
||||
};
|
||||
|
||||
// Environments contain the bindings that are visible from a given point in the source code. An ENVIRONMENT is
|
||||
// a list of two or more frames. Each frame corresponds to a scope. More specific frames are listed first
|
||||
// -each frame's scope is directly contained in the following frame's scope. The last frame is always the
|
||||
// SYSTEMFRAME. The next-to-last frame is always a PACKAGE or GLOBAL frame.
|
||||
typedef std::deque<Frame *> FrameList;
|
||||
typedef FrameList::iterator FrameListIterator;
|
||||
|
||||
// Deriving from JS2Object for gc sake only, these are supposed to be found as JS2 values
|
||||
class Environment : public JS2Object {
|
||||
public:
|
||||
Environment(SystemFrame *systemFrame, Frame *nextToLast) : JS2Object(EnvironmentKind) { frameList.push_back(nextToLast); frameList.push_back(systemFrame); }
|
||||
virtual ~Environment() { }
|
||||
|
||||
JS2Class *getEnclosingClass();
|
||||
FrameListIterator getRegionalFrame();
|
||||
Frame *getTopFrame() { return frameList.front(); }
|
||||
FrameListIterator getBegin() { return frameList.begin(); }
|
||||
FrameListIterator getEnd() { return frameList.end(); }
|
||||
Frame *getPackageOrGlobalFrame();
|
||||
SystemFrame *getSystemFrame() { return checked_cast<SystemFrame *>(frameList.back()); }
|
||||
|
||||
void setTopFrame(Frame *f) { while (frameList.front() != f) frameList.pop_front(); }
|
||||
|
||||
void addFrame(Frame *f) { frameList.push_front(f); }
|
||||
void removeTopFrame() { frameList.pop_front(); }
|
||||
|
||||
js2val findThis(bool allowPrototypeThis);
|
||||
js2val lexicalRead(JS2Metadata *meta, Multiname *multiname, Phase phase);
|
||||
void lexicalWrite(JS2Metadata *meta, Multiname *multiname, js2val newValue, bool createIfMissing, Phase phase);
|
||||
void lexicalInit(JS2Metadata *meta, Multiname *multiname, js2val newValue);
|
||||
bool lexicalDelete(JS2Metadata *meta, Multiname *multiname, Phase phase);
|
||||
|
||||
void instantiateFrame(NonWithFrame *pluralFrame, NonWithFrame *singularFrame);
|
||||
|
||||
void markChildren();
|
||||
|
||||
private:
|
||||
FrameList frameList;
|
||||
};
|
||||
|
||||
|
||||
typedef std::vector<Namespace *> NamespaceList;
|
||||
typedef NamespaceList::iterator NamespaceListIterator;
|
||||
|
||||
@ -334,11 +334,7 @@
|
||||
if (JS2VAL_IS_STRING(a) || JS2VAL_IS_STRING(b)) {
|
||||
const String *astr = meta->toString(a);
|
||||
const String *bstr = meta->toString(b);
|
||||
|
||||
String c = *astr;
|
||||
|
||||
c += *bstr;
|
||||
push(STRING_TO_JS2VAL(allocStringPtr(&c)));
|
||||
push(STRING_TO_JS2VAL(concatStrings(astr, bstr)));
|
||||
}
|
||||
else {
|
||||
a = meta->toGeneralNumber(a);
|
||||
|
||||
@ -92,7 +92,7 @@
|
||||
baseVal = OBJECT_TO_JS2VAL(pInst);
|
||||
pFrame->thisObject = baseVal;
|
||||
pFrame->assignArguments(meta, obj, base(argCount), argCount);
|
||||
jsr(phase, fWrap->bCon, base(argCount + 1) - execStack, baseVal); // seems out of order, but we need to catch the current top frame
|
||||
jsr(phase, fWrap->bCon, base(argCount + 1) - execStack, baseVal, fWrap->env); // seems out of order, but we need to catch the current top frame
|
||||
meta->env->addFrame(pFrame);
|
||||
pFrame = NULL;
|
||||
}
|
||||
@ -114,9 +114,8 @@
|
||||
pc += sizeof(uint16);
|
||||
a = top(argCount + 2); // 'this'
|
||||
b = top(argCount + 1); // target function
|
||||
// uint32 length = 0;
|
||||
if (JS2VAL_IS_PRIMITIVE(b))
|
||||
meta->reportError(Exception::badValueError, "Can't call on primitive value", errorPos());
|
||||
meta->reportError(Exception::badValueError, "{0} is not a function", errorPos(), JS2VAL_TO_STRING(typeofString(b)));
|
||||
JS2Object *fObj = JS2VAL_TO_OBJECT(b);
|
||||
FunctionWrapper *fWrap = NULL;
|
||||
if ((fObj->kind == SimpleInstanceKind)
|
||||
@ -127,7 +126,6 @@
|
||||
if ((fObj->kind == PrototypeInstanceKind)
|
||||
&& ((checked_cast<PrototypeInstance *>(fObj))->type == meta->functionClass)) {
|
||||
fWrap = (checked_cast<FunctionInstance *>(fObj))->fWrap;
|
||||
// length = getLength(meta, fObj);
|
||||
}
|
||||
if (fWrap) {
|
||||
if (fWrap->compileFrame->prototype) {
|
||||
@ -138,10 +136,6 @@
|
||||
}
|
||||
}
|
||||
if (fWrap->code) { // native code
|
||||
// while (length > argCount) {
|
||||
// push(JS2VAL_UNDEFINED);
|
||||
// argCount++;
|
||||
// }
|
||||
a = fWrap->code(meta, a, base(argCount), argCount);
|
||||
pop(argCount + 2);
|
||||
push(a);
|
||||
@ -153,7 +147,7 @@
|
||||
// assignArguments(runtimeFrame, fWrap->compileFrame->signature);
|
||||
// XXX
|
||||
pFrame->assignArguments(meta, fObj, base(argCount), argCount);
|
||||
jsr(phase, fWrap->bCon, base(argCount + 2) - execStack, JS2VAL_VOID); // seems out of order, but we need to catch the current top frame
|
||||
jsr(phase, fWrap->bCon, base(argCount + 2) - execStack, JS2VAL_VOID, fWrap->env); // seems out of order, but we need to catch the current top frame
|
||||
meta->env->addFrame(pFrame);
|
||||
pFrame = NULL;
|
||||
}
|
||||
@ -175,7 +169,7 @@
|
||||
pFrame->thisObject = mc->thisObject;
|
||||
// assignArguments(runtimeFrame, fWrap->compileFrame->signature);
|
||||
pFrame->assignArguments(meta, fObj, base(argCount), argCount);
|
||||
jsr(phase, fWrap->bCon, base(argCount + 2) - execStack, JS2VAL_VOID); // seems out of order, but we need to catch the current top frame
|
||||
jsr(phase, fWrap->bCon, base(argCount + 2) - execStack, JS2VAL_VOID, fWrap->env); // seems out of order, but we need to catch the current top frame
|
||||
meta->env->addFrame(meta->objectType(mc->thisObject));
|
||||
meta->env->addFrame(pFrame);
|
||||
pFrame = NULL;
|
||||
@ -192,7 +186,7 @@
|
||||
push(a);
|
||||
}
|
||||
else
|
||||
meta->reportError(Exception::badValueError, "Un-callable object", errorPos());
|
||||
meta->reportError(Exception::badValueError, "{0} is not a function", errorPos(), JS2VAL_TO_STRING(typeofString(b)));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -340,51 +334,7 @@
|
||||
case eTypeof:
|
||||
{
|
||||
a = pop();
|
||||
if (JS2VAL_IS_UNDEFINED(a))
|
||||
a = STRING_TO_JS2VAL(undefined_StringAtom);
|
||||
else
|
||||
if (JS2VAL_IS_BOOLEAN(a))
|
||||
a = allocString("boolean");
|
||||
else
|
||||
if (JS2VAL_IS_NUMBER(a))
|
||||
a = allocString("number");
|
||||
else
|
||||
if (JS2VAL_IS_STRING(a))
|
||||
a = allocString("string");
|
||||
else {
|
||||
ASSERT(JS2VAL_IS_OBJECT(a));
|
||||
if (JS2VAL_IS_NULL(a))
|
||||
a = STRING_TO_JS2VAL(object_StringAtom);
|
||||
else {
|
||||
JS2Object *obj = JS2VAL_TO_OBJECT(a);
|
||||
switch (obj->kind) {
|
||||
case MultinameKind:
|
||||
a = allocString("namespace");
|
||||
break;
|
||||
case AttributeObjectKind:
|
||||
a = allocString("attribute");
|
||||
break;
|
||||
case ClassKind:
|
||||
case MethodClosureKind:
|
||||
a = STRING_TO_JS2VAL(Function_StringAtom);
|
||||
break;
|
||||
case PrototypeInstanceKind:
|
||||
if (checked_cast<PrototypeInstance *>(obj)->type == meta->functionClass)
|
||||
a = STRING_TO_JS2VAL(Function_StringAtom);
|
||||
else
|
||||
a = STRING_TO_JS2VAL(object_StringAtom);
|
||||
break;
|
||||
case PackageKind:
|
||||
case GlobalObjectKind:
|
||||
a = STRING_TO_JS2VAL(object_StringAtom);
|
||||
break;
|
||||
case SimpleInstanceKind:
|
||||
a = STRING_TO_JS2VAL(checked_cast<SimpleInstance *>(obj)->type->getName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
push(a);
|
||||
push(typeofString(a));
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user