From 65a4138aa94d2aa9ee5fe9c4e0ed2400b22b01c7 Mon Sep 17 00:00:00 2001 From: "rogerl%netscape.com" Date: Wed, 26 Jul 2000 01:56:47 +0000 Subject: [PATCH] Function prototype objects etc. git-svn-id: svn://10.0.0.236/trunk@74792 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/js/js2/icodegenerator.cpp | 8 ++- mozilla/js/js2/interpreter.cpp | 13 ++++- mozilla/js/js2/interpreter.h | 1 + mozilla/js/js2/js2.cpp | 1 - mozilla/js/js2/jstypes.cpp | 87 ++++++++++++++++++++++++++++- mozilla/js/js2/jstypes.h | 9 ++- mozilla/js2/src/icodegenerator.cpp | 8 ++- mozilla/js2/src/interpreter.cpp | 13 ++++- mozilla/js2/src/interpreter.h | 1 + mozilla/js2/src/jstypes.cpp | 87 ++++++++++++++++++++++++++++- mozilla/js2/src/jstypes.h | 9 ++- mozilla/js2/tests/cpp/js2_shell.cpp | 1 - 12 files changed, 220 insertions(+), 18 deletions(-) diff --git a/mozilla/js/js2/icodegenerator.cpp b/mozilla/js/js2/icodegenerator.cpp index d27593feb7e..b6c86df0588 100644 --- a/mozilla/js/js2/icodegenerator.cpp +++ b/mozilla/js/js2/icodegenerator.cpp @@ -1100,7 +1100,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, JSClass* clazz = dynamic_cast(value.type); if (clazz) { ret = newClass(clazz); - call(getStatic(clazz, className), ret, &args); + ret = call(getStatic(clazz, className), ret, &args); } else NOT_REACHED("new , where is not a new-able type (whatever that means)"); // XXX Runtime error. @@ -1109,7 +1109,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, if (value.isFunction()) { TypedRegister f = loadName(className, value.type); ret = newObject(f); - call(f, ret, &args); + ret = call(f, ret, &args); } else NOT_REACHED("new , where is not a function"); // XXX Runtime error. @@ -1695,7 +1695,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) else thisClass->defineMethod(name, new JSFunction(icm)); } - } + } break; default: NOT_REACHED("unimplemented class member statement"); @@ -1712,9 +1712,11 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) TypedRegister thisValue = TypedRegister(0, thisClass); RegisterList args; ICodeGenerator icg(mWorld, thisScope, thisClass, kIsStaticMethod); + icg.allocateParameter(mWorld->identifiers["this"], thisClass); // always parameter #0 if (superclass) icg.call(icg.getStatic(superclass, superclass->getName()), thisValue, &args); icg.call(icg.getStatic(thisClass, initName), thisValue, &args); + icg.returnStmt(thisValue); thisClass->defineConstructor(nameExpr->name); scg.setStatic(thisClass, nameExpr->name, scg.newFunction(icg.complete())); } diff --git a/mozilla/js/js2/interpreter.cpp b/mozilla/js/js2/interpreter.cpp index e1e2313bcd2..4a1629da962 100644 --- a/mozilla/js/js2/interpreter.cpp +++ b/mozilla/js/js2/interpreter.cpp @@ -129,6 +129,15 @@ public: ~autosaver() { mRef = mOld; } }; +ICodeModule* Context::compile(const String &source) +{ + Arena a; + String filename = widenCString("Some source source"); + Parser p(getWorld(), a, source, filename); + StmtNode *parsedStatements = p.parseProgram(); + return genCode(parsedStatements, filename); +} + JSValue Context::readEvalFile(FILE* in, const String& fileName) { String buffer; @@ -162,7 +171,7 @@ JSValue Context::readEvalFile(FILE* in, const String& fileName) } stdOut << '\n'; - // Generate code for parsedStatements, which is a linked + // Generate code for parsedStatements, which is a linked // list of zero or more statements ICodeModule* icm = genCode(parsedStatements, fileName); if (icm) { @@ -508,6 +517,7 @@ void Context::initContext() // 'Object', 'Date', 'RegExp', 'Array' etc are all (constructor) properties of the global object JSObject::initObjectObject(mGlobal); + JSFunction::initFunctionObject(mGlobal); // the 'Math' object just has some useful properties JSMath::initMathObject(mGlobal); @@ -715,7 +725,6 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) case NEW_OBJECT: { NewObject* no = static_cast(instruction); - JSObject *obj = new JSObject(); if (src1(no).first != NotARegister) (*registers)[dst(no).first] = new JSObject((*registers)[src1(no).first]); else diff --git a/mozilla/js/js2/interpreter.h b/mozilla/js/js2/interpreter.h index 09b904fc8b5..0acf8320867 100644 --- a/mozilla/js/js2/interpreter.h +++ b/mozilla/js/js2/interpreter.h @@ -77,6 +77,7 @@ namespace Interpreter { JSValue interpret(ICodeModule* iCode, const JSValues& args); void doCall(JSFunction *target, Instruction *pc); + ICodeModule* compile(const String &source); ICodeModule* genCode(StmtNode *p, const String &fileName); JSValue readEvalFile(FILE* in, const String& fileName); diff --git a/mozilla/js/js2/js2.cpp b/mozilla/js/js2/js2.cpp index 1f4e0988ed5..dfe62f20907 100644 --- a/mozilla/js/js2/js2.cpp +++ b/mozilla/js/js2/js2.cpp @@ -303,7 +303,6 @@ static void testCompile() JSScope glob; Context cx(world, &glob); glob.defineNativeFunction(world.identifiers["print"], print); - for (uint i = 0; i < sizeof(tests) / sizeof(char *); i++) { String testScript = widenCString(tests[i]); Arena a; diff --git a/mozilla/js/js2/jstypes.cpp b/mozilla/js/js2/jstypes.cpp index 18000a3f468..3f54f657fff 100644 --- a/mozilla/js/js2/jstypes.cpp +++ b/mozilla/js/js2/jstypes.cpp @@ -35,12 +35,15 @@ #include "jsclasses.h" #include "numerics.h" #include "icodegenerator.h" +#include "interpreter.h" namespace JavaScript { namespace JSTypes { using namespace JSClasses; +using namespace Interpreter; +/********** Object Object Stuff **************************/ JSValue object_toString(Context *cx, const JSValues& argv) { @@ -93,14 +96,94 @@ JSObject *JSObject::initJSObject() // a new JSObject does all the work of setting the prototype and [[class]] values. void JSObject::initObjectObject(JSScope *g) { - JSObject* o = new JSObject(); + JSNativeFunction *objCon = new JSNativeFunction(objectConstructor); - g->setProperty(ObjectString, JSValue(new JSNativeFunction(objectConstructor))); + objCon->setProperty(widenCString("prototype"), JSValue(objectPrototypeObject)); + + + + g->setProperty(ObjectString, JSValue(objCon)); } +/********** Function Object Stuff **************************/ + +// An empty function that returns undefined +JSValue functionPrototypeFunction(Context *cx, const JSValues& argv) +{ + return kUndefinedValue; +} + + +JSValue function_constructor(Context *cx, const JSValues& argv) +{ + // build a function from the arguments into the this. + ASSERT(argv.size() > 0); + JSValue theThis = argv[0]; + ASSERT(theThis.isObject()); + + if (argv.size() == 2) { + JSValue s = JSValue::valueToString(argv[1]); + theThis = new JSFunction(cx->compile((String)(*s.string))); + } + + return theThis; +} + +JSValue function_toString(Context *cx, const JSValues& argv) +{ + return JSValue(new JSString("function XXX() { }" )); +} +JSValue function_apply(Context *cx, const JSValues& argv) +{ + // XXX + return kUndefinedValue; +} +JSValue function_call(Context *cx, const JSValues& argv) +{ + // XXX + return kUndefinedValue; +} + + + +String JSFunction::FunctionString = widenCString("Function"); +JSObject *JSFunction::functionPrototypeObject = NULL; // the 'original Function prototype object' + +struct FunctionFunctionEntry { + char *name; + JSNativeFunction::JSCode fn; +} FunctionFunctions[] = { + { "constructor", function_constructor }, + { "toString", function_toString }, + { "apply", function_apply }, + { "call", function_call }, +}; + +void JSFunction::initFunctionObject(JSScope *g) +{ + // first build the Function Prototype Object + functionPrototypeObject = new JSNativeFunction(functionPrototypeFunction); + for (int i = 0; i < sizeof(FunctionFunctions) / sizeof(FunctionFunctionEntry); i++) + functionPrototypeObject->setProperty(widenCString(FunctionFunctions[i].name), JSValue(new JSNativeFunction(FunctionFunctions[i].fn) ) ); + + // now the Function Constructor Object + JSNativeFunction *functionConstructorObject = new JSNativeFunction(function_constructor); + functionConstructorObject->setPrototype(functionPrototypeObject); + functionConstructorObject->setProperty(widenCString("length"), JSValue((int32)1)); + functionConstructorObject->setProperty(widenCString("prototype"), JSValue(functionPrototypeObject)); + + // This is interesting - had to use defineVariable here to specify a type because + // when left as Any_Type (via setProperty), the Function predefined type interacted + // badly with this value. (I think setProperty perhaps should have reset the entry + // in mTypes) (?) + g->defineVariable(FunctionString, &Function_Type, JSValue(functionConstructorObject)); +} + +/**************************************************************************************/ + JSType Any_Type = JSType(widenCString("any"), NULL); JSType Integer_Type = JSType(widenCString("Integer"), &Any_Type); JSType Number_Type = JSType(widenCString("Number"), &Integer_Type); diff --git a/mozilla/js/js2/jstypes.h b/mozilla/js/js2/jstypes.h index 04e88415bb8..b398aab7833 100644 --- a/mozilla/js/js2/jstypes.h +++ b/mozilla/js/js2/jstypes.h @@ -234,6 +234,7 @@ namespace JSTypes { public: JSObject() { init(objectPrototypeObject); } JSObject(JSValue &constructor) { init(constructor.object->getProperty(widenCString("prototype")).object); } + JSObject(JSObject *prototype) { init(prototype); } static void initObjectObject(JSScope *g); @@ -367,6 +368,8 @@ namespace JSTypes { * compiled code of the function. */ class JSFunction : public JSObject { + static String FunctionString; + static JSObject *functionPrototypeObject; ICodeModule* mICode; protected: JSFunction() : mICode(0) {} @@ -375,7 +378,9 @@ namespace JSTypes { typedef gc_allocator allocator; public: - JSFunction(ICodeModule* iCode) : mICode(iCode) {} + static void JSFunction::initFunctionObject(JSScope *g); + + JSFunction(ICodeModule* iCode); ~JSFunction(); void* operator new(size_t) { return allocator::allocate(1); } @@ -558,6 +563,8 @@ namespace JSTypes { inline void JSObject::init(JSObject* prototype) { mPrototype = prototype; mType = &Any_Type; mClass = new JSString(ObjectString); } + + inline JSFunction::JSFunction(ICodeModule* iCode) : mICode(iCode), JSObject(functionPrototypeObject) { setClass(new JSString(FunctionString)); } } /* namespace JSTypes */ diff --git a/mozilla/js2/src/icodegenerator.cpp b/mozilla/js2/src/icodegenerator.cpp index d27593feb7e..b6c86df0588 100644 --- a/mozilla/js2/src/icodegenerator.cpp +++ b/mozilla/js2/src/icodegenerator.cpp @@ -1100,7 +1100,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, JSClass* clazz = dynamic_cast(value.type); if (clazz) { ret = newClass(clazz); - call(getStatic(clazz, className), ret, &args); + ret = call(getStatic(clazz, className), ret, &args); } else NOT_REACHED("new , where is not a new-able type (whatever that means)"); // XXX Runtime error. @@ -1109,7 +1109,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, if (value.isFunction()) { TypedRegister f = loadName(className, value.type); ret = newObject(f); - call(f, ret, &args); + ret = call(f, ret, &args); } else NOT_REACHED("new , where is not a function"); // XXX Runtime error. @@ -1695,7 +1695,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) else thisClass->defineMethod(name, new JSFunction(icm)); } - } + } break; default: NOT_REACHED("unimplemented class member statement"); @@ -1712,9 +1712,11 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) TypedRegister thisValue = TypedRegister(0, thisClass); RegisterList args; ICodeGenerator icg(mWorld, thisScope, thisClass, kIsStaticMethod); + icg.allocateParameter(mWorld->identifiers["this"], thisClass); // always parameter #0 if (superclass) icg.call(icg.getStatic(superclass, superclass->getName()), thisValue, &args); icg.call(icg.getStatic(thisClass, initName), thisValue, &args); + icg.returnStmt(thisValue); thisClass->defineConstructor(nameExpr->name); scg.setStatic(thisClass, nameExpr->name, scg.newFunction(icg.complete())); } diff --git a/mozilla/js2/src/interpreter.cpp b/mozilla/js2/src/interpreter.cpp index e1e2313bcd2..4a1629da962 100644 --- a/mozilla/js2/src/interpreter.cpp +++ b/mozilla/js2/src/interpreter.cpp @@ -129,6 +129,15 @@ public: ~autosaver() { mRef = mOld; } }; +ICodeModule* Context::compile(const String &source) +{ + Arena a; + String filename = widenCString("Some source source"); + Parser p(getWorld(), a, source, filename); + StmtNode *parsedStatements = p.parseProgram(); + return genCode(parsedStatements, filename); +} + JSValue Context::readEvalFile(FILE* in, const String& fileName) { String buffer; @@ -162,7 +171,7 @@ JSValue Context::readEvalFile(FILE* in, const String& fileName) } stdOut << '\n'; - // Generate code for parsedStatements, which is a linked + // Generate code for parsedStatements, which is a linked // list of zero or more statements ICodeModule* icm = genCode(parsedStatements, fileName); if (icm) { @@ -508,6 +517,7 @@ void Context::initContext() // 'Object', 'Date', 'RegExp', 'Array' etc are all (constructor) properties of the global object JSObject::initObjectObject(mGlobal); + JSFunction::initFunctionObject(mGlobal); // the 'Math' object just has some useful properties JSMath::initMathObject(mGlobal); @@ -715,7 +725,6 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) case NEW_OBJECT: { NewObject* no = static_cast(instruction); - JSObject *obj = new JSObject(); if (src1(no).first != NotARegister) (*registers)[dst(no).first] = new JSObject((*registers)[src1(no).first]); else diff --git a/mozilla/js2/src/interpreter.h b/mozilla/js2/src/interpreter.h index 09b904fc8b5..0acf8320867 100644 --- a/mozilla/js2/src/interpreter.h +++ b/mozilla/js2/src/interpreter.h @@ -77,6 +77,7 @@ namespace Interpreter { JSValue interpret(ICodeModule* iCode, const JSValues& args); void doCall(JSFunction *target, Instruction *pc); + ICodeModule* compile(const String &source); ICodeModule* genCode(StmtNode *p, const String &fileName); JSValue readEvalFile(FILE* in, const String& fileName); diff --git a/mozilla/js2/src/jstypes.cpp b/mozilla/js2/src/jstypes.cpp index 18000a3f468..3f54f657fff 100644 --- a/mozilla/js2/src/jstypes.cpp +++ b/mozilla/js2/src/jstypes.cpp @@ -35,12 +35,15 @@ #include "jsclasses.h" #include "numerics.h" #include "icodegenerator.h" +#include "interpreter.h" namespace JavaScript { namespace JSTypes { using namespace JSClasses; +using namespace Interpreter; +/********** Object Object Stuff **************************/ JSValue object_toString(Context *cx, const JSValues& argv) { @@ -93,14 +96,94 @@ JSObject *JSObject::initJSObject() // a new JSObject does all the work of setting the prototype and [[class]] values. void JSObject::initObjectObject(JSScope *g) { - JSObject* o = new JSObject(); + JSNativeFunction *objCon = new JSNativeFunction(objectConstructor); - g->setProperty(ObjectString, JSValue(new JSNativeFunction(objectConstructor))); + objCon->setProperty(widenCString("prototype"), JSValue(objectPrototypeObject)); + + + + g->setProperty(ObjectString, JSValue(objCon)); } +/********** Function Object Stuff **************************/ + +// An empty function that returns undefined +JSValue functionPrototypeFunction(Context *cx, const JSValues& argv) +{ + return kUndefinedValue; +} + + +JSValue function_constructor(Context *cx, const JSValues& argv) +{ + // build a function from the arguments into the this. + ASSERT(argv.size() > 0); + JSValue theThis = argv[0]; + ASSERT(theThis.isObject()); + + if (argv.size() == 2) { + JSValue s = JSValue::valueToString(argv[1]); + theThis = new JSFunction(cx->compile((String)(*s.string))); + } + + return theThis; +} + +JSValue function_toString(Context *cx, const JSValues& argv) +{ + return JSValue(new JSString("function XXX() { }" )); +} +JSValue function_apply(Context *cx, const JSValues& argv) +{ + // XXX + return kUndefinedValue; +} +JSValue function_call(Context *cx, const JSValues& argv) +{ + // XXX + return kUndefinedValue; +} + + + +String JSFunction::FunctionString = widenCString("Function"); +JSObject *JSFunction::functionPrototypeObject = NULL; // the 'original Function prototype object' + +struct FunctionFunctionEntry { + char *name; + JSNativeFunction::JSCode fn; +} FunctionFunctions[] = { + { "constructor", function_constructor }, + { "toString", function_toString }, + { "apply", function_apply }, + { "call", function_call }, +}; + +void JSFunction::initFunctionObject(JSScope *g) +{ + // first build the Function Prototype Object + functionPrototypeObject = new JSNativeFunction(functionPrototypeFunction); + for (int i = 0; i < sizeof(FunctionFunctions) / sizeof(FunctionFunctionEntry); i++) + functionPrototypeObject->setProperty(widenCString(FunctionFunctions[i].name), JSValue(new JSNativeFunction(FunctionFunctions[i].fn) ) ); + + // now the Function Constructor Object + JSNativeFunction *functionConstructorObject = new JSNativeFunction(function_constructor); + functionConstructorObject->setPrototype(functionPrototypeObject); + functionConstructorObject->setProperty(widenCString("length"), JSValue((int32)1)); + functionConstructorObject->setProperty(widenCString("prototype"), JSValue(functionPrototypeObject)); + + // This is interesting - had to use defineVariable here to specify a type because + // when left as Any_Type (via setProperty), the Function predefined type interacted + // badly with this value. (I think setProperty perhaps should have reset the entry + // in mTypes) (?) + g->defineVariable(FunctionString, &Function_Type, JSValue(functionConstructorObject)); +} + +/**************************************************************************************/ + JSType Any_Type = JSType(widenCString("any"), NULL); JSType Integer_Type = JSType(widenCString("Integer"), &Any_Type); JSType Number_Type = JSType(widenCString("Number"), &Integer_Type); diff --git a/mozilla/js2/src/jstypes.h b/mozilla/js2/src/jstypes.h index 04e88415bb8..b398aab7833 100644 --- a/mozilla/js2/src/jstypes.h +++ b/mozilla/js2/src/jstypes.h @@ -234,6 +234,7 @@ namespace JSTypes { public: JSObject() { init(objectPrototypeObject); } JSObject(JSValue &constructor) { init(constructor.object->getProperty(widenCString("prototype")).object); } + JSObject(JSObject *prototype) { init(prototype); } static void initObjectObject(JSScope *g); @@ -367,6 +368,8 @@ namespace JSTypes { * compiled code of the function. */ class JSFunction : public JSObject { + static String FunctionString; + static JSObject *functionPrototypeObject; ICodeModule* mICode; protected: JSFunction() : mICode(0) {} @@ -375,7 +378,9 @@ namespace JSTypes { typedef gc_allocator allocator; public: - JSFunction(ICodeModule* iCode) : mICode(iCode) {} + static void JSFunction::initFunctionObject(JSScope *g); + + JSFunction(ICodeModule* iCode); ~JSFunction(); void* operator new(size_t) { return allocator::allocate(1); } @@ -558,6 +563,8 @@ namespace JSTypes { inline void JSObject::init(JSObject* prototype) { mPrototype = prototype; mType = &Any_Type; mClass = new JSString(ObjectString); } + + inline JSFunction::JSFunction(ICodeModule* iCode) : mICode(iCode), JSObject(functionPrototypeObject) { setClass(new JSString(FunctionString)); } } /* namespace JSTypes */ diff --git a/mozilla/js2/tests/cpp/js2_shell.cpp b/mozilla/js2/tests/cpp/js2_shell.cpp index 1f4e0988ed5..dfe62f20907 100644 --- a/mozilla/js2/tests/cpp/js2_shell.cpp +++ b/mozilla/js2/tests/cpp/js2_shell.cpp @@ -303,7 +303,6 @@ static void testCompile() JSScope glob; Context cx(world, &glob); glob.defineNativeFunction(world.identifiers["print"], print); - for (uint i = 0; i < sizeof(tests) / sizeof(char *); i++) { String testScript = widenCString(tests[i]); Arena a;