Added more string handling + valueToString/Number code.

NativeFunction support.
This commit is contained in:
rogerl%netscape.com 2000-05-08 22:59:42 +00:00
parent 1639cd5231
commit 261b8ef660
10 changed files with 290 additions and 22 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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 &params = 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);

View File

@ -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 */

View File

@ -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 */

View File

@ -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);

View File

@ -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);

View File

@ -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 &params = 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);

View File

@ -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 */

View File

@ -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 */