Merge places to mozilla-central.

This commit is contained in:
Shawn Wilsher 2009-07-20 16:04:01 -07:00
Родитель 231a5ea0d6 dba2472e83
Коммит 39d40f70b0
80 изменённых файлов: 4239 добавлений и 1691 удалений

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

@ -41,8 +41,8 @@ static BOOL sh_DoCopy(wchar_t *srcFileName, DWORD srcFileAttributes,
#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
#define STR_LEN(a) (ARRAY_LEN(a) - 1)
/* changes all forward slashes in token to back slashes */
void changeForwardSlashesTpBackSlashes ( wchar_t *arg )
/* changes all forward slashes in token to backslashes */
void changeForwardSlashesToBackSlashes ( wchar_t *arg )
{
if ( arg == NULL )
return;
@ -136,7 +136,7 @@ shellMkdir (wchar_t **pArgv)
while ( *pArgv ) {
arg = *pArgv;
changeForwardSlashesTpBackSlashes ( arg );
changeForwardSlashesToBackSlashes ( arg );
pArg = arg;
pTmpPath = tmpPath;
while ( 1 ) {
@ -148,13 +148,12 @@ shellMkdir (wchar_t **pArgv)
}
*pTmpPath = '\0';
/* check if directory alreay exists */
/* check if directory already exists */
_wgetcwd ( path, _MAX_PATH );
if ( _wchdir ( tmpPath ) != -1 ) {
_wchdir ( path );
} else {
if ( _wmkdir ( tmpPath ) == -1 ) {
// while ( waitForDebug );
printf ( "%ls: ", tmpPath );
perror ( "Could not create the directory" );
retVal = 3;
@ -365,7 +364,7 @@ shellCp (wchar_t **pArgv)
* one file or directory.
*/
changeForwardSlashesTpBackSlashes(*pDst);
changeForwardSlashesToBackSlashes(*pDst);
sh_EnumerateFiles(*pDst, *pDst, sh_RecordFileData, &dstData, &n);
assert(n >= 0);
if (n == 1) {
@ -439,7 +438,7 @@ shellCp (wchar_t **pArgv)
struct sh_FileData srcData;
assert(pDst - pSrc == 1);
changeForwardSlashesTpBackSlashes(*pSrc);
changeForwardSlashesToBackSlashes(*pSrc);
sh_EnumerateFiles(*pSrc, *pSrc, sh_RecordFileData, &srcData, &n);
if (n == 0) {
fprintf(stderr, "nsinstall: %ls: No such file or directory\n",
@ -463,7 +462,7 @@ shellCp (wchar_t **pArgv)
for ( ; *pSrc != *pDst; pSrc++) {
BOOL rv;
changeForwardSlashesTpBackSlashes(*pSrc);
changeForwardSlashesToBackSlashes(*pSrc);
rv = sh_EnumerateFiles(*pSrc, *pSrc, sh_CpFileCmd, &arg, &n);
if (rv == FALSE) {
retVal = 3;

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

@ -2885,7 +2885,24 @@ else
AC_MSG_RESULT(no)
fi
AC_LANG_C
AC_LANG_CPLUSPLUS
dnl Check for usable char16_t (2 bytes, unsigned)
dnl (we might not need the unsignedness check anymore)
AC_CACHE_CHECK(for usable char16_t (2 bytes, unsigned),
ac_cv_have_usable_char16_t,
[AC_TRY_COMPILE([$configure_static_assert_macros],
[CONFIGURE_STATIC_ASSERT(sizeof(char16_t) == 2);
CONFIGURE_STATIC_ASSERT(char16_t(-1) > char16_t(0));
CONFIGURE_STATIC_ASSERT(sizeof((u"hello")[0]) == 2);
CONFIGURE_STATIC_ASSERT(sizeof(u'a') == 2);
CONFIGURE_STATIC_ASSERT(u'\xFFFF' > u'\x0')],
ac_cv_have_usable_char16_t="yes",
ac_cv_have_usable_char16_t="no")])
if test "$ac_cv_have_usable_char16_t" = "yes"; then
AC_DEFINE(HAVE_CPP_CHAR16_T)
HAVE_CPP_CHAR16_T=1
fi
dnl Check for usable wchar_t (2 bytes, unsigned)
dnl (we really don't need the unsignedness check anymore)
@ -2902,15 +2919,13 @@ AC_CACHE_CHECK(for usable wchar_t (2 bytes, unsigned),
if test "$ac_cv_have_usable_wchar_v2" = "yes"; then
AC_DEFINE(HAVE_CPP_2BYTE_WCHAR_T)
HAVE_CPP_2BYTE_WCHAR_T=1
else
elif test "$ac_cv_have_usable_char16_t" != "yes"; then
dnl This is really gcc-only
dnl Do this test using CXX only since some versions of gcc
dnl 2.95-2.97 have a signed wchar_t in c++ only and some versions
dnl only have short-wchar support for c++.
dnl Note that we assume that mac & win32 have short wchar (see nscore.h)
AC_LANG_SAVE
AC_LANG_CPLUSPLUS
_SAVE_CXXFLAGS=$CXXFLAGS
CXXFLAGS="$CXXFLAGS -fshort-wchar"
@ -2930,9 +2945,10 @@ dnl Note that we assume that mac & win32 have short wchar (see nscore.h)
else
CXXFLAGS=$_SAVE_CXXFLAGS
fi
AC_LANG_RESTORE
fi
AC_LANG_C
dnl Check for .hidden assembler directive and visibility attribute.
dnl Borrowed from glibc configure.in
dnl ===============================================================
@ -8392,6 +8408,7 @@ HAVE_CPP_2BYTE_WCHAR_T
HAVE_CPP_ACCESS_CHANGING_USING
HAVE_CPP_AMBIGUITY_RESOLVING_USING
HAVE_CPP_BOOL
HAVE_CPP_CHAR16_T
HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR
HAVE_CPP_EXPLICIT
HAVE_CPP_MODERN_SPECIALIZE_TEMPLATE_SYNTAX

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

@ -142,8 +142,6 @@ MOZ_NATIVE_NSPR = @MOZ_NATIVE_NSPR@
CROSS_COMPILE = @CROSS_COMPILE@
WCHAR_CFLAGS = @WCHAR_CFLAGS@
OS_CPPFLAGS = @CPPFLAGS@
OS_CFLAGS = $(OS_CPPFLAGS) @CFLAGS@
OS_CXXFLAGS = $(OS_CPPFLAGS) @CXXFLAGS@

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

@ -41,8 +41,8 @@ static BOOL sh_DoCopy(wchar_t *srcFileName, DWORD srcFileAttributes,
#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
#define STR_LEN(a) (ARRAY_LEN(a) - 1)
/* changes all forward slashes in token to back slashes */
void changeForwardSlashesTpBackSlashes ( wchar_t *arg )
/* changes all forward slashes in token to backslashes */
void changeForwardSlashesToBackSlashes ( wchar_t *arg )
{
if ( arg == NULL )
return;
@ -136,7 +136,7 @@ shellMkdir (wchar_t **pArgv)
while ( *pArgv ) {
arg = *pArgv;
changeForwardSlashesTpBackSlashes ( arg );
changeForwardSlashesToBackSlashes ( arg );
pArg = arg;
pTmpPath = tmpPath;
while ( 1 ) {
@ -148,13 +148,12 @@ shellMkdir (wchar_t **pArgv)
}
*pTmpPath = '\0';
/* check if directory alreay exists */
/* check if directory already exists */
_wgetcwd ( path, _MAX_PATH );
if ( _wchdir ( tmpPath ) != -1 ) {
_wchdir ( path );
} else {
if ( _wmkdir ( tmpPath ) == -1 ) {
// while ( waitForDebug );
printf ( "%ls: ", tmpPath );
perror ( "Could not create the directory" );
retVal = 3;
@ -365,7 +364,7 @@ shellCp (wchar_t **pArgv)
* one file or directory.
*/
changeForwardSlashesTpBackSlashes(*pDst);
changeForwardSlashesToBackSlashes(*pDst);
sh_EnumerateFiles(*pDst, *pDst, sh_RecordFileData, &dstData, &n);
assert(n >= 0);
if (n == 1) {
@ -439,7 +438,7 @@ shellCp (wchar_t **pArgv)
struct sh_FileData srcData;
assert(pDst - pSrc == 1);
changeForwardSlashesTpBackSlashes(*pSrc);
changeForwardSlashesToBackSlashes(*pSrc);
sh_EnumerateFiles(*pSrc, *pSrc, sh_RecordFileData, &srcData, &n);
if (n == 0) {
fprintf(stderr, "nsinstall: %ls: No such file or directory\n",
@ -463,7 +462,7 @@ shellCp (wchar_t **pArgv)
for ( ; *pSrc != *pDst; pSrc++) {
BOOL rv;
changeForwardSlashesTpBackSlashes(*pSrc);
changeForwardSlashesToBackSlashes(*pSrc);
rv = sh_EnumerateFiles(*pSrc, *pSrc, sh_CpFileCmd, &arg, &n);
if (rv == FALSE) {
retVal = 3;

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

@ -2727,52 +2727,6 @@ fi
AC_LANG_C
dnl Check for usable wchar_t (2 bytes, unsigned)
dnl (we really don't need the unsignedness check anymore)
dnl ========================================================
AC_CACHE_CHECK(for usable wchar_t (2 bytes, unsigned),
ac_cv_have_usable_wchar_v2,
[AC_TRY_COMPILE([#include <stddef.h>
$configure_static_assert_macros],
[CONFIGURE_STATIC_ASSERT(sizeof(wchar_t) == 2);
CONFIGURE_STATIC_ASSERT((wchar_t)-1 > (wchar_t) 0)],
ac_cv_have_usable_wchar_v2="yes",
ac_cv_have_usable_wchar_v2="no")])
if test "$ac_cv_have_usable_wchar_v2" = "yes"; then
AC_DEFINE(HAVE_CPP_2BYTE_WCHAR_T)
HAVE_CPP_2BYTE_WCHAR_T=1
else
dnl This is really gcc-only
dnl Do this test using CXX only since some versions of gcc
dnl 2.95-2.97 have a signed wchar_t in c++ only and some versions
dnl only have short-wchar support for c++.
dnl Note that we assume that mac & win32 have short wchar (see nscore.h)
AC_LANG_SAVE
AC_LANG_CPLUSPLUS
_SAVE_CXXFLAGS=$CXXFLAGS
CXXFLAGS="$CXXFLAGS -fshort-wchar"
AC_CACHE_CHECK(for compiler -fshort-wchar option,
ac_cv_have_usable_wchar_option_v2,
[AC_TRY_LINK([#include <stddef.h>
$configure_static_assert_macros],
[CONFIGURE_STATIC_ASSERT(sizeof(wchar_t) == 2);
CONFIGURE_STATIC_ASSERT((wchar_t)-1 > (wchar_t) 0)],
ac_cv_have_usable_wchar_option_v2="yes",
ac_cv_have_usable_wchar_option_v2="no")])
if test "$ac_cv_have_usable_wchar_option_v2" = "yes"; then
AC_DEFINE(HAVE_CPP_2BYTE_WCHAR_T)
HAVE_CPP_2BYTE_WCHAR_T=1
WCHAR_CFLAGS="-fshort-wchar"
else
CXXFLAGS=$_SAVE_CXXFLAGS
fi
AC_LANG_RESTORE
fi
dnl Check for .hidden assembler directive and visibility attribute.
dnl Borrowed from glibc configure.in
dnl ===============================================================
@ -5073,7 +5027,6 @@ AC_SUBST(COMPILE_CXXFLAGS)
AC_SUBST(LDFLAGS)
AC_SUBST(LIBS)
AC_SUBST(CROSS_COMPILE)
AC_SUBST(WCHAR_CFLAGS)
AC_SUBST(HOST_CC)
AC_SUBST(HOST_CXX)

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

@ -1847,7 +1847,7 @@ JS_malloc(JSContext *cx, size_t nbytes)
JS_ReportOutOfMemory(cx);
return NULL;
}
js_UpdateMallocCounter(cx, nbytes);
cx->updateMallocCounter(nbytes);
return p;
}
@ -1862,7 +1862,7 @@ JS_realloc(JSContext *cx, void *p, size_t nbytes)
return NULL;
}
if (!orig)
js_UpdateMallocCounter(cx, nbytes);
cx->updateMallocCounter(nbytes);
return p;
}
@ -2585,7 +2585,7 @@ JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value)
default:
JS_ASSERT(key == JSGC_TRIGGER_FACTOR);
JS_ASSERT(value >= 100);
rt->gcTriggerFactor = value;
rt->setGCTriggerFactor(value);
return;
}
}
@ -2650,8 +2650,7 @@ JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type)
CHECK_REQUEST(cx);
JS_ASSERT((uintN) type < (uintN) (GCX_NTYPES - GCX_EXTERNAL_STRING));
str = (JSString *) js_NewGCThing(cx, (uintN) type + GCX_EXTERNAL_STRING,
sizeof(JSString));
str = js_NewGCString(cx, (uintN) type + GCX_EXTERNAL_STRING);
if (!str)
return NULL;
str->initFlat(chars, length);
@ -2896,7 +2895,7 @@ JS_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
CHECK_REQUEST(cx);
if (!clasp)
clasp = &js_ObjectClass; /* default class is Object */
return js_NewObject(cx, clasp, proto, parent, 0);
return js_NewObject(cx, clasp, proto, parent);
}
JS_PUBLIC_API(JSObject *)
@ -2906,7 +2905,7 @@ JS_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
CHECK_REQUEST(cx);
if (!clasp)
clasp = &js_ObjectClass; /* default class is Object */
return js_NewObjectWithGivenProto(cx, clasp, proto, parent, 0);
return js_NewObjectWithGivenProto(cx, clasp, proto, parent);
}
JS_PUBLIC_API(JSBool)
@ -3064,7 +3063,7 @@ JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *clasp,
CHECK_REQUEST(cx);
if (!clasp)
clasp = &js_ObjectClass; /* default class is Object */
nobj = js_NewObject(cx, clasp, proto, obj, 0);
nobj = js_NewObject(cx, clasp, proto, obj);
if (!nobj)
return NULL;
if (!DefineProperty(cx, obj, name, OBJECT_TO_JSVAL(nobj), NULL, NULL, attrs,
@ -4109,7 +4108,7 @@ JS_NewPropertyIterator(JSContext *cx, JSObject *obj)
JSIdArray *ida;
CHECK_REQUEST(cx);
iterobj = js_NewObject(cx, &prop_iter_class, NULL, obj, 0);
iterobj = js_NewObject(cx, &prop_iter_class, NULL, obj);
if (!iterobj)
return NULL;
@ -4361,7 +4360,7 @@ JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
uint32 nslots = JSSLOT_FREE(&js_FunctionClass);
JS_ASSERT(nslots == JS_INITIAL_NSLOTS);
nslots += js_FunctionClass.reserveSlots(cx, clone);
if (!js_ReallocSlots(cx, clone, nslots, JS_TRUE))
if (!js_AllocSlots(cx, clone, nslots))
return NULL;
JSUpvarArray *uva = JS_SCRIPT_UPVARS(fun->u.i.script);
@ -4822,12 +4821,12 @@ JS_NewScriptObject(JSContext *cx, JSScript *script)
CHECK_REQUEST(cx);
if (!script)
return js_NewObject(cx, &js_ScriptClass, NULL, NULL, 0);
return js_NewObject(cx, &js_ScriptClass, NULL, NULL);
JS_ASSERT(!script->u.object);
JS_PUSH_TEMP_ROOT_SCRIPT(cx, script, &tvr);
obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL, 0);
obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL);
if (obj) {
JS_SetPrivate(cx, obj, script);
script->u.object = obj;

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

@ -3346,7 +3346,7 @@ js_Array(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
/* If called without new, replace obj with a new Array object. */
if (!JS_IsConstructing(cx)) {
obj = js_NewObject(cx, &js_ArrayClass, NULL, NULL, 0);
obj = js_NewObject(cx, &js_ArrayClass, NULL, NULL);
if (!obj)
return JS_FALSE;
*rval = OBJECT_TO_JSVAL(obj);
@ -3381,7 +3381,7 @@ js_NewEmptyArray(JSContext* cx, JSObject* proto)
JS_ASSERT(OBJ_IS_ARRAY(cx, proto));
JS_ASSERT(JS_ON_TRACE(cx));
JSObject* obj = (JSObject*) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject));
JSObject* obj = js_NewGCObject(cx, GCX_OBJECT);
if (!obj)
return NULL;
@ -3442,7 +3442,7 @@ js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector, JSBool holey)
JSTempValueRooter tvr;
JSObject *obj;
obj = js_NewObject(cx, &js_ArrayClass, NULL, NULL, 0);
obj = js_NewObject(cx, &js_ArrayClass, NULL, NULL);
if (!obj)
return NULL;
@ -3459,7 +3459,7 @@ js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector, JSBool holey)
JSObject *
js_NewSlowArrayObject(JSContext *cx)
{
JSObject *obj = js_NewObject(cx, &js_SlowArrayClass, NULL, NULL, 0);
JSObject *obj = js_NewObject(cx, &js_SlowArrayClass, NULL, NULL);
if (obj)
obj->fslots[JSSLOT_ARRAY_LENGTH] = 0;
return obj;

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

@ -1094,6 +1094,7 @@ JSAtomList::add(JSCompiler *jsc, JSAtom *atom, AddHow how)
* with the given key.
*/
if (how == HOIST && ale->entry.next) {
JS_ASSERT(*hep == &ale->entry);
*hep = ale->entry.next;
ale->entry.next = NULL;
do {

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

@ -83,8 +83,9 @@ js_ValueToStringId(JSContext *cx, jsval v, jsid *idp)
static inline JSBool
js_Int32ToId(JSContext* cx, int32 index, jsid* id)
{
if (index <= JSVAL_INT_MAX) {
if (INT_FITS_IN_JSVAL(index)) {
*id = INT_TO_JSID(index);
JS_ASSERT(INT_JSID_TO_JSVAL(*id) == INT_TO_JSVAL(index));
return JS_TRUE;
}
JSString* str = js_NumberToString(cx, index);

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

@ -308,7 +308,7 @@ HasProperty(JSContext* cx, JSObject* obj, jsid id)
JSObject* obj2;
JSProperty* prop;
if (!js_LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop))
if (js_LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop) < 0)
return JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID);
if (prop)
OBJ_DROP_PROPERTY(cx, obj2, prop);
@ -390,7 +390,7 @@ js_Arguments(JSContext* cx, JSObject* parent, JSObject* cached)
{
if (cached)
return cached;
return js_NewObject(cx, &js_ArgumentsClass, NULL, NULL, 0);
return js_NewObject(cx, &js_ArgumentsClass, NULL, NULL);
}
JS_DEFINE_CALLINFO_3(extern, OBJECT, js_Arguments, CONTEXT, OBJECT, OBJECT, 0, 0)
@ -404,7 +404,7 @@ js_NewNullClosure(JSContext* cx, JSObject* funobj, JSObject* proto, JSObject* pa
JSFunction *fun = (JSFunction*) funobj;
JS_ASSERT(GET_FUNCTION_PRIVATE(cx, funobj) == fun);
JSObject* closure = (JSObject*) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject));
JSObject* closure = js_NewGCObject(cx, GCX_OBJECT);
if (!closure)
return NULL;

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

@ -249,6 +249,12 @@ struct JSThreadData {
#ifdef JS_EVAL_CACHE_METERING
JSEvalCacheMeter evalCacheMeter;
#endif
/*
* Thread-local version of JSRuntime.gcMallocBytes to avoid taking
* locks on each JS_malloc.
*/
size_t gcMallocBytes;
};
#ifdef JS_THREADSAFE
@ -264,12 +270,6 @@ struct JSThread {
/* Opaque thread-id, from NSPR's PR_GetCurrentThread(). */
jsword id;
/*
* Thread-local version of JSRuntime.gcMallocBytes to avoid taking
* locks on each JS_malloc.
*/
uint32 gcMallocBytes;
/* Indicates that the thread is waiting in ClaimTitle from jslock.cpp. */
JSTitle *titleToShare;
@ -369,15 +369,16 @@ struct JSRuntime {
JSDHashTable gcRootsHash;
JSDHashTable *gcLocksHash;
jsrefcount gcKeepAtoms;
uint32 gcBytes;
uint32 gcLastBytes;
uint32 gcMaxBytes;
uint32 gcMaxMallocBytes;
size_t gcBytes;
size_t gcLastBytes;
size_t gcMaxBytes;
size_t gcMaxMallocBytes;
uint32 gcEmptyArenaPoolLifespan;
uint32 gcLevel;
uint32 gcNumber;
JSTracer *gcMarkingTracer;
uint32 gcTriggerFactor;
size_t gcTriggerBytes;
volatile JSBool gcIsNeeded;
/*
@ -394,7 +395,7 @@ struct JSRuntime {
#endif
JSGCCallback gcCallback;
uint32 gcMallocBytes;
size_t gcMallocBytes;
JSGCArenaInfo *gcUntracedArenaStackTop;
#ifdef DEBUG
size_t gcTraceLaterCount;
@ -682,6 +683,9 @@ struct JSRuntime {
JSFunctionMeter functionMeter;
char lastScriptFilename[1024];
#endif
void setGCTriggerFactor(uint32 factor);
void setGCLastBytes(size_t lastBytes);
};
/* Common macros to access thread-local caches in JSThread or JSRuntime. */
@ -1036,6 +1040,17 @@ struct JSContext {
uintN nativeVpLen;
jsval *nativeVp;
#endif
/* Call this after succesful malloc of memory for GC-related things. */
inline void
updateMallocCounter(size_t nbytes)
{
size_t *pbytes, bytes;
pbytes = &JS_THREAD_DATA(this)->gcMallocBytes;
bytes = *pbytes;
*pbytes = (size_t(-1) - bytes <= nbytes) ? size_t(-1) : bytes + nbytes;
}
};
#ifdef JS_THREADSAFE

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

@ -2199,7 +2199,7 @@ js_NewDateObjectMsec(JSContext *cx, jsdouble msec_time)
JSObject *obj;
jsdouble *date;
obj = js_NewObject(cx, &js_DateClass, NULL, NULL, 0);
obj = js_NewObject(cx, &js_DateClass, NULL, NULL);
if (!obj)
return NULL;

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

@ -1729,7 +1729,7 @@ JS_NewSystemObject(JSContext *cx, JSClass *clasp, JSObject *proto,
{
JSObject *obj;
obj = js_NewObject(cx, clasp, proto, parent, 0);
obj = js_NewObject(cx, clasp, proto, parent);
if (obj && system)
STOBJ_SET_SYSTEM(obj);
return obj;

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

@ -1822,8 +1822,7 @@ EmitEnterBlock(JSContext *cx, JSParseNode *pn, JSCodeGenerator *cg)
}
OBJ_SCOPE(blockObj)->freeslot = JSSLOT_FREE(&js_BlockClass);
js_ReallocSlots(cx, blockObj, JSSLOT_FREE(&js_BlockClass), JS_TRUE);
return true;
return js_GrowSlots(cx, blockObj, JSSLOT_FREE(&js_BlockClass));
}
/*

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

@ -709,7 +709,7 @@ Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
.classPrototypeAtom),
rval))
return JS_FALSE;
obj = js_NewObject(cx, &js_ErrorClass, JSVAL_TO_OBJECT(*rval), NULL, 0);
obj = js_NewObject(cx, &js_ErrorClass, JSVAL_TO_OBJECT(*rval), NULL);
if (!obj)
return JS_FALSE;
*rval = OBJECT_TO_JSVAL(obj);
@ -1033,7 +1033,7 @@ js_InitExceptionClasses(JSContext *cx, JSObject *obj)
/* Make the prototype for the current constructor name. */
proto = js_NewObject(cx, &js_ErrorClass,
(i != JSEXN_ERR) ? error_proto : obj_proto,
obj, 0);
obj);
if (!proto)
return NULL;
if (i == JSEXN_ERR) {
@ -1185,7 +1185,7 @@ js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp)
goto out;
tv[0] = OBJECT_TO_JSVAL(errProto);
errObject = js_NewObject(cx, &js_ErrorClass, errProto, NULL, 0);
errObject = js_NewObject(cx, &js_ErrorClass, errProto, NULL);
if (!errObject) {
ok = JS_FALSE;
goto out;

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

@ -259,7 +259,7 @@ js_GetArgsObject(JSContext *cx, JSStackFrame *fp)
return argsobj;
/* Link the new object to fp so it can get actual argument values. */
argsobj = js_NewObject(cx, &js_ArgumentsClass, NULL, NULL, 0);
argsobj = js_NewObject(cx, &js_ArgumentsClass, NULL, NULL);
if (!argsobj || !JS_SetPrivate(cx, argsobj, fp)) {
cx->weakRoots.newborn[GCX_OBJECT] = NULL;
return NULL;
@ -386,7 +386,7 @@ WrapEscapingClosure(JSContext *cx, JSStackFrame *fp, JSObject *funobj, JSFunctio
return NULL;
JSObject *wfunobj = js_NewObjectWithGivenProto(cx, &js_FunctionClass,
funobj, scopeChain, 0);
funobj, scopeChain);
if (!wfunobj)
return NULL;
JSAutoTempValueRooter tvr(cx, wfunobj);
@ -880,7 +880,7 @@ js_GetCallObject(JSContext *cx, JSStackFrame *fp)
JSAtom *lambdaName = (fp->fun->flags & JSFUN_LAMBDA) ? fp->fun->atom : NULL;
if (lambdaName) {
JSObject *env = js_NewObjectWithGivenProto(cx, &js_DeclEnvClass, NULL,
fp->scopeChain, 0);
fp->scopeChain);
if (!env)
return NULL;
env->fslots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(fp);
@ -896,8 +896,7 @@ js_GetCallObject(JSContext *cx, JSStackFrame *fp)
}
}
callobj = js_NewObjectWithGivenProto(cx, &js_CallClass, NULL,
fp->scopeChain, 0);
callobj = js_NewObjectWithGivenProto(cx, &js_CallClass, NULL, fp->scopeChain);
if (!callobj)
return NULL;
@ -969,7 +968,7 @@ js_PutCallObject(JSContext *cx, JSStackFrame *fp)
JS_LOCK_OBJ(cx, callobj);
n += JS_INITIAL_NSLOTS;
if (n > STOBJ_NSLOTS(callobj))
ok &= js_ReallocSlots(cx, callobj, n, JS_TRUE);
ok &= js_GrowSlots(cx, callobj, n);
scope = OBJ_SCOPE(callobj);
if (ok) {
memcpy(callobj->dslots, fp->argv, fun->nargs * sizeof(jsval));
@ -1514,8 +1513,7 @@ fun_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
* Make the prototype object to have the same parent as the function
* object itself.
*/
proto = js_NewObject(cx, &js_ObjectClass, NULL, OBJ_GET_PARENT(cx, obj),
0);
proto = js_NewObject(cx, &js_ObjectClass, NULL, OBJ_GET_PARENT(cx, obj));
if (!proto)
return JS_FALSE;
@ -2187,7 +2185,7 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
JSTokenType tt;
if (!JS_IsConstructing(cx)) {
obj = js_NewObject(cx, &js_FunctionClass, NULL, NULL, 0);
obj = js_NewObject(cx, &js_FunctionClass, NULL, NULL);
if (!obj)
return JS_FALSE;
*rval = OBJECT_TO_JSVAL(obj);
@ -2437,7 +2435,7 @@ js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs,
JS_ASSERT(HAS_FUNCTION_CLASS(funobj));
OBJ_SET_PARENT(cx, funobj, parent);
} else {
funobj = js_NewObject(cx, &js_FunctionClass, NULL, parent, 0);
funobj = js_NewObject(cx, &js_FunctionClass, NULL, parent);
if (!funobj)
return NULL;
}
@ -2491,8 +2489,7 @@ js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent)
* The cloned function object does not need the extra JSFunction members
* beyond JSObject as it points to fun via the private slot.
*/
JSObject *clone = js_NewObject(cx, &js_FunctionClass, NULL, parent,
sizeof(JSObject));
JSObject *clone = js_NewObject(cx, &js_FunctionClass, NULL, parent, sizeof(JSObject));
if (!clone)
return NULL;
clone->fslots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(fun);
@ -2519,7 +2516,7 @@ js_AllocFlatClosure(JSContext *cx, JSFunction *fun, JSObject *scopeChain)
uint32 nslots = JSSLOT_FREE(&js_FunctionClass);
JS_ASSERT(nslots == JS_INITIAL_NSLOTS);
nslots += fun_reserveSlots(cx, closure);
if (!js_ReallocSlots(cx, closure, nslots, JS_TRUE))
if (!js_GrowSlots(cx, closure, nslots))
return NULL;
return closure;

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

@ -1308,13 +1308,13 @@ js_InitGC(JSRuntime *rt, uint32 maxbytes)
* By default the trigger factor gets maximum possible value. This
* means that GC will not be triggered by growth of GC memory (gcBytes).
*/
rt->gcTriggerFactor = (uint32) -1;
rt->setGCTriggerFactor((uint32) -1);
/*
* The assigned value prevents GC from running when GC memory is too low
* (during JS engine start).
*/
rt->gcLastBytes = 8192;
rt->setGCLastBytes(8192);
METER(memset(&rt->gcStats, 0, sizeof rt->gcStats));
return JS_TRUE;
@ -1800,6 +1800,25 @@ EnsureLocalFreeList(JSContext *cx)
#endif
void
JSRuntime::setGCTriggerFactor(uint32 factor)
{
JS_ASSERT(factor >= 100);
gcTriggerFactor = factor;
setGCLastBytes(gcLastBytes);
}
void
JSRuntime::setGCLastBytes(size_t lastBytes)
{
gcLastBytes = lastBytes;
uint64 triggerBytes = uint64(lastBytes) * uint64(gcTriggerFactor / 100);
if (triggerBytes != size_t(triggerBytes))
triggerBytes = size_t(-1);
gcTriggerBytes = size_t(triggerBytes);
}
static JS_INLINE bool
IsGCThresholdReached(JSRuntime *rt)
{
@ -1814,14 +1833,13 @@ IsGCThresholdReached(JSRuntime *rt)
* the gcBytes value is close to zero at the JS engine start.
*/
return rt->gcMallocBytes >= rt->gcMaxMallocBytes ||
rt->gcBytes / rt->gcTriggerFactor >= rt->gcLastBytes / 100;
rt->gcBytes >= rt->gcTriggerBytes;
}
void *
js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes)
template <class T> static JS_INLINE T*
NewGCThing(JSContext *cx, uintN flags)
{
JSRuntime *rt;
uintN flindex;
bool doGC;
JSGCThing *thing;
uint8 *flagp;
@ -1844,8 +1862,9 @@ js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes)
JS_ASSERT((flags & GCF_TYPEMASK) != GCX_DOUBLE);
rt = cx->runtime;
nbytes = JS_ROUNDUP(nbytes, sizeof(JSGCThing));
flindex = GC_FREELIST_INDEX(nbytes);
size_t nbytes = sizeof(T);
JS_ASSERT(JS_ROUNDUP(nbytes, sizeof(JSGCThing)) == nbytes);
uintN flindex = GC_FREELIST_INDEX(nbytes);
/* Updates of metering counters here may not be thread-safe. */
METER(astats = &cx->runtime->gcStats.arenaStats[flindex]);
@ -1856,7 +1875,7 @@ js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes)
JS_ASSERT(cx->thread);
freeLists = cx->gcLocalFreeLists;
thing = freeLists->array[flindex];
localMallocBytes = cx->thread->gcMallocBytes;
localMallocBytes = JS_THREAD_DATA(cx)->gcMallocBytes;
if (thing && rt->gcMaxMallocBytes - rt->gcMallocBytes > localMallocBytes) {
flagp = thing->flagp;
freeLists->array[flindex] = thing->next;
@ -1869,7 +1888,7 @@ js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes)
/* Transfer thread-local counter to global one. */
if (localMallocBytes != 0) {
cx->thread->gcMallocBytes = 0;
JS_THREAD_DATA(cx)->gcMallocBytes = 0;
if (rt->gcMaxMallocBytes - rt->gcMallocBytes < localMallocBytes)
rt->gcMallocBytes = rt->gcMaxMallocBytes;
else
@ -2079,7 +2098,7 @@ testReservedObjects:
if (gcLocked)
JS_UNLOCK_GC(rt);
#endif
return thing;
return (T*)thing;
fail:
#ifdef JS_THREADSAFE
@ -2091,6 +2110,26 @@ fail:
return NULL;
}
extern JSObject* js_NewGCObject(JSContext *cx, uintN flags)
{
return NewGCThing<JSObject>(cx, flags);
}
extern JSString* js_NewGCString(JSContext *cx, uintN flags)
{
return NewGCThing<JSString>(cx, flags);
}
extern JSFunction* js_NewGCFunction(JSContext *cx, uintN flags)
{
return NewGCThing<JSFunction>(cx, flags);
}
extern JSXML* js_NewGCXML(JSContext *cx, uintN flags)
{
return NewGCThing<JSXML>(cx, flags);
}
static JSGCDoubleCell *
RefillDoubleFreeList(JSContext *cx)
{
@ -2284,7 +2323,7 @@ js_ReserveObjects(JSContext *cx, size_t nobjects)
JSObject *&head = JS_TRACE_MONITOR(cx).reservedObjects;
size_t i = head ? JSVAL_TO_INT(head->fslots[1]) : 0;
while (i < nobjects) {
JSObject *obj = (JSObject *) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject));
JSObject *obj = js_NewGCObject(cx, GCX_OBJECT);
if (!obj)
return JS_FALSE;
memset(obj, 0, sizeof(JSObject));
@ -3846,7 +3885,7 @@ out:
goto restart;
}
rt->gcLastBytes = rt->gcBytes;
rt->setGCLastBytes(rt->gcBytes);
done_running:
rt->gcLevel = 0;
rt->gcRunning = JS_FALSE;
@ -3898,17 +3937,3 @@ out:
}
}
}
void
js_UpdateMallocCounter(JSContext *cx, size_t nbytes)
{
uint32 *pbytes, bytes;
#ifdef JS_THREADSAFE
pbytes = &cx->thread->gcMallocBytes;
#else
pbytes = &cx->runtime->gcMallocBytes;
#endif
bytes = *pbytes;
*pbytes = ((uint32)-1 - bytes <= nbytes) ? (uint32)-1 : bytes + nbytes;
}

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

@ -167,8 +167,17 @@ struct JSGCThing {
* can potentially trigger GC. This will ensure that GC tracing never sees junk
* values stored in the partially initialized thing.
*/
extern void *
js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes);
extern JSObject*
js_NewGCObject(JSContext *cx, uintN flags);
extern JSString*
js_NewGCString(JSContext *cx, uintN flags);
extern JSFunction*
js_NewGCFunction(JSContext *cx, uintN flags);
extern JSXML*
js_NewGCXML(JSContext *cx, uintN flags);
/*
* Allocate a new double jsval and store the result in *vp. vp must be a root.
@ -274,10 +283,6 @@ typedef enum JSGCInvocationKind {
extern void
js_GC(JSContext *cx, JSGCInvocationKind gckind);
/* Call this after succesful malloc of memory for GC-related things. */
extern void
js_UpdateMallocCounter(JSContext *cx, size_t nbytes);
typedef struct JSGCArenaInfo JSGCArenaInfo;
typedef struct JSGCArenaList JSGCArenaList;
typedef struct JSGCChunkInfo JSGCChunkInfo;

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

@ -246,7 +246,7 @@ Resize(JSHashTable *ht, uint32 newshift)
}
JS_PUBLIC_API(JSHashEntry *)
JS_HashTableRawAdd(JSHashTable *ht, JSHashEntry **hep,
JS_HashTableRawAdd(JSHashTable *ht, JSHashEntry **&hep,
JSHashNumber keyHash, const void *key, void *value)
{
uint32 n;

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

@ -115,9 +115,11 @@ JS_HashTableDestroy(JSHashTable *ht);
extern JS_PUBLIC_API(JSHashEntry **)
JS_HashTableRawLookup(JSHashTable *ht, JSHashNumber keyHash, const void *key);
#ifdef __cplusplus
extern JS_PUBLIC_API(JSHashEntry *)
JS_HashTableRawAdd(JSHashTable *ht, JSHashEntry **hep, JSHashNumber keyHash,
JS_HashTableRawAdd(JSHashTable *ht, JSHashEntry **&hep, JSHashNumber keyHash,
const void *key, void *value);
#endif
extern JS_PUBLIC_API(void)
JS_HashTableRawRemove(JSHashTable *ht, JSHashEntry **hep, JSHashEntry *he);

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

@ -998,7 +998,7 @@ js_OnUnknownMethod(JSContext *cx, jsval *vp)
}
#endif
obj = js_NewObjectWithGivenProto(cx, &js_NoSuchMethodClass,
NULL, NULL, 0);
NULL, NULL);
if (!obj) {
ok = JS_FALSE;
goto out;
@ -1877,7 +1877,7 @@ js_InvokeConstructor(JSContext *cx, uintN argc, JSBool clampReturn, jsval *vp)
clasp = fun2->u.n.clasp;
}
}
obj = js_NewObject(cx, clasp, proto, parent, 0);
obj = js_NewObject(cx, clasp, proto, parent);
if (!obj)
return JS_FALSE;
@ -4960,8 +4960,7 @@ js_Interpret(JSContext *cx)
JSVAL_IS_OBJECT(rval)
? JSVAL_TO_OBJECT(rval)
: NULL,
OBJ_GET_PARENT(cx, obj),
0);
OBJ_GET_PARENT(cx, obj));
if (!obj2)
goto error;
vp[1] = OBJECT_TO_JSVAL(obj2);
@ -6217,13 +6216,15 @@ js_Interpret(JSContext *cx)
if (!parent)
goto error;
/* If re-parenting, push a clone of the function object. */
if (OBJ_GET_PARENT(cx, obj) != parent) {
/*
* FIXME: bug 471214, Cloning here even when the compiler saw
* the right parent is wasteful but we don't fully support
* joined function objects, yet.
*/
obj = js_CloneFunctionObject(cx, fun, parent);
if (!obj)
goto error;
}
}
PUSH_OPND(OBJECT_TO_JSVAL(obj));
END_CASE(JSOP_LAMBDA)
@ -6372,7 +6373,7 @@ js_Interpret(JSContext *cx)
JS_ASSERT(i == JSProto_Array || i == JSProto_Object);
obj = (i == JSProto_Array)
? js_NewArrayObject(cx, 0, NULL)
: js_NewObject(cx, &js_ObjectClass, NULL, NULL, 0);
: js_NewObject(cx, &js_ObjectClass, NULL, NULL);
if (!obj)
goto error;
PUSH_OPND(OBJECT_TO_JSVAL(obj));

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

@ -388,7 +388,7 @@ js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp)
* we use the parent slot to keep track of the iterable, we must
* fix it up after.
*/
iterobj = js_NewObject(cx, &js_IteratorClass, NULL, NULL, 0);
iterobj = js_NewObject(cx, &js_IteratorClass, NULL, NULL);
if (!iterobj)
goto bad;
@ -705,7 +705,7 @@ js_NewGenerator(JSContext *cx, JSStackFrame *fp)
jsval *slots;
/* After the following return, failing control flow must goto bad. */
obj = js_NewObject(cx, &js_GeneratorClass, NULL, NULL, 0);
obj = js_NewObject(cx, &js_GeneratorClass, NULL, NULL);
if (!obj)
return NULL;

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

@ -2011,29 +2011,6 @@ static JSFunctionSpec object_static_methods[] = {
JS_FS_END
};
JSBool
js_Object(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
if (argc == 0) {
/* Trigger logic below to construct a blank object. */
obj = NULL;
} else {
/* If argv[0] is null or undefined, obj comes back null. */
if (!js_ValueToObject(cx, argv[0], &obj))
return JS_FALSE;
}
if (!obj) {
JS_ASSERT(!argc || JSVAL_IS_NULL(argv[0]) || JSVAL_IS_VOID(argv[0]));
if (JS_IsConstructing(cx))
return JS_TRUE;
obj = js_NewObject(cx, &js_ObjectClass, NULL, NULL, 0);
if (!obj)
return JS_FALSE;
}
*rval = OBJECT_TO_JSVAL(obj);
return JS_TRUE;
}
static inline bool
InitScopeForObject(JSContext* cx, JSObject* obj, JSObject* proto,
JSObjectOps* ops)
@ -2072,7 +2049,7 @@ InitScopeForObject(JSContext* cx, JSObject* obj, JSObject* proto,
/* Let JSScope::create set freeslot so as to reserve slots. */
JS_ASSERT(scope->freeslot >= JSSLOT_PRIVATE);
if (scope->freeslot > JS_INITIAL_NSLOTS &&
!js_ReallocSlots(cx, obj, scope->freeslot, JS_TRUE)) {
!js_AllocSlots(cx, obj, scope->freeslot)) {
JSScope::destroy(cx, scope);
goto bad;
}
@ -2085,13 +2062,156 @@ InitScopeForObject(JSContext* cx, JSObject* obj, JSObject* proto,
return false;
}
JSObject *
js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
JSObject *parent, size_t objectSize)
{
#ifdef INCLUDE_MOZILLA_DTRACE
if (JAVASCRIPT_OBJECT_CREATE_START_ENABLED())
jsdtrace_object_create_start(cx->fp, clasp);
#endif
/* Assert that the class is a proper class. */
JS_ASSERT_IF(clasp->flags & JSCLASS_IS_EXTENDED,
((JSExtendedClass *)clasp)->equality);
/* Always call the class's getObjectOps hook if it has one. */
JSObjectOps *ops = clasp->getObjectOps
? clasp->getObjectOps(cx, clasp)
: &js_ObjectOps;
/*
* Allocate an object from the GC heap and initialize all its fields before
* doing any operation that can potentially trigger GC. Functions have a
* larger non-standard allocation size.
*/
JSObject* obj;
if (clasp == &js_FunctionClass && !objectSize) {
obj = (JSObject*) js_NewGCFunction(cx, GCX_OBJECT);
#ifdef DEBUG
memset((uint8 *) obj + sizeof(JSObject), JS_FREE_PATTERN,
sizeof(JSFunction) - sizeof(JSObject));
#endif
} else {
JS_ASSERT(!objectSize || objectSize == sizeof(JSObject));
obj = js_NewGCObject(cx, GCX_OBJECT);
}
if (!obj)
goto out;
/*
* Set the class slot with the initial value of the system and delegate
* flags set to false.
*/
JS_ASSERT(((jsuword) clasp & 3) == 0);
obj->classword = jsuword(clasp);
JS_ASSERT(!STOBJ_IS_DELEGATE(obj));
JS_ASSERT(!STOBJ_IS_SYSTEM(obj));
obj->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);
/*
* Default parent to the parent of the prototype, which was set from
* the parent of the prototype's constructor.
*/
obj->fslots[JSSLOT_PARENT] = OBJECT_TO_JSVAL((!parent && proto)
? OBJ_GET_PARENT(cx, proto)
: parent);
/* Initialize the remaining fixed slots. */
for (uint32 i = JSSLOT_PRIVATE; i < JS_INITIAL_NSLOTS; ++i)
obj->fslots[i] = JSVAL_VOID;
obj->dslots = NULL;
if (OPS_IS_NATIVE(ops)) {
if (!InitScopeForObject(cx, obj, proto, ops)) {
obj = NULL;
goto out;
}
} else {
JS_ASSERT(ops->objectMap->ops == ops);
obj->map = const_cast<JSObjectMap *>(ops->objectMap);
}
/* Check that the newborn root still holds the object. */
JS_ASSERT_IF(!cx->localRootStack, cx->weakRoots.newborn[GCX_OBJECT] == obj);
/*
* Do not call debug hooks on trace, because we might be in a non-_FAIL
* builtin. See bug 481444.
*/
if (cx->debugHooks->objectHook && !JS_ON_TRACE(cx)) {
JSAutoTempValueRooter tvr(cx, obj);
JS_KEEP_ATOMS(cx->runtime);
cx->debugHooks->objectHook(cx, obj, JS_TRUE,
cx->debugHooks->objectHookData);
JS_UNKEEP_ATOMS(cx->runtime);
cx->weakRoots.newborn[GCX_OBJECT] = obj;
}
out:
#ifdef INCLUDE_MOZILLA_DTRACE
if (JAVASCRIPT_OBJECT_CREATE_ENABLED())
jsdtrace_object_create(cx, clasp, obj);
if (JAVASCRIPT_OBJECT_CREATE_DONE_ENABLED())
jsdtrace_object_create_done(cx->fp, clasp);
#endif
return obj;
}
JSObject *
js_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto,
JSObject *parent, size_t objectSize)
{
jsid id;
/* Bootstrap the ur-object, and make it the default prototype object. */
if (!proto) {
if (!js_GetClassId(cx, clasp, &id))
return NULL;
if (!js_GetClassPrototype(cx, parent, id, &proto))
return NULL;
if (!proto &&
!js_GetClassPrototype(cx, parent, INT_TO_JSID(JSProto_Object),
&proto)) {
return NULL;
}
}
return js_NewObjectWithGivenProto(cx, clasp, proto, parent, objectSize);
}
JSBool
js_Object(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
if (argc == 0) {
/* Trigger logic below to construct a blank object. */
obj = NULL;
} else {
/* If argv[0] is null or undefined, obj comes back null. */
if (!js_ValueToObject(cx, argv[0], &obj))
return JS_FALSE;
}
if (!obj) {
JS_ASSERT(!argc || JSVAL_IS_NULL(argv[0]) || JSVAL_IS_VOID(argv[0]));
if (JS_IsConstructing(cx))
return JS_TRUE;
obj = js_NewObject(cx, &js_ObjectClass, NULL, NULL);
if (!obj)
return JS_FALSE;
}
*rval = OBJECT_TO_JSVAL(obj);
return JS_TRUE;
}
#ifdef JS_TRACER
static inline JSObject*
NewNativeObject(JSContext* cx, JSClass* clasp, JSObject* proto, JSObject *parent)
{
JS_ASSERT(JS_ON_TRACE(cx));
JSObject* obj = (JSObject*) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject));
JSObject* obj = js_NewGCObject(cx, GCX_OBJECT);
if (!obj)
return NULL;
@ -2141,7 +2261,7 @@ js_NewInstance(JSContext *cx, JSClass *clasp, JSObject *ctor)
proto = JSVAL_TO_OBJECT(pval);
} else if (pval == JSVAL_HOLE) {
/* No ctor.prototype yet, inline and optimize fun_resolve's prototype code. */
proto = js_NewObject(cx, clasp, NULL, OBJ_GET_PARENT(cx, ctor), 0);
proto = js_NewObject(cx, clasp, NULL, OBJ_GET_PARENT(cx, ctor));
if (!proto)
return NULL;
if (!js_SetClassPrototype(cx, ctor, proto, JSPROP_ENUMERATE | JSPROP_PERMANENT))
@ -2408,7 +2528,7 @@ js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth)
{
JSObject *obj;
obj = js_NewObject(cx, &js_WithClass, proto, parent, 0);
obj = js_NewObject(cx, &js_WithClass, proto, parent);
if (!obj)
return NULL;
STOBJ_SET_SLOT(obj, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(cx->fp));
@ -2424,7 +2544,7 @@ js_NewBlockObject(JSContext *cx)
* scopes and to give the block object its own scope.
*/
JSObject *blockObj = js_NewObjectWithGivenProto(cx, &js_BlockClass,
NULL, NULL, 0);
NULL, NULL);
JS_ASSERT_IF(blockObj, !OBJ_IS_CLONED_BLOCK(blockObj));
return blockObj;
}
@ -2437,7 +2557,7 @@ js_CloneBlockObject(JSContext *cx, JSObject *proto, JSObject *parent,
JS_ASSERT(STOBJ_GET_CLASS(proto) == &js_BlockClass);
JS_ASSERT(!OBJ_IS_CLONED_BLOCK(proto));
clone = js_NewObject(cx, &js_BlockClass, proto, parent, 0);
clone = js_NewObject(cx, &js_BlockClass, proto, parent);
if (!clone)
return NULL;
STOBJ_SET_SLOT(clone, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(fp));
@ -2489,7 +2609,7 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
if (normalUnwind && count > 1) {
--count;
JS_LOCK_OBJ(cx, obj);
if (!js_ReallocSlots(cx, obj, JS_INITIAL_NSLOTS + count, JS_TRUE))
if (!js_AllocSlots(cx, obj, JS_INITIAL_NSLOTS + count))
normalUnwind = JS_FALSE;
else
memcpy(obj->dslots, fp->slots + depth + 1, count * sizeof(jsval));
@ -2763,7 +2883,7 @@ js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
}
/* Create a prototype object for this class. */
proto = js_NewObject(cx, clasp, parent_proto, obj, 0);
proto = js_NewObject(cx, clasp, parent_proto, obj);
if (!proto)
return NULL;
@ -2864,65 +2984,52 @@ bad:
#define DYNAMIC_WORDS_TO_SLOTS(words) \
(JS_ASSERT((words) > 1), (words) - 1 + JS_INITIAL_NSLOTS)
JSBool
js_ReallocSlots(JSContext *cx, JSObject *obj, uint32 nslots,
JSBool exactAllocation)
{
jsval *old, *slots;
uint32 oslots, nwords, owords, log, i;
bool
js_AllocSlots(JSContext *cx, JSObject *obj, size_t nslots)
{
JS_ASSERT(!obj->dslots);
JS_ASSERT(nslots > JS_INITIAL_NSLOTS);
jsval* slots;
slots = (jsval*) JS_malloc(cx, SLOTS_TO_DYNAMIC_WORDS(nslots) * sizeof(jsval));
if (!slots)
return true;
*slots++ = nslots;
/* clear the newly allocated cells. */
for (jsuint n = JS_INITIAL_NSLOTS; n < nslots; ++n)
slots[n - JS_INITIAL_NSLOTS] = JSVAL_VOID;
obj->dslots = slots;
return true;
}
bool
js_GrowSlots(JSContext *cx, JSObject *obj, size_t nslots)
{
/*
* Minimal number of dynamic slots to allocate.
*/
#define MIN_DYNAMIC_WORDS 4
const size_t MIN_DYNAMIC_WORDS = 4;
/*
* The limit to switch to linear allocation strategy from the power of 2
* growth no to waste too much memory.
*/
#define LINEAR_GROWTH_STEP JS_BIT(16)
const size_t LINEAR_GROWTH_STEP = JS_BIT(16);
old = obj->dslots;
if (nslots <= JS_INITIAL_NSLOTS) {
if (old &&
(exactAllocation ||
SLOTS_TO_DYNAMIC_WORDS((uint32)old[-1]) != MIN_DYNAMIC_WORDS ||
nslots <= (JS_INITIAL_NSLOTS +
JSSLOT_FREE(STOBJ_GET_CLASS(obj))) / 2)) {
/*
* We do not want to free dynamic slots when allocation is a hint,
* we reached minimal allocation and almost all fixed slots are
* used. It avoids allocating dynamic slots again when properties
* are added to the object.
*
* If there were no private or reserved slots, the condition to
* free the slots would be
*
* nslots <= JS_INITIAL_NSLOTS / 2
*
* but to account for never removed slots before JSSLOT_FREE(class)
* we need to subtract it from the slot counts which gives
*
* nslots - JSSLOT_FREE <= (JS_INITIAL_NSLOTS - JSSLOT_FREE) / 2
*
* or
*
* nslots <= (JS_INITIAL_NSLOTS + JSSLOT_FREE) / 2
*/
js_FreeSlots(cx, obj);
}
/* If we are allocating fslots, there is nothing to do. */
if (nslots <= JS_INITIAL_NSLOTS)
return JS_TRUE;
}
oslots = (old) ? (uint32)*--old : JS_INITIAL_NSLOTS;
nwords = SLOTS_TO_DYNAMIC_WORDS(nslots);
size_t nwords = SLOTS_TO_DYNAMIC_WORDS(nslots);
if (nslots > oslots) {
if (!exactAllocation) {
/*
* Round up nslots so the number of bytes in dslots array is power
* of 2 to ensure exponential grouth.
*/
uintN log;
if (nwords <= MIN_DYNAMIC_WORDS) {
nwords = MIN_DYNAMIC_WORDS;
} else if (nwords < LINEAR_GROWTH_STEP) {
@ -2931,58 +3038,51 @@ js_ReallocSlots(JSContext *cx, JSObject *obj, uint32 nslots,
} else {
nwords = JS_ROUNDUP(nwords, LINEAR_GROWTH_STEP);
}
}
slots = (jsval *)JS_realloc(cx, old, nwords * sizeof(jsval));
if (!slots)
return JS_FALSE;
} else {
JS_ASSERT(nslots < oslots);
if (!exactAllocation) {
owords = DYNAMIC_WORDS_TO_SLOTS(oslots);
if (owords <= MIN_DYNAMIC_WORDS)
return JS_TRUE;
if (owords < LINEAR_GROWTH_STEP * 2) {
/*
* Shrink only if 1/4 of slots are left and we need to grow
* the array at least twice to reach the current capacity. It
* prevents frequent capacity growth/shrinking when slots are
* often removed and added.
*/
if (nwords > owords / 4)
return JS_TRUE;
JS_CEILING_LOG2(log, nwords);
nwords = JS_BIT(log);
if (nwords < MIN_DYNAMIC_WORDS)
nwords = MIN_DYNAMIC_WORDS;
} else {
/*
* Shrink only if we free at least 2 linear allocation
* segments, to prevent growth/shrinking resonance.
*/
if (nwords > owords - LINEAR_GROWTH_STEP * 2)
return JS_TRUE;
nwords = JS_ROUNDUP(nwords, LINEAR_GROWTH_STEP);
}
}
/* We avoid JS_realloc not to report a failed shrink attempt. */
slots = (jsval *)realloc(old, nwords * sizeof(jsval));
if (!slots)
slots = old;
}
nslots = DYNAMIC_WORDS_TO_SLOTS(nwords);
*slots++ = (jsval)nslots;
/*
* If nothing was allocated yet, treat it as initial allocation (but with
* the exponential growth algorithm applied).
*/
jsval* slots = obj->dslots;
if (!slots)
return js_AllocSlots(cx, obj, nslots);
size_t oslots = size_t(slots[-1]);
slots = (jsval*) JS_realloc(cx, slots - 1, nwords * sizeof(jsval));
*slots++ = nslots;
obj->dslots = slots;
/* If we're extending an allocation, initialize free slots. */
for (i = oslots; i < nslots; i++)
/* Initialize the additional slots we added. */
JS_ASSERT(nslots > oslots);
for (size_t i = oslots; i < nslots; i++)
slots[i - JS_INITIAL_NSLOTS] = JSVAL_VOID;
return JS_TRUE;
return true;
}
#undef LINEAR_GROWTH_STEP
#undef MIN_DYNAMIC_WORDS
void
js_ShrinkSlots(JSContext *cx, JSObject *obj, size_t nslots)
{
jsval* slots = obj->dslots;
/* Nothing to shrink? */
if (!slots)
return;
JS_ASSERT(size_t(slots[-1]) > JS_INITIAL_NSLOTS);
JS_ASSERT(nslots <= size_t(slots[-1]));
if (nslots <= JS_INITIAL_NSLOTS) {
JS_free(cx, slots - 1);
obj->dslots = NULL;
} else {
size_t nwords = SLOTS_TO_DYNAMIC_WORDS(nslots);
slots = (jsval*) JS_realloc(cx, slots - 1, nwords * sizeof(jsval));
*slots++ = nslots;
obj->dslots = slots;
}
}
extern JSBool
@ -3005,131 +3105,6 @@ js_GetClassId(JSContext *cx, JSClass *clasp, jsid *idp)
return JS_TRUE;
}
JSObject *
js_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent,
uintN objectSize)
{
jsid id;
/* Bootstrap the ur-object, and make it the default prototype object. */
if (!proto) {
if (!js_GetClassId(cx, clasp, &id))
return NULL;
if (!js_GetClassPrototype(cx, parent, id, &proto))
return NULL;
if (!proto &&
!js_GetClassPrototype(cx, parent, INT_TO_JSID(JSProto_Object),
&proto)) {
return NULL;
}
}
return js_NewObjectWithGivenProto(cx, clasp, proto, parent, objectSize);
}
JSObject *
js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
JSObject *parent, uintN objectSize)
{
#ifdef INCLUDE_MOZILLA_DTRACE
if (JAVASCRIPT_OBJECT_CREATE_START_ENABLED())
jsdtrace_object_create_start(cx->fp, clasp);
#endif
/* Currently only functions can have non-standard allocation size. */
if (clasp == &js_FunctionClass) {
if (objectSize == 0)
objectSize = sizeof(JSFunction);
else
JS_ASSERT(objectSize == sizeof(JSObject));
} else {
JS_ASSERT(objectSize == 0);
objectSize = sizeof(JSObject);
}
/* Assert that the class is a proper class. */
JS_ASSERT_IF(clasp->flags & JSCLASS_IS_EXTENDED,
((JSExtendedClass *)clasp)->equality);
/* Always call the class's getObjectOps hook if it has one. */
JSObjectOps *ops = clasp->getObjectOps
? clasp->getObjectOps(cx, clasp)
: &js_ObjectOps;
/*
* Allocate an object from the GC heap and initialize all its fields before
* doing any operation that can potentially trigger GC.
*/
JSObject *obj = (JSObject *) js_NewGCThing(cx, GCX_OBJECT, objectSize);
if (!obj)
goto out;
/*
* Set the class slot with the initial value of the system and delegate
* flags set to false.
*/
JS_ASSERT(((jsuword) clasp & 3) == 0);
obj->classword = jsuword(clasp);
JS_ASSERT(!STOBJ_IS_DELEGATE(obj));
JS_ASSERT(!STOBJ_IS_SYSTEM(obj));
obj->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);
/*
* Default parent to the parent of the prototype, which was set from
* the parent of the prototype's constructor.
*/
obj->fslots[JSSLOT_PARENT] = OBJECT_TO_JSVAL((!parent && proto)
? OBJ_GET_PARENT(cx, proto)
: parent);
/* Initialize the remaining fixed slots. */
for (uint32 i = JSSLOT_PRIVATE; i < JS_INITIAL_NSLOTS; ++i)
obj->fslots[i] = JSVAL_VOID;
obj->dslots = NULL;
if (OPS_IS_NATIVE(ops)) {
if (!InitScopeForObject(cx, obj, proto, ops)) {
obj = NULL;
goto out;
}
} else {
JS_ASSERT(ops->objectMap->ops == ops);
obj->map = const_cast<JSObjectMap *>(ops->objectMap);
}
#ifdef DEBUG
memset((uint8 *) obj + sizeof(JSObject), JS_FREE_PATTERN,
objectSize - sizeof(JSObject));
#endif
/* Check that the newborn root still holds the object. */
JS_ASSERT_IF(!cx->localRootStack, cx->weakRoots.newborn[GCX_OBJECT] == obj);
/*
* Do not call debug hooks on trace, because we might be in a non-_FAIL
* builtin. See bug 481444.
*/
if (cx->debugHooks->objectHook && !JS_ON_TRACE(cx)) {
JSAutoTempValueRooter tvr(cx, obj);
JS_KEEP_ATOMS(cx->runtime);
cx->debugHooks->objectHook(cx, obj, JS_TRUE,
cx->debugHooks->objectHookData);
JS_UNKEEP_ATOMS(cx->runtime);
cx->weakRoots.newborn[GCX_OBJECT] = obj;
}
out:
#ifdef INCLUDE_MOZILLA_DTRACE
if (JAVASCRIPT_OBJECT_CREATE_ENABLED())
jsdtrace_object_create(cx, clasp, obj);
if (JAVASCRIPT_OBJECT_CREATE_DONE_ENABLED())
jsdtrace_object_create_done(cx->fp, clasp);
#endif
return obj;
}
JSObject*
js_NewNativeObject(JSContext *cx, JSClass *clasp, JSObject *proto, uint32 slot)
{
@ -3137,7 +3112,7 @@ js_NewNativeObject(JSContext *cx, JSClass *clasp, JSObject *proto, uint32 slot)
JS_ASSERT(proto->map->ops == &js_ObjectOps);
JS_ASSERT(OBJ_GET_CLASS(cx, proto) == clasp);
JSObject* obj = (JSObject*) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject));
JSObject* obj = js_NewGCObject(cx, GCX_OBJECT);
if (!obj)
return NULL;
@ -3360,7 +3335,7 @@ js_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto,
proto = JSVAL_TO_OBJECT(rval);
}
obj = js_NewObject(cx, clasp, proto, parent, 0);
obj = js_NewObject(cx, clasp, proto, parent);
if (!obj)
goto out;
@ -3413,7 +3388,7 @@ js_AllocSlot(JSContext *cx, JSObject *obj, uint32 *slotp)
}
if (scope->freeslot >= STOBJ_NSLOTS(obj) &&
!js_ReallocSlots(cx, obj, scope->freeslot + 1, JS_FALSE)) {
!js_GrowSlots(cx, obj, scope->freeslot + 1)) {
return JS_FALSE;
}
@ -3430,12 +3405,8 @@ js_FreeSlot(JSContext *cx, JSObject *obj, uint32 slot)
JSScope *scope = OBJ_SCOPE(obj);
LOCKED_OBJ_SET_SLOT(obj, slot, JSVAL_VOID);
if (scope->freeslot == slot + 1) {
if (scope->freeslot == slot + 1)
scope->freeslot = slot;
/* When shrinking, js_ReallocSlots always returns true. */
js_ReallocSlots(cx, obj, slot, JS_FALSE);
}
}
@ -4738,6 +4709,48 @@ js_DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp)
v = save = OBJECT_TO_JSVAL(obj);
switch (hint) {
case JSTYPE_STRING:
/*
* Optimize for String objects with standard toString methods. Support
* new String(...) instances whether mutated to have their own scope or
* not, as well as direct String.prototype references.
*/
if (OBJ_GET_CLASS(cx, obj) == &js_StringClass) {
jsid toStringId = ATOM_TO_JSID(cx->runtime->atomState.toStringAtom);
JS_LOCK_OBJ(cx, obj);
JSScope *scope = OBJ_SCOPE(obj);
JSScopeProperty *sprop = scope->lookup(toStringId);
if (!sprop && scope->object == obj) {
JSObject *proto = LOCKED_OBJ_GET_PROTO(obj);
if (proto && OBJ_GET_CLASS(cx, proto) == &js_StringClass) {
JS_UNLOCK_SCOPE(cx, scope);
JS_LOCK_OBJ(cx, proto);
scope = OBJ_SCOPE(proto);
sprop = scope->lookup(toStringId);
}
}
if (sprop &&
SPROP_HAS_STUB_GETTER(sprop) &&
SPROP_HAS_VALID_SLOT(sprop, scope)) {
jsval fval = LOCKED_OBJ_GET_SLOT(scope->object, sprop->slot);
if (VALUE_IS_FUNCTION(cx, fval)) {
JSObject *funobj = JSVAL_TO_OBJECT(fval);
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
if (FUN_FAST_NATIVE(fun) == js_str_toString) {
JS_UNLOCK_SCOPE(cx, scope);
*vp = obj->fslots[JSSLOT_PRIVATE];
return JS_TRUE;
}
}
}
JS_UNLOCK_SCOPE(cx, scope);
}
/*
* Propagate the exception if js_TryMethod finds an appropriate
* method, and calling that method returned failure.
@ -5447,7 +5460,7 @@ js_PrimitiveToObject(JSContext *cx, jsval *vp)
JS_ASSERT(!JSVAL_IS_OBJECT(*vp));
JS_ASSERT(!JSVAL_IS_VOID(*vp));
clasp = PrimitiveClasses[JSVAL_TAG(*vp) - 1];
obj = js_NewObject(cx, clasp, NULL, NULL, 0);
obj = js_NewObject(cx, clasp, NULL, NULL);
if (!obj)
return JS_FALSE;
STOBJ_SET_SLOT(obj, JSSLOT_PRIVATE, *vp);
@ -5748,6 +5761,13 @@ js_TraceObject(JSTracer *trc, JSObject *obj)
}
if (traceScope) {
if (IS_GC_MARKING_TRACER(trc)) {
/* Check whether we should shrink the object's slots. */
size_t slots = scope->freeslot;
if (STOBJ_NSLOTS(obj) != slots)
js_ShrinkSlots(cx, obj, slots);
}
#ifdef JS_DUMP_SCOPE_METERS
MeterEntryCount(scope->entryCount);
#endif
@ -5880,7 +5900,7 @@ js_SetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot, jsval v)
if (clasp->reserveSlots)
nslots += clasp->reserveSlots(cx, obj);
JS_ASSERT(slot < nslots);
if (!js_ReallocSlots(cx, obj, nslots, JS_TRUE)) {
if (!js_AllocSlots(cx, obj, nslots)) {
JS_UNLOCK_SCOPE(cx, scope);
return JS_FALSE;
}

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

@ -529,18 +529,15 @@ extern JSBool
js_GetClassId(JSContext *cx, JSClass *clasp, jsid *idp);
extern JSObject *
js_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent,
uintN objectSize);
js_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto,
JSObject *parent, size_t objectSize = 0);
/*
* See jsapi.h, JS_NewObjectWithGivenProto.
*
* objectSize is either the explicit size for the allocated object or 0
* indicating to use the default size based on object's class.
*/
extern JSObject *
js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
JSObject *parent, uintN objectSize);
JSObject *parent, size_t objectSize = 0);
/*
* Allocate a new native object and initialize all fslots with JSVAL_VOID
@ -578,14 +575,20 @@ js_AllocSlot(JSContext *cx, JSObject *obj, uint32 *slotp);
extern void
js_FreeSlot(JSContext *cx, JSObject *obj, uint32 slot);
extern bool
js_AllocSlots(JSContext *cx, JSObject *obj, size_t nslots);
extern bool
js_GrowSlots(JSContext *cx, JSObject *obj, size_t nslots);
extern void
js_ShrinkSlots(JSContext *cx, JSObject *obj, size_t nslots);
static inline void
js_FreeSlots(JSContext *cx, JSObject *obj)
{
if (obj->dslots) {
JS_ASSERT((uint32)obj->dslots[-1] > JS_INITIAL_NSLOTS);
JS_free(cx, obj->dslots - 1);
obj->dslots = NULL;
}
if (obj->dslots)
js_ShrinkSlots(cx, obj, 0);
}
extern jsid

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

@ -609,7 +609,7 @@ js_Stringify(JSContext *cx, jsval *vp, JSObject *replacer, jsval space,
if (!InitializeGap(cx, space, &scx.gap))
return JS_FALSE;
JSObject *obj = js_NewObject(cx, &js_ObjectClass, NULL, NULL, 0);
JSObject *obj = js_NewObject(cx, &js_ObjectClass, NULL, NULL);
if (!obj)
return JS_FALSE;
@ -714,7 +714,7 @@ static JSBool
Revive(JSContext *cx, jsval reviver, jsval *vp)
{
JSObject *obj = js_NewObject(cx, &js_ObjectClass, NULL, NULL, 0);
JSObject *obj = js_NewObject(cx, &js_ObjectClass, NULL, NULL);
if (!obj)
return JS_FALSE;
@ -921,7 +921,7 @@ PushObject(JSContext *cx, JSONParser *jp, JSObject *obj)
static JSBool
OpenObject(JSContext *cx, JSONParser *jp)
{
JSObject *obj = js_NewObject(cx, &js_ObjectClass, NULL, NULL, 0);
JSObject *obj = js_NewObject(cx, &js_ObjectClass, NULL, NULL);
if (!obj)
return JS_FALSE;

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

@ -1270,7 +1270,7 @@ Define(JSParseNode *pn, JSAtom *atom, JSTreeContext *tc, bool let = false)
while ((pnu = *pnup) != NULL && pnu->pn_blockid >= start) {
JS_ASSERT(pnu->pn_used);
pnu->pn_lexdef = (JSDefinition *) pn;
pn->pn_dflags |= pnu->pn_dflags & (PND_ASSIGNED | PND_FUNARG);
pn->pn_dflags |= pnu->pn_dflags & PND_USE2DEF_FLAGS;
pnup = &pnu->pn_link;
}
@ -1386,9 +1386,9 @@ MakeDefIntoUse(JSDefinition *dn, JSParseNode *pn, JSAtom *atom, JSTreeContext *t
JS_ASSERT(pnu->pn_used);
JS_ASSERT(!pnu->pn_defn);
pnu->pn_lexdef = (JSDefinition *) pn;
pn->pn_dflags |= pnu->pn_dflags & (PND_ASSIGNED | PND_FUNARG);
pn->pn_dflags |= pnu->pn_dflags & PND_USE2DEF_FLAGS;
}
pn->pn_dflags |= dn->pn_dflags & (PND_ASSIGNED | PND_FUNARG);
pn->pn_dflags |= dn->pn_dflags & PND_USE2DEF_FLAGS;
pn->dn_uses = dn;
dn->pn_defn = false;
@ -3071,7 +3071,7 @@ BindLet(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
*/
uintN slot = JSSLOT_FREE(&js_BlockClass) + n;
if (slot >= STOBJ_NSLOTS(blockObj) &&
!js_ReallocSlots(cx, blockObj, slot + 1, JS_FALSE)) {
!js_GrowSlots(cx, blockObj, slot + 1)) {
return JS_FALSE;
}
OBJ_SCOPE(blockObj)->freeslot = slot + 1;
@ -4335,7 +4335,7 @@ RebindLets(JSParseNode *pn, JSTreeContext *tc)
JSDefinition *dn = ALE_DEFN(ale);
dn->pn_type = TOK_NAME;
dn->pn_op = JSOP_NOP;
dn->pn_dflags |= pn->pn_dflags & (PND_ASSIGNED | PND_FUNARG);
dn->pn_dflags |= pn->pn_dflags & PND_USE2DEF_FLAGS;
}
LinkUseToDef(pn, ALE_DEFN(ale), tc);
}
@ -6403,7 +6403,7 @@ CompExprTransplanter::transplant(JSParseNode *pn)
JSParseNode *pnu;
while ((pnu = *pnup) != NULL && pnu->pn_pos >= root->pn_pos) {
pnu->pn_lexdef = dn2;
dn2->pn_dflags |= pnu->pn_dflags & (PND_ASSIGNED | PND_FUNARG);
dn2->pn_dflags |= pnu->pn_dflags & PND_USE2DEF_FLAGS;
pnup = &pnu->pn_link;
}
dn2->dn_uses = dn->dn_uses;

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

@ -418,6 +418,9 @@ struct JSParseNode {
#define PND_FUNARG 0x100 /* downward or upward funarg usage */
#define PND_BOUND 0x200 /* bound to a stack or global slot */
/* Flags to propagate from uses to definition. */
#define PND_USE2DEF_FLAGS (PND_ASSIGNED | PND_FUNARG)
/* PN_LIST pn_xflags bits. */
#define PNX_STRCAT 0x01 /* TOK_PLUS list has string term */
#define PNX_CANTFOLD 0x02 /* TOK_PLUS list has unfoldable term */

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -172,7 +172,7 @@ JSScope::createTable(JSContext *cx, bool report)
JS_ReportOutOfMemory(cx);
return false;
}
js_UpdateMallocCounter(cx, JS_BIT(sizeLog2) * sizeof(JSScopeProperty *));
cx->updateMallocCounter(JS_BIT(sizeLog2) * sizeof(JSScopeProperty *));
hashShift = JS_DHASH_BITS - sizeLog2;
for (sprop = lastProp; sprop; sprop = sprop->parent) {

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

@ -919,7 +919,7 @@ Script(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
/* If not constructing, replace obj with a new Script object. */
if (!JS_IsConstructing(cx)) {
obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL, 0);
obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL);
if (!obj)
return JS_FALSE;

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

@ -716,8 +716,8 @@ str_toSource(JSContext *cx, uintN argc, jsval *vp)
#endif /* JS_HAS_TOSOURCE */
static JSBool
str_toString(JSContext *cx, uintN argc, jsval *vp)
JSBool
js_str_toString(JSContext *cx, uintN argc, jsval *vp)
{
return js_GetPrimitiveThis(cx, vp, &js_StringClass, vp);
}
@ -2399,7 +2399,7 @@ js_String_getelem(JSContext* cx, JSString* str, int32 i)
}
#endif
JS_DEFINE_TRCINFO_1(str_toString,
JS_DEFINE_TRCINFO_1(js_str_toString,
(2, (extern, STRING_RETRY, String_p_toString, CONTEXT, THIS, 1, 1)))
JS_DEFINE_TRCINFO_1(str_charAt,
(3, (extern, STRING_RETRY, js_String_getelem, CONTEXT, THIS_STRING, INT32, 1, 1)))
@ -2420,9 +2420,10 @@ static JSFunctionSpec string_methods[] = {
#endif
/* Java-like methods. */
JS_TN(js_toString_str, str_toString, 0,JSFUN_THISP_STRING, str_toString_trcinfo),
JS_FN(js_valueOf_str, str_toString, 0,JSFUN_THISP_STRING),
JS_FN(js_toJSON_str, str_toString, 0,JSFUN_THISP_STRING),
JS_TN(js_toString_str, js_str_toString, 0,JSFUN_THISP_STRING,
js_str_toString_trcinfo),
JS_FN(js_valueOf_str, js_str_toString, 0,JSFUN_THISP_STRING),
JS_FN(js_toJSON_str, js_str_toString, 0,JSFUN_THISP_STRING),
JS_FN("substring", str_substring, 2,GENERIC_PRIMITIVE),
JS_FN("toLowerCase", str_toLowerCase, 0,GENERIC_PRIMITIVE),
JS_FN("toUpperCase", str_toUpperCase, 0,GENERIC_PRIMITIVE),
@ -2742,7 +2743,7 @@ js_NewString(JSContext *cx, jschar *chars, size_t length)
return NULL;
}
str = (JSString *) js_NewGCThing(cx, GCX_STRING, sizeof(JSString));
str = js_NewGCString(cx, GCX_STRING);
if (!str)
return NULL;
str->initFlat(chars, length);
@ -2776,7 +2777,7 @@ js_NewDependentString(JSContext *cx, JSString *base, size_t start,
return js_NewStringCopyN(cx, base->chars() + start, length);
}
ds = (JSString *)js_NewGCThing(cx, GCX_STRING, sizeof(JSString));
ds = js_NewGCString(cx, GCX_STRING);
if (!ds)
return NULL;
if (start == 0)
@ -4797,6 +4798,27 @@ const jschar js_uriUnescaped_ucstr[] =
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'-', '_', '.', '!', '~', '*', '\'', '(', ')', 0};
/*
* This table allows efficient testing for the regular expression \w which is
* defined by ECMA-262 15.10.2.6 to be [0-9A-Z_a-z].
*/
const bool js_alnum[] = {
/* 0 1 2 3 4 5 5 7 8 9 */
/* 0 */ false, false, false, false, false, false, false, false, false, false,
/* 1 */ false, false, false, false, false, false, false, false, false, false,
/* 2 */ false, false, false, false, false, false, false, false, false, false,
/* 3 */ false, false, false, false, false, false, false, false, false, false,
/* 4 */ false, false, false, false, false, false, false, false, true, true,
/* 5 */ true, true, true, true, true, true, true, true, false, false,
/* 6 */ false, false, false, false, false, true, true, true, true, true,
/* 7 */ true, true, true, true, true, true, true, true, true, true,
/* 8 */ true, true, true, true, true, true, true, true, true, true,
/* 9 */ true, false, false, false, false, true, false, true, true, true,
/* 10 */ true, true, true, true, true, true, true, true, true, true,
/* 11 */ true, true, true, true, true, true, true, true, true, true,
/* 12 */ true, true, true, false, false, false, false, false
};
#define URI_CHUNK 64U
/* Concatenate jschars onto the buffer */

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

@ -469,11 +469,18 @@ typedef enum JSCharType {
#define JS_ISFORMAT(c) (((1 << JSCT_FORMAT) >> JS_CTYPE(c)) & 1)
/*
* Per ECMA-262 15.10.2.6, these characters are the only ones that make up a
* "word", as far as a RegExp is concerned. If we want a Unicode-friendlier
* definition of "word", we should rename this macro to something regexp-y.
* This table is used in JS_ISWORD. The definition has external linkage to
* allow the raw table data to be used in the regular expression compiler.
*/
#define JS_ISWORD(c) ((c) < 128 && (isalnum(c) || (c) == '_'))
extern const bool js_alnum[];
/*
* This macro performs testing for the regular expression word class \w, which
* is defined by ECMA-262 15.10.2.6 to be [0-9A-Z_a-z]. If we want a
* Unicode-friendlier definition of "word", we should rename this macro to
* something regexp-y.
*/
#define JS_ISWORD(c) ((c) < 128 && js_alnum[(c)])
#define JS_ISIDSTART(c) (JS_ISLETTER(c) || (c) == '_' || (c) == '$')
#define JS_ISIDENT(c) (JS_ISIDPART(c) || (c) == '_' || (c) == '$')
@ -731,6 +738,9 @@ extern JSBool
js_str_escape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval);
extern JSBool
js_str_toString(JSContext *cx, uintN argc, jsval *vp);
extern JSBool
js_StringReplaceHelper(JSContext *cx, uintN argc, JSObject *lambda,
JSString *repstr, jsval *vp);

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

@ -2879,7 +2879,9 @@ TraceRecorder::snapshot(ExitType exitType)
/* Capture the type map into a temporary location. */
unsigned ngslots = treeInfo->globalSlots->length();
unsigned typemap_size = (stackSlots + ngslots) * sizeof(JSTraceType);
JSTraceType* typemap = (JSTraceType*)alloca(typemap_size);
void *mark = JS_ARENA_MARK(&cx->tempPool);
JSTraceType* typemap;
JS_ARENA_ALLOCATE_CAST(typemap, JSTraceType*, &cx->tempPool, typemap_size);
/*
* Determine the type of a store by looking at the current type of the
@ -2927,6 +2929,7 @@ TraceRecorder::snapshot(ExitType exitType)
ngslots == e->numGlobalSlots &&
!memcmp(getFullTypeMap(exits[n]), typemap, typemap_size)) {
AUDIT(mergedLoopExits);
JS_ARENA_RELEASE(&cx->tempPool, mark);
return e;
}
}
@ -2943,6 +2946,7 @@ TraceRecorder::snapshot(ExitType exitType)
*/
stackSlots = 0;
ngslots = 0;
typemap_size = 0;
trashSelf = true;
}
@ -2968,6 +2972,8 @@ TraceRecorder::snapshot(ExitType exitType)
exit->nativeCalleeWord = 0;
exit->lookupFlags = js_InferFlags(cx, 0);
memcpy(getFullTypeMap(exit), typemap, typemap_size);
JS_ARENA_RELEASE(&cx->tempPool, mark);
return exit;
}
@ -3601,7 +3607,7 @@ TraceRecorder::closeLoop(JSTraceMonitor* tm, bool& demote)
}
if (!stable) {
fragment->lastIns = lir->insGuard(LIR_x, lir->insImm(1), createGuardRecord(exit));
fragment->lastIns = lir->insGuard(LIR_x, NULL, createGuardRecord(exit));
/*
* If we didn't find a type stable peer, we compile the loop anyway and
@ -3633,7 +3639,7 @@ TraceRecorder::closeLoop(JSTraceMonitor* tm, bool& demote)
}
} else {
exit->target = fragment->root;
fragment->lastIns = lir->insGuard(LIR_loop, lir->insImm(1), createGuardRecord(exit));
fragment->lastIns = lir->insGuard(LIR_loop, NULL, createGuardRecord(exit));
}
compile(tm);
@ -3760,7 +3766,7 @@ TraceRecorder::endLoop(JSTraceMonitor* tm)
}
fragment->lastIns =
lir->insGuard(LIR_x, lir->insImm(1), createGuardRecord(snapshot(LOOP_EXIT)));
lir->insGuard(LIR_x, NULL, createGuardRecord(snapshot(LOOP_EXIT)));
compile(tm);
if (tm->fragmento->assm()->error() != nanojit::None)
@ -4052,7 +4058,7 @@ nanojit::LirNameMap::formatGuard(LIns *i, char *out)
"%s: %s %s -> pc=%p imacpc=%p sp%+ld rp%+ld",
formatRef(i),
lirNames[i->opcode()],
i->oprnd1()->isCond() ? formatRef(i->oprnd1()) : "",
i->oprnd1() ? formatRef(i->oprnd1()) : "",
(void *)x->pc,
(void *)x->imacpc,
(long int)x->sp_adj,
@ -4196,6 +4202,10 @@ js_TrashTree(JSContext* cx, Fragment* f)
f->releaseCode(fragmento);
Fragment** data = ti->dependentTrees.data();
unsigned length = ti->dependentTrees.length();
for (unsigned n = 0; n < length; ++n)
js_TrashTree(cx, data[n]);
data = ti->linkedTrees.data();
length = ti->linkedTrees.length();
for (unsigned n = 0; n < length; ++n)
js_TrashTree(cx, data[n]);
delete ti;
@ -8572,7 +8582,7 @@ TraceRecorder::emitNativeCall(JSTraceableNative* known, uintN argc, LIns* args[]
// Tell nanojit not to discard or defer stack writes before this call.
LIns* guardRec = createGuardRecord(exit);
lir->insGuard(LIR_xbarrier, guardRec, guardRec);
lir->insGuard(LIR_xbarrier, NULL, guardRec);
}
LIns* res_ins = lir->insCall(known->builtin, args);
@ -10253,7 +10263,7 @@ TraceRecorder::denseArrayElement(jsval& oval, jsval& ival, jsval*& vp, LIns*& v_
dslots_ins,
-(int)sizeof(jsval))),
NULL);
lir->insGuard(LIR_x, lir->insImm(1), createGuardRecord(exit));
lir->insGuard(LIR_x, NULL, createGuardRecord(exit));
LIns* label = lir->ins0(LIR_label);
if (br1)
br1->setTarget(label);

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

@ -238,8 +238,7 @@ public:
}
};
#if defined(_MSC_VER) && _MSC_VER >= 1400 || defined(__GNUC__)
#if defined(_MSC_VER) && _MSC_VER >= 1400 || (defined(__GNUC__) && __GNUC__ >= 4)
#define USE_TRACE_TYPE_ENUM
#endif
@ -269,7 +268,7 @@ enum JSTraceType_
TT_PSEUDOBOOLEAN = 6, /* true, false, or undefined (0, 1, or 2) */
TT_FUNCTION = 7 /* pointer to JSObject whose class is js_FunctionClass */
}
#ifdef __GNUC__
#if defined(__GNUC__) && defined(USE_TRACE_TYPE_ENUM)
__attribute__((packed))
#endif
;

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

@ -203,12 +203,12 @@ class JSTempVector
size_t capacity() const { return mCapacity - mBegin; }
bool empty() const { return mBegin == mEnd; }
T &operator[](int i) {
T &operator[](size_t i) {
JS_ASSERT(!mInProgress && i < size());
return mBegin[i];
}
const T &operator[](int i) const {
const T &operator[](size_t i) const {
JS_ASSERT(!mInProgress && i < size());
return mBegin[i];
}

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

@ -292,7 +292,7 @@ NewXMLNamespace(JSContext *cx, JSString *prefix, JSString *uri, JSBool declared)
{
JSObject *obj;
obj = js_NewObject(cx, &js_NamespaceClass.base, NULL, NULL, 0);
obj = js_NewObject(cx, &js_NamespaceClass.base, NULL, NULL);
if (!obj)
return JS_FALSE;
JS_ASSERT(JSVAL_IS_VOID(obj->fslots[JSSLOT_PREFIX]));
@ -505,7 +505,7 @@ NewXMLQName(JSContext *cx, JSString *uri, JSString *prefix, JSString *localName,
JSObject *obj;
JS_ASSERT(IsQNameClass(clasp));
obj = js_NewObject(cx, clasp, NULL, NULL, 0);
obj = js_NewObject(cx, clasp, NULL, NULL);
if (!obj)
return NULL;
InitXMLQName(obj, uri, prefix, localName);
@ -617,7 +617,7 @@ NamespaceHelper(JSContext *cx, JSObject *obj, intN argc, jsval *argv,
return JS_TRUE;
}
obj = js_NewObject(cx, &js_NamespaceClass.base, NULL, NULL, 0);
obj = js_NewObject(cx, &js_NamespaceClass.base, NULL, NULL);
if (!obj)
return JS_FALSE;
*rval = OBJECT_TO_JSVAL(obj);
@ -724,7 +724,7 @@ QNameHelper(JSContext *cx, JSObject *obj, JSClass *clasp, intN argc,
* Create and return a new QName or AttributeName object exactly as if
* constructed.
*/
obj = js_NewObject(cx, clasp, NULL, NULL, 0);
obj = js_NewObject(cx, clasp, NULL, NULL);
if (!obj)
return JS_FALSE;
*rval = OBJECT_TO_JSVAL(obj);
@ -7317,19 +7317,6 @@ XMLList(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
return JS_TRUE;
}
#define JSXML_LIST_SIZE (offsetof(JSXML, u) + sizeof(struct JSXMLListVar))
#define JSXML_ELEMENT_SIZE (offsetof(JSXML, u) + sizeof(struct JSXMLElemVar))
#define JSXML_LEAF_SIZE (offsetof(JSXML, u) + sizeof(JSString *))
static size_t sizeof_JSXML[JSXML_CLASS_LIMIT] = {
JSXML_LIST_SIZE, /* JSXML_CLASS_LIST */
JSXML_ELEMENT_SIZE, /* JSXML_CLASS_ELEMENT */
JSXML_LEAF_SIZE, /* JSXML_CLASS_ATTRIBUTE */
JSXML_LEAF_SIZE, /* JSXML_CLASS_PROCESSING_INSTRUCTION */
JSXML_LEAF_SIZE, /* JSXML_CLASS_TEXT */
JSXML_LEAF_SIZE /* JSXML_CLASS_COMMENT */
};
#ifdef DEBUG_notme
JSCList xml_leaks = JS_INIT_STATIC_CLIST(&xml_leaks);
uint32 xml_serial;
@ -7340,7 +7327,7 @@ js_NewXML(JSContext *cx, JSXMLClass xml_class)
{
JSXML *xml;
xml = (JSXML *) js_NewGCThing(cx, GCX_XML, sizeof_JSXML[xml_class]);
xml = (JSXML *) js_NewGCXML(cx, GCX_XML);
if (!xml)
return NULL;
@ -7478,7 +7465,7 @@ NewXMLObject(JSContext *cx, JSXML *xml)
{
JSObject *obj;
obj = js_NewObject(cx, &js_XMLClass, NULL, NULL, 0);
obj = js_NewObject(cx, &js_XMLClass, NULL, NULL);
if (!obj || !JS_SetPrivate(cx, obj, xml)) {
cx->weakRoots.newborn[GCX_OBJECT] = NULL;
return NULL;
@ -7881,7 +7868,7 @@ js_GetAnyName(JSContext *cx, jsval *vp)
do {
obj = js_NewObjectWithGivenProto(cx, &js_AnyNameClass, NULL,
NULL, 0);
NULL);
if (!obj) {
ok = JS_FALSE;
break;
@ -8178,7 +8165,7 @@ js_StepXMLListFilter(JSContext *cx, JSBool initialized)
}
filterobj = js_NewObjectWithGivenProto(cx, &js_XMLFilterClass,
NULL, NULL, 0);
NULL, NULL);
if (!filterobj)
return JS_FALSE;

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

@ -122,15 +122,16 @@ struct JSXML {
JSObject *name;
uint16 xml_class; /* discriminates u, below */
uint16 xml_flags; /* flags, see below */
uint32 align;
union {
JSXMLListVar list;
JSXMLElemVar elem;
JSString *value;
} u;
/* Don't add anything after u -- see js_NewXML for why. */
};
JS_STATIC_ASSERT(JS_ROUNDUP(sizeof(JSXML), sizeof(JSGCThing)) == sizeof(JSXML));
/* union member shorthands */
#define xml_kids u.list.kids
#define xml_target u.list.target

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -47,7 +47,7 @@
#if defined(AVMPLUS_UNIX) && defined(AVMPLUS_ARM)
#include <asm/unistd.h>
extern "C" void __clear_cache(char *BEG, char *END);
extern "C" void __clear_cache(void *BEG, void *END);
#endif
#ifdef AVMPLUS_SPARC
@ -255,7 +255,7 @@ namespace nanojit
* they can just be recalculated w/out any inputs.
*/
bool Assembler::canRemat(LIns *i) {
return i->isconst() || i->isconstq() || i->isop(LIR_alloc);
return i->isconst() || i->isconstq() || i->isop(LIR_ialloc);
}
void Assembler::internalReset()
@ -403,7 +403,7 @@ namespace nanojit
Reservation *r = getresv(ins);
NanoAssert(r != 0);
if (r->arIndex) {
if (ins->isop(LIR_alloc)) {
if (ins->isop(LIR_ialloc)) {
int j=i+1;
for (int n = i + (ins->size()>>2); j < n; j++) {
NanoAssert(ar.entry[j]==ins);
@ -495,7 +495,7 @@ namespace nanojit
Register Assembler::getBaseReg(LIns *i, int &d, RegisterMask allow)
{
if (i->isop(LIR_alloc)) {
if (i->isop(LIR_ialloc)) {
d += findMemFor(i);
return FP;
} else {
@ -505,7 +505,7 @@ namespace nanojit
Register Assembler::findRegFor(LIns* i, RegisterMask allow)
{
if (i->isop(LIR_alloc)) {
if (i->isop(LIR_ialloc)) {
// never allocate a reg for this w/out stack space too
findMemFor(i);
}
@ -597,7 +597,7 @@ namespace nanojit
{
int d = disp(resv);
Register rr = resv->reg;
bool quad = i->opcode() == LIR_param || i->isQuad();
bool quad = i->opcode() == LIR_iparam || i->isQuad();
verbose_only( if (d && (_logc->lcbits & LC_RegAlloc)) {
outputForEOL(" <= spill %s",
_thisfrag->lirbuf->names->formatRef(i)); } )
@ -1176,7 +1176,7 @@ namespace nanojit
// allocate some stack space. the value of this instruction
// is the address of the stack space.
case LIR_alloc: {
case LIR_ialloc: {
countlir_alloc();
Reservation *resv = getresv(ins);
NanoAssert(resv->arIndex != 0);
@ -1211,7 +1211,7 @@ namespace nanojit
break;
}
#endif
case LIR_param:
case LIR_iparam:
{
countlir_param();
asm_param(ins);
@ -1278,7 +1278,7 @@ namespace nanojit
#endif
case LIR_add:
case LIR_addp:
case LIR_iaddp:
case LIR_sub:
case LIR_mul:
case LIR_and:
@ -1590,6 +1590,12 @@ namespace nanojit
for (int i=0, n=pending_lives.size(); i < n; i++) {
findMemFor(pending_lives[i]);
}
/*
* TODO: I'm not positive, but I think the following line needs to be
* added, otherwise the pending_lives will build up and never get
* cleared.
*/
pending_lives.clear();
}
void Assembler::arFree(uint32_t idx)
@ -1663,7 +1669,7 @@ namespace nanojit
uint32_t Assembler::arReserve(LIns* l)
{
//verbose_only(printActivationState());
int32_t size = l->isop(LIR_alloc) ? (l->size()>>2) : l->isQuad() ? 2 : sizeof(intptr_t)>>2;
int32_t size = l->isop(LIR_ialloc) ? (l->size()>>2) : l->isQuad() ? 2 : sizeof(intptr_t)>>2;
AR &ar = _activation;
const int32_t tos = ar.tos;
int32_t start = ar.lowwatermark;

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

@ -270,6 +270,14 @@ namespace nanojit
return ins;
}
LInsp LirBufWriter::ins3(LOpcode op, LInsp o1, LInsp o2, LInsp o3)
{
LInsOp3* insOp3 = (LInsOp3*)_buf->makeRoom(sizeof(LInsOp3));
LIns* ins = insOp3->getLIns();
ins->initLInsOp3(op, o1, o2, o3);
return ins;
}
LInsp LirBufWriter::insLoad(LOpcode op, LInsp base, int32_t d)
{
LInsLd* insLd = (LInsLd*)_buf->makeRoom(sizeof(LInsLd));
@ -294,7 +302,7 @@ namespace nanojit
size = (size+3)>>2; // # of required 32bit words
LInsI* insI = (LInsI*)_buf->makeRoom(sizeof(LInsI));
LIns* ins = insI->getLIns();
ins->initLInsI(LIR_alloc, size);
ins->initLInsI(LIR_ialloc, size);
return ins;
}
@ -405,7 +413,7 @@ namespace nanojit
}
iop = ((LInsp)i)->opcode();
}
while (iop==LIR_skip || iop==LIR_2);
while (LIR_skip == iop);
_i = (LInsp)i;
return cur;
}
@ -441,6 +449,11 @@ namespace nanojit
return LRK_Op2 == repKinds[opcode()];
}
bool LIns::isLInsOp3() const {
NanoAssert(LRK_None != repKinds[opcode()]);
return LRK_Op3 == repKinds[opcode()];
}
bool LIns::isLInsLd() const {
NanoAssert(LRK_None != repKinds[opcode()]);
return LRK_Ld == repKinds[opcode()];
@ -647,16 +660,6 @@ namespace nanojit
LIns* ExprFilter::ins2(LOpcode v, LIns* oprnd1, LIns* oprnd2)
{
NanoAssert(oprnd1 && oprnd2);
if (v == LIR_cmov || v == LIR_qcmov) {
if (oprnd2->oprnd1() == oprnd2->oprnd2()) {
// c ? a : a => a
return oprnd2->oprnd1();
}
if (oprnd1->isconst()) {
// const ? x : y => return x or y depending on const
return oprnd1->imm32() ? oprnd2->oprnd1() : oprnd2->oprnd2();
}
}
if (oprnd1 == oprnd2)
{
switch (v) {
@ -779,7 +782,7 @@ namespace nanojit
LIns* t;
switch (v) {
case LIR_add:
case LIR_addp:
case LIR_iaddp:
case LIR_mul:
case LIR_fadd:
case LIR_fmul:
@ -845,7 +848,7 @@ namespace nanojit
if (c == 0) {
switch (v) {
case LIR_add:
case LIR_addp:
case LIR_iaddp:
case LIR_or:
case LIR_xor:
case LIR_sub:
@ -890,6 +893,22 @@ namespace nanojit
return out->ins2(v, oprnd1, oprnd2);
}
LIns* ExprFilter::ins3(LOpcode v, LIns* oprnd1, LIns* oprnd2, LIns* oprnd3)
{
NanoAssert(oprnd1 && oprnd2 && oprnd3);
NanoAssert(v == LIR_cmov || v == LIR_qcmov);
if (oprnd2 == oprnd3) {
// c ? a : a => a
return oprnd2;
}
if (oprnd1->isconst()) {
// const ? x : y => return x or y depending on const
return oprnd1->imm32() ? oprnd2 : oprnd3;
}
return out->ins3(v, oprnd1, oprnd2, oprnd3);
}
LIns* ExprFilter::insGuard(LOpcode v, LInsp c, LInsp x)
{
if (v == LIR_xt || v == LIR_xf) {
@ -906,7 +925,7 @@ namespace nanojit
// so assert in debug builds.
NanoAssertMsg(0, "Constantly false guard detected");
#endif
return out->insGuard(LIR_x, out->insImm(1), x);
return out->insGuard(LIR_x, NULL, x);
}
}
else {
@ -976,7 +995,7 @@ namespace nanojit
}
if (avmplus::AvmCore::use_cmov())
return ins2((iftrue->isQuad() || iffalse->isQuad()) ? LIR_qcmov : LIR_cmov, cond, ins2(LIR_2, iftrue, iffalse));
return ins3((iftrue->isQuad() || iffalse->isQuad()) ? LIR_qcmov : LIR_cmov, cond, iftrue, iffalse);
LInsp ncond = ins1(LIR_neg, cond); // cond ? -1 : 0
return ins2(LIR_or,
@ -1174,7 +1193,9 @@ namespace nanojit
return hashLoad(op, i->oprnd1(), i->disp());
default:
if (operandCount[op] == 2)
if (operandCount[op] == 3)
return hash3(op, i->oprnd1(), i->oprnd2(), i->oprnd3());
else if (operandCount[op] == 2)
return hash2(op, i->oprnd1(), i->oprnd2());
else
return hash1(op, i->oprnd1());
@ -1221,13 +1242,14 @@ namespace nanojit
case LIR_ldq:
case LIR_ldqc:
return
(a->oprnd1() == a->oprnd2() && a->disp() == b->disp() ? true : false );
(a->oprnd1() == b->oprnd1() && a->disp() == b->disp() ? true : false );
default:
{
const uint32_t count = operandCount[op];
if ((count >= 1 && a->oprnd1() != b->oprnd1()) ||
(count >= 2 && a->oprnd2() != b->oprnd2()))
(count >= 2 && a->oprnd2() != b->oprnd2()) ||
(count >= 3 && a->oprnd3() != b->oprnd3()))
return false;
return true;
}
@ -1313,6 +1335,13 @@ namespace nanojit
return _hashfinish(_hashptr(hash, b));
}
uint32_t LInsHashSet::hash3(LOpcode op, LInsp a, LInsp b, LInsp c) {
uint32_t hash = _hash8(0,uint8_t(op));
hash = _hashptr(hash, a);
hash = _hashptr(hash, b);
return _hashfinish(_hashptr(hash, c));
}
uint32_t LInsHashSet::hashLoad(LOpcode op, LInsp a, int32_t d) {
uint32_t hash = _hash8(0,uint8_t(op));
hash = _hashptr(hash, a);
@ -1394,6 +1423,23 @@ namespace nanojit
return k;
}
LInsp LInsHashSet::find3(LOpcode op, LInsp a, LInsp b, LInsp c, uint32_t &i)
{
uint32_t cap = m_cap;
const LInsp *list = m_list;
const uint32_t bitmask = (cap - 1) & ~0x1;
uint32_t hash = hash3(op,a,b,c) & bitmask;
uint32_t n = 7 << 1;
LInsp k;
while ((k = list[hash]) != NULL &&
(k->opcode() != op || k->oprnd1() != a || k->oprnd2() != b || k->oprnd3() != c))
{
hash = (hash + (n += 2)) & bitmask; // quadratic probe
}
i = hash;
return k;
}
LInsp LInsHashSet::findLoad(LOpcode op, LInsp a, int32_t d, uint32_t &i)
{
uint32_t cap = m_cap;
@ -1691,7 +1737,7 @@ namespace nanojit
break;
}
case LIR_alloc: {
case LIR_ialloc: {
sprintf(s, "%s = %s %d", formatRef(i), lirNames[op], i->size());
break;
}
@ -1722,7 +1768,7 @@ namespace nanojit
break;
}
case LIR_param: {
case LIR_iparam: {
uint32_t arg = i->paramArg();
if (!i->paramKind()) {
if (arg < sizeof(Assembler::argRegs)/sizeof(Assembler::argRegs[0])) {
@ -1781,7 +1827,7 @@ namespace nanojit
break;
case LIR_add:
case LIR_addp:
case LIR_iaddp:
case LIR_sub:
case LIR_mul:
case LIR_div:
@ -1914,6 +1960,17 @@ namespace nanojit
return out->ins2(v,a,b);
}
LIns* CseFilter::ins3(LOpcode v, LInsp a, LInsp b, LInsp c)
{
NanoAssert(isCseOpcode(v));
NanoAssert(operandCount[v]==3);
uint32_t k;
LInsp found = exprs.find3(v, a, b, c, k);
if (found)
return found;
return exprs.add(out->ins3(v,a,b,c), k);
}
LIns* CseFilter::insLoad(LOpcode v, LInsp base, int32_t disp)
{
if (isCseOpcode(v)) {

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

@ -51,6 +51,8 @@
*/
namespace nanojit
{
using namespace MMgc;
enum LOpcode
#if defined(_MSC_VER) && _MSC_VER >= 1400
: unsigned
@ -278,6 +280,7 @@ namespace nanojit
LRK_Op0,
LRK_Op1,
LRK_Op2,
LRK_Op3,
LRK_Ld,
LRK_Sti,
LRK_Sk,
@ -332,6 +335,24 @@ namespace nanojit
LIns* getLIns() { return (LIns*)&ins; };
};
// 3-operand form. Used for conditional moves.
class LInsOp3
{
private:
friend class LIns;
LIns* oprnd_3;
LIns* oprnd_2;
LIns* oprnd_1;
void* ins;
public:
LIns* getLIns() { return (LIns*)&ins; };
};
// Used for all loads.
class LInsLd
{
@ -396,7 +417,7 @@ namespace nanojit
LIns* getLIns() { return (LIns*)&ins; };
};
// Used for LIR_param.
// Used for LIR_iparam.
class LInsP
{
private:
@ -411,7 +432,7 @@ namespace nanojit
LIns* getLIns() { return (LIns*)&ins; };
};
// Used for LIR_int and LIR_alloc.
// Used for LIR_int and LIR_ialloc.
class LInsI
{
private:
@ -458,6 +479,7 @@ namespace nanojit
LInsOp0* toLInsOp0() const { return (LInsOp0*)( uintptr_t(this+1) - sizeof(LInsOp0) ); }
LInsOp1* toLInsOp1() const { return (LInsOp1*)( uintptr_t(this+1) - sizeof(LInsOp1) ); }
LInsOp2* toLInsOp2() const { return (LInsOp2*)( uintptr_t(this+1) - sizeof(LInsOp2) ); }
LInsOp3* toLInsOp3() const { return (LInsOp3*)( uintptr_t(this+1) - sizeof(LInsOp3) ); }
LInsLd* toLInsLd() const { return (LInsLd* )( uintptr_t(this+1) - sizeof(LInsLd ) ); }
LInsSti* toLInsSti() const { return (LInsSti*)( uintptr_t(this+1) - sizeof(LInsSti) ); }
LInsSk* toLInsSk() const { return (LInsSk* )( uintptr_t(this+1) - sizeof(LInsSk ) ); }
@ -477,6 +499,7 @@ namespace nanojit
NanoStaticAssert(sizeof(LInsOp0) == 1*sizeof(void*));
NanoStaticAssert(sizeof(LInsOp1) == 2*sizeof(void*));
NanoStaticAssert(sizeof(LInsOp2) == 3*sizeof(void*));
NanoStaticAssert(sizeof(LInsOp3) == 4*sizeof(void*));
NanoStaticAssert(sizeof(LInsLd) == 3*sizeof(void*));
NanoStaticAssert(sizeof(LInsSti) == 4*sizeof(void*));
NanoStaticAssert(sizeof(LInsSk) == 2*sizeof(void*));
@ -489,18 +512,22 @@ namespace nanojit
NanoStaticAssert(sizeof(LInsI64) == 3*sizeof(void*));
#endif
// oprnd_1 must be in the same position in LIns{Op1,Op2,Ld,Sti}
// oprnd_1 must be in the same position in LIns{Op1,Op2,Op3,Ld,Sti}
// because oprnd1() is used for all of them.
NanoStaticAssert( (offsetof(LInsOp1, ins) - offsetof(LInsOp1, oprnd_1)) ==
(offsetof(LInsOp2, ins) - offsetof(LInsOp2, oprnd_1)) );
NanoStaticAssert( (offsetof(LInsOp2, ins) - offsetof(LInsOp2, oprnd_1)) ==
(offsetof(LInsOp3, ins) - offsetof(LInsOp3, oprnd_1)) );
NanoStaticAssert( (offsetof(LInsOp3, ins) - offsetof(LInsOp3, oprnd_1)) ==
(offsetof(LInsLd, ins) - offsetof(LInsLd, oprnd_1)) );
NanoStaticAssert( (offsetof(LInsLd, ins) - offsetof(LInsLd, oprnd_1)) ==
(offsetof(LInsSti, ins) - offsetof(LInsSti, oprnd_1)) );
// oprnd_2 must be in the same position in LIns{Op2,Sti}
// oprnd_2 must be in the same position in LIns{Op2,Op3,Sti}
// because oprnd2() is used for both of them.
NanoStaticAssert( (offsetof(LInsOp2, ins) - offsetof(LInsOp2, oprnd_2)) ==
(offsetof(LInsOp3, ins) - offsetof(LInsOp3, oprnd_2)) );
NanoStaticAssert( (offsetof(LInsOp3, ins) - offsetof(LInsOp3, oprnd_2)) ==
(offsetof(LInsSti, ins) - offsetof(LInsSti, oprnd_2)) );
}
@ -523,6 +550,14 @@ namespace nanojit
toLInsOp2()->oprnd_2 = oprnd2;
NanoAssert(isLInsOp2());
}
void initLInsOp3(LOpcode opcode, LIns* oprnd1, LIns* oprnd2, LIns* oprnd3) {
lastWord.clear();
lastWord.opcode = opcode;
toLInsOp3()->oprnd_1 = oprnd1;
toLInsOp3()->oprnd_2 = oprnd2;
toLInsOp3()->oprnd_3 = oprnd3;
NanoAssert(isLInsOp3());
}
void initLInsLd(LOpcode opcode, LIns* val, int32_t d) {
lastWord.clear();
lastWord.opcode = opcode;
@ -556,7 +591,7 @@ namespace nanojit
}
void initLInsP(int32_t arg, int32_t kind) {
lastWord.clear();
lastWord.opcode = LIR_param;
lastWord.opcode = LIR_iparam;
NanoAssert(isU8(arg) && isU8(kind));
toLInsP()->arg = arg;
toLInsP()->kind = kind;
@ -577,13 +612,17 @@ namespace nanojit
}
LIns* oprnd1() const {
NanoAssert(isLInsOp1() || isLInsOp2() || isLInsLd() || isLInsSti());
NanoAssert(isLInsOp1() || isLInsOp2() || isLInsOp3() || isLInsLd() || isLInsSti());
return toLInsOp2()->oprnd_1;
}
LIns* oprnd2() const {
NanoAssert(isLInsOp2() || isLInsSti());
NanoAssert(isLInsOp2() || isLInsOp3() || isLInsSti());
return toLInsOp2()->oprnd_2;
}
LIns* oprnd3() const {
NanoAssert(isLInsOp3());
return toLInsOp3()->oprnd_3;
}
LIns* prevLIns() const {
NanoAssert(isLInsSk());
@ -591,8 +630,8 @@ namespace nanojit
}
inline LOpcode opcode() const { return lastWord.opcode; }
inline uint8_t paramArg() const { NanoAssert(isop(LIR_param)); return toLInsP()->arg; }
inline uint8_t paramKind() const { NanoAssert(isop(LIR_param)); return toLInsP()->kind; }
inline uint8_t paramArg() const { NanoAssert(isop(LIR_iparam)); return toLInsP()->arg; }
inline uint8_t paramKind() const { NanoAssert(isop(LIR_iparam)); return toLInsP()->kind; }
inline int32_t imm32() const { NanoAssert(isconst()); return toLInsI()->imm32; }
inline int32_t imm64_0() const { NanoAssert(isconstq()); return toLInsI64()->imm64_0; }
inline int32_t imm64_1() const { NanoAssert(isconstq()); return toLInsI64()->imm64_1; }
@ -602,7 +641,7 @@ namespace nanojit
void* payload() const;
inline Page* page() { return (Page*) alignTo(this,NJ_PAGE_SIZE); }
inline int32_t size() const {
NanoAssert(isop(LIR_alloc));
NanoAssert(isop(LIR_ialloc));
return toLInsI()->imm32 << 2;
}
@ -639,6 +678,7 @@ namespace nanojit
bool isLInsOp0() const;
bool isLInsOp1() const;
bool isLInsOp2() const;
bool isLInsOp3() const;
bool isLInsSti() const;
bool isLInsLd() const;
bool isLInsSk() const;
@ -715,7 +755,7 @@ namespace nanojit
class Fragmento; // @todo remove this ; needed for minbuild for some reason?!? Should not be compiling this code at all
// make it a GCObject so we can explicitly delete it early
class LirWriter : public avmplus::GCObject
class LirWriter : public GCObject
{
public:
LirWriter *out;
@ -733,6 +773,9 @@ namespace nanojit
virtual LInsp ins2(LOpcode v, LIns* a, LIns* b) {
return out->ins2(v, a, b);
}
virtual LInsp ins3(LOpcode v, LIns* a, LIns* b, LIns* c) {
return out->ins3(v, a, b, c);
}
virtual LInsp insGuard(LOpcode v, LIns *c, LIns *x) {
return out->insGuard(v, c, x);
}
@ -833,7 +876,7 @@ namespace nanojit
template <class Key>
class CountMap: public avmplus::SortedMap<Key, int, avmplus::LIST_NonGCObjects> {
public:
CountMap(avmplus::GC*gc) : avmplus::SortedMap<Key, int, avmplus::LIST_NonGCObjects>(gc) {}
CountMap(GC*gc) : avmplus::SortedMap<Key, int, avmplus::LIST_NonGCObjects>(gc) {}
int add(Key k) {
int c = 1;
if (containsKey(k)) {
@ -859,7 +902,7 @@ namespace nanojit
void formatImm(int32_t c, char *buf);
public:
LirNameMap(avmplus::GC *gc, LabelMap *r)
LirNameMap(GC *gc, LabelMap *r)
: lircounts(gc),
funccounts(gc),
names(gc),
@ -882,7 +925,7 @@ namespace nanojit
DWB(LirNameMap*) names;
LogControl* logc;
public:
VerboseWriter(avmplus::GC *gc, LirWriter *out,
VerboseWriter(GC *gc, LirWriter *out,
LirNameMap* names, LogControl* logc)
: LirWriter(out), code(gc), names(names), logc(logc)
{}
@ -930,7 +973,10 @@ namespace nanojit
return isRetOpcode(v) ? add_flush(out->ins1(v, a)) : add(out->ins1(v, a));
}
LIns* ins2(LOpcode v, LInsp a, LInsp b) {
return v == LIR_2 ? out->ins2(v,a,b) : add(out->ins2(v, a, b));
return add(out->ins2(v, a, b));
}
LIns* ins3(LOpcode v, LInsp a, LInsp b, LInsp c) {
return add(out->ins3(v, a, b, c));
}
LIns* insCall(const CallInfo *call, LInsp args[]) {
return add_flush(out->insCall(call, args));
@ -963,6 +1009,7 @@ namespace nanojit
ExprFilter(LirWriter *out) : LirWriter(out) {}
LIns* ins1(LOpcode v, LIns* a);
LIns* ins2(LOpcode v, LIns* a, LIns* b);
LIns* ins3(LOpcode v, LIns* a, LIns* b, LIns* c);
LIns* insGuard(LOpcode, LIns *cond, LIns *);
LIns* insBranch(LOpcode, LIns *cond, LIns *target);
};
@ -977,7 +1024,7 @@ namespace nanojit
LInsp *m_list; // explicit WB's are used, no DWB needed.
uint32_t m_used, m_cap;
avmplus::GC* m_gc;
GC* m_gc;
static uint32_t FASTCALL hashcode(LInsp i);
uint32_t FASTCALL find(LInsp name, uint32_t hash, const LInsp *list, uint32_t cap);
@ -985,13 +1032,13 @@ namespace nanojit
void FASTCALL grow();
public:
LInsHashSet(avmplus::GC* gc);
LInsHashSet(GC* gc);
~LInsHashSet();
LInsp find32(int32_t a, uint32_t &i);
LInsp find64(uint64_t a, uint32_t &i);
LInsp find1(LOpcode v, LInsp a, uint32_t &i);
LInsp find2(LOpcode v, LInsp a, LInsp b, uint32_t &i);
LInsp find3(LOpcode v, LInsp a, LInsp b, LInsp c, uint32_t &i);
LInsp findLoad(LOpcode v, LInsp a, int32_t b, uint32_t &i);
LInsp findcall(const CallInfo *call, uint32_t argc, LInsp args[], uint32_t &i);
LInsp add(LInsp i, uint32_t k);
@ -1002,6 +1049,7 @@ namespace nanojit
static uint32_t FASTCALL hashimmq(uint64_t);
static uint32_t FASTCALL hash1(LOpcode v, LInsp);
static uint32_t FASTCALL hash2(LOpcode v, LInsp, LInsp);
static uint32_t FASTCALL hash3(LOpcode v, LInsp, LInsp, LInsp);
static uint32_t FASTCALL hashLoad(LOpcode v, LInsp, int32_t);
static uint32_t FASTCALL hashcall(const CallInfo *call, uint32_t argc, LInsp args[]);
};
@ -1010,18 +1058,19 @@ namespace nanojit
{
public:
LInsHashSet exprs;
CseFilter(LirWriter *out, avmplus::GC *gc);
CseFilter(LirWriter *out, GC *gc);
LIns* insImm(int32_t imm);
LIns* insImmq(uint64_t q);
LIns* ins0(LOpcode v);
LIns* ins1(LOpcode v, LInsp);
LIns* ins2(LOpcode v, LInsp, LInsp);
LIns* ins3(LOpcode v, LInsp, LInsp, LInsp);
LIns* insLoad(LOpcode op, LInsp cond, int32_t d);
LIns* insCall(const CallInfo *call, LInsp args[]);
LIns* insGuard(LOpcode op, LInsp cond, LIns *x);
};
class LirBuffer : public avmplus::GCFinalizedObject
class LirBuffer : public GCFinalizedObject
{
public:
DWB(Fragmento*) _frago;
@ -1075,6 +1124,7 @@ namespace nanojit
LInsp ins0(LOpcode op);
LInsp ins1(LOpcode op, LInsp o1);
LInsp ins2(LOpcode op, LInsp o1, LInsp o2);
LInsp ins3(LOpcode op, LInsp o1, LInsp o2, LInsp o3);
LInsp insParam(int32_t i, int32_t kind);
LInsp insImm(int32_t imm);
LInsp insImmq(uint64_t imm);
@ -1122,18 +1172,18 @@ namespace nanojit
class Assembler;
void compile(Assembler *assm, Fragment *frag);
verbose_only(void live(avmplus::GC *gc, LirBuffer *lirbuf);)
verbose_only(void live(GC *gc, LirBuffer *lirbuf);)
class StackFilter: public LirFilter
{
avmplus::GC *gc;
GC *gc;
LirBuffer *lirbuf;
LInsp sp;
avmplus::BitSet stk;
int top;
int getTop(LInsp br);
public:
StackFilter(LirFilter *in, avmplus::GC *gc, LirBuffer *lirbuf, LInsp sp);
StackFilter(LirFilter *in, GC *gc, LirBuffer *lirbuf, LInsp sp);
virtual ~StackFilter() {}
LInsp read();
};
@ -1154,7 +1204,7 @@ namespace nanojit
LInsHashSet exprs;
void clear(LInsp p);
public:
LoadFilter(LirWriter *out, avmplus::GC *gc)
LoadFilter(LirWriter *out, GC *gc)
: LirWriter(out), exprs(gc) { }
LInsp ins0(LOpcode);

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

@ -77,11 +77,11 @@ OPDEF(unused5, 5,-1, None)
OPDEF(unused6, 6,-1, None)
/* non-pure operations */
OPDEF(addp, 7, 2, Op2) // integer addition for temporary pointer calculations
OPDEF(param, 8, 0, P) // load a parameter
OPDEF(iaddp, 7, 2, Op2) // 32-bit integer addition for temporary pointer calculations
OPDEF(iparam, 8, 0, P) // load a parameter (32-bit register or stack location)
OPDEF(unused9, 9,-1, None)
OPDEF(ld, 10, 1, Ld) // 32-bit load
OPDEF(alloc, 11, 0, I) // alloca some stack space
OPDEF(ialloc, 11, 0, I) // alloca some stack space
OPDEF(sti, 12, 2, Sti) // 32-bit store
OPDEF(ret, 13, 1, Op1) // return a word-sized value
OPDEF(live, 14, 1, Op1) // extend live range of reference
@ -107,7 +107,7 @@ OPDEF(ji, 23,-1, None) // indirect jump (currently not implemented)
*/
OPDEF(int, 24, 0, I) // constant 32-bit integer
OPDEF(cmov, 25, 2, Op2) // conditional move (op1=cond, op2=LIR_2(iftrue,iffalse))
OPDEF(cmov, 25, 3, Op3) // conditional move
#if defined(NANOJIT_64BIT)
OPDEF(callh, 26,-1, None) // unused on 64-bit machines
#else
@ -179,7 +179,8 @@ OPDEF(ugt, 61, 2, Op2) // unsigned integer greater-than (0x3D
OPDEF(ule, 62, 2, Op2) // unsigned integer less-than-or-equal (0x3E 0011 1110)
OPDEF(uge, 63, 2, Op2) // unsigned integer greater-than-or-equal (0x3F 0011 1111)
OPDEF64(2, 0, 2, Op2) // wraps a pair of refs, for LIR_cmov or LIR_qcmov
OPDEF64(unused0_64, 0,-1, None)
OPDEF64(file, 1, 2, Op1) // source filename for debug symbols
OPDEF64(line, 2, 2, Op1) // source line number for debug symbols
OPDEF64(xbarrier, 3, 1, Op2) // memory barrier; doesn't exit, but flushes all values to the stack
@ -216,7 +217,7 @@ OPDEF64(unused23_64, 23,-1, None)
// this marker are subject to CSE.
OPDEF64(quad, LIR_int, 0, I64) // 64-bit (quad) constant value
OPDEF64(qcmov, LIR_cmov, 2, Op2) // 64-bit conditional move
OPDEF64(qcmov, LIR_cmov, 3, Op3) // 64-bit conditional move
OPDEF64(unused26_64, 26,-1, None)
OPDEF64(unused27_64, 27,-1, None)

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -142,7 +142,7 @@ typedef enum {
// an instruction encoding unless the special (ARMv5+) meaning is required.
NV = 0xF // NeVer
} ConditionCode;
#define IsCond(_cc) (((_cc) & 0xf) == (_cc))
#define IsCond(_cc) ( (((_cc) & 0xf) == (_cc)) && ((_cc) != NV) )
// Bit 0 of the condition code can be flipped to obtain the opposite condition.
// However, this won't work for AL because its opposite — NV — has special
@ -192,9 +192,20 @@ verbose_only( extern const char* shiftNames[]; )
#define DECLARE_PLATFORM_REGALLOC()
#ifdef DEBUG
# define DECLARE_PLATFORM_ASSEMBLER_DEBUG() \
inline bool isOp2Imm(uint32_t literal); \
inline uint32_t decOp2Imm(uint32_t enc);
#else
# define DECLARE_PLATFORM_ASSEMBLER_DEBUG()
#endif
#define DECLARE_PLATFORM_ASSEMBLER() \
\
DECLARE_PLATFORM_ASSEMBLER_DEBUG() \
\
const static Register argRegs[4], retRegs[2]; \
void LD32_nochk(Register r, int32_t imm); \
\
void BranchWithLink(NIns*); \
void JMP_far(NIns*); \
void B_cond_chk(ConditionCode, NIns*, bool); \
@ -202,16 +213,20 @@ verbose_only( extern const char* shiftNames[]; )
void nativePageReset(); \
void nativePageSetup(); \
void asm_quad_nochk(Register, int32_t, int32_t); \
void asm_add_imm(Register, Register, int32_t, int stat = 0); \
void asm_sub_imm(Register, Register, int32_t, int stat = 0); \
void asm_cmpi(Register, int32_t imm); \
void asm_ldr_chk(Register d, Register b, int32_t off, bool chk); \
void asm_ld_imm(Register d, int32_t imm); \
void asm_ld_imm(Register d, int32_t imm, bool chk = true); \
void asm_arg(ArgSize sz, LInsp arg, Register& r, int& stkd); \
uint32_t CountLeadingZeroes(uint32_t data); \
int* _nSlot; \
int* _startingSlot; \
int* _nExitSlot;
void asm_add_imm(Register rd, Register rn, int32_t imm, int stat = 0); \
void asm_sub_imm(Register rd, Register rn, int32_t imm, int stat = 0); \
void asm_and_imm(Register rd, Register rn, int32_t imm, int stat = 0); \
void asm_orr_imm(Register rd, Register rn, int32_t imm, int stat = 0); \
void asm_eor_imm(Register rd, Register rn, int32_t imm, int stat = 0); \
inline bool encOp2Imm(uint32_t literal, uint32_t * enc); \
inline uint32_t CountLeadingZeroes(uint32_t data); \
int * _nSlot; \
int * _startingSlot; \
int * _nExitSlot;
//nj_dprintf("jmp_l_n count=%d, nins=%X, %X = %X\n", (_c), nins, _nIns, ((intptr_t)(nins+(_c))-(intptr_t)_nIns - 4) );
@ -228,7 +243,7 @@ verbose_only( extern const char* shiftNames[]; )
#define OP_IMM (1<<25)
#define OP_STAT (1<<20)
#define COND_AL (0xE<<28)
#define COND_AL ((uint32_t)AL<<28)
typedef enum {
LSL_imm = 0, // LSL #c - Logical Shift Left
@ -286,55 +301,33 @@ enum {
// S - bit, 0 or 1, whether the CPSR register is updated
// rd - destination register
// rl - first (left) operand register
// imm - immediate (max 8 bits)
#define ALUi(cond, op, S, rd, rl, imm) do {\
underrunProtect(4);\
// op2imm - operand 2 immediate. Use encOp2Imm (from NativeARM.cpp) to calculate this.
#define ALUi(cond, op, S, rd, rl, op2imm) ALUi_chk(cond, op, S, rd, rl, op2imm, 1)
#define ALUi_chk(cond, op, S, rd, rl, op2imm, chk) do {\
if (chk) underrunProtect(4);\
NanoAssert(IsCond(cond));\
NanoAssert(IsOp(op));\
NanoAssert(((S)==0) || ((S)==1));\
NanoAssert(IsGpReg(rd) && IsGpReg(rl));\
NanoAssert(isU8(imm));\
*(--_nIns) = (NIns) ((cond)<<28 | OP_IMM | (ARM_##op)<<21 | (S)<<20 | (rl)<<16 | (rd)<<12 | (imm));\
NanoAssert(isOp2Imm(op2imm));\
*(--_nIns) = (NIns) ((cond)<<28 | OP_IMM | (ARM_##op)<<21 | (S)<<20 | (rl)<<16 | (rd)<<12 | (op2imm));\
if (ARM_##op == ARM_mov || ARM_##op == ARM_mvn)\
asm_output("%s%s%s %s, #0x%X", #op, condNames[cond], (S)?"s":"", gpn(rd), (imm));\
asm_output("%s%s%s %s, #0x%X", #op, condNames[cond], (S)?"s":"", gpn(rd), decOp2Imm(op2imm));\
else if (ARM_##op >= ARM_tst && ARM_##op <= ARM_cmn) {\
NanoAssert(S==1);\
asm_output("%s%s %s, #0x%X", #op, condNames[cond], gpn(rl), (imm));\
asm_output("%s%s %s, #0x%X", #op, condNames[cond], gpn(rl), decOp2Imm(op2imm));\
} else\
asm_output("%s%s%s %s, %s, #0x%X", #op, condNames[cond], (S)?"s":"", gpn(rd), gpn(rl), (imm));\
asm_output("%s%s%s %s, %s, #0x%X", #op, condNames[cond], (S)?"s":"", gpn(rd), gpn(rl), decOp2Imm(op2imm));\
} while (0)
// ALU operation with register and rotated 8-bit immediate arguments
// S - bit, 0 or 1, whether the CPSR register is updated
// rd - destination register
// rl - first (left) operand register
// imm - immediate (max 8 bits)
// rot - rotation to apply to imm
#define ALUi_rot(cond, op, S, rd, rl, imm, rot) do {\
underrunProtect(4);\
NanoAssert(IsCond(cond));\
NanoAssert(IsOp(op));\
NanoAssert(((S)==0) || ((S)==1));\
NanoAssert(IsGpReg(rd) && IsGpReg(rl));\
NanoAssert(isU8(imm));\
*(--_nIns) = (NIns) ((cond)<<28 | OP_IMM | (ARM_##op)<<21 | (S)<<20 | (rl)<<16 | (rd)<<12 | (rot)<<8 | (imm));\
if (ARM_##op == ARM_mov || ARM_##op == ARM_mvn)\
asm_output("%s%s%s %s, #0x%X, %d", #op, condNames[cond], (S)?"s":"", gpn(rd), (imm), (rot)*2);\
else if (ARM_##op >= ARM_tst && ARM_##op <= ARM_cmn) {\
NanoAssert(S==1);\
asm_output("%s%s %s, #0x%X, %d", #op, condNames[cond], gpn(rl), (imm), (rot)*2);\
} else\
asm_output("%s%s%s %s, %s, #0x%X, %d", #op, condNames[cond], (S)?"s":"", gpn(rd), gpn(rl), (imm), (rot)*2);\
} while (0)
// ALU operation with two register arguments
// S - bit, 0 or 1, whether the CPSR register is updated
// rd - destination register
// rl - first (left) operand register
// rr - first (left) operand register
#define ALUr(cond, op, S, rd, rl, rr) do {\
underrunProtect(4);\
#define ALUr(cond, op, S, rd, rl, rr) ALUr_chk(cond, op, S, rd, rl, rr, 1)
#define ALUr_chk(cond, op, S, rd, rl, rr, chk) do {\
if (chk) underrunProtect(4);\
NanoAssert(IsCond(cond));\
NanoAssert(IsOp(op));\
NanoAssert(((S)==0) || ((S)==1));\
@ -398,41 +391,64 @@ enum {
asm_output("%s%s%s %s, %s, %s, %s %s", #op, condNames[cond], (S)?"s":"", gpn(rd), gpn(rl), gpn(rr), shiftNames[sh], gpn(rs));\
} while (0)
// _d = _l OR _r
// --------
// Basic arithmetic operations.
// --------
// Argument naming conventions for these macros:
// _d Destination register.
// _l First (left) operand.
// _r Second (right) operand.
// _op2imm An operand 2 immediate value. Use encOp2Imm to calculate this.
// _s Set to 1 to update the status flags (for subsequent conditional
// tests). Otherwise, set to 0.
// _d = _l + decOp2Imm(_op2imm)
#define ADDis(_d,_l,_op2imm,_s) ALUi(AL, add, _s, _d, _l, _op2imm)
#define ADDi(_d,_l,_op2imm) ALUi(AL, add, 0, _d, _l, _op2imm)
// _d = _l & ~decOp2Imm(_op2imm)
#define BICis(_d,_l,_op2imm,_s) ALUi(AL, bic, _s, _d, _l, _op2imm)
#define BICi(_d,_l,_op2imm) ALUi(AL, bic, 0, _d, _l, _op2imm)
// _d = _l - decOp2Imm(_op2imm)
#define SUBis(_d,_l,_op2imm,_s) ALUi(AL, sub, _s, _d, _l, _op2imm)
#define SUBi(_d,_l,_op2imm) ALUi(AL, sub, 0, _d, _l, _op2imm)
// _d = _l & decOp2Imm(_op2imm)
#define ANDis(_d,_l,_op2imm,_s) ALUi(AL, and, _s, _d, _l, _op2imm)
#define ANDi(_d,_l,_op2imm) ALUi(AL, and, 0, _d, _l, _op2imm)
// _d = _l | decOp2Imm(_op2imm)
#define ORRis(_d,_l,_op2imm,_s) ALUi(AL, orr, _s, _d, _l, _op2imm)
#define ORRi(_d,_l,_op2imm) ALUi(AL, orr, 0, _d, _l, _op2imm)
// _d = _l ^ decOp2Imm(_op2imm)
#define EORis(_d,_l,_op2imm,_s) ALUi(AL, eor, _s, _d, _l, _op2imm)
#define EORi(_d,_l,_op2imm) ALUi(AL, eor, 0, _d, _l, _op2imm)
// _d = _l | _r
#define ORRs(_d,_l,_r,_s) ALUr(AL, orr, _s, _d, _l, _r)
#define ORR(_d,_l,_r) ALUr(AL, orr, 0, _d, _l, _r)
// _d = _l OR _imm
#define ORRi(_d,_l,_imm) ALUi(AL, orr, 0, _d, _l, _imm)
// _d = _l AND _r
// _d = _l & _r
#define ANDs(_d,_l,_r,_s) ALUr(AL, and, _s, _d, _l, _r)
#define AND(_d,_l,_r) ALUr(AL, and, 0, _d, _l, _r)
// _d = _l AND _imm
#define ANDi(_d,_l,_imm) ALUi(AL, and, 0, _d, _l, _imm)
// _d = _l ^ _r
#define EORs(_d,_l,_r,_s) ALUr(AL, eor, _s, _d, _l, _r)
#define EOR(_d,_l,_r) ALUr(AL, eor, 0, _d, _l, _r)
// _d = _l ^ _imm
#define EORi(_d,_l,_imm) ALUi(AL, eor, 0, _d, _l, _imm)
// _d = _l + _r
#define ADDs(_d,_l,_r,_s) ALUr(AL, add, _s, _d, _l, _r)
#define ADD(_d,_l,_r) ALUr(AL, add, 0, _d, _l, _r)
// _d = _l + _r; update flags
#define ADD(_d,_l,_r) ALUr(AL, add, 1, _d, _l, _r)
// _d = _l - _r
#define SUBs(_d,_l,_r,_s) ALUr(AL, sub, _s, _d, _l, _r)
#define SUB(_d,_l,_r) ALUr(AL, sub, 0, _d, _l, _r)
// _d = _l + _r; update flags if _stat == 1
#define ADDs(_d,_l,_r,_stat) ALUr(AL, add, _stat, _d, _l, _r)
// _d = _l + _imm; update flags
#define ADDi(_d,_l,_imm) asm_add_imm(_d, _l, _imm, 1)
// _d = _l + _imm; update flags if _stat == 1
#define ADDis(_d,_l,_imm,_stat) asm_add_imm(_d, _l, _imm, _stat)
// _d = _l - _r; update flags
#define SUB(_d,_l,_r) ALUr(AL, sub, 1, _d, _l, _r)
// _d = _l - _imm; update flags
#define SUBi(_d,_l,_imm) asm_sub_imm(_d, _l, _imm, 1)
// --------
// Other operations.
// --------
// _d = _l * _r
#define MUL(_d,_l,_r) do { \
@ -448,6 +464,8 @@ enum {
// _d = ~_r (one's compliment)
#define MVN(_d,_r) ALUr(AL, mvn, 0, _d, 0, _r)
#define MVNis_chk(_d,_op2imm,_stat,_chk) ALUi_chk(AL, mvn, _stat, _d, 0, op2imm, _chk)
#define MVNis(_d,_op2imm,_stat) MVNis_chk(_d,_op2imm,_stat,1);
// Logical Shift Right (LSR) rotates the bits without maintaining sign extensions.
// MOVS _d, _r, LSR <_s>
@ -488,6 +506,10 @@ enum {
// MOV
#define MOVis_chk(_d,_op2imm,_stat,_chk) ALUi_chk(AL, mov, _stat, _d, 0, op2imm, _chk)
#define MOVis(_d,_op2imm,_stat) MOVis_chk(_d,_op2imm,_stat,1)
#define MOVi(_d,_op2imm) MOVis(_d,_op2imm,0);
#define MOV_cond(_cond,_d,_s) ALUr(_cond, mov, 0, _d, 0, _s)
#define MOV(dr,sr) MOV_cond(AL, dr, sr)
@ -509,35 +531,38 @@ enum {
#define LDR(_d,_b,_off) asm_ldr_chk(_d,_b,_off,1)
#define LDR_nochk(_d,_b,_off) asm_ldr_chk(_d,_b,_off,0)
// _d = #_imm
#define LDi(_d,_imm) asm_ld_imm(_d,_imm)
// MOVW and MOVT are ARMv6T2 or newer only
// MOVW -- writes _imm into _d, zero-extends.
#define MOVW_cond(_cond,_d,_imm) do { \
NanoAssert(isU16(_imm) || isS16(_imm)); \
underrunProtect(4); \
*(--_nIns) = (NIns)( (_cond)<<28 | 3<<24 | 0<<20 | (((_imm)>>12)&0xf)<<16 | (_d)<<12 | (_imm)&0xfff ); \
#define MOVWi_cond_chk(_cond,_d,_imm,_chk) do { \
NanoAssert(isU16(_imm)); \
NanoAssert(IsGpReg(_d)); \
NanoAssert(IsCond(_cond)); \
if (_chk) underrunProtect(4); \
*(--_nIns) = (NIns)( (_cond)<<28 | 3<<24 | 0<<20 | (((_imm)>>12)&0xf)<<16 | (_d)<<12 | ((_imm)&0xfff) ); \
asm_output("movw%s %s, #0x%x", condNames[_cond], gpn(_d), (_imm)); \
} while (0)
#define MOVW(_d,_imm) MOVW_cond(AL, _d, _imm)
#define MOVWi(_d,_imm) MOVWi_cond_chk(AL, _d, _imm, 1)
#define MOVWi_chk(_d,_imm,_chk) MOVWi_cond_chk(AL, _d, _imm, _chk)
#define MOVWi_cond(_cond,_d,_imm) MOVWi_cond_chk(_cond, _d, _imm, 1)
// MOVT -- writes _imm into top halfword of _d, does not affect bottom halfword
#define MOVT_cond(_cond,_d,_imm) do { \
NanoAssert(isU16(_imm) || isS16(_imm)); \
underrunProtect(4); \
*(--_nIns) = (NIns)( (_cond)<<28 | 3<<24 | 4<<20 | (((_imm)>>12)&0xf)<<16 | (_d)<<12 | (_imm)&0xfff ); \
#define MOVTi_cond_chk(_cond,_d,_imm,_chk) do { \
NanoAssert(isU16(_imm)); \
NanoAssert(IsGpReg(_d)); \
NanoAssert(IsCond(_cond)); \
if (_chk) underrunProtect(4); \
*(--_nIns) = (NIns)( (_cond)<<28 | 3<<24 | 4<<20 | (((_imm)>>12)&0xf)<<16 | (_d)<<12 | ((_imm)&0xfff) ); \
asm_output("movt%s %s, #0x%x", condNames[_cond], gpn(_d), (_imm)); \
} while (0)
#define MOVT(_d,_imm) MOVT_cond(AL, _d, _imm)
#define MOVTi(_d,_imm) MOVTi_cond_chk(AL, _d, _imm, 1)
#define MOVTi_chk(_d,_imm,_chk) MOVTi_cond_chk(AL, _d, _imm, _chk)
#define MOVTi_cond(_cond,_d,_imm) MOVTi_cond_chk(_cond, _d, _imm, 1)
// i386 compat, for Assembler.cpp
#define MR(d,s) MOV(d,s)
#define LD(reg,offset,base) asm_ldr_chk(reg,base,offset,1)
#define ST(base,offset,reg) STR(reg,base,offset)
// Load a byte (8 bits). The offset range is ±4095.
#define LDRB(_d,_n,_off) do { \
@ -553,10 +578,13 @@ enum {
asm_output("ldrb %s, [%s,#%d]", gpn(_d),gpn(_n),(_off)); \
} while(0)
// Load a half word (16 bits). The offset range is ±255, and must be aligned to
// two bytes on some architectures.
// Load and sign-extend a half word (16 bits). The offset range is ±255, and
// must be aligned to two bytes on some architectures, but we never make
// unaligned accesses so a simple assertion is sufficient here.
#define LDRH(_d,_n,_off) do { \
/* TODO: This is actually LDRSH. Is this correct? */ \
NanoAssert(IsGpReg(_d) && IsGpReg(_n)); \
NanoAssert(((_off) & ~1) == (_off)); \
underrunProtect(4); \
if (_off < 0) { \
NanoAssert(isU8(-_off)); \
@ -597,9 +625,16 @@ enum {
asm_output("str %s, [%s]!, %d", gpn(_d), gpn(_n), (_off)); \
} while(0)
// Encode a breakpoint. The ID is not important and is ignored by the
// processor, but it can be useful as a marker when debugging emitted code.
#define BKPT_insn ((NIns)( COND_AL | (0x12<<20) | (0x7<<4) ))
#define BKPT_nochk() do { \
*(--_nIns) = BKPT_insn; } while (0)
#define BKPTi_insn(id) ((NIns)(BKPT_insn | ((id << 4) & 0xfff00) | (id & 0xf)));
#define BKPT_nochk() BKPTi_nochk(0)
#define BKPTi_nochk(id) do { \
NanoAssert((id & 0xffff) == id); \
*(--_nIns) = BKPTi_insn(id); \
} while (0)
// this isn't a armv6t2 NOP -- it's a mov r0,r0
#define NOP_nochk() do { \

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

@ -580,7 +580,7 @@ namespace nanojit
void Assembler::asm_restore(LIns *i, Reservation *resv, Register r) {
int d;
if (i->isop(LIR_alloc)) {
if (i->isop(LIR_ialloc)) {
d = disp(resv);
ADDI(r, FP, d);
}
@ -734,7 +734,7 @@ namespace nanojit
if (rA->reg == UnknownReg) {
// load it into the arg reg
int d = findMemFor(p);
if (p->isop(LIR_alloc)) {
if (p->isop(LIR_ialloc)) {
NanoAssert(isS16(d));
ADDI(r, FP, d);
} else if (p->isQuad()) {
@ -1144,7 +1144,7 @@ namespace nanojit
prefer = rmask(R3);
else if (op == LIR_fcall)
prefer = rmask(F1);
else if (op == LIR_param) {
else if (op == LIR_iparam) {
if (i->imm8() < 8) {
prefer = rmask(argRegs[i->imm8()]);
}

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

@ -282,7 +282,7 @@ namespace nanojit
void Assembler::asm_restore(LInsp i, Reservation *resv, Register r)
{
underrunProtect(24);
if (i->isop(LIR_alloc)) {
if (i->isop(LIR_ialloc)) {
ADD(FP, L2, r);
SET32(disp(resv), L2);
verbose_only(if (_logc->lcbits & LC_RegAlloc) {
@ -323,7 +323,7 @@ namespace nanojit
// make sure what is in a register
Reservation *rA, *rB;
Register ra, rb;
if (base->isop(LIR_alloc)) {
if (base->isop(LIR_ialloc)) {
rb = FP;
dr += findMemFor(base);
ra = findRegFor(value, GpRegs);
@ -364,7 +364,7 @@ namespace nanojit
int dr = disp(resv);
Register rb;
if (base->isop(LIR_alloc)) {
if (base->isop(LIR_ialloc)) {
rb = FP;
db += findMemFor(base);
} else {
@ -414,7 +414,7 @@ namespace nanojit
int da = findMemFor(value);
Register rb;
if (base->isop(LIR_alloc)) {
if (base->isop(LIR_ialloc)) {
rb = FP;
dr += findMemFor(base);
} else {
@ -425,7 +425,7 @@ namespace nanojit
}
Register rb;
if (base->isop(LIR_alloc)) {
if (base->isop(LIR_ialloc)) {
rb = FP;
dr += findMemFor(base);
} else {
@ -649,7 +649,7 @@ namespace nanojit
}
allow &= ~rmask(rb);
}
else if ((op == LIR_add||op == LIR_addp) && lhs->isop(LIR_alloc) && rhs->isconst()) {
else if ((op == LIR_add||op == LIR_iaddp) && lhs->isop(LIR_ialloc) && rhs->isconst()) {
// add alloc+const, use lea
Register rr = prepResultReg(ins, allow);
int d = findMemFor(lhs) + rhs->imm32();
@ -670,7 +670,7 @@ namespace nanojit
if (lhs == rhs)
rb = ra;
if (op == LIR_add || op == LIR_addp)
if (op == LIR_add || op == LIR_iaddp)
ADDCC(rr, rb, rr);
else if (op == LIR_sub)
SUBCC(rr, rb, rr);
@ -694,7 +694,7 @@ namespace nanojit
else
{
int c = rhs->imm32();
if (op == LIR_add || op == LIR_addp) {
if (op == LIR_add || op == LIR_iaddp) {
ADDCC(rr, L2, rr);
} else if (op == LIR_sub) {
SUBCC(rr, L2, rr);
@ -764,14 +764,10 @@ namespace nanojit
underrunProtect(4);
LOpcode op = ins->opcode();
LIns* condval = ins->oprnd1();
LIns* iftrue = ins->oprnd2();
LIns* iffalse = ins->oprnd3();
NanoAssert(condval->isCmp());
LIns* values = ins->oprnd2();
NanoAssert(values->opcode() == LIR_2);
LIns* iftrue = values->oprnd1();
LIns* iffalse = values->oprnd2();
NanoAssert(op == LIR_qcmov || (!iftrue->isQuad() && !iffalse->isQuad()));
const Register rr = prepResultReg(ins, GpRegs);

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

@ -342,7 +342,7 @@ namespace nanojit
else if (op == LIR_fcall) {
prefer &= rmask(FST0);
}
else if (op == LIR_param) {
else if (op == LIR_iparam) {
uint32_t max_regs = max_abi_regs[_thisfrag->lirbuf->abi];
if (i->paramArg() < max_regs)
prefer &= rmask(Register(i->paramArg()));
@ -414,7 +414,7 @@ namespace nanojit
void Assembler::asm_restore(LInsp i, Reservation *resv, Register r)
{
if (i->isop(LIR_alloc)) {
if (i->isop(LIR_ialloc)) {
verbose_only( if (_logc->lcbits & LC_RegAlloc) {
outputForEOL(" <= remat %s size %d",
_thisfrag->lirbuf->names->formatRef(i), i->size()); } )
@ -448,7 +448,7 @@ namespace nanojit
// make sure what is in a register
Reservation *rA, *rB;
Register ra, rb;
if (base->isop(LIR_alloc)) {
if (base->isop(LIR_ialloc)) {
rb = FP;
dr += findMemFor(base);
ra = findRegFor(value, GpRegs);
@ -509,7 +509,7 @@ namespace nanojit
{
int dr = disp(resv);
Register rb;
if (base->isop(LIR_alloc)) {
if (base->isop(LIR_ialloc)) {
rb = FP;
db += findMemFor(base);
} else {
@ -539,7 +539,7 @@ namespace nanojit
// if a constant 64-bit value just store it now rather than
// generating a pointless store/load/store sequence
Register rb;
if (base->isop(LIR_alloc)) {
if (base->isop(LIR_ialloc)) {
rb = FP;
dr += findMemFor(base);
} else {
@ -564,7 +564,7 @@ namespace nanojit
if (config.sse2) {
Register rv = findRegFor(value, XmmRegs);
Register rb;
if (base->isop(LIR_alloc)) {
if (base->isop(LIR_ialloc)) {
rb = FP;
dr += findMemFor(base);
} else {
@ -576,7 +576,7 @@ namespace nanojit
int da = findMemFor(value);
Register rb;
if (base->isop(LIR_alloc)) {
if (base->isop(LIR_ialloc)) {
rb = FP;
dr += findMemFor(base);
} else {
@ -587,7 +587,7 @@ namespace nanojit
}
Register rb;
if (base->isop(LIR_alloc)) {
if (base->isop(LIR_ialloc)) {
rb = FP;
dr += findMemFor(base);
} else {
@ -843,8 +843,8 @@ namespace nanojit
}
break;
case LIR_add:
case LIR_addp:
if (lhs->isop(LIR_alloc) && rhs->isconst()) {
case LIR_iaddp:
if (lhs->isop(LIR_ialloc) && rhs->isconst()) {
// add alloc+const, use lea
Register rr = prepResultReg(ins, allow);
int d = findMemFor(lhs) + rhs->imm32();
@ -879,7 +879,7 @@ namespace nanojit
switch (op) {
case LIR_add:
case LIR_addp:
case LIR_iaddp:
ADD(rr, rb);
break;
case LIR_sub:
@ -919,7 +919,7 @@ namespace nanojit
{
int c = rhs->imm32();
switch (op) {
case LIR_addp:
case LIR_iaddp:
// this doesn't set cc's, only use it when cc's not required.
LEA(rr, c, ra);
ra = rr; // suppress mov
@ -1059,14 +1059,10 @@ namespace nanojit
{
LOpcode op = ins->opcode();
LIns* condval = ins->oprnd1();
LIns* iftrue = ins->oprnd2();
LIns* iffalse = ins->oprnd3();
NanoAssert(condval->isCmp());
LIns* values = ins->oprnd2();
NanoAssert(values->opcode() == LIR_2);
LIns* iftrue = values->oprnd1();
LIns* iffalse = values->oprnd2();
NanoAssert(op == LIR_qcmov || (!iftrue->isQuad() && !iffalse->isQuad()));
const Register rr = prepResultReg(ins, GpRegs);
@ -1302,7 +1298,7 @@ namespace nanojit
if (rA->reg == UnknownReg) {
// load it into the arg reg
int d = findMemFor(p);
if (p->isop(LIR_alloc)) {
if (p->isop(LIR_ialloc)) {
LEA(r, d, FP);
} else {
LD(r, d, FP);
@ -1339,7 +1335,7 @@ namespace nanojit
// small const we push directly
PUSHi(p->imm32());
}
else if (rA == 0 || p->isop(LIR_alloc))
else if (rA == 0 || p->isop(LIR_ialloc))
{
Register ra = findRegFor(p, GpRegs);
PUSHr(ra);

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

@ -68,14 +68,17 @@ namespace nanojit
void RegAlloc::addActive(Register r, LIns* v)
{
// Count++;
NanoAssert(v && r != UnknownReg && active[r] == NULL );
NanoAssert(v);
NanoAssert(r != UnknownReg);
NanoAssert(active[r] == NULL);
active[r] = v;
useActive(r);
}
void RegAlloc::useActive(Register r)
{
NanoAssert(r != UnknownReg && active[r] != NULL);
NanoAssert(r != UnknownReg);
NanoAssert(active[r] != NULL);
usepri[r] = priority++;
}

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

@ -156,7 +156,7 @@ static __inline__ unsigned long long rdtsc(void)
struct JSContext;
namespace avmplus {
namespace MMgc {
class GC;
@ -279,6 +279,7 @@ namespace avmplus {
return &heap;
}
};
}
#define DWB(x) x
#define DRCWB(x) x
@ -287,6 +288,10 @@ namespace avmplus {
#define MMGC_MEM_TYPE(x)
namespace avmplus {
using namespace MMgc;
typedef int FunctionID;
class String

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

@ -3596,7 +3596,7 @@ static JSFunctionSpec shell_functions[] = {
JS_FS("help", Help, 0,0,0),
JS_FS("quit", Quit, 0,0,0),
JS_FN("assertEq", AssertEq, 2,0),
JS_FN("gc", GC, 0,0),
JS_FN("gc", ::GC, 0,0),
JS_FN("gcparam", GCParameter, 2,0),
JS_FN("countHeap", CountHeap, 0,0),
#ifdef JS_GC_ZEAL

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

@ -28,7 +28,7 @@ if (!('gReportSummary' in this))
var testName = null;
if ("arguments" in this && arguments.length > 0)
testName = arguments[0];
var fails = [], passes=[];
var fails = [], passes = [];
function jitstatHandler(f)
{
@ -5406,6 +5406,60 @@ function testDivisionWithNegative1() {
testDivisionWithNegative1.expected = -Infinity;
test(testDivisionWithNegative1);
function testInt32ToId()
{
// Ensure that a property which is a negative integer that does not fit in a
// jsval is properly detected by the 'in' operator.
var obj = { "-1073741828": 17 };
var index = -1073741819;
var a = [];
for (var i = 0; i < 10; i++)
{
a.push(index in obj);
index--;
}
// Ensure that a property which is a negative integer that does not fit in a
// jsval is properly *not* detected by the 'in' operator. In this case
// wrongly applying INT_TO_JSID to -2147483648 will shift off the sign bit
// (the only bit set in that number) and bitwise-or that value with 1,
// producing jsid(1) -- which actually represents "0", not "-2147483648".
// Thus 'in' will report a "-2147483648" property when none exists, because
// it thinks the request was really whether the object had property "0".
var obj2 = { 0: 17 };
var b = [];
var index = -(1 << 28);
for (var i = 0; i < 10; i++)
{
b.push(index in obj2);
index = index - (1 << 28);
}
return a.join(",") + b.join(",");
}
testInt32ToId.expected =
"false,false,false,false,false,false,false,false,false,true" +
"false,false,false,false,false,false,false,false,false,false";
testInt32ToId.jitstats = {
sideExitIntoInterpreter: 2
};
test(testInt32ToId);
function testOwnPropertyWithInOperator()
{
var o = { 0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6 };
var a = [];
for (var i = 0; i < 7; i++)
a.push(i in o);
return a.join(",");
}
testOwnPropertyWithInOperator.expected = "true,true,true,true,true,true,true";
testOwnPropertyWithInOperator.jitstats = {
sideExitIntoInterpreter: 1
};
test(testOwnPropertyWithInOperator);
/*****************************************************************************
* *
* _____ _ _ _____ ______ _____ _______ *

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

@ -984,7 +984,8 @@ CSS_PROP_BORDER(
box_shadow,
MozBoxShadow,
CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
CSS_PROPERTY_VALUE_LIST_USES_COMMAS,
CSS_PROPERTY_VALUE_LIST_USES_COMMAS |
CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED,
Margin,
mBoxShadow,
eCSSType_ValueList,

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

@ -9,7 +9,7 @@
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<style type="text/css">
#one, #three { background: blue; color: yellow; border: thin solid red; -moz-column-rule: 2px solid green; text-shadow: 2px 2px green; }
#one, #three { background: blue; color: yellow; border: thin solid red; -moz-column-rule: 2px solid green; text-shadow: 2px 2px green; -moz-box-shadow: 3px 7px blue; }
#two { background: transparent; border: thin solid; }
#five, #six {border: thick solid red; -moz-border-start-color:green; -moz-border-end-color:blue}
#seven {
@ -93,6 +93,8 @@ function part1()
"-moz-column-rule-color applies");
isnot(cs1.textShadow, cs2.textShadow,
"text-shadow applies");
isnot(cs1.MozBoxShadow, cs2.MozBoxShadow,
"-moz-box-shadow applies");
is(cs1.borderTopColor, cs3.borderTopColor, "border-top-color applies");
is(cs1.borderRightColor, cs3.borderRightColor,
"border-right-color applies");
@ -102,8 +104,10 @@ function part1()
"border-top-color applies");
is(cs1.MozColumnRuleColor, cs3.MozColumnRuleColor,
"-moz-column-rule-color applies");
is(cs1.TextShadow, cs3.TextShadow,
is(cs1.textShadow, cs3.textShadow,
"text-shadow applies");
is(cs1.MozBoxShadow, cs3.MozBoxShadow,
"-moz-box-shadow applies");
isnot(cs5.borderRightColor, cs2.borderRightColor,
"-moz-border-end-color applies");
isnot(cs5.borderLeftColor, cs2.borderLeftColor,
@ -172,8 +176,10 @@ function part2()
"border-bottom-color is blocked");
is(cs1.MozColumnRuleColor, cs2.MozColumnRuleColor,
"-moz-column-rule-color is blocked");
is(cs1.TextShadow, cs2.TextShadow,
is(cs1.textShadow, cs2.textShadow,
"text-shadow is blocked");
is(cs1.MozBoxShadow, cs2.MozBoxShadow,
"-moz-box-shadow is blocked");
is(cs3.backgroundColor, cs1.backgroundColor, "background-color transparency preserved (opaque)");
is(cs3.color, cs4.color, "color is blocked");
is(cs3.borderTopColor, cs4.borderTopColor, "border-top-color is blocked");

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

@ -24,11 +24,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=156716
SimpleTest.waitForExplicitFinish();
var iframe;
function run() {
var subdoc = document.getElementById("subdoc").contentDocument;
var subwin = document.getElementById("subdoc").contentWindow;
iframe = document.getElementById("subdoc");
var subdoc = iframe.contentDocument;
var subwin = iframe.contentWindow;
var style = subdoc.getElementById("style");
var iframe_style = document.getElementById("subdoc").style;
var iframe_style = iframe.style;
var body_cs = subdoc.defaultView.getComputedStyle(subdoc.body, "");
function query_applies(q) {
@ -46,6 +49,16 @@ function run() {
test_serialization(q, true, false);
}
/* for queries that are parseable standalone but not within CSS */
function should_apply_unbalanced(q) {
ok(query_applies(q), q + " should apply");
}
/* for queries that are parseable standalone but not within CSS */
function should_not_apply_unbalanced(q) {
ok(!query_applies(q), q + " should not apply");
}
/*
* Functions to test whether a query is parseable at all. (Should not
* be used for parse errors within expressions.)
@ -107,8 +120,37 @@ function run() {
if (test_application) {
var applies = body_cs.getPropertyValue("text-decoration") == "underline";
is(applies, should_apply,
"Media query '" + q + "' should apply after serialize + reparse");
"Media query '" + q + "' should " + (should_apply ? "" : "NOT ") +
"apply after serialize + reparse");
}
// Test cloning
var sheet = "@media " + q + " { body { text-decoration: underline } }"
var sheeturl = "data:text/css," + escape(sheet);
var link = "<link rel='stylesheet' href='" + sheeturl + "'>";
var htmldoc = "<!DOCTYPE HTML>" + link + link + "<body>";
var docurl = "data:text/html," + escape(htmldoc);
post_clone_test(docurl, function() {
var clonedoc = iframe.contentDocument;
var clonewin = iframe.contentWindow;
var links = clonedoc.getElementsByTagName("link");
// cause a clone
var clonedsheet = links[1].sheet;
clonedsheet.insertRule("#nonexistent { color: purple}", 1);
// remove the uncloned sheet
links[0].parentNode.removeChild(links[0]);
var ser3 = clonedsheet.cssRules[0].media.mediaText;
is(ser3, ser1, "cloning query '" + q + "' should not change " +
"serialization");
if (test_application) {
var applies = clonewin.getComputedStyle(clonedoc.body, "").
textDecoration == "underline";
is(applies, should_apply,
"Media query '" + q + "' should " + (should_apply ? "" : "NOT ") +
"apply after cloning");
}
});
}
// The no-type syntax doesn't mix with the not and only keywords.
@ -152,8 +194,10 @@ function run() {
// in this test, assume the common underlying implementation is correct
var width_val = 117; // pick two not-too-round numbers
var height_val = 76;
change_state(function() {
iframe_style.width = width_val + "px";
iframe_style.height = height_val + "px";
});
var device_width = window.screen.width;
var device_height = window.screen.height;
features = { "width": width_val,
@ -181,24 +225,34 @@ function run() {
(Math.floor(value/em_size) - 1) + "em)");
}
change_state(function() {
iframe_style.width = "0";
});
should_apply("all and (height)");
should_not_apply("all and (width)");
change_state(function() {
iframe_style.height = "0";
});
should_not_apply("all and (height)");
should_not_apply("all and (width)");
should_apply("all and (device-height)");
should_apply("all and (device-width)");
change_state(function() {
iframe_style.width = width_val + "px";
});
should_not_apply("all and (height)");
should_apply("all and (width)");
change_state(function() {
iframe_style.height = height_val + "px";
});
should_apply("all and (height)");
should_apply("all and (width)");
// ratio that reduces to 59/40
change_state(function() {
iframe_style.width = "236px";
iframe_style.height = "160px";
});
expression_should_be_parseable("orientation");
expression_should_be_parseable("orientation: portrait");
expression_should_be_parseable("orientation: landscape");
@ -213,7 +267,9 @@ function run() {
should_not_apply("(orientation: portrait)");
should_apply("not all and (orientation: portrait)");
// ratio that reduces to 59/80
change_state(function() {
iframe_style.height = "320px";
});
should_apply("(orientation)");
should_not_apply("(orientation: landscape)");
should_apply("not all and (orientation: landscape)");
@ -438,16 +494,16 @@ function run() {
// Parsing tests
// bug 454227
should_apply("(orientation");
should_not_apply("not all and (orientation");
should_not_apply("(orientation:");
should_apply("all,(orientation:");
should_not_apply("(orientation:,all");
should_apply("not all and (grid");
should_not_apply("only all and (grid");
should_not_apply("(grid");
should_apply("all,(grid");
should_not_apply("(grid,all");
should_apply_unbalanced("(orientation");
should_not_apply_unbalanced("not all and (orientation");
should_not_apply_unbalanced("(orientation:");
should_apply_unbalanced("all,(orientation:");
should_not_apply_unbalanced("(orientation:,all");
should_apply_unbalanced("not all and (grid");
should_not_apply_unbalanced("only all and (grid");
should_not_apply_unbalanced("(grid");
should_apply_unbalanced("all,(grid");
should_not_apply_unbalanced("(grid,all");
// bug 454226
should_apply(",all");
should_apply("all,");
@ -464,7 +520,57 @@ function run() {
should_not_apply("badmedium,[badsyntax]");
should_not_apply("[badsyntax],badmedium");
handle_posted_items();
}
/*
* The cloning tests have to post tests that wait for onload. However,
* we also make a bunch of state changes during the tests above. So we
* always change state using the change_state call, with both makes the
* change immediately and posts an item in the same queue so that we
* make the same state change again later.
*/
var posted_items = [];
function change_state(func)
{
func();
posted_items.push({state: func});
}
function post_clone_test(docurl, testfunc)
{
posted_items.push({docurl: docurl, testfunc: testfunc});
}
function handle_posted_items()
{
if (posted_items.length == 0) {
SimpleTest.finish();
return;
}
if ("state" in posted_items[0]) {
var item = posted_items.shift();
item.state();
handle_posted_items();
return;
}
var docurl = posted_items[0].docurl;
iframe.onload = handle_iframe_onload;
iframe.src = docurl;
}
function handle_iframe_onload(event)
{
if (event.target != iframe)
return;
var item = posted_items.shift();
item.testfunc();
handle_posted_items();
}
</script>

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

@ -0,0 +1,56 @@
diff --git a/media/liboggplay/src/liboggplay/oggplay_callback.c b/media/liboggplay/src/liboggplay/oggplay_callback.c
--- a/media/liboggplay/src/liboggplay/oggplay_callback.c
+++ b/media/liboggplay/src/liboggplay/oggplay_callback.c
@@ -115,6 +115,15 @@
decoder->y_height = decoder->video_info.frame_height;
decoder->uv_width = decoder->uv_stride = decoder->video_info.frame_width / 2;
decoder->uv_height = decoder->video_info.frame_height / 2;
+
+ if (decoder->y_width == 0 ||
+ decoder->y_height == 0 ||
+ decoder->uv_width == 0 ||
+ decoder->uv_height == 0) {
+ decoder->decoder.active = 0;
+ return 0;
+ }
+
if (--(decoder->remaining_header_packets) == 0) {
/* Ensure the offsets do not push the viewable area outside of the decoded frame. */
if (((decoder->video_info.height - decoder->video_info.offset_y)<decoder->video_info.frame_height)||
diff --git a/media/liboggplay/src/liboggplay/oggplay_data.c b/media/liboggplay/src/liboggplay/oggplay_data.c
--- a/media/liboggplay/src/liboggplay/oggplay_data.c
+++ b/media/liboggplay/src/liboggplay/oggplay_data.c
@@ -317,6 +317,23 @@
}
+static int
+get_uv_offset(OggPlayTheoraDecode *decode, yuv_buffer *buffer)
+{
+ int xo=0, yo = 0;
+ if (decode->y_width != 0 &&
+ decode->uv_width != 0 &&
+ decode->y_width/decode->uv_width != 0) {
+ xo = (decode->video_info.offset_x/(decode->y_width/decode->uv_width));
+ }
+ if (decode->y_height != 0 &&
+ decode->uv_height != 0 &&
+ decode->y_height/decode->uv_height != 0) {
+ yo = (buffer->uv_stride)*(decode->video_info.offset_y/(decode->y_height/decode->uv_height));
+ }
+ return xo + yo;
+}
+
void
oggplay_data_handle_theora_frame (OggPlayTheoraDecode *decode,
yuv_buffer *buffer) {
@@ -367,8 +384,7 @@
q += buffer->y_stride;
}
- uv_offset = (decode->video_info.offset_x/(decode->y_width/decode->uv_width)) +
- (buffer->uv_stride) *(decode->video_info.offset_y/(decode->y_height/decode->uv_height));
+ uv_offset = get_uv_offset(decode, buffer);
p = data->u;
q = buffer->u + uv_offset;

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

@ -115,6 +115,15 @@ oggplay_callback_theora (OGGZ * oggz, ogg_packet * op, long serialno,
decoder->y_height = decoder->video_info.frame_height;
decoder->uv_width = decoder->uv_stride = decoder->video_info.frame_width / 2;
decoder->uv_height = decoder->video_info.frame_height / 2;
if (decoder->y_width == 0 ||
decoder->y_height == 0 ||
decoder->uv_width == 0 ||
decoder->uv_height == 0) {
decoder->decoder.active = 0;
return 0;
}
if (--(decoder->remaining_header_packets) == 0) {
/* Ensure the offsets do not push the viewable area outside of the decoded frame. */
if (((decoder->video_info.height - decoder->video_info.offset_y)<decoder->video_info.frame_height)||

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

@ -317,6 +317,23 @@ oggplay_data_handle_cmml_data(OggPlayDecode *decode, unsigned char *data,
}
static int
get_uv_offset(OggPlayTheoraDecode *decode, yuv_buffer *buffer)
{
int xo=0, yo = 0;
if (decode->y_width != 0 &&
decode->uv_width != 0 &&
decode->y_width/decode->uv_width != 0) {
xo = (decode->video_info.offset_x/(decode->y_width/decode->uv_width));
}
if (decode->y_height != 0 &&
decode->uv_height != 0 &&
decode->y_height/decode->uv_height != 0) {
yo = (buffer->uv_stride)*(decode->video_info.offset_y/(decode->y_height/decode->uv_height));
}
return xo + yo;
}
void
oggplay_data_handle_theora_frame (OggPlayTheoraDecode *decode,
yuv_buffer *buffer) {
@ -367,8 +384,7 @@ oggplay_data_handle_theora_frame (OggPlayTheoraDecode *decode,
q += buffer->y_stride;
}
uv_offset = (decode->video_info.offset_x/(decode->y_width/decode->uv_width)) +
(buffer->uv_stride) *(decode->video_info.offset_y/(decode->y_height/decode->uv_height));
uv_offset = get_uv_offset(decode, buffer);
p = data->u;
q = buffer->u + uv_offset;

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

@ -62,3 +62,4 @@ patch -p3 < bug487519.patch
patch -p3 < bug498815.patch
patch -p3 < bug498824.patch
patch -p3 < bug496529.patch
patch -p3 < bug499519.patch

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

@ -48,7 +48,7 @@ interface nsIAuthInformation;
* It can be used to prompt users for authentication information, either
* synchronously or asynchronously.
*/
[scriptable, uuid(447fc780-1d28-412a-91a1-466d48129c65)]
[scriptable, uuid(651395EB-8612-4876-8AC0-A88D4DCE9E1E)]
interface nsIAuthPrompt2 : nsISupports
{
/** @name Security Levels */
@ -110,9 +110,23 @@ interface nsIAuthPrompt2 : nsISupports
* dialog and MUST call nsIAuthPromptCallback::onAuthCancelled on the provided
* callback.
*
* @throw NS_ERROR_NOT_IMPLEMENTED
* Asynchronous authentication prompts are not supported;
* the caller should fall back to promptUsernameAndPassword().
* This implementation may:
*
* 1) Coalesce identical prompts. This means prompts that are guaranteed to
* want the same auth information from the user. A single prompt will be
* shown; then the callbacks for all the coalesced prompts will be notified
* with the resulting auth information.
* 2) Serialize prompts that are all in the same "context" (this might mean
* application-wide, for a given window, or something else depending on
* the user interface) so that the user is not deluged with prompts.
*
* @throw
* This method may throw any exception when the prompt fails to queue e.g
* because of out-of-memory error. It must not throw when the prompt
* could already be potentially shown to the user. In that case information
* about the failure has to come through the callback. This way we
* prevent multiple dialogs shown to the user because consumer may fall
* back to synchronous prompt on synchronous failure of this method.
*/
nsICancelable asyncPromptAuth(in nsIChannel aChannel,
in nsIAuthPromptCallback aCallback,
@ -120,5 +134,3 @@ interface nsIAuthPrompt2 : nsISupports
in PRUint32 level,
in nsIAuthInformation authInfo);
};

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

@ -83,6 +83,7 @@
#include "nsAuthInformationHolder.h"
#include "nsICacheService.h"
#include "nsDNSPrefetch.h"
#include "nsNetSegmentUtils.h"
// True if the local cache should be bypassed when processing a request.
#define BYPASS_LOCAL_CACHE(loadFlags) \
@ -125,6 +126,7 @@ nsHttpChannel::nsHttpChannel()
, mTransactionReplaced(PR_FALSE)
, mUploadStreamHasHeaders(PR_FALSE)
, mAuthRetryPending(PR_FALSE)
, mProxyAuth(PR_FALSE)
, mSuppressDefensiveAuth(PR_FALSE)
, mResuming(PR_FALSE)
, mInitedCacheEntry(PR_FALSE)
@ -849,8 +851,32 @@ nsHttpChannel::CallOnStartRequest()
// install stream converter if required
rv = ApplyContentConversions();
if (NS_FAILED(rv)) return rv;
return rv;
if (!mCanceled) {
// create offline cache entry if offline caching was requested
if (mCacheForOfflineUse) {
PRBool shouldCacheForOfflineUse;
rv = ShouldUpdateOfflineCacheEntry(&shouldCacheForOfflineUse);
if (NS_FAILED(rv)) return rv;
if (shouldCacheForOfflineUse) {
LOG(("writing to the offline cache"));
rv = InitOfflineCacheEntry();
if (NS_FAILED(rv)) return rv;
if (mOfflineCacheEntry) {
rv = InstallOfflineCacheListener();
if (NS_FAILED(rv)) return rv;
}
} else {
LOG(("offline cache is up to date, not updating"));
CloseOfflineCacheEntry();
}
}
}
return NS_OK;
}
nsresult
@ -1134,28 +1160,8 @@ nsHttpChannel::ProcessNormal()
rv = InstallCacheListener();
if (NS_FAILED(rv)) return rv;
}
// create offline cache entry if offline caching was requested
if (mCacheForOfflineUse) {
PRBool shouldCacheForOfflineUse;
rv = ShouldUpdateOfflineCacheEntry(&shouldCacheForOfflineUse);
if (NS_FAILED(rv)) return rv;
if (shouldCacheForOfflineUse) {
LOG(("writing to the offline cache"));
rv = InitOfflineCacheEntry();
if (NS_FAILED(rv)) return rv;
if (mOfflineCacheEntry) {
rv = InstallOfflineCacheListener();
if (NS_FAILED(rv)) return rv;
}
} else {
LOG(("offline cache is up to date, not updating"));
CloseOfflineCacheEntry();
}
}
return rv;
return NS_OK;
}
nsresult
@ -2358,27 +2364,6 @@ nsHttpChannel::ReadFromCache()
}
}
// set up the offline cache entry for writing
if (mCacheForOfflineUse) {
PRBool shouldUpdateOffline;
rv = ShouldUpdateOfflineCacheEntry(&shouldUpdateOffline);
if (NS_FAILED(rv)) return rv;
if (shouldUpdateOffline) {
LOG(("writing to the offline cache"));
rv = InitOfflineCacheEntry();
if (NS_FAILED(rv)) return rv;
if (mOfflineCacheEntry) {
rv = InstallOfflineCacheListener();
if (NS_FAILED(rv)) return rv;
}
} else {
LOG(("offline cache is up to date, not updating"));
CloseOfflineCacheEntry();
}
}
// open input stream for reading...
nsCOMPtr<nsIInputStream> stream;
rv = mCacheEntry->OpenInputStream(0, getter_AddRefs(stream));
@ -3134,13 +3119,13 @@ nsHttpChannel::ProcessAuthentication(PRUint32 httpStatus)
}
const char *challenges;
PRBool proxyAuth = (httpStatus == 407);
mProxyAuth = (httpStatus == 407);
nsresult rv = PrepareForAuthentication(proxyAuth);
nsresult rv = PrepareForAuthentication(mProxyAuth);
if (NS_FAILED(rv))
return rv;
if (proxyAuth) {
if (mProxyAuth) {
// only allow a proxy challenge if we have a proxy server configured.
// otherwise, we could inadvertantly expose the user's proxy
// credentials to an origin server. We could attempt to proceed as
@ -3165,12 +3150,24 @@ nsHttpChannel::ProcessAuthentication(PRUint32 httpStatus)
NS_ENSURE_TRUE(challenges, NS_ERROR_UNEXPECTED);
nsCAutoString creds;
rv = GetCredentials(challenges, proxyAuth, creds);
if (NS_FAILED(rv))
rv = GetCredentials(challenges, mProxyAuth, creds);
if (rv == NS_ERROR_IN_PROGRESS) {
// authentication prompt has been invoked and result
// is expected asynchronously
mAuthRetryPending = PR_TRUE;
// suspend the transaction pump to stop receiving the
// unauthenticated content data. We will throw that data
// away when user provides credentials or resume the pump
// when user refuses to authenticate.
LOG(("Suspending the transaction, asynchronously prompting for credentials"));
mTransactionPump->Suspend();
return NS_OK;
}
else if (NS_FAILED(rv))
LOG(("unable to authenticate\n"));
else {
// set the authentication credentials
if (proxyAuth)
if (mProxyAuth)
mRequestHead.SetHeader(nsHttp::Proxy_Authorization, creds);
else
mRequestHead.SetHeader(nsHttp::Authorization, creds);
@ -3297,6 +3294,15 @@ nsHttpChannel::GetCredentials(const char *challenges,
break;
}
else if (rv == NS_ERROR_IN_PROGRESS) {
// authentication prompt has been invoked and result is
// expected asynchronously, save current challenge being
// processed and all remaining challenges to use later in
// OnAuthAvailable and now immediately return
mCurrentChallenge = challenge;
mRemainingChallenges = eol ? eol+1 : nsnull;
return rv;
}
// reset the auth type and continuation state
NS_IF_RELEASE(*currentContinuationState);
@ -3316,6 +3322,43 @@ nsHttpChannel::GetCredentials(const char *challenges,
return rv;
}
nsresult
nsHttpChannel::GetAuthorizationMembers(PRBool proxyAuth,
nsCSubstring& scheme,
const char*& host,
PRInt32& port,
nsCSubstring& path,
nsHttpAuthIdentity*& ident,
nsISupports**& continuationState)
{
if (proxyAuth) {
NS_ASSERTION (mConnectionInfo->UsingHttpProxy(), "proxyAuth is true, but no HTTP proxy is configured!");
host = mConnectionInfo->ProxyHost();
port = mConnectionInfo->ProxyPort();
ident = &mProxyIdent;
scheme.AssignLiteral("http");
continuationState = &mProxyAuthContinuationState;
}
else {
host = mConnectionInfo->Host();
port = mConnectionInfo->Port();
ident = &mIdent;
nsresult rv;
rv = GetCurrentPath(path);
if (NS_FAILED(rv)) return rv;
rv = mURI->GetScheme(scheme);
if (NS_FAILED(rv)) return rv;
continuationState = &mAuthContinuationState;
}
return NS_OK;
}
nsresult
nsHttpChannel::GetCredentialsForChallenge(const char *challenge,
const char *authType,
@ -3357,35 +3400,16 @@ nsHttpChannel::GetCredentialsForChallenge(const char *challenge,
PRBool identFromURI = PR_FALSE;
nsISupports **continuationState;
if (proxyAuth) {
NS_ASSERTION (mConnectionInfo->UsingHttpProxy(), "proxyAuth is true, but no HTTP proxy is configured!");
host = mConnectionInfo->ProxyHost();
port = mConnectionInfo->ProxyPort();
ident = &mProxyIdent;
scheme.AssignLiteral("http");
continuationState = &mProxyAuthContinuationState;
}
else {
host = mConnectionInfo->Host();
port = mConnectionInfo->Port();
ident = &mIdent;
rv = GetCurrentPath(path);
if (NS_FAILED(rv)) return rv;
rv = mURI->GetScheme(scheme);
rv = GetAuthorizationMembers(proxyAuth, scheme, host, port, path, ident, continuationState);
if (NS_FAILED(rv)) return rv;
if (!proxyAuth) {
// if this is the first challenge, then try using the identity
// specified in the URL.
if (mIdent.IsEmpty()) {
GetIdentityFromURI(authFlags, mIdent);
identFromURI = !mIdent.IsEmpty();
}
continuationState = &mAuthContinuationState;
}
//
@ -3639,25 +3663,165 @@ nsHttpChannel::PromptForIdentity(PRUint32 level,
nsDependentCString(authType));
if (!holder)
return NS_ERROR_OUT_OF_MEMORY;
rv = authPrompt->AsyncPromptAuth(this, this, nsnull, level, holder,
getter_AddRefs(mAsyncPromptAuthCancelable));
if (NS_SUCCEEDED(rv)) {
// indicate using this error code that authentication prompt
// result is expected asynchronously
rv = NS_ERROR_IN_PROGRESS;
}
else {
// Fall back to synchronous prompt
PRBool retval = PR_FALSE;
rv = authPrompt->PromptAuth(this,
level,
holder, &retval);
rv = authPrompt->PromptAuth(this, level, holder, &retval);
if (NS_FAILED(rv))
return rv;
// remember that we successfully showed the user an auth dialog
if (!proxyAuth)
mSuppressDefensiveAuth = PR_TRUE;
if (!retval)
rv = NS_ERROR_ABORT;
else
holder->SetToHttpAuthIdentity(authFlags, ident);
}
// remember that we successfully showed the user an auth dialog
if (!proxyAuth)
mSuppressDefensiveAuth = PR_TRUE;
return rv;
}
NS_IMETHODIMP nsHttpChannel::OnAuthAvailable(nsISupports *aContext,
nsIAuthInformation *aAuthInfo)
{
LOG(("nsHttpChannel::OnAuthAvailable [this=%x]", this));
mAsyncPromptAuthCancelable = nsnull;
nsresult rv;
const char *host;
PRInt32 port;
nsHttpAuthIdentity *ident;
nsCAutoString path, scheme;
nsISupports **continuationState;
rv = GetAuthorizationMembers(mProxyAuth, scheme, host, port, path, ident, continuationState);
if (NS_FAILED(rv))
OnAuthCancelled(aContext, PR_FALSE);
nsCAutoString realm;
ParseRealm(mCurrentChallenge.get(), realm);
nsHttpAuthCache *authCache = gHttpHandler->AuthCache();
nsHttpAuthEntry *entry = nsnull;
authCache->GetAuthEntryForDomain(scheme.get(), host, port, realm.get(), &entry);
nsCOMPtr<nsISupports> sessionStateGrip;
if (entry)
sessionStateGrip = entry->mMetaData;
nsAuthInformationHolder* holder =
static_cast<nsAuthInformationHolder*>(aAuthInfo);
ident->Set(holder->Domain().get(),
holder->User().get(),
holder->Password().get());
nsCAutoString unused;
nsCOMPtr<nsIHttpAuthenticator> auth;
rv = GetAuthenticator(mCurrentChallenge.get(), unused, getter_AddRefs(auth));
if (NS_FAILED(rv)) {
NS_ASSERTION(PR_FALSE, "GetAuthenticator failed");
OnAuthCancelled(aContext, PR_TRUE);
return NS_OK;
}
nsXPIDLCString creds;
rv = GenCredsAndSetEntry(auth, mProxyAuth,
scheme.get(), host, port, path.get(),
realm.get(), mCurrentChallenge.get(), *ident, sessionStateGrip,
getter_Copies(creds));
mCurrentChallenge.Truncate();
if (NS_FAILED(rv)) {
OnAuthCancelled(aContext, PR_TRUE);
return NS_OK;
}
return ContinueOnAuthAvailable(creds);
}
NS_IMETHODIMP nsHttpChannel::OnAuthCancelled(nsISupports *aContext,
PRBool userCancel)
{
LOG(("nsHttpChannel::OnAuthCancelled [this=%x]", this));
mAsyncPromptAuthCancelable = nsnull;
if (userCancel) {
if (!mRemainingChallenges.IsEmpty()) {
// there are still some challenges to process, do so
nsresult rv;
nsCAutoString creds;
rv = GetCredentials(mRemainingChallenges.get(), mProxyAuth, creds);
if (NS_SUCCEEDED(rv)) {
// GetCredentials loaded the credentials from the cache or
// some other way in a synchronous manner, process those
// credentials now
mRemainingChallenges.Truncate();
return ContinueOnAuthAvailable(creds);
}
else if (rv == NS_ERROR_IN_PROGRESS) {
// GetCredentials successfully queued another authprompt for
// a challenge from the list, we are now waiting for the user
// to provide the credentials
return NS_OK;
}
// otherwise, we failed...
}
mRemainingChallenges.Truncate();
// ensure call of OnStartRequest of the current listener here,
// it would not be called otherwise at all
nsresult rv = CallOnStartRequest();
// drop mAuthRetryPending flag and resume the transaction
// this resumes load of the unauthenticated content data
mAuthRetryPending = PR_FALSE;
LOG(("Resuming the transaction, user cancelled the auth dialog"));
mTransactionPump->Resume();
if (NS_FAILED(rv))
mTransactionPump->Cancel(rv);
}
return NS_OK;
}
nsresult
nsHttpChannel::ContinueOnAuthAvailable(const nsCSubstring& creds)
{
if (mProxyAuth)
mRequestHead.SetHeader(nsHttp::Proxy_Authorization, creds);
else
mRequestHead.SetHeader(nsHttp::Authorization, creds);
// drop our remaining list of challenges. We don't need them, because we
// have now authenticated against a challenge and will be sending that
// information to the server (or proxy). If it doesn't accept our
// authentication it'll respond with failure and resend the challenge list
mRemainingChallenges.Truncate();
// setting mAuthRetryPending flag and resuming the transaction
// triggers process of throwing away the unauthenticated data already
// coming from the network
mAuthRetryPending = PR_TRUE;
LOG(("Resuming the transaction, we got credentials from user"));
mTransactionPump->Resume();
return NS_OK;
}
PRBool
nsHttpChannel::ConfirmAuth(const nsString &bundleKey, PRBool doYesNoPrompt)
{
@ -3913,6 +4077,7 @@ NS_INTERFACE_MAP_BEGIN(nsHttpChannel)
NS_INTERFACE_MAP_ENTRY(nsITraceableChannel)
NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheContainer)
NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheChannel)
NS_INTERFACE_MAP_ENTRY(nsIAuthPromptCallback)
NS_INTERFACE_MAP_END_INHERITING(nsHashPropertyBag)
//-----------------------------------------------------------------------------
@ -3960,6 +4125,8 @@ nsHttpChannel::Cancel(nsresult status)
mTransactionPump->Cancel(status);
if (mCachePump)
mCachePump->Cancel(status);
if (mAsyncPromptAuthCancelable)
mAsyncPromptAuthCancelable->Cancel(status);
return NS_OK;
}
@ -4990,8 +5157,14 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult st
// keep the connection around after the transaction is finished.
//
nsRefPtr<nsAHttpConnection> conn;
if (authRetry && (mCaps & NS_HTTP_STICKY_CONNECTION))
if (authRetry && (mCaps & NS_HTTP_STICKY_CONNECTION)) {
conn = mTransaction->Connection();
// This is so far a workaround to fix leak when reusing unpersistent
// connection for authentication retry. See bug 459620 comment 4
// for details.
if (conn && !conn->IsPersistent())
conn = nsnull;
}
// at this point, we're done with the transaction
NS_RELEASE(mTransaction);

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

@ -84,6 +84,7 @@
#include "nsICancelable.h"
#include "nsIProxiedChannel.h"
#include "nsITraceableChannel.h"
#include "nsIAuthPromptCallback.h"
class nsHttpResponseHead;
class nsAHttpConnection;
@ -109,6 +110,7 @@ class nsHttpChannel : public nsHashPropertyBag
, public nsIProxiedChannel
, public nsITraceableChannel
, public nsIApplicationCacheChannel
, public nsIAuthPromptCallback
{
public:
NS_DECL_ISUPPORTS_INHERITED
@ -130,6 +132,7 @@ public:
NS_DECL_NSITRACEABLECHANNEL
NS_DECL_NSIAPPLICATIONCACHECONTAINER
NS_DECL_NSIAPPLICATIONCACHECHANNEL
NS_DECL_NSIAUTHPROMPTCALLBACK
nsHttpChannel();
virtual ~nsHttpChannel();
@ -223,19 +226,38 @@ private:
// auth specific methods
nsresult PrepareForAuthentication(PRBool proxyAuth);
nsresult GenCredsAndSetEntry(nsIHttpAuthenticator *, PRBool proxyAuth, const char *scheme, const char *host, PRInt32 port, const char *dir, const char *realm, const char *challenge, const nsHttpAuthIdentity &ident, nsCOMPtr<nsISupports> &session, char **result);
nsresult GetCredentials(const char *challenges, PRBool proxyAuth, nsAFlatCString &creds);
nsresult GetCredentialsForChallenge(const char *challenge, const char *scheme, PRBool proxyAuth, nsIHttpAuthenticator *auth, nsAFlatCString &creds);
nsresult GetAuthenticator(const char *challenge, nsCString &scheme, nsIHttpAuthenticator **auth);
void ParseRealm(const char *challenge, nsACString &realm);
void GetIdentityFromURI(PRUint32 authFlags, nsHttpAuthIdentity&);
/**
* Following three methods return NS_ERROR_IN_PROGRESS when
* nsIAuthPrompt2.asyncPromptAuth method is called. This result indicates
* the user's decision will be gathered in a callback and is not an actual
* error.
*/
nsresult GetCredentials(const char *challenges, PRBool proxyAuth, nsAFlatCString &creds);
nsresult GetCredentialsForChallenge(const char *challenge, const char *scheme, PRBool proxyAuth, nsIHttpAuthenticator *auth, nsAFlatCString &creds);
nsresult PromptForIdentity(PRUint32 level, PRBool proxyAuth, const char *realm, const char *authType, PRUint32 authFlags, nsHttpAuthIdentity &);
PRBool ConfirmAuth(const nsString &bundleKey, PRBool doYesNoPrompt);
void CheckForSuperfluousAuth();
void SetAuthorizationHeader(nsHttpAuthCache *, nsHttpAtom header, const char *scheme, const char *host, PRInt32 port, const char *path, nsHttpAuthIdentity &ident);
void AddAuthorizationHeaders();
nsresult GetCurrentPath(nsACString &);
/**
* Return all information needed to build authorization information,
* all paramters except proxyAuth are out parameters. proxyAuth specifies
* with what authorization we work (WWW or proxy).
*/
nsresult GetAuthorizationMembers(PRBool proxyAuth, nsCSubstring& scheme, const char*& host, PRInt32& port, nsCSubstring& path, nsHttpAuthIdentity*& ident, nsISupports**& continuationState);
nsresult DoAuthRetry(nsAHttpConnection *);
PRBool MustValidateBasedOnQueryUrl();
/**
* Method called to resume suspended transaction after we got credentials
* from the user. Called from OnAuthAvailable callback or OnAuthCancelled
* when credentials for next challenge were obtained synchronously.
*/
nsresult ContinueOnAuthAvailable(const nsCSubstring& creds);
private:
nsCOMPtr<nsIURI> mOriginalURI;
@ -293,6 +315,19 @@ private:
nsHttpAuthIdentity mIdent;
nsHttpAuthIdentity mProxyIdent;
// Reference to the prompt wating in prompt queue. The channel is
// responsible to call its cancel method when user in any way cancels
// this request.
nsCOMPtr<nsICancelable> mAsyncPromptAuthCancelable;
// Saved in GetCredentials when prompt is asynchronous, the first challenge
// we obtained from the server with 401/407 response, will be processed in
// OnAuthAvailable callback.
nsCString mCurrentChallenge;
// Saved in GetCredentials when prompt is asynchronous, remaning challenges
// we have to process when user cancels the auth dialog for the current
// challenge.
nsCString mRemainingChallenges;
// Resumable channel specific data
nsCString mEntityID;
PRUint64 mStartPos;
@ -329,6 +364,9 @@ private:
PRUint32 mTransactionReplaced : 1;
PRUint32 mUploadStreamHasHeaders : 1;
PRUint32 mAuthRetryPending : 1;
// True when we need to authenticate to proxy, i.e. when we get 407
// response. Used in OnAuthAvailable and OnAuthCancelled callbacks.
PRUint32 mProxyAuth : 1;
PRUint32 mSuppressDefensiveAuth : 1;
PRUint32 mResuming : 1;
PRUint32 mInitedCacheEntry : 1;

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

@ -127,7 +127,7 @@ AuthPrompt2.prototype = {
},
asyncPromptAuth: function ap2_async(chan, cb, ctx, lvl, info) {
do_throw("not implemented yet")
throw 0x80004001;
}
};
@ -195,7 +195,7 @@ RealmTestRequestor.prototype = {
},
asyncPromptAuth: function realmtest_async(chan, cb, ctx, lvl, info) {
do_throw("not implemented yet");
throw 0x80004001;
}
};

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

@ -38,7 +38,7 @@ AuthPrompt2.prototype = {
},
asyncPromptAuth: function ap2_async(chan, cb, ctx, lvl, info) {
do_throw("not implemented yet")
throw 0x80004001;
}
};

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

@ -829,6 +829,11 @@ void nsSSLIOLayerHelpers::Cleanup()
mTLSIntolerantSites = nsnull;
}
if (mTLSTolerantSites) {
delete mTLSTolerantSites;
mTLSTolerantSites = nsnull;
}
if (mSharedPollableEvent)
PR_DestroyPollableEvent(mSharedPollableEvent);
@ -1622,6 +1627,18 @@ nsPSMRememberCertErrorsTable::LookupCertErrorBits(nsNSSSocketInfo* infoObject,
status->mIsUntrusted = bits.mIsUntrusted;
}
void
nsSSLIOLayerHelpers::getSiteKey(nsNSSSocketInfo *socketInfo, nsCSubstring &key)
{
PRInt32 port;
socketInfo->GetPort(&port);
nsXPIDLCString host;
socketInfo->GetHostName(getter_Copies(host));
key = host + NS_LITERAL_CSTRING(":") + nsPrintfCString("%d", port);
}
// Call this function to report a site that is possibly TLS intolerant.
// This function will return true, if the given socket is currently using TLS.
PRBool
@ -1629,30 +1646,50 @@ nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(PRFileDesc* ssl_layer_fd, ns
{
PRBool currentlyUsesTLS = PR_FALSE;
nsCAutoString key;
getSiteKey(socketInfo, key);
SSL_OptionGet(ssl_layer_fd, SSL_ENABLE_TLS, &currentlyUsesTLS);
if (!currentlyUsesTLS)
if (!currentlyUsesTLS) {
// We were not using TLS but failed with an intolerant error using
// a different protocol. To give TLS a try on next connection attempt again
// drop this site from the list of intolerant sites. TLS failure might be
// caused only by a traffic congestion while the server is TLS tolerant.
removeIntolerantSite(key);
return PR_FALSE;
}
PRBool enableSSL3 = PR_FALSE;
SSL_OptionGet(ssl_layer_fd, SSL_ENABLE_SSL3, &enableSSL3);
PRBool enableSSL2 = PR_FALSE;
SSL_OptionGet(ssl_layer_fd, SSL_ENABLE_SSL2, &enableSSL2);
if (enableSSL3 || enableSSL2)
{
if (enableSSL3 || enableSSL2) {
// Add this site to the list of TLS intolerant sites.
PRInt32 port;
nsXPIDLCString host;
socketInfo->GetPort(&port);
socketInfo->GetHostName(getter_Copies(host));
nsCAutoString key;
key = host + NS_LITERAL_CSTRING(":") + nsPrintfCString("%d", port);
addIntolerantSite(key);
}
return currentlyUsesTLS;
}
void
nsSSLIOLayerHelpers::rememberTolerantSite(PRFileDesc* ssl_layer_fd,
nsNSSSocketInfo *socketInfo)
{
PRBool usingSecurity = PR_FALSE;
PRBool currentlyUsesTLS = PR_FALSE;
SSL_OptionGet(ssl_layer_fd, SSL_SECURITY, &usingSecurity);
SSL_OptionGet(ssl_layer_fd, SSL_ENABLE_TLS, &currentlyUsesTLS);
if (!usingSecurity || !currentlyUsesTLS) {
return;
}
nsCAutoString key;
getSiteKey(socketInfo, key);
nsAutoLock lock(mutex);
nsSSLIOLayerHelpers::mTLSTolerantSites->Put(key);
}
static PRStatus PR_CALLBACK
nsSSLIOLayerClose(PRFileDesc *fd)
{
@ -1927,6 +1964,7 @@ PRDescIdentity nsSSLIOLayerHelpers::nsSSLIOLayerIdentity;
PRIOMethods nsSSLIOLayerHelpers::nsSSLIOLayerMethods;
PRLock *nsSSLIOLayerHelpers::mutex = nsnull;
nsCStringHashSet *nsSSLIOLayerHelpers::mTLSIntolerantSites = nsnull;
nsCStringHashSet *nsSSLIOLayerHelpers::mTLSTolerantSites = nsnull;
nsPSMRememberCertErrorsTable *nsSSLIOLayerHelpers::mHostsWithCertErrors = nsnull;
PRFileDesc *nsSSLIOLayerHelpers::mSharedPollableEvent = nsnull;
nsNSSSocketInfo *nsSSLIOLayerHelpers::mSocketOwningPollableEvent = nsnull;
@ -2137,6 +2175,15 @@ nsresult nsSSLIOLayerHelpers::Init()
mTLSIntolerantSites->Init(1);
mTLSTolerantSites = new nsCStringHashSet();
if (!mTLSTolerantSites)
return NS_ERROR_OUT_OF_MEMORY;
// Initialize the tolerant site hashtable to 16 items at the start seems
// reasonable as most servers are TLS tolerant. We just want to lower
// the rate of hashtable array reallocation.
mTLSTolerantSites->Init(16);
mHostsWithCertErrors = new nsPSMRememberCertErrorsTable();
if (!mHostsWithCertErrors || !mHostsWithCertErrors->mErrorHosts.IsInitialized())
return NS_ERROR_OUT_OF_MEMORY;
@ -2147,9 +2194,17 @@ nsresult nsSSLIOLayerHelpers::Init()
void nsSSLIOLayerHelpers::addIntolerantSite(const nsCString &str)
{
nsAutoLock lock(mutex);
// Remember intolerant site only if it is not known as tolerant
if (!mTLSTolerantSites->Contains(str))
nsSSLIOLayerHelpers::mTLSIntolerantSites->Put(str);
}
void nsSSLIOLayerHelpers::removeIntolerantSite(const nsCString &str)
{
nsAutoLock lock(mutex);
nsSSLIOLayerHelpers::mTLSIntolerantSites->Remove(str);
}
PRBool nsSSLIOLayerHelpers::isKnownAsIntolerantSite(const nsCString &str)
{
nsAutoLock lock(mutex);

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

@ -284,11 +284,15 @@ public:
static PRLock *mutex;
static nsCStringHashSet *mTLSIntolerantSites;
static nsCStringHashSet *mTLSTolerantSites;
static nsPSMRememberCertErrorsTable* mHostsWithCertErrors;
static void getSiteKey(nsNSSSocketInfo *socketInfo, nsCSubstring &key);
static PRBool rememberPossibleTLSProblemSite(PRFileDesc* fd, nsNSSSocketInfo *socketInfo);
static void rememberTolerantSite(PRFileDesc* ssl_layer_fd, nsNSSSocketInfo *socketInfo);
static void addIntolerantSite(const nsCString &str);
static void removeIntolerantSite(const nsCString &str);
static PRBool isKnownAsIntolerantSite(const nsCString &str);
static PRFileDesc *mSharedPollableEvent;

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

@ -819,6 +819,8 @@ PRInt32 nsSSLThread::requestWrite(nsNSSSocketInfo *si, const void *buf, PRInt32
return si->mThreadData->mSSLResultRemainingBytes;
}
nsSSLIOLayerHelpers::rememberTolerantSite(si->mFd, si);
PRInt32 return_amount = NS_MIN(amount, si->mThreadData->mSSLResultRemainingBytes);
si->mThreadData->mSSLResultRemainingBytes -= return_amount;

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

@ -50,18 +50,42 @@ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
* Invoked by NS_NewAuthPrompter2()
* [embedding/components/windowwatcher/src/nsPrompt.cpp]
*/
function LoginManagerPromptFactory() {}
function LoginManagerPromptFactory() {
var observerService = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
observerService.addObserver(this, "quit-application-granted", true);
}
LoginManagerPromptFactory.prototype = {
classDescription : "LoginManagerPromptFactory",
contractID : "@mozilla.org/passwordmanager/authpromptfactory;1",
classID : Components.ID("{749e62f4-60ae-4569-a8a2-de78b649660e}"),
QueryInterface : XPCOMUtils.generateQI([Ci.nsIPromptFactory]),
QueryInterface : XPCOMUtils.generateQI([Ci.nsIPromptFactory, Ci.nsIObserver, Ci.nsISupportsWeakReference]),
_asyncPrompts : {},
_asyncPromptInProgress : false,
observe : function (subject, topic, data) {
if (topic == "quit-application-granted") {
var asyncPrompts = this._asyncPrompts;
this._asyncPrompts = {};
for each (var asyncPrompt in asyncPrompts) {
for each (var consumer in asyncPrompt.consumers) {
if (consumer.callback) {
this.log("Canceling async auth prompt callback " + consumer.callback);
try {
consumer.callback.onAuthCancelled(consumer.context, true);
} catch (e) { /* Just ignore exceptions from the callback */ }
}
}
}
}
},
getPrompt : function (aWindow, aIID) {
var prompt = new LoginManagerPrompter().QueryInterface(aIID);
prompt.init(aWindow);
prompt.init(aWindow, this);
return prompt;
}
}; // end of LoginManagerPromptFactory implementation
@ -98,6 +122,7 @@ LoginManagerPrompter.prototype = {
Ci.nsIAuthPrompt2,
Ci.nsILoginManagerPrompter]),
_factory : null,
_window : null,
_debug : false, // mirrors signon.debug
@ -165,6 +190,14 @@ LoginManagerPrompter.prototype = {
return this.__ioService;
},
__threadManager: null,
get _threadManager() {
if (!this.__threadManager)
this.__threadManager = Cc["@mozilla.org/thread-manager;1"].
getService(Ci.nsIThreadManager);
return this.__threadManager;
},
__ellipsis : null,
get _ellipsis() {
@ -556,10 +589,114 @@ LoginManagerPrompter.prototype = {
return ok;
},
asyncPromptAuth : function () {
return NS_ERROR_NOT_IMPLEMENTED;
asyncPromptAuth : function (aChannel, aCallback, aContext, aLevel, aAuthInfo) {
var cancelable = null;
try {
this.log("===== asyncPromptAuth called =====");
// If the user submits a login but it fails, we need to remove the
// notification bar that was displayed. Conveniently, the user will
// be prompted for authentication again, which brings us here.
var notifyBox = this._getNotifyBox();
if (notifyBox)
this._removeLoginNotifications(notifyBox);
cancelable = this._newAsyncPromptConsumer(aCallback, aContext);
var [hostname, httpRealm] = this._getAuthTarget(aChannel, aAuthInfo);
var hashKey = aLevel + "|" + hostname + "|" + httpRealm;
this.log("Async prompt key = " + hashKey);
var asyncPrompt = this._factory._asyncPrompts[hashKey];
if (asyncPrompt) {
this.log("Prompt bound to an existing one in the queue, callback = " + aCallback);
asyncPrompt.consumers.push(cancelable);
return cancelable;
}
this.log("Adding new prompt to the queue, callback = " + aCallback);
asyncPrompt = {
consumers: [cancelable],
channel: aChannel,
authInfo: aAuthInfo,
level: aLevel
}
this._factory._asyncPrompts[hashKey] = asyncPrompt;
this._doAsyncPrompt();
}
catch (e) {
Components.utils.reportError("LoginManagerPrompter: " +
"asyncPromptAuth: " + e + "\nFalling back to promptAuth\n");
// Fail the prompt operation to let the consumer fall back
// to synchronous promptAuth method
throw e;
}
return cancelable;
},
_doAsyncPrompt : function() {
if (this._factory._asyncPromptInProgress) {
this.log("_doAsyncPrompt bypassed, already in progress");
return;
}
// Find the first prompt key we have in the queue
var hashKey = null;
for (hashKey in this._factory._asyncPrompts)
break;
if (!hashKey) {
this.log("_doAsyncPrompt:run bypassed, no prompts in the queue");
return;
}
this._factory._asyncPromptInProgress = true;
var self = this;
var runnable = {
run : function() {
var ok = false;
var prompt = self._factory._asyncPrompts[hashKey];
try {
self.log("_doAsyncPrompt:run - performing the prompt for '" + hashKey + "'");
ok = self.promptAuth(
prompt.channel,
prompt.level,
prompt.authInfo
);
} catch (e) {
Components.utils.reportError("LoginManagerPrompter: " +
"_doAsyncPrompt:run: " + e + "\n");
}
delete self._factory._asyncPrompts[hashKey];
self._factory._asyncPromptInProgress = false;
for each (var consumer in prompt.consumers) {
if (!consumer.callback)
// Not having a callback means that consumer didn't provide it
// or canceled the notification
continue;
self.log("Calling back to " + consumer.callback + " ok=" + ok);
try {
if (ok)
consumer.callback.onAuthAvailable(consumer.context, prompt.authInfo);
else
consumer.callback.onAuthCancelled(consumer.context, true);
} catch (e) { /* Throw away exceptions caused by callback */ }
}
self._doAsyncPrompt();
}
}
this._threadManager.mainThread.dispatch(runnable,
Ci.nsIThread.DISPATCH_NORMAL);
this.log("_doAsyncPrompt:run dispatched");
},
@ -572,8 +709,9 @@ LoginManagerPrompter.prototype = {
* init
*
*/
init : function (aWindow) {
init : function (aWindow, aFactory) {
this._window = aWindow;
this._factory = aFactory || null;
var prefBranch = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefService).getBranch("signon.");
@ -1218,6 +1356,19 @@ LoginManagerPrompter.prototype = {
aAuthInfo.username = username;
}
aAuthInfo.password = password;
},
_newAsyncPromptConsumer : function(aCallback, aContext) {
return {
QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
callback: aCallback,
context: aContext,
cancel: function() {
this.callback.onAuthCancelled(this.context, false);
this.callback = null;
this.context = null;
}
}
}
}; // end of LoginManagerPrompter implementation

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

@ -74,6 +74,7 @@ MOCHI_TESTS = \
test_bug_391514.html \
test_bug_427033.html \
test_bug_444968.html \
test_prompt_async.html \
test_notifications.html \
test_prompt.html \
test_xhr.html \
@ -101,6 +102,7 @@ MOCHI_CONTENT = \
subtst_notifications_8.html \
subtst_notifications_9.html \
subtst_notifications_10.html \
subtst_prompt_async.html \
$(NULL)
XPCSHELL_TESTS = unit

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

@ -11,13 +11,16 @@ function handleRequest(request, response)
function reallyHandleRequest(request, response) {
var match;
var requestAuth = true;
var requestAuth = true, requestProxyAuth = true;
// Allow the caller to drive how authentication is processed via the query.
// Eg, http://localhost:8888/authenticate.sjs?user=foo&realm=bar
var query = request.queryString;
var expected_user = "", expected_pass = "", realm = "mochitest";
var proxy_expected_user = "", proxy_expected_pass = "", proxy_realm = "mochi-proxy";
var huge = false;
var authHeaderCount = 1;
// user=xxx
match = /user=([^&]*)/.exec(query);
if (match)
@ -33,6 +36,31 @@ function reallyHandleRequest(request, response) {
if (match)
realm = match[1];
// proxy_user=xxx
match = /proxy_user=([^&]*)/.exec(query);
if (match)
proxy_expected_user = match[1];
// proxy_pass=xxx
match = /proxy_pass=([^&]*)/.exec(query);
if (match)
proxy_expected_pass = match[1];
// proxy_realm=xxx
match = /proxy_realm=([^&]*)/.exec(query);
if (match)
proxy_realm = match[1];
// huge=1
match = /huge=1/.exec(query);
if (match)
huge = true;
// multiple=1
match = /multiple=([^&]*)/.exec(query);
if (match)
authHeaderCount = match[1]+0;
// Look for an authentication header, if any, in the request.
//
@ -56,16 +84,40 @@ function reallyHandleRequest(request, response) {
actual_pass = match[2];
}
var proxy_actual_user = "", proxy_actual_pass = "";
if (request.hasHeader("Proxy-Authorization")) {
authHeader = request.getHeader("Proxy-Authorization");
match = /Basic (.+)/.exec(authHeader);
if (match.length != 2)
throw "Couldn't parse auth header: " + authHeader;
var userpass = base64ToString(match[1]); // no atob() :-(
match = /(.*):(.*)/.exec(userpass);
if (match.length != 3)
throw "Couldn't decode auth header: " + userpass;
proxy_actual_user = match[1];
proxy_actual_pass = match[2];
}
// Don't request authentication if the credentials we got were what we
// expected.
if (expected_user == actual_user &&
expected_pass == actual_pass) {
requestAuth = false;
}
if (proxy_expected_user == proxy_actual_user &&
proxy_expected_pass == proxy_actual_pass) {
requestProxyAuth = false;
}
if (requestAuth) {
if (requestProxyAuth) {
response.setStatusLine("1.0", 407, "Proxy authentication required");
for (i = 0; i < authHeaderCount; ++i)
response.setHeader("Proxy-Authenticate", "basic realm=\"" + proxy_realm + "\"", true);
} else if (requestAuth) {
response.setStatusLine("1.0", 401, "Authentication required");
response.setHeader("WWW-Authenticate", "basic realm=\"" + realm + "\"", false);
for (i = 0; i < authHeaderCount; ++i)
response.setHeader("WWW-Authenticate", "basic realm=\"" + realm + "\"", true);
} else {
response.setStatusLine("1.0", 200, "OK");
}
@ -73,9 +125,20 @@ function reallyHandleRequest(request, response) {
response.setHeader("Content-Type", "application/xhtml+xml", false);
response.write("<html xmlns='http://www.w3.org/1999/xhtml'>");
response.write("<p>Login: <span id='ok'>" + (requestAuth ? "FAIL" : "PASS") + "</span></p>\n");
response.write("<p>Proxy: <span id='proxy'>" + (requestProxyAuth ? "FAIL" : "PASS") + "</span></p>\n");
response.write("<p>Auth: <span id='auth'>" + authHeader + "</span></p>\n");
response.write("<p>User: <span id='user'>" + actual_user + "</span></p>\n");
response.write("<p>Pass: <span id='pass'>" + actual_pass + "</span></p>\n");
if (huge) {
response.write("<div style='display: none'>");
for (i = 0; i < 100000; i++) {
response.write("123456789\n");
}
response.write("</div>");
response.write("<span id='footnote'>This is a footnote after the huge content fill</span>");
}
response.write("</html>");
}

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

@ -0,0 +1,11 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Multiple auth request</title>
</head>
<body>
<iframe id="iframe1" src="http://example.com/tests/toolkit/components/passwordmgr/test/authenticate.sjs?r=1&user=user3name&pass=user3pass&realm=mochirealm3&proxy_user=proxy_user2&proxy_pass=proxy_pass2&proxy_realm=proxy_realm2"></iframe>
<iframe id="iframe2" src="http://example.com/tests/toolkit/components/passwordmgr/test/authenticate.sjs?r=2&user=user3name&pass=user3pass&realm=mochirealm3&proxy_user=proxy_user2&proxy_pass=proxy_pass2&proxy_realm=proxy_realm2"></iframe>
<iframe id="iframe3" src="http://example.com/tests/toolkit/components/passwordmgr/test/authenticate.sjs?r=3&user=user3name&pass=user3pass&realm=mochirealm3&proxy_user=proxy_user2&proxy_pass=proxy_pass2&proxy_realm=proxy_realm2"></iframe>
</body>
</html>

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

@ -0,0 +1,492 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for Async Auth Prompt</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="prompt_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
// Class monitoring number of open dialog windows
// It checks there is always open just a single dialog per application
function dialogMonitor() {
var observerService = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
observerService.addObserver(this, "domwindowopened", false);
observerService.addObserver(this, "domwindowclosed", false);
}
dialogMonitor.prototype = {
windowsOpen : new Array(),
windowsRegistered : 0,
QueryInterface : function (iid) {
const interfaces = [Ci.nsIObserver,
Ci.nsISupports];
if (!interfaces.some( function(v) { return iid.equals(v) } ))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
},
observe: function(subject, topic, data) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
if (topic === "domwindowopened") {
var win = subject.QueryInterface(Ci.nsIDOMWindow);
this.windowsOpen.push(win);
ok(this.windowsOpen.length == 1, "Didn't open more then one dialog at a time");
this.windowsRegistered++;
return;
}
if (topic === "domwindowclosed") {
var win = subject.QueryInterface(Ci.nsIDOMWindow);
for (p in this.windowsOpen)
if (win == this.windowsOpen[p]) {
this.windowsOpen.splice(p, 1);
break;
}
return;
}
},
shutdown: function() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var observerService = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
observerService.removeObserver(this, "domwindowopened");
observerService.removeObserver(this, "domwindowclosed");
},
reset: function() {
while (this.windowsOpen.length)
this.windowsOpen.shift();
this.windowsRegistered = 0;
}
}
var monitor = new dialogMonitor();
var pwmgr, logins = [];
function initLogins() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
pwmgr = Cc["@mozilla.org/login-manager;1"].
getService(Ci.nsILoginManager);
function addLogin(host, realm, user, pass) {
var login = Cc["@mozilla.org/login-manager/loginInfo;1"].
createInstance(Ci.nsILoginInfo);
login.init(host, null, realm, user, pass, "", "");
pwmgr.addLogin(login);
logins.push(login);
}
addLogin("moz-proxy://127.0.0.1:8888", "proxy_realm",
"proxy_user", "proxy_pass");
addLogin("moz-proxy://127.0.0.1:8888", "proxy_realm2",
"proxy_user2", "proxy_pass2");
addLogin("moz-proxy://127.0.0.1:8888", "proxy_realm3",
"proxy_user3", "proxy_pass3");
addLogin("moz-proxy://127.0.0.1:8888", "proxy_realm4",
"proxy_user4", "proxy_pass4");
addLogin("moz-proxy://127.0.0.1:8888", "proxy_realm5",
"proxy_user5", "proxy_pass5");
addLogin("http://example.com", "mochirealm",
"user1name", "user1pass");
addLogin("http://example.org", "mochirealm2",
"user2name", "user2pass");
addLogin("http://example.com", "mochirealm3",
"user3name", "user3pass");
addLogin("http://example.com", "mochirealm4",
"user4name", "user4pass");
addLogin("http://example.com", "mochirealm5",
"user5name", "user5pass");
addLogin("http://example.com", "mochirealm6",
"user6name", "user6pass");
}
function finishTest() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
ok(true, "finishTest removing testing logins...");
for (i in logins)
pwmgr.removeLogin(logins[i]);
var authMgr = Cc['@mozilla.org/network/http-auth-manager;1'].
getService(Ci.nsIHttpAuthManager);
authMgr.clearAll();
monitor.shutdown();
SimpleTest.finish();
}
// --------------- Test loop spin ----------------
var testNum = 1;
var iframe1;
var iframe2a;
var iframe2b;
window.onload = function () {
iframe1 = document.getElementById("iframe1");
iframe2a = document.getElementById("iframe2a");
iframe2b = document.getElementById("iframe2b");
iframe1.onload = onFrameLoad;
iframe2a.onload = onFrameLoad;
iframe2b.onload = onFrameLoad;
initLogins();
doTest(testNum);
}
var expectedLoads;
var expectedDialogs;
function onFrameLoad()
{
if (--expectedLoads == 0) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
// All pages expected to load has loaded, continue with the next test
ok(true, "Expected frames loaded");
doCheck(testNum);
monitor.reset();
testNum++;
doTest(testNum);
}
}
function doTest(testNum)
{
var exampleCom = "http://example.com/tests/toolkit/components/passwordmgr/test/";
var exampleOrg = "http://example.org/tests/toolkit/components/passwordmgr/test/";
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
switch (testNum)
{
case 1:
// Load through a single proxy with authentication required 3 different
// pages, first with one login, other two with their own different login.
// We expect to show just a single dialog for proxy authentication and
// then two dialogs to authenticate to login 1 and then login 2.
ok(true, "doTest testNum 1");
expectedLoads = 3;
expectedDialogs = 3;
iframe1.src = exampleCom + "authenticate.sjs?"+
"r=1&"+
"user=user1name&"+
"pass=user1pass&"+
"realm=mochirealm&"+
"proxy_user=proxy_user&"+
"proxy_pass=proxy_pass&"+
"proxy_realm=proxy_realm";
iframe2a.src = exampleOrg + "authenticate.sjs?"+
"r=2&"+
"user=user2name&"+
"pass=user2pass&"+
"realm=mochirealm2&"+
"proxy_user=proxy_user&"+
"proxy_pass=proxy_pass&"+
"proxy_realm=proxy_realm";
iframe2b.src = exampleOrg + "authenticate.sjs?"+
"r=3&"+
"user=user2name&"+
"pass=user2pass&"+
"realm=mochirealm2&"+
"proxy_user=proxy_user&"+
"proxy_pass=proxy_pass&"+
"proxy_realm=proxy_realm";
break;
case 2:
// Load an iframe with 3 subpages all requiring the same login through
// anuthenticated proxy. We expect 2 dialogs, proxy authentication
// and web authentication.
ok(true, "doTest testNum 2");
expectedLoads = 3;
expectedDialogs = 2;
iframe1.src = exampleCom + "subtst_prompt_async.html";
iframe2a.src = "about:blank";
iframe2b.src = "about:blank";
break;
case 3:
// Load in the iframe page through unauthenticated proxy
// and discard the proxy authentication. We expect to see
// unauthenticated page content and just a single dialog.
ok(true, "doTest testNum 3");
expectedLoads = 1;
expectedDialogs = 1;
iframe1.src = exampleCom + "authenticate.sjs?"+
"user=user4name&"+
"pass=user4pass&"+
"realm=mochirealm4&"+
"proxy_user=proxy_user3&"+
"proxy_pass=proxy_pass3&"+
"proxy_realm=proxy_realm3";
break;
case 4:
// Reload the frame from previous step and pass the proxy authentication
// but cancel the WWW authentication. We should get the proxy=ok and WWW=fail
// content as a result.
ok(true, "doTest testNum 4");
expectedLoads = 1;
expectedDialogs = 2;
iframe1.contentDocument.location.reload();
break;
case 5:
// Same as the previous two steps but let the server generate
// huge content load to check http channel is capable to handle
// case when auth dialog is canceled or accepted before unauthenticated
// content data is load from the server. (This would be better to
// implement using delay of server response).
ok(true, "doTest testNum 5");
expectedLoads = 1;
expectedDialogs = 1;
iframe1.src = exampleCom + "authenticate.sjs?"+
"user=user5name&"+
"pass=user5pass&"+
"realm=mochirealm5&"+
"proxy_user=proxy_user4&"+
"proxy_pass=proxy_pass4&"+
"proxy_realm=proxy_realm4&"+
"huge=1";
break;
case 6:
// Reload the frame from the previous step and let the proxy
// authentication pass but WWW fail. We expect two dialogs
// and an unathentiocated page content load.
ok(true, "doTest testNum 6");
expectedLoads = 1;
expectedDialogs = 2;
iframe1.contentDocument.location.reload();
break;
case 7:
// Reload again and let pass all authentication dialogs.
// Check we get the authenticated content not broken by
// the unauthenticated content.
ok(true, "doTest testNum 7");
expectedLoads = 1;
expectedDialogs = 1;
iframe1.contentDocument.location.reload();
break;
case 8:
// Check we proccess all challenges sent by server when
// user cancels prompts
ok(true, "doTest testNum 8");
expectedLoads = 1;
expectedDialogs = 5;
iframe1.src = exampleCom + "authenticate.sjs?"+
"user=user6name&"+
"pass=user6pass&"+
"realm=mochirealm6&"+
"proxy_user=proxy_user5&"+
"proxy_pass=proxy_pass5&"+
"proxy_realm=proxy_realm5&"+
"huge=1&"+
"multiple=3";
break;
case 9:
finishTest();
return;
}
startCallbackTimer();
}
function handleDialog(doc, testNum)
{
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var dialog = doc.getElementById("commonDialog");
switch (testNum)
{
case 1:
case 2:
dialog.acceptDialog();
break;
case 3:
dialog.cancelDialog();
break;
case 4:
if (expectedDialogs == 2)
dialog.acceptDialog();
else
dialog.cancelDialog();
break;
case 5:
dialog.cancelDialog();
break;
case 6:
if (expectedDialogs == 2)
dialog.acceptDialog();
else
dialog.cancelDialog();
break;
case 7:
dialog.acceptDialog();
break;
case 8:
if (expectedDialogs == 3 || expectedDialogs == 1)
dialog.acceptDialog();
else
dialog.cancelDialog();
break;
default:
ok(false, "Unhandled testNum "+testNum+" in handleDialog");
}
if (--expectedDialogs > 0)
startCallbackTimer();
}
function doCheck(testNum)
{
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
switch (testNum)
{
case 1:
ok(true, "doCheck testNum 1");
is(monitor.windowsRegistered, 3, "Registered 3 open dialogs");
var authok1 = iframe1.contentDocument.getElementById("ok").textContent;
var proxyok1 = iframe1.contentDocument.getElementById("proxy").textContent;
var authok2a = iframe2a.contentDocument.getElementById("ok").textContent;
var proxyok2a = iframe2a.contentDocument.getElementById("proxy").textContent;
var authok2b = iframe2b.contentDocument.getElementById("ok").textContent;
var proxyok2b = iframe2b.contentDocument.getElementById("proxy").textContent;
is(authok1, "PASS", "WWW Authorization OK, frame1");
is(authok2a, "PASS", "WWW Authorization OK, frame2a");
is(authok2b, "PASS", "WWW Authorization OK, frame2b");
is(proxyok1, "PASS", "Proxy Authorization OK, frame1");
is(proxyok2a, "PASS", "Proxy Authorization OK, frame2a");
is(proxyok2b, "PASS", "Proxy Authorization OK, frame2b");
break;
case 2:
is(monitor.windowsRegistered, 2, "Registered 2 open dialogs");
ok(true, "doCheck testNum 2");
function checkIframe(frame) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var authok = frame.contentDocument.getElementById("ok").textContent;
var proxyok = frame.contentDocument.getElementById("proxy").textContent;
is(authok, "PASS", "WWW Authorization OK, " + frame.id);
is(proxyok, "PASS", "Proxy Authorization OK, " + frame.id);
}
checkIframe(iframe1.contentDocument.getElementById("iframe1"));
checkIframe(iframe1.contentDocument.getElementById("iframe2"));
checkIframe(iframe1.contentDocument.getElementById("iframe3"));
break;
case 3:
ok(true, "doCheck testNum 3");
is(monitor.windowsRegistered, 1, "Registered 1 open dialog");
var authok1 = iframe1.contentDocument.getElementById("ok").textContent;
var proxyok1 = iframe1.contentDocument.getElementById("proxy").textContent;
is(authok1, "FAIL", "WWW Authorization FAILED, frame1");
is(proxyok1, "FAIL", "Proxy Authorization FAILED, frame1");
break;
case 4:
ok(true, "doCheck testNum 4");
is(monitor.windowsRegistered, 2, "Registered 2 open dialogs");
var authok1 = iframe1.contentDocument.getElementById("ok").textContent;
var proxyok1 = iframe1.contentDocument.getElementById("proxy").textContent;
is(authok1, "FAIL", "WWW Authorization FAILED, frame1");
is(proxyok1, "PASS", "Proxy Authorization OK, frame1");
break;
case 5:
ok(true, "doCheck testNum 5");
is(monitor.windowsRegistered, 1, "Registered 1 open dialog");
var authok1 = iframe1.contentDocument.getElementById("ok").textContent;
var proxyok1 = iframe1.contentDocument.getElementById("proxy").textContent;
var footnote = iframe1.contentDocument.getElementById("footnote").textContent;
is(authok1, "FAIL", "WWW Authorization FAILED, frame1");
is(proxyok1, "FAIL", "Proxy Authorization FAILED, frame1");
is(footnote, "This is a footnote after the huge content fill",
"Footnote present and loaded completely");
break;
case 6:
ok(true, "doCheck testNum 6");
is(monitor.windowsRegistered, 2, "Registered 2 open dialogs");
var authok1 = iframe1.contentDocument.getElementById("ok").textContent;
var proxyok1 = iframe1.contentDocument.getElementById("proxy").textContent;
var footnote = iframe1.contentDocument.getElementById("footnote").textContent;
is(authok1, "FAIL", "WWW Authorization FAILED, frame1");
is(proxyok1, "PASS", "Proxy Authorization OK, frame1");
is(footnote, "This is a footnote after the huge content fill",
"Footnote present and loaded completely");
break;
case 7:
ok(true, "doCheck testNum 7");
is(monitor.windowsRegistered, 1, "Registered 1 open dialogs");
var authok1 = iframe1.contentDocument.getElementById("ok").textContent;
var proxyok1 = iframe1.contentDocument.getElementById("proxy").textContent;
var footnote = iframe1.contentDocument.getElementById("footnote").textContent;
is(authok1, "PASS", "WWW Authorization OK, frame1");
is(proxyok1, "PASS", "Proxy Authorization OK, frame1");
is(footnote, "This is a footnote after the huge content fill",
"Footnote present and loaded completely");
break;
case 8:
ok(true, "doCheck testNum 8");
is(monitor.windowsRegistered, 5, "Registered 5 open dialogs");
var authok1 = iframe1.contentDocument.getElementById("ok").textContent;
var proxyok1 = iframe1.contentDocument.getElementById("proxy").textContent;
var footnote = iframe1.contentDocument.getElementById("footnote").textContent;
is(authok1, "PASS", "WWW Authorization OK, frame1");
is(proxyok1, "PASS", "Proxy Authorization OK, frame1");
is(footnote, "This is a footnote after the huge content fill",
"Footnote present and loaded completely");
break;
default:
ok(false, "Unhandled testNum "+testNum+" in doCheck");
}
}
</script>
</head>
<body>
<iframe id="iframe1"></iframe>
<iframe id="iframe2a"></iframe>
<iframe id="iframe2b"></iframe>
</body>
</html>

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

@ -528,9 +528,12 @@ nsChildView::nsChildView() : nsBaseWidget()
nsChildView::~nsChildView()
{
// notify the children that we're gone
for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) {
// Notify the children that we're gone. childView->ResetParent() can change
// our list of children while it's being iterated, so the way we iterate the
// list must allow for this.
for (nsIWidget* kid = mLastChild; kid;) {
nsChildView* childView = static_cast<nsChildView*>(kid);
kid = kid->GetPrevSibling();
childView->ResetParent();
}

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

@ -161,16 +161,20 @@ nsCocoaWindow::~nsCocoaWindow()
// Notify the children that we're gone. Popup windows (e.g. tooltips) can
// have nsChildView children. 'kid' is an nsChildView object if and only if
// its 'type' is 'eWindowType_child'.
for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) {
// its 'type' is 'eWindowType_child'. childView->ResetParent() can change
// our list of children while it's being iterated, so the way we iterate the
// list must allow for this.
for (nsIWidget* kid = mLastChild; kid;) {
nsWindowType kidType;
kid->GetWindowType(kidType);
if (kidType == eWindowType_child) {
nsChildView* childView = static_cast<nsChildView*>(kid);
kid = kid->GetPrevSibling();
childView->ResetParent();
} else {
nsCocoaWindow* childWindow = static_cast<nsCocoaWindow*>(kid);
childWindow->mParent = nsnull;
kid = kid->GetPrevSibling();
}
}
@ -779,22 +783,8 @@ NS_IMETHODIMP nsCocoaWindow::Show(PRBool bState)
// the NSApplication class (in header files generated using class-dump).
// This workaround was "borrowed" from the Java Embedding Plugin (which
// uses it for a different purpose).
if (mWindowType == eWindowType_popup) {
if (mWindowType == eWindowType_popup)
[NSApp _removeWindowFromCache:mWindow];
// Apple's focus ring APIs sometimes clip themselves when they draw under
// other windows. Redraw the window that was likely under the popup to
// get focus rings to draw correctly. Sometimes the window is not properly
// the parent of the popup, so we can't just tell the parent to redraw.
// We only have this problem on 10.4. See bug 417124.
if (!nsToolkit::OnLeopardOrLater()) {
NSWindow* keyWindow = [NSApp keyWindow];
if (keyWindow)
[keyWindow display];
NSWindow* mainWindow = [NSApp mainWindow];
if (mainWindow && mainWindow != keyWindow)
[mainWindow display];
}
}
// it's very important to turn off mouse moved events when hiding a window, otherwise
// the windows' tracking rects will interfere with each other. (bug 356528)

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

@ -1050,12 +1050,17 @@ private:
* Under GCC, this define should only be set if compiling with -fshort-wchar.
*/
#ifdef HAVE_CPP_2BYTE_WCHAR_T
#if defined(HAVE_CPP_CHAR16_T) || defined(HAVE_CPP_2BYTE_WCHAR_T)
#if defined(HAVE_CPP_CHAR16_T)
PR_STATIC_ASSERT(sizeof(char16_t) == 2);
#define NS_LL(s) u##s
#else
PR_STATIC_ASSERT(sizeof(wchar_t) == 2);
#define NS_LL(s) L##s
#define NS_MULTILINE_LITERAL_STRING(s) nsDependentString(reinterpret_cast<const nsAString::char_type*>(s), PRUint32((sizeof(s)/sizeof(wchar_t))-1))
#define NS_MULTILINE_LITERAL_STRING_INIT(n,s) n(reinterpret_cast<const nsAString::char_type*>(s), PRUint32((sizeof(s)/sizeof(wchar_t))-1))
#define NS_NAMED_MULTILINE_LITERAL_STRING(n,s) const nsDependentString n(reinterpret_cast<const nsAString::char_type*>(s), PRUint32((sizeof(s)/sizeof(wchar_t))-1))
#endif
#define NS_MULTILINE_LITERAL_STRING(s) nsDependentString(reinterpret_cast<const nsAString::char_type*>(s), PRUint32((sizeof(s)/2)-1))
#define NS_MULTILINE_LITERAL_STRING_INIT(n,s) n(reinterpret_cast<const nsAString::char_type*>(s), PRUint32((sizeof(s)/2)-1))
#define NS_NAMED_MULTILINE_LITERAL_STRING(n,s) const nsDependentString n(reinterpret_cast<const nsAString::char_type*>(s), PRUint32((sizeof(s)/2)-1))
typedef nsDependentString nsLiteralString;
#else
#define NS_LL(s) s

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

@ -151,7 +151,7 @@ struct nsCharTraits<PRUnichar>
typedef PRUint16 unsigned_char_type;
typedef char incompatible_char_type;
NS_COM static const char_type *sEmptyBuffer;
NS_COM static char_type *sEmptyBuffer;
static
void
@ -441,7 +441,7 @@ struct nsCharTraits<char>
typedef unsigned char unsigned_char_type;
typedef PRUnichar incompatible_char_type;
NS_COM static const char_type *sEmptyBuffer;
NS_COM static char_type *sEmptyBuffer;
static
void

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

@ -78,11 +78,17 @@ literal_string( const nsACString::char_type* aPtr, PRUint32 aLength )
}
#endif
#ifdef HAVE_CPP_2BYTE_WCHAR_T
#if defined(HAVE_CPP_CHAR16_T) || defined(HAVE_CPP_2BYTE_WCHAR_T)
#if defined(HAVE_CPP_CHAR16_T)
//PR_STATIC_ASSERT(sizeof(char16_t) == 2);
#define NS_LL(s) u##s
#else
//PR_STATIC_ASSERT(sizeof(wchar_t) == 2);
#define NS_LL(s) L##s
#define NS_MULTILINE_LITERAL_STRING(s) nsDependentString(reinterpret_cast<const nsAString::char_type*>(s), PRUint32((sizeof(s)/sizeof(wchar_t))-1))
#define NS_MULTILINE_LITERAL_STRING_INIT(n,s) n(reinterpret_cast<const nsAString::char_type*>(s), PRUint32((sizeof(s)/sizeof(wchar_t))-1))
#define NS_NAMED_MULTILINE_LITERAL_STRING(n,s) const nsDependentString n(reinterpret_cast<const nsAString::char_type*>(s), PRUint32((sizeof(s)/sizeof(wchar_t))-1))
#endif
#define NS_MULTILINE_LITERAL_STRING(s) nsDependentString(reinterpret_cast<const nsAString::char_type*>(s), PRUint32((sizeof(s)/2)-1))
#define NS_MULTILINE_LITERAL_STRING_INIT(n,s) n(reinterpret_cast<const nsAString::char_type*>(s), PRUint32((sizeof(s)/2)-1))
#define NS_NAMED_MULTILINE_LITERAL_STRING(n,s) const nsDependentString n(reinterpret_cast<const nsAString::char_type*>(s), PRUint32((sizeof(s)/2)-1))
typedef nsDependentString nsLiteralString;
#else
#define NS_LL(s) s

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

@ -560,11 +560,11 @@ class nsTXPIDLString_CharT : public nsTString_CharT
public:
nsTXPIDLString_CharT()
: string_type(const_cast<char_type*>(char_traits::sEmptyBuffer), 0, F_TERMINATED | F_VOIDED) {}
: string_type(char_traits::sEmptyBuffer, 0, F_TERMINATED | F_VOIDED) {}
// copy-constructor required to avoid default
nsTXPIDLString_CharT( const self_type& str )
: string_type(const_cast<char_type*>(char_traits::sEmptyBuffer), 0, F_TERMINATED | F_VOIDED)
: string_type(char_traits::sEmptyBuffer, 0, F_TERMINATED | F_VOIDED)
{
Assign(str);
}

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

@ -54,10 +54,10 @@
// ---------------------------------------------------------------------------
static const PRUnichar gNullChar = 0;
static PRUnichar gNullChar = 0;
const char* nsCharTraits<char> ::sEmptyBuffer = (const char*) &gNullChar;
const PRUnichar* nsCharTraits<PRUnichar>::sEmptyBuffer = &gNullChar;
char* nsCharTraits<char> ::sEmptyBuffer = (char*) &gNullChar;
PRUnichar* nsCharTraits<PRUnichar>::sEmptyBuffer = &gNullChar;
// ---------------------------------------------------------------------------

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

@ -59,7 +59,7 @@ nsTSubstring_CharT::nsTSubstring_CharT(const substring_tuple_type& tuple)
}
nsTSubstring_CharT::nsTSubstring_CharT()
: mData(const_cast<char_type*>(char_traits::sEmptyBuffer)),
: mData(char_traits::sEmptyBuffer),
mLength(0),
mFlags(F_TERMINATED) {}
@ -563,7 +563,7 @@ nsTSubstring_CharT::SetCapacity( size_type capacity )
if (capacity == 0)
{
::ReleaseData(mData, mFlags);
mData = const_cast<char_type*>(char_traits::sEmptyBuffer);
mData = char_traits::sEmptyBuffer;
mLength = 0;
SetDataFlags(F_TERMINATED);
}

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

@ -20,6 +20,9 @@
/* Define if the c++ compiler has builtin Bool type */
#undef HAVE_CPP_BOOL
/* Define if the c++ compiler supports char16_t */
#undef HAVE_CPP_CHAR16_T
/* Define if a dyanmic_cast to void* gives the most derived object */
#undef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR