Arithmetic. Global properties.

This commit is contained in:
rogerl%netscape.com 2002-09-16 06:33:47 +00:00
Родитель dbf6ed10ae
Коммит 35c3192b27
10 изменённых файлов: 550 добавлений и 76 удалений

Просмотреть файл

@ -115,7 +115,7 @@ public:
void addPointer(const void *v) { ASSERT(sizeof(void *) == sizeof(uint32)); addLong((uint32)(v)); }
static void *getPointer(void *pc) { return (void *)getLong(pc); }
void addFloat64(float64 v) { mBuffer.insert(mBuffer.end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(float64)); }
void addFloat64(float64 v, size_t pos) { emitOp(eNumber, pos); mBuffer.insert(mBuffer.end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(float64)); }
static float64 getFloat64(void *pc) { return *((float64 *)pc); }
void addLong(const uint32 v) { mBuffer.insert(mBuffer.end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(uint32)); }

Просмотреть файл

@ -49,6 +49,7 @@
#include "utilities.h"
#include "js2value.h"
#include "numerics.h"
#include "fdlibm_ns.h"
#include <map>
#include <algorithm>
@ -62,6 +63,7 @@
namespace JavaScript {
namespace MetaData {
// Begin execution of a bytecodeContainer
js2val JS2Engine::interpret(JS2Metadata *metadata, Phase execPhase, BytecodeContainer *targetbCon)
{
bCon = targetbCon;
@ -71,6 +73,7 @@ namespace MetaData {
return interpreterLoop();
}
// Execute the opcode sequence at pc.
js2val JS2Engine::interpreterLoop()
{
js2val retval = JS2VAL_VOID;
@ -83,7 +86,7 @@ namespace MetaData {
#include "js2op_literal.cpp"
#include "js2op_flowcontrol.cpp"
}
JS2Object::gc(meta);
JS2Object::gc(meta); // XXX temporarily, for testing
}
return retval;
}
@ -249,6 +252,9 @@ namespace MetaData {
activationStackTop = activationStack = new ActivationFrame[MAX_ACTIVATION_STACK];
}
// Return the effect of an opcode on the execution stack.
// Some ops (e.g. eCall) have a variable effect, those are handled separately
// (see emitOp)
int getStackEffect(JS2Op op)
{
switch (op) {
@ -257,19 +263,31 @@ namespace MetaData {
case eAdd: // pop two, push one
case eSubtract:
case eMultiply:
case eDivide:
case eModulo:
case eEqual:
case eNotEqual:
case eLess:
case eGreater:
case eLessEqual:
case eGreaterEqual:
case eXor:
case eLogicalXor:
return -1;
case eMinus: // pop one, push one
case ePlus:
case eComplement:
case eTypeof:
return 0;
case eString:
case eTrue:
case eFalse:
case eNumber:
case eNull:
case eThis:
return 1; // push literal value
case eLexicalRead:
@ -297,11 +315,17 @@ namespace MetaData {
case eBranch:
return 0;
case eDup: // duplicate top item
return 1;
case ePop: // remove top item
return -1;
case ePopv: // pop a statement result value
return -1;
// case eToBoolean: // pop object, push boolean
// return 0;
case eToBoolean: // pop object, push boolean
return 0;
case ePushFrame: // affect the frame stack...
case ePopFrame: // ...not the exec stack
@ -320,29 +344,41 @@ namespace MetaData {
case eLexicalPreDec:
return 1; // push the new/old value
case eLexicalAssignOp: // pop value, push result
return 0;
case eDotPostInc:
case eDotPostDec:
case eDotPreInc:
case eDotPreDec:
return 0; // pop the base, push the new/old value
case eDotAssignOp: // pop base, pop value, push result
return -1;
case eBracketPostInc:
case eBracketPostDec:
case eBracketPreInc:
case eBracketPreDec:
return -1; // pop the base, pop the index, push the new/old value
case eBracketAssignOp: // pop base, pop index, push result
return 0;
default:
ASSERT(false);
}
return 0;
}
// Return the mapped source location for the current pc
size_t JS2Engine::errorPos()
{
return bCon->getPosition(pc - bCon->getCodeStart());
}
// XXX Default construction of an instance of the class
// that is the value at the top of the execution stack
JS2Object *JS2Engine::defaultConstructor(JS2Engine *engine)
{
js2val v = engine->pop();
@ -359,6 +395,8 @@ namespace MetaData {
return new FixedInstance(c);
}
// Save current engine state (pc, environment top) and
// jump to start of new bytecodeContainer
void JS2Engine::jsr(BytecodeContainer *new_bCon)
{
ASSERT(activationStackTop < (activationStack + MAX_ACTIVATION_STACK));
@ -372,6 +410,7 @@ namespace MetaData {
}
// Return to previously saved execution state
void JS2Engine::rts()
{
ASSERT(activationStackTop > activationStack);
@ -384,6 +423,8 @@ namespace MetaData {
}
// GC-mark any JS2Objects in the activation frame stack, the execution stack
// and in structures contained in those locations.
void JS2Engine::mark()
{
if (bCon)
@ -404,6 +445,17 @@ namespace MetaData {
}
}
int32 JS2Engine::toInt32(float64 d)
{
if ((d == 0.0) || !JSDOUBLE_IS_FINITE(d) )
return 0;
d = fd::fmod(d, two32);
d = (d >= 0) ? d : d + two32;
if (d >= two31)
return (int32)(d - two32);
else
return (int32)(d);
}
}
}

Просмотреть файл

@ -51,17 +51,26 @@ namespace MetaData {
enum JS2Op {
eAdd,
eSubtract,
eMultiply,
eDivide,
eModulo,
eEqual,
eNotEqual,
eLess,
eGreater,
eLessEqual,
eGreaterEqual,
eXor,
eLogicalXor,
eMinus,
ePlus,
eComplement,
eTrue,
eFalse,
eNull,
eNumber,
eString, // <string pointer:u32>
eThis,
eNewObject, // <argCount:u16>
eLexicalRead, // <multiname index:u16>
eLexicalWrite, // <multiname index:u16>
@ -76,27 +85,33 @@ enum JS2Op {
eReturnVoid,
ePushFrame, // <frame index:u16>
ePopFrame,
// eToBoolean,
eToBoolean,
eBranchFalse, // <branch displacement:s32> XXX save space with short and long versions instead ?
eBranchTrue, // <branch displacement:s32>
eBranch, // <branch displacement:s32>
eNew, // <argCount:u16>
eCall, // <argCount:u16>
eTypeof,
ePopv,
ePop,
eDup,
eLexicalPostInc, // <multiname index:u16>
eLexicalPostDec, // <multiname index:u16>
eLexicalPreInc, // <multiname index:u16>
eLexicalPreDec, // <multiname index:u16>
eLexicalAssignOp, // <op:u8> <multiname index:u16>
eDotPostInc, // <multiname index:u16>
eDotPostDec, // <multiname index:u16>
eDotPreInc, // <multiname index:u16>
eDotPreDec, // <multiname index:u16>
eDotAssignOp, // <op:u8> <multiname index:u16>
eBracketPostInc,
eBracketPostDec,
eBracketPreInc,
eBracketPreDec,
eBracketAssignOp, // <op:u8>
};
@ -129,7 +144,7 @@ public:
js2val toPrimitive(js2val x) { if (JS2VAL_IS_PRIMITIVE(x)) return x; else return convertValueToPrimitive(x); }
float64 toNumber(js2val x) { if (JS2VAL_IS_INT(x)) return JS2VAL_TO_INT(x); else if (JS2VAL_IS_DOUBLE(x)) return *JS2VAL_TO_DOUBLE(x); else return convertValueToDouble(x); }
bool toBoolean(js2val x) { if (JS2VAL_IS_BOOLEAN(x)) return JS2VAL_TO_BOOLEAN(x); else return convertValueToBoolean(x); }
int32 toInt32(float64 f);
js2val assignmentConversion(js2val val, JS2Class *type) { return val; } // XXX s'more code, please

Просмотреть файл

@ -46,6 +46,7 @@
#include "world.h"
#include "utilities.h"
#include "js2value.h"
#include "numerics.h"
#include <map>
#include <algorithm>
@ -1035,6 +1036,8 @@ namespace MetaData {
{
}
// Convert an attribute to a compoundAttribute. If the attribute
// is NULL, return a default compoundAttribute
CompoundAttribute *Attribute::toCompoundAttribute(Attribute *a)
{
if (a)
@ -1043,6 +1046,7 @@ namespace MetaData {
return new CompoundAttribute();
}
// Convert a simple namespace to a compoundAttribute with that namespace
CompoundAttribute *Namespace::toCompoundAttribute()
{
CompoundAttribute *t = new CompoundAttribute();
@ -1050,11 +1054,13 @@ namespace MetaData {
return t;
}
// Convert a 'true' attribute to a default compoundAttribute
CompoundAttribute *TrueAttribute::toCompoundAttribute()
{
return new CompoundAttribute();
}
// gc-mark all contained JS2Objects and visit contained structures to do likewise
void CompoundAttribute::markChildren()
{
if (namespaces) {
@ -1074,10 +1080,11 @@ namespace MetaData {
// Validate the entire expression rooted at p
void JS2Metadata::ValidateExpression(Context *cxt, Environment *env, ExprNode *p)
{
JS2Object::gc(this);
JS2Object::gc(this); // XXX testing stability
switch (p->getKind()) {
case ExprNode::Null:
case ExprNode::number:
case ExprNode::string:
case ExprNode::boolean:
break;
case ExprNode::This:
@ -1124,6 +1131,17 @@ namespace MetaData {
case ExprNode::assignment:
case ExprNode::add:
case ExprNode::subtract:
case ExprNode::multiply:
case ExprNode::divide:
case ExprNode::modulo:
case ExprNode::addEquals:
case ExprNode::subtractEquals:
case ExprNode::multiplyEquals:
case ExprNode::divideEquals:
case ExprNode::moduloEquals:
case ExprNode::logicalAnd:
case ExprNode::logicalXor:
case ExprNode::logicalOr:
{
BinaryExprNode *b = checked_cast<BinaryExprNode *>(p);
ValidateExpression(cxt, env, b->op1);
@ -1131,10 +1149,15 @@ namespace MetaData {
}
break;
case ExprNode::minus:
case ExprNode::plus:
case ExprNode::complement:
case ExprNode::postIncrement:
case ExprNode::postDecrement:
case ExprNode::preIncrement:
case ExprNode::preDecrement:
case ExprNode::parentheses:
case ExprNode::Typeof:
{
UnaryExprNode *u = checked_cast<UnaryExprNode *>(p);
ValidateExpression(cxt, env, u->op);
@ -1177,7 +1200,7 @@ namespace MetaData {
/*
* Evaluate an expression 'p' and execute the associated bytecode
* Evaluate an expression 'p' AND execute the associated bytecode
*/
js2val JS2Metadata::EvalExpression(Environment *env, Phase phase, ExprNode *p)
{
@ -1192,15 +1215,21 @@ namespace MetaData {
}
/*
* Evaluate the expression rooted at p.
* Evaluate the expression (i.e. generate bytecode, but don't execute) rooted at p.
*/
Reference *JS2Metadata::EvalExprNode(Environment *env, Phase phase, ExprNode *p)
{
Reference *returnRef = NULL;
JS2Op binaryOp;
JS2Op op;
switch (p->getKind()) {
case ExprNode::parentheses:
{
UnaryExprNode *u = checked_cast<UnaryExprNode *>(p);
EvalExprNode(env, phase, u->op);
}
break;
case ExprNode::assignment:
{
if (phase == CompilePhase) reportError(Exception::compileExpressionError, "Inappropriate compile time expression", p->pos);
@ -1215,30 +1244,68 @@ namespace MetaData {
reportError(Exception::semanticError, "Assignment needs an lValue", p->pos);
}
break;
case ExprNode::addEquals:
op = eAdd;
goto doAssignBinary;
case ExprNode::subtractEquals:
op = eSubtract;
goto doAssignBinary;
case ExprNode::multiplyEquals:
op = eMultiply;
goto doAssignBinary;
case ExprNode::divideEquals:
op = eDivide;
goto doAssignBinary;
case ExprNode::moduloEquals:
op = eModulo;
goto doAssignBinary;
doAssignBinary:
{
if (phase == CompilePhase) reportError(Exception::compileExpressionError, "Inappropriate compile time expression", p->pos);
BinaryExprNode *b = checked_cast<BinaryExprNode *>(p);
Reference *lVal = EvalExprNode(env, phase, b->op1);
if (lVal) {
Reference *rVal = EvalExprNode(env, phase, b->op2);
if (rVal) rVal->emitReadBytecode(bCon, p->pos);
lVal->emitAssignOpBytecode(bCon, op, p->pos);
}
else
reportError(Exception::semanticError, "Assignment needs an lValue", p->pos);
}
break;
case ExprNode::lessThan:
binaryOp = eLess;
op = eLess;
goto doBinary;
case ExprNode::lessThanOrEqual:
binaryOp = eLessEqual;
op = eLessEqual;
goto doBinary;
case ExprNode::greaterThan:
binaryOp = eGreater;
op = eGreater;
goto doBinary;
case ExprNode::greaterThanOrEqual:
binaryOp = eGreaterEqual;
op = eGreaterEqual;
goto doBinary;
case ExprNode::equal:
binaryOp = eEqual;
op = eEqual;
goto doBinary;
case ExprNode::notEqual:
binaryOp = eNotEqual;
op = eNotEqual;
goto doBinary;
case ExprNode::add:
binaryOp = eAdd;
op = eAdd;
goto doBinary;
case ExprNode::subtract:
binaryOp = eSubtract;
op = eSubtract;
goto doBinary;
case ExprNode::multiply:
op = eMultiply;
goto doBinary;
case ExprNode::divide:
op = eDivide;
goto doBinary;
case ExprNode::modulo:
op = eModulo;
goto doBinary;
doBinary:
{
@ -1247,12 +1314,74 @@ doBinary:
if (lVal) lVal->emitReadBytecode(bCon, p->pos);
Reference *rVal = EvalExprNode(env, phase, b->op2);
if (rVal) rVal->emitReadBytecode(bCon, p->pos);
bCon->emitOp(binaryOp, p->pos);
bCon->emitOp(op, p->pos);
}
break;
case ExprNode::minus:
op = eMinus;
goto doUnary;
case ExprNode::plus:
op = ePlus;
goto doUnary;
case ExprNode::complement:
op = eComplement;
goto doUnary;
doUnary:
{
UnaryExprNode *u = checked_cast<UnaryExprNode *>(p);
Reference *rVal = EvalExprNode(env, phase, u->op);
if (rVal) rVal->emitReadBytecode(bCon, p->pos);
bCon->emitOp(op, p->pos);
}
break;
case ExprNode::logicalAnd:
{
BinaryExprNode *b = checked_cast<BinaryExprNode *>(p);
BytecodeContainer::LabelID skipOverSecondHalf = bCon->getLabel();
Reference *lVal = EvalExprNode(env, phase, b->op1);
if (lVal) lVal->emitReadBytecode(bCon, p->pos);
bCon->emitOp(eDup, p->pos);
bCon->emitBranch(eBranchFalse, skipOverSecondHalf, p->pos);
bCon->emitOp(ePop, p->pos);
Reference *rVal = EvalExprNode(env, phase, b->op2);
if (rVal) rVal->emitReadBytecode(bCon, p->pos);
bCon->setLabel(skipOverSecondHalf);
}
break;
case ExprNode::logicalXor:
{
BinaryExprNode *b = checked_cast<BinaryExprNode *>(p);
Reference *lVal = EvalExprNode(env, phase, b->op1);
if (lVal) lVal->emitReadBytecode(bCon, p->pos);
bCon->emitOp(eToBoolean, p->pos);
Reference *rVal = EvalExprNode(env, phase, b->op2);
if (rVal) rVal->emitReadBytecode(bCon, p->pos);
bCon->emitOp(eToBoolean, p->pos);
bCon->emitOp(eLogicalXor, p->pos);
}
break;
case ExprNode::logicalOr:
{
BinaryExprNode *b = checked_cast<BinaryExprNode *>(p);
BytecodeContainer::LabelID skipOverSecondHalf = bCon->getLabel();
Reference *lVal = EvalExprNode(env, phase, b->op1);
if (lVal) lVal->emitReadBytecode(bCon, p->pos);
bCon->emitOp(eDup, p->pos);
bCon->emitBranch(eBranchTrue, skipOverSecondHalf, p->pos);
bCon->emitOp(ePop, p->pos);
Reference *rVal = EvalExprNode(env, phase, b->op2);
if (rVal) rVal->emitReadBytecode(bCon, p->pos);
bCon->setLabel(skipOverSecondHalf);
}
break;
case ExprNode::This:
{
bCon->emitOp(eThis, p->pos);
}
break;
case ExprNode::Null:
@ -1262,8 +1391,12 @@ doBinary:
break;
case ExprNode::number:
{
bCon->emitOp(eNumber, p->pos);
bCon->addFloat64(checked_cast<NumberExprNode *>(p)->value);
bCon->addFloat64(checked_cast<NumberExprNode *>(p)->value, p->pos);
}
break;
case ExprNode::string:
{
bCon->addString(checked_cast<StringExprNode *>(p)->str, p->pos);
}
break;
case ExprNode::qualify:
@ -1398,6 +1531,14 @@ doBinary:
bCon->addShort(argCount);
}
break;
case ExprNode::Typeof:
{
UnaryExprNode *u = checked_cast<UnaryExprNode *>(p);
Reference *rVal = EvalExprNode(env, phase, u->op);
if (rVal) rVal->emitReadBytecode(bCon, p->pos);
bCon->emitOp(eTypeof, p->pos);
}
break;
case ExprNode::call:
{
InvokeExprNode *i = checked_cast<InvokeExprNode *>(p);
@ -1436,6 +1577,7 @@ doBinary:
return returnRef;
}
// Execute an expression and return the result, which must be a type
JS2Class *JS2Metadata::EvalTypeExpression(Environment *env, Phase phase, ExprNode *p)
{
js2val retval = EvalExpression(env, phase, p);
@ -1608,6 +1750,7 @@ doBinary:
return false;
}
// add all the open namespaces from the given context
void Multiname::addNamespace(Context &cxt)
{
addNamespace(&cxt.openNamespaces);
@ -1622,6 +1765,7 @@ doBinary:
nsList.push_back(*nli);
}
// gc-mark all contained JS2Objects and visit contained structures to do likewise
void Multiname::markChildren()
{
for (NamespaceListIterator n = nsList.begin(), end = nsList.end(); (n != end); n++) {
@ -1920,6 +2064,9 @@ doBinary:
//else A hoisted binding of the same var already exists, so there is no need to create another one
}
void t(JS2Engine *engine)
{
}
#define MAKEBUILTINCLASS(c, super, dynamic, allowNull, final, name) c = new JS2Class(super, new JS2Object(PrototypeInstanceKind), new Namespace(engine->private_StringAtom), dynamic, allowNull, final, name); c->complete = true
@ -1950,6 +2097,20 @@ doBinary:
MAKEBUILTINCLASS(packageClass, objectClass, true, true, true, world.identifiers["package"]);
forbiddenMember = new StaticMember(Member::Forbidden);
writeDynamicProperty(glob, new Multiname(engine->undefined_StringAtom, publicNamespace), true, JS2VAL_UNDEFINED, RunPhase);
writeDynamicProperty(glob, new Multiname(world.identifiers["NaN"], publicNamespace), true, engine->allocNumber(nan), RunPhase);
writeDynamicProperty(glob, new Multiname(world.identifiers["Infinity"], publicNamespace), true, engine->allocNumber(positiveInfinity), RunPhase);
FixedInstance *fInst = new FixedInstance(functionClass);
fInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_VOID, true), t);
env.addFrame(objectClass);
NamespaceList publicNamespaceList;
publicNamespaceList.push_back(publicNamespace);
Variable *v = new Variable(functionClass, OBJECT_TO_JS2VAL(fInst), true);
defineStaticMember(&env, world.identifiers["toString"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
env.removeTopFrame();
}
// objectType(o) returns an OBJECT o's most specific type.
@ -2098,7 +2259,7 @@ doBinary:
return false; // 'None'
}
// Read the static member
// Read a value from the static member
bool JS2Metadata::readStaticMember(StaticMember *m, Phase phase, js2val *rval)
{
if (m == NULL)
@ -2122,7 +2283,7 @@ doBinary:
return false;
}
// Write the static member
// Write a value to the static member
bool JS2Metadata::writeStaticMember(StaticMember *m, js2val newValue, Phase phase)
{
if (m == NULL)
@ -2316,7 +2477,9 @@ readClassProperty:
}
}
// Write the value of an instance member into a container instance.
// Only instanceVariables are writable.
bool JS2Metadata::writeInstanceMember(js2val containerVal, JS2Class *c, QualifiedName *qname, js2val newValue, Phase phase)
{
if (phase == CompilePhase)
@ -2380,7 +2543,7 @@ readClassProperty:
}
}
// Find a binding in the frame that matches the multiname and access
// Find a binding that matches the multiname and access.
// It's an error if more than one such binding exists.
StaticMember *JS2Metadata::findFlatMember(Frame *container, Multiname *multiname, Access access, Phase phase)
{
@ -2416,7 +2579,8 @@ readClassProperty:
return found;
}
// Find the multiname in the class - either in the static bindings (first) or
// in the instance bindings. If not there, look in the super class.
bool JS2Metadata::findStaticMember(JS2Class *c, Multiname *multiname, Access access, Phase phase, MemberDescriptor *result)
{
JS2Class *s = c;
@ -2522,6 +2686,8 @@ readClassProperty:
// and then invoke mark on all other structures that contain JS2Objects
void JS2Metadata::mark()
{
// XXX - maybe have a separate pool to allocate chunks
// that are meant to be never collected?
GCMARKOBJECT(publicNamespace);
GCMARKOBJECT(forbiddenMember);
GCMARKOBJECT(undefinedClass);
@ -2574,6 +2740,7 @@ readClassProperty:
}
inline char narrow(char16 ch) { return char(ch); }
// Accepts a String as the error argument and converts to char *
void JS2Metadata::reportError(Exception::Kind kind, const char *message, size_t pos, const String& name)
{
@ -2700,6 +2867,7 @@ readClassProperty:
}
// gc-mark all contained JS2Objects and visit contained structures to do likewise
void JS2Class::markChildren()
{
GCMARKOBJECT(super)
@ -2720,7 +2888,8 @@ readClassProperty:
*
************************************************************************************/
// Construct a dynamic instance of a class. Set the
// initial value of all slots to uninitialized.
DynamicInstance::DynamicInstance(JS2Class *type)
: JS2Object(DynamicInstanceKind),
type(type),
@ -2735,6 +2904,7 @@ readClassProperty:
}
}
// gc-mark all contained JS2Objects and visit contained structures to do likewise
void DynamicInstance::markChildren()
{
GCMARKOBJECT(type)
@ -2764,6 +2934,8 @@ readClassProperty:
************************************************************************************/
// Construct a fixed instance of a class. Set the
// initial value of all slots to uninitialized.
FixedInstance::FixedInstance(JS2Class *type)
: JS2Object(FixedInstanceKind),
type(type),
@ -2779,12 +2951,14 @@ readClassProperty:
}
}
// gc-mark all contained JS2Objects and visit contained structures to do likewise
void FixedInstance::markChildren()
{
GCMARKOBJECT(type)
if (fWrap) {
GCMARKOBJECT(fWrap->compileFrame);
fWrap->bCon->mark();
if (fWrap->bCon)
fWrap->bCon->mark();
}
if (slots) {
ASSERT(type);
@ -2804,7 +2978,7 @@ readClassProperty:
*
************************************************************************************/
// gc-mark all contained JS2Objects and visit contained structures to do likewise
void PrototypeInstance::markChildren()
{
GCMARKOBJECT(parent)
@ -2823,6 +2997,7 @@ readClassProperty:
*
************************************************************************************/
// gc-mark all contained JS2Objects and visit contained structures to do likewise
void MethodClosure::markChildren()
{
if (JS2VAL_IS_OBJECT(thisObject)) {
@ -2838,6 +3013,7 @@ readClassProperty:
*
************************************************************************************/
// gc-mark all contained JS2Objects and visit contained structures to do likewise
void Frame::markChildren()
{
GCMARKOBJECT(nextFrame)
@ -2858,6 +3034,7 @@ readClassProperty:
*
************************************************************************************/
// gc-mark all contained JS2Objects and visit contained structures to do likewise
void GlobalObject::markChildren()
{
Frame::markChildren();
@ -2882,6 +3059,7 @@ readClassProperty:
env->instantiateFrame(pluralFrame, this);
}
// gc-mark all contained JS2Objects and visit contained structures to do likewise
void ParameterFrame::markChildren()
{
Frame::markChildren();
@ -2921,6 +3099,7 @@ readClassProperty:
type->mark();
}
// gc-mark all contained JS2Objects and visit contained structures to do likewise
void InstanceMember::markChildren()
{
type->markChildren();
@ -2933,6 +3112,8 @@ readClassProperty:
*
************************************************************************************/
// An instance variable type could be future'd when a gc runs (i.e. validate
// has executed, but the pre-eval stage has yet to determine the actual type)
bool InstanceVariable::isMarked()
{
if (type != FUTURE_TYPE)
@ -2947,6 +3128,7 @@ readClassProperty:
type->mark();
}
// gc-mark all contained JS2Objects and visit contained structures to do likewise
void InstanceVariable::markChildren()
{
if (type != FUTURE_TYPE)
@ -2970,6 +3152,7 @@ readClassProperty:
fInst->mark();
}
// gc-mark all contained JS2Objects and visit contained structures to do likewise
void InstanceMethod::markChildren()
{
fInst->markChildren();
@ -2985,6 +3168,9 @@ readClassProperty:
Pond JS2Object::pond(POND_SIZE, NULL);
std::list<PondScum **> JS2Object::rootList;
// Add a pointer to a gc-allocated object to the root list
// (Note - we hand out an iterator, so it's essential to
// use something like std::list that doesn't mess with locations)
JS2Object::RootIterator JS2Object::addRoot(void *t)
{
PondScum **p = (PondScum **)t;
@ -2992,11 +3178,13 @@ readClassProperty:
return rootList.insert(rootList.end(), p);
}
// Remove a root pointer
void JS2Object::removeRoot(RootIterator ri)
{
rootList.erase(ri);
}
// Mark all reachable objects and put the rest back on the freelist
void JS2Object::gc(JS2Metadata *meta)
{
pond.resetMarks();
@ -3016,6 +3204,7 @@ readClassProperty:
pond.moveUnmarkedToFreeList();
}
// Allocate a chink of size s and mark whether it's a JS2Object or not
void *JS2Object::alloc(size_t s, bool isJS2Object)
{
s += sizeof(PondScum);
@ -3025,6 +3214,7 @@ readClassProperty:
return pond.allocFromPond((int32)s, isJS2Object);
}
// Release a chunk back to it's pond
void JS2Object::unalloc(void *t)
{
PondScum *p = (PondScum *)t - 1;

Просмотреть файл

@ -57,16 +57,25 @@ typedef void (Invokable)();
typedef Invokable Callor;
typedef JS2Object *(Constructor)(JS2Engine *engine);
// OBJECT is the semantic domain of all possible objects and is defined as:
// OBJECT = UNDEFINED | NULL | BOOLEAN | FLOAT64 | LONG | ULONG | CHARACTER | STRING | NAMESPACE |
// COMPOUNDATTRIBUTE | CLASS | METHODCLOSURE | PROTOTYPE | INSTANCE | PACKAGE | GLOBAL
//
// In this implementation, the primitive types are distinguished by the tag value
// of a JS2Value (see js2value.h). Non-primitive types are distinguished by calling
// 'kind()' on the object to recover one of the values below:
//
enum ObjectKind {
AttributeObjectKind,
SystemKind,
AttributeObjectKind,
SystemKind,
GlobalObjectKind,
PackageKind,
ParameterKind,
ClassKind,
BlockKind,
PrototypeInstanceKind,
FixedInstanceKind,
PrototypeInstanceKind,
FixedInstanceKind,
DynamicInstanceKind,
MultinameKind,
MethodClosureKind
@ -147,10 +156,6 @@ public:
static void mark(void *p) { ((PondScum *)p)[-1].mark(); }
#ifdef DEBUG
virtual void uselessVirtual() { } // want the checked_cast stuff to work, so need a virtual function
#endif
};
class Attribute : public JS2Object {
@ -191,10 +196,9 @@ public:
const StringAtom &id; // The name
};
// MULTINAME is the semantic domain of sets of qualified names. Multinames are used internally in property lookup.
// A MULTINAME is the semantic domain of sets of qualified names. Multinames are used internally in property lookup.
// We keep Multinames as a basename and a list of namespace qualifiers (XXX is that right - would the basename
// ever be different for the same multiname?)
// Pointers to Multiname instances get embedded in the bytecode.
typedef std::vector<Namespace *> NamespaceList;
typedef NamespaceList::iterator NamespaceListIterator;
class Multiname : public JS2Object {
@ -216,12 +220,6 @@ public:
};
class Object_Uninit_Future {
public:
enum { Object, Uninitialized, Future } state;
js2val value;
};
class NamedParameter {
public:
StringAtom &name; // This parameter's name
@ -259,7 +257,7 @@ public:
StaticMember(MemberKind kind) : Member(kind) { }
StaticMember *cloneContent; // Used during cloning operation to prevent cloning of duplicates (i.e. once
// a clone exists for this member it's stored here and used for any other
// a clone exists for this member it's recorded here and used for any other
// bindings that refer to this member.)
virtual StaticMember *clone() { ASSERT(false); return NULL; }
@ -312,19 +310,8 @@ public:
Invokable *code; // calling this object does the read or write
};
/*
class StaticMethod : public StaticMember {
public:
StaticMethod() : StaticMember(
Signature type; // This function's signature
Invokable *code; // This function itself (a callable object)
enum { Static, Constructor }
modifier; // static if this is a function or a static method; constructor if this is a constructor for a class
};
*/
// DYNAMICPROPERTY record describes one dynamic property of one (prototype or class) instance.
// A DYNAMICPROPERTY record describes one dynamic property of one (prototype or class) instance.
typedef std::map<String, js2val> DynamicPropertyMap;
typedef DynamicPropertyMap::iterator DynamicPropertyIterator;
@ -559,6 +546,9 @@ public:
virtual void emitPostDecBytecode(BytecodeContainer *bCon, size_t pos) { ASSERT(false); }
virtual void emitPreIncBytecode(BytecodeContainer *bCon, size_t pos) { ASSERT(false); }
virtual void emitPreDecBytecode(BytecodeContainer *bCon, size_t pos) { ASSERT(false); }
virtual void emitAssignOpBytecode(BytecodeContainer *bCon, JS2Op op, size_t pos){ ASSERT(false); }
};
class LexicalReference : public Reference {
@ -584,6 +574,7 @@ public:
virtual void emitPreIncBytecode(BytecodeContainer *bCon, size_t pos) { bCon->emitOp(eLexicalPreInc, pos); bCon->addMultiname(variableMultiname); }
virtual void emitPreDecBytecode(BytecodeContainer *bCon, size_t pos) { bCon->emitOp(eLexicalPreDec, pos); bCon->addMultiname(variableMultiname); }
virtual void emitAssignOpBytecode(BytecodeContainer *bCon, JS2Op op, size_t pos){ bCon->emitOp(eLexicalAssignOp, pos); bCon->addByte((uint8)op); bCon->addMultiname(variableMultiname); }
};
class DotReference : public Reference {
@ -610,6 +601,7 @@ public:
virtual void emitPreIncBytecode(BytecodeContainer *bCon, size_t pos) { bCon->emitOp(eDotPreInc, pos); bCon->addMultiname(propertyMultiname); }
virtual void emitPreDecBytecode(BytecodeContainer *bCon, size_t pos) { bCon->emitOp(eDotPreDec, pos); bCon->addMultiname(propertyMultiname); }
virtual void emitAssignOpBytecode(BytecodeContainer *bCon, JS2Op op, size_t pos){ bCon->emitOp(eDotAssignOp, pos); bCon->addByte((uint8)op); bCon->addMultiname(propertyMultiname); }
};
@ -647,6 +639,7 @@ public:
virtual void emitPreIncBytecode(BytecodeContainer *bCon, size_t pos) { bCon->emitOp(eBracketPreInc, pos); }
virtual void emitPreDecBytecode(BytecodeContainer *bCon, size_t pos) { bCon->emitOp(eBracketPreDec, pos); }
virtual void emitAssignOpBytecode(BytecodeContainer *bCon, JS2Op op, size_t pos){ bCon->emitOp(eBracketAssignOp, pos); bCon->addByte((uint8)op); }
};
@ -723,12 +716,17 @@ private:
};
typedef void (NativeCode)(JS2Engine *engine);
class FunctionWrapper {
public:
FunctionWrapper(bool unchecked, ParameterFrame *compileFrame)
: bCon(new BytecodeContainer), unchecked(unchecked), compileFrame(compileFrame) { }
: bCon(new BytecodeContainer), code(NULL), unchecked(unchecked), compileFrame(compileFrame) { }
FunctionWrapper(bool unchecked, ParameterFrame *compileFrame, NativeCode *code)
: bCon(NULL), code(code), unchecked(unchecked), compileFrame(compileFrame) { }
BytecodeContainer *bCon;
NativeCode *code;
bool unchecked; // true if the function is untyped, non-method, normal
ParameterFrame *compileFrame;
};

Просмотреть файл

@ -149,4 +149,13 @@
}
break;
case eThis:
{
js2val rval = meta->env.findThis(true);
if (JS2VAL_IS_INACCESSIBLE(rval))
meta->reportError(Exception::compileExpressionError, "'this' not available", errorPos());
push(rval);
}
break;

Просмотреть файл

@ -32,12 +32,31 @@
* file under either the NPL or the GPL.
*/
case eMinus:
{
js2val a = pop();
pushNumber(-toNumber(a));
}
break;
case ePlus:
{
js2val a = pop();
pushNumber(toNumber(a));
}
break;
case eComplement:
{
js2val a = pop();
pushNumber(~toInt32(toNumber(a)));
}
break;
case eAdd:
{
js2val a = pop();
js2val b = pop();
js2val a = pop();
a = toPrimitive(a);
b = toPrimitive(b);
if (JS2VAL_IS_STRING(a) || JS2VAL_IS_STRING(b)) {
@ -54,20 +73,76 @@
}
}
break;
case eSubtract:
{
js2val a = pop();
js2val b = pop();
js2val a = pop();
float64 anum = toNumber(a);
float64 bnum = toNumber(b);
pushNumber(anum - bnum);
}
break;
case eMultiply:
{
js2val b = pop();
js2val a = pop();
float64 anum = toNumber(a);
float64 bnum = toNumber(b);
pushNumber(anum * bnum);
}
break;
case eDivide:
{
js2val b = pop();
js2val a = pop();
float64 anum = toNumber(a);
float64 bnum = toNumber(b);
pushNumber(anum / bnum);
}
break;
case eModulo:
{
js2val b = pop();
js2val a = pop();
float64 anum = toNumber(a);
float64 bnum = toNumber(b);
#ifdef XP_PC
/* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. */
if (JSDOUBLE_IS_FINITE(anum) && JSDOUBLE_IS_INFINITE(bnum))
pushNumber(anum);
else
#endif
pushNumber(fd::fmod(anum, bnum));
}
break;
case eXor:
{
js2val b = pop();
js2val a = pop();
float64 anum = toNumber(a);
float64 bnum = toNumber(b);
pushNumber(toInt32(anum) ^ toInt32(bnum));
}
break;
case eLogicalXor:
{
js2val b = pop();
js2val a = pop();
ASSERT(JS2VAL_IS_BOOLEAN(a) && JS2VAL_IS_BOOLEAN(b));
push(BOOLEAN_TO_JS2VAL(JS2VAL_TO_BOOLEAN(a) ^ JS2VAL_TO_BOOLEAN(b)));
}
break;
case eLess:
{
js2val a = pop();
js2val b = pop();
js2val a = pop();
js2val ap = toPrimitive(a);
js2val bp = toPrimitive(b);
bool rval;
@ -81,8 +156,8 @@
case eLessEqual:
{
js2val a = pop();
js2val b = pop();
js2val a = pop();
js2val ap = toPrimitive(a);
js2val bp = toPrimitive(b);
bool rval;
@ -96,8 +171,8 @@
case eGreater:
{
js2val a = pop();
js2val b = pop();
js2val a = pop();
js2val ap = toPrimitive(a);
js2val bp = toPrimitive(b);
bool rval;
@ -111,8 +186,8 @@
case eGreaterEqual:
{
js2val a = pop();
js2val b = pop();
js2val a = pop();
js2val ap = toPrimitive(a);
js2val bp = toPrimitive(b);
bool rval;
@ -128,8 +203,8 @@
case eEqual:
{
bool rval;
js2val a = pop();
js2val b = pop();
js2val a = pop();
if (JS2VAL_IS_NULL(a) || JS2VAL_IS_UNDEFINED(a))
rval = (JS2VAL_IS_NULL(b) || JS2VAL_IS_UNDEFINED(b));
else
@ -206,6 +281,76 @@
}
break;
case eLexicalAssignOp:
{
op = (JS2Op)*pc++;
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];
pc += sizeof(short);
js2val a = meta->env.lexicalRead(meta, mn, phase);
js2val b = pop();
js2val rval;
switch (op) {
case eAdd:
{
a = toPrimitive(a);
b = toPrimitive(b);
if (JS2VAL_IS_STRING(a) || JS2VAL_IS_STRING(b)) {
String *astr = toString(a);
String *bstr = toString(b);
String *c = new String(*astr);
*c += *bstr;
rval = STRING_TO_JS2VAL(c);
}
else {
float64 anum = toNumber(a);
float64 bnum = toNumber(b);
rval = allocNumber(anum + bnum);
}
}
break;
case eSubtract:
{
float64 anum = toNumber(a);
float64 bnum = toNumber(b);
rval = allocNumber(anum - bnum);
}
break;
case eMultiply:
{
float64 anum = toNumber(a);
float64 bnum = toNumber(b);
rval = allocNumber(anum * bnum);
}
break;
case eDivide:
{
float64 anum = toNumber(a);
float64 bnum = toNumber(b);
rval = allocNumber(anum / bnum);
}
break;
case eModulo:
{
float64 anum = toNumber(a);
float64 bnum = toNumber(b);
#ifdef XP_PC
/* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. */
if (JSDOUBLE_IS_FINITE(anum) && JSDOUBLE_IS_INFINITE(bnum))
rval = anum;
else
#endif
rval = allocNumber(fd::fmod(anum, bnum));
}
break;
}
meta->env.lexicalWrite(meta, mn, rval, true, phase);
push(rval);
}
break;
case eLexicalPostInc:
{
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];

Просмотреть файл

@ -63,3 +63,15 @@
pc += offset;
}
break;
case ePop:
{
pop();
}
break;
case eDup:
{
push(top());
}
break;

Просмотреть файл

@ -50,16 +50,15 @@
push(OBJECT_TO_JS2VAL(pInst));
}
break;
/*
case eToBoolean:
{
js2val v = pop();
bool b = toBoolean(v);
retval = BOOLEAN_TO_JS2VAL(b);
push(retval);
push(BOOLEAN_TO_JS2VAL(b));
}
break;
*/
case eNew:
{
uint16 argCount = BytecodeContainer::getShort(pc);
@ -101,12 +100,16 @@
runtimeFrame->instantiate(&meta->env);
runtimeFrame->thisObject = runtimeThis;
// assignArguments(runtimeFrame, fWrap->compileFrame->signature);
jsr(fWrap->bCon); // seems out of order, but we need to catch the current top frame
if (!fWrap->code)
jsr(fWrap->bCon); // seems out of order, but we need to catch the current top frame
meta->env.addFrame(runtimeFrame);
if (fWrap->code) {
fWrap->code(this);
meta->env.removeTopFrame();
}
}
else
if (fObj->kind == MethodClosureKind) {
if (fObj->kind == MethodClosureKind) { // XXX I made this up (particularly the push of the objectType)
MethodClosure *mc = checked_cast<MethodClosure *>(fObj);
FixedInstance *fInst = mc->method->fInst;
FunctionWrapper *fWrap = fInst->fWrap;
@ -129,7 +132,6 @@
case eReturn:
{
// retval = pop();
if (activationStackEmpty())
return pop();
else
@ -161,3 +163,50 @@
}
break;
case eTypeof:
{
js2val a = pop();
js2val rval;
if (JS2VAL_IS_UNDEFINED(a))
rval = STRING_TO_JS2VAL(&undefined_StringAtom);
else
if (JS2VAL_IS_BOOLEAN(a))
rval = STRING_TO_JS2VAL(&world.identifiers["boolean"]);
else
if (JS2VAL_IS_NUMBER(a))
rval = STRING_TO_JS2VAL(&world.identifiers["number"]);
else
if (JS2VAL_IS_STRING(a))
rval = STRING_TO_JS2VAL(&world.identifiers["string"]);
else {
ASSERT(JS2VAL_IS_OBJECT(a));
if (JS2VAL_IS_NULL(a))
rval = STRING_TO_JS2VAL(&object_StringAtom);
JS2Object *obj = JS2VAL_TO_OBJECT(a);
switch (obj->kind) {
case MultinameKind:
rval = STRING_TO_JS2VAL(&world.identifiers["namespace"]);
break;
case AttributeObjectKind:
rval = STRING_TO_JS2VAL(&world.identifiers["attribute"]);
break;
case ClassKind:
case MethodClosureKind:
rval = STRING_TO_JS2VAL(&function_StringAtom);
break;
case PrototypeInstanceKind:
case PackageKind:
case GlobalObjectKind:
rval = STRING_TO_JS2VAL(&object_StringAtom);
break;
case FixedInstanceKind:
rval = STRING_TO_JS2VAL(&checked_cast<FixedInstance *>(obj)->typeofString);
break;
case DynamicInstanceKind:
rval = STRING_TO_JS2VAL(&checked_cast<DynamicInstance *>(obj)->typeofString);
break;
}
}
push(rval);
}
break;

Просмотреть файл

@ -69,6 +69,10 @@ namespace JavaScript {
extern double minValue;
extern double maxValue;
static const double two32minus1 = 4294967295.0;
static const double two32 = 4294967296.0;
static const double two16 = 65536.0;
static const double two31 = 2147483648.0;
//
// Portable double-precision floating point to string and back conversions
//