зеркало из https://github.com/mozilla/pjs.git
Completed arithmetic (except Long & float32). Gc work. Hooked up Math class
This commit is contained in:
Родитель
b6ccbcd514
Коммит
5ffffdd50f
|
@ -75,7 +75,7 @@ namespace MetaData {
|
|||
// Execute the opcode sequence at pc.
|
||||
js2val JS2Engine::interpreterLoop()
|
||||
{
|
||||
js2val retval = JS2VAL_VOID;
|
||||
retval = JS2VAL_VOID;
|
||||
while (true) {
|
||||
JS2Op op = (JS2Op)*pc++;
|
||||
switch (op) {
|
||||
|
@ -90,12 +90,6 @@ namespace MetaData {
|
|||
return retval;
|
||||
}
|
||||
|
||||
// return a pointer to an 8 byte chunk in the gc heap
|
||||
void *JS2Engine::gc_alloc_8()
|
||||
{
|
||||
return JS2Object::alloc(8);
|
||||
}
|
||||
|
||||
// See if the double value is in the hash table, return it's pointer if so
|
||||
// If not, fill the table or return a un-hashed pointer
|
||||
float64 *JS2Engine::newDoubleValue(float64 x)
|
||||
|
@ -111,13 +105,13 @@ namespace MetaData {
|
|||
if (*float64Table[hash] == x)
|
||||
return float64Table[hash];
|
||||
else {
|
||||
float64 *p = (float64 *)gc_alloc_8();
|
||||
float64 *p = (float64 *)malloc(sizeof(float64));
|
||||
*p = x;
|
||||
return p;
|
||||
}
|
||||
}
|
||||
else {
|
||||
float64 *p = (float64 *)gc_alloc_8();
|
||||
float64 *p = (float64 *)malloc(sizeof(float64));
|
||||
float64Table[hash] = p;
|
||||
*p = x;
|
||||
return p;
|
||||
|
@ -276,6 +270,7 @@ namespace MetaData {
|
|||
: pc(NULL),
|
||||
bCon(NULL),
|
||||
meta(NULL),
|
||||
retval(JS2VAL_VOID),
|
||||
INIT_STRINGATOM(true),
|
||||
INIT_STRINGATOM(false),
|
||||
INIT_STRINGATOM(null),
|
||||
|
@ -318,8 +313,13 @@ namespace MetaData {
|
|||
case eGreater:
|
||||
case eLessEqual:
|
||||
case eGreaterEqual:
|
||||
case eXor:
|
||||
case eLogicalXor:
|
||||
case eLeftShift:
|
||||
case eRightShift:
|
||||
case eLogicalRightShift:
|
||||
case eBitwiseAnd:
|
||||
case eBitwiseXor:
|
||||
case eBitwiseOr:
|
||||
return -1;
|
||||
|
||||
case eMinus: // pop one, push one
|
||||
|
@ -494,6 +494,10 @@ namespace MetaData {
|
|||
if (float64Table[i])
|
||||
JS2Object::mark(float64Table[i]);
|
||||
}
|
||||
if (JS2VAL_IS_OBJECT(retval)) {
|
||||
JS2Object *obj = JS2VAL_TO_OBJECT(retval);
|
||||
GCMARKOBJECT(obj)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -60,11 +60,16 @@ enum JS2Op {
|
|||
eGreater,
|
||||
eLessEqual,
|
||||
eGreaterEqual,
|
||||
eXor,
|
||||
eLogicalXor,
|
||||
eMinus,
|
||||
ePlus,
|
||||
eComplement,
|
||||
eLeftShift,
|
||||
eRightShift,
|
||||
eLogicalRightShift,
|
||||
eBitwiseAnd,
|
||||
eBitwiseXor,
|
||||
eBitwiseOr,
|
||||
eTrue,
|
||||
eFalse,
|
||||
eNull,
|
||||
|
@ -169,9 +174,9 @@ public:
|
|||
float64 *float64Table[256];
|
||||
js2val allocNumber(float64 x);
|
||||
js2val pushNumber(float64 x) { js2val retval = allocNumber(x); push(retval); return retval; }
|
||||
void *gc_alloc_8();
|
||||
private:
|
||||
float64 *newDoubleValue(float64 x);
|
||||
js2val retval;
|
||||
|
||||
public:
|
||||
|
||||
|
|
|
@ -342,17 +342,19 @@ void initMathObject(JS2Metadata *meta)
|
|||
{ "sin", 1, Math_sin },
|
||||
{ "sqrt", 1, Math_sqrt },
|
||||
{ "tan", 1, Math_tan },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
meta->env.addFrame(meta->mathClass);
|
||||
PrototypeFunction *pf = &prototypeFunctions[0];
|
||||
while (pf->name) {
|
||||
FixedInstance *fInst = new FixedInstance(meta->functionClass);
|
||||
fInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_INACCESSIBLE, true), pf->code);
|
||||
InstanceMember *m = new InstanceMethod(fInst);
|
||||
meta->defineInstanceMember(meta->mathClass, &meta->cxt, meta->world.identifiers[pf->name], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, m, 0);
|
||||
Variable *v = new Variable(meta->functionClass, OBJECT_TO_JS2VAL(fInst), true);
|
||||
meta->defineStaticMember(&meta->env, meta->world.identifiers[pf->name], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
|
||||
pf++;
|
||||
}
|
||||
|
||||
meta->env.removeTopFrame();
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1145,6 +1145,18 @@ namespace MetaData {
|
|||
case ExprNode::logicalAnd:
|
||||
case ExprNode::logicalXor:
|
||||
case ExprNode::logicalOr:
|
||||
case ExprNode::leftShift:
|
||||
case ExprNode::rightShift:
|
||||
case ExprNode::logicalRightShift:
|
||||
case ExprNode::bitwiseAnd:
|
||||
case ExprNode::bitwiseXor:
|
||||
case ExprNode::bitwiseOr:
|
||||
case ExprNode::leftShiftEquals:
|
||||
case ExprNode::rightShiftEquals:
|
||||
case ExprNode::logicalRightShiftEquals:
|
||||
case ExprNode::bitwiseAndEquals:
|
||||
case ExprNode::bitwiseXorEquals:
|
||||
case ExprNode::bitwiseOrEquals:
|
||||
{
|
||||
BinaryExprNode *b = checked_cast<BinaryExprNode *>(p);
|
||||
ValidateExpression(cxt, env, b->op1);
|
||||
|
@ -1247,6 +1259,24 @@ namespace MetaData {
|
|||
reportError(Exception::semanticError, "Assignment needs an lValue", p->pos);
|
||||
}
|
||||
break;
|
||||
case ExprNode::leftShiftEquals:
|
||||
op = eLeftShift;
|
||||
goto doAssignBinary;
|
||||
case ExprNode::rightShiftEquals:
|
||||
op = eRightShift;
|
||||
goto doAssignBinary;
|
||||
case ExprNode::logicalRightShiftEquals:
|
||||
op = eLogicalRightShift;
|
||||
goto doAssignBinary;
|
||||
case ExprNode::bitwiseAndEquals:
|
||||
op = eBitwiseAnd;
|
||||
goto doAssignBinary;
|
||||
case ExprNode::bitwiseXorEquals:
|
||||
op = eBitwiseXor;
|
||||
goto doAssignBinary;
|
||||
case ExprNode::bitwiseOrEquals:
|
||||
op = eBitwiseOr;
|
||||
goto doAssignBinary;
|
||||
case ExprNode::addEquals:
|
||||
op = eAdd;
|
||||
goto doAssignBinary;
|
||||
|
@ -1302,16 +1332,16 @@ doAssignBinary:
|
|||
op = eRightShift;
|
||||
goto doBinary;
|
||||
case ExprNode::logicalRightShift:
|
||||
op = eUShiftRight;
|
||||
op = eLogicalRightShift;
|
||||
goto doBinary;
|
||||
case ExprNode::bitwiseAnd:
|
||||
op = BitAnd;
|
||||
op = eBitwiseAnd;
|
||||
goto doBinary;
|
||||
case ExprNode::bitwiseXor:
|
||||
op = BitXor;
|
||||
op = eBitwiseXor;
|
||||
goto doBinary;
|
||||
case ExprNode::bitwiseOr:
|
||||
op = BitOr;
|
||||
op = eBitwiseOr;
|
||||
goto doBinary;
|
||||
|
||||
case ExprNode::add:
|
||||
|
@ -2783,6 +2813,7 @@ readClassProperty:
|
|||
// that are meant to be never collected?
|
||||
GCMARKOBJECT(publicNamespace);
|
||||
GCMARKOBJECT(forbiddenMember);
|
||||
GCMARKOBJECT(objectClass);
|
||||
GCMARKOBJECT(undefinedClass);
|
||||
GCMARKOBJECT(nullClass);
|
||||
GCMARKOBJECT(booleanClass);
|
||||
|
@ -2790,13 +2821,15 @@ readClassProperty:
|
|||
GCMARKOBJECT(numberClass);
|
||||
GCMARKOBJECT(characterClass);
|
||||
GCMARKOBJECT(stringClass);
|
||||
GCMARKOBJECT(objectClass);
|
||||
GCMARKOBJECT(namespaceClass);
|
||||
GCMARKOBJECT(classClass);
|
||||
GCMARKOBJECT(packageClass);
|
||||
GCMARKOBJECT(prototypeClass);
|
||||
GCMARKOBJECT(attributeClass);
|
||||
GCMARKOBJECT(classClass);
|
||||
GCMARKOBJECT(functionClass);
|
||||
GCMARKOBJECT(prototypeClass);
|
||||
GCMARKOBJECT(packageClass);
|
||||
GCMARKOBJECT(dateClass);
|
||||
GCMARKOBJECT(regexpClass);
|
||||
GCMARKOBJECT(mathClass);
|
||||
|
||||
if (bCon)
|
||||
bCon->mark();
|
||||
|
@ -2853,7 +2886,7 @@ readClassProperty:
|
|||
}
|
||||
|
||||
// Allocate from this or the next Pond (make a new one if necessary)
|
||||
void *Pond::allocFromPond(int32 sz, bool isJS2Object)
|
||||
void *Pond::allocFromPond(int32 sz)
|
||||
{
|
||||
// Try scannning the free list...
|
||||
PondScum *p = freeHeader;
|
||||
|
@ -2867,8 +2900,6 @@ readClassProperty:
|
|||
freeHeader = (PondScum *)(p->owner);
|
||||
p->owner = this;
|
||||
p->resetMark(); // might have lingering mark from previous gc
|
||||
if (isJS2Object)
|
||||
p->setIsJS2Object();
|
||||
#ifdef DEBUG
|
||||
memset((p + 1), 0xB7, p->getSize() - sizeof(PondScum));
|
||||
#endif
|
||||
|
@ -2882,13 +2913,11 @@ readClassProperty:
|
|||
if (sz > (pondSize - (pondTop - pondBase))) {
|
||||
if (nextPond == NULL)
|
||||
nextPond = new Pond(sz, nextPond);
|
||||
return nextPond->allocFromPond(sz, isJS2Object);
|
||||
return nextPond->allocFromPond(sz);
|
||||
}
|
||||
p = (PondScum *)pondTop;
|
||||
p->owner = this;
|
||||
p->setSize(sz);
|
||||
if (isJS2Object)
|
||||
p->setIsJS2Object();
|
||||
pondTop += sz;
|
||||
#ifdef DEBUG
|
||||
memset((p + 1), 0xB7, sz - sizeof(PondScum));
|
||||
|
@ -2963,6 +2992,7 @@ readClassProperty:
|
|||
// gc-mark all contained JS2Objects and visit contained structures to do likewise
|
||||
void JS2Class::markChildren()
|
||||
{
|
||||
Frame::markChildren();
|
||||
GCMARKOBJECT(super)
|
||||
GCMARKOBJECT(prototype)
|
||||
GCMARKOBJECT(privateNamespace)
|
||||
|
@ -3281,30 +3311,27 @@ readClassProperty:
|
|||
void JS2Object::gc(JS2Metadata *meta)
|
||||
{
|
||||
pond.resetMarks();
|
||||
// Anything on the root list is a pointer to a JS2Object.
|
||||
for (std::list<PondScum **>::iterator i = rootList.begin(), end = rootList.end(); (i != end); i++) {
|
||||
if (**i) {
|
||||
PondScum *p = (**i) - 1;
|
||||
ASSERT(p->owner && (p->getSize() >= sizeof(PondScum)) && (p->owner->sanity == POND_SANITY));
|
||||
if (p->isJS2Object()) {
|
||||
JS2Object *obj = (JS2Object *)(p + 1);
|
||||
GCMARKOBJECT(obj)
|
||||
}
|
||||
else
|
||||
p->mark();
|
||||
}
|
||||
}
|
||||
meta->mark();
|
||||
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)
|
||||
void *JS2Object::alloc(size_t s)
|
||||
{
|
||||
s += sizeof(PondScum);
|
||||
// make sure that the thing is 8-byte aligned
|
||||
if (s & 0x7) s += 8 - (s & 0x7);
|
||||
ASSERT(s <= 0x7FFFFFFF);
|
||||
return pond.allocFromPond((int32)s, isJS2Object);
|
||||
return pond.allocFromPond((int32)s);
|
||||
}
|
||||
|
||||
// Release a chunk back to it's pond
|
||||
|
|
|
@ -92,18 +92,13 @@ public:
|
|||
void resetMark() { size &= 0x7FFFFFFF; }
|
||||
void mark() { size |= 0x80000000; }
|
||||
bool isMarked() { return ((size & 0x80000000) != 0); }
|
||||
uint32 getSize() { return size & 0x3FFFFFFF; }
|
||||
void setSize(uint32 sz) { ASSERT((sz & 0xC000000) == 0); size = (sz & 0x3FFFFFFF); }
|
||||
void setIsJS2Object() { size |= 0x40000000; }
|
||||
bool isJS2Object() { return ((size & 0x30000000) != 0); }
|
||||
uint32 getSize() { return size & 0x7FFFFFFF; }
|
||||
void setSize(uint32 sz) { ASSERT((sz & 0x8000000) == 0); size = (sz & 0x7FFFFFFF); }
|
||||
|
||||
Pond *owner; // for a piece of scum in use, this points to it's own Pond
|
||||
// otherwise it's a link to the next item on the free list
|
||||
private:
|
||||
uint32 size; // The high bit is used as the gc mark flag
|
||||
// The next highest bit indicates that the object is a JS2Object
|
||||
// or just raw memory (with the implication of not containing
|
||||
// pointers to gc-able data)
|
||||
};
|
||||
|
||||
// A pond is a place to get chunks of PondScum from and to return them to
|
||||
|
@ -113,7 +108,7 @@ class Pond {
|
|||
public:
|
||||
Pond(size_t sz, Pond *nextPond);
|
||||
|
||||
void *allocFromPond(int32 sz, bool isJS2Object);
|
||||
void *allocFromPond(int32 sz);
|
||||
void returnToPond(PondScum *p);
|
||||
|
||||
void resetMarks();
|
||||
|
@ -148,12 +143,13 @@ public:
|
|||
|
||||
static void gc(JS2Metadata *meta);
|
||||
static RootIterator addRoot(void *t); // pass the address of any JS2Object pointer
|
||||
// Note: Not the address of a JS2VAL!
|
||||
static void removeRoot(RootIterator ri);
|
||||
|
||||
static void *alloc(size_t s, bool isJS2Object = false);
|
||||
static void *alloc(size_t s);
|
||||
static void unalloc(void *p);
|
||||
|
||||
void *operator new(size_t s) { return alloc(s, true); }
|
||||
void *operator new(size_t s) { return alloc(s); }
|
||||
void operator delete(void *p) { unalloc(p); }
|
||||
|
||||
virtual void markChildren() { }
|
||||
|
|
|
@ -49,7 +49,52 @@
|
|||
case eComplement:
|
||||
{
|
||||
js2val a = pop();
|
||||
pushNumber(~toInt32(toNumber(a)));
|
||||
pushNumber(~toInteger(a));
|
||||
}
|
||||
break;
|
||||
case eLeftShift:
|
||||
{
|
||||
js2val b = pop();
|
||||
js2val a = pop();
|
||||
int32 count = toInteger(b) & 0x1F;
|
||||
pushNumber(toInteger(a) << count);
|
||||
}
|
||||
break;
|
||||
case eRightShift:
|
||||
{
|
||||
js2val b = pop();
|
||||
js2val a = pop();
|
||||
int32 count = toInteger(b) & 0x1F;
|
||||
pushNumber(toInteger(a) >> count);
|
||||
}
|
||||
break;
|
||||
case eLogicalRightShift:
|
||||
{
|
||||
js2val b = pop();
|
||||
js2val a = pop();
|
||||
int32 count = toInteger(b) & 0x1F;
|
||||
pushNumber(toUInt32(toInteger(a)) >> count);
|
||||
}
|
||||
break;
|
||||
case eBitwiseAnd:
|
||||
{
|
||||
js2val b = pop();
|
||||
js2val a = pop();
|
||||
pushNumber(toInteger(a) & toInteger(b));
|
||||
}
|
||||
break;
|
||||
case eBitwiseXor:
|
||||
{
|
||||
js2val b = pop();
|
||||
js2val a = pop();
|
||||
pushNumber(toInteger(a) ^ toInteger(b));
|
||||
}
|
||||
break;
|
||||
case eBitwiseOr:
|
||||
{
|
||||
js2val b = pop();
|
||||
js2val a = pop();
|
||||
pushNumber(toInteger(a) | toInteger(b));
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -120,16 +165,6 @@
|
|||
}
|
||||
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();
|
||||
|
@ -345,6 +380,39 @@
|
|||
}
|
||||
break;
|
||||
|
||||
case eLeftShift:
|
||||
{
|
||||
int32 count = toInteger(b) & 0x1F;
|
||||
rval = allocNumber(toInteger(a) << count);
|
||||
}
|
||||
break;
|
||||
case eRightShift:
|
||||
{
|
||||
int32 count = toInteger(b) & 0x1F;
|
||||
rval = allocNumber(toInteger(a) >> count);
|
||||
}
|
||||
break;
|
||||
case eLogicalRightShift:
|
||||
{
|
||||
int32 count = toInteger(b) & 0x1F;
|
||||
rval = allocNumber(toUInt32(toInteger(a)) >> count);
|
||||
}
|
||||
break;
|
||||
case eBitwiseAnd:
|
||||
{
|
||||
rval = allocNumber(toInteger(a) & toInteger(b));
|
||||
}
|
||||
break;
|
||||
case eBitwiseXor:
|
||||
{
|
||||
rval = allocNumber(toInteger(a) ^ toInteger(b));
|
||||
}
|
||||
break;
|
||||
case eBitwiseOr:
|
||||
{
|
||||
rval = allocNumber(toInteger(a) | toInteger(b));
|
||||
}
|
||||
break;
|
||||
}
|
||||
meta->env.lexicalWrite(meta, mn, rval, true, phase);
|
||||
push(rval);
|
||||
|
@ -392,6 +460,113 @@
|
|||
}
|
||||
break;
|
||||
|
||||
case eDotAssignOp:
|
||||
{
|
||||
op = (JS2Op)*pc++;
|
||||
LookupKind lookup(false, NULL);
|
||||
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];
|
||||
pc += sizeof(short);
|
||||
js2val b = pop();
|
||||
js2val baseVal = pop();
|
||||
js2val a;
|
||||
if (!meta->readProperty(baseVal, mn, &lookup, RunPhase, &a))
|
||||
meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn->name);
|
||||
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;
|
||||
|
||||
case eLeftShift:
|
||||
{
|
||||
int32 count = toInteger(b) & 0x1F;
|
||||
rval = allocNumber(toInteger(a) << count);
|
||||
}
|
||||
break;
|
||||
case eRightShift:
|
||||
{
|
||||
int32 count = toInteger(b) & 0x1F;
|
||||
rval = allocNumber(toInteger(a) >> count);
|
||||
}
|
||||
break;
|
||||
case eLogicalRightShift:
|
||||
{
|
||||
int32 count = toInteger(b) & 0x1F;
|
||||
rval = allocNumber(toUInt32(toInteger(a)) >> count);
|
||||
}
|
||||
break;
|
||||
case eBitwiseAnd:
|
||||
{
|
||||
rval = allocNumber(toInteger(a) & toInteger(b));
|
||||
}
|
||||
break;
|
||||
case eBitwiseXor:
|
||||
{
|
||||
rval = allocNumber(toInteger(a) ^ toInteger(b));
|
||||
}
|
||||
break;
|
||||
case eBitwiseOr:
|
||||
{
|
||||
rval = allocNumber(toInteger(a) | toInteger(b));
|
||||
}
|
||||
break;
|
||||
}
|
||||
meta->writeProperty(baseVal, mn, &lookup, true, rval, RunPhase);
|
||||
push(rval);
|
||||
}
|
||||
break;
|
||||
|
||||
case eDotPostInc:
|
||||
{
|
||||
LookupKind lookup(false, NULL);
|
||||
|
@ -448,6 +623,115 @@
|
|||
meta->writeProperty(baseVal, mn, &lookup, true, rval, RunPhase);
|
||||
}
|
||||
break;
|
||||
|
||||
case eBracketAssignOp:
|
||||
{
|
||||
op = (JS2Op)*pc++;
|
||||
LookupKind lookup(false, NULL);
|
||||
js2val b = pop();
|
||||
js2val indexVal = pop();
|
||||
js2val baseVal = pop();
|
||||
js2val a;
|
||||
String *indexStr = toString(indexVal);
|
||||
Multiname mn(meta->world.identifiers[*indexStr], meta->publicNamespace);
|
||||
if (!meta->readProperty(baseVal, &mn, &lookup, RunPhase, &a))
|
||||
meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn.name);
|
||||
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;
|
||||
|
||||
case eLeftShift:
|
||||
{
|
||||
int32 count = toInteger(b) & 0x1F;
|
||||
rval = allocNumber(toInteger(a) << count);
|
||||
}
|
||||
break;
|
||||
case eRightShift:
|
||||
{
|
||||
int32 count = toInteger(b) & 0x1F;
|
||||
rval = allocNumber(toInteger(a) >> count);
|
||||
}
|
||||
break;
|
||||
case eLogicalRightShift:
|
||||
{
|
||||
int32 count = toInteger(b) & 0x1F;
|
||||
rval = allocNumber(toUInt32(toInteger(a)) >> count);
|
||||
}
|
||||
break;
|
||||
case eBitwiseAnd:
|
||||
{
|
||||
rval = allocNumber(toInteger(a) & toInteger(b));
|
||||
}
|
||||
break;
|
||||
case eBitwiseXor:
|
||||
{
|
||||
rval = allocNumber(toInteger(a) ^ toInteger(b));
|
||||
}
|
||||
break;
|
||||
case eBitwiseOr:
|
||||
{
|
||||
rval = allocNumber(toInteger(a) | toInteger(b));
|
||||
}
|
||||
break;
|
||||
}
|
||||
meta->writeProperty(baseVal, &mn, &lookup, true, rval, RunPhase);
|
||||
push(rval);
|
||||
}
|
||||
break;
|
||||
|
||||
case eBracketPostInc:
|
||||
{
|
||||
LookupKind lookup(false, NULL);
|
||||
|
|
Загрузка…
Ссылка в новой задаче