Function literals, switch bcc to collect generic JS2Objects.
git-svn-id: svn://10.0.0.236/trunk@137889 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
c72534171c
commit
58d30a86b6
@ -150,14 +150,16 @@ namespace MetaData {
|
||||
for (std::vector<Multiname *>::iterator mi = mMultinameList.begin(), mend = mMultinameList.end(); (mi != mend); mi++) {
|
||||
GCMARKOBJECT(*mi);
|
||||
}
|
||||
for (std::vector<Frame *>::iterator fi = mFrameList.begin(), fend = mFrameList.end(); (fi != fend); fi++) {
|
||||
for (std::vector<JS2Object *>::iterator fi = mObjectList.begin(), fend = mObjectList.end(); (fi != fend); fi++) {
|
||||
GCMARKOBJECT(*fi);
|
||||
}
|
||||
for (std::vector<RegExpInstance *>::iterator ri = mRegExpList.begin(), rend = mRegExpList.end(); (ri != rend); ri++) {
|
||||
GCMARKOBJECT(*ri);
|
||||
}
|
||||
}
|
||||
|
||||
void BytecodeContainer::addFrame(Frame *f) { saveObject(f); addShort((uint16)(mObjectList.size() - 1)); }
|
||||
void BytecodeContainer::saveFrame(Frame *f) { saveObject(f); }
|
||||
void BytecodeContainer::addRegExp(RegExpInstance *x, size_t pos) { emitOp(eRegExp, pos); saveObject(x); addShort((uint16)(mObjectList.size() - 1)); }
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -80,6 +80,7 @@ public:
|
||||
#define NotALabel (BytecodeContainer::LabelID)(-1)
|
||||
|
||||
class Multiname;
|
||||
class JS2Object;
|
||||
class Frame;
|
||||
class RegExpInstance;
|
||||
|
||||
@ -137,9 +138,12 @@ public:
|
||||
// Maintain list of associated pointers, so as to keep the objects safe across gc's
|
||||
void addMultiname(Multiname *mn) { mMultinameList.push_back(mn); addShort((uint16)(mMultinameList.size() - 1)); }
|
||||
void saveMultiname(Multiname *mn) { mMultinameList.push_back(mn); }
|
||||
void addFrame(Frame *f) { mFrameList.push_back(f); addShort((uint16)(mFrameList.size() - 1)); }
|
||||
void saveFrame(Frame *f) { mFrameList.push_back(f); }
|
||||
void addRegExp(RegExpInstance *x, size_t pos) { emitOp(eRegExp, pos); mRegExpList.push_back(x); addShort((uint16)(mRegExpList.size() - 1)); }
|
||||
|
||||
void addFrame(Frame *f);
|
||||
void saveFrame(Frame *f);
|
||||
void addRegExp(RegExpInstance *x, size_t pos);
|
||||
void addObject(JS2Object *b) { mObjectList.push_back(b); addShort((uint16)(mObjectList.size() - 1)); }
|
||||
void saveObject(JS2Object *b) { mObjectList.push_back(b); }
|
||||
|
||||
void addOffset(int32 v) { mBuffer.insert(mBuffer.end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(int32)); }
|
||||
void setOffset(uint32 index, int32 v) { *((int32 *)(mBuffer.begin() + index)) = v; }
|
||||
@ -159,9 +163,8 @@ public:
|
||||
typedef std::vector<uint8> CodeBuffer;
|
||||
|
||||
CodeBuffer mBuffer;
|
||||
std::vector<RegExpInstance *> mRegExpList; // gc tracking
|
||||
std::vector<Multiname *> mMultinameList; // gc tracking
|
||||
std::vector<Frame *> mFrameList; // gc tracking
|
||||
std::vector<JS2Object *> mObjectList; // gc tracking
|
||||
|
||||
std::vector<String> mStringList;
|
||||
|
||||
|
||||
@ -435,6 +435,7 @@ namespace MetaData {
|
||||
{ eLongZero, "0(64)", 0 },
|
||||
{ eNumber, "Number", FLOAT64 },
|
||||
{ eRegExp, "RegExp", U16 },
|
||||
{ eFunction, "Function", U16 },
|
||||
{ eUInt64, "UInt64", 0 },
|
||||
{ eInt64, "Int64", 0 },
|
||||
{ eString, "String", STR_PTR }, // <string pointer:u32>
|
||||
@ -655,6 +656,7 @@ namespace MetaData {
|
||||
case eNull:
|
||||
case eThis:
|
||||
case eRegExp:
|
||||
case eFunction:
|
||||
case eUndefined:
|
||||
case eLongZero:
|
||||
return 1; // push literal value
|
||||
|
||||
@ -75,6 +75,7 @@ enum JS2Op {
|
||||
eLongZero,
|
||||
eNumber,
|
||||
eRegExp,
|
||||
eFunction,
|
||||
eUInt64,
|
||||
eInt64,
|
||||
eString, // <string pointer:u32>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -57,58 +57,37 @@ namespace MetaData {
|
||||
|
||||
js2val Function_Constructor(JS2Metadata *meta, const js2val thisValue, js2val argv[], uint32 argc)
|
||||
{
|
||||
js2val thatValue = OBJECT_TO_JS2VAL(new FunctionInstance(meta->functionClass->prototype, meta->functionClass));
|
||||
FunctionInstance *fnInst = checked_cast<FunctionInstance *>(JS2VAL_TO_OBJECT(thatValue));
|
||||
JS2Object::RootIterator ri = JS2Object::addRoot(&fnInst);
|
||||
fnInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_INACCESSIBLE, true));
|
||||
|
||||
if (argc) {
|
||||
const String *str = meta->toString(argv[0]);
|
||||
const String &srcLoc = widenCString("Function constructor source");
|
||||
const String *bodyStr = meta->toString(argv[argc - 1]);
|
||||
String functionExpr(widenCString("("));
|
||||
if (argc > 1) {
|
||||
for (uint32 i = 0; i < (argc - 1); i++) {
|
||||
functionExpr += *meta->toString(argv[i]);
|
||||
if (i < (argc - 2))
|
||||
functionExpr += ",";
|
||||
}
|
||||
}
|
||||
functionExpr += widenCString("){") + *bodyStr + widenCString("}");
|
||||
|
||||
Arena a;
|
||||
Pragma::Flags flags = Pragma::js1; // XXX get flags from meta/context ?
|
||||
Parser parser(meta->world, a, flags, *str, srcLoc);
|
||||
CompilationData *oldData = NULL;
|
||||
try {
|
||||
StmtNode *parsedStatements = parser.parseProgram();
|
||||
ASSERT(parser.lexer.peek(true).hasKind(Token::end));
|
||||
if (meta->showTrees)
|
||||
{
|
||||
PrettyPrinter f(stdOut, 80);
|
||||
{
|
||||
PrettyPrinter::Block b(f, 2);
|
||||
f << "Program =";
|
||||
f.linearBreak(1);
|
||||
StmtNode::printStatements(f, parsedStatements);
|
||||
}
|
||||
f.end();
|
||||
stdOut << '\n';
|
||||
}
|
||||
if (parsedStatements) {
|
||||
oldData = meta->startCompilationUnit(fnInst->fWrap->bCon, *str, srcLoc);
|
||||
meta->ValidateStmtList(parsedStatements);
|
||||
StmtNode *p = parsedStatements;
|
||||
size_t lastPos = p->pos;
|
||||
while (p) {
|
||||
meta->SetupStmt(meta->env, RunPhase, p);
|
||||
lastPos = p->pos;
|
||||
p = p->next;
|
||||
}
|
||||
fnInst->fWrap->bCon->emitOp(eReturnVoid, lastPos);
|
||||
}
|
||||
}
|
||||
catch (Exception &x) {
|
||||
if (oldData)
|
||||
meta->restoreCompilationUnit(oldData);
|
||||
JS2Object::removeRoot(ri);
|
||||
throw x;
|
||||
}
|
||||
if (oldData)
|
||||
meta->restoreCompilationUnit(oldData);
|
||||
Parser parser(meta->world, a, flags, functionExpr, srcLoc);
|
||||
FunctionExprNode *fnExpr = parser.parseFunctionExpression(meta->engine->errorPos());
|
||||
ASSERT(parser.lexer.peek(true).hasKind(Token::end));
|
||||
ASSERT(fnExpr); // otherwise, an exception would have been thrown out of here
|
||||
JS2Class *exprType;
|
||||
meta->ValidateExpression(&meta->cxt, meta->env, fnExpr);
|
||||
meta->SetupExprNode(meta->env, RunPhase, fnExpr, &exprType);
|
||||
ASSERT(fnExpr);
|
||||
return OBJECT_TO_JS2VAL(fnExpr->obj);
|
||||
}
|
||||
JS2Object::removeRoot(ri);
|
||||
return thatValue;
|
||||
else { // construct an empty function wrapper
|
||||
js2val thatValue = OBJECT_TO_JS2VAL(new FunctionInstance(meta->functionClass->prototype, meta->functionClass));
|
||||
FunctionInstance *fnInst = checked_cast<FunctionInstance *>(JS2VAL_TO_OBJECT(thatValue));
|
||||
fnInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_INACCESSIBLE, true));
|
||||
return thatValue;
|
||||
}
|
||||
}
|
||||
|
||||
static js2val Function_Call(JS2Metadata *meta, const js2val thisValue, js2val argv[], uint32 argc)
|
||||
|
||||
@ -85,7 +85,7 @@ namespace MetaData {
|
||||
}
|
||||
}
|
||||
|
||||
JS2Object *JS2Metadata::validateStaticFunction(FunctionStmtNode *f, js2val compileThis, bool prototype, bool unchecked, Context *cxt, Environment *env)
|
||||
JS2Object *JS2Metadata::validateStaticFunction(FunctionDefinition *fnDef, js2val compileThis, bool prototype, bool unchecked, Context *cxt, Environment *env)
|
||||
{
|
||||
ParameterFrame *compileFrame = new ParameterFrame(compileThis, prototype);
|
||||
JS2Object *result;
|
||||
@ -93,13 +93,13 @@ namespace MetaData {
|
||||
if (prototype) {
|
||||
FunctionInstance *fInst = new FunctionInstance(functionClass->prototype, functionClass);
|
||||
fInst->fWrap = new FunctionWrapper(unchecked, compileFrame);
|
||||
f->fWrap = fInst->fWrap;
|
||||
fnDef->fWrap = fInst->fWrap;
|
||||
result = fInst;
|
||||
}
|
||||
else {
|
||||
SimpleInstance *sInst = new SimpleInstance(functionClass);
|
||||
sInst->fWrap = new FunctionWrapper(unchecked, compileFrame);
|
||||
f->fWrap = sInst->fWrap;
|
||||
fnDef->fWrap = sInst->fWrap;
|
||||
result = sInst;
|
||||
}
|
||||
|
||||
@ -107,9 +107,9 @@ namespace MetaData {
|
||||
Frame *curTopFrame = env->getTopFrame();
|
||||
|
||||
try {
|
||||
CompilationData *oldData = startCompilationUnit(f->fWrap->bCon, bCon->mSource, bCon->mSourceLocation);
|
||||
CompilationData *oldData = startCompilationUnit(fnDef->fWrap->bCon, bCon->mSource, bCon->mSourceLocation);
|
||||
env->addFrame(compileFrame);
|
||||
VariableBinding *pb = f->function.parameters;
|
||||
VariableBinding *pb = fnDef->parameters;
|
||||
if (pb) {
|
||||
NamespaceList publicNamespaceList;
|
||||
publicNamespaceList.push_back(publicNamespace);
|
||||
@ -120,7 +120,7 @@ namespace MetaData {
|
||||
}
|
||||
if (prototype)
|
||||
writeDynamicProperty(result, new Multiname(engine->length_StringAtom, publicNamespace), true, INT_TO_JS2VAL(pCount), RunPhase);
|
||||
pb = f->function.parameters;
|
||||
pb = fnDef->parameters;
|
||||
compileFrame->positional = new Variable *[pCount];
|
||||
compileFrame->positionalCount = pCount;
|
||||
pCount = 0;
|
||||
@ -132,7 +132,7 @@ namespace MetaData {
|
||||
pb = pb->next;
|
||||
}
|
||||
}
|
||||
ValidateStmt(cxt, env, Plural, f->function.body);
|
||||
ValidateStmt(cxt, env, Plural, fnDef->body);
|
||||
env->removeTopFrame();
|
||||
restoreCompilationUnit(oldData);
|
||||
}
|
||||
@ -435,7 +435,7 @@ namespace MetaData {
|
||||
// XXX getter/setter --> ????
|
||||
}
|
||||
else {
|
||||
JS2Object *fObj = validateStaticFunction(f, compileThis, prototype, unchecked, cxt, env);
|
||||
JS2Object *fObj = validateStaticFunction(&f->function, compileThis, prototype, unchecked, cxt, env);
|
||||
if (unchecked
|
||||
&& (f->attributes == NULL)
|
||||
&& ((topFrame->kind == GlobalObjectKind)
|
||||
@ -455,7 +455,7 @@ namespace MetaData {
|
||||
case Attribute::Final:
|
||||
{
|
||||
// XXX Here the spec. has ???, so the following is tentative
|
||||
JS2Object *fObj = validateStaticFunction(f, compileThis, prototype, unchecked, cxt, env);
|
||||
JS2Object *fObj = validateStaticFunction(&f->function, compileThis, prototype, unchecked, cxt, env);
|
||||
JS2Class *c = checked_cast<JS2Class *>(env->getTopFrame());
|
||||
InstanceMember *m = new InstanceMethod(checked_cast<SimpleInstance *>(fObj));
|
||||
defineInstanceMember(c, cxt, f->function.name, a->namespaces, a->overrideMod, a->xplicit, ReadWriteAccess, m, p->pos);
|
||||
@ -465,7 +465,7 @@ namespace MetaData {
|
||||
{
|
||||
// XXX Here the spec. has ???, so the following is tentative
|
||||
ASSERT(!prototype); // XXX right?
|
||||
JS2Object *fObj = validateStaticFunction(f, compileThis, prototype, unchecked, cxt, env);
|
||||
JS2Object *fObj = validateStaticFunction(&f->function, compileThis, prototype, unchecked, cxt, env);
|
||||
ConstructorMethod *cm = new ConstructorMethod(OBJECT_TO_JS2VAL(fObj));
|
||||
defineLocalMember(env, f->function.name, a->namespaces, a->overrideMod, a->xplicit, ReadWriteAccess, cm, p->pos);
|
||||
}
|
||||
@ -1095,8 +1095,8 @@ namespace MetaData {
|
||||
case StmtNode::Function:
|
||||
{
|
||||
FunctionStmtNode *f = checked_cast<FunctionStmtNode *>(p);
|
||||
CompilationData *oldData = startCompilationUnit(f->fWrap->bCon, bCon->mSource, bCon->mSourceLocation);
|
||||
env->addFrame(f->fWrap->compileFrame);
|
||||
CompilationData *oldData = startCompilationUnit(f->function.fWrap->bCon, bCon->mSource, bCon->mSourceLocation);
|
||||
env->addFrame(f->function.fWrap->compileFrame);
|
||||
SetupStmt(env, phase, f->function.body);
|
||||
// XXX need to make sure that all paths lead to an exit of some kind
|
||||
bCon->emitOp(eReturnVoid, p->pos);
|
||||
@ -1663,6 +1663,12 @@ namespace MetaData {
|
||||
ValidateExpression(cxt, env, b->op2);
|
||||
}
|
||||
break;
|
||||
case ExprNode::functionLiteral:
|
||||
{
|
||||
FunctionExprNode *f = checked_cast<FunctionExprNode *>(p);
|
||||
f->obj = validateStaticFunction(&f->function, JS2VAL_INACCESSIBLE, true, true, cxt, env);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED("Not Yet Implemented");
|
||||
} // switch (p->getKind())
|
||||
@ -2267,6 +2273,18 @@ doUnary:
|
||||
SetupExprNode(env, phase, b->op2, exprType);
|
||||
}
|
||||
break;
|
||||
case ExprNode::functionLiteral:
|
||||
{
|
||||
FunctionExprNode *f = checked_cast<FunctionExprNode *>(p);
|
||||
CompilationData *oldData = startCompilationUnit(f->function.fWrap->bCon, bCon->mSource, bCon->mSourceLocation);
|
||||
env->addFrame(f->function.fWrap->compileFrame);
|
||||
SetupStmt(env, phase, f->function.body);
|
||||
// XXX need to make sure that all paths lead to an exit of some kind
|
||||
bCon->emitOp(eReturnVoid, p->pos);
|
||||
env->removeTopFrame();
|
||||
restoreCompilationUnit(oldData);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED("Not Yet Implemented");
|
||||
}
|
||||
|
||||
@ -1040,7 +1040,7 @@ public:
|
||||
void ValidateStmt(Context *cxt, Environment *env, Plurality pl, StmtNode *p);
|
||||
void ValidateExpression(Context *cxt, Environment *env, ExprNode *p);
|
||||
void ValidateAttributeExpression(Context *cxt, Environment *env, ExprNode *p);
|
||||
JS2Object *validateStaticFunction(FunctionStmtNode *f, js2val compileThis, bool prototype, bool unchecked, Context *cxt, Environment *env);
|
||||
JS2Object *validateStaticFunction(FunctionDefinition *fnDef, js2val compileThis, bool prototype, bool unchecked, Context *cxt, Environment *env);
|
||||
|
||||
js2val ExecuteStmtList(Phase phase, StmtNode *p);
|
||||
js2val EvalExpression(Environment *env, Phase phase, ExprNode *p);
|
||||
|
||||
@ -220,7 +220,7 @@
|
||||
|
||||
case ePushFrame:
|
||||
{
|
||||
Frame *f = bCon->mFrameList[BytecodeContainer::getShort(pc)];
|
||||
Frame *f = checked_cast<Frame *>(bCon->mObjectList[BytecodeContainer::getShort(pc)]);
|
||||
pc += sizeof(short);
|
||||
meta->env->addFrame(f);
|
||||
f->instantiate(meta->env);
|
||||
|
||||
@ -56,15 +56,15 @@
|
||||
|
||||
case eTrue:
|
||||
{
|
||||
push(JS2VAL_TRUE);
|
||||
}
|
||||
break;
|
||||
push(JS2VAL_TRUE);
|
||||
}
|
||||
break;
|
||||
|
||||
case eFalse:
|
||||
{
|
||||
push(JS2VAL_FALSE);
|
||||
}
|
||||
break;
|
||||
push(JS2VAL_FALSE);
|
||||
}
|
||||
break;
|
||||
|
||||
case eString:
|
||||
{
|
||||
@ -76,7 +76,15 @@
|
||||
|
||||
case eRegExp:
|
||||
{
|
||||
RegExpInstance *x = bCon->mRegExpList[BytecodeContainer::getShort(pc)];
|
||||
RegExpInstance *x = checked_cast<RegExpInstance *>(bCon->mObjectList[BytecodeContainer::getShort(pc)]);
|
||||
push(OBJECT_TO_JS2VAL(x));
|
||||
pc += sizeof(short);
|
||||
}
|
||||
break;
|
||||
|
||||
case eFunction:
|
||||
{
|
||||
JS2Object *x = checked_cast<JS2Object *>(bCon->mObjectList[BytecodeContainer::getShort(pc)]);
|
||||
push(OBJECT_TO_JS2VAL(x));
|
||||
pc += sizeof(short);
|
||||
}
|
||||
@ -84,15 +92,15 @@
|
||||
|
||||
case eNull:
|
||||
{
|
||||
push(JS2VAL_NULL);
|
||||
}
|
||||
break;
|
||||
push(JS2VAL_NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
case eUndefined:
|
||||
{
|
||||
push(JS2VAL_UNDEFINED);
|
||||
}
|
||||
break;
|
||||
push(JS2VAL_UNDEFINED);
|
||||
}
|
||||
break;
|
||||
|
||||
case eThis: // XXX literal?
|
||||
{
|
||||
|
||||
@ -59,6 +59,7 @@ namespace JavaScript {
|
||||
#ifdef EPIMETHEUS
|
||||
namespace MetaData {
|
||||
class Context;
|
||||
class JS2Object;
|
||||
class JS2Class;
|
||||
class Member;
|
||||
class Multiname;
|
||||
@ -313,6 +314,9 @@ namespace JavaScript {
|
||||
BlockStmtNode *body; // Body; nil if none
|
||||
|
||||
void print(PrettyPrinter &f, const AttributeStmtNode *attributes, bool noSemi) const;
|
||||
#ifdef EPIMETHEUS
|
||||
MetaData::FunctionWrapper *fWrap; // Runtime data, bytecode, parameters etc.
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@ -394,6 +398,9 @@ namespace JavaScript {
|
||||
explicit FunctionExprNode(size_t pos): ExprNode(pos, functionLiteral) {}
|
||||
|
||||
void print(PrettyPrinter &f) const;
|
||||
#ifdef EPIMETHEUS
|
||||
MetaData::JS2Object *obj; // used by backend to store the function object
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ExprPairList: ArenaObject {
|
||||
@ -701,9 +708,6 @@ namespace JavaScript {
|
||||
FunctionDefinition function; // Function definition
|
||||
#ifdef DIKDIK
|
||||
JS2Runtime::JSFunction *mFunction; // used by backend
|
||||
#endif
|
||||
#ifdef EPIMETHEUS
|
||||
MetaData::FunctionWrapper *fWrap; // Runtime data, bytecode, parameters etc.
|
||||
#endif
|
||||
FunctionStmtNode(size_t pos, Kind kind, ExprNode *attributes): AttributeStmtNode(pos, kind, attributes) {}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user