diff --git a/mozilla/js2/src/bytecodecontainer.h b/mozilla/js2/src/bytecodecontainer.h index df20039b1f8..988fedd2023 100644 --- a/mozilla/js2/src/bytecodecontainer.h +++ b/mozilla/js2/src/bytecodecontainer.h @@ -139,6 +139,9 @@ public: void addShort(uint16 v) { mBuffer.insert(mBuffer.end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(uint16)); } static uint16 getShort(void *pc) { return *((uint16 *)pc); } + void addInt32(int32 v) { addOffset(v); } + static int32 getInt32(void *pc) { return *((int32 *)pc); } + // Maintain list of associated pointers, so as to keep the objects safe across gc's void addMultiname(Multiname *mn) { mMultinameList.push_back(mn); addShort((uint16)(mMultinameList.size() - 1)); } diff --git a/mozilla/js2/src/js2engine.cpp b/mozilla/js2/src/js2engine.cpp index 9d26efcd739..b08d4678d8e 100644 --- a/mozilla/js2/src/js2engine.cpp +++ b/mozilla/js2/src/js2engine.cpp @@ -335,9 +335,13 @@ namespace MetaData { JSLL_L2I(i, *JS2VAL_TO_LONG(x)); return i; } - ASSERT(JS2VAL_IS_ULONG(x)); - JSLL_UL2I(i, *JS2VAL_TO_ULONG(x)); - return i; + else + if (JS2VAL_IS_ULONG(x)) { + JSLL_UL2I(i, *JS2VAL_TO_ULONG(x)); + return i; + } + ASSERT(JS2VAL_IS_INT(x)); + return JS2VAL_TO_INT(x); } float64 JS2Engine::truncateFloat64(float64 d) @@ -457,7 +461,7 @@ namespace MetaData { #ifdef DEBUG - enum { BRANCH_OFFSET = 1, STR_PTR, TYPE_PTR, NAME_INDEX, FRAME_INDEX, BRANCH_PAIR, U16, FLOAT64, BREAK_OFFSET_AND_COUNT }; + enum { BRANCH_OFFSET = 1, STR_PTR, TYPE_PTR, NAME_INDEX, FRAME_INDEX, BRANCH_PAIR, U16, FLOAT64, S32, BREAK_OFFSET_AND_COUNT }; struct { JS2Op op; char *name; @@ -494,6 +498,7 @@ namespace MetaData { { eUndefined, "Undefined", 0 }, { eLongZero, "0(64)", 0 }, { eNumber, "Number", FLOAT64 }, + { eInteger, "Integer", S32 }, { eRegExp, "RegExp", U16 }, { eFunction, "Function", U16 }, { eUInt64, "UInt64", 0 }, @@ -657,6 +662,12 @@ namespace MetaData { pc += sizeof(short); } break; + case S32: + { + printFormat(stdOut, " %d", BytecodeContainer::getInt32(pc)); + pc += sizeof(int32); + } + break; case FRAME_INDEX: case U16: { @@ -761,6 +772,7 @@ namespace MetaData { case eTrue: case eFalse: case eNumber: + case eInteger: case eUInt64: case eInt64: case eNull: diff --git a/mozilla/js2/src/js2engine.h b/mozilla/js2/src/js2engine.h index 685217cf135..771adfe3a36 100644 --- a/mozilla/js2/src/js2engine.h +++ b/mozilla/js2/src/js2engine.h @@ -76,6 +76,7 @@ enum JS2Op { eUndefined, eLongZero, eNumber, + eInteger, eRegExp, eFunction, eUInt64, diff --git a/mozilla/js2/src/js2eval.cpp b/mozilla/js2/src/js2eval.cpp index de00a86191f..d53d8dd3dca 100644 --- a/mozilla/js2/src/js2eval.cpp +++ b/mozilla/js2/src/js2eval.cpp @@ -659,7 +659,6 @@ namespace MetaData { bool result = defaultWriteProperty(meta, base, limit, multiname, lookupKind, createIfMissing, newValue, false); if (result && (multiname->nsList->size() == 1) && (multiname->nsList->back() == meta->publicNamespace)) { - const char16 *numEnd; float64 f = stringToDouble(multiname->name->data(), multiname->name->data() + multiname->name->length(), numEnd); uint32 index = JS2Engine::float64toUInt32(f); @@ -844,6 +843,35 @@ VariableMemberCommon: return limit->deleteProperty(meta, base, limit, multiname, &lookup, result); } + js2val defaultImplicitCoerce(JS2Metadata *meta, js2val newValue, JS2Class *isClass) + { + if (JS2VAL_IS_NULL(newValue) || meta->objectType(newValue)->isAncestor(isClass) ) + return newValue; + meta->reportError(Exception::badValueError, "Illegal coercion", meta->engine->errorPos()); + return JS2VAL_VOID; + } + + js2val integerImplicitCoerce(JS2Metadata *meta, js2val newValue, JS2Class *isClass) + { + if (JS2VAL_IS_UNDEFINED(newValue)) + return JS2VAL_ZERO; + if (JS2VAL_IS_NUMBER(newValue)) { + int64 x = meta->engine->checkInteger(newValue); + if (LONG_IS_INT(x)) { + int32 i = 0; + JSLL_L2I(x, i); + return INT_TO_JS2VAL(i); + } + } + meta->reportError(Exception::badValueError, "Illegal coercion", meta->engine->errorPos()); + return JS2VAL_VOID; + } + + js2val defaultIs(JS2Metadata *meta, js2val newValue, JS2Class *isClass) + { + return BOOLEAN_TO_JS2VAL(meta->objectType(newValue) == isClass); + } + }; // namespace MetaData }; // namespace Javascript diff --git a/mozilla/js2/src/js2metadata.cpp b/mozilla/js2/src/js2metadata.cpp index 008f26b2c28..86a414e9bbe 100644 --- a/mozilla/js2/src/js2metadata.cpp +++ b/mozilla/js2/src/js2metadata.cpp @@ -1255,7 +1255,7 @@ namespace MetaData { if (vb->initializer) { try { js2val newValue = EvalExpression(env, CompilePhase, vb->initializer); - v->value = type->implicitCoerce(this, newValue); + v->value = type->implicitCoerce(this, newValue, type); } catch (Exception x) { // If a compileExpressionError occurred, then the initialiser is @@ -1327,7 +1327,7 @@ namespace MetaData { v->type = t; if (vb->initializer) { js2val newValue = EvalExpression(env, CompilePhase, vb->initializer); - v->defaultValue = t->implicitCoerce(this, newValue); + v->defaultValue = t->implicitCoerce(this, newValue, t); } else v->defaultValue = t->defaultValue; @@ -3557,6 +3557,7 @@ bool nullClass_BracketDelete(JS2Metadata *meta, js2val base, JS2Class *limit, Mu MAKEBUILTINCLASS(generalNumberClass, objectClass, false, false, engine->allocStringPtr(&world.identifiers["general number"]), engine->nanValue); MAKEBUILTINCLASS(numberClass, generalNumberClass, false, true, engine->allocStringPtr(&world.identifiers["Number"]), engine->nanValue); MAKEBUILTINCLASS(integerClass, numberClass, false, true, engine->allocStringPtr(&world.identifiers["Integer"]), JS2VAL_ZERO); + integerClass->implicitCoerce = integerImplicitCoerce; MAKEBUILTINCLASS(characterClass, objectClass, false, true, engine->allocStringPtr(&world.identifiers["Character"]), JS2VAL_ZERO); MAKEBUILTINCLASS(stringClass, objectClass, false, true, engine->allocStringPtr(&world.identifiers["String"]), JS2VAL_NULL); MAKEBUILTINCLASS(namespaceClass, objectClass, false, true, engine->allocStringPtr(&world.identifiers["namespace"]), JS2VAL_NULL); @@ -3634,7 +3635,7 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... /*** ECMA 4 Integer Class ***/ v = new Variable(classClass, OBJECT_TO_JS2VAL(integerClass), true); defineLocalMember(env, &world.identifiers["Integer"], NULL, Attribute::NoOverride, false, ReadWriteAccess, v, 0, true); - + /*** ECMA 3 Date Class ***/ MAKEBUILTINCLASS(dateClass, objectClass, true, true, engine->allocStringPtr(&world.identifiers["Date"]), JS2VAL_NULL); @@ -3935,7 +3936,7 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... Slot *s = findSlot(containerVal, mv); if (mv->immutable && !JS2VAL_IS_UNINITIALIZED(s->value)) reportError(Exception::compileExpressionError, "Reinitialization of constant", engine->errorPos()); - s->value = mv->type->implicitCoerce(this, newValue); + s->value = mv->type->implicitCoerce(this, newValue, mv->type); return true; } default: @@ -4020,7 +4021,7 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... reportError(Exception::propertyAccessError, "Forbidden access", engine->errorPos()); else // quietly ignore the write for JS1 compatibility return true; - v->value = v->type->implicitCoerce(this, newValue); + v->value = v->type->implicitCoerce(this, newValue, v->type); } return true; case LocalMember::FrameVariableMember: @@ -4282,6 +4283,8 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... bracketRead(defaultBracketRead), bracketWrite(defaultBracketWrite), bracketDelete(defaultBracketDelete), + implicitCoerce(defaultImplicitCoerce), + is(defaultIs), slotCount(super ? super->slotCount : 0) { } @@ -4329,14 +4332,6 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... return false; } - js2val JS2Class::implicitCoerce(JS2Metadata *meta, js2val newValue) - { - if (JS2VAL_IS_NULL(newValue) || meta->objectType(newValue)->isAncestor(this) ) - return newValue; - meta->reportError(Exception::badValueError, "Illegal coercion", meta->engine->errorPos()); - return JS2VAL_VOID; - } - void JS2Class::emitDefaultValue(BytecodeContainer *bCon, size_t pos) { if (JS2VAL_IS_NULL(defaultValue)) @@ -4351,6 +4346,11 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... if ((JS2VAL_IS_LONG(defaultValue) || JS2VAL_IS_ULONG(defaultValue)) && (*JS2VAL_TO_LONG(defaultValue) == 0)) bCon->emitOp(eLongZero, pos); + else + if (JS2VAL_IS_INT(defaultValue)) { + bCon->emitOp(eInteger, pos); + bCon->addInt32(JS2VAL_TO_INT(defaultValue)); + } else NOT_REACHED("unrecognized default value"); } diff --git a/mozilla/js2/src/js2metadata.h b/mozilla/js2/src/js2metadata.h index 0c0e679dba9..5eb4fb9252b 100644 --- a/mozilla/js2/src/js2metadata.h +++ b/mozilla/js2/src/js2metadata.h @@ -67,6 +67,8 @@ typedef bool (DeletePublic)(JS2Metadata *meta, js2val base, JS2Class *limit, con typedef bool (BracketRead)(JS2Metadata *meta, js2val *base, JS2Class *limit, Multiname *multiname, Phase phase, js2val *rval); typedef bool (BracketWrite)(JS2Metadata *meta, js2val base, JS2Class *limit, Multiname *multiname, js2val newValue); typedef bool (BracketDelete)(JS2Metadata *meta, js2val base, JS2Class *limit, Multiname *multiname, bool *result); +typedef js2val (ImplicitCoerce)(JS2Metadata *meta, js2val newValue, JS2Class *isClass); +typedef js2val (Is)(JS2Metadata *meta, js2val newValue, JS2Class *isClass); bool defaultReadProperty(JS2Metadata *meta, js2val *base, JS2Class *limit, Multiname *multiname, LookupKind *lookupKind, Phase phase, js2val *rval); bool defaultReadPublicProperty(JS2Metadata *meta, js2val *base, JS2Class *limit, const String *name, Phase phase, js2val *rval); @@ -79,6 +81,9 @@ bool defaultDeleteProperty(JS2Metadata *meta, js2val base, JS2Class *limit, Mult bool defaultDeletePublic(JS2Metadata *meta, js2val base, JS2Class *limit, const String *name, bool *result); bool defaultBracketDelete(JS2Metadata *meta, js2val base, JS2Class *limit, Multiname *multiname, bool *result); bool arrayWritePublic(JS2Metadata *meta, js2val base, JS2Class *limit, const String *name, bool createIfMissing, js2val newValue); +js2val defaultImplicitCoerce(JS2Metadata *meta, js2val newValue, JS2Class *isClass); +js2val defaultIs(JS2Metadata *meta, js2val newValue, JS2Class *isClass); +js2val integerImplicitCoerce(JS2Metadata *meta, js2val newValue, JS2Class *isClass); @@ -741,8 +746,6 @@ public: Callor *call; // A procedure to call when this class is used in a call expression Constructor *construct; // A procedure to call when this class is used in a new expression - js2val implicitCoerce(JS2Metadata *meta, js2val newValue); - // A procedure to call when a value is assigned whose type is this class void emitDefaultValue(BytecodeContainer *bCon, size_t pos); @@ -756,7 +759,8 @@ public: BracketRead *bracketRead; BracketWrite *bracketWrite; BracketDelete *bracketDelete; - + ImplicitCoerce *implicitCoerce; + Is *is; bool isAncestor(JS2Class *heir); diff --git a/mozilla/js2/src/js2op_invocation.cpp b/mozilla/js2/src/js2op_invocation.cpp index eafb9cc203a..1fcbaa28b94 100644 --- a/mozilla/js2/src/js2op_invocation.cpp +++ b/mozilla/js2/src/js2op_invocation.cpp @@ -236,14 +236,13 @@ { b = pop(); a = pop(); // doing 'a is b' - if (!JS2VAL_IS_OBJECT(b)) meta->reportError(Exception::badValueError, "Type expected", errorPos()); JS2Object *obj = JS2VAL_TO_OBJECT(b); if (obj->kind != ClassKind) meta->reportError(Exception::badValueError, "Type expected", errorPos()); JS2Class *isClass = checked_cast(obj); - push(BOOLEAN_TO_JS2VAL(meta->objectType(a) == isClass)); + push(isClass->is(meta, a, isClass)); } break; @@ -340,6 +339,6 @@ JS2Class *c = BytecodeContainer::getType(pc); pc += sizeof(JS2Class *); a = pop(); - push(c->implicitCoerce(meta, a)); + push(c->implicitCoerce(meta, a, c)); } break; diff --git a/mozilla/js2/src/js2op_literal.cpp b/mozilla/js2/src/js2op_literal.cpp index 43e14b332e7..1a41388b48a 100644 --- a/mozilla/js2/src/js2op_literal.cpp +++ b/mozilla/js2/src/js2op_literal.cpp @@ -40,6 +40,13 @@ } break; + case eInteger: + { + push(INT_TO_JS2VAL(BytecodeContainer::getInt32(pc))); + pc += sizeof(int32); + } + break; + case eUInt64: { pushULong(BytecodeContainer::getUInt64(pc)); diff --git a/mozilla/js2/src/js2value.h b/mozilla/js2/src/js2value.h index 7eea9d3eecd..9e11ad55156 100644 --- a/mozilla/js2/src/js2value.h +++ b/mozilla/js2/src/js2value.h @@ -78,8 +78,8 @@ #define INT_FITS_IN_JS2VAL(i) ((uint32)((i)+JS2VAL_INT_MAX) <= 2*JS2VAL_INT_MAX) #define INT_FITS_IN_JSVAL(i) ((jsuint)((i)+JSVAL_INT_MAX) <= 2*JSVAL_INT_MAX) -#define LONG_FITS_IN_JS2VAL(x) (JSLL_CMP((x), >, -JS2VAL_INT_MAX) && JSLL_CMP(JS2VAL_INT_MAX, >, (x))) -#define ULONG_FITS_IN_JS2VAL(x) (JSLL_CMP(JS2VAL_INT_MAX, >, (x))) +#define LONG_IS_INT(x) (JSLL_CMP((x), >, -JS2VAL_INT_MAX) && JSLL_CMP(JS2VAL_INT_MAX, >, (x))) +#define ULONG_IS_INT(x) (JSLL_CMP(JS2VAL_INT_MAX, >, (x))) #define JS2VAL_VOID INT_TO_JS2VAL(0 - JS2VAL_INT_POW2(30)) #define JS2VAL_NULL OBJECT_TO_JS2VAL(0)