Long/Float support.

This commit is contained in:
rogerl%netscape.com 2002-10-03 06:49:07 +00:00
parent d0545ad04d
commit f11162aae4
11 changed files with 289 additions and 44 deletions

View File

@ -83,7 +83,7 @@ namespace MetaData {
bCon->addOffset(int32(mLocation - branchLocation));
else {
mFixupList.push_back(branchLocation);
bCon->addLong(0);
bCon->addOffset(0);
}
}

View File

@ -112,14 +112,22 @@ public:
void addByte(uint8 v) { mBuffer.push_back(v); }
void addPointer(const void *v) { ASSERT(sizeof(void *) == sizeof(uint32)); addLong((uint32)(v)); }
static void *getPointer(void *pc) { return (void *)getLong(pc); }
void addPointer(const void *v) { ASSERT(sizeof(void *) == sizeof(uint32)); addUInt32((uint32)(v)); }
static void *getPointer(void *pc) { return (void *)getUInt32(pc); }
// These insert the opcodes...
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)); }
static uint32 getLong(void *pc) { return *((uint32 *)pc); }
void addUInt64(const uint64 v, size_t pos) { emitOp(eUInt64, pos); mBuffer.insert(mBuffer.end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(uint64)); }
static uint64 getUInt64(void *pc) { return *((uint64 *)pc); }
void addInt64(const int64 v, size_t pos) { emitOp(eInt64, pos); mBuffer.insert(mBuffer.end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(int64)); }
static int64 getInt64(void *pc) { return *((int64 *)pc); }
// These don't insert opcodes...
void addUInt32(const uint32 v) { mBuffer.insert(mBuffer.end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(uint32)); }
static uint32 getUInt32(void *pc) { return *((uint32 *)pc); }
void addShort(uint16 v) { mBuffer.insert(mBuffer.end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(uint16)); }
static uint16 getShort(void *pc) { return *((uint16 *)pc); }

View File

@ -48,6 +48,7 @@
#include "world.h"
#include "utilities.h"
#include "js2value.h"
#include "jslong.h"
#include "numerics.h"
#include "fdlibm_ns.h"
@ -140,6 +141,23 @@ namespace MetaData {
return retval;
}
// Don't store as an int, even if possible, we need to retain 'longness'
js2val JS2Engine::allocULong(uint64 x)
{
uint64 *p = (uint64 *)(JS2Object::alloc(sizeof(uint64)));
*p = x;
return ULONG_TO_JS2VAL(p);
}
// Don't store as an int, even if possible, we need to retain 'longness'
js2val JS2Engine::allocLong(int64 x)
{
int64 *p = (int64 *)(JS2Object::alloc(sizeof(int64)));
*p = x;
return LONG_TO_JS2VAL(p);
}
// Convert an integer to a string
String *numberToString(int32 i)
{
@ -167,6 +185,20 @@ namespace MetaData {
return (JS2VAL_TO_BOOLEAN(x)) ? &true_StringAtom : &false_StringAtom;
if (JS2VAL_IS_INT(x))
return numberToString(JS2VAL_TO_INT(x));
if (JS2VAL_IS_LONG(x)) {
float64 d;
JSLL_L2D(d, *JS2VAL_TO_LONG(x));
return numberToString(&d);
}
if (JS2VAL_IS_ULONG(x)) {
float64 d;
JSLL_UL2D(d, *JS2VAL_TO_ULONG(x));
return numberToString(&d);
}
if (JS2VAL_IS_FLOAT(x)) {
float64 d = *JS2VAL_TO_FLOAT(x);
return numberToString(&d);
}
if (JS2VAL_IS_DOUBLE(x))
return numberToString(JS2VAL_TO_DOUBLE(x));
return toString(toPrimitive(x));
@ -202,6 +234,45 @@ namespace MetaData {
return toNumber(toPrimitive(x));
}
// x is not a number
js2val JS2Engine::convertValueToGeneralNumber(js2val x)
{
// XXX Assuming convert to float64, rather than long/ulong
return allocNumber(toNumber(x));
}
// x is a Number
int64 JS2Engine::checkInteger(js2val x)
{
if (JS2VAL_IS_FLOAT(x)) {
float64 f = *JS2VAL_TO_FLOAT(x);
if (!JSDOUBLE_IS_FINITE(f, i))
meta->reportError(Exception::rangeError, "Non integer", errorPos());
int64 i;
JSLL_D2L(i, f);
JSLL_L2D(f, i);
if (!=) rangeError...
return i;
}
else
if (JS2VAL_IS_DOUBLE(x)) {
float64 d = *JS2VAL_TO_DOUBLE(x);
if (!JSDOUBLE_IS_INT(d, i))
meta->reportError(Exception::rangeError, "Non integer", errorPos());
return i;
}
else
if (JS2VAL_IS_LONG(x)) {
JSLL_L2I(i, *JS2VAL_TO_LONG(x));
return i;
}
ASSERT(JS2VAL_IS_ULONG(x));
JSLL_UL2I(i, *JS2VAL_TO_ULONG(x));
return i;
}
}
// x is any js2val
float64 JS2Engine::toNumber(js2val x)
{
if (JS2VAL_IS_INT(x))
@ -210,11 +281,17 @@ namespace MetaData {
if (JS2VAL_IS_DOUBLE(x))
return *JS2VAL_TO_DOUBLE(x);
else
if (JS2VAL_IS_LONG(x))
return *JS2VAL_TO_LONG(x);
if (JS2VAL_IS_LONG(x)) {
float64 d;
JSLL_L2D(d, *JS2VAL_TO_LONG(x));
return d;
}
else
if (JS2VAL_IS_ULONG(x))
return *JS2VAL_TO_ULONG(x);
if (JS2VAL_IS_ULONG(x)) {
float64 d;
JSLL_UL2D(d, *JS2VAL_TO_ULONG(x));
return d;
}
else
if (JS2VAL_IS_FLOAT(x))
return *JS2VAL_TO_FLOAT(x);
@ -222,7 +299,6 @@ namespace MetaData {
return convertValueToDouble(x);
}
// x is not a bool
bool JS2Engine::convertValueToBoolean(js2val x)
{
@ -232,9 +308,15 @@ namespace MetaData {
return false;
if (JS2VAL_IS_INT(x))
return (JS2VAL_TO_INT(x) != 0);
if (JS2VAL_IS_LONG(x) || JS2VAL_IS_ULONG(x))
return (!JSLL_IS_ZERO(x));
if (JS2VAL_IS_FLOAT(x)) {
float64 xd = *JS2VAL_TO_FLOAT(x);
return ! (JSDOUBLE_IS_POSZERO(xd) || JSDOUBLE_IS_NEGZERO(xd) || JSDOUBLE_IS_NaN(xd));
}
if (JS2VAL_IS_DOUBLE(x)) {
float64 *xd = JS2VAL_TO_DOUBLE(x);
return ! (JSDOUBLE_IS_POSZERO(*xd) || JSDOUBLE_IS_NEGZERO(*xd) || JSDOUBLE_IS_NaN(*xd));
float64 xd = *JS2VAL_TO_DOUBLE(x);
return ! (JSDOUBLE_IS_POSZERO(xd) || JSDOUBLE_IS_NEGZERO(xd) || JSDOUBLE_IS_NaN(xd));
}
if (JS2VAL_IS_STRING(x)) {
String *str = JS2VAL_TO_STRING(x);
@ -246,8 +328,25 @@ namespace MetaData {
// x is not an int
int32 JS2Engine::convertValueToInteger(js2val x)
{
float64 f = (JS2VAL_IS_DOUBLE(x)) ? *JS2VAL_TO_DOUBLE(x) : convertValueToDouble(x);
return toInt32(f);
int32 i;
if (JS2VAL_IS_LONG(x)) {
JSLL_L2I(i, *JS2VAL_TO_LONG(x));
return i;
}
if (JS2VAL_IS_ULONG(x)) {
JSLL_UL2I(i, *JS2VAL_TO_ULONG(x));
return i;
}
if (JS2VAL_IS_FLOAT(x)) {
float64 f = *JS2VAL_TO_FLOAT(x);
return toInt32(f);
}
if (JS2VAL_IS_DOUBLE(x)) {
float64 d = *JS2VAL_TO_DOUBLE(x);
return toInt32(d);
}
float64 d = convertValueToDouble(x);
return toInt32(d);
}
int32 JS2Engine::toInt32(float64 d)
@ -356,6 +455,8 @@ namespace MetaData {
case eTrue:
case eFalse:
case eNumber:
case eUInt64:
case eInt64:
case eNull:
case eThis:
return 1; // push literal value
@ -515,10 +616,7 @@ namespace MetaData {
f->bCon->mark();
}
for (js2val *e = execStack; (e < sp); e++) {
if (JS2VAL_IS_OBJECT(*e)) {
JS2Object *obj = JS2VAL_TO_OBJECT(*e);
GCMARKOBJECT(obj)
}
GCMARKVALUE(*e);
}
JS2Object::mark(JS2VAL_TO_DOUBLE(nanValue));
JS2Object::mark(JS2VAL_TO_DOUBLE(posInfValue));
@ -534,6 +632,6 @@ namespace MetaData {
GCMARKVALUE(indexVal);
}
}
}
}
}

View File

@ -74,6 +74,8 @@ enum JS2Op {
eFalse,
eNull,
eNumber,
eUInt64,
eInt64,
eString, // <string pointer:u32>
eThis,
eNewObject, // <argCount:u16>
@ -149,20 +151,24 @@ public:
uint32 toUInt32(float64 f);
uint16 toUInt16(float64 f);
String *convertValueToString(js2val x);
js2val convertValueToPrimitive(js2val x);
float64 convertValueToDouble(js2val x);
bool convertValueToBoolean(js2val x);
int32 convertValueToInteger(js2val x);
js2val convertValueToGeneralNumber(js2val x);
String *toString(js2val x) { if (JS2VAL_IS_STRING(x)) return JS2VAL_TO_STRING(x); else return convertValueToString(x); }
js2val toPrimitive(js2val x) { if (JS2VAL_IS_PRIMITIVE(x)) return x; else return convertValueToPrimitive(x); }
float64 toNumber(js2val x);
js2val toGeneralNumber(js2val x){ if (JS2VAL_IS_NUMBER(x)) return x; else return convertValueToGeneralNumber(x); }
bool toBoolean(js2val x) { if (JS2VAL_IS_BOOLEAN(x)) return JS2VAL_TO_BOOLEAN(x); else return convertValueToBoolean(x); }
int32 toInteger(js2val x) { if (JS2VAL_IS_INT(x)) return JS2VAL_TO_INT(x); else return convertValueToInteger(x); }
js2val assignmentConversion(js2val val, JS2Class *type) { return val; } // XXX s'more code, please
int32 checkInteger(js2val x);
JS2Metadata *meta;
@ -176,11 +182,18 @@ public:
js2val posInfValue;
js2val negInfValue;
// A cache of f.p. values (XXX experimentally trying to reduce # of double pointers XXX)
float64 *float64Table[256];
js2val allocNumber(float64 x);
js2val pushNumber(float64 x) { js2val retval = allocNumber(x); push(retval); return retval; }
js2val allocULong(uint64 x);
js2val pushULong(uint64 x) { js2val retval = allocULong(x); push(retval); return retval; }
js2val allocLong(int64 x);
js2val pushLong(int64 x) { js2val retval = allocLong(x); push(retval); return retval; }
private:
// A cache of f.p. values (XXX experimentally trying to reduce # of double pointers XXX)
float64 *float64Table[256];
float64 *newDoubleValue(float64 x);
js2val retval;

View File

@ -1087,6 +1087,7 @@ namespace MetaData {
switch (p->getKind()) {
case ExprNode::Null:
case ExprNode::number:
case ExprNode::numUnit:
case ExprNode::string:
case ExprNode::boolean:
break;
@ -1487,6 +1488,18 @@ doUnary:
bCon->emitOp(eNull, p->pos);
}
break;
case ExprNode::numUnit:
{
NumUnitExprNode *n = checked_cast<NumUnitExprNode *>(p);
if (n->str == L"UL")
bCon->addUInt64(n->num, p->pos);
else
if (n->str == L"L")
bCon->addInt64(n->num, p->pos);
else
reportError(Exception::badValueError, "Unrecognized unit", p->pos);
}
break;
case ExprNode::number:
{
bCon->addFloat64(checked_cast<NumberExprNode *>(p)->value, p->pos);
@ -3149,11 +3162,11 @@ deleteClassProperty:
if (slots) {
ASSERT(type);
for (uint32 i = 0; (i < type->slotCount); i++) {
GCMARKVALUE(slots[i].value)
GCMARKVALUE(slots[i].value);
}
}
for (DynamicPropertyIterator i = dynamicProperties.begin(), end = dynamicProperties.end(); (i != end); i++) {
GCMARKVALUE(i->second)
GCMARKVALUE(i->second);
}
}
@ -3195,7 +3208,7 @@ deleteClassProperty:
if (slots) {
ASSERT(type);
for (uint32 i = 0; (i < type->slotCount); i++) {
GCMARKVALUE(slots[i].value)
GCMARKVALUE(slots[i].value);
}
}
}
@ -3212,7 +3225,7 @@ deleteClassProperty:
{
GCMARKOBJECT(parent)
for (DynamicPropertyIterator i = dynamicProperties.begin(), end = dynamicProperties.end(); (i != end); i++) {
GCMARKVALUE(i->second)
GCMARKVALUE(i->second);
}
}
@ -3226,7 +3239,7 @@ deleteClassProperty:
// gc-mark all contained JS2Objects and visit contained structures to do likewise
void MethodClosure::markChildren()
{
GCMARKVALUE(thisObject)
GCMARKVALUE(thisObject);
GCMARKOBJECT(method->fInst)
}
@ -3263,7 +3276,7 @@ deleteClassProperty:
Frame::markChildren();
GCMARKOBJECT(internalNamespace)
for (DynamicPropertyIterator i = dynamicProperties.begin(), end = dynamicProperties.end(); (i != end); i++) {
GCMARKVALUE(i->second)
GCMARKVALUE(i->second);
}
}
@ -3283,7 +3296,7 @@ deleteClassProperty:
void ParameterFrame::markChildren()
{
Frame::markChildren();
GCMARKVALUE(thisObject)
GCMARKVALUE(thisObject);
}
@ -3438,6 +3451,25 @@ deleteClassProperty:
p->owner->returnToPond(p);
}
void JS2Object::markJS2Value(js2val v)
{
if (JS2VAL_IS_OBJECT(v)) {
JS2Object *obj = JS2VAL_TO_OBJECT(v);
GCMARKOBJECT(obj);
}
else
if (JS2VAL_IS_DOUBLE(v))
JS2Object::mark(JS2VAL_TO_DOUBLE(v));
else
if (JS2VAL_IS_LONG(v))
JS2Object::mark(JS2VAL_TO_LONG(v));
else
if (JS2VAL_IS_ULONG(v))
JS2Object::mark(JS2VAL_TO_ULONG(v));
else
if (JS2VAL_IS_FLOAT(v))
JS2Object::mark(JS2VAL_TO_FLOAT(v));
}
/************************************************************************************
*

View File

@ -127,8 +127,7 @@ public:
};
#define GCMARKOBJECT(n) if ((n) && !(n)->isMarked()) { (n)->mark(); (n)->markChildren(); }
#define GCMARKVALUE(v) if (JS2VAL_IS_OBJECT(v)) { JS2Object *_obj = JS2VAL_TO_OBJECT(v); GCMARKOBJECT(_obj) } \
else { if (JS2VAL_IS_DOUBLE(v)) { JS2Object::mark(JS2VAL_TO_DOUBLE(v)); } }
#define GCMARKVALUE(v) JS2Object::markJS2Value(v)
class JS2Object {
// Every object is either undefined, null, a Boolean,
@ -160,6 +159,7 @@ public:
void mark() { ((PondScum *)this)[-1].mark(); }
static void mark(void *p) { ((PondScum *)p)[-1].mark(); }
static void markJS2Value(js2val v);
};

View File

@ -35,7 +35,24 @@
case eMinus:
{
a = pop();
pushNumber(-toNumber(a));
a = toGeneralNumber(a);
if (JS2VAL_IS_LONG(a)) {
int64 v = *JS2VAL_TO_LONG(a);
if (JSLL_EQ(v, JSLL_MININT))
meta->reportError(Exception::rangeError, "Arithmetic overflow", errorPos());
JSLL_NEG(v, v);
pushLong(v);
}
else
if (JS2VAL_IS_ULONG(a)) {
uint64 v = *JS2VAL_TO_ULONG(a);
if (JSLL_UCMP(v, >, JSLL_MAXINT))
meta->reportError(Exception::rangeError, "Arithmetic overflow", errorPos());
JSLL_NEG(v, v);
pushLong(v);
}
else
pushNumber(-toNumber(a));
}
break;
@ -56,30 +73,71 @@
{
b = pop();
a = pop();
int32 count = toInteger(b) & 0x1F;
pushNumber(toInteger(a) << count);
a = toGeneralNumber(a);
int32 count = toInteger(b);
if (JS2VAL_IS_LONG(a)) {
int64 r;
JSLL_SHL(r, *JS2VAL_TO_LONG(a), count & 0x3F);
pushLong(r);
}
else
if (JS2VAL_IS_ULONG(a)) {
uint64 r;
JSLL_SHL(r, *JS2VAL_TO_ULONG(a), count & 0x3F);
pushULong(r);
}
else
pushNumber(toInteger(a) << (count & 0x1F));
}
break;
case eRightShift:
{
b = pop();
a = pop();
int32 count = toInteger(b) & 0x1F;
pushNumber(toInteger(a) >> count);
a = toGeneralNumber(a);
int32 count = toInteger(b);
if (JS2VAL_IS_LONG(a)) {
int64 r;
JSLL_SHR(r, *JS2VAL_TO_LONG(a), count & 0x3F);
pushLong(r);
}
else
if (JS2VAL_IS_ULONG(a)) {
uint64 r;
JSLL_USHR(r, *JS2VAL_TO_ULONG(a), count & 0x3F);
pushULong(r);
}
else
pushNumber(toInteger(a) >> (count & 0x1F));
}
break;
case eLogicalRightShift:
{
b = pop();
a = pop();
int32 count = toInteger(b) & 0x1F;
pushNumber(toUInt32(toInteger(a)) >> count);
a = toGeneralNumber(a);
int32 count = toInteger(b);
if (JS2VAL_IS_LONG(a)) {
int64 r;
JSLL_SHR(r, *JS2VAL_TO_LONG(a), count & 0x3F);
pushLong(r);
}
else
if (JS2VAL_IS_ULONG(a)) {
uint64 r;
JSLL_USHR(r, *JS2VAL_TO_ULONG(a), count & 0x3F);
pushULong(r);
}
else
pushNumber(toUInt32(toInteger(a)) >> (count & 0x1F));
}
break;
case eBitwiseAnd:
{
b = pop();
a = pop();
b = toGeneralNumber(b);
a = toGeneralNumber(a);
pushNumber(toInteger(a) & toInteger(b));
}
break;

View File

@ -40,6 +40,20 @@
}
break;
case eUInt64:
{
pushULong(BytecodeContainer::getUInt64(pc));
pc += sizeof(uint64);
}
break;
case eInt64:
{
pushLong(BytecodeContainer::getInt64(pc));
pc += sizeof(int64);
}
break;
case eTrue:
{
push(JS2VAL_TRUE);

View File

@ -79,6 +79,8 @@
#define INT_TO_JS2VAL(i) (((js2val)(i) << 1) | JS2VAL_INT)
#define JS2VAL_TO_INT(v) ((int32)(v) >> 1)
#define INT_FITS_IN_JS2VAL(i) ((uint32)((i)+JS2VAL_INT_MAX) <= 2*JS2VAL_INT_MAX)
#define LONG_FITS_IN_JS2VAL(x) (JSLL_CMP((x), >, -JS2VAL_INT_MAX) && JSLL_CMP(JS2VAL_INT_MAX, >, (x)))
#define ULONG_FITS_IN_JS2VAL(x) (JSLL_CMP(JS2VAL_INT_MAX, >, (x)))
#define JS2VAL_VOID INT_TO_JS2VAL(0 - JS2VAL_INT_POW2(30))
#define JS2VAL_NULL OBJECT_TO_JS2VAL(0)

View File

@ -54,6 +54,10 @@
** initializer
***********************************************************************/
extern int64 JSLL_MaxInt();
extern int64 JSLL_MinInt();
extern int64 JSLL_Zero();
#define JSLL_MAXINT JSLL_MaxInt()
#define JSLL_MININT JSLL_MinInt()
#define JSLL_ZERO JSLL_Zero()
@ -155,12 +159,26 @@
** JSLL_D2L Convert float to 64 bit
***********************************************************************/
#define JSLL_L2I(i, l) ((i) = (int32)(l))
#define JSLL_L2UI(ui, l) ((ui) = (uint32)(l))
#define JSLL_UL2I(i, ul) ((i) = (int32)(ul))
#define JSLL_L2UI(ui, l) ((ui) = (uint32)(l))
#define JSLL_L2F(f, l) ((f) = (float64)(l))
#define JSLL_L2D(d, l) ((d) = (float64)(l))
#ifdef _WIN32
#define JSLL_UL2D(d, ul) { \
if (ul > JSLL_MAXINT) { \
int64 _l2 = ul - JSLL_MAXINT; \
JSLL_L2D(d, _l2); \
(d) += JSLL_MININT; \
} \
else \
(d) = (int64)ul; \
}
#else
#define JSLL_UL2D(d, ul) ((d) = (float64)(ul))
#endif
#define JSLL_I2L(l, i) ((l) = (int64)(i))
#define JSLL_UI2L(l, ui) ((l) = (int64)(ui))
#define JSLL_UI2L(l, ui) ((l) = (int64)(ui))
#define JSLL_F2L(l, f) ((l) = (int64)(f))
#define JSLL_D2L(l, d) ((l) = (int64)(d))
@ -383,6 +401,8 @@ extern void jsll_udivmod(uint64 *qp, uint64 *rp, uint64 a, uint64 b);
(d) = -(d); \
}
#define JSLL_UL2D(d, ul) ((d) = (double)ul.hi * 4.294967296e9 + ul.lo)
#define JSLL_I2L(l, i) { int32 _i = (i) >> 31; (l).lo = (i); (l).hi = _i; }
#define JSLL_UI2L(l, ui) ((l).lo = (ui), (l).hi = 0)
#define JSLL_F2L(l, f) { double _d = (double)f; JSLL_D2L(l, _d); }

View File

@ -56,9 +56,9 @@ static int64 ll_zero = JSLL_INIT( 0x00000000,0x00000000 );
static int64 ll_maxint = JSLL_INIT( 0x7fffffff, 0xffffffff );
static int64 ll_minint = JSLL_INIT( 0x80000000, 0x00000000 );
static int64 JSLL_Zero(void) { return ll_zero; }
static int64 JSLL_MaxInt(void) { return ll_maxint; }
static int64 JSLL_MinInt(void) { return ll_minint; }
int64 JSLL_Zero(void) { return ll_zero; }
int64 JSLL_MaxInt(void) { return ll_maxint; }
int64 JSLL_MinInt(void) { return ll_minint; }
//
//