зеркало из https://github.com/mozilla/gecko-dev.git
Merge places to mozilla-central.
This commit is contained in:
Коммит
39d40f70b0
|
@ -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;
|
||||
|
@ -50,20 +50,20 @@ void changeForwardSlashesTpBackSlashes ( wchar_t *arg )
|
|||
while ( *arg ) {
|
||||
if ( *arg == '/' )
|
||||
*arg = '\\';
|
||||
arg++;
|
||||
arg++;
|
||||
}
|
||||
}
|
||||
|
||||
int wmain(int argc, wchar_t *argv[ ])
|
||||
{
|
||||
return shellNsinstall ( argv + 1 );
|
||||
return shellNsinstall ( argv + 1 );
|
||||
}
|
||||
|
||||
static int
|
||||
shellNsinstall (wchar_t **pArgv)
|
||||
{
|
||||
int retVal = 0; /* exit status */
|
||||
int dirOnly = 0; /* 1 if and only if -D is specified */
|
||||
int retVal = 0; /* exit status */
|
||||
int dirOnly = 0; /* 1 if and only if -D is specified */
|
||||
wchar_t **pSrc;
|
||||
wchar_t **pDst;
|
||||
|
||||
|
@ -119,7 +119,7 @@ shellNsinstall (wchar_t **pArgv)
|
|||
static int
|
||||
shellMkdir (wchar_t **pArgv)
|
||||
{
|
||||
int retVal = 0; /* assume valid return */
|
||||
int retVal = 0; /* assume valid return */
|
||||
wchar_t *arg;
|
||||
wchar_t *pArg;
|
||||
wchar_t path[_MAX_PATH];
|
||||
|
@ -136,7 +136,7 @@ shellMkdir (wchar_t **pArgv)
|
|||
|
||||
while ( *pArgv ) {
|
||||
arg = *pArgv;
|
||||
changeForwardSlashesTpBackSlashes ( arg );
|
||||
changeForwardSlashesToBackSlashes ( arg );
|
||||
pArg = arg;
|
||||
pTmpPath = tmpPath;
|
||||
while ( 1 ) {
|
||||
|
@ -148,20 +148,19 @@ 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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( *pArg == '\0' ) /* complete path? */
|
||||
if ( *pArg == '\0' ) /* complete path? */
|
||||
break;
|
||||
/* loop for next directory */
|
||||
}
|
||||
|
@ -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;
|
||||
|
|
27
configure.in
27
configure.in
|
@ -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;
|
||||
|
@ -50,20 +50,20 @@ void changeForwardSlashesTpBackSlashes ( wchar_t *arg )
|
|||
while ( *arg ) {
|
||||
if ( *arg == '/' )
|
||||
*arg = '\\';
|
||||
arg++;
|
||||
arg++;
|
||||
}
|
||||
}
|
||||
|
||||
int wmain(int argc, wchar_t *argv[ ])
|
||||
{
|
||||
return shellNsinstall ( argv + 1 );
|
||||
return shellNsinstall ( argv + 1 );
|
||||
}
|
||||
|
||||
static int
|
||||
shellNsinstall (wchar_t **pArgv)
|
||||
{
|
||||
int retVal = 0; /* exit status */
|
||||
int dirOnly = 0; /* 1 if and only if -D is specified */
|
||||
int retVal = 0; /* exit status */
|
||||
int dirOnly = 0; /* 1 if and only if -D is specified */
|
||||
wchar_t **pSrc;
|
||||
wchar_t **pDst;
|
||||
|
||||
|
@ -119,7 +119,7 @@ shellNsinstall (wchar_t **pArgv)
|
|||
static int
|
||||
shellMkdir (wchar_t **pArgv)
|
||||
{
|
||||
int retVal = 0; /* assume valid return */
|
||||
int retVal = 0; /* assume valid return */
|
||||
wchar_t *arg;
|
||||
wchar_t *pArg;
|
||||
wchar_t path[_MAX_PATH];
|
||||
|
@ -136,7 +136,7 @@ shellMkdir (wchar_t **pArgv)
|
|||
|
||||
while ( *pArgv ) {
|
||||
arg = *pArgv;
|
||||
changeForwardSlashesTpBackSlashes ( arg );
|
||||
changeForwardSlashesToBackSlashes ( arg );
|
||||
pArg = arg;
|
||||
pTmpPath = tmpPath;
|
||||
while ( 1 ) {
|
||||
|
@ -148,20 +148,19 @@ 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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( *pArg == '\0' ) /* complete path? */
|
||||
if ( *pArg == '\0' ) /* complete path? */
|
||||
break;
|
||||
/* loop for next directory */
|
||||
}
|
||||
|
@ -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,12 +6216,14 @@ 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) {
|
||||
obj = js_CloneFunctionObject(cx, fun, parent);
|
||||
if (!obj)
|
||||
goto error;
|
||||
}
|
||||
/*
|
||||
* 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));
|
||||
|
@ -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;
|
||||
|
||||
|
|
548
js/src/jsobj.cpp
548
js/src/jsobj.cpp
|
@ -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,125 +2984,105 @@ 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.
|
||||
*/
|
||||
if (nwords <= MIN_DYNAMIC_WORDS) {
|
||||
nwords = MIN_DYNAMIC_WORDS;
|
||||
} else if (nwords < LINEAR_GROWTH_STEP) {
|
||||
JS_CEILING_LOG2(log, nwords);
|
||||
nwords = JS_BIT(log);
|
||||
} else {
|
||||
nwords = JS_ROUNDUP(nwords, LINEAR_GROWTH_STEP);
|
||||
}
|
||||
}
|
||||
slots = (jsval *)JS_realloc(cx, old, nwords * sizeof(jsval));
|
||||
if (!slots)
|
||||
return JS_FALSE;
|
||||
/*
|
||||
* 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) {
|
||||
JS_CEILING_LOG2(log, nwords);
|
||||
nwords = JS_BIT(log);
|
||||
} 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;
|
||||
nwords = JS_ROUNDUP(nwords, LINEAR_GROWTH_STEP);
|
||||
}
|
||||
|
||||
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 */
|
||||
|
|
1001
js/src/jsregexp.cpp
1001
js/src/jsregexp.cpp
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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,26 +192,41 @@ verbose_only( extern const char* shiftNames[]; )
|
|||
|
||||
#define DECLARE_PLATFORM_REGALLOC()
|
||||
|
||||
#define DECLARE_PLATFORM_ASSEMBLER() \
|
||||
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); \
|
||||
void underrunProtect(int bytes); \
|
||||
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_arg(ArgSize sz, LInsp arg, Register& r, int& stkd); \
|
||||
uint32_t CountLeadingZeroes(uint32_t data); \
|
||||
int* _nSlot; \
|
||||
int* _startingSlot; \
|
||||
int* _nExitSlot;
|
||||
#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 BranchWithLink(NIns*); \
|
||||
void JMP_far(NIns*); \
|
||||
void B_cond_chk(ConditionCode, NIns*, bool); \
|
||||
void underrunProtect(int bytes); \
|
||||
void nativePageReset(); \
|
||||
void nativePageSetup(); \
|
||||
void asm_quad_nochk(Register, int32_t, int32_t); \
|
||||
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, bool chk = true); \
|
||||
void asm_arg(ArgSize sz, LInsp arg, Register& r, int& stkd); \
|
||||
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
|
||||
|
@ -283,58 +298,36 @@ enum {
|
|||
#define IsOp(op) (((ARM_##op) >= ARM_and) && ((ARM_##op) <= ARM_mvn))
|
||||
|
||||
// ALU operation with register and 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)
|
||||
#define ALUi(cond, op, S, rd, rl, imm) do {\
|
||||
underrunProtect(4);\
|
||||
// S - bit, 0 or 1, whether the CPSR register is updated
|
||||
// rd - destination register
|
||||
// rl - first (left) operand register
|
||||
// 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
|
||||
#define ORR(_d,_l,_r) ALUr(AL, orr, 0, _d, _l, _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 OR _imm
|
||||
#define ORRi(_d,_l,_imm) ALUi(AL, orr, 0, _d, _l, _imm)
|
||||
// _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 AND _r
|
||||
#define AND(_d,_l,_r) ALUr(AL, and, 0, _d, _l, _r)
|
||||
// _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 AND _imm
|
||||
#define ANDi(_d,_l,_imm) ALUi(AL, and, 0, _d, _l, _imm)
|
||||
// _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 & _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 ^ _r
|
||||
#define EOR(_d,_l,_r) ALUr(AL, eor, 0, _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 { \
|
||||
|
@ -447,7 +463,9 @@ enum {
|
|||
#define RSBS(_d,_r) ALUi(AL, rsb, 1, _d, _r, 0)
|
||||
|
||||
// _d = ~_r (one's compliment)
|
||||
#define MVN(_d,_r) ALUr(AL, mvn, 0, _d, 0, _r)
|
||||
#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,7 +506,11 @@ enum {
|
|||
|
||||
// MOV
|
||||
|
||||
#define MOV_cond(_cond,_d,_s) ALUr(_cond, mov, 0, _d, 0, _s)
|
||||
#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)
|
||||
#define MOVEQ(dr,sr) MOV_cond(EQ, 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)
|
||||
|
||||
#define BKPT_insn ((NIns)( COND_AL | (0x12<<20) | (0x7<<4) ))
|
||||
#define BKPT_nochk() do { \
|
||||
*(--_nIns) = BKPT_insn; } 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 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;
|
||||
iframe_style.width = width_val + "px";
|
||||
iframe_style.height = height_val + "px";
|
||||
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)");
|
||||
}
|
||||
|
||||
iframe_style.width = "0";
|
||||
change_state(function() {
|
||||
iframe_style.width = "0";
|
||||
});
|
||||
should_apply("all and (height)");
|
||||
should_not_apply("all and (width)");
|
||||
iframe_style.height = "0";
|
||||
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)");
|
||||
iframe_style.width = width_val + "px";
|
||||
change_state(function() {
|
||||
iframe_style.width = width_val + "px";
|
||||
});
|
||||
should_not_apply("all and (height)");
|
||||
should_apply("all and (width)");
|
||||
iframe_style.height = height_val + "px";
|
||||
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
|
||||
iframe_style.width = "236px";
|
||||
iframe_style.height = "160px";
|
||||
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
|
||||
iframe_style.height = "320px";
|
||||
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");
|
||||
|
||||
SimpleTest.finish();
|
||||
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);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
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;
|
||||
PRBool retval = PR_FALSE;
|
||||
rv = authPrompt->PromptAuth(this,
|
||||
level,
|
||||
holder, &retval);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
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);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
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;
|
||||
|
||||
if (!retval)
|
||||
rv = NS_ERROR_ABORT;
|
||||
else
|
||||
holder->SetToHttpAuthIdentity(authFlags, ident);
|
||||
|
||||
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, ¤tlyUsesTLS);
|
||||
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, ¤tlyUsesTLS);
|
||||
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,7 +2194,15 @@ nsresult nsSSLIOLayerHelpers::Init()
|
|||
void nsSSLIOLayerHelpers::addIntolerantSite(const nsCString &str)
|
||||
{
|
||||
nsAutoLock lock(mutex);
|
||||
nsSSLIOLayerHelpers::mTLSIntolerantSites->Put(str);
|
||||
// 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)
|
||||
|
|
|
@ -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;
|
||||
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
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче