// Java literal class, with associated operations. This code assumes that // the rules for integer and floating point arithmetic are the same as // for java (i.e. 2's complement integer arithmetic, IEEE floating point // with the correct options set) #include #include #include #include #include #include #include #include "AST.h" #include "osstream.h" #include "runtime/fp-utils.h" /* These are off by default */ bool sizeofRuntimeIntIs64 = 0; bool sizeofRuntimeCharIs32 = 0; bool sizeofRuntimeShortIs32 = 0; #if defined(sun) # define strtou64 strtoull #elif defined(__APPLE__) # define strtou64 strtouq #elif defined(_HPUX_SOURCE) /* lacks strtoull - simple implementation */ static uint64 strtou64(const char *nptr, char **endptr, int base) { uint64 val = 0; int neg = 0; const char *p = nptr; assert (base == 0 || (base >= 2 && base <= 36)); while (*p && isspace(*p)) p++; if (*p == '+') p++; else if (*p == '-') { neg=1; p++; } if ((base==0||base==16) && *p == '0' && toupper(*(p+1)) == 'X') { base = 16; p += 2; } else if (base==0 && *p == '0') { base = 8; p++; } else if (base == 0) base = 10; while (*p && ( (isdigit(*p) && *p < ('0'+base)) || (isalpha(*p) && toupper(*p) < ('A'+base-10)) ) ) { if (isdigit(*p)) { val = (val * base) + (*p - '0'); } else if (isalpha(*p)) { val = (val * base) + (10 + toupper(*p) - 'A'); } p++; } if (endptr) *endptr = (char *)p; if (neg) return (uint64)(-((int64)val)); else return val; } #elif SIZEOF_LONG >= 8 # define strtou64 strtoul #else # define strtou64 strtoull #endif int64 Literal::intValue() const { switch (kind()) { case Common::ByteKind: return (int8)value.i; case Common::ShortKind: return (int16)value.i; case Common::CharKind: return (uint16)value.i; case Common::IntKind: return (int32)value.i; case Common::LongKind: return value.i; default: fatal_error(""); return 0; } } Literal Literal::arithPromote() { switch (kind()) { case Common::ByteKind: case Common::ShortKind: case Common::CharKind: return cast(Common::IntKind); default: return *this; } } Literal Literal::arithPromote(Common::Kind to) { if (kind() == Common::DoubleKind || to == Common::DoubleKind) return cast(Common::DoubleKind); if (kind() == Common::FloatKind || to == Common::FloatKind) return cast(Common::FloatKind); if (kind() == Common::LongKind || to == Common::LongKind) return cast(Common::LongKind); if (kind() == Common::BoolKind || to == Common::BoolKind) return cast(Common::BoolKind); return cast(Common::IntKind); } Literal Literal::cast(Common::Kind to) { Literal me = *this; switch (kind()) { case Common::BoolKind: assert(to == Common::BoolKind); break; case IntegerKind: switch (to) { case Common::ByteKind: me.value.i = (int8)value.i; break; case Common::ShortKind: me.value.i = (int16)value.i; break; case Common::CharKind: me.value.i = (uint16)value.i; break; case Common::IntKind: me.value.i = (int32)value.i; break; case Common::LongKind: me.value.i = (int64)value.i; break; case Common::FloatKind: me.value.f = value.i; break; case Common::DoubleKind: me.value.d = value.i; break; case Common::BoolKind: me.value.b = (bool)!!value.i; break; default: fatal_error(""); } break; case Common::FloatKind: switch (to) { case Common::ByteKind: me.value.i = (int8)value.f; break; case Common::ShortKind: me.value.i = (int16)value.f; break; case Common::CharKind: me.value.i = (uint16)value.f; break; case Common::IntKind: me.value.i = (int32)value.f; break; case Common::LongKind: me.value.i = (int64)value.f; break; case Common::FloatKind: break; case Common::DoubleKind: me.value.d = value.f; break; case Common::BoolKind: fatal_error(""); default: fatal_error(""); } break; case Common::DoubleKind: switch (to) { case Common::ByteKind: me.value.i = (int8)value.d; break; case Common::ShortKind: me.value.i = (int16)value.d; break; case Common::CharKind: me.value.i = (uint16)value.d; break; case Common::IntKind: me.value.i = (int32)value.d; break; case Common::LongKind: me.value.i = (int64)value.d; break; case Common::FloatKind: me.value.f = value.d; case Common::DoubleKind: break; case Common::BoolKind: fatal_error(""); default: fatal_error(""); } break; default: fatal_error(""); } me._kind = to; return me; } Literal Literal::operator~() { Literal me = arithPromote(); switch (me.kind()) { case IntegerKind: me.value.i = ~me.intValue(); break; default: fatal_error(""); } return me; } Literal Literal::operator!() { assert(kind() == Common::BoolKind); return Literal((bool)!value.b); } Literal Literal::operator-() { Literal me = arithPromote(); switch (me.kind()) { case IntegerKind: me.value.i = -me.intValue(); break; case Common::FloatKind: me.value.f = -me.value.f; break; case Common::DoubleKind: me.value.d = -me.doubleValue(); break; default: fatal_error(""); } return me; } Literal Literal::operator*(Literal arg) { Literal me = arithPromote(arg.kind()); arg = arg.arithPromote(me.kind()); switch (me.kind()) { case IntegerKind: me.value.i = me.intValue() * arg.intValue(); break; case Common::FloatKind: me.value.f = me.value.f * arg.value.f; break; case Common::DoubleKind: me.value.d = me.doubleValue() * arg.doubleValue(); break; default: fatal_error(""); } return me; } Literal Literal::operator/(Literal arg) { Literal me = arithPromote(arg.kind()); arg = arg.arithPromote(me.kind()); switch (me.kind()) { case IntegerKind: me.value.i = me.intValue() / arg.intValue(); break; case Common::FloatKind: me.value.f = me.value.f / arg.value.f; break; case Common::DoubleKind: me.value.d = me.doubleValue() / arg.doubleValue(); break; default: fatal_error(""); } return me; } Literal Literal::operator%(Literal arg) { Literal me = arithPromote(arg.kind()); arg = arg.arithPromote(me.kind()); switch (me.kind()) { case IntegerKind: me.value.i = me.intValue() % arg.intValue(); break; case Common::FloatKind: me.value.f = fmod(me.value.f, arg.value.f); break; case Common::DoubleKind: me.value.d = fmod(me.doubleValue(), arg.doubleValue()); break; default: fatal_error(""); } return me; } Literal Literal::operator+(Literal arg) { Literal me = arithPromote(arg.kind()); arg = arg.arithPromote(me.kind()); switch (me.kind()) { case IntegerKind: me.value.i = me.intValue() + arg.intValue(); break; case Common::FloatKind: me.value.f = me.value.f + arg.value.f; break; case Common::DoubleKind: me.value.d = me.doubleValue() + arg.doubleValue(); break; default: fatal_error(""); } return me; } Literal Literal::operator-(Literal arg) { Literal me = arithPromote(arg.kind()); arg = arg.arithPromote(me.kind()); switch (me.kind()) { case IntegerKind: me.value.i = me.intValue() - arg.intValue(); break; case Common::FloatKind: me.value.f = me.value.f - arg.value.f; break; case Common::DoubleKind: me.value.d = me.doubleValue() - arg.doubleValue(); break; default: fatal_error(""); } return me; } Literal Literal::lsl(Literal arg) { Literal me = arithPromote(); // Java spec 5.6.1 - shift args promoted separately arg = arg.arithPromote(); int shiftval = arg.intValue(); switch (me.kind()) { case Common::LongKind: shiftval = shiftval & 0x3F; // Java spec 15.18 assert(shiftval >= 0 && shiftval <= 63); if (shiftval != 0) me.value.i = me.intValue() << shiftval; break; case Common::IntKind: shiftval = shiftval & 0x1F; // Java spec 15.18 assert(shiftval >= 0 && shiftval <= 31); if (shiftval != 0) me.value.i = me.intValue() << shiftval; break; default: fatal_error(""); } return me; } Literal Literal::rsl(Literal arg) { Literal me = arithPromote(); // Java spec 5.6.1 - shift args promoted separately arg = arg.arithPromote(); int shiftval = arg.intValue(); switch (me.kind()) { // DOB: need to be careful that negative 32-bit values are handled correctly case Common::LongKind: shiftval = shiftval & 0x3F; // Java spec 15.18 assert(shiftval >= 0 && shiftval <= 63); if (shiftval != 0) me.value.i = (unsigned long long)me.intValue() >> shiftval; break; case Common::IntKind: shiftval = shiftval & 0x1F; // Java spec 15.18 assert(shiftval >= 0 && shiftval <= 31); if (shiftval != 0) me.value.i = ((unsigned long long)(uint32)me.intValue()) >> shiftval; break; default: fatal_error(""); } return me; } Literal Literal::rsa(Literal arg) { Literal me = arithPromote(); // Java spec 5.6.1 - shift args promoted separately arg = arg.arithPromote(); int shiftval = arg.intValue(); switch (me.kind()) { // warning: this assumes that >> on signed quantities is arithmetic // right shift (not guaranteed by ANSI C, at least) case Common::LongKind: shiftval = shiftval & 0x3F; // Java spec 15.18 assert(shiftval >= 0 && shiftval <= 63); if (shiftval != 0) me.value.i = me.intValue() >> shiftval; break; case Common::IntKind: shiftval = shiftval & 0x1F; // Java spec 15.18 assert(shiftval >= 0 && shiftval <= 31); if (shiftval != 0) me.value.i = me.intValue() >> shiftval; break; default: fatal_error(""); } return me; } Literal Literal::lt(Literal arg) { Literal me = arithPromote(arg.kind()); arg = arg.arithPromote(me.kind()); switch (me.kind()) { case IntegerKind: me.value.b = me.intValue() < arg.intValue(); break; case Common::FloatKind: me.value.b = me.value.f < arg.value.f; break; case Common::DoubleKind: me.value.b = me.doubleValue() < arg.doubleValue(); break; default: fatal_error(""); } me._kind = Common::BoolKind; return me; } Literal Literal::le(Literal arg) { Literal me = arithPromote(arg.kind()); arg = arg.arithPromote(me.kind()); switch (me.kind()) { case IntegerKind: me.value.b = me.intValue() <= arg.intValue(); break; case Common::FloatKind: me.value.b = me.value.f <= arg.value.f; break; case Common::DoubleKind: me.value.b = me.doubleValue() <= arg.doubleValue(); break; default: fatal_error(""); } me._kind = Common::BoolKind; return me; } Literal Literal::gt(Literal arg) { Literal me = arithPromote(arg.kind()); arg = arg.arithPromote(me.kind()); switch (me.kind()) { case IntegerKind: me.value.b = me.intValue() > arg.intValue(); break; case Common::FloatKind: me.value.b = me.value.f > arg.value.f; break; case Common::DoubleKind: me.value.b = me.doubleValue() > arg.doubleValue(); break; default: fatal_error(""); } me._kind = Common::BoolKind; return me; } Literal Literal::ge(Literal arg) { Literal me = arithPromote(arg.kind()); arg = arg.arithPromote(me.kind()); switch (me.kind()) { case IntegerKind: me.value.b = me.intValue() >= arg.intValue(); break; case Common::FloatKind: me.value.b = me.value.f >= arg.value.f; break; case Common::DoubleKind: me.value.b = me.doubleValue() >= arg.doubleValue(); break; default: fatal_error(""); } me._kind = Common::BoolKind; return me; } Literal Literal::eq(Literal arg) { Literal me = arithPromote(arg.kind()); arg = arg.arithPromote(me.kind()); if (me.kind() != arg.kind()) return false; switch (me.kind()) { case Common::BoolKind: me.value.b = me.boolValue() == arg.boolValue(); break; case IntegerKind: me.value.b = me.intValue() == arg.intValue(); break; case Common::FloatKind: me.value.b = me.value.f == arg.value.f; break; case Common::DoubleKind: me.value.b = me.doubleValue() == arg.doubleValue(); break; default: fatal_error(""); } me._kind = Common::BoolKind; return me; } Literal Literal::ne(Literal arg) { Literal me = arithPromote(arg.kind()); arg = arg.arithPromote(me.kind()); if (me.kind() != arg.kind()) return true; switch (me.kind()) { case Common::BoolKind: me.value.b = me.boolValue() != arg.boolValue(); break; case IntegerKind: me.value.b = me.intValue() != arg.intValue(); break; case Common::FloatKind: me.value.b = me.value.f != arg.value.f; break; case Common::DoubleKind: me.value.b = me.doubleValue() != arg.doubleValue(); break; default: fatal_error(""); } me._kind = Common::BoolKind; return me; } Literal Literal::operator&(Literal arg) { Literal me = arithPromote(arg.kind()); arg = arg.arithPromote(me.kind()); switch (me.kind()) { case Common::BoolKind: me.value.b = me.boolValue() && arg.boolValue(); break; case IntegerKind: me.value.i = me.intValue() & arg.intValue(); break; default: fatal_error(""); } return me; } Literal Literal::operator|(Literal arg) { Literal me = arithPromote(arg.kind()); arg = arg.arithPromote(me.kind()); switch (me.kind()) { case Common::BoolKind: me.value.b = me.boolValue() || arg.boolValue(); break; case IntegerKind: me.value.i = me.intValue() | arg.intValue(); break; default: fatal_error(""); } return me; } Literal Literal::operator^(Literal arg) { Literal me = arithPromote(arg.kind()); arg = arg.arithPromote(me.kind()); switch (me.kind()) { case Common::BoolKind: me.value.b = me.boolValue() ^ arg.boolValue(); break; case IntegerKind: me.value.i = me.intValue() ^ arg.intValue(); break; default: fatal_error(""); } return me; } Literal Literal::operator&&(Literal arg) { Literal me = *this; assert(me.kind() == Common::BoolKind && arg.kind() == Common::BoolKind); me.value.b = me.boolValue() && arg.boolValue(); return me; } Literal Literal::operator||(Literal arg) { Literal me = *this; assert(me.kind() == Common::BoolKind && arg.kind() == Common::BoolKind); me.value.b = me.boolValue() || arg.boolValue(); return me; } ostream& operator<<(ostream& os, Literal l) { switch (l.kind()) { case Common::ByteKind: os << "jbyte(" << l.intValue() << ")"; break; case Common::ShortKind: os << "jshort(" << l.intValue() << ")"; break; case Common::CharKind: os << "jchar(" << l.intValue() << ")"; break; case Common::IntKind: os << "jint(" << l.intValue() << ")"; break; case Common::LongKind: os << "jlong(" << l.intValue() << ")"; break; case Common::FloatKind: os << "jfloat(" << l.doubleValue() << ")"; break; case Common::DoubleKind: os << "jdouble(" << l.doubleValue() << ")"; break; case Common::BoolKind: os << "jboolean(" << l.boolValue() << ")"; break; default: fatal_error(""); } return os; } Literal intLiteral(const string &s) { const char *beginptr = s.c_str(); char *endptr = NULL; errno = 0; const int32 value = strtou64( beginptr, &endptr, 0 ); assert( !errno || (endptr&&!*endptr)); return Literal( value ); } Literal longLiteral(const string &s) { const char *beginptr = s.c_str(); char *endptr = NULL; errno = 0; const int64 value = strtou64( beginptr, &endptr, 0 ); assert( !errno || (endptr&&!*endptr)); return Literal( value ); } Literal floatLiteral(const string &s) { float value; #if defined(__KCC) /* strtod() is apparently broken for these cases on the Cray */ if (!strcmp(s.c_str(), "3.40282346638528860e+38f")) value = 3.40282346638528860e+38; else if (!strcmp(s.c_str(), "1.40129846432481707e-45f")) value = 1.40129846432481707e-45; else #endif value = strtod( s.c_str(), 0 ); return Literal( value ); } Literal doubleLiteral(const string &s) { double value; #if defined(__KCC) /* strtod() is apparently broken for these cases on the Cray */ if (!strcmp(s.c_str(), "1.79769313486231570e+308")) value = 1.79769313486231570e+308; else if (!strcmp(s.c_str(), "2.2250738585072014E-308")) value = 2.2250738585072014E-308; else #endif value = strtod( s.c_str(), 0 ); return Literal(value, s); } const string Literal::asString() const { ostringstream format; format.setf( ios::hex | ios::showbase, ios::basefield | ios::showbase ); switch (kind()) { case Common::BoolKind: return boolValue() ? "1" : "0"; case Common::ByteKind: format << (int32) (uint8) intValue(); break; case Common::CharKind: if (sizeofRuntimeCharIs32) { format << (uint32) intValue(); } else { format << (uint16) intValue(); } break; case Common::ShortKind: if (sizeofRuntimeShortIs32) { format << (int32) intValue(); } else { format << (int16) intValue(); } break; case Common::IntKind: if (sizeofRuntimeIntIs64) { format << (int64) intValue(); } else { format << (int32) intValue(); } break; case Common::LongKind: format << (int64) intValue() << "LL"; break; case Common::FloatKind: case Common::DoubleKind: { char buffer[ 32 ]; g_fmt( buffer, doubleValue() ); string result = buffer; if (result.find_first_of(".eE") == string::npos) result += '.'; return result; } default: fatal_error(""); } return format.str(); } bool Literal::isNd() const { if (kind() == Common::DoubleKind) { /* I'm a C programmer. Can you tell ? */ const char *s = orig.c_str(); int l = strlen(s); assert(l > 0); if (s[l - 1] == 'd' && !::strchr(s, 'e') && !::strchr(s, '.')) return true; } return false; }