From 8ba0e32346c271132850ebfa9dfb1f2d2e940494 Mon Sep 17 00:00:00 2001 From: "rogerl%netscape.com" Date: Mon, 8 May 2000 22:59:42 +0000 Subject: [PATCH] Added more string handling + valueToString/Number code. NativeFunction support. git-svn-id: svn://10.0.0.236/trunk@68732 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/js/js2/icodegenerator.cpp | 6 +++ mozilla/js/js2/icodegenerator.h | 1 + mozilla/js/js2/interpreter.cpp | 61 +++++++++++++++++++++++++----- mozilla/js/js2/jstypes.cpp | 56 +++++++++++++++++++++++++++ mozilla/js/js2/jstypes.h | 32 +++++++++++++++- mozilla/js2/src/icodegenerator.cpp | 6 +++ mozilla/js2/src/icodegenerator.h | 1 + mozilla/js2/src/interpreter.cpp | 61 +++++++++++++++++++++++++----- mozilla/js2/src/jstypes.cpp | 56 +++++++++++++++++++++++++++ mozilla/js2/src/jstypes.h | 32 +++++++++++++++- 10 files changed, 290 insertions(+), 22 deletions(-) diff --git a/mozilla/js/js2/icodegenerator.cpp b/mozilla/js/js2/icodegenerator.cpp index 4325950af37..a3dc800fd1a 100644 --- a/mozilla/js/js2/icodegenerator.cpp +++ b/mozilla/js/js2/icodegenerator.cpp @@ -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); diff --git a/mozilla/js/js2/icodegenerator.h b/mozilla/js/js2/icodegenerator.h index e571b3aa790..97d0c6b034a 100644 --- a/mozilla/js/js2/icodegenerator.h +++ b/mozilla/js/js2/icodegenerator.h @@ -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); diff --git a/mozilla/js/js2/interpreter.cpp b/mozilla/js/js2/interpreter.cpp index b0b2d8d1508..fbdf4b517c8 100644 --- a/mozilla/js/js2/interpreter.cpp +++ b/mozilla/js/js2/interpreter.cpp @@ -158,12 +158,27 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) case CALL: { Call* call = static_cast(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(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(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(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(instruction); + (*registers)[dst(neg)] = JSValue(-(*registers)[src1(neg)].toNumber()->f64); + } + break; + case POSATE: + { + Posate* pos = static_cast(instruction); + (*registers)[dst(pos)] = *(*registers)[src1(pos)].toNumber(); + } + break; case NOT: { Not* nt = static_cast(instruction); diff --git a/mozilla/js/js2/jstypes.cpp b/mozilla/js/js2/jstypes.cpp index 85bf483072f..e0e6e00e7b9 100644 --- a/mozilla/js/js2/jstypes.cpp +++ b/mozilla/js/js2/jstypes.cpp @@ -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 */ diff --git a/mozilla/js/js2/jstypes.h b/mozilla/js/js2/jstypes.h index c96229044c6..0f5367a6ac7 100644 --- a/mozilla/js/js2/jstypes.h +++ b/mozilla/js/js2/jstypes.h @@ -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 */ diff --git a/mozilla/js2/src/icodegenerator.cpp b/mozilla/js2/src/icodegenerator.cpp index 4325950af37..a3dc800fd1a 100644 --- a/mozilla/js2/src/icodegenerator.cpp +++ b/mozilla/js2/src/icodegenerator.cpp @@ -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); diff --git a/mozilla/js2/src/icodegenerator.h b/mozilla/js2/src/icodegenerator.h index e571b3aa790..97d0c6b034a 100644 --- a/mozilla/js2/src/icodegenerator.h +++ b/mozilla/js2/src/icodegenerator.h @@ -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); diff --git a/mozilla/js2/src/interpreter.cpp b/mozilla/js2/src/interpreter.cpp index b0b2d8d1508..fbdf4b517c8 100644 --- a/mozilla/js2/src/interpreter.cpp +++ b/mozilla/js2/src/interpreter.cpp @@ -158,12 +158,27 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) case CALL: { Call* call = static_cast(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(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(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(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(instruction); + (*registers)[dst(neg)] = JSValue(-(*registers)[src1(neg)].toNumber()->f64); + } + break; + case POSATE: + { + Posate* pos = static_cast(instruction); + (*registers)[dst(pos)] = *(*registers)[src1(pos)].toNumber(); + } + break; case NOT: { Not* nt = static_cast(instruction); diff --git a/mozilla/js2/src/jstypes.cpp b/mozilla/js2/src/jstypes.cpp index 85bf483072f..e0e6e00e7b9 100644 --- a/mozilla/js2/src/jstypes.cpp +++ b/mozilla/js2/src/jstypes.cpp @@ -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 */ diff --git a/mozilla/js2/src/jstypes.h b/mozilla/js2/src/jstypes.h index c96229044c6..0f5367a6ac7 100644 --- a/mozilla/js2/src/jstypes.h +++ b/mozilla/js2/src/jstypes.h @@ -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 */