Moved genExpr to ICodeGenerator - added most expression ops.

This commit is contained in:
rogerl%netscape.com 2000-05-18 00:03:23 +00:00
Родитель ad5c33b8e4
Коммит 4ec5cba5d9
14 изменённых файлов: 3490 добавлений и 1674 удалений

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -131,6 +131,8 @@ namespace ICG {
Register switchRegister; // register containing switch control value for most
// recently in progress switch statement.
VariableList *variableList; // name|register pair for each variable
World *mWorld; // used to register strings
@ -158,6 +160,8 @@ namespace ICG {
void branch(Label *label);
void branchConditional(Label *label, Register condition);
void branchNotConditional(Label *label, Register condition);
void branchTrue(Label *label, Register condition);
void branchFalse(Label *label, Register condition);
void beginTry(Label *catchLabel, Label *finallyLabel)
{ iCode->push_back(new Tryin(catchLabel, finallyLabel)); }
@ -167,6 +171,8 @@ namespace ICG {
void resetStatement()
{ if (labelSet) { delete labelSet; labelSet = NULL; } resetTopRegister(); }
ICodeOp mapExprNodeToICodeOp(ExprNode::Kind kind);
public:
ICodeGenerator(World *world = NULL,
bool hasTryStatement = false,
@ -182,14 +188,18 @@ namespace ICG {
ICodeModule *complete();
Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch = false,
Label *trueBranch = NULL,
Label *falseBranch = NULL);
Register allocateVariable(const StringAtom& name)
{ Register result = getRegister(); (*variableList)[name] = result;
registerBase = topRegister; return result; }
Register findVariable(const StringAtom& name)
{ VariableList::iterator i = variableList->find(name);
// What's map? // ASSERT(i != map.end());
return (*i).second; }
ASSERT(i != variableList->end()); return (*i).second; }
Register allocateParameter(const StringAtom& name)
{ parameterCount++; return allocateVariable(name); }
@ -203,9 +213,11 @@ namespace ICG {
void move(Register destination, Register source);
void complement(Register destination, Register source);
Register test(Register source);
Register compare(ICodeOp op, Register source1, Register source2);
Register loadValue(JSValue value);
Register loadImmediate(double value);
Register loadString(String &value);
@ -224,7 +236,9 @@ namespace ICG {
Register getElement(Register base, Register index);
void setElement(Register base, Register index, Register value);
Register elementInc(Register base, Register index);
Register elementDec(Register base, Register index);
Register getRegisterBase() { return topRegister; }
InstructionStream *get_iCode() { return iCode; }
StatementLabels *getStatementLabels() { return labelSet; labelSet = NULL; }
@ -285,7 +299,7 @@ namespace ICG {
void beginLabelStatement(uint32 /* pos */, const StringAtom &label)
{ labelSet->push_back(&label); }
void endLabelStatement() { labelSet->pop_back(); }
void endLabelStatement() { if (labelSet) labelSet->pop_back(); }
void continueStatement(uint32 pos);
void breakStatement(uint32 pos);

Просмотреть файл

@ -277,6 +277,21 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
}
}
break;
/*
versions below are not right, there is no 'array' type really, the index operation
turns into a get_property call like this, only we need to be using JSString throughout.
case GET_ELEMENT:
{
GetElement* ge = static_cast<GetElement*>(instruction);
JSValue& base = (*registers)[src1(ge)];
JSValue index = (*registers)[src2(ge)].toString();
if (base.tag == JSValue::object_tag) {
JSObject* object = base.object;
(*registers)[dst(ge)] = object->getProperty(*index.string);
}
}
break;
*/
case GET_ELEMENT:
{
GetElement* ge = static_cast<GetElement*>(instruction);
@ -297,6 +312,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
}
}
break;
case LOAD_IMMEDIATE:
{
LoadImmediate* li = static_cast<LoadImmediate*>(instruction);
@ -309,6 +325,12 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
(*registers)[dst(ls)] = JSValue(src1(ls));
}
break;
case LOAD_VALUE:
{
LoadValue* lv = static_cast<LoadValue*>(instruction);
(*registers)[dst(lv)] = src1(lv);
}
break;
case BRANCH:
{
GenericBranch* bra =
@ -357,6 +379,28 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
}
}
break;
case BRANCH_TRUE:
{
GenericBranch* bc =
static_cast<GenericBranch*>(instruction);
ASSERT((*registers)[src1(bc)].isBoolean());
if ((*registers)[src1(bc)].boolean) {
mPC = begin_pc + ofs(bc);
continue;
}
}
break;
case BRANCH_FALSE:
{
GenericBranch* bc =
static_cast<GenericBranch*>(instruction);
ASSERT((*registers)[src1(bc)].isBoolean());
if (!(*registers)[src1(bc)].boolean) {
mPC = begin_pc + ofs(bc);
continue;
}
}
break;
case BRANCH_GE:
{
GenericBranch* bc =
@ -377,6 +421,74 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
}
}
break;
case SHIFTLEFT:
{
Arithmetic* shl = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(shl)];
JSValue& r1 = (*registers)[src1(shl)];
JSValue& r2 = (*registers)[src2(shl)];
JSValue num1(r1.toInt32());
JSValue num2(r2.toUInt32());
dest = num1.i32 << (num2.u32 & 0x1F);
}
break;
case SHIFTRIGHT:
{
Arithmetic* shr = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(shr)];
JSValue& r1 = (*registers)[src1(shr)];
JSValue& r2 = (*registers)[src2(shr)];
JSValue num1(r1.toInt32());
JSValue num2(r2.toUInt32());
dest = num1.i32 >> (num2.u32 & 0x1F);
}
break;
case USHIFTRIGHT:
{
Arithmetic* ushr = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(ushr)];
JSValue& r1 = (*registers)[src1(ushr)];
JSValue& r2 = (*registers)[src2(ushr)];
JSValue num1(r1.toUInt32());
JSValue num2(r2.toUInt32());
dest = num1.u32 >> (num2.u32 & 0x1F);
}
break;
case AND:
{
Arithmetic* shr = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(shr)];
JSValue& r1 = (*registers)[src1(shr)];
JSValue& r2 = (*registers)[src2(shr)];
JSValue num1(r1.toInt32());
JSValue num2(r2.toInt32());
dest = num1.i32 & num2.i32;
}
break;
case OR:
{
Arithmetic* shr = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(shr)];
JSValue& r1 = (*registers)[src1(shr)];
JSValue& r2 = (*registers)[src2(shr)];
JSValue num1(r1.toInt32());
JSValue num2(r2.toInt32());
dest = num1.i32 | num2.i32;
}
break;
case XOR:
{
Arithmetic* shr = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(shr)];
JSValue& r1 = (*registers)[src1(shr)];
JSValue& r2 = (*registers)[src2(shr)];
JSValue num1(r1.toInt32());
JSValue num2(r2.toInt32());
dest = num1.i32 ^ num2.i32;
}
break;
case ADD:
{
// could get clever here with Functional forms.
@ -462,11 +574,10 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
JSValue r = mGlobal->getVariable(*src1(nx)).toNumber();
dest = r;
r.f64 += val3(nx);
mGlobal->setVariable(*src1(nx), dest);
mGlobal->setVariable(*src1(nx), r);
}
break;
case COMPARE_LT:
case COMPARE_LE:
case COMPARE_EQ:
@ -475,11 +586,44 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
case COMPARE_GE:
{
Arithmetic* cmp = static_cast<Arithmetic*>(instruction);
float64 diff =
((*registers)[src1(cmp)].f64 -
(*registers)[src2(cmp)].f64);
(*registers)[dst(cmp)] =
JSValue(int32(diff == 0.0 ? 0 : (diff > 0.0 ? 1 : -1)));
JSValue& dest = (*registers)[dst(cmp)];
JSValue lv = (*registers)[src1(cmp)].toPrimitive(JSValue::Number);
JSValue rv = (*registers)[src2(cmp)].toPrimitive(JSValue::Number);
if (lv.isString() && rv.isString()) {
// XXX FIXME urgh, call w_strcmp ??? on a JSString ???
}
else {
lv = lv.toNumber();
rv = rv.toNumber();
if (lv.isNaN() || rv.isNaN())
dest = JSValue();
else {
// FIXME, does this do the right thing for +/- infinity?
switch (instruction->op()) {
case COMPARE_LT:
dest = JSValue(lv.f64 < rv.f64); break;
case COMPARE_LE:
dest = JSValue(lv.f64 <= rv.f64); break;
case COMPARE_EQ:
dest = JSValue(lv.f64 == rv.f64); break;
case COMPARE_NE:
dest = JSValue(lv.f64 != rv.f64); break;
case COMPARE_GT:
dest = JSValue(lv.f64 > rv.f64); break;
case COMPARE_GE:
dest = JSValue(lv.f64 >= rv.f64); break;
}
// float64 diff = lv.f64 - rv.f64;
// dest = JSValue( (int32) (diff == 0.0 ? 0 : (diff > 0.0 ? 1 : -1)));
}
}
}
break;
case TEST:
{
Test* tst = static_cast<Test*>(instruction);
(*registers)[dst(tst)] = (*registers)[src1(tst)].toBoolean();
}
break;
case NEGATE:
@ -494,6 +638,13 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
(*registers)[dst(pos)] = (*registers)[src1(pos)].toNumber();
}
break;
case BITNOT:
{
Bitnot* bn = static_cast<Bitnot*>(instruction);
(*registers)[dst(bn)] = JSValue(~(*registers)[src1(bn)].toInt32().i32);
}
break;
/*
case NOT:
{
Not* nt = static_cast<Not*>(instruction);
@ -501,7 +652,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
JSValue(int32(!(*registers)[src1(nt)].i32));
}
break;
*/
case THROW:
{
Throw* thrw = static_cast<Throw*>(instruction);
@ -610,7 +761,7 @@ void Context::addListener(Listener* listener)
void Context::removeListener(Listener* listener)
{
ListenerIterator e = mListeners.end();
ListenerIterator l = find(mListeners.begin(), e, listener);
ListenerIterator l = std::find(mListeners.begin(), e, listener);
if (l != e) mListeners.erase(l);
}

Просмотреть файл

@ -40,18 +40,54 @@ namespace JSTypes {
// using JavaScript::StringAtom;
// the canonical undefined value.
// the canonical undefined value, etc.
const JSValue kUndefinedValue;
const JSValue kNaN(0.0, 0.0);
const JSValue kNaN = JSValue(nan);
const JSValue kTrue = JSValue(true);
const JSValue kFalse = JSValue(false);
#ifdef IS_LITTLE_ENDIAN
#define JSDOUBLE_HI32(x) (((uint32 *)&(x))[1])
#define JSDOUBLE_LO32(x) (((uint32 *)&(x))[0])
#else
#define JSDOUBLE_HI32(x) (((uint32 *)&(x))[0])
#define JSDOUBLE_LO32(x) (((uint32 *)&(x))[1])
#endif
#define JSDOUBLE_HI32_SIGNBIT 0x80000000
#define JSDOUBLE_HI32_EXPMASK 0x7ff00000
#define JSDOUBLE_HI32_MANTMASK 0x000fffff
#define JSDOUBLE_IS_NaN(x) \
((JSDOUBLE_HI32(x) & JSDOUBLE_HI32_EXPMASK) == JSDOUBLE_HI32_EXPMASK && \
(JSDOUBLE_LO32(x) || (JSDOUBLE_HI32(x) & JSDOUBLE_HI32_MANTMASK)))
#define JSDOUBLE_IS_INFINITE(x) \
((JSDOUBLE_HI32(x) & ~JSDOUBLE_HI32_SIGNBIT) == JSDOUBLE_HI32_EXPMASK && \
!JSDOUBLE_LO32(x))
#define JSDOUBLE_IS_FINITE(x) \
((JSDOUBLE_HI32(x) & JSDOUBLE_HI32_EXPMASK) != JSDOUBLE_HI32_EXPMASK)
#define JSDOUBLE_IS_NEGZERO(d) (JSDOUBLE_HI32(d) == JSDOUBLE_HI32_SIGNBIT && \
JSDOUBLE_LO32(d) == 0)
JSValue::JSValue(float64 a, float64 b)
bool JSValue::isNaN() const
{
f64 = a/b;
tag = f64_tag;
ASSERT(isNumber());
switch (tag) {
case i32_tag:
case u32_tag:
return false;
case f64_tag:
return JSDOUBLE_IS_NaN(f64);
default:
NOT_REACHED("Broken compiler?");
return true;
}
}
int JSValue::operator==(const JSValue& value) const
{
if (this->tag == value.tag) {
@ -62,6 +98,7 @@ int JSValue::operator==(const JSValue& value) const
CASE(i32); CASE(u32); CASE(f32);
CASE(i64); CASE(u64); CASE(f64);
CASE(object); CASE(array); CASE(function); CASE(string);
CASE(boolean);
#undef CASE
// question: are all undefined values equal to one another?
case undefined_tag: return 1;
@ -76,6 +113,9 @@ Formatter& operator<<(Formatter& f, const JSValue& value)
case JSValue::i32_tag:
f << float64(value.i32);
break;
case JSValue::u32_tag:
f << float64(value.u32);
break;
case JSValue::f64_tag:
f << value.f64;
break;
@ -87,39 +127,80 @@ Formatter& operator<<(Formatter& f, const JSValue& value)
case JSValue::string_tag:
f << *value.string;
break;
default:
case JSValue::boolean_tag:
f << ((value.boolean) ? "true" : "false");
break;
case JSValue::undefined_tag:
f << "undefined";
break;
default:
NOT_REACHED("Bad tag");
}
return f;
}
JSValue JSValue::toPrimitive(ECMA_type hint) const
{
switch (tag) {
case i32_tag:
case u32_tag:
case f64_tag:
case string_tag:
case boolean_tag:
case undefined_tag:
return *this;
case object_tag:
case array_tag:
case function_tag:
if (hint == String) {
// FIXME
}
else {
// FIXME
}
break;
default:
NOT_REACHED("Bad tag");
}
return kUndefinedValue;
}
JSValue JSValue::valueToString(const JSValue& value) // can assume value is not a string
{
char *chrp;
char buf[dtosStandardBufferSize];
switch (value.tag) {
case JSValue::i32_tag:
case i32_tag:
chrp = doubleToStr(buf, dtosStandardBufferSize, value.i32, dtosStandard, 0);
break;
case JSValue::f64_tag:
case u32_tag:
chrp = doubleToStr(buf, dtosStandardBufferSize, value.u32, dtosStandard, 0);
break;
case f64_tag:
chrp = doubleToStr(buf, dtosStandardBufferSize, value.f64, dtosStandard, 0);
break;
case JSValue::object_tag:
case object_tag:
chrp = "object";
break;
case JSValue::array_tag:
case array_tag:
chrp = "array";
break;
case JSValue::function_tag:
case function_tag:
chrp = "function";
break;
case JSValue::string_tag:
case string_tag:
return value;
default:
case boolean_tag:
chrp = (value.boolean) ? "true" : "false";
break;
case undefined_tag:
chrp = "undefined";
break;
default:
NOT_REACHED("Bad tag");
}
return JSValue(new JSString(chrp));
}
@ -127,25 +208,142 @@ JSValue JSValue::valueToString(const JSValue& value) // can assume value is not
JSValue JSValue::valueToNumber(const JSValue& value) // can assume value is not a number
{
switch (value.tag) {
case JSValue::i32_tag:
case JSValue::f64_tag:
case i32_tag:
return JSValue((float64)value.i32);
case u32_tag:
return JSValue((float64)value.u32);
case f64_tag:
return value;
case JSValue::string_tag:
case string_tag:
{
JSString* str = value.string;
const char16 *numEnd;
double d = stringToDouble(str->begin(), str->end(), numEnd);
return JSValue(d);
}
case JSValue::object_tag:
case JSValue::array_tag:
case JSValue::function_tag:
break;
default:
case object_tag:
case array_tag:
case function_tag:
// XXX more needed :
// toNumber(toPrimitive(hint Number))
return kUndefinedValue;
case boolean_tag:
return JSValue((value.boolean) ? 1.0 : 0.0);
case undefined_tag:
return kNaN;
break;
default:
NOT_REACHED("Bad tag");
return kUndefinedValue;
}
return kUndefinedValue;
}
JSValue JSValue::valueToBoolean(const JSValue& value)
{
switch (value.tag) {
case i32_tag:
return JSValue(value.i32 != 0);
case u32_tag:
return JSValue(value.u32 != 0);
case f64_tag:
return JSValue(!(value.f64 == 0.0) || JSDOUBLE_IS_NaN(value.f64));
case string_tag:
return JSValue(value.string->length() != 0);
case boolean_tag:
return value;
case object_tag:
case array_tag:
case function_tag:
return kTrue;
case undefined_tag:
return kFalse;
default:
NOT_REACHED("Bad tag");
return kUndefinedValue;
}
}
static const double two32 = 4294967296.0;
static const double two31 = 2147483648.0;
JSValue JSValue::valueToInt32(const JSValue& value)
{
double d;
switch (value.tag) {
case i32_tag:
return value;
case u32_tag:
d = value.u32;
break;
case f64_tag:
d = value.f64;
break;
case string_tag:
{
JSString* str = value.string;
const char16 *numEnd;
d = stringToDouble(str->begin(), str->end(), numEnd);
}
break;
case boolean_tag:
return JSValue((int32)((value.boolean) ? 1 : 0));
case object_tag:
case array_tag:
case undefined_tag:
// toNumber(toPrimitive(hint Number))
return kUndefinedValue;
default:
NOT_REACHED("Bad tag");
return kUndefinedValue;
}
if ((d == 0.0) || !JSDOUBLE_IS_FINITE(d) )
return JSValue((int32)0);
d = fmod(d, two32);
d = (d >= 0) ? d : d + two32;
if (d >= two31)
return JSValue((int32)(d - two32));
else
return JSValue((int32)d);
}
JSValue JSValue::valueToUInt32(const JSValue& value)
{
double d;
switch (value.tag) {
case i32_tag:
return JSValue((uint32)value.i32);
case u32_tag:
return value;
case f64_tag:
d = value.f64;
break;
case string_tag:
{
JSString* str = value.string;
const char16 *numEnd;
d = stringToDouble(str->begin(), str->end(), numEnd);
}
break;
case boolean_tag:
return JSValue((uint32)((value.boolean) ? 1 : 0));
case object_tag:
case array_tag:
case undefined_tag:
// toNumber(toPrimitive(hint Number))
return kUndefinedValue;
default:
NOT_REACHED("Bad tag");
return kUndefinedValue;
}
if ((d == 0.0) || !JSDOUBLE_IS_FINITE(d))
return JSValue((uint32)0);
bool neg = (d < 0);
d = floor(neg ? -d : d);
d = neg ? -d : d;
d = fmod(d, two32);
d = (d >= 0) ? d : d + two32;
return JSValue((uint32)d);
}
JSFunction::~JSFunction()

Просмотреть файл

@ -76,44 +76,66 @@ namespace JSTypes {
JSArray* array;
JSFunction *function;
JSString *string;
bool boolean;
};
/* These are the ECMA types, for use in 'toPrimitive' calls */
enum ECMA_type {
Undefined, Null, Boolean, Number, Object, String,
NoHint
};
enum {
i8_tag, u8_tag,
i16_tag, u16_tag,
i32_tag, u32_tag,
i64_tag, u64_tag,
f32_tag, f64_tag,
object_tag, array_tag, function_tag, string_tag,
object_tag, array_tag, function_tag, string_tag, boolean_tag,
undefined_tag
} tag;
JSValue() : f64(0.0), tag(undefined_tag) {}
explicit JSValue(int32 i32) : i32(i32), tag(i32_tag) {}
explicit JSValue(uint32 u32) : u32(u32), tag(u32_tag) {}
explicit JSValue(float64 f64) : f64(f64), tag(f64_tag) {}
explicit JSValue(JSObject* object) : object(object), tag(object_tag) {}
explicit JSValue(JSArray* array) : array(array), tag(array_tag) {}
explicit JSValue(JSFunction* function) : function(function), tag(function_tag) {}
explicit JSValue(JSString* string) : string(string), tag(string_tag) {}
explicit JSValue(bool boolean) : boolean(boolean), tag(boolean_tag) {}
JSValue(float64 a, float64 b);
int32& operator=(int32 i32) { return (tag = i32_tag, this->i32 = i32); }
uint32& operator=(uint32 u32) { return (tag = u32_tag, this->u32 = u32); }
float64& operator=(float64 f64) { return (tag = f64_tag, this->f64 = f64); }
JSObject*& operator=(JSObject* object) { return (tag = object_tag, this->object = object); }
JSArray*& operator=(JSArray* array) { return (tag = array_tag, this->array = array); }
JSFunction*& operator=(JSFunction* function) { return (tag = function_tag, this->function = function); }
JSString*& operator=(JSString* string) { return (tag = string_tag, this->string = string); }
bool& operator=(bool boolean) { return (tag = boolean_tag, this->boolean = boolean); }
bool isString() const { return (tag == string_tag); }
bool isNumber() const { return ((tag == f64_tag) || (tag == i32_tag)); }
bool isBoolean() const { return (tag == boolean_tag); }
bool isNumber() const { return (tag == f64_tag); }
/* this is correct wrt ECMA, The i32 & u32 kinds
will have to be converted to doubles anyway because
we can't have overflow happening in generic arithmetic */
bool isNaN() const;
JSValue toString() const { return (isString() ? *this : valueToString(*this)); }
JSValue toNumber() const { return (isNumber() ? *this : valueToNumber(*this)); }
JSValue toInt32() const { return ((tag == i32_tag) ? *this : valueToInt32(*this)); }
JSValue toUInt32() const { return ((tag == u32_tag) ? *this : valueToUInt32(*this)); }
JSValue toBoolean() const { return ((tag == boolean_tag) ? *this : valueToBoolean(*this)); }
JSValue toPrimitive(ECMA_type hint = NoHint) const;
static JSValue valueToString(const JSValue& value);
static JSValue valueToNumber(const JSValue& value);
static JSValue valueToInt32(const JSValue& value);
static JSValue valueToUInt32(const JSValue& value);
static JSValue valueToBoolean(const JSValue& value);
int operator==(const JSValue& value) const;
};
@ -140,6 +162,8 @@ namespace JSTypes {
extern const JSValue kUndefinedValue;
extern const JSValue kNaN;
extern const JSValue kTrue;
extern const JSValue kFalse;
/**
* Basic behavior of all JS objects, mapping a name to a value,

Просмотреть файл

@ -107,6 +107,30 @@ namespace VM {
return f;
}
ICodeOp Instruction::getBranchOp()
{
// XXX FIXME, convert to table lookup or arithmetic after the dust settles
switch (mOpcode) {
case COMPARE_EQ:
// return BRANCH_EQ;
case COMPARE_NE:
// return BRANCH_NE;
case COMPARE_GE:
// return BRANCH_GE;
case COMPARE_GT:
// return BRANCH_GT;
case COMPARE_LE:
// return BRANCH_LE;
case COMPARE_LT:
// return BRANCH_LT;
case TEST:
return BRANCH_TRUE;
default:
NOT_REACHED("Unexpected branch code");
return NOP;
}
}
} /* namespace VM */
} /* namespace JavaScript */

Просмотреть файл

@ -42,6 +42,7 @@
namespace JavaScript {
namespace VM {
using JSTypes::JSValue;
using JSTypes::JSValues;
using JSTypes::JSString;
@ -51,11 +52,13 @@ namespace VM {
BITNOT, /* dest, source */
BRANCH, /* target label */
BRANCH_EQ, /* target label, condition */
BRANCH_FALSE, /* target label, condition */
BRANCH_GE, /* target label, condition */
BRANCH_GT, /* target label, condition */
BRANCH_LE, /* target label, condition */
BRANCH_LT, /* target label, condition */
BRANCH_NE, /* target label, condition */
BRANCH_TRUE, /* target label, condition */
CALL, /* result, target, args */
COMPARE_EQ, /* dest, source */
COMPARE_GE, /* dest, source */
@ -65,13 +68,15 @@ namespace VM {
COMPARE_LT, /* dest, source */
COMPARE_NE, /* dest, source */
DIVIDE, /* dest, source1, source2 */
GET_ELEMENT, /* dest, array, index */
ELEM_XCR, /* dest, base, index, value */
GET_ELEMENT, /* dest, base, index */
GET_PROP, /* dest, object, prop name */
INSTANCEOF, /* dest, source */
JSR, /* target */
LOAD_IMMEDIATE, /* dest, immediate value (double) */
LOAD_NAME, /* dest, name */
LOAD_STRING, /* dest, immediate value (string) */
LOAD_VALUE, /* dest, immediate value (JSValue) */
MOVE, /* dest, source */
MULTIPLY, /* dest, source1, source2 */
NAME_XCR, /* dest, name, value */
@ -88,13 +93,14 @@ namespace VM {
RETURN_VOID, /* Return without a value */
RTS, /* Return to sender */
SAVE_NAME, /* name, source */
SET_ELEMENT, /* base, source1, source2 */
SET_ELEMENT, /* base, index, value */
SET_PROP, /* object, name, source */
SHIFTLEFT, /* dest, source1, source2 */
SHIFTRIGHT, /* dest, source1, source2 */
STRICT_EQ, /* dest, source */
STRICT_NE, /* dest, source */
SUBTRACT, /* dest, source1, source2 */
TEST, /* dest, source */
THROW, /* exception value */
TRYIN, /* catch target, finally target */
TRYOUT, /* mmm, there is no try, only do */
@ -114,11 +120,13 @@ namespace VM {
"BITNOT ",
"BRANCH ",
"BRANCH_EQ ",
"BRANCH_FALSE ",
"BRANCH_GE ",
"BRANCH_GT ",
"BRANCH_LE ",
"BRANCH_LT ",
"BRANCH_NE ",
"BRANCH_TRUE ",
"CALL ",
"COMPARE_EQ ",
"COMPARE_GE ",
@ -128,6 +136,7 @@ namespace VM {
"COMPARE_LT ",
"COMPARE_NE ",
"DIVIDE ",
"ELEM_XCR ",
"GET_ELEMENT ",
"GET_PROP ",
"INSTANCEOF ",
@ -135,6 +144,7 @@ namespace VM {
"LOAD_IMMEDIATE",
"LOAD_NAME ",
"LOAD_STRING ",
"LOAD_VALUE ",
"MOVE ",
"MULTIPLY ",
"NAME_XCR ",
@ -158,6 +168,7 @@ namespace VM {
"STRICT_EQ ",
"STRICT_NE ",
"SUBTRACT ",
"TEST ",
"THROW ",
"TRYIN ",
"TRYOUT ",
@ -188,11 +199,7 @@ namespace VM {
return f;
}
ICodeOp getBranchOp()
{
return ((mOpcode >= COMPARE_EQ) && (mOpcode <= COMPARE_NE)) ?
(ICodeOp)(BRANCH_EQ + (mOpcode - COMPARE_EQ)) : NOP;
}
ICodeOp getBranchOp();
ICodeOp op() { return mOpcode; }
@ -445,6 +452,15 @@ namespace VM {
/* print() and printOperands() inherited from GenericBranch */
};
class BranchFalse : public GenericBranch {
public:
/* target label, condition */
BranchFalse (Label* aOp1, Register aOp2) :
GenericBranch
(BRANCH_FALSE, aOp1, aOp2) {};
/* print() and printOperands() inherited from GenericBranch */
};
class BranchGE : public GenericBranch {
public:
/* target label, condition */
@ -490,6 +506,15 @@ namespace VM {
/* print() and printOperands() inherited from GenericBranch */
};
class BranchTrue : public GenericBranch {
public:
/* target label, condition */
BranchTrue (Label* aOp1, Register aOp2) :
GenericBranch
(BRANCH_TRUE, aOp1, aOp2) {};
/* print() and printOperands() inherited from GenericBranch */
};
class Call : public Instruction_3<Register, Register, RegisterList> {
public:
/* result, target, args */
@ -578,6 +603,22 @@ namespace VM {
/* print() and printOperands() inherited from Arithmetic */
};
class ElemXcr : public Instruction_4<Register, Register, Register, double> {
public:
/* dest, base, index, value */
ElemXcr (Register aOp1, Register aOp2, Register aOp3, double aOp4) :
Instruction_4<Register, Register, Register, double>
(ELEM_XCR, aOp1, aOp2, aOp3, aOp4) {};
virtual Formatter& print(Formatter& f) {
f << opcodeNames[ELEM_XCR] << "\t" << "R" << mOp1 << ", " << "R" << mOp2 << ", " << "R" << mOp3 << ", " << mOp4;
return f;
}
virtual Formatter& printOperands(Formatter& f, const JSValues& registers) {
f << "R" << mOp1 << '=' << registers[mOp1] << ", " << "R" << mOp2 << '=' << registers[mOp2] << ", " << "R" << mOp3 << '=' << registers[mOp3];
return f;
}
};
class GetElement : public Instruction_3<Register, Register, Register> {
public:
/* dest, array, index */
@ -682,6 +723,22 @@ namespace VM {
}
};
class LoadValue : public Instruction_2<Register, JSValue> {
public:
/* dest, immediate value (JSValue) */
LoadValue (Register aOp1, JSValue aOp2) :
Instruction_2<Register, JSValue>
(LOAD_VALUE, aOp1, aOp2) {};
virtual Formatter& print(Formatter& f) {
f << opcodeNames[LOAD_VALUE] << "\t" << "R" << mOp1 << ", " << mOp2;
return f;
}
virtual Formatter& printOperands(Formatter& f, const JSValues& registers) {
f << "R" << mOp1 << '=' << registers[mOp1];
return f;
}
};
class Move : public Instruction_2<Register, Register> {
public:
/* dest, source */
@ -991,6 +1048,22 @@ namespace VM {
/* print() and printOperands() inherited from Arithmetic */
};
class Test : public Instruction_2<Register, Register> {
public:
/* dest, source */
Test (Register aOp1, Register aOp2) :
Instruction_2<Register, Register>
(TEST, aOp1, aOp2) {};
virtual Formatter& print(Formatter& f) {
f << opcodeNames[TEST] << "\t" << "R" << mOp1 << ", " << "R" << mOp2;
return f;
}
virtual Formatter& printOperands(Formatter& f, const JSValues& registers) {
f << "R" << mOp1 << '=' << registers[mOp1] << ", " << "R" << mOp2 << '=' << registers[mOp2];
return f;
}
};
class Throw : public Instruction_1<Register> {
public:
/* exception value */

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -131,6 +131,8 @@ namespace ICG {
Register switchRegister; // register containing switch control value for most
// recently in progress switch statement.
VariableList *variableList; // name|register pair for each variable
World *mWorld; // used to register strings
@ -158,6 +160,8 @@ namespace ICG {
void branch(Label *label);
void branchConditional(Label *label, Register condition);
void branchNotConditional(Label *label, Register condition);
void branchTrue(Label *label, Register condition);
void branchFalse(Label *label, Register condition);
void beginTry(Label *catchLabel, Label *finallyLabel)
{ iCode->push_back(new Tryin(catchLabel, finallyLabel)); }
@ -167,6 +171,8 @@ namespace ICG {
void resetStatement()
{ if (labelSet) { delete labelSet; labelSet = NULL; } resetTopRegister(); }
ICodeOp mapExprNodeToICodeOp(ExprNode::Kind kind);
public:
ICodeGenerator(World *world = NULL,
bool hasTryStatement = false,
@ -182,14 +188,18 @@ namespace ICG {
ICodeModule *complete();
Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch = false,
Label *trueBranch = NULL,
Label *falseBranch = NULL);
Register allocateVariable(const StringAtom& name)
{ Register result = getRegister(); (*variableList)[name] = result;
registerBase = topRegister; return result; }
Register findVariable(const StringAtom& name)
{ VariableList::iterator i = variableList->find(name);
// What's map? // ASSERT(i != map.end());
return (*i).second; }
ASSERT(i != variableList->end()); return (*i).second; }
Register allocateParameter(const StringAtom& name)
{ parameterCount++; return allocateVariable(name); }
@ -203,9 +213,11 @@ namespace ICG {
void move(Register destination, Register source);
void complement(Register destination, Register source);
Register test(Register source);
Register compare(ICodeOp op, Register source1, Register source2);
Register loadValue(JSValue value);
Register loadImmediate(double value);
Register loadString(String &value);
@ -224,7 +236,9 @@ namespace ICG {
Register getElement(Register base, Register index);
void setElement(Register base, Register index, Register value);
Register elementInc(Register base, Register index);
Register elementDec(Register base, Register index);
Register getRegisterBase() { return topRegister; }
InstructionStream *get_iCode() { return iCode; }
StatementLabels *getStatementLabels() { return labelSet; labelSet = NULL; }
@ -285,7 +299,7 @@ namespace ICG {
void beginLabelStatement(uint32 /* pos */, const StringAtom &label)
{ labelSet->push_back(&label); }
void endLabelStatement() { labelSet->pop_back(); }
void endLabelStatement() { if (labelSet) labelSet->pop_back(); }
void continueStatement(uint32 pos);
void breakStatement(uint32 pos);

Просмотреть файл

@ -277,6 +277,21 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
}
}
break;
/*
versions below are not right, there is no 'array' type really, the index operation
turns into a get_property call like this, only we need to be using JSString throughout.
case GET_ELEMENT:
{
GetElement* ge = static_cast<GetElement*>(instruction);
JSValue& base = (*registers)[src1(ge)];
JSValue index = (*registers)[src2(ge)].toString();
if (base.tag == JSValue::object_tag) {
JSObject* object = base.object;
(*registers)[dst(ge)] = object->getProperty(*index.string);
}
}
break;
*/
case GET_ELEMENT:
{
GetElement* ge = static_cast<GetElement*>(instruction);
@ -297,6 +312,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
}
}
break;
case LOAD_IMMEDIATE:
{
LoadImmediate* li = static_cast<LoadImmediate*>(instruction);
@ -309,6 +325,12 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
(*registers)[dst(ls)] = JSValue(src1(ls));
}
break;
case LOAD_VALUE:
{
LoadValue* lv = static_cast<LoadValue*>(instruction);
(*registers)[dst(lv)] = src1(lv);
}
break;
case BRANCH:
{
GenericBranch* bra =
@ -357,6 +379,28 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
}
}
break;
case BRANCH_TRUE:
{
GenericBranch* bc =
static_cast<GenericBranch*>(instruction);
ASSERT((*registers)[src1(bc)].isBoolean());
if ((*registers)[src1(bc)].boolean) {
mPC = begin_pc + ofs(bc);
continue;
}
}
break;
case BRANCH_FALSE:
{
GenericBranch* bc =
static_cast<GenericBranch*>(instruction);
ASSERT((*registers)[src1(bc)].isBoolean());
if (!(*registers)[src1(bc)].boolean) {
mPC = begin_pc + ofs(bc);
continue;
}
}
break;
case BRANCH_GE:
{
GenericBranch* bc =
@ -377,6 +421,74 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
}
}
break;
case SHIFTLEFT:
{
Arithmetic* shl = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(shl)];
JSValue& r1 = (*registers)[src1(shl)];
JSValue& r2 = (*registers)[src2(shl)];
JSValue num1(r1.toInt32());
JSValue num2(r2.toUInt32());
dest = num1.i32 << (num2.u32 & 0x1F);
}
break;
case SHIFTRIGHT:
{
Arithmetic* shr = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(shr)];
JSValue& r1 = (*registers)[src1(shr)];
JSValue& r2 = (*registers)[src2(shr)];
JSValue num1(r1.toInt32());
JSValue num2(r2.toUInt32());
dest = num1.i32 >> (num2.u32 & 0x1F);
}
break;
case USHIFTRIGHT:
{
Arithmetic* ushr = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(ushr)];
JSValue& r1 = (*registers)[src1(ushr)];
JSValue& r2 = (*registers)[src2(ushr)];
JSValue num1(r1.toUInt32());
JSValue num2(r2.toUInt32());
dest = num1.u32 >> (num2.u32 & 0x1F);
}
break;
case AND:
{
Arithmetic* shr = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(shr)];
JSValue& r1 = (*registers)[src1(shr)];
JSValue& r2 = (*registers)[src2(shr)];
JSValue num1(r1.toInt32());
JSValue num2(r2.toInt32());
dest = num1.i32 & num2.i32;
}
break;
case OR:
{
Arithmetic* shr = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(shr)];
JSValue& r1 = (*registers)[src1(shr)];
JSValue& r2 = (*registers)[src2(shr)];
JSValue num1(r1.toInt32());
JSValue num2(r2.toInt32());
dest = num1.i32 | num2.i32;
}
break;
case XOR:
{
Arithmetic* shr = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(shr)];
JSValue& r1 = (*registers)[src1(shr)];
JSValue& r2 = (*registers)[src2(shr)];
JSValue num1(r1.toInt32());
JSValue num2(r2.toInt32());
dest = num1.i32 ^ num2.i32;
}
break;
case ADD:
{
// could get clever here with Functional forms.
@ -462,11 +574,10 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
JSValue r = mGlobal->getVariable(*src1(nx)).toNumber();
dest = r;
r.f64 += val3(nx);
mGlobal->setVariable(*src1(nx), dest);
mGlobal->setVariable(*src1(nx), r);
}
break;
case COMPARE_LT:
case COMPARE_LE:
case COMPARE_EQ:
@ -475,11 +586,44 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
case COMPARE_GE:
{
Arithmetic* cmp = static_cast<Arithmetic*>(instruction);
float64 diff =
((*registers)[src1(cmp)].f64 -
(*registers)[src2(cmp)].f64);
(*registers)[dst(cmp)] =
JSValue(int32(diff == 0.0 ? 0 : (diff > 0.0 ? 1 : -1)));
JSValue& dest = (*registers)[dst(cmp)];
JSValue lv = (*registers)[src1(cmp)].toPrimitive(JSValue::Number);
JSValue rv = (*registers)[src2(cmp)].toPrimitive(JSValue::Number);
if (lv.isString() && rv.isString()) {
// XXX FIXME urgh, call w_strcmp ??? on a JSString ???
}
else {
lv = lv.toNumber();
rv = rv.toNumber();
if (lv.isNaN() || rv.isNaN())
dest = JSValue();
else {
// FIXME, does this do the right thing for +/- infinity?
switch (instruction->op()) {
case COMPARE_LT:
dest = JSValue(lv.f64 < rv.f64); break;
case COMPARE_LE:
dest = JSValue(lv.f64 <= rv.f64); break;
case COMPARE_EQ:
dest = JSValue(lv.f64 == rv.f64); break;
case COMPARE_NE:
dest = JSValue(lv.f64 != rv.f64); break;
case COMPARE_GT:
dest = JSValue(lv.f64 > rv.f64); break;
case COMPARE_GE:
dest = JSValue(lv.f64 >= rv.f64); break;
}
// float64 diff = lv.f64 - rv.f64;
// dest = JSValue( (int32) (diff == 0.0 ? 0 : (diff > 0.0 ? 1 : -1)));
}
}
}
break;
case TEST:
{
Test* tst = static_cast<Test*>(instruction);
(*registers)[dst(tst)] = (*registers)[src1(tst)].toBoolean();
}
break;
case NEGATE:
@ -494,6 +638,13 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
(*registers)[dst(pos)] = (*registers)[src1(pos)].toNumber();
}
break;
case BITNOT:
{
Bitnot* bn = static_cast<Bitnot*>(instruction);
(*registers)[dst(bn)] = JSValue(~(*registers)[src1(bn)].toInt32().i32);
}
break;
/*
case NOT:
{
Not* nt = static_cast<Not*>(instruction);
@ -501,7 +652,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
JSValue(int32(!(*registers)[src1(nt)].i32));
}
break;
*/
case THROW:
{
Throw* thrw = static_cast<Throw*>(instruction);
@ -610,7 +761,7 @@ void Context::addListener(Listener* listener)
void Context::removeListener(Listener* listener)
{
ListenerIterator e = mListeners.end();
ListenerIterator l = find(mListeners.begin(), e, listener);
ListenerIterator l = std::find(mListeners.begin(), e, listener);
if (l != e) mListeners.erase(l);
}

Просмотреть файл

@ -40,18 +40,54 @@ namespace JSTypes {
// using JavaScript::StringAtom;
// the canonical undefined value.
// the canonical undefined value, etc.
const JSValue kUndefinedValue;
const JSValue kNaN(0.0, 0.0);
const JSValue kNaN = JSValue(nan);
const JSValue kTrue = JSValue(true);
const JSValue kFalse = JSValue(false);
#ifdef IS_LITTLE_ENDIAN
#define JSDOUBLE_HI32(x) (((uint32 *)&(x))[1])
#define JSDOUBLE_LO32(x) (((uint32 *)&(x))[0])
#else
#define JSDOUBLE_HI32(x) (((uint32 *)&(x))[0])
#define JSDOUBLE_LO32(x) (((uint32 *)&(x))[1])
#endif
#define JSDOUBLE_HI32_SIGNBIT 0x80000000
#define JSDOUBLE_HI32_EXPMASK 0x7ff00000
#define JSDOUBLE_HI32_MANTMASK 0x000fffff
#define JSDOUBLE_IS_NaN(x) \
((JSDOUBLE_HI32(x) & JSDOUBLE_HI32_EXPMASK) == JSDOUBLE_HI32_EXPMASK && \
(JSDOUBLE_LO32(x) || (JSDOUBLE_HI32(x) & JSDOUBLE_HI32_MANTMASK)))
#define JSDOUBLE_IS_INFINITE(x) \
((JSDOUBLE_HI32(x) & ~JSDOUBLE_HI32_SIGNBIT) == JSDOUBLE_HI32_EXPMASK && \
!JSDOUBLE_LO32(x))
#define JSDOUBLE_IS_FINITE(x) \
((JSDOUBLE_HI32(x) & JSDOUBLE_HI32_EXPMASK) != JSDOUBLE_HI32_EXPMASK)
#define JSDOUBLE_IS_NEGZERO(d) (JSDOUBLE_HI32(d) == JSDOUBLE_HI32_SIGNBIT && \
JSDOUBLE_LO32(d) == 0)
JSValue::JSValue(float64 a, float64 b)
bool JSValue::isNaN() const
{
f64 = a/b;
tag = f64_tag;
ASSERT(isNumber());
switch (tag) {
case i32_tag:
case u32_tag:
return false;
case f64_tag:
return JSDOUBLE_IS_NaN(f64);
default:
NOT_REACHED("Broken compiler?");
return true;
}
}
int JSValue::operator==(const JSValue& value) const
{
if (this->tag == value.tag) {
@ -62,6 +98,7 @@ int JSValue::operator==(const JSValue& value) const
CASE(i32); CASE(u32); CASE(f32);
CASE(i64); CASE(u64); CASE(f64);
CASE(object); CASE(array); CASE(function); CASE(string);
CASE(boolean);
#undef CASE
// question: are all undefined values equal to one another?
case undefined_tag: return 1;
@ -76,6 +113,9 @@ Formatter& operator<<(Formatter& f, const JSValue& value)
case JSValue::i32_tag:
f << float64(value.i32);
break;
case JSValue::u32_tag:
f << float64(value.u32);
break;
case JSValue::f64_tag:
f << value.f64;
break;
@ -87,39 +127,80 @@ Formatter& operator<<(Formatter& f, const JSValue& value)
case JSValue::string_tag:
f << *value.string;
break;
default:
case JSValue::boolean_tag:
f << ((value.boolean) ? "true" : "false");
break;
case JSValue::undefined_tag:
f << "undefined";
break;
default:
NOT_REACHED("Bad tag");
}
return f;
}
JSValue JSValue::toPrimitive(ECMA_type hint) const
{
switch (tag) {
case i32_tag:
case u32_tag:
case f64_tag:
case string_tag:
case boolean_tag:
case undefined_tag:
return *this;
case object_tag:
case array_tag:
case function_tag:
if (hint == String) {
// FIXME
}
else {
// FIXME
}
break;
default:
NOT_REACHED("Bad tag");
}
return kUndefinedValue;
}
JSValue JSValue::valueToString(const JSValue& value) // can assume value is not a string
{
char *chrp;
char buf[dtosStandardBufferSize];
switch (value.tag) {
case JSValue::i32_tag:
case i32_tag:
chrp = doubleToStr(buf, dtosStandardBufferSize, value.i32, dtosStandard, 0);
break;
case JSValue::f64_tag:
case u32_tag:
chrp = doubleToStr(buf, dtosStandardBufferSize, value.u32, dtosStandard, 0);
break;
case f64_tag:
chrp = doubleToStr(buf, dtosStandardBufferSize, value.f64, dtosStandard, 0);
break;
case JSValue::object_tag:
case object_tag:
chrp = "object";
break;
case JSValue::array_tag:
case array_tag:
chrp = "array";
break;
case JSValue::function_tag:
case function_tag:
chrp = "function";
break;
case JSValue::string_tag:
case string_tag:
return value;
default:
case boolean_tag:
chrp = (value.boolean) ? "true" : "false";
break;
case undefined_tag:
chrp = "undefined";
break;
default:
NOT_REACHED("Bad tag");
}
return JSValue(new JSString(chrp));
}
@ -127,25 +208,142 @@ JSValue JSValue::valueToString(const JSValue& value) // can assume value is not
JSValue JSValue::valueToNumber(const JSValue& value) // can assume value is not a number
{
switch (value.tag) {
case JSValue::i32_tag:
case JSValue::f64_tag:
case i32_tag:
return JSValue((float64)value.i32);
case u32_tag:
return JSValue((float64)value.u32);
case f64_tag:
return value;
case JSValue::string_tag:
case string_tag:
{
JSString* str = value.string;
const char16 *numEnd;
double d = stringToDouble(str->begin(), str->end(), numEnd);
return JSValue(d);
}
case JSValue::object_tag:
case JSValue::array_tag:
case JSValue::function_tag:
break;
default:
case object_tag:
case array_tag:
case function_tag:
// XXX more needed :
// toNumber(toPrimitive(hint Number))
return kUndefinedValue;
case boolean_tag:
return JSValue((value.boolean) ? 1.0 : 0.0);
case undefined_tag:
return kNaN;
break;
default:
NOT_REACHED("Bad tag");
return kUndefinedValue;
}
return kUndefinedValue;
}
JSValue JSValue::valueToBoolean(const JSValue& value)
{
switch (value.tag) {
case i32_tag:
return JSValue(value.i32 != 0);
case u32_tag:
return JSValue(value.u32 != 0);
case f64_tag:
return JSValue(!(value.f64 == 0.0) || JSDOUBLE_IS_NaN(value.f64));
case string_tag:
return JSValue(value.string->length() != 0);
case boolean_tag:
return value;
case object_tag:
case array_tag:
case function_tag:
return kTrue;
case undefined_tag:
return kFalse;
default:
NOT_REACHED("Bad tag");
return kUndefinedValue;
}
}
static const double two32 = 4294967296.0;
static const double two31 = 2147483648.0;
JSValue JSValue::valueToInt32(const JSValue& value)
{
double d;
switch (value.tag) {
case i32_tag:
return value;
case u32_tag:
d = value.u32;
break;
case f64_tag:
d = value.f64;
break;
case string_tag:
{
JSString* str = value.string;
const char16 *numEnd;
d = stringToDouble(str->begin(), str->end(), numEnd);
}
break;
case boolean_tag:
return JSValue((int32)((value.boolean) ? 1 : 0));
case object_tag:
case array_tag:
case undefined_tag:
// toNumber(toPrimitive(hint Number))
return kUndefinedValue;
default:
NOT_REACHED("Bad tag");
return kUndefinedValue;
}
if ((d == 0.0) || !JSDOUBLE_IS_FINITE(d) )
return JSValue((int32)0);
d = fmod(d, two32);
d = (d >= 0) ? d : d + two32;
if (d >= two31)
return JSValue((int32)(d - two32));
else
return JSValue((int32)d);
}
JSValue JSValue::valueToUInt32(const JSValue& value)
{
double d;
switch (value.tag) {
case i32_tag:
return JSValue((uint32)value.i32);
case u32_tag:
return value;
case f64_tag:
d = value.f64;
break;
case string_tag:
{
JSString* str = value.string;
const char16 *numEnd;
d = stringToDouble(str->begin(), str->end(), numEnd);
}
break;
case boolean_tag:
return JSValue((uint32)((value.boolean) ? 1 : 0));
case object_tag:
case array_tag:
case undefined_tag:
// toNumber(toPrimitive(hint Number))
return kUndefinedValue;
default:
NOT_REACHED("Bad tag");
return kUndefinedValue;
}
if ((d == 0.0) || !JSDOUBLE_IS_FINITE(d))
return JSValue((uint32)0);
bool neg = (d < 0);
d = floor(neg ? -d : d);
d = neg ? -d : d;
d = fmod(d, two32);
d = (d >= 0) ? d : d + two32;
return JSValue((uint32)d);
}
JSFunction::~JSFunction()

Просмотреть файл

@ -76,44 +76,66 @@ namespace JSTypes {
JSArray* array;
JSFunction *function;
JSString *string;
bool boolean;
};
/* These are the ECMA types, for use in 'toPrimitive' calls */
enum ECMA_type {
Undefined, Null, Boolean, Number, Object, String,
NoHint
};
enum {
i8_tag, u8_tag,
i16_tag, u16_tag,
i32_tag, u32_tag,
i64_tag, u64_tag,
f32_tag, f64_tag,
object_tag, array_tag, function_tag, string_tag,
object_tag, array_tag, function_tag, string_tag, boolean_tag,
undefined_tag
} tag;
JSValue() : f64(0.0), tag(undefined_tag) {}
explicit JSValue(int32 i32) : i32(i32), tag(i32_tag) {}
explicit JSValue(uint32 u32) : u32(u32), tag(u32_tag) {}
explicit JSValue(float64 f64) : f64(f64), tag(f64_tag) {}
explicit JSValue(JSObject* object) : object(object), tag(object_tag) {}
explicit JSValue(JSArray* array) : array(array), tag(array_tag) {}
explicit JSValue(JSFunction* function) : function(function), tag(function_tag) {}
explicit JSValue(JSString* string) : string(string), tag(string_tag) {}
explicit JSValue(bool boolean) : boolean(boolean), tag(boolean_tag) {}
JSValue(float64 a, float64 b);
int32& operator=(int32 i32) { return (tag = i32_tag, this->i32 = i32); }
uint32& operator=(uint32 u32) { return (tag = u32_tag, this->u32 = u32); }
float64& operator=(float64 f64) { return (tag = f64_tag, this->f64 = f64); }
JSObject*& operator=(JSObject* object) { return (tag = object_tag, this->object = object); }
JSArray*& operator=(JSArray* array) { return (tag = array_tag, this->array = array); }
JSFunction*& operator=(JSFunction* function) { return (tag = function_tag, this->function = function); }
JSString*& operator=(JSString* string) { return (tag = string_tag, this->string = string); }
bool& operator=(bool boolean) { return (tag = boolean_tag, this->boolean = boolean); }
bool isString() const { return (tag == string_tag); }
bool isNumber() const { return ((tag == f64_tag) || (tag == i32_tag)); }
bool isBoolean() const { return (tag == boolean_tag); }
bool isNumber() const { return (tag == f64_tag); }
/* this is correct wrt ECMA, The i32 & u32 kinds
will have to be converted to doubles anyway because
we can't have overflow happening in generic arithmetic */
bool isNaN() const;
JSValue toString() const { return (isString() ? *this : valueToString(*this)); }
JSValue toNumber() const { return (isNumber() ? *this : valueToNumber(*this)); }
JSValue toInt32() const { return ((tag == i32_tag) ? *this : valueToInt32(*this)); }
JSValue toUInt32() const { return ((tag == u32_tag) ? *this : valueToUInt32(*this)); }
JSValue toBoolean() const { return ((tag == boolean_tag) ? *this : valueToBoolean(*this)); }
JSValue toPrimitive(ECMA_type hint = NoHint) const;
static JSValue valueToString(const JSValue& value);
static JSValue valueToNumber(const JSValue& value);
static JSValue valueToInt32(const JSValue& value);
static JSValue valueToUInt32(const JSValue& value);
static JSValue valueToBoolean(const JSValue& value);
int operator==(const JSValue& value) const;
};
@ -140,6 +162,8 @@ namespace JSTypes {
extern const JSValue kUndefinedValue;
extern const JSValue kNaN;
extern const JSValue kTrue;
extern const JSValue kFalse;
/**
* Basic behavior of all JS objects, mapping a name to a value,

Просмотреть файл

@ -107,6 +107,30 @@ namespace VM {
return f;
}
ICodeOp Instruction::getBranchOp()
{
// XXX FIXME, convert to table lookup or arithmetic after the dust settles
switch (mOpcode) {
case COMPARE_EQ:
// return BRANCH_EQ;
case COMPARE_NE:
// return BRANCH_NE;
case COMPARE_GE:
// return BRANCH_GE;
case COMPARE_GT:
// return BRANCH_GT;
case COMPARE_LE:
// return BRANCH_LE;
case COMPARE_LT:
// return BRANCH_LT;
case TEST:
return BRANCH_TRUE;
default:
NOT_REACHED("Unexpected branch code");
return NOP;
}
}
} /* namespace VM */
} /* namespace JavaScript */

Просмотреть файл

@ -42,6 +42,7 @@
namespace JavaScript {
namespace VM {
using JSTypes::JSValue;
using JSTypes::JSValues;
using JSTypes::JSString;
@ -51,11 +52,13 @@ namespace VM {
BITNOT, /* dest, source */
BRANCH, /* target label */
BRANCH_EQ, /* target label, condition */
BRANCH_FALSE, /* target label, condition */
BRANCH_GE, /* target label, condition */
BRANCH_GT, /* target label, condition */
BRANCH_LE, /* target label, condition */
BRANCH_LT, /* target label, condition */
BRANCH_NE, /* target label, condition */
BRANCH_TRUE, /* target label, condition */
CALL, /* result, target, args */
COMPARE_EQ, /* dest, source */
COMPARE_GE, /* dest, source */
@ -65,13 +68,15 @@ namespace VM {
COMPARE_LT, /* dest, source */
COMPARE_NE, /* dest, source */
DIVIDE, /* dest, source1, source2 */
GET_ELEMENT, /* dest, array, index */
ELEM_XCR, /* dest, base, index, value */
GET_ELEMENT, /* dest, base, index */
GET_PROP, /* dest, object, prop name */
INSTANCEOF, /* dest, source */
JSR, /* target */
LOAD_IMMEDIATE, /* dest, immediate value (double) */
LOAD_NAME, /* dest, name */
LOAD_STRING, /* dest, immediate value (string) */
LOAD_VALUE, /* dest, immediate value (JSValue) */
MOVE, /* dest, source */
MULTIPLY, /* dest, source1, source2 */
NAME_XCR, /* dest, name, value */
@ -88,13 +93,14 @@ namespace VM {
RETURN_VOID, /* Return without a value */
RTS, /* Return to sender */
SAVE_NAME, /* name, source */
SET_ELEMENT, /* base, source1, source2 */
SET_ELEMENT, /* base, index, value */
SET_PROP, /* object, name, source */
SHIFTLEFT, /* dest, source1, source2 */
SHIFTRIGHT, /* dest, source1, source2 */
STRICT_EQ, /* dest, source */
STRICT_NE, /* dest, source */
SUBTRACT, /* dest, source1, source2 */
TEST, /* dest, source */
THROW, /* exception value */
TRYIN, /* catch target, finally target */
TRYOUT, /* mmm, there is no try, only do */
@ -114,11 +120,13 @@ namespace VM {
"BITNOT ",
"BRANCH ",
"BRANCH_EQ ",
"BRANCH_FALSE ",
"BRANCH_GE ",
"BRANCH_GT ",
"BRANCH_LE ",
"BRANCH_LT ",
"BRANCH_NE ",
"BRANCH_TRUE ",
"CALL ",
"COMPARE_EQ ",
"COMPARE_GE ",
@ -128,6 +136,7 @@ namespace VM {
"COMPARE_LT ",
"COMPARE_NE ",
"DIVIDE ",
"ELEM_XCR ",
"GET_ELEMENT ",
"GET_PROP ",
"INSTANCEOF ",
@ -135,6 +144,7 @@ namespace VM {
"LOAD_IMMEDIATE",
"LOAD_NAME ",
"LOAD_STRING ",
"LOAD_VALUE ",
"MOVE ",
"MULTIPLY ",
"NAME_XCR ",
@ -158,6 +168,7 @@ namespace VM {
"STRICT_EQ ",
"STRICT_NE ",
"SUBTRACT ",
"TEST ",
"THROW ",
"TRYIN ",
"TRYOUT ",
@ -188,11 +199,7 @@ namespace VM {
return f;
}
ICodeOp getBranchOp()
{
return ((mOpcode >= COMPARE_EQ) && (mOpcode <= COMPARE_NE)) ?
(ICodeOp)(BRANCH_EQ + (mOpcode - COMPARE_EQ)) : NOP;
}
ICodeOp getBranchOp();
ICodeOp op() { return mOpcode; }
@ -445,6 +452,15 @@ namespace VM {
/* print() and printOperands() inherited from GenericBranch */
};
class BranchFalse : public GenericBranch {
public:
/* target label, condition */
BranchFalse (Label* aOp1, Register aOp2) :
GenericBranch
(BRANCH_FALSE, aOp1, aOp2) {};
/* print() and printOperands() inherited from GenericBranch */
};
class BranchGE : public GenericBranch {
public:
/* target label, condition */
@ -490,6 +506,15 @@ namespace VM {
/* print() and printOperands() inherited from GenericBranch */
};
class BranchTrue : public GenericBranch {
public:
/* target label, condition */
BranchTrue (Label* aOp1, Register aOp2) :
GenericBranch
(BRANCH_TRUE, aOp1, aOp2) {};
/* print() and printOperands() inherited from GenericBranch */
};
class Call : public Instruction_3<Register, Register, RegisterList> {
public:
/* result, target, args */
@ -578,6 +603,22 @@ namespace VM {
/* print() and printOperands() inherited from Arithmetic */
};
class ElemXcr : public Instruction_4<Register, Register, Register, double> {
public:
/* dest, base, index, value */
ElemXcr (Register aOp1, Register aOp2, Register aOp3, double aOp4) :
Instruction_4<Register, Register, Register, double>
(ELEM_XCR, aOp1, aOp2, aOp3, aOp4) {};
virtual Formatter& print(Formatter& f) {
f << opcodeNames[ELEM_XCR] << "\t" << "R" << mOp1 << ", " << "R" << mOp2 << ", " << "R" << mOp3 << ", " << mOp4;
return f;
}
virtual Formatter& printOperands(Formatter& f, const JSValues& registers) {
f << "R" << mOp1 << '=' << registers[mOp1] << ", " << "R" << mOp2 << '=' << registers[mOp2] << ", " << "R" << mOp3 << '=' << registers[mOp3];
return f;
}
};
class GetElement : public Instruction_3<Register, Register, Register> {
public:
/* dest, array, index */
@ -682,6 +723,22 @@ namespace VM {
}
};
class LoadValue : public Instruction_2<Register, JSValue> {
public:
/* dest, immediate value (JSValue) */
LoadValue (Register aOp1, JSValue aOp2) :
Instruction_2<Register, JSValue>
(LOAD_VALUE, aOp1, aOp2) {};
virtual Formatter& print(Formatter& f) {
f << opcodeNames[LOAD_VALUE] << "\t" << "R" << mOp1 << ", " << mOp2;
return f;
}
virtual Formatter& printOperands(Formatter& f, const JSValues& registers) {
f << "R" << mOp1 << '=' << registers[mOp1];
return f;
}
};
class Move : public Instruction_2<Register, Register> {
public:
/* dest, source */
@ -991,6 +1048,22 @@ namespace VM {
/* print() and printOperands() inherited from Arithmetic */
};
class Test : public Instruction_2<Register, Register> {
public:
/* dest, source */
Test (Register aOp1, Register aOp2) :
Instruction_2<Register, Register>
(TEST, aOp1, aOp2) {};
virtual Formatter& print(Formatter& f) {
f << opcodeNames[TEST] << "\t" << "R" << mOp1 << ", " << "R" << mOp2;
return f;
}
virtual Formatter& printOperands(Formatter& f, const JSValues& registers) {
f << "R" << mOp1 << '=' << registers[mOp1] << ", " << "R" << mOp2 << '=' << registers[mOp2];
return f;
}
};
class Throw : public Instruction_1<Register> {
public:
/* exception value */