mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-04 02:57:38 +00:00
Added more string handling + valueToString/Number code.
NativeFunction support.
This commit is contained in:
parent
1639cd5231
commit
261b8ef660
@ -256,6 +256,12 @@ namespace ICG {
|
||||
return dest;
|
||||
}
|
||||
|
||||
void ICodeGenerator::callVoid(Register target, RegisterList args)
|
||||
{
|
||||
Call *instr = new Call(NotARegister, target, args);
|
||||
iCode->push_back(instr);
|
||||
}
|
||||
|
||||
void ICodeGenerator::branch(Label *label)
|
||||
{
|
||||
Branch *instr = new Branch(label);
|
||||
|
@ -189,6 +189,7 @@ namespace ICG {
|
||||
Register op(ICodeOp op, Register source);
|
||||
Register op(ICodeOp op, Register source1, Register source2);
|
||||
Register call(Register target, RegisterList args);
|
||||
void callVoid(Register target, RegisterList args);
|
||||
|
||||
void move(Register destination, Register source);
|
||||
void complement(Register destination, Register source);
|
||||
|
@ -158,12 +158,27 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
||||
case CALL:
|
||||
{
|
||||
Call* call = static_cast<Call*>(instruction);
|
||||
mLinkage = new Linkage(mLinkage, ++mPC, begin_pc,
|
||||
mActivation, op1(call));
|
||||
iCode = (*registers)[op2(call)].function->getICode();
|
||||
mActivation = new Activation(iCode, mActivation, op3(call));
|
||||
registers = &mActivation->mRegisters;
|
||||
begin_pc = mPC = iCode->its_iCode->begin();
|
||||
JSFunction *target = (*registers)[op2(call)].function;
|
||||
if (target->isNative()) {
|
||||
RegisterList ¶ms = op3(call);
|
||||
JSValues argv(params.size());
|
||||
int i = 0;
|
||||
for (RegisterList::const_iterator src = params.begin(), end = params.end();
|
||||
src != end; ++src, ++i) {
|
||||
argv[i] = (*registers)[*src];
|
||||
}
|
||||
if (op2(call) != NotARegister)
|
||||
(*registers)[op2(call)] = *static_cast<JSNativeFunction*>(target)->mCode(argv);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
mLinkage = new Linkage(mLinkage, ++mPC, begin_pc,
|
||||
mActivation, op1(call));
|
||||
iCode = target->getICode();
|
||||
mActivation = new Activation(iCode, mActivation, op3(call));
|
||||
registers = &mActivation->mRegisters;
|
||||
begin_pc = mPC = iCode->its_iCode->begin();
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
||||
@ -285,6 +300,12 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
||||
(*registers)[dst(li)] = JSValue(src1(li));
|
||||
}
|
||||
break;
|
||||
case LOAD_STRING:
|
||||
{
|
||||
LoadString* ls = static_cast<LoadString*>(instruction);
|
||||
(*registers)[dst(ls)] = JSValue(src1(ls));
|
||||
}
|
||||
break;
|
||||
case BRANCH:
|
||||
{
|
||||
GenericBranch* bra =
|
||||
@ -355,11 +376,21 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
||||
break;
|
||||
case ADD:
|
||||
{
|
||||
// LEAKING like a sieve here because the toXXX are returning pointers
|
||||
// to possibly new JSValues.
|
||||
|
||||
// could get clever here with Functional forms.
|
||||
Arithmetic* add = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(add)] =
|
||||
JSValue((*registers)[src1(add)].f64 +
|
||||
(*registers)[src2(add)].f64);
|
||||
if ((*registers)[src1(add)].isString()
|
||||
|| (*registers)[src2(add)].isString()) {
|
||||
JSValue *s = (*registers)[src1(add)].toString();
|
||||
*(s->string) += *((*registers)[src2(add)].toString()->string);
|
||||
(*registers)[dst(add)] = *s;
|
||||
}
|
||||
else {
|
||||
(*registers)[dst(add)] = (*registers)[src1(add)].toNumber()->f64
|
||||
+ (*registers)[src2(add)].toNumber()->f64;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SUBTRACT:
|
||||
@ -401,6 +432,18 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
||||
JSValue(int32(diff == 0.0 ? 0 : (diff > 0.0 ? 1 : -1)));
|
||||
}
|
||||
break;
|
||||
case NEGATE:
|
||||
{
|
||||
Negate* neg = static_cast<Negate*>(instruction);
|
||||
(*registers)[dst(neg)] = JSValue(-(*registers)[src1(neg)].toNumber()->f64);
|
||||
}
|
||||
break;
|
||||
case POSATE:
|
||||
{
|
||||
Posate* pos = static_cast<Posate*>(instruction);
|
||||
(*registers)[dst(pos)] = *(*registers)[src1(pos)].toNumber();
|
||||
}
|
||||
break;
|
||||
case NOT:
|
||||
{
|
||||
Not* nt = static_cast<Not*>(instruction);
|
||||
|
@ -37,6 +37,8 @@
|
||||
namespace JavaScript {
|
||||
namespace JSTypes {
|
||||
|
||||
// using JavaScript::StringAtom;
|
||||
|
||||
// the canonical undefined value.
|
||||
const JSValue kUndefinedValue;
|
||||
|
||||
@ -82,5 +84,59 @@ Formatter& operator<<(Formatter& f, const JSValue& value)
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
JSValue *JSValue::valueToString(JSValue *v) // can assume v is not a string
|
||||
{
|
||||
char *chrp;
|
||||
char buf[dtosStandardBufferSize];
|
||||
switch (v->tag) {
|
||||
case JSValue::i32_tag:
|
||||
chrp = doubleToStr(buf, dtosStandardBufferSize, v->i32, dtosStandard, 0);
|
||||
break;
|
||||
case JSValue::f64_tag:
|
||||
chrp = doubleToStr(buf, dtosStandardBufferSize, v->f64, dtosStandard, 0);
|
||||
break;
|
||||
case JSValue::object_tag:
|
||||
chrp = "object";
|
||||
break;
|
||||
case JSValue::array_tag:
|
||||
chrp = "array";
|
||||
break;
|
||||
case JSValue::function_tag:
|
||||
chrp = "function";
|
||||
break;
|
||||
case JSValue::string_tag:
|
||||
return v;
|
||||
default:
|
||||
chrp = "undefined";
|
||||
break;
|
||||
}
|
||||
return new JSValue(new String(widenCString(chrp)));
|
||||
}
|
||||
|
||||
JSValue *JSValue::valueToNumber(JSValue *v)// can assume v is not a number
|
||||
{
|
||||
switch (v->tag) {
|
||||
case JSValue::i32_tag:
|
||||
case JSValue::f64_tag:
|
||||
return v;
|
||||
case JSValue::string_tag:
|
||||
{
|
||||
int length = v->string->length();
|
||||
const char16 *s = v->string->c_str();
|
||||
const char16 *numEnd;
|
||||
double d = stringToDouble(s, s + length, numEnd);
|
||||
return new JSValue(d);
|
||||
}
|
||||
case JSValue::object_tag:
|
||||
case JSValue::array_tag:
|
||||
case JSValue::function_tag:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return new JSValue();
|
||||
}
|
||||
|
||||
|
||||
} /* namespace JSTypes */
|
||||
} /* namespace JavaScript */
|
||||
|
@ -101,8 +101,17 @@ namespace JSTypes {
|
||||
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); }
|
||||
const String*& operator=(String* string) { return (tag = string_tag, this->string = string); }
|
||||
String*& operator=(String* string) { return (tag = string_tag, this->string = string); }
|
||||
|
||||
bool isString() { return (tag == string_tag); }
|
||||
bool isNumber() { return ((tag == f64_tag) || (tag == i32_tag)); }
|
||||
|
||||
JSValue *toString() { if (isString()) return this; else return valueToString(this); }
|
||||
JSValue *toNumber() { if (isNumber()) return this; else return valueToNumber(this); }
|
||||
|
||||
static JSValue *valueToString(JSValue *v);
|
||||
static JSValue *valueToNumber(JSValue *v);
|
||||
|
||||
int operator==(const JSValue& value) const;
|
||||
};
|
||||
|
||||
@ -234,10 +243,22 @@ namespace JSTypes {
|
||||
*/
|
||||
class JSFunction : public JSObject {
|
||||
ICodeModule* mICode;
|
||||
protected:
|
||||
JSFunction() : mICode(0) {}
|
||||
public:
|
||||
virtual bool isNative() { return false; }
|
||||
JSFunction(ICodeModule* iCode) : mICode(iCode) {}
|
||||
ICodeModule* getICode() { return mICode; }
|
||||
};
|
||||
|
||||
typedef JSValue * (*NativeFunction)(const JSValues& argv);
|
||||
|
||||
class JSNativeFunction : public JSFunction {
|
||||
public:
|
||||
NativeFunction mCode;
|
||||
JSNativeFunction(NativeFunction code) : mCode(code) {}
|
||||
virtual bool isNative() { return true; }
|
||||
};
|
||||
|
||||
class JSException : public gc_base {
|
||||
public:
|
||||
@ -288,12 +309,19 @@ namespace JSTypes {
|
||||
return setProperty(name, value);
|
||||
}
|
||||
|
||||
// FIXME: need to copy the ICodeModule's instruction stream.
|
||||
// FIXME: need to copy the ICodeModule's instruction stream.
|
||||
// why? it belongs to the ICodeModule exclusively
|
||||
JSValue& defineFunction(const String& name, ICodeModule* iCode)
|
||||
{
|
||||
JSValue value(new JSFunction(iCode));
|
||||
return defineVariable(name, value);
|
||||
}
|
||||
|
||||
JSValue& defineNativeFunction(const String& name, NativeFunction code)
|
||||
{
|
||||
JSValue value(new JSNativeFunction(code));
|
||||
return defineVariable(name, value);
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace JSTypes */
|
||||
|
@ -256,6 +256,12 @@ namespace ICG {
|
||||
return dest;
|
||||
}
|
||||
|
||||
void ICodeGenerator::callVoid(Register target, RegisterList args)
|
||||
{
|
||||
Call *instr = new Call(NotARegister, target, args);
|
||||
iCode->push_back(instr);
|
||||
}
|
||||
|
||||
void ICodeGenerator::branch(Label *label)
|
||||
{
|
||||
Branch *instr = new Branch(label);
|
||||
|
@ -189,6 +189,7 @@ namespace ICG {
|
||||
Register op(ICodeOp op, Register source);
|
||||
Register op(ICodeOp op, Register source1, Register source2);
|
||||
Register call(Register target, RegisterList args);
|
||||
void callVoid(Register target, RegisterList args);
|
||||
|
||||
void move(Register destination, Register source);
|
||||
void complement(Register destination, Register source);
|
||||
|
@ -158,12 +158,27 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
||||
case CALL:
|
||||
{
|
||||
Call* call = static_cast<Call*>(instruction);
|
||||
mLinkage = new Linkage(mLinkage, ++mPC, begin_pc,
|
||||
mActivation, op1(call));
|
||||
iCode = (*registers)[op2(call)].function->getICode();
|
||||
mActivation = new Activation(iCode, mActivation, op3(call));
|
||||
registers = &mActivation->mRegisters;
|
||||
begin_pc = mPC = iCode->its_iCode->begin();
|
||||
JSFunction *target = (*registers)[op2(call)].function;
|
||||
if (target->isNative()) {
|
||||
RegisterList ¶ms = op3(call);
|
||||
JSValues argv(params.size());
|
||||
int i = 0;
|
||||
for (RegisterList::const_iterator src = params.begin(), end = params.end();
|
||||
src != end; ++src, ++i) {
|
||||
argv[i] = (*registers)[*src];
|
||||
}
|
||||
if (op2(call) != NotARegister)
|
||||
(*registers)[op2(call)] = *static_cast<JSNativeFunction*>(target)->mCode(argv);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
mLinkage = new Linkage(mLinkage, ++mPC, begin_pc,
|
||||
mActivation, op1(call));
|
||||
iCode = target->getICode();
|
||||
mActivation = new Activation(iCode, mActivation, op3(call));
|
||||
registers = &mActivation->mRegisters;
|
||||
begin_pc = mPC = iCode->its_iCode->begin();
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
||||
@ -285,6 +300,12 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
||||
(*registers)[dst(li)] = JSValue(src1(li));
|
||||
}
|
||||
break;
|
||||
case LOAD_STRING:
|
||||
{
|
||||
LoadString* ls = static_cast<LoadString*>(instruction);
|
||||
(*registers)[dst(ls)] = JSValue(src1(ls));
|
||||
}
|
||||
break;
|
||||
case BRANCH:
|
||||
{
|
||||
GenericBranch* bra =
|
||||
@ -355,11 +376,21 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
||||
break;
|
||||
case ADD:
|
||||
{
|
||||
// LEAKING like a sieve here because the toXXX are returning pointers
|
||||
// to possibly new JSValues.
|
||||
|
||||
// could get clever here with Functional forms.
|
||||
Arithmetic* add = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(add)] =
|
||||
JSValue((*registers)[src1(add)].f64 +
|
||||
(*registers)[src2(add)].f64);
|
||||
if ((*registers)[src1(add)].isString()
|
||||
|| (*registers)[src2(add)].isString()) {
|
||||
JSValue *s = (*registers)[src1(add)].toString();
|
||||
*(s->string) += *((*registers)[src2(add)].toString()->string);
|
||||
(*registers)[dst(add)] = *s;
|
||||
}
|
||||
else {
|
||||
(*registers)[dst(add)] = (*registers)[src1(add)].toNumber()->f64
|
||||
+ (*registers)[src2(add)].toNumber()->f64;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SUBTRACT:
|
||||
@ -401,6 +432,18 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
||||
JSValue(int32(diff == 0.0 ? 0 : (diff > 0.0 ? 1 : -1)));
|
||||
}
|
||||
break;
|
||||
case NEGATE:
|
||||
{
|
||||
Negate* neg = static_cast<Negate*>(instruction);
|
||||
(*registers)[dst(neg)] = JSValue(-(*registers)[src1(neg)].toNumber()->f64);
|
||||
}
|
||||
break;
|
||||
case POSATE:
|
||||
{
|
||||
Posate* pos = static_cast<Posate*>(instruction);
|
||||
(*registers)[dst(pos)] = *(*registers)[src1(pos)].toNumber();
|
||||
}
|
||||
break;
|
||||
case NOT:
|
||||
{
|
||||
Not* nt = static_cast<Not*>(instruction);
|
||||
|
@ -37,6 +37,8 @@
|
||||
namespace JavaScript {
|
||||
namespace JSTypes {
|
||||
|
||||
// using JavaScript::StringAtom;
|
||||
|
||||
// the canonical undefined value.
|
||||
const JSValue kUndefinedValue;
|
||||
|
||||
@ -82,5 +84,59 @@ Formatter& operator<<(Formatter& f, const JSValue& value)
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
JSValue *JSValue::valueToString(JSValue *v) // can assume v is not a string
|
||||
{
|
||||
char *chrp;
|
||||
char buf[dtosStandardBufferSize];
|
||||
switch (v->tag) {
|
||||
case JSValue::i32_tag:
|
||||
chrp = doubleToStr(buf, dtosStandardBufferSize, v->i32, dtosStandard, 0);
|
||||
break;
|
||||
case JSValue::f64_tag:
|
||||
chrp = doubleToStr(buf, dtosStandardBufferSize, v->f64, dtosStandard, 0);
|
||||
break;
|
||||
case JSValue::object_tag:
|
||||
chrp = "object";
|
||||
break;
|
||||
case JSValue::array_tag:
|
||||
chrp = "array";
|
||||
break;
|
||||
case JSValue::function_tag:
|
||||
chrp = "function";
|
||||
break;
|
||||
case JSValue::string_tag:
|
||||
return v;
|
||||
default:
|
||||
chrp = "undefined";
|
||||
break;
|
||||
}
|
||||
return new JSValue(new String(widenCString(chrp)));
|
||||
}
|
||||
|
||||
JSValue *JSValue::valueToNumber(JSValue *v)// can assume v is not a number
|
||||
{
|
||||
switch (v->tag) {
|
||||
case JSValue::i32_tag:
|
||||
case JSValue::f64_tag:
|
||||
return v;
|
||||
case JSValue::string_tag:
|
||||
{
|
||||
int length = v->string->length();
|
||||
const char16 *s = v->string->c_str();
|
||||
const char16 *numEnd;
|
||||
double d = stringToDouble(s, s + length, numEnd);
|
||||
return new JSValue(d);
|
||||
}
|
||||
case JSValue::object_tag:
|
||||
case JSValue::array_tag:
|
||||
case JSValue::function_tag:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return new JSValue();
|
||||
}
|
||||
|
||||
|
||||
} /* namespace JSTypes */
|
||||
} /* namespace JavaScript */
|
||||
|
@ -101,8 +101,17 @@ namespace JSTypes {
|
||||
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); }
|
||||
const String*& operator=(String* string) { return (tag = string_tag, this->string = string); }
|
||||
String*& operator=(String* string) { return (tag = string_tag, this->string = string); }
|
||||
|
||||
bool isString() { return (tag == string_tag); }
|
||||
bool isNumber() { return ((tag == f64_tag) || (tag == i32_tag)); }
|
||||
|
||||
JSValue *toString() { if (isString()) return this; else return valueToString(this); }
|
||||
JSValue *toNumber() { if (isNumber()) return this; else return valueToNumber(this); }
|
||||
|
||||
static JSValue *valueToString(JSValue *v);
|
||||
static JSValue *valueToNumber(JSValue *v);
|
||||
|
||||
int operator==(const JSValue& value) const;
|
||||
};
|
||||
|
||||
@ -234,10 +243,22 @@ namespace JSTypes {
|
||||
*/
|
||||
class JSFunction : public JSObject {
|
||||
ICodeModule* mICode;
|
||||
protected:
|
||||
JSFunction() : mICode(0) {}
|
||||
public:
|
||||
virtual bool isNative() { return false; }
|
||||
JSFunction(ICodeModule* iCode) : mICode(iCode) {}
|
||||
ICodeModule* getICode() { return mICode; }
|
||||
};
|
||||
|
||||
typedef JSValue * (*NativeFunction)(const JSValues& argv);
|
||||
|
||||
class JSNativeFunction : public JSFunction {
|
||||
public:
|
||||
NativeFunction mCode;
|
||||
JSNativeFunction(NativeFunction code) : mCode(code) {}
|
||||
virtual bool isNative() { return true; }
|
||||
};
|
||||
|
||||
class JSException : public gc_base {
|
||||
public:
|
||||
@ -288,12 +309,19 @@ namespace JSTypes {
|
||||
return setProperty(name, value);
|
||||
}
|
||||
|
||||
// FIXME: need to copy the ICodeModule's instruction stream.
|
||||
// FIXME: need to copy the ICodeModule's instruction stream.
|
||||
// why? it belongs to the ICodeModule exclusively
|
||||
JSValue& defineFunction(const String& name, ICodeModule* iCode)
|
||||
{
|
||||
JSValue value(new JSFunction(iCode));
|
||||
return defineVariable(name, value);
|
||||
}
|
||||
|
||||
JSValue& defineNativeFunction(const String& name, NativeFunction code)
|
||||
{
|
||||
JSValue value(new JSNativeFunction(code));
|
||||
return defineVariable(name, value);
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace JSTypes */
|
||||
|
Loading…
Reference in New Issue
Block a user