зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
53f415bde5
Коммит
a6a2e6754e
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче