зеркало из https://github.com/mozilla/gecko-dev.git
Arithmetic. Global properties.
This commit is contained in:
Родитель
dbf6ed10ae
Коммит
35c3192b27
|
@ -115,7 +115,7 @@ public:
|
|||
void addPointer(const void *v) { ASSERT(sizeof(void *) == sizeof(uint32)); addLong((uint32)(v)); }
|
||||
static void *getPointer(void *pc) { return (void *)getLong(pc); }
|
||||
|
||||
void addFloat64(float64 v) { mBuffer.insert(mBuffer.end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(float64)); }
|
||||
void addFloat64(float64 v, size_t pos) { emitOp(eNumber, pos); mBuffer.insert(mBuffer.end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(float64)); }
|
||||
static float64 getFloat64(void *pc) { return *((float64 *)pc); }
|
||||
|
||||
void addLong(const uint32 v) { mBuffer.insert(mBuffer.end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(uint32)); }
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "utilities.h"
|
||||
#include "js2value.h"
|
||||
#include "numerics.h"
|
||||
#include "fdlibm_ns.h"
|
||||
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
|
@ -62,6 +63,7 @@
|
|||
namespace JavaScript {
|
||||
namespace MetaData {
|
||||
|
||||
// Begin execution of a bytecodeContainer
|
||||
js2val JS2Engine::interpret(JS2Metadata *metadata, Phase execPhase, BytecodeContainer *targetbCon)
|
||||
{
|
||||
bCon = targetbCon;
|
||||
|
@ -71,6 +73,7 @@ namespace MetaData {
|
|||
return interpreterLoop();
|
||||
}
|
||||
|
||||
// Execute the opcode sequence at pc.
|
||||
js2val JS2Engine::interpreterLoop()
|
||||
{
|
||||
js2val retval = JS2VAL_VOID;
|
||||
|
@ -83,7 +86,7 @@ namespace MetaData {
|
|||
#include "js2op_literal.cpp"
|
||||
#include "js2op_flowcontrol.cpp"
|
||||
}
|
||||
JS2Object::gc(meta);
|
||||
JS2Object::gc(meta); // XXX temporarily, for testing
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
@ -249,6 +252,9 @@ namespace MetaData {
|
|||
activationStackTop = activationStack = new ActivationFrame[MAX_ACTIVATION_STACK];
|
||||
}
|
||||
|
||||
// Return the effect of an opcode on the execution stack.
|
||||
// Some ops (e.g. eCall) have a variable effect, those are handled separately
|
||||
// (see emitOp)
|
||||
int getStackEffect(JS2Op op)
|
||||
{
|
||||
switch (op) {
|
||||
|
@ -257,19 +263,31 @@ namespace MetaData {
|
|||
|
||||
case eAdd: // pop two, push one
|
||||
case eSubtract:
|
||||
case eMultiply:
|
||||
case eDivide:
|
||||
case eModulo:
|
||||
case eEqual:
|
||||
case eNotEqual:
|
||||
case eLess:
|
||||
case eGreater:
|
||||
case eLessEqual:
|
||||
case eGreaterEqual:
|
||||
case eXor:
|
||||
case eLogicalXor:
|
||||
return -1;
|
||||
|
||||
case eMinus: // pop one, push one
|
||||
case ePlus:
|
||||
case eComplement:
|
||||
case eTypeof:
|
||||
return 0;
|
||||
|
||||
case eString:
|
||||
case eTrue:
|
||||
case eFalse:
|
||||
case eNumber:
|
||||
case eNull:
|
||||
case eThis:
|
||||
return 1; // push literal value
|
||||
|
||||
case eLexicalRead:
|
||||
|
@ -297,11 +315,17 @@ namespace MetaData {
|
|||
case eBranch:
|
||||
return 0;
|
||||
|
||||
case eDup: // duplicate top item
|
||||
return 1;
|
||||
|
||||
case ePop: // remove top item
|
||||
return -1;
|
||||
|
||||
case ePopv: // pop a statement result value
|
||||
return -1;
|
||||
|
||||
// case eToBoolean: // pop object, push boolean
|
||||
// return 0;
|
||||
case eToBoolean: // pop object, push boolean
|
||||
return 0;
|
||||
|
||||
case ePushFrame: // affect the frame stack...
|
||||
case ePopFrame: // ...not the exec stack
|
||||
|
@ -320,29 +344,41 @@ namespace MetaData {
|
|||
case eLexicalPreDec:
|
||||
return 1; // push the new/old value
|
||||
|
||||
case eLexicalAssignOp: // pop value, push result
|
||||
return 0;
|
||||
|
||||
case eDotPostInc:
|
||||
case eDotPostDec:
|
||||
case eDotPreInc:
|
||||
case eDotPreDec:
|
||||
return 0; // pop the base, push the new/old value
|
||||
|
||||
case eDotAssignOp: // pop base, pop value, push result
|
||||
return -1;
|
||||
|
||||
case eBracketPostInc:
|
||||
case eBracketPostDec:
|
||||
case eBracketPreInc:
|
||||
case eBracketPreDec:
|
||||
return -1; // pop the base, pop the index, push the new/old value
|
||||
|
||||
case eBracketAssignOp: // pop base, pop index, push result
|
||||
return 0;
|
||||
|
||||
default:
|
||||
ASSERT(false);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Return the mapped source location for the current pc
|
||||
size_t JS2Engine::errorPos()
|
||||
{
|
||||
return bCon->getPosition(pc - bCon->getCodeStart());
|
||||
}
|
||||
|
||||
// XXX Default construction of an instance of the class
|
||||
// that is the value at the top of the execution stack
|
||||
JS2Object *JS2Engine::defaultConstructor(JS2Engine *engine)
|
||||
{
|
||||
js2val v = engine->pop();
|
||||
|
@ -359,6 +395,8 @@ namespace MetaData {
|
|||
return new FixedInstance(c);
|
||||
}
|
||||
|
||||
// Save current engine state (pc, environment top) and
|
||||
// jump to start of new bytecodeContainer
|
||||
void JS2Engine::jsr(BytecodeContainer *new_bCon)
|
||||
{
|
||||
ASSERT(activationStackTop < (activationStack + MAX_ACTIVATION_STACK));
|
||||
|
@ -372,6 +410,7 @@ namespace MetaData {
|
|||
|
||||
}
|
||||
|
||||
// Return to previously saved execution state
|
||||
void JS2Engine::rts()
|
||||
{
|
||||
ASSERT(activationStackTop > activationStack);
|
||||
|
@ -384,6 +423,8 @@ namespace MetaData {
|
|||
|
||||
}
|
||||
|
||||
// GC-mark any JS2Objects in the activation frame stack, the execution stack
|
||||
// and in structures contained in those locations.
|
||||
void JS2Engine::mark()
|
||||
{
|
||||
if (bCon)
|
||||
|
@ -404,6 +445,17 @@ namespace MetaData {
|
|||
}
|
||||
}
|
||||
|
||||
int32 JS2Engine::toInt32(float64 d)
|
||||
{
|
||||
if ((d == 0.0) || !JSDOUBLE_IS_FINITE(d) )
|
||||
return 0;
|
||||
d = fd::fmod(d, two32);
|
||||
d = (d >= 0) ? d : d + two32;
|
||||
if (d >= two31)
|
||||
return (int32)(d - two32);
|
||||
else
|
||||
return (int32)(d);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -51,17 +51,26 @@ namespace MetaData {
|
|||
enum JS2Op {
|
||||
eAdd,
|
||||
eSubtract,
|
||||
eMultiply,
|
||||
eDivide,
|
||||
eModulo,
|
||||
eEqual,
|
||||
eNotEqual,
|
||||
eLess,
|
||||
eGreater,
|
||||
eLessEqual,
|
||||
eGreaterEqual,
|
||||
eXor,
|
||||
eLogicalXor,
|
||||
eMinus,
|
||||
ePlus,
|
||||
eComplement,
|
||||
eTrue,
|
||||
eFalse,
|
||||
eNull,
|
||||
eNumber,
|
||||
eString, // <string pointer:u32>
|
||||
eThis,
|
||||
eNewObject, // <argCount:u16>
|
||||
eLexicalRead, // <multiname index:u16>
|
||||
eLexicalWrite, // <multiname index:u16>
|
||||
|
@ -76,27 +85,33 @@ enum JS2Op {
|
|||
eReturnVoid,
|
||||
ePushFrame, // <frame index:u16>
|
||||
ePopFrame,
|
||||
// eToBoolean,
|
||||
eToBoolean,
|
||||
eBranchFalse, // <branch displacement:s32> XXX save space with short and long versions instead ?
|
||||
eBranchTrue, // <branch displacement:s32>
|
||||
eBranch, // <branch displacement:s32>
|
||||
eNew, // <argCount:u16>
|
||||
eCall, // <argCount:u16>
|
||||
eTypeof,
|
||||
|
||||
ePopv,
|
||||
ePop,
|
||||
eDup,
|
||||
|
||||
eLexicalPostInc, // <multiname index:u16>
|
||||
eLexicalPostDec, // <multiname index:u16>
|
||||
eLexicalPreInc, // <multiname index:u16>
|
||||
eLexicalPreDec, // <multiname index:u16>
|
||||
eLexicalAssignOp, // <op:u8> <multiname index:u16>
|
||||
eDotPostInc, // <multiname index:u16>
|
||||
eDotPostDec, // <multiname index:u16>
|
||||
eDotPreInc, // <multiname index:u16>
|
||||
eDotPreDec, // <multiname index:u16>
|
||||
eDotAssignOp, // <op:u8> <multiname index:u16>
|
||||
eBracketPostInc,
|
||||
eBracketPostDec,
|
||||
eBracketPreInc,
|
||||
eBracketPreDec,
|
||||
eBracketAssignOp, // <op:u8>
|
||||
|
||||
};
|
||||
|
||||
|
@ -129,7 +144,7 @@ public:
|
|||
js2val toPrimitive(js2val x) { if (JS2VAL_IS_PRIMITIVE(x)) return x; else return convertValueToPrimitive(x); }
|
||||
float64 toNumber(js2val x) { if (JS2VAL_IS_INT(x)) return JS2VAL_TO_INT(x); else if (JS2VAL_IS_DOUBLE(x)) return *JS2VAL_TO_DOUBLE(x); else return convertValueToDouble(x); }
|
||||
bool toBoolean(js2val x) { if (JS2VAL_IS_BOOLEAN(x)) return JS2VAL_TO_BOOLEAN(x); else return convertValueToBoolean(x); }
|
||||
|
||||
int32 toInt32(float64 f);
|
||||
|
||||
js2val assignmentConversion(js2val val, JS2Class *type) { return val; } // XXX s'more code, please
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include "world.h"
|
||||
#include "utilities.h"
|
||||
#include "js2value.h"
|
||||
#include "numerics.h"
|
||||
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
|
@ -1035,6 +1036,8 @@ namespace MetaData {
|
|||
{
|
||||
}
|
||||
|
||||
// Convert an attribute to a compoundAttribute. If the attribute
|
||||
// is NULL, return a default compoundAttribute
|
||||
CompoundAttribute *Attribute::toCompoundAttribute(Attribute *a)
|
||||
{
|
||||
if (a)
|
||||
|
@ -1043,6 +1046,7 @@ namespace MetaData {
|
|||
return new CompoundAttribute();
|
||||
}
|
||||
|
||||
// Convert a simple namespace to a compoundAttribute with that namespace
|
||||
CompoundAttribute *Namespace::toCompoundAttribute()
|
||||
{
|
||||
CompoundAttribute *t = new CompoundAttribute();
|
||||
|
@ -1050,11 +1054,13 @@ namespace MetaData {
|
|||
return t;
|
||||
}
|
||||
|
||||
// Convert a 'true' attribute to a default compoundAttribute
|
||||
CompoundAttribute *TrueAttribute::toCompoundAttribute()
|
||||
{
|
||||
return new CompoundAttribute();
|
||||
}
|
||||
|
||||
// gc-mark all contained JS2Objects and visit contained structures to do likewise
|
||||
void CompoundAttribute::markChildren()
|
||||
{
|
||||
if (namespaces) {
|
||||
|
@ -1074,10 +1080,11 @@ namespace MetaData {
|
|||
// Validate the entire expression rooted at p
|
||||
void JS2Metadata::ValidateExpression(Context *cxt, Environment *env, ExprNode *p)
|
||||
{
|
||||
JS2Object::gc(this);
|
||||
JS2Object::gc(this); // XXX testing stability
|
||||
switch (p->getKind()) {
|
||||
case ExprNode::Null:
|
||||
case ExprNode::number:
|
||||
case ExprNode::string:
|
||||
case ExprNode::boolean:
|
||||
break;
|
||||
case ExprNode::This:
|
||||
|
@ -1124,6 +1131,17 @@ namespace MetaData {
|
|||
case ExprNode::assignment:
|
||||
case ExprNode::add:
|
||||
case ExprNode::subtract:
|
||||
case ExprNode::multiply:
|
||||
case ExprNode::divide:
|
||||
case ExprNode::modulo:
|
||||
case ExprNode::addEquals:
|
||||
case ExprNode::subtractEquals:
|
||||
case ExprNode::multiplyEquals:
|
||||
case ExprNode::divideEquals:
|
||||
case ExprNode::moduloEquals:
|
||||
case ExprNode::logicalAnd:
|
||||
case ExprNode::logicalXor:
|
||||
case ExprNode::logicalOr:
|
||||
{
|
||||
BinaryExprNode *b = checked_cast<BinaryExprNode *>(p);
|
||||
ValidateExpression(cxt, env, b->op1);
|
||||
|
@ -1131,10 +1149,15 @@ namespace MetaData {
|
|||
}
|
||||
break;
|
||||
|
||||
case ExprNode::minus:
|
||||
case ExprNode::plus:
|
||||
case ExprNode::complement:
|
||||
case ExprNode::postIncrement:
|
||||
case ExprNode::postDecrement:
|
||||
case ExprNode::preIncrement:
|
||||
case ExprNode::preDecrement:
|
||||
case ExprNode::parentheses:
|
||||
case ExprNode::Typeof:
|
||||
{
|
||||
UnaryExprNode *u = checked_cast<UnaryExprNode *>(p);
|
||||
ValidateExpression(cxt, env, u->op);
|
||||
|
@ -1177,7 +1200,7 @@ namespace MetaData {
|
|||
|
||||
|
||||
/*
|
||||
* Evaluate an expression 'p' and execute the associated bytecode
|
||||
* Evaluate an expression 'p' AND execute the associated bytecode
|
||||
*/
|
||||
js2val JS2Metadata::EvalExpression(Environment *env, Phase phase, ExprNode *p)
|
||||
{
|
||||
|
@ -1192,15 +1215,21 @@ namespace MetaData {
|
|||
}
|
||||
|
||||
/*
|
||||
* Evaluate the expression rooted at p.
|
||||
* Evaluate the expression (i.e. generate bytecode, but don't execute) rooted at p.
|
||||
*/
|
||||
Reference *JS2Metadata::EvalExprNode(Environment *env, Phase phase, ExprNode *p)
|
||||
{
|
||||
Reference *returnRef = NULL;
|
||||
JS2Op binaryOp;
|
||||
JS2Op op;
|
||||
|
||||
switch (p->getKind()) {
|
||||
|
||||
case ExprNode::parentheses:
|
||||
{
|
||||
UnaryExprNode *u = checked_cast<UnaryExprNode *>(p);
|
||||
EvalExprNode(env, phase, u->op);
|
||||
}
|
||||
break;
|
||||
case ExprNode::assignment:
|
||||
{
|
||||
if (phase == CompilePhase) reportError(Exception::compileExpressionError, "Inappropriate compile time expression", p->pos);
|
||||
|
@ -1215,30 +1244,68 @@ namespace MetaData {
|
|||
reportError(Exception::semanticError, "Assignment needs an lValue", p->pos);
|
||||
}
|
||||
break;
|
||||
case ExprNode::addEquals:
|
||||
op = eAdd;
|
||||
goto doAssignBinary;
|
||||
case ExprNode::subtractEquals:
|
||||
op = eSubtract;
|
||||
goto doAssignBinary;
|
||||
case ExprNode::multiplyEquals:
|
||||
op = eMultiply;
|
||||
goto doAssignBinary;
|
||||
case ExprNode::divideEquals:
|
||||
op = eDivide;
|
||||
goto doAssignBinary;
|
||||
case ExprNode::moduloEquals:
|
||||
op = eModulo;
|
||||
goto doAssignBinary;
|
||||
doAssignBinary:
|
||||
{
|
||||
if (phase == CompilePhase) reportError(Exception::compileExpressionError, "Inappropriate compile time expression", p->pos);
|
||||
BinaryExprNode *b = checked_cast<BinaryExprNode *>(p);
|
||||
Reference *lVal = EvalExprNode(env, phase, b->op1);
|
||||
if (lVal) {
|
||||
Reference *rVal = EvalExprNode(env, phase, b->op2);
|
||||
if (rVal) rVal->emitReadBytecode(bCon, p->pos);
|
||||
lVal->emitAssignOpBytecode(bCon, op, p->pos);
|
||||
}
|
||||
else
|
||||
reportError(Exception::semanticError, "Assignment needs an lValue", p->pos);
|
||||
}
|
||||
break;
|
||||
case ExprNode::lessThan:
|
||||
binaryOp = eLess;
|
||||
op = eLess;
|
||||
goto doBinary;
|
||||
case ExprNode::lessThanOrEqual:
|
||||
binaryOp = eLessEqual;
|
||||
op = eLessEqual;
|
||||
goto doBinary;
|
||||
case ExprNode::greaterThan:
|
||||
binaryOp = eGreater;
|
||||
op = eGreater;
|
||||
goto doBinary;
|
||||
case ExprNode::greaterThanOrEqual:
|
||||
binaryOp = eGreaterEqual;
|
||||
op = eGreaterEqual;
|
||||
goto doBinary;
|
||||
case ExprNode::equal:
|
||||
binaryOp = eEqual;
|
||||
op = eEqual;
|
||||
goto doBinary;
|
||||
case ExprNode::notEqual:
|
||||
binaryOp = eNotEqual;
|
||||
op = eNotEqual;
|
||||
goto doBinary;
|
||||
|
||||
case ExprNode::add:
|
||||
binaryOp = eAdd;
|
||||
op = eAdd;
|
||||
goto doBinary;
|
||||
case ExprNode::subtract:
|
||||
binaryOp = eSubtract;
|
||||
op = eSubtract;
|
||||
goto doBinary;
|
||||
case ExprNode::multiply:
|
||||
op = eMultiply;
|
||||
goto doBinary;
|
||||
case ExprNode::divide:
|
||||
op = eDivide;
|
||||
goto doBinary;
|
||||
case ExprNode::modulo:
|
||||
op = eModulo;
|
||||
goto doBinary;
|
||||
doBinary:
|
||||
{
|
||||
|
@ -1247,12 +1314,74 @@ doBinary:
|
|||
if (lVal) lVal->emitReadBytecode(bCon, p->pos);
|
||||
Reference *rVal = EvalExprNode(env, phase, b->op2);
|
||||
if (rVal) rVal->emitReadBytecode(bCon, p->pos);
|
||||
bCon->emitOp(binaryOp, p->pos);
|
||||
bCon->emitOp(op, p->pos);
|
||||
}
|
||||
break;
|
||||
case ExprNode::minus:
|
||||
op = eMinus;
|
||||
goto doUnary;
|
||||
case ExprNode::plus:
|
||||
op = ePlus;
|
||||
goto doUnary;
|
||||
case ExprNode::complement:
|
||||
op = eComplement;
|
||||
goto doUnary;
|
||||
doUnary:
|
||||
{
|
||||
UnaryExprNode *u = checked_cast<UnaryExprNode *>(p);
|
||||
Reference *rVal = EvalExprNode(env, phase, u->op);
|
||||
if (rVal) rVal->emitReadBytecode(bCon, p->pos);
|
||||
bCon->emitOp(op, p->pos);
|
||||
}
|
||||
break;
|
||||
|
||||
case ExprNode::logicalAnd:
|
||||
{
|
||||
BinaryExprNode *b = checked_cast<BinaryExprNode *>(p);
|
||||
BytecodeContainer::LabelID skipOverSecondHalf = bCon->getLabel();
|
||||
Reference *lVal = EvalExprNode(env, phase, b->op1);
|
||||
if (lVal) lVal->emitReadBytecode(bCon, p->pos);
|
||||
bCon->emitOp(eDup, p->pos);
|
||||
bCon->emitBranch(eBranchFalse, skipOverSecondHalf, p->pos);
|
||||
bCon->emitOp(ePop, p->pos);
|
||||
Reference *rVal = EvalExprNode(env, phase, b->op2);
|
||||
if (rVal) rVal->emitReadBytecode(bCon, p->pos);
|
||||
bCon->setLabel(skipOverSecondHalf);
|
||||
}
|
||||
break;
|
||||
|
||||
case ExprNode::logicalXor:
|
||||
{
|
||||
BinaryExprNode *b = checked_cast<BinaryExprNode *>(p);
|
||||
Reference *lVal = EvalExprNode(env, phase, b->op1);
|
||||
if (lVal) lVal->emitReadBytecode(bCon, p->pos);
|
||||
bCon->emitOp(eToBoolean, p->pos);
|
||||
Reference *rVal = EvalExprNode(env, phase, b->op2);
|
||||
if (rVal) rVal->emitReadBytecode(bCon, p->pos);
|
||||
bCon->emitOp(eToBoolean, p->pos);
|
||||
bCon->emitOp(eLogicalXor, p->pos);
|
||||
}
|
||||
break;
|
||||
|
||||
case ExprNode::logicalOr:
|
||||
{
|
||||
BinaryExprNode *b = checked_cast<BinaryExprNode *>(p);
|
||||
BytecodeContainer::LabelID skipOverSecondHalf = bCon->getLabel();
|
||||
Reference *lVal = EvalExprNode(env, phase, b->op1);
|
||||
if (lVal) lVal->emitReadBytecode(bCon, p->pos);
|
||||
bCon->emitOp(eDup, p->pos);
|
||||
bCon->emitBranch(eBranchTrue, skipOverSecondHalf, p->pos);
|
||||
bCon->emitOp(ePop, p->pos);
|
||||
Reference *rVal = EvalExprNode(env, phase, b->op2);
|
||||
if (rVal) rVal->emitReadBytecode(bCon, p->pos);
|
||||
bCon->setLabel(skipOverSecondHalf);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case ExprNode::This:
|
||||
{
|
||||
|
||||
bCon->emitOp(eThis, p->pos);
|
||||
}
|
||||
break;
|
||||
case ExprNode::Null:
|
||||
|
@ -1262,8 +1391,12 @@ doBinary:
|
|||
break;
|
||||
case ExprNode::number:
|
||||
{
|
||||
bCon->emitOp(eNumber, p->pos);
|
||||
bCon->addFloat64(checked_cast<NumberExprNode *>(p)->value);
|
||||
bCon->addFloat64(checked_cast<NumberExprNode *>(p)->value, p->pos);
|
||||
}
|
||||
break;
|
||||
case ExprNode::string:
|
||||
{
|
||||
bCon->addString(checked_cast<StringExprNode *>(p)->str, p->pos);
|
||||
}
|
||||
break;
|
||||
case ExprNode::qualify:
|
||||
|
@ -1398,6 +1531,14 @@ doBinary:
|
|||
bCon->addShort(argCount);
|
||||
}
|
||||
break;
|
||||
case ExprNode::Typeof:
|
||||
{
|
||||
UnaryExprNode *u = checked_cast<UnaryExprNode *>(p);
|
||||
Reference *rVal = EvalExprNode(env, phase, u->op);
|
||||
if (rVal) rVal->emitReadBytecode(bCon, p->pos);
|
||||
bCon->emitOp(eTypeof, p->pos);
|
||||
}
|
||||
break;
|
||||
case ExprNode::call:
|
||||
{
|
||||
InvokeExprNode *i = checked_cast<InvokeExprNode *>(p);
|
||||
|
@ -1436,6 +1577,7 @@ doBinary:
|
|||
return returnRef;
|
||||
}
|
||||
|
||||
// Execute an expression and return the result, which must be a type
|
||||
JS2Class *JS2Metadata::EvalTypeExpression(Environment *env, Phase phase, ExprNode *p)
|
||||
{
|
||||
js2val retval = EvalExpression(env, phase, p);
|
||||
|
@ -1608,6 +1750,7 @@ doBinary:
|
|||
return false;
|
||||
}
|
||||
|
||||
// add all the open namespaces from the given context
|
||||
void Multiname::addNamespace(Context &cxt)
|
||||
{
|
||||
addNamespace(&cxt.openNamespaces);
|
||||
|
@ -1622,6 +1765,7 @@ doBinary:
|
|||
nsList.push_back(*nli);
|
||||
}
|
||||
|
||||
// gc-mark all contained JS2Objects and visit contained structures to do likewise
|
||||
void Multiname::markChildren()
|
||||
{
|
||||
for (NamespaceListIterator n = nsList.begin(), end = nsList.end(); (n != end); n++) {
|
||||
|
@ -1920,6 +2064,9 @@ doBinary:
|
|||
//else A hoisted binding of the same var already exists, so there is no need to create another one
|
||||
}
|
||||
|
||||
void t(JS2Engine *engine)
|
||||
{
|
||||
}
|
||||
|
||||
#define MAKEBUILTINCLASS(c, super, dynamic, allowNull, final, name) c = new JS2Class(super, new JS2Object(PrototypeInstanceKind), new Namespace(engine->private_StringAtom), dynamic, allowNull, final, name); c->complete = true
|
||||
|
||||
|
@ -1950,6 +2097,20 @@ doBinary:
|
|||
MAKEBUILTINCLASS(packageClass, objectClass, true, true, true, world.identifiers["package"]);
|
||||
|
||||
forbiddenMember = new StaticMember(Member::Forbidden);
|
||||
|
||||
writeDynamicProperty(glob, new Multiname(engine->undefined_StringAtom, publicNamespace), true, JS2VAL_UNDEFINED, RunPhase);
|
||||
writeDynamicProperty(glob, new Multiname(world.identifiers["NaN"], publicNamespace), true, engine->allocNumber(nan), RunPhase);
|
||||
writeDynamicProperty(glob, new Multiname(world.identifiers["Infinity"], publicNamespace), true, engine->allocNumber(positiveInfinity), RunPhase);
|
||||
|
||||
FixedInstance *fInst = new FixedInstance(functionClass);
|
||||
fInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_VOID, true), t);
|
||||
env.addFrame(objectClass);
|
||||
NamespaceList publicNamespaceList;
|
||||
publicNamespaceList.push_back(publicNamespace);
|
||||
Variable *v = new Variable(functionClass, OBJECT_TO_JS2VAL(fInst), true);
|
||||
defineStaticMember(&env, world.identifiers["toString"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
|
||||
env.removeTopFrame();
|
||||
|
||||
}
|
||||
|
||||
// objectType(o) returns an OBJECT o's most specific type.
|
||||
|
@ -2098,7 +2259,7 @@ doBinary:
|
|||
return false; // 'None'
|
||||
}
|
||||
|
||||
// Read the static member
|
||||
// Read a value from the static member
|
||||
bool JS2Metadata::readStaticMember(StaticMember *m, Phase phase, js2val *rval)
|
||||
{
|
||||
if (m == NULL)
|
||||
|
@ -2122,7 +2283,7 @@ doBinary:
|
|||
return false;
|
||||
}
|
||||
|
||||
// Write the static member
|
||||
// Write a value to the static member
|
||||
bool JS2Metadata::writeStaticMember(StaticMember *m, js2val newValue, Phase phase)
|
||||
{
|
||||
if (m == NULL)
|
||||
|
@ -2316,7 +2477,9 @@ readClassProperty:
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Write the value of an instance member into a container instance.
|
||||
// Only instanceVariables are writable.
|
||||
bool JS2Metadata::writeInstanceMember(js2val containerVal, JS2Class *c, QualifiedName *qname, js2val newValue, Phase phase)
|
||||
{
|
||||
if (phase == CompilePhase)
|
||||
|
@ -2380,7 +2543,7 @@ readClassProperty:
|
|||
}
|
||||
}
|
||||
|
||||
// Find a binding in the frame that matches the multiname and access
|
||||
// Find a binding that matches the multiname and access.
|
||||
// It's an error if more than one such binding exists.
|
||||
StaticMember *JS2Metadata::findFlatMember(Frame *container, Multiname *multiname, Access access, Phase phase)
|
||||
{
|
||||
|
@ -2416,7 +2579,8 @@ readClassProperty:
|
|||
return found;
|
||||
}
|
||||
|
||||
|
||||
// Find the multiname in the class - either in the static bindings (first) or
|
||||
// in the instance bindings. If not there, look in the super class.
|
||||
bool JS2Metadata::findStaticMember(JS2Class *c, Multiname *multiname, Access access, Phase phase, MemberDescriptor *result)
|
||||
{
|
||||
JS2Class *s = c;
|
||||
|
@ -2522,6 +2686,8 @@ readClassProperty:
|
|||
// and then invoke mark on all other structures that contain JS2Objects
|
||||
void JS2Metadata::mark()
|
||||
{
|
||||
// XXX - maybe have a separate pool to allocate chunks
|
||||
// that are meant to be never collected?
|
||||
GCMARKOBJECT(publicNamespace);
|
||||
GCMARKOBJECT(forbiddenMember);
|
||||
GCMARKOBJECT(undefinedClass);
|
||||
|
@ -2574,6 +2740,7 @@ readClassProperty:
|
|||
}
|
||||
|
||||
inline char narrow(char16 ch) { return char(ch); }
|
||||
|
||||
// Accepts a String as the error argument and converts to char *
|
||||
void JS2Metadata::reportError(Exception::Kind kind, const char *message, size_t pos, const String& name)
|
||||
{
|
||||
|
@ -2700,6 +2867,7 @@ readClassProperty:
|
|||
|
||||
}
|
||||
|
||||
// gc-mark all contained JS2Objects and visit contained structures to do likewise
|
||||
void JS2Class::markChildren()
|
||||
{
|
||||
GCMARKOBJECT(super)
|
||||
|
@ -2720,7 +2888,8 @@ readClassProperty:
|
|||
*
|
||||
************************************************************************************/
|
||||
|
||||
|
||||
// Construct a dynamic instance of a class. Set the
|
||||
// initial value of all slots to uninitialized.
|
||||
DynamicInstance::DynamicInstance(JS2Class *type)
|
||||
: JS2Object(DynamicInstanceKind),
|
||||
type(type),
|
||||
|
@ -2735,6 +2904,7 @@ readClassProperty:
|
|||
}
|
||||
}
|
||||
|
||||
// gc-mark all contained JS2Objects and visit contained structures to do likewise
|
||||
void DynamicInstance::markChildren()
|
||||
{
|
||||
GCMARKOBJECT(type)
|
||||
|
@ -2764,6 +2934,8 @@ readClassProperty:
|
|||
************************************************************************************/
|
||||
|
||||
|
||||
// Construct a fixed instance of a class. Set the
|
||||
// initial value of all slots to uninitialized.
|
||||
FixedInstance::FixedInstance(JS2Class *type)
|
||||
: JS2Object(FixedInstanceKind),
|
||||
type(type),
|
||||
|
@ -2779,12 +2951,14 @@ readClassProperty:
|
|||
}
|
||||
}
|
||||
|
||||
// gc-mark all contained JS2Objects and visit contained structures to do likewise
|
||||
void FixedInstance::markChildren()
|
||||
{
|
||||
GCMARKOBJECT(type)
|
||||
if (fWrap) {
|
||||
GCMARKOBJECT(fWrap->compileFrame);
|
||||
fWrap->bCon->mark();
|
||||
if (fWrap->bCon)
|
||||
fWrap->bCon->mark();
|
||||
}
|
||||
if (slots) {
|
||||
ASSERT(type);
|
||||
|
@ -2804,7 +2978,7 @@ readClassProperty:
|
|||
*
|
||||
************************************************************************************/
|
||||
|
||||
|
||||
// gc-mark all contained JS2Objects and visit contained structures to do likewise
|
||||
void PrototypeInstance::markChildren()
|
||||
{
|
||||
GCMARKOBJECT(parent)
|
||||
|
@ -2823,6 +2997,7 @@ readClassProperty:
|
|||
*
|
||||
************************************************************************************/
|
||||
|
||||
// gc-mark all contained JS2Objects and visit contained structures to do likewise
|
||||
void MethodClosure::markChildren()
|
||||
{
|
||||
if (JS2VAL_IS_OBJECT(thisObject)) {
|
||||
|
@ -2838,6 +3013,7 @@ readClassProperty:
|
|||
*
|
||||
************************************************************************************/
|
||||
|
||||
// gc-mark all contained JS2Objects and visit contained structures to do likewise
|
||||
void Frame::markChildren()
|
||||
{
|
||||
GCMARKOBJECT(nextFrame)
|
||||
|
@ -2858,6 +3034,7 @@ readClassProperty:
|
|||
*
|
||||
************************************************************************************/
|
||||
|
||||
// gc-mark all contained JS2Objects and visit contained structures to do likewise
|
||||
void GlobalObject::markChildren()
|
||||
{
|
||||
Frame::markChildren();
|
||||
|
@ -2882,6 +3059,7 @@ readClassProperty:
|
|||
env->instantiateFrame(pluralFrame, this);
|
||||
}
|
||||
|
||||
// gc-mark all contained JS2Objects and visit contained structures to do likewise
|
||||
void ParameterFrame::markChildren()
|
||||
{
|
||||
Frame::markChildren();
|
||||
|
@ -2921,6 +3099,7 @@ readClassProperty:
|
|||
type->mark();
|
||||
}
|
||||
|
||||
// gc-mark all contained JS2Objects and visit contained structures to do likewise
|
||||
void InstanceMember::markChildren()
|
||||
{
|
||||
type->markChildren();
|
||||
|
@ -2933,6 +3112,8 @@ readClassProperty:
|
|||
*
|
||||
************************************************************************************/
|
||||
|
||||
// An instance variable type could be future'd when a gc runs (i.e. validate
|
||||
// has executed, but the pre-eval stage has yet to determine the actual type)
|
||||
bool InstanceVariable::isMarked()
|
||||
{
|
||||
if (type != FUTURE_TYPE)
|
||||
|
@ -2947,6 +3128,7 @@ readClassProperty:
|
|||
type->mark();
|
||||
}
|
||||
|
||||
// gc-mark all contained JS2Objects and visit contained structures to do likewise
|
||||
void InstanceVariable::markChildren()
|
||||
{
|
||||
if (type != FUTURE_TYPE)
|
||||
|
@ -2970,6 +3152,7 @@ readClassProperty:
|
|||
fInst->mark();
|
||||
}
|
||||
|
||||
// gc-mark all contained JS2Objects and visit contained structures to do likewise
|
||||
void InstanceMethod::markChildren()
|
||||
{
|
||||
fInst->markChildren();
|
||||
|
@ -2985,6 +3168,9 @@ readClassProperty:
|
|||
Pond JS2Object::pond(POND_SIZE, NULL);
|
||||
std::list<PondScum **> JS2Object::rootList;
|
||||
|
||||
// Add a pointer to a gc-allocated object to the root list
|
||||
// (Note - we hand out an iterator, so it's essential to
|
||||
// use something like std::list that doesn't mess with locations)
|
||||
JS2Object::RootIterator JS2Object::addRoot(void *t)
|
||||
{
|
||||
PondScum **p = (PondScum **)t;
|
||||
|
@ -2992,11 +3178,13 @@ readClassProperty:
|
|||
return rootList.insert(rootList.end(), p);
|
||||
}
|
||||
|
||||
// Remove a root pointer
|
||||
void JS2Object::removeRoot(RootIterator ri)
|
||||
{
|
||||
rootList.erase(ri);
|
||||
}
|
||||
|
||||
// Mark all reachable objects and put the rest back on the freelist
|
||||
void JS2Object::gc(JS2Metadata *meta)
|
||||
{
|
||||
pond.resetMarks();
|
||||
|
@ -3016,6 +3204,7 @@ readClassProperty:
|
|||
pond.moveUnmarkedToFreeList();
|
||||
}
|
||||
|
||||
// Allocate a chink of size s and mark whether it's a JS2Object or not
|
||||
void *JS2Object::alloc(size_t s, bool isJS2Object)
|
||||
{
|
||||
s += sizeof(PondScum);
|
||||
|
@ -3025,6 +3214,7 @@ readClassProperty:
|
|||
return pond.allocFromPond((int32)s, isJS2Object);
|
||||
}
|
||||
|
||||
// Release a chunk back to it's pond
|
||||
void JS2Object::unalloc(void *t)
|
||||
{
|
||||
PondScum *p = (PondScum *)t - 1;
|
||||
|
|
|
@ -57,16 +57,25 @@ typedef void (Invokable)();
|
|||
typedef Invokable Callor;
|
||||
typedef JS2Object *(Constructor)(JS2Engine *engine);
|
||||
|
||||
|
||||
// OBJECT is the semantic domain of all possible objects and is defined as:
|
||||
// OBJECT = UNDEFINED | NULL | BOOLEAN | FLOAT64 | LONG | ULONG | CHARACTER | STRING | NAMESPACE |
|
||||
// COMPOUNDATTRIBUTE | CLASS | METHODCLOSURE | PROTOTYPE | INSTANCE | PACKAGE | GLOBAL
|
||||
//
|
||||
// In this implementation, the primitive types are distinguished by the tag value
|
||||
// of a JS2Value (see js2value.h). Non-primitive types are distinguished by calling
|
||||
// 'kind()' on the object to recover one of the values below:
|
||||
//
|
||||
enum ObjectKind {
|
||||
AttributeObjectKind,
|
||||
SystemKind,
|
||||
AttributeObjectKind,
|
||||
SystemKind,
|
||||
GlobalObjectKind,
|
||||
PackageKind,
|
||||
ParameterKind,
|
||||
ClassKind,
|
||||
BlockKind,
|
||||
PrototypeInstanceKind,
|
||||
FixedInstanceKind,
|
||||
PrototypeInstanceKind,
|
||||
FixedInstanceKind,
|
||||
DynamicInstanceKind,
|
||||
MultinameKind,
|
||||
MethodClosureKind
|
||||
|
@ -147,10 +156,6 @@ public:
|
|||
|
||||
static void mark(void *p) { ((PondScum *)p)[-1].mark(); }
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
virtual void uselessVirtual() { } // want the checked_cast stuff to work, so need a virtual function
|
||||
#endif
|
||||
};
|
||||
|
||||
class Attribute : public JS2Object {
|
||||
|
@ -191,10 +196,9 @@ public:
|
|||
const StringAtom &id; // The name
|
||||
};
|
||||
|
||||
// MULTINAME is the semantic domain of sets of qualified names. Multinames are used internally in property lookup.
|
||||
// A MULTINAME is the semantic domain of sets of qualified names. Multinames are used internally in property lookup.
|
||||
// We keep Multinames as a basename and a list of namespace qualifiers (XXX is that right - would the basename
|
||||
// ever be different for the same multiname?)
|
||||
// Pointers to Multiname instances get embedded in the bytecode.
|
||||
typedef std::vector<Namespace *> NamespaceList;
|
||||
typedef NamespaceList::iterator NamespaceListIterator;
|
||||
class Multiname : public JS2Object {
|
||||
|
@ -216,12 +220,6 @@ public:
|
|||
};
|
||||
|
||||
|
||||
class Object_Uninit_Future {
|
||||
public:
|
||||
enum { Object, Uninitialized, Future } state;
|
||||
js2val value;
|
||||
};
|
||||
|
||||
class NamedParameter {
|
||||
public:
|
||||
StringAtom &name; // This parameter's name
|
||||
|
@ -259,7 +257,7 @@ public:
|
|||
StaticMember(MemberKind kind) : Member(kind) { }
|
||||
|
||||
StaticMember *cloneContent; // Used during cloning operation to prevent cloning of duplicates (i.e. once
|
||||
// a clone exists for this member it's stored here and used for any other
|
||||
// a clone exists for this member it's recorded here and used for any other
|
||||
// bindings that refer to this member.)
|
||||
|
||||
virtual StaticMember *clone() { ASSERT(false); return NULL; }
|
||||
|
@ -312,19 +310,8 @@ public:
|
|||
Invokable *code; // calling this object does the read or write
|
||||
};
|
||||
|
||||
/*
|
||||
class StaticMethod : public StaticMember {
|
||||
public:
|
||||
StaticMethod() : StaticMember(
|
||||
|
||||
Signature type; // This function's signature
|
||||
Invokable *code; // This function itself (a callable object)
|
||||
enum { Static, Constructor }
|
||||
modifier; // static if this is a function or a static method; constructor if this is a constructor for a class
|
||||
};
|
||||
*/
|
||||
|
||||
// DYNAMICPROPERTY record describes one dynamic property of one (prototype or class) instance.
|
||||
// A DYNAMICPROPERTY record describes one dynamic property of one (prototype or class) instance.
|
||||
typedef std::map<String, js2val> DynamicPropertyMap;
|
||||
typedef DynamicPropertyMap::iterator DynamicPropertyIterator;
|
||||
|
||||
|
@ -559,6 +546,9 @@ public:
|
|||
virtual void emitPostDecBytecode(BytecodeContainer *bCon, size_t pos) { ASSERT(false); }
|
||||
virtual void emitPreIncBytecode(BytecodeContainer *bCon, size_t pos) { ASSERT(false); }
|
||||
virtual void emitPreDecBytecode(BytecodeContainer *bCon, size_t pos) { ASSERT(false); }
|
||||
|
||||
virtual void emitAssignOpBytecode(BytecodeContainer *bCon, JS2Op op, size_t pos){ ASSERT(false); }
|
||||
|
||||
};
|
||||
|
||||
class LexicalReference : public Reference {
|
||||
|
@ -584,6 +574,7 @@ public:
|
|||
virtual void emitPreIncBytecode(BytecodeContainer *bCon, size_t pos) { bCon->emitOp(eLexicalPreInc, pos); bCon->addMultiname(variableMultiname); }
|
||||
virtual void emitPreDecBytecode(BytecodeContainer *bCon, size_t pos) { bCon->emitOp(eLexicalPreDec, pos); bCon->addMultiname(variableMultiname); }
|
||||
|
||||
virtual void emitAssignOpBytecode(BytecodeContainer *bCon, JS2Op op, size_t pos){ bCon->emitOp(eLexicalAssignOp, pos); bCon->addByte((uint8)op); bCon->addMultiname(variableMultiname); }
|
||||
};
|
||||
|
||||
class DotReference : public Reference {
|
||||
|
@ -610,6 +601,7 @@ public:
|
|||
virtual void emitPreIncBytecode(BytecodeContainer *bCon, size_t pos) { bCon->emitOp(eDotPreInc, pos); bCon->addMultiname(propertyMultiname); }
|
||||
virtual void emitPreDecBytecode(BytecodeContainer *bCon, size_t pos) { bCon->emitOp(eDotPreDec, pos); bCon->addMultiname(propertyMultiname); }
|
||||
|
||||
virtual void emitAssignOpBytecode(BytecodeContainer *bCon, JS2Op op, size_t pos){ bCon->emitOp(eDotAssignOp, pos); bCon->addByte((uint8)op); bCon->addMultiname(propertyMultiname); }
|
||||
};
|
||||
|
||||
|
||||
|
@ -647,6 +639,7 @@ public:
|
|||
virtual void emitPreIncBytecode(BytecodeContainer *bCon, size_t pos) { bCon->emitOp(eBracketPreInc, pos); }
|
||||
virtual void emitPreDecBytecode(BytecodeContainer *bCon, size_t pos) { bCon->emitOp(eBracketPreDec, pos); }
|
||||
|
||||
virtual void emitAssignOpBytecode(BytecodeContainer *bCon, JS2Op op, size_t pos){ bCon->emitOp(eBracketAssignOp, pos); bCon->addByte((uint8)op); }
|
||||
};
|
||||
|
||||
|
||||
|
@ -723,12 +716,17 @@ private:
|
|||
};
|
||||
|
||||
|
||||
typedef void (NativeCode)(JS2Engine *engine);
|
||||
|
||||
class FunctionWrapper {
|
||||
public:
|
||||
FunctionWrapper(bool unchecked, ParameterFrame *compileFrame)
|
||||
: bCon(new BytecodeContainer), unchecked(unchecked), compileFrame(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) { }
|
||||
|
||||
BytecodeContainer *bCon;
|
||||
NativeCode *code;
|
||||
bool unchecked; // true if the function is untyped, non-method, normal
|
||||
ParameterFrame *compileFrame;
|
||||
};
|
||||
|
|
|
@ -149,4 +149,13 @@
|
|||
}
|
||||
break;
|
||||
|
||||
case eThis:
|
||||
{
|
||||
js2val rval = meta->env.findThis(true);
|
||||
if (JS2VAL_IS_INACCESSIBLE(rval))
|
||||
meta->reportError(Exception::compileExpressionError, "'this' not available", errorPos());
|
||||
push(rval);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
|
|
@ -32,12 +32,31 @@
|
|||
* file under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
case eMinus:
|
||||
{
|
||||
js2val a = pop();
|
||||
pushNumber(-toNumber(a));
|
||||
}
|
||||
break;
|
||||
|
||||
case ePlus:
|
||||
{
|
||||
js2val a = pop();
|
||||
pushNumber(toNumber(a));
|
||||
}
|
||||
break;
|
||||
|
||||
case eComplement:
|
||||
{
|
||||
js2val a = pop();
|
||||
pushNumber(~toInt32(toNumber(a)));
|
||||
}
|
||||
break;
|
||||
|
||||
case eAdd:
|
||||
{
|
||||
js2val a = pop();
|
||||
js2val b = pop();
|
||||
js2val a = pop();
|
||||
a = toPrimitive(a);
|
||||
b = toPrimitive(b);
|
||||
if (JS2VAL_IS_STRING(a) || JS2VAL_IS_STRING(b)) {
|
||||
|
@ -54,20 +73,76 @@
|
|||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case eSubtract:
|
||||
{
|
||||
js2val a = pop();
|
||||
js2val b = pop();
|
||||
js2val a = pop();
|
||||
float64 anum = toNumber(a);
|
||||
float64 bnum = toNumber(b);
|
||||
pushNumber(anum - bnum);
|
||||
}
|
||||
break;
|
||||
|
||||
case eMultiply:
|
||||
{
|
||||
js2val b = pop();
|
||||
js2val a = pop();
|
||||
float64 anum = toNumber(a);
|
||||
float64 bnum = toNumber(b);
|
||||
pushNumber(anum * bnum);
|
||||
}
|
||||
break;
|
||||
|
||||
case eDivide:
|
||||
{
|
||||
js2val b = pop();
|
||||
js2val a = pop();
|
||||
float64 anum = toNumber(a);
|
||||
float64 bnum = toNumber(b);
|
||||
pushNumber(anum / bnum);
|
||||
}
|
||||
break;
|
||||
|
||||
case eModulo:
|
||||
{
|
||||
js2val b = pop();
|
||||
js2val a = pop();
|
||||
float64 anum = toNumber(a);
|
||||
float64 bnum = toNumber(b);
|
||||
#ifdef XP_PC
|
||||
/* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. */
|
||||
if (JSDOUBLE_IS_FINITE(anum) && JSDOUBLE_IS_INFINITE(bnum))
|
||||
pushNumber(anum);
|
||||
else
|
||||
#endif
|
||||
pushNumber(fd::fmod(anum, bnum));
|
||||
}
|
||||
break;
|
||||
|
||||
case eXor:
|
||||
{
|
||||
js2val b = pop();
|
||||
js2val a = pop();
|
||||
float64 anum = toNumber(a);
|
||||
float64 bnum = toNumber(b);
|
||||
pushNumber(toInt32(anum) ^ toInt32(bnum));
|
||||
}
|
||||
break;
|
||||
|
||||
case eLogicalXor:
|
||||
{
|
||||
js2val b = pop();
|
||||
js2val a = pop();
|
||||
ASSERT(JS2VAL_IS_BOOLEAN(a) && JS2VAL_IS_BOOLEAN(b));
|
||||
push(BOOLEAN_TO_JS2VAL(JS2VAL_TO_BOOLEAN(a) ^ JS2VAL_TO_BOOLEAN(b)));
|
||||
}
|
||||
break;
|
||||
|
||||
case eLess:
|
||||
{
|
||||
js2val a = pop();
|
||||
js2val b = pop();
|
||||
js2val a = pop();
|
||||
js2val ap = toPrimitive(a);
|
||||
js2val bp = toPrimitive(b);
|
||||
bool rval;
|
||||
|
@ -81,8 +156,8 @@
|
|||
|
||||
case eLessEqual:
|
||||
{
|
||||
js2val a = pop();
|
||||
js2val b = pop();
|
||||
js2val a = pop();
|
||||
js2val ap = toPrimitive(a);
|
||||
js2val bp = toPrimitive(b);
|
||||
bool rval;
|
||||
|
@ -96,8 +171,8 @@
|
|||
|
||||
case eGreater:
|
||||
{
|
||||
js2val a = pop();
|
||||
js2val b = pop();
|
||||
js2val a = pop();
|
||||
js2val ap = toPrimitive(a);
|
||||
js2val bp = toPrimitive(b);
|
||||
bool rval;
|
||||
|
@ -111,8 +186,8 @@
|
|||
|
||||
case eGreaterEqual:
|
||||
{
|
||||
js2val a = pop();
|
||||
js2val b = pop();
|
||||
js2val a = pop();
|
||||
js2val ap = toPrimitive(a);
|
||||
js2val bp = toPrimitive(b);
|
||||
bool rval;
|
||||
|
@ -128,8 +203,8 @@
|
|||
case eEqual:
|
||||
{
|
||||
bool rval;
|
||||
js2val a = pop();
|
||||
js2val b = pop();
|
||||
js2val a = pop();
|
||||
if (JS2VAL_IS_NULL(a) || JS2VAL_IS_UNDEFINED(a))
|
||||
rval = (JS2VAL_IS_NULL(b) || JS2VAL_IS_UNDEFINED(b));
|
||||
else
|
||||
|
@ -206,6 +281,76 @@
|
|||
}
|
||||
break;
|
||||
|
||||
case eLexicalAssignOp:
|
||||
{
|
||||
op = (JS2Op)*pc++;
|
||||
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];
|
||||
pc += sizeof(short);
|
||||
js2val a = meta->env.lexicalRead(meta, mn, phase);
|
||||
js2val b = pop();
|
||||
js2val rval;
|
||||
switch (op) {
|
||||
case eAdd:
|
||||
{
|
||||
a = toPrimitive(a);
|
||||
b = toPrimitive(b);
|
||||
if (JS2VAL_IS_STRING(a) || JS2VAL_IS_STRING(b)) {
|
||||
String *astr = toString(a);
|
||||
String *bstr = toString(b);
|
||||
String *c = new String(*astr);
|
||||
*c += *bstr;
|
||||
rval = STRING_TO_JS2VAL(c);
|
||||
}
|
||||
else {
|
||||
float64 anum = toNumber(a);
|
||||
float64 bnum = toNumber(b);
|
||||
rval = allocNumber(anum + bnum);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case eSubtract:
|
||||
{
|
||||
float64 anum = toNumber(a);
|
||||
float64 bnum = toNumber(b);
|
||||
rval = allocNumber(anum - bnum);
|
||||
}
|
||||
break;
|
||||
case eMultiply:
|
||||
{
|
||||
float64 anum = toNumber(a);
|
||||
float64 bnum = toNumber(b);
|
||||
rval = allocNumber(anum * bnum);
|
||||
}
|
||||
break;
|
||||
|
||||
case eDivide:
|
||||
{
|
||||
float64 anum = toNumber(a);
|
||||
float64 bnum = toNumber(b);
|
||||
rval = allocNumber(anum / bnum);
|
||||
}
|
||||
break;
|
||||
|
||||
case eModulo:
|
||||
{
|
||||
float64 anum = toNumber(a);
|
||||
float64 bnum = toNumber(b);
|
||||
#ifdef XP_PC
|
||||
/* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. */
|
||||
if (JSDOUBLE_IS_FINITE(anum) && JSDOUBLE_IS_INFINITE(bnum))
|
||||
rval = anum;
|
||||
else
|
||||
#endif
|
||||
rval = allocNumber(fd::fmod(anum, bnum));
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
meta->env.lexicalWrite(meta, mn, rval, true, phase);
|
||||
push(rval);
|
||||
}
|
||||
break;
|
||||
|
||||
case eLexicalPostInc:
|
||||
{
|
||||
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];
|
||||
|
|
|
@ -63,3 +63,15 @@
|
|||
pc += offset;
|
||||
}
|
||||
break;
|
||||
|
||||
case ePop:
|
||||
{
|
||||
pop();
|
||||
}
|
||||
break;
|
||||
|
||||
case eDup:
|
||||
{
|
||||
push(top());
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -50,16 +50,15 @@
|
|||
push(OBJECT_TO_JS2VAL(pInst));
|
||||
}
|
||||
break;
|
||||
/*
|
||||
|
||||
case eToBoolean:
|
||||
{
|
||||
js2val v = pop();
|
||||
bool b = toBoolean(v);
|
||||
retval = BOOLEAN_TO_JS2VAL(b);
|
||||
push(retval);
|
||||
push(BOOLEAN_TO_JS2VAL(b));
|
||||
}
|
||||
break;
|
||||
*/
|
||||
|
||||
case eNew:
|
||||
{
|
||||
uint16 argCount = BytecodeContainer::getShort(pc);
|
||||
|
@ -101,12 +100,16 @@
|
|||
runtimeFrame->instantiate(&meta->env);
|
||||
runtimeFrame->thisObject = runtimeThis;
|
||||
// assignArguments(runtimeFrame, fWrap->compileFrame->signature);
|
||||
jsr(fWrap->bCon); // seems out of order, but we need to catch the current top frame
|
||||
if (!fWrap->code)
|
||||
jsr(fWrap->bCon); // seems out of order, but we need to catch the current top frame
|
||||
meta->env.addFrame(runtimeFrame);
|
||||
|
||||
if (fWrap->code) {
|
||||
fWrap->code(this);
|
||||
meta->env.removeTopFrame();
|
||||
}
|
||||
}
|
||||
else
|
||||
if (fObj->kind == MethodClosureKind) {
|
||||
if (fObj->kind == MethodClosureKind) { // XXX I made this up (particularly the push of the objectType)
|
||||
MethodClosure *mc = checked_cast<MethodClosure *>(fObj);
|
||||
FixedInstance *fInst = mc->method->fInst;
|
||||
FunctionWrapper *fWrap = fInst->fWrap;
|
||||
|
@ -129,7 +132,6 @@
|
|||
|
||||
case eReturn:
|
||||
{
|
||||
// retval = pop();
|
||||
if (activationStackEmpty())
|
||||
return pop();
|
||||
else
|
||||
|
@ -161,3 +163,50 @@
|
|||
}
|
||||
break;
|
||||
|
||||
case eTypeof:
|
||||
{
|
||||
js2val a = pop();
|
||||
js2val rval;
|
||||
if (JS2VAL_IS_UNDEFINED(a))
|
||||
rval = STRING_TO_JS2VAL(&undefined_StringAtom);
|
||||
else
|
||||
if (JS2VAL_IS_BOOLEAN(a))
|
||||
rval = STRING_TO_JS2VAL(&world.identifiers["boolean"]);
|
||||
else
|
||||
if (JS2VAL_IS_NUMBER(a))
|
||||
rval = STRING_TO_JS2VAL(&world.identifiers["number"]);
|
||||
else
|
||||
if (JS2VAL_IS_STRING(a))
|
||||
rval = STRING_TO_JS2VAL(&world.identifiers["string"]);
|
||||
else {
|
||||
ASSERT(JS2VAL_IS_OBJECT(a));
|
||||
if (JS2VAL_IS_NULL(a))
|
||||
rval = STRING_TO_JS2VAL(&object_StringAtom);
|
||||
JS2Object *obj = JS2VAL_TO_OBJECT(a);
|
||||
switch (obj->kind) {
|
||||
case MultinameKind:
|
||||
rval = STRING_TO_JS2VAL(&world.identifiers["namespace"]);
|
||||
break;
|
||||
case AttributeObjectKind:
|
||||
rval = STRING_TO_JS2VAL(&world.identifiers["attribute"]);
|
||||
break;
|
||||
case ClassKind:
|
||||
case MethodClosureKind:
|
||||
rval = STRING_TO_JS2VAL(&function_StringAtom);
|
||||
break;
|
||||
case PrototypeInstanceKind:
|
||||
case PackageKind:
|
||||
case GlobalObjectKind:
|
||||
rval = STRING_TO_JS2VAL(&object_StringAtom);
|
||||
break;
|
||||
case FixedInstanceKind:
|
||||
rval = STRING_TO_JS2VAL(&checked_cast<FixedInstance *>(obj)->typeofString);
|
||||
break;
|
||||
case DynamicInstanceKind:
|
||||
rval = STRING_TO_JS2VAL(&checked_cast<DynamicInstance *>(obj)->typeofString);
|
||||
break;
|
||||
}
|
||||
}
|
||||
push(rval);
|
||||
}
|
||||
break;
|
|
@ -69,6 +69,10 @@ namespace JavaScript {
|
|||
extern double minValue;
|
||||
extern double maxValue;
|
||||
|
||||
static const double two32minus1 = 4294967295.0;
|
||||
static const double two32 = 4294967296.0;
|
||||
static const double two16 = 65536.0;
|
||||
static const double two31 = 2147483648.0;
|
||||
//
|
||||
// Portable double-precision floating point to string and back conversions
|
||||
//
|
||||
|
|
Загрузка…
Ссылка в новой задаче