More multiname fixes. Various typos throughout Date. Use length property

for prototype functions to pack argv. Fixed array length setting.
This commit is contained in:
rogerl%netscape.com 2003-02-25 23:48:44 +00:00
Родитель 53f415bde5
Коммит a6a2e6754e
7 изменённых файлов: 516 добавлений и 424 удалений

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

@ -68,9 +68,20 @@ uint32 getLength(JS2Metadata *meta, JS2Object *obj)
return length;
}
js2val setLength(JS2Metadata *meta, JS2Object *obj, uint32 length)
js2val setLength(JS2Metadata *meta, JS2Object *obj, uint32 newLength)
{
js2val result = meta->engine->allocNumber(length);
js2val result = meta->engine->allocNumber(newLength);
uint32 length = getLength(meta, obj);
if (newLength < length) {
// need to delete all the elements above the new length
LookupKind lookup(false, JS2VAL_NULL);
bool deleteResult;
for (uint32 i = newLength; i < length; i++) {
meta->mn1->name = meta->engine->numberToString(i);
meta->deleteProperty(OBJECT_TO_JS2VAL(obj), meta->mn1, &lookup, RunPhase, &deleteResult);
}
}
if (obj->kind == PrototypeInstanceKind) {
// Can't call 'writeDynamicProperty' as that'll just cycle back here for
@ -81,14 +92,6 @@ js2val setLength(JS2Metadata *meta, JS2Object *obj, uint32 length)
i->second.value = result;
return result;
}
/*
for (DynamicPropertyIterator i = dMap->begin(), end = dMap->end(); (i != end); i++) {
if (i->first == *meta->engine->length_StringAtom) {
i->second.value = result;
return result;
}
}
*/
const DynamicPropertyMap::value_type e(*meta->engine->length_StringAtom, DynamicPropertyValue(result, DynamicPropertyValue::PERMANENT));
checked_cast<PrototypeInstance *>(obj)->dynamicProperties.insert(e);
}
@ -540,7 +543,7 @@ static int32 sort_compare(js2val *a, js2val *b, CompareArgs *arg)
js2val argv[2];
argv[0] = av;
argv[1] = bv;
js2val v = JS2VAL_UNDEFINED;// XXX = cx->invokeFunction(ca->target, kNullValue, argv, 2);
js2val v = meta->invokeFunction(ca->target, JS2VAL_NULL, argv, 2);
float64 f = meta->toFloat64(v);
if (JSDOUBLE_IS_NaN(f) || (f == 0))
result = 0;

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

@ -392,7 +392,7 @@ static js2val Date_makeTime(JS2Metadata *meta, const js2val thisValue, js2val *a
*date = nan;
return meta->engine->nanValue;
}
args[i] = (float64)(JS2Engine::float64toInt32(f));
args[i] = JS2Engine::truncateFloat64(f);
}
if (local)
@ -853,6 +853,18 @@ static js2val Date_format(JS2Metadata *meta, float64 date, formatspec format)
return meta->engine->allocString(outf.getString());
}
js2val Date_Call(JS2Metadata *meta, const js2val /* thisValue */, js2val *argv, uint32 argc)
{
int64 us, ms, us2ms;
float64 msec_time;
us = PRMJ_Now();
JSLL_UI2L(us2ms, PRMJ_USEC_PER_MSEC);
JSLL_DIV(ms, us, us2ms);
JSLL_L2D(msec_time, ms);
return Date_format(meta, msec_time, FORMATSPEC_FULL);
}
#define MAXARGS 7
js2val Date_Constructor(JS2Metadata *meta, const js2val /* thisValue */, js2val *argv, uint32 argc)
@ -902,7 +914,7 @@ js2val Date_Constructor(JS2Metadata *meta, const js2val /* thisValue */, js2val
JS2Object::removeRoot(ri);
return thatValue;
}
array[loop] = meta->engine->allocNumber(JS2Engine::float64toInt32(double_arg));
array[loop] = JS2Engine::float64toInt32(double_arg);
} else {
if (loop == 2) {
array[loop] = 1; /* Default the date argument to 1. */
@ -1471,6 +1483,7 @@ void initDateObject(JS2Metadata *meta)
LocalTZA = -(PRMJ_LocalGMTDifference() * msPerSecond);
meta->dateClass->construct = Date_Constructor;
meta->dateClass->call = Date_Call;
NamespaceList publicNamespaceList;
publicNamespaceList.push_back(meta->publicNamespace);
@ -1484,6 +1497,16 @@ void initDateObject(JS2Metadata *meta)
meta->defineLocalMember(meta->env, meta->engine->prototype_StringAtom, &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
v = new Variable(meta->numberClass, INT_TO_JS2VAL(1), true);
meta->defineLocalMember(meta->env, meta->engine->length_StringAtom, &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
// "parse" & "UTC" as static members:
SimpleInstance *callInst = new SimpleInstance(meta->functionClass);
callInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_INACCESSIBLE, true), Date_parse);
v = new Variable(meta->functionClass, OBJECT_TO_JS2VAL(callInst), true);
meta->defineLocalMember(meta->env, &meta->world.identifiers["parse"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
callInst = new SimpleInstance(meta->functionClass);
callInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_INACCESSIBLE, true), Date_UTC);
v = new Variable(meta->functionClass, OBJECT_TO_JS2VAL(callInst), true);
meta->defineLocalMember(meta->env, &meta->world.identifiers["UTC"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
meta->env->removeTopFrame();

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

@ -195,6 +195,379 @@ namespace MetaData {
return checked_cast<JS2Class *>(obj);
}
// Invoke the named function on the thisValue object (it is an object)
// Returns false if no callable function exists. Otherwise return the
// function result value.
bool JS2Metadata::invokeFunctionOnObject(js2val thisValue, const String *fnName, js2val &result)
{
Multiname mn(fnName, publicNamespace);
LookupKind lookup(true, JS2VAL_NULL); // XXX using lexical lookup since we want readProperty to fail
// if the function isn't defined
js2val fnVal;
if (readProperty(&thisValue, &mn, &lookup, RunPhase, &fnVal)) {
if (JS2VAL_IS_OBJECT(fnVal)) {
JS2Object *fnObj = JS2VAL_TO_OBJECT(fnVal);
result = invokeFunction(fnObj, thisValue, NULL, 0);
return true;
/*
FunctionWrapper *fWrap = NULL;
if ((fnObj->kind == SimpleInstanceKind)
&& (objectType(fnVal) == functionClass)) {
fWrap = (checked_cast<SimpleInstance *>(fnObj))->fWrap;
}
else
if ((fnObj->kind == PrototypeInstanceKind)
&& ((checked_cast<PrototypeInstance *>(fnObj))->type == functionClass)) {
fWrap = (checked_cast<FunctionInstance *>(fnObj))->fWrap;
}
else
if (fnObj->kind == MethodClosureKind) {
// XXX here we ignore the bound this, can that be right?
MethodClosure *mc = checked_cast<MethodClosure *>(fnObj);
fWrap = mc->method->fInst->fWrap;
}
if (fWrap) {
if (fWrap->code) {
result = (fWrap->code)(this, thisValue, NULL, 0);
return true;
}
else {
uint8 *savePC = NULL;
BytecodeContainer *bCon = fWrap->bCon;
CompilationData *oldData = startCompilationUnit(bCon, bCon->mSource, bCon->mSourceLocation);
ParameterFrame *runtimeFrame = new ParameterFrame(fWrap->compileFrame);
runtimeFrame->instantiate(env);
runtimeFrame->thisObject = thisValue;
Frame *oldTopFrame = env->getTopFrame();
env->addFrame(runtimeFrame);
try {
savePC = engine->pc;
engine->pc = NULL;
result = engine->interpret(RunPhase, bCon);
}
catch (Exception &x) {
engine->pc = savePC;
restoreCompilationUnit(oldData);
env->setTopFrame(oldTopFrame);
throw x;
}
engine->pc = savePC;
restoreCompilationUnit(oldData);
env->setTopFrame(oldTopFrame);
return true;
}
}
*/
}
}
return false;
}
// Invoke the named function, no args, by looking it up
// the current scope. (Do this by emitting and executing the
// appropriate bytecode sequence)
js2val JS2Metadata::invokeFunction(const char *fname)
{
js2val retval;
uint8 *savePC = NULL;
CompilationData *oldData = startCompilationUnit(NULL, bCon->mSource, bCon->mSourceLocation);
try {
LexicalReference rVal(&world.identifiers[widenCString(fname)], false);
rVal.emitReadForInvokeBytecode(bCon, 0);
bCon->emitOp(eCall, 0, -(0 + 2) + 1); // pop argCount args, the base & function, and push a result
bCon->addShort(0);
bCon->emitOp(eReturn, 0);
savePC = engine->pc;
engine->pc = NULL;
retval = engine->interpret(RunPhase, bCon);
}
catch (Exception &x) {
engine->pc = savePC;
restoreCompilationUnit(oldData);
throw x;
}
engine->pc = savePC;
restoreCompilationUnit(oldData);
return retval;
}
js2val JS2Metadata::invokeFunction(JS2Object *fnObj, js2val thisValue, js2val *argv, uint32 argc)
{
js2val result = JS2VAL_UNDEFINED;
FunctionWrapper *fWrap = NULL;
if ((fnObj->kind == SimpleInstanceKind)
&& ((checked_cast<SimpleInstance *>(fnObj))->type == functionClass)) {
fWrap = (checked_cast<SimpleInstance *>(fnObj))->fWrap;
}
else
if ((fnObj->kind == PrototypeInstanceKind)
&& ((checked_cast<PrototypeInstance *>(fnObj))->type == functionClass)) {
fWrap = (checked_cast<FunctionInstance *>(fnObj))->fWrap;
}
else
if (fnObj->kind == MethodClosureKind) {
// XXX here we ignore the bound this, can that be right?
MethodClosure *mc = checked_cast<MethodClosure *>(fnObj);
fWrap = mc->method->fInst->fWrap;
}
if (fWrap) {
if (fWrap->code) {
result = (fWrap->code)(this, thisValue, argv, argc);
}
else {
uint8 *savePC = NULL;
BytecodeContainer *bCon = fWrap->bCon;
CompilationData *oldData = startCompilationUnit(bCon, bCon->mSource, bCon->mSourceLocation);
ParameterFrame *runtimeFrame = new ParameterFrame(fWrap->compileFrame);
JS2Object::RootIterator ri = JS2Object::addRoot(&runtimeFrame);
runtimeFrame->instantiate(env);
runtimeFrame->thisObject = thisValue;
runtimeFrame->assignArguments(this, argv, argc);
Frame *oldTopFrame = env->getTopFrame();
env->addFrame(runtimeFrame);
try {
savePC = engine->pc;
engine->pc = NULL;
result = engine->interpret(RunPhase, bCon);
}
catch (Exception &x) {
engine->pc = savePC;
restoreCompilationUnit(oldData);
env->setTopFrame(oldTopFrame);
JS2Object::removeRoot(ri);
throw x;
}
engine->pc = savePC;
restoreCompilationUnit(oldData);
env->setTopFrame(oldTopFrame);
JS2Object::removeRoot(ri);
}
}
return result;
}
// Save off info about the current compilation and begin a
// new one - using the given parser.
CompilationData *JS2Metadata::startCompilationUnit(BytecodeContainer *newBCon, const String &source, const String &sourceLocation)
{
CompilationData *result = new CompilationData();
result->compilation_bCon = bCon;
result->execution_bCon = engine->bCon;
bConList.push_back(bCon);
if (newBCon)
bCon = newBCon;
else
bCon = new BytecodeContainer();
bCon->mSource = source;
bCon->mSourceLocation = sourceLocation;
engine->bCon = bCon;
return result;
}
// Restore the compilation data, and then delete the cached copy.
void JS2Metadata::restoreCompilationUnit(CompilationData *oldData)
{
BytecodeContainer *xbCon = bConList.back();
ASSERT(oldData->compilation_bCon == xbCon);
bConList.pop_back();
bCon = oldData->compilation_bCon;
engine->bCon = oldData->execution_bCon;
delete oldData;
}
// x is not a String
const String *JS2Metadata::convertValueToString(js2val x)
{
if (JS2VAL_IS_UNDEFINED(x))
return engine->undefined_StringAtom;
if (JS2VAL_IS_NULL(x))
return engine->null_StringAtom;
if (JS2VAL_IS_BOOLEAN(x))
return (JS2VAL_TO_BOOLEAN(x)) ? engine->true_StringAtom : engine->false_StringAtom;
if (JS2VAL_IS_INT(x))
return engine->numberToString(JS2VAL_TO_INT(x));
if (JS2VAL_IS_LONG(x)) {
float64 d;
JSLL_L2D(d, *JS2VAL_TO_LONG(x));
return engine->numberToString(&d);
}
if (JS2VAL_IS_ULONG(x)) {
float64 d;
JSLL_UL2D(d, *JS2VAL_TO_ULONG(x));
return engine->numberToString(&d);
}
if (JS2VAL_IS_FLOAT(x)) {
float64 d = *JS2VAL_TO_FLOAT(x);
return engine->numberToString(&d);
}
if (JS2VAL_IS_DOUBLE(x))
return engine->numberToString(JS2VAL_TO_DOUBLE(x));
return toString(toPrimitive(x, StringHint));
}
// x is not a primitive (it is an object and not null)
js2val JS2Metadata::convertValueToPrimitive(js2val x, Hint hint)
{
// return [[DefaultValue]] --> get property 'toString' and invoke it,
// if not available or result is not primitive then try property 'valueOf'
// if that's not available or returns a non primitive, throw a TypeError
if (hint == StringHint) {
js2val result;
if (invokeFunctionOnObject(x, engine->toString_StringAtom, result)) {
if (JS2VAL_IS_PRIMITIVE(result))
return result;
}
if (invokeFunctionOnObject(x, engine->valueOf_StringAtom, result)) {
if (JS2VAL_IS_PRIMITIVE(result))
return result;
}
reportError(Exception::typeError, "DefaultValue failure", engine->errorPos());
}
else {
js2val result;
if (invokeFunctionOnObject(x, engine->valueOf_StringAtom, result)) {
if (JS2VAL_IS_PRIMITIVE(result))
return result;
}
if (invokeFunctionOnObject(x, engine->toString_StringAtom, result)) {
if (JS2VAL_IS_PRIMITIVE(result))
return result;
}
reportError(Exception::typeError, "DefaultValue failure", engine->errorPos());
}
return JS2VAL_VOID;
}
// x is not a number
float64 JS2Metadata::convertValueToDouble(js2val x)
{
if (JS2VAL_IS_UNDEFINED(x))
return nan;
if (JS2VAL_IS_NULL(x))
return 0;
if (JS2VAL_IS_BOOLEAN(x))
return (JS2VAL_TO_BOOLEAN(x)) ? 1.0 : 0.0;
if (JS2VAL_IS_STRING(x)) {
String *str = JS2VAL_TO_STRING(x);
const char16 *numEnd;
return stringToDouble(str->data(), str->data() + str->length(), numEnd);
}
if (JS2VAL_IS_INACCESSIBLE(x))
reportError(Exception::compileExpressionError, "Inappropriate compile time expression", engine->errorPos());
if (JS2VAL_IS_UNINITIALIZED(x))
reportError(Exception::compileExpressionError, "Inappropriate compile time expression", engine->errorPos());
return toFloat64(toPrimitive(x, NumberHint));
}
// x is not a number, convert it to one
js2val JS2Metadata::convertValueToGeneralNumber(js2val x)
{
// XXX Assuming convert to float64, rather than long/ulong
return engine->allocNumber(toFloat64(x));
}
// x is not an Object, it needs to be wrapped in one
js2val JS2Metadata::convertValueToObject(js2val x)
{
if (JS2VAL_IS_UNDEFINED(x) || JS2VAL_IS_NULL(x) || JS2VAL_IS_SPECIALREF(x))
reportError(Exception::typeError, "Can't convert to Object", engine->errorPos());
if (JS2VAL_IS_STRING(x))
return String_Constructor(this, JS2VAL_NULL, &x, 1);
if (JS2VAL_IS_BOOLEAN(x))
return Boolean_Constructor(this, JS2VAL_NULL, &x, 1);
if (JS2VAL_IS_NUMBER(x))
return Number_Constructor(this, JS2VAL_NULL, &x, 1);
NOT_REACHED("unsupported value type");
return JS2VAL_VOID;
}
// x is any js2val
float64 JS2Metadata::toFloat64(js2val x)
{
if (JS2VAL_IS_INT(x))
return JS2VAL_TO_INT(x);
else
if (JS2VAL_IS_DOUBLE(x))
return *JS2VAL_TO_DOUBLE(x);
else
if (JS2VAL_IS_LONG(x)) {
float64 d;
JSLL_L2D(d, *JS2VAL_TO_LONG(x));
return d;
}
else
if (JS2VAL_IS_ULONG(x)) {
float64 d;
JSLL_UL2D(d, *JS2VAL_TO_ULONG(x));
return d;
}
else
if (JS2VAL_IS_FLOAT(x))
return *JS2VAL_TO_FLOAT(x);
else
return convertValueToDouble(x);
}
// x is not a bool
bool JS2Metadata::convertValueToBoolean(js2val x)
{
if (JS2VAL_IS_UNDEFINED(x))
return false;
if (JS2VAL_IS_NULL(x))
return false;
if (JS2VAL_IS_INT(x))
return (JS2VAL_TO_INT(x) != 0);
if (JS2VAL_IS_LONG(x) || JS2VAL_IS_ULONG(x))
return (!JSLL_IS_ZERO(x));
if (JS2VAL_IS_FLOAT(x)) {
float64 xd = *JS2VAL_TO_FLOAT(x);
return ! (JSDOUBLE_IS_POSZERO(xd) || JSDOUBLE_IS_NEGZERO(xd) || JSDOUBLE_IS_NaN(xd));
}
if (JS2VAL_IS_DOUBLE(x)) {
float64 xd = *JS2VAL_TO_DOUBLE(x);
return ! (JSDOUBLE_IS_POSZERO(xd) || JSDOUBLE_IS_NEGZERO(xd) || JSDOUBLE_IS_NaN(xd));
}
if (JS2VAL_IS_STRING(x)) {
String *str = JS2VAL_TO_STRING(x);
return (str->length() != 0);
}
return true;
}
// x is not an int
int32 JS2Metadata::convertValueToInteger(js2val x)
{
int32 i;
if (JS2VAL_IS_LONG(x)) {
JSLL_L2I(i, *JS2VAL_TO_LONG(x));
return i;
}
if (JS2VAL_IS_ULONG(x)) {
JSLL_UL2I(i, *JS2VAL_TO_ULONG(x));
return i;
}
if (JS2VAL_IS_FLOAT(x)) {
float64 f = *JS2VAL_TO_FLOAT(x);
return JS2Engine::float64toInt32(f);
}
if (JS2VAL_IS_DOUBLE(x)) {
float64 d = *JS2VAL_TO_DOUBLE(x);
return JS2Engine::float64toInt32(d);
}
float64 d = convertValueToDouble(x);
return JS2Engine::float64toInt32(d);
}
}; // namespace MetaData
}; // namespace Javascript

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

@ -3392,13 +3392,6 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
DynamicPropertyIterator i = dMap->find(*name);
if (i != dMap->end())
return obj;
/*
for (DynamicPropertyIterator i = dMap->begin(), end = dMap->end(); (i != end); i++) {
if (i->first == *name) {
return obj;
}
}
*/
if (isPrototypeInstance) {
PrototypeInstance *pInst = checked_cast<PrototypeInstance *>(obj);
if (pInst->parent)
@ -3427,13 +3420,6 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
DynamicPropertyIterator i = dMap->find(*name);
if (i != dMap->end())
return true;
/*
for (DynamicPropertyIterator i = dMap->begin(), end = dMap->end(); (i != end); i++) {
if (i->first == *name) {
return true;
}
}
*/
return false;
}
@ -3467,14 +3453,6 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
*rval = i->second.value;
return true;
}
/*
for (DynamicPropertyIterator i = dMap->begin(), end = dMap->end(); (i != end); i++) {
if (i->first == *name) {
*rval = i->second;
return true;
}
}
*/
if (isPrototypeInstance) {
PrototypeInstance *pInst = checked_cast<PrototypeInstance *>(container);
if (pInst->parent)
@ -3551,17 +3529,23 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
return false; // 'None'
DynamicPropertyIterator i = dMap->find(*name);
if (i != dMap->end()) {
i->second.value = newValue;
// special case handling for setting 'length' property of ArrayInstances
// XXX should handle this with dispatch to 'writeProperty' of each of
// the different dynamic map containing objects, and change current
// 'writeProperty' functions to 'addProperty'.
if ((container->kind == PrototypeInstanceKind)
&& ((checked_cast<PrototypeInstance *>(container))->type == arrayClass)
&& (*name == *engine->length_StringAtom)) {
float64 f = toFloat64(newValue);
uint32 newLength = f;
if (f != newLength)
reportError(Exception::rangeError, "Invalid length value", engine->errorPos());
setLength(this, container, newLength);
}
else
i->second.value = newValue;
return true;
}
/*
for (DynamicPropertyIterator i = dMap->begin(), end = dMap->end(); (i != end); i++) {
if (i->first == *name) {
i->second.value = newValue;
return true;
}
}
*/
if (!createIfMissing)
return false;
if (container->kind == SimpleInstanceKind) {
@ -3997,15 +3981,6 @@ deleteClassProperty:
return true;
}
}
/*
for (DynamicPropertyIterator i = dMap->begin(), end = dMap->end(); (i != end); i++) {
if (i->first == *name) {
dMap->erase(i);
*result = true;
return true;
}
}
*/
return false;
}
@ -4227,315 +4202,6 @@ deleteClassProperty:
}
// x is not a String
const String *JS2Metadata::convertValueToString(js2val x)
{
if (JS2VAL_IS_UNDEFINED(x))
return engine->undefined_StringAtom;
if (JS2VAL_IS_NULL(x))
return engine->null_StringAtom;
if (JS2VAL_IS_BOOLEAN(x))
return (JS2VAL_TO_BOOLEAN(x)) ? engine->true_StringAtom : engine->false_StringAtom;
if (JS2VAL_IS_INT(x))
return engine->numberToString(JS2VAL_TO_INT(x));
if (JS2VAL_IS_LONG(x)) {
float64 d;
JSLL_L2D(d, *JS2VAL_TO_LONG(x));
return engine->numberToString(&d);
}
if (JS2VAL_IS_ULONG(x)) {
float64 d;
JSLL_UL2D(d, *JS2VAL_TO_ULONG(x));
return engine->numberToString(&d);
}
if (JS2VAL_IS_FLOAT(x)) {
float64 d = *JS2VAL_TO_FLOAT(x);
return engine->numberToString(&d);
}
if (JS2VAL_IS_DOUBLE(x))
return engine->numberToString(JS2VAL_TO_DOUBLE(x));
return toString(toPrimitive(x, StringHint));
}
// Invoke the named function on the thisValue object (it is an object)
// Returns false if no callable function exists. Otherwise return the
// function result value.
bool JS2Metadata::invokeFunctionOnObject(js2val thisValue, const String *fnName, js2val &result)
{
Multiname mn(fnName, publicNamespace);
LookupKind lookup(true, JS2VAL_NULL); // XXX using lexical lookup since we want readProperty to fail
// if the function isn't defined
js2val fnVal;
if (readProperty(&thisValue, &mn, &lookup, RunPhase, &fnVal)) {
if (JS2VAL_IS_OBJECT(fnVal)) {
JS2Object *fnObj = JS2VAL_TO_OBJECT(fnVal);
FunctionWrapper *fWrap = NULL;
if ((fnObj->kind == SimpleInstanceKind)
&& (objectType(fnVal) == functionClass)) {
fWrap = (checked_cast<SimpleInstance *>(fnObj))->fWrap;
}
else
if ((fnObj->kind == PrototypeInstanceKind)
&& ((checked_cast<PrototypeInstance *>(fnObj))->type == functionClass)) {
fWrap = (checked_cast<FunctionInstance *>(fnObj))->fWrap;
}
else
if (fnObj->kind == MethodClosureKind) {
// XXX here we ignore the bound this, can that be right?
MethodClosure *mc = checked_cast<MethodClosure *>(fnObj);
fWrap = mc->method->fInst->fWrap;
}
if (fWrap) {
if (fWrap->code) {
result = (fWrap->code)(this, thisValue, NULL, 0);
return true;
}
else {
uint8 *savePC = NULL;
BytecodeContainer *bCon = fWrap->bCon;
CompilationData *oldData = startCompilationUnit(bCon, bCon->mSource, bCon->mSourceLocation);
ParameterFrame *runtimeFrame = new ParameterFrame(fWrap->compileFrame);
runtimeFrame->instantiate(env);
runtimeFrame->thisObject = thisValue;
Frame *oldTopFrame = env->getTopFrame();
env->addFrame(runtimeFrame);
try {
savePC = engine->pc;
engine->pc = NULL;
result = engine->interpret(RunPhase, bCon);
}
catch (Exception &x) {
engine->pc = savePC;
restoreCompilationUnit(oldData);
env->setTopFrame(oldTopFrame);
throw x;
}
engine->pc = savePC;
restoreCompilationUnit(oldData);
env->setTopFrame(oldTopFrame);
return true;
}
}
}
}
return false;
}
// x is not a primitive (it is an object and not null)
js2val JS2Metadata::convertValueToPrimitive(js2val x, Hint hint)
{
// return [[DefaultValue]] --> get property 'toString' and invoke it,
// if not available or result is not primitive then try property 'valueOf'
// if that's not available or returns a non primitive, throw a TypeError
if (hint == StringHint) {
js2val result;
if (invokeFunctionOnObject(x, engine->toString_StringAtom, result)) {
if (JS2VAL_IS_PRIMITIVE(result))
return result;
}
if (invokeFunctionOnObject(x, engine->valueOf_StringAtom, result)) {
if (JS2VAL_IS_PRIMITIVE(result))
return result;
}
reportError(Exception::typeError, "DefaultValue failure", engine->errorPos());
}
else {
js2val result;
if (invokeFunctionOnObject(x, engine->valueOf_StringAtom, result)) {
if (JS2VAL_IS_PRIMITIVE(result))
return result;
}
if (invokeFunctionOnObject(x, engine->toString_StringAtom, result)) {
if (JS2VAL_IS_PRIMITIVE(result))
return result;
}
reportError(Exception::typeError, "DefaultValue failure", engine->errorPos());
}
return JS2VAL_VOID;
}
// x is not a number
float64 JS2Metadata::convertValueToDouble(js2val x)
{
if (JS2VAL_IS_UNDEFINED(x))
return nan;
if (JS2VAL_IS_NULL(x))
return 0;
if (JS2VAL_IS_BOOLEAN(x))
return (JS2VAL_TO_BOOLEAN(x)) ? 1.0 : 0.0;
if (JS2VAL_IS_STRING(x)) {
String *str = JS2VAL_TO_STRING(x);
const char16 *numEnd;
return stringToDouble(str->data(), str->data() + str->length(), numEnd);
}
if (JS2VAL_IS_INACCESSIBLE(x))
reportError(Exception::compileExpressionError, "Inappropriate compile time expression", engine->errorPos());
if (JS2VAL_IS_UNINITIALIZED(x))
reportError(Exception::compileExpressionError, "Inappropriate compile time expression", engine->errorPos());
return toFloat64(toPrimitive(x, NumberHint));
}
// x is not a number, convert it to one
js2val JS2Metadata::convertValueToGeneralNumber(js2val x)
{
// XXX Assuming convert to float64, rather than long/ulong
return engine->allocNumber(toFloat64(x));
}
// x is not an Object, it needs to be wrapped in one
js2val JS2Metadata::convertValueToObject(js2val x)
{
if (JS2VAL_IS_UNDEFINED(x) || JS2VAL_IS_NULL(x) || JS2VAL_IS_SPECIALREF(x))
reportError(Exception::typeError, "Can't convert to Object", engine->errorPos());
if (JS2VAL_IS_STRING(x))
return String_Constructor(this, JS2VAL_NULL, &x, 1);
if (JS2VAL_IS_BOOLEAN(x))
return Boolean_Constructor(this, JS2VAL_NULL, &x, 1);
if (JS2VAL_IS_NUMBER(x))
return Number_Constructor(this, JS2VAL_NULL, &x, 1);
NOT_REACHED("unsupported value type");
return JS2VAL_VOID;
}
// x is any js2val
float64 JS2Metadata::toFloat64(js2val x)
{
if (JS2VAL_IS_INT(x))
return JS2VAL_TO_INT(x);
else
if (JS2VAL_IS_DOUBLE(x))
return *JS2VAL_TO_DOUBLE(x);
else
if (JS2VAL_IS_LONG(x)) {
float64 d;
JSLL_L2D(d, *JS2VAL_TO_LONG(x));
return d;
}
else
if (JS2VAL_IS_ULONG(x)) {
float64 d;
JSLL_UL2D(d, *JS2VAL_TO_ULONG(x));
return d;
}
else
if (JS2VAL_IS_FLOAT(x))
return *JS2VAL_TO_FLOAT(x);
else
return convertValueToDouble(x);
}
// x is not a bool
bool JS2Metadata::convertValueToBoolean(js2val x)
{
if (JS2VAL_IS_UNDEFINED(x))
return false;
if (JS2VAL_IS_NULL(x))
return false;
if (JS2VAL_IS_INT(x))
return (JS2VAL_TO_INT(x) != 0);
if (JS2VAL_IS_LONG(x) || JS2VAL_IS_ULONG(x))
return (!JSLL_IS_ZERO(x));
if (JS2VAL_IS_FLOAT(x)) {
float64 xd = *JS2VAL_TO_FLOAT(x);
return ! (JSDOUBLE_IS_POSZERO(xd) || JSDOUBLE_IS_NEGZERO(xd) || JSDOUBLE_IS_NaN(xd));
}
if (JS2VAL_IS_DOUBLE(x)) {
float64 xd = *JS2VAL_TO_DOUBLE(x);
return ! (JSDOUBLE_IS_POSZERO(xd) || JSDOUBLE_IS_NEGZERO(xd) || JSDOUBLE_IS_NaN(xd));
}
if (JS2VAL_IS_STRING(x)) {
String *str = JS2VAL_TO_STRING(x);
return (str->length() != 0);
}
return true;
}
// x is not an int
int32 JS2Metadata::convertValueToInteger(js2val x)
{
int32 i;
if (JS2VAL_IS_LONG(x)) {
JSLL_L2I(i, *JS2VAL_TO_LONG(x));
return i;
}
if (JS2VAL_IS_ULONG(x)) {
JSLL_UL2I(i, *JS2VAL_TO_ULONG(x));
return i;
}
if (JS2VAL_IS_FLOAT(x)) {
float64 f = *JS2VAL_TO_FLOAT(x);
return JS2Engine::float64toInt32(f);
}
if (JS2VAL_IS_DOUBLE(x)) {
float64 d = *JS2VAL_TO_DOUBLE(x);
return JS2Engine::float64toInt32(d);
}
float64 d = convertValueToDouble(x);
return JS2Engine::float64toInt32(d);
}
// Save off info about the current compilation and begin a
// new one - using the given parser.
CompilationData *JS2Metadata::startCompilationUnit(BytecodeContainer *newBCon, const String &source, const String &sourceLocation)
{
CompilationData *result = new CompilationData();
result->compilation_bCon = bCon;
result->execution_bCon = engine->bCon;
bConList.push_back(bCon);
if (newBCon)
bCon = newBCon;
else
bCon = new BytecodeContainer();
bCon->mSource = source;
bCon->mSourceLocation = sourceLocation;
engine->bCon = bCon;
return result;
}
// Restore the compilation data, and then delete the cached copy.
void JS2Metadata::restoreCompilationUnit(CompilationData *oldData)
{
BytecodeContainer *xbCon = bConList.back();
ASSERT(oldData->compilation_bCon == xbCon);
bConList.pop_back();
bCon = oldData->compilation_bCon;
engine->bCon = oldData->execution_bCon;
delete oldData;
}
js2val JS2Metadata::invokeFunction(const char *fname)
{
js2val retval;
uint8 *savePC = NULL;
CompilationData *oldData = startCompilationUnit(NULL, bCon->mSource, bCon->mSourceLocation);
try {
LexicalReference rVal(&world.identifiers[widenCString(fname)], false);
rVal.emitReadForInvokeBytecode(bCon, 0);
bCon->emitOp(eCall, 0, -(0 + 2) + 1); // pop argCount args, the base & function, and push a result
bCon->addShort(0);
bCon->emitOp(eReturn, 0);
savePC = engine->pc;
engine->pc = NULL;
retval = engine->interpret(RunPhase, bCon);
}
catch (Exception &x) {
engine->pc = savePC;
restoreCompilationUnit(oldData);
throw x;
}
engine->pc = savePC;
restoreCompilationUnit(oldData);
return retval;
}
/*
* Throw an exception of the specified kind, indicating the position 'pos' and
* attaching the given message. If 'arg' is specified, replace {0} in the message
@ -4783,7 +4449,7 @@ deleteClassProperty:
/************************************************************************************
*
* Frame
* MethodClosure
*
************************************************************************************/

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

@ -1095,6 +1095,7 @@ public:
js2val invokeFunction(const char *fname);
bool invokeFunctionOnObject(js2val thisValue, const String *fnName, js2val &result);
js2val invokeFunction(JS2Object *fnObj, js2val thisValue, js2val *argv, uint32 argc);
bool readProperty(js2val *container, Multiname *multiname, LookupKind *lookupKind, Phase phase, js2val *rval);
bool readProperty(Frame *pf, Multiname *multiname, LookupKind *lookupKind, Phase phase, js2val *rval);

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

@ -37,7 +37,7 @@
case eMinus:
{
a = pop();
a = pop();
a = meta->toGeneralNumber(a);
if (JS2VAL_IS_LONG(a)) {
int64 v = *JS2VAL_TO_LONG(a);
@ -61,14 +61,14 @@
case ePlus:
{
a = pop();
a = pop();
push(meta->toGeneralNumber(a));
}
break;
case eComplement:
{
a = pop();
a = pop();
a = meta->toGeneralNumber(a);
if (JS2VAL_IS_LONG(a)) {
int64 i = *JS2VAL_TO_LONG(a);
@ -89,8 +89,8 @@
break;
case eLeftShift:
{
b = pop();
a = pop();
b = pop();
a = pop();
a = meta->toGeneralNumber(a);
int32 count = meta->toInteger(b);
if (JS2VAL_IS_LONG(a)) {
@ -110,8 +110,8 @@
break;
case eRightShift:
{
b = pop();
a = pop();
b = pop();
a = pop();
a = meta->toGeneralNumber(a);
int32 count = meta->toInteger(b);
if (JS2VAL_IS_LONG(a)) {
@ -131,8 +131,8 @@
break;
case eLogicalRightShift:
{
b = pop();
a = pop();
b = pop();
a = pop();
a = meta->toGeneralNumber(a);
int32 count = meta->toInteger(b);
if (JS2VAL_IS_LONG(a)) {
@ -152,8 +152,8 @@
break;
case eBitwiseAnd:
{
b = pop();
a = pop();
b = pop();
a = pop();
a = meta->toGeneralNumber(a);
b = meta->toGeneralNumber(b);
if (JS2VAL_IS_LONG(a)) {
@ -210,8 +210,8 @@
break;
case eBitwiseXor:
{
b = pop();
a = pop();
b = pop();
a = pop();
a = meta->toGeneralNumber(a);
b = meta->toGeneralNumber(b);
if (JS2VAL_IS_LONG(a)) {
@ -268,8 +268,8 @@
break;
case eBitwiseOr:
{
b = pop();
a = pop();
b = pop();
a = pop();
a = meta->toGeneralNumber(a);
b = meta->toGeneralNumber(b);
if (JS2VAL_IS_LONG(a)) {
@ -327,18 +327,20 @@
case eAdd:
{
b = pop();
a = pop();
a = meta->toPrimitive(a, NumberHint);
b = meta->toPrimitive(b, NumberHint);
if (JS2VAL_IS_STRING(a) || JS2VAL_IS_STRING(b)) {
const String *astr = meta->toString(a);
const String *bstr = meta->toString(b);
String c = *astr;
c += *bstr;
push(STRING_TO_JS2VAL(allocStringPtr(&c)));
}
else {
b = pop();
a = pop();
a = meta->toPrimitive(a, NumberHint);
b = meta->toPrimitive(b, NumberHint);
if (JS2VAL_IS_STRING(a) || JS2VAL_IS_STRING(b)) {
const String *astr = meta->toString(a);
const String *bstr = meta->toString(b);
String c = *astr;
c += *bstr;
push(STRING_TO_JS2VAL(allocStringPtr(&c)));
}
else {
a = meta->toGeneralNumber(a);
b = meta->toGeneralNumber(b);
if (JS2VAL_IS_LONG(a)) {
@ -470,8 +472,8 @@
case eMultiply:
{
b = pop();
a = pop();
b = pop();
a = pop();
a = meta->toGeneralNumber(a);
b = meta->toGeneralNumber(b);
if (JS2VAL_IS_LONG(a)) {
@ -536,8 +538,8 @@
case eDivide:
{
b = pop();
a = pop();
b = pop();
a = pop();
a = meta->toGeneralNumber(a);
b = meta->toGeneralNumber(b);
if (JS2VAL_IS_LONG(a)) {
@ -602,8 +604,8 @@
case eModulo:
{
b = pop();
a = pop();
b = pop();
a = pop();
a = meta->toGeneralNumber(a);
b = meta->toGeneralNumber(b);
if (JS2VAL_IS_LONG(a)) {
@ -675,23 +677,23 @@
case eLogicalXor:
{
b = pop();
a = pop();
b = pop();
a = pop();
push(BOOLEAN_TO_JS2VAL(meta->toBoolean(a) ^ meta->toBoolean(b)));
}
break;
case eLogicalNot:
{
a = pop();
a = pop();
push(BOOLEAN_TO_JS2VAL(!meta->toBoolean(a)));
}
break;
case eLess:
{
b = pop();
a = pop();
b = pop();
a = pop();
a = meta->toPrimitive(a, NumberHint);
b = meta->toPrimitive(b, NumberHint);
bool rval;
@ -705,8 +707,8 @@
case eLessEqual:
{
b = pop();
a = pop();
b = pop();
a = pop();
a = meta->toPrimitive(a, NumberHint);
b = meta->toPrimitive(b, NumberHint);
bool rval;
@ -720,8 +722,8 @@
case eGreater:
{
b = pop();
a = pop();
b = pop();
a = pop();
a = meta->toPrimitive(a, NumberHint);
b = meta->toPrimitive(b, NumberHint);
bool rval;
@ -735,8 +737,8 @@
case eGreaterEqual:
{
b = pop();
a = pop();
b = pop();
a = pop();
a = meta->toPrimitive(a, NumberHint);
b = meta->toPrimitive(b, NumberHint);
bool rval;
@ -752,8 +754,8 @@
case eEqual:
{
bool rval;
b = pop();
a = pop();
b = pop();
a = pop();
if (JS2VAL_IS_NULL(a) || JS2VAL_IS_UNDEFINED(a))
rval = (JS2VAL_IS_NULL(b) || JS2VAL_IS_UNDEFINED(b));
else
@ -764,8 +766,11 @@
b = meta->toPrimitive(b, NumberHint);
if (JS2VAL_IS_NULL(b) || JS2VAL_IS_UNDEFINED(b))
rval = false;
else
rval = (meta->toFloat64(a) == meta->toFloat64(b));
else {
float64 x = meta->toFloat64(a);
float64 y = meta->toFloat64(b);
rval = (!JSDOUBLE_IS_NaN(x) && !JSDOUBLE_IS_NaN(y) && (x == y));
}
}
}
else
@ -773,8 +778,11 @@
b = meta->toPrimitive(b, NumberHint);
if (JS2VAL_IS_NULL(b) || JS2VAL_IS_UNDEFINED(b))
rval = false;
else
rval = (meta->toFloat64(a) == meta->toFloat64(b));
else {
float64 x = meta->toFloat64(a);
float64 y = meta->toFloat64(b);
rval = (!JSDOUBLE_IS_NaN(x) && !JSDOUBLE_IS_NaN(y) && (x == y));
}
}
else
if (JS2VAL_IS_STRING(a)) {
@ -782,8 +790,11 @@
if (JS2VAL_IS_NULL(b) || JS2VAL_IS_UNDEFINED(b))
rval = false;
else
if (JS2VAL_IS_BOOLEAN(b) || JS2VAL_IS_NUMBER(b))
rval = (meta->toFloat64(a) == meta->toFloat64(b));
if (JS2VAL_IS_BOOLEAN(b) || JS2VAL_IS_NUMBER(b)) {
float64 x = meta->toFloat64(a);
float64 y = meta->toFloat64(b);
rval = (!JSDOUBLE_IS_NaN(x) && !JSDOUBLE_IS_NaN(y) && (x == y));
}
else
rval = (*JS2VAL_TO_STRING(a) == *JS2VAL_TO_STRING(b));
}
@ -798,16 +809,22 @@
else
if (JS2VAL_IS_BOOLEAN(a))
rval = (JS2VAL_TO_BOOLEAN(a) == JS2VAL_TO_BOOLEAN(b));
else
rval = (meta->toFloat64(a) == meta->toFloat64(b));
else {
float64 x = meta->toFloat64(a);
float64 y = meta->toFloat64(b);
rval = (!JSDOUBLE_IS_NaN(x) && !JSDOUBLE_IS_NaN(y) && (x == y));
}
}
else
if (JS2VAL_IS_NUMBER(b)) {
a = meta->toPrimitive(a, NumberHint);
if (JS2VAL_IS_NULL(a) || JS2VAL_IS_UNDEFINED(a))
rval = false;
else
rval = (meta->toFloat64(a) == meta->toFloat64(b));
else {
float64 x = meta->toFloat64(a);
float64 y = meta->toFloat64(b);
rval = (!JSDOUBLE_IS_NaN(x) && !JSDOUBLE_IS_NaN(y) && (x == y));
}
}
else
if (JS2VAL_IS_STRING(b)) {
@ -815,8 +832,11 @@
if (JS2VAL_IS_NULL(a) || JS2VAL_IS_UNDEFINED(a))
rval = false;
else
if (JS2VAL_IS_BOOLEAN(a) || JS2VAL_IS_NUMBER(a))
rval = (meta->toFloat64(a) == meta->toFloat64(b));
if (JS2VAL_IS_BOOLEAN(a) || JS2VAL_IS_NUMBER(a)) {
float64 x = meta->toFloat64(a);
float64 y = meta->toFloat64(b);
rval = (!JSDOUBLE_IS_NaN(x) && !JSDOUBLE_IS_NaN(y) && (x == y));
}
else
rval = (*JS2VAL_TO_STRING(a) == *JS2VAL_TO_STRING(b));
}
@ -834,9 +854,8 @@
case eNotIdentical:
{
bool rval;
b = pop();
a = pop();
b = pop();
a = pop();
if (meta->objectType(a) != meta->objectType(b))
rval = false;
else {

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

@ -113,6 +113,7 @@
pc += sizeof(uint16);
a = top(argCount + 2); // 'this'
b = top(argCount + 1); // target function
uint32 length = 0;
if (JS2VAL_IS_PRIMITIVE(b))
meta->reportError(Exception::badValueError, "Can't call on primitive value", errorPos());
JS2Object *fObj = JS2VAL_TO_OBJECT(b);
@ -125,6 +126,7 @@
if ((fObj->kind == PrototypeInstanceKind)
&& ((checked_cast<PrototypeInstance *>(fObj))->type == meta->functionClass)) {
fWrap = (checked_cast<FunctionInstance *>(fObj))->fWrap;
length = getLength(meta, fObj);
}
if (fWrap) {
if (fWrap->compileFrame->prototype) {
@ -135,6 +137,10 @@
}
}
if (fWrap->code) { // native code
while (length > argCount) {
push(JS2VAL_UNDEFINED);
argCount++;
}
a = fWrap->code(meta, a, base(argCount), argCount);
pop(argCount + 2);
push(a);
@ -167,6 +173,7 @@
pFrame->instantiate(meta->env);
pFrame->thisObject = mc->thisObject;
// assignArguments(runtimeFrame, fWrap->compileFrame->signature);
pFrame->assignArguments(meta, base(argCount), argCount);
jsr(phase, fWrap->bCon, base(argCount + 2) - execStack, JS2VAL_VOID); // seems out of order, but we need to catch the current top frame
meta->env->addFrame(meta->objectType(mc->thisObject));
meta->env->addFrame(pFrame);