diff --git a/js/js2/icode.h b/js/js2/icode.h index a0a98afbca11..69b0169e5162 100644 --- a/js/js2/icode.h +++ b/js/js2/icode.h @@ -41,7 +41,7 @@ NEW_ARRAY, /* dest */ NEW_CLASS, /* dest, class */ NEW_FUNCTION, /* dest, ICodeModule */ - NEW_OBJECT, /* dest */ + NEW_OBJECT, /* dest, constructor */ NOP, /* do nothing and like it */ NOT, /* dest, source */ OR, /* dest, source1, source2 */ @@ -582,18 +582,18 @@ } }; - class NewObject : public Instruction_1 { + class NewObject : public Instruction_2 { public: - /* dest */ - NewObject (TypedRegister aOp1) : - Instruction_1 - (NEW_OBJECT, aOp1) {}; + /* dest, constructor */ + NewObject (TypedRegister aOp1, TypedRegister aOp2) : + Instruction_2 + (NEW_OBJECT, aOp1, aOp2) {}; virtual Formatter& print(Formatter& f) { - f << opcodeNames[NEW_OBJECT] << "\t" << mOp1; + f << opcodeNames[NEW_OBJECT] << "\t" << mOp1 << ", " << mOp2; return f; } virtual Formatter& printOperands(Formatter& f, const JSValues& registers) { - f << mOp1.first; + f << mOp1.first << ", " << mOp2.first; return f; } }; diff --git a/js/js2/icodegenerator.cpp b/js/js2/icodegenerator.cpp index 46835ac5392a..d27593feb7e8 100644 --- a/js/js2/icodegenerator.cpp +++ b/js/js2/icodegenerator.cpp @@ -211,10 +211,10 @@ TypedRegister ICodeGenerator::loadBoolean(bool value) return dest; } -TypedRegister ICodeGenerator::newObject(RegisterList * /*args*/) +TypedRegister ICodeGenerator::newObject(TypedRegister constructor) { TypedRegister dest(getTempRegister(), &Any_Type); - NewObject *instr = new NewObject(dest); + NewObject *instr = new NewObject(dest, constructor); iCode->push_back(instr); return dest; } @@ -1103,11 +1103,19 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, call(getStatic(clazz, className), ret, &args); } else - NOT_REACHED("New , where is not a known class"); // XXX Runtime error. + NOT_REACHED("new , where is not a new-able type (whatever that means)"); // XXX Runtime error. } + else + if (value.isFunction()) { + TypedRegister f = loadName(className, value.type); + ret = newObject(f); + call(f, ret, &args); + } + else + NOT_REACHED("new , where is not a function"); // XXX Runtime error. } else - ret = newObject(&args); // XXX more ? + ret = newObject(TypedRegister(NotARegister, &Any_Type)); // XXX more ? } break; case ExprNode::Delete: @@ -1449,7 +1457,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, case ExprNode::objectLiteral: { - ret = newObject(NULL); + ret = newObject(TypedRegister(NotARegister, &Any_Type)); PairListExprNode *plen = static_cast(p); ExprPairList *e = plen->pairs; while (e) { diff --git a/js/js2/icodegenerator.h b/js/js2/icodegenerator.h index 51ab22fca500..12abffaf8df7 100644 --- a/js/js2/icodegenerator.h +++ b/js/js2/icodegenerator.h @@ -254,7 +254,7 @@ namespace ICG { TypedRegister loadString(const String &value); TypedRegister loadString(const StringAtom &name); - TypedRegister newObject(RegisterList *args); + TypedRegister newObject(TypedRegister constructor); TypedRegister newArray(); TypedRegister newFunction(ICodeModule *icm); TypedRegister newClass(JSClass *clazz); diff --git a/js/js2/interpreter.cpp b/js/js2/interpreter.cpp index 5c3ba00af135..e1e2313bcd26 100644 --- a/js/js2/interpreter.cpp +++ b/js/js2/interpreter.cpp @@ -500,13 +500,17 @@ void Context::initContext() // set up the correct [[Class]] for the global object (matching SpiderMonkey) mGlobal->setClass(new JSString("global")); + // add (XXX some) of the global object properties mGlobal->setProperty(widenCString("NaN"), kNaNValue); mGlobal->setProperty(widenCString("undefined"), kUndefinedValue); + // 'Object', 'Date', 'RegExp', 'Array' etc are all (constructor) properties of the global object - - mGlobal->setProperty(widenCString("Math"), JSValue(new JSMath())); + JSObject::initObjectObject(mGlobal); + + // the 'Math' object just has some useful properties + JSMath::initMathObject(mGlobal); // This initializes the state of the binary operator overload mechanism. @@ -712,7 +716,10 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) { NewObject* no = static_cast(instruction); JSObject *obj = new JSObject(); - (*registers)[dst(no).first] = new JSObject(); + if (src1(no).first != NotARegister) + (*registers)[dst(no).first] = new JSObject((*registers)[src1(no).first]); + else + (*registers)[dst(no).first] = new JSObject(); } break; case NEW_CLASS: diff --git a/js/js2/js2.cpp b/js/js2/js2.cpp index 7162d3bcd279..1f4e0988ed5f 100644 --- a/js/js2/js2.cpp +++ b/js/js2/js2.cpp @@ -235,6 +235,7 @@ static void readEvalPrint(FILE *in, World &world) // list of zero or more statements ICodeModule* icm = cx.genCode(parsedStatements, ConsoleName); if (icm) { +stdOut << *icm; JSValue result = cx.interpret(icm, JSValues()); stdOut << "result = " << result << "\n"; delete icm; diff --git a/js/js2/jsmath.cpp b/js/js2/jsmath.cpp index 1514481bf875..dd31f362dcb4 100644 --- a/js/js2/jsmath.cpp +++ b/js/js2/jsmath.cpp @@ -186,18 +186,23 @@ struct MathConstantEntry { { "SQRT1_2", M_SQRT1_2 } }; -JSMath::JSMath() -{ - setClass(new JSString("Math")); +// There is no constructor for Math, we simply initialize +// the properties of the Math object +void JSMath::initMathObject(JSScope *g) +{ + int i; + JSMath *m = new JSMath(); + m->setClass(new JSString("Math")); - for (int i = 0; i < sizeof(MathFunctions) / sizeof(MathFunctionEntry); i++) - setProperty(widenCString(MathFunctions[i].name), JSValue(new JSNativeFunction(MathFunctions[i].fn) ) ); + for (i = 0; i < sizeof(MathFunctions) / sizeof(MathFunctionEntry); i++) + m->setProperty(widenCString(MathFunctions[i].name), JSValue(new JSNativeFunction(MathFunctions[i].fn) ) ); - for (int i = 0; i < sizeof(MathConstants) / sizeof(MathConstantEntry); i++) - setProperty(widenCString(MathConstants[i].name), JSValue(MathConstants[i].value) ); + for (i = 0; i < sizeof(MathConstants) / sizeof(MathConstantEntry); i++) + m->setProperty(widenCString(MathConstants[i].name), JSValue(MathConstants[i].value) ); + g->setProperty(widenCString("Math"), JSValue(m)); + } - } /* JSMathClass */ } /* JavaScript */ diff --git a/js/js2/jsmath.h b/js/js2/jsmath.h index 605227ebe59e..0e32d2305718 100644 --- a/js/js2/jsmath.h +++ b/js/js2/jsmath.h @@ -41,11 +41,13 @@ namespace JSMathClass { using JSTypes::JSObject; using JSTypes::JSString; + using JSTypes::JSScope; class JSMath : public JSObject { + private: + JSMath() { } public: - JSMath(); - + static void initMathObject(JSScope *g); }; diff --git a/js/js2/jstypes.cpp b/js/js2/jstypes.cpp index 1cf1f5335b75..18000a3f4686 100644 --- a/js/js2/jstypes.cpp +++ b/js/js2/jstypes.cpp @@ -55,17 +55,49 @@ JSValue object_toString(Context *cx, const JSValues& argv) return kUndefinedValue; } +JSValue objectConstructor(Context *cx, const JSValues& argv) +{ + ASSERT(argv.size() > 0); + JSValue theThis = argv[0]; + + // the prototype and class have been established already + + return theThis; +} + +struct ObjectFunctionEntry { + char *name; + JSNativeFunction::JSCode fn; +} ObjectFunctions[] = { + { "toString", object_toString }, +}; + JSObject *JSObject::objectPrototypeObject = JSObject::initJSObject(); -JSString *JSObject::ObjectString = new JSString("Object"); +String JSObject::ObjectString = widenCString("Object"); +// This establishes the ur-prototype, there's a timing issue +// here - the JSObject static initializers have to run before +// any other JSObject objects are constructed. JSObject *JSObject::initJSObject() { JSObject *result = new JSObject(); - result->setProperty(widenCString("toString"), JSValue(new JSNativeFunction(object_toString) ) ); + + for (int i = 0; i < sizeof(ObjectFunctions) / sizeof(ObjectFunctionEntry); i++) + result->setProperty(widenCString(ObjectFunctions[i].name), JSValue(new JSNativeFunction(ObjectFunctions[i].fn) ) ); + return result; } +// Install the 'Object' constructor into the scope, mostly irrelevant since making +// a new JSObject does all the work of setting the prototype and [[class]] values. +void JSObject::initObjectObject(JSScope *g) +{ + JSObject* o = new JSObject(); + + g->setProperty(ObjectString, JSValue(new JSNativeFunction(objectConstructor))); + +} diff --git a/js/js2/jstypes.h b/js/js2/jstypes.h index 01d8f68b177d..04e88415bb86 100644 --- a/js/js2/jstypes.h +++ b/js/js2/jstypes.h @@ -60,6 +60,7 @@ namespace JSTypes { class JSObject; class JSArray; class JSFunction; + class JSScope; class JSString; class JSType; class Context; @@ -224,12 +225,17 @@ namespace JSTypes { JSType* mType; JSString* mClass; // this is the internal [[Class]] property - public: - JSObject() : mPrototype(objectPrototypeObject), mType(&Any_Type), mClass(ObjectString) {} - - static JSObject *objectPrototypeObject; static JSObject *initJSObject(); - static JSString *ObjectString; + static String ObjectString; + static JSObject *objectPrototypeObject; + + void init(JSObject* prototype); + + public: + JSObject() { init(objectPrototypeObject); } + JSObject(JSValue &constructor) { init(constructor.object->getProperty(widenCString("prototype")).object); } + + static void initObjectObject(JSScope *g); bool hasProperty(const String& name) { @@ -551,6 +557,9 @@ namespace JSTypes { }; + inline void JSObject::init(JSObject* prototype) { mPrototype = prototype; mType = &Any_Type; mClass = new JSString(ObjectString); } + + } /* namespace JSTypes */ } /* namespace JavaScript */ diff --git a/js/js2/tools/gencode.pl b/js/js2/tools/gencode.pl index 1c7ba2d7fbaf..52bea9ec8819 100644 --- a/js/js2/tools/gencode.pl +++ b/js/js2/tools/gencode.pl @@ -128,9 +128,9 @@ $ops{"SAVE_NAME"} = }; $ops{"NEW_OBJECT"} = { - super => "Instruction_1", - rem => "dest", - params => [ ("TypedRegister") ] + super => "Instruction_2", + rem => "dest, constructor", + params => [ ("TypedRegister", "TypedRegister") ] }; $ops{"NEW_CLASS"} = { diff --git a/js/js2/winbuild/js2.dsp b/js/js2/winbuild/js2.dsp index 31b00713674b..28007a7d9a6b 100644 --- a/js/js2/winbuild/js2.dsp +++ b/js/js2/winbuild/js2.dsp @@ -195,6 +195,10 @@ SOURCE=..\jsclasses.h # End Source File # Begin Source File +SOURCE=..\jsmath.h +# End Source File +# Begin Source File + SOURCE=..\jstypes.h # End Source File # Begin Source File diff --git a/js2/src/icode.h b/js2/src/icode.h index a0a98afbca11..69b0169e5162 100644 --- a/js2/src/icode.h +++ b/js2/src/icode.h @@ -41,7 +41,7 @@ NEW_ARRAY, /* dest */ NEW_CLASS, /* dest, class */ NEW_FUNCTION, /* dest, ICodeModule */ - NEW_OBJECT, /* dest */ + NEW_OBJECT, /* dest, constructor */ NOP, /* do nothing and like it */ NOT, /* dest, source */ OR, /* dest, source1, source2 */ @@ -582,18 +582,18 @@ } }; - class NewObject : public Instruction_1 { + class NewObject : public Instruction_2 { public: - /* dest */ - NewObject (TypedRegister aOp1) : - Instruction_1 - (NEW_OBJECT, aOp1) {}; + /* dest, constructor */ + NewObject (TypedRegister aOp1, TypedRegister aOp2) : + Instruction_2 + (NEW_OBJECT, aOp1, aOp2) {}; virtual Formatter& print(Formatter& f) { - f << opcodeNames[NEW_OBJECT] << "\t" << mOp1; + f << opcodeNames[NEW_OBJECT] << "\t" << mOp1 << ", " << mOp2; return f; } virtual Formatter& printOperands(Formatter& f, const JSValues& registers) { - f << mOp1.first; + f << mOp1.first << ", " << mOp2.first; return f; } }; diff --git a/js2/src/icodegenerator.cpp b/js2/src/icodegenerator.cpp index 46835ac5392a..d27593feb7e8 100644 --- a/js2/src/icodegenerator.cpp +++ b/js2/src/icodegenerator.cpp @@ -211,10 +211,10 @@ TypedRegister ICodeGenerator::loadBoolean(bool value) return dest; } -TypedRegister ICodeGenerator::newObject(RegisterList * /*args*/) +TypedRegister ICodeGenerator::newObject(TypedRegister constructor) { TypedRegister dest(getTempRegister(), &Any_Type); - NewObject *instr = new NewObject(dest); + NewObject *instr = new NewObject(dest, constructor); iCode->push_back(instr); return dest; } @@ -1103,11 +1103,19 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, call(getStatic(clazz, className), ret, &args); } else - NOT_REACHED("New , where is not a known class"); // XXX Runtime error. + NOT_REACHED("new , where is not a new-able type (whatever that means)"); // XXX Runtime error. } + else + if (value.isFunction()) { + TypedRegister f = loadName(className, value.type); + ret = newObject(f); + call(f, ret, &args); + } + else + NOT_REACHED("new , where is not a function"); // XXX Runtime error. } else - ret = newObject(&args); // XXX more ? + ret = newObject(TypedRegister(NotARegister, &Any_Type)); // XXX more ? } break; case ExprNode::Delete: @@ -1449,7 +1457,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, case ExprNode::objectLiteral: { - ret = newObject(NULL); + ret = newObject(TypedRegister(NotARegister, &Any_Type)); PairListExprNode *plen = static_cast(p); ExprPairList *e = plen->pairs; while (e) { diff --git a/js2/src/icodegenerator.h b/js2/src/icodegenerator.h index 51ab22fca500..12abffaf8df7 100644 --- a/js2/src/icodegenerator.h +++ b/js2/src/icodegenerator.h @@ -254,7 +254,7 @@ namespace ICG { TypedRegister loadString(const String &value); TypedRegister loadString(const StringAtom &name); - TypedRegister newObject(RegisterList *args); + TypedRegister newObject(TypedRegister constructor); TypedRegister newArray(); TypedRegister newFunction(ICodeModule *icm); TypedRegister newClass(JSClass *clazz); diff --git a/js2/src/interpreter.cpp b/js2/src/interpreter.cpp index 5c3ba00af135..e1e2313bcd26 100644 --- a/js2/src/interpreter.cpp +++ b/js2/src/interpreter.cpp @@ -500,13 +500,17 @@ void Context::initContext() // set up the correct [[Class]] for the global object (matching SpiderMonkey) mGlobal->setClass(new JSString("global")); + // add (XXX some) of the global object properties mGlobal->setProperty(widenCString("NaN"), kNaNValue); mGlobal->setProperty(widenCString("undefined"), kUndefinedValue); + // 'Object', 'Date', 'RegExp', 'Array' etc are all (constructor) properties of the global object - - mGlobal->setProperty(widenCString("Math"), JSValue(new JSMath())); + JSObject::initObjectObject(mGlobal); + + // the 'Math' object just has some useful properties + JSMath::initMathObject(mGlobal); // This initializes the state of the binary operator overload mechanism. @@ -712,7 +716,10 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) { NewObject* no = static_cast(instruction); JSObject *obj = new JSObject(); - (*registers)[dst(no).first] = new JSObject(); + if (src1(no).first != NotARegister) + (*registers)[dst(no).first] = new JSObject((*registers)[src1(no).first]); + else + (*registers)[dst(no).first] = new JSObject(); } break; case NEW_CLASS: diff --git a/js2/src/jsmath.cpp b/js2/src/jsmath.cpp index 1514481bf875..dd31f362dcb4 100644 --- a/js2/src/jsmath.cpp +++ b/js2/src/jsmath.cpp @@ -186,18 +186,23 @@ struct MathConstantEntry { { "SQRT1_2", M_SQRT1_2 } }; -JSMath::JSMath() -{ - setClass(new JSString("Math")); +// There is no constructor for Math, we simply initialize +// the properties of the Math object +void JSMath::initMathObject(JSScope *g) +{ + int i; + JSMath *m = new JSMath(); + m->setClass(new JSString("Math")); - for (int i = 0; i < sizeof(MathFunctions) / sizeof(MathFunctionEntry); i++) - setProperty(widenCString(MathFunctions[i].name), JSValue(new JSNativeFunction(MathFunctions[i].fn) ) ); + for (i = 0; i < sizeof(MathFunctions) / sizeof(MathFunctionEntry); i++) + m->setProperty(widenCString(MathFunctions[i].name), JSValue(new JSNativeFunction(MathFunctions[i].fn) ) ); - for (int i = 0; i < sizeof(MathConstants) / sizeof(MathConstantEntry); i++) - setProperty(widenCString(MathConstants[i].name), JSValue(MathConstants[i].value) ); + for (i = 0; i < sizeof(MathConstants) / sizeof(MathConstantEntry); i++) + m->setProperty(widenCString(MathConstants[i].name), JSValue(MathConstants[i].value) ); + g->setProperty(widenCString("Math"), JSValue(m)); + } - } /* JSMathClass */ } /* JavaScript */ diff --git a/js2/src/jsmath.h b/js2/src/jsmath.h index 605227ebe59e..0e32d2305718 100644 --- a/js2/src/jsmath.h +++ b/js2/src/jsmath.h @@ -41,11 +41,13 @@ namespace JSMathClass { using JSTypes::JSObject; using JSTypes::JSString; + using JSTypes::JSScope; class JSMath : public JSObject { + private: + JSMath() { } public: - JSMath(); - + static void initMathObject(JSScope *g); }; diff --git a/js2/src/jstypes.cpp b/js2/src/jstypes.cpp index 1cf1f5335b75..18000a3f4686 100644 --- a/js2/src/jstypes.cpp +++ b/js2/src/jstypes.cpp @@ -55,17 +55,49 @@ JSValue object_toString(Context *cx, const JSValues& argv) return kUndefinedValue; } +JSValue objectConstructor(Context *cx, const JSValues& argv) +{ + ASSERT(argv.size() > 0); + JSValue theThis = argv[0]; + + // the prototype and class have been established already + + return theThis; +} + +struct ObjectFunctionEntry { + char *name; + JSNativeFunction::JSCode fn; +} ObjectFunctions[] = { + { "toString", object_toString }, +}; + JSObject *JSObject::objectPrototypeObject = JSObject::initJSObject(); -JSString *JSObject::ObjectString = new JSString("Object"); +String JSObject::ObjectString = widenCString("Object"); +// This establishes the ur-prototype, there's a timing issue +// here - the JSObject static initializers have to run before +// any other JSObject objects are constructed. JSObject *JSObject::initJSObject() { JSObject *result = new JSObject(); - result->setProperty(widenCString("toString"), JSValue(new JSNativeFunction(object_toString) ) ); + + for (int i = 0; i < sizeof(ObjectFunctions) / sizeof(ObjectFunctionEntry); i++) + result->setProperty(widenCString(ObjectFunctions[i].name), JSValue(new JSNativeFunction(ObjectFunctions[i].fn) ) ); + return result; } +// Install the 'Object' constructor into the scope, mostly irrelevant since making +// a new JSObject does all the work of setting the prototype and [[class]] values. +void JSObject::initObjectObject(JSScope *g) +{ + JSObject* o = new JSObject(); + + g->setProperty(ObjectString, JSValue(new JSNativeFunction(objectConstructor))); + +} diff --git a/js2/src/jstypes.h b/js2/src/jstypes.h index 01d8f68b177d..04e88415bb86 100644 --- a/js2/src/jstypes.h +++ b/js2/src/jstypes.h @@ -60,6 +60,7 @@ namespace JSTypes { class JSObject; class JSArray; class JSFunction; + class JSScope; class JSString; class JSType; class Context; @@ -224,12 +225,17 @@ namespace JSTypes { JSType* mType; JSString* mClass; // this is the internal [[Class]] property - public: - JSObject() : mPrototype(objectPrototypeObject), mType(&Any_Type), mClass(ObjectString) {} - - static JSObject *objectPrototypeObject; static JSObject *initJSObject(); - static JSString *ObjectString; + static String ObjectString; + static JSObject *objectPrototypeObject; + + void init(JSObject* prototype); + + public: + JSObject() { init(objectPrototypeObject); } + JSObject(JSValue &constructor) { init(constructor.object->getProperty(widenCString("prototype")).object); } + + static void initObjectObject(JSScope *g); bool hasProperty(const String& name) { @@ -551,6 +557,9 @@ namespace JSTypes { }; + inline void JSObject::init(JSObject* prototype) { mPrototype = prototype; mType = &Any_Type; mClass = new JSString(ObjectString); } + + } /* namespace JSTypes */ } /* namespace JavaScript */ diff --git a/js2/src/winbuild/js2.dsp b/js2/src/winbuild/js2.dsp index 31b00713674b..28007a7d9a6b 100644 --- a/js2/src/winbuild/js2.dsp +++ b/js2/src/winbuild/js2.dsp @@ -195,6 +195,10 @@ SOURCE=..\jsclasses.h # End Source File # Begin Source File +SOURCE=..\jsmath.h +# End Source File +# Begin Source File + SOURCE=..\jstypes.h # End Source File # Begin Source File diff --git a/js2/tests/cpp/js2_shell.cpp b/js2/tests/cpp/js2_shell.cpp index 7162d3bcd279..1f4e0988ed5f 100644 --- a/js2/tests/cpp/js2_shell.cpp +++ b/js2/tests/cpp/js2_shell.cpp @@ -235,6 +235,7 @@ static void readEvalPrint(FILE *in, World &world) // list of zero or more statements ICodeModule* icm = cx.genCode(parsedStatements, ConsoleName); if (icm) { +stdOut << *icm; JSValue result = cx.interpret(icm, JSValues()); stdOut << "result = " << result << "\n"; delete icm; diff --git a/js2/tools/gencode.pl b/js2/tools/gencode.pl index 1c7ba2d7fbaf..52bea9ec8819 100644 --- a/js2/tools/gencode.pl +++ b/js2/tools/gencode.pl @@ -128,9 +128,9 @@ $ops{"SAVE_NAME"} = }; $ops{"NEW_OBJECT"} = { - super => "Instruction_1", - rem => "dest", - params => [ ("TypedRegister") ] + super => "Instruction_2", + rem => "dest, constructor", + params => [ ("TypedRegister", "TypedRegister") ] }; $ops{"NEW_CLASS"} = {