Merge places to mozilla-central.

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

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

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

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

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

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

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

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

@ -2727,52 +2727,6 @@ fi
AC_LANG_C 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 Check for .hidden assembler directive and visibility attribute.
dnl Borrowed from glibc configure.in dnl Borrowed from glibc configure.in
dnl =============================================================== dnl ===============================================================
@ -5073,7 +5027,6 @@ AC_SUBST(COMPILE_CXXFLAGS)
AC_SUBST(LDFLAGS) AC_SUBST(LDFLAGS)
AC_SUBST(LIBS) AC_SUBST(LIBS)
AC_SUBST(CROSS_COMPILE) AC_SUBST(CROSS_COMPILE)
AC_SUBST(WCHAR_CFLAGS)
AC_SUBST(HOST_CC) AC_SUBST(HOST_CC)
AC_SUBST(HOST_CXX) AC_SUBST(HOST_CXX)

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

@ -1847,7 +1847,7 @@ JS_malloc(JSContext *cx, size_t nbytes)
JS_ReportOutOfMemory(cx); JS_ReportOutOfMemory(cx);
return NULL; return NULL;
} }
js_UpdateMallocCounter(cx, nbytes); cx->updateMallocCounter(nbytes);
return p; return p;
} }
@ -1862,7 +1862,7 @@ JS_realloc(JSContext *cx, void *p, size_t nbytes)
return NULL; return NULL;
} }
if (!orig) if (!orig)
js_UpdateMallocCounter(cx, nbytes); cx->updateMallocCounter(nbytes);
return p; return p;
} }
@ -2585,7 +2585,7 @@ JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value)
default: default:
JS_ASSERT(key == JSGC_TRIGGER_FACTOR); JS_ASSERT(key == JSGC_TRIGGER_FACTOR);
JS_ASSERT(value >= 100); JS_ASSERT(value >= 100);
rt->gcTriggerFactor = value; rt->setGCTriggerFactor(value);
return; return;
} }
} }
@ -2650,8 +2650,7 @@ JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type)
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
JS_ASSERT((uintN) type < (uintN) (GCX_NTYPES - GCX_EXTERNAL_STRING)); JS_ASSERT((uintN) type < (uintN) (GCX_NTYPES - GCX_EXTERNAL_STRING));
str = (JSString *) js_NewGCThing(cx, (uintN) type + GCX_EXTERNAL_STRING, str = js_NewGCString(cx, (uintN) type + GCX_EXTERNAL_STRING);
sizeof(JSString));
if (!str) if (!str)
return NULL; return NULL;
str->initFlat(chars, length); str->initFlat(chars, length);
@ -2896,7 +2895,7 @@ JS_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
if (!clasp) if (!clasp)
clasp = &js_ObjectClass; /* default class is Object */ 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 *) JS_PUBLIC_API(JSObject *)
@ -2906,7 +2905,7 @@ JS_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
if (!clasp) if (!clasp)
clasp = &js_ObjectClass; /* default class is Object */ 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) JS_PUBLIC_API(JSBool)
@ -3064,7 +3063,7 @@ JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *clasp,
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
if (!clasp) if (!clasp)
clasp = &js_ObjectClass; /* default class is Object */ clasp = &js_ObjectClass; /* default class is Object */
nobj = js_NewObject(cx, clasp, proto, obj, 0); nobj = js_NewObject(cx, clasp, proto, obj);
if (!nobj) if (!nobj)
return NULL; return NULL;
if (!DefineProperty(cx, obj, name, OBJECT_TO_JSVAL(nobj), NULL, NULL, attrs, if (!DefineProperty(cx, obj, name, OBJECT_TO_JSVAL(nobj), NULL, NULL, attrs,
@ -4109,7 +4108,7 @@ JS_NewPropertyIterator(JSContext *cx, JSObject *obj)
JSIdArray *ida; JSIdArray *ida;
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
iterobj = js_NewObject(cx, &prop_iter_class, NULL, obj, 0); iterobj = js_NewObject(cx, &prop_iter_class, NULL, obj);
if (!iterobj) if (!iterobj)
return NULL; return NULL;
@ -4361,7 +4360,7 @@ JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
uint32 nslots = JSSLOT_FREE(&js_FunctionClass); uint32 nslots = JSSLOT_FREE(&js_FunctionClass);
JS_ASSERT(nslots == JS_INITIAL_NSLOTS); JS_ASSERT(nslots == JS_INITIAL_NSLOTS);
nslots += js_FunctionClass.reserveSlots(cx, clone); nslots += js_FunctionClass.reserveSlots(cx, clone);
if (!js_ReallocSlots(cx, clone, nslots, JS_TRUE)) if (!js_AllocSlots(cx, clone, nslots))
return NULL; return NULL;
JSUpvarArray *uva = JS_SCRIPT_UPVARS(fun->u.i.script); JSUpvarArray *uva = JS_SCRIPT_UPVARS(fun->u.i.script);
@ -4822,12 +4821,12 @@ JS_NewScriptObject(JSContext *cx, JSScript *script)
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
if (!script) 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_ASSERT(!script->u.object);
JS_PUSH_TEMP_ROOT_SCRIPT(cx, script, &tvr); 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) { if (obj) {
JS_SetPrivate(cx, obj, script); JS_SetPrivate(cx, obj, script);
script->u.object = obj; 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 called without new, replace obj with a new Array object. */
if (!JS_IsConstructing(cx)) { if (!JS_IsConstructing(cx)) {
obj = js_NewObject(cx, &js_ArrayClass, NULL, NULL, 0); obj = js_NewObject(cx, &js_ArrayClass, NULL, NULL);
if (!obj) if (!obj)
return JS_FALSE; return JS_FALSE;
*rval = OBJECT_TO_JSVAL(obj); *rval = OBJECT_TO_JSVAL(obj);
@ -3381,7 +3381,7 @@ js_NewEmptyArray(JSContext* cx, JSObject* proto)
JS_ASSERT(OBJ_IS_ARRAY(cx, proto)); JS_ASSERT(OBJ_IS_ARRAY(cx, proto));
JS_ASSERT(JS_ON_TRACE(cx)); 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) if (!obj)
return NULL; return NULL;
@ -3442,7 +3442,7 @@ js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector, JSBool holey)
JSTempValueRooter tvr; JSTempValueRooter tvr;
JSObject *obj; JSObject *obj;
obj = js_NewObject(cx, &js_ArrayClass, NULL, NULL, 0); obj = js_NewObject(cx, &js_ArrayClass, NULL, NULL);
if (!obj) if (!obj)
return NULL; return NULL;
@ -3459,7 +3459,7 @@ js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector, JSBool holey)
JSObject * JSObject *
js_NewSlowArrayObject(JSContext *cx) 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) if (obj)
obj->fslots[JSSLOT_ARRAY_LENGTH] = 0; obj->fslots[JSSLOT_ARRAY_LENGTH] = 0;
return obj; return obj;

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

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

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

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

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

@ -308,7 +308,7 @@ HasProperty(JSContext* cx, JSObject* obj, jsid id)
JSObject* obj2; JSObject* obj2;
JSProperty* prop; 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); return JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID);
if (prop) if (prop)
OBJ_DROP_PROPERTY(cx, obj2, prop); OBJ_DROP_PROPERTY(cx, obj2, prop);
@ -390,7 +390,7 @@ js_Arguments(JSContext* cx, JSObject* parent, JSObject* cached)
{ {
if (cached) if (cached)
return 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) 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; JSFunction *fun = (JSFunction*) funobj;
JS_ASSERT(GET_FUNCTION_PRIVATE(cx, funobj) == fun); 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) if (!closure)
return NULL; return NULL;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -115,9 +115,11 @@ JS_HashTableDestroy(JSHashTable *ht);
extern JS_PUBLIC_API(JSHashEntry **) extern JS_PUBLIC_API(JSHashEntry **)
JS_HashTableRawLookup(JSHashTable *ht, JSHashNumber keyHash, const void *key); JS_HashTableRawLookup(JSHashTable *ht, JSHashNumber keyHash, const void *key);
#ifdef __cplusplus
extern JS_PUBLIC_API(JSHashEntry *) 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); const void *key, void *value);
#endif
extern JS_PUBLIC_API(void) extern JS_PUBLIC_API(void)
JS_HashTableRawRemove(JSHashTable *ht, JSHashEntry **hep, JSHashEntry *he); JS_HashTableRawRemove(JSHashTable *ht, JSHashEntry **hep, JSHashEntry *he);

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

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

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

@ -2011,29 +2011,6 @@ static JSFunctionSpec object_static_methods[] = {
JS_FS_END 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 static inline bool
InitScopeForObject(JSContext* cx, JSObject* obj, JSObject* proto, InitScopeForObject(JSContext* cx, JSObject* obj, JSObject* proto,
JSObjectOps* ops) JSObjectOps* ops)
@ -2072,7 +2049,7 @@ InitScopeForObject(JSContext* cx, JSObject* obj, JSObject* proto,
/* Let JSScope::create set freeslot so as to reserve slots. */ /* Let JSScope::create set freeslot so as to reserve slots. */
JS_ASSERT(scope->freeslot >= JSSLOT_PRIVATE); JS_ASSERT(scope->freeslot >= JSSLOT_PRIVATE);
if (scope->freeslot > JS_INITIAL_NSLOTS && if (scope->freeslot > JS_INITIAL_NSLOTS &&
!js_ReallocSlots(cx, obj, scope->freeslot, JS_TRUE)) { !js_AllocSlots(cx, obj, scope->freeslot)) {
JSScope::destroy(cx, scope); JSScope::destroy(cx, scope);
goto bad; goto bad;
} }
@ -2085,13 +2062,156 @@ InitScopeForObject(JSContext* cx, JSObject* obj, JSObject* proto,
return false; 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 #ifdef JS_TRACER
static inline JSObject* static inline JSObject*
NewNativeObject(JSContext* cx, JSClass* clasp, JSObject* proto, JSObject *parent) NewNativeObject(JSContext* cx, JSClass* clasp, JSObject* proto, JSObject *parent)
{ {
JS_ASSERT(JS_ON_TRACE(cx)); 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) if (!obj)
return NULL; return NULL;
@ -2141,7 +2261,7 @@ js_NewInstance(JSContext *cx, JSClass *clasp, JSObject *ctor)
proto = JSVAL_TO_OBJECT(pval); proto = JSVAL_TO_OBJECT(pval);
} else if (pval == JSVAL_HOLE) { } else if (pval == JSVAL_HOLE) {
/* No ctor.prototype yet, inline and optimize fun_resolve's prototype code. */ /* 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) if (!proto)
return NULL; return NULL;
if (!js_SetClassPrototype(cx, ctor, proto, JSPROP_ENUMERATE | JSPROP_PERMANENT)) 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; JSObject *obj;
obj = js_NewObject(cx, &js_WithClass, proto, parent, 0); obj = js_NewObject(cx, &js_WithClass, proto, parent);
if (!obj) if (!obj)
return NULL; return NULL;
STOBJ_SET_SLOT(obj, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(cx->fp)); 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. * scopes and to give the block object its own scope.
*/ */
JSObject *blockObj = js_NewObjectWithGivenProto(cx, &js_BlockClass, JSObject *blockObj = js_NewObjectWithGivenProto(cx, &js_BlockClass,
NULL, NULL, 0); NULL, NULL);
JS_ASSERT_IF(blockObj, !OBJ_IS_CLONED_BLOCK(blockObj)); JS_ASSERT_IF(blockObj, !OBJ_IS_CLONED_BLOCK(blockObj));
return 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(STOBJ_GET_CLASS(proto) == &js_BlockClass);
JS_ASSERT(!OBJ_IS_CLONED_BLOCK(proto)); 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) if (!clone)
return NULL; return NULL;
STOBJ_SET_SLOT(clone, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(fp)); STOBJ_SET_SLOT(clone, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(fp));
@ -2489,7 +2609,7 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
if (normalUnwind && count > 1) { if (normalUnwind && count > 1) {
--count; --count;
JS_LOCK_OBJ(cx, obj); 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; normalUnwind = JS_FALSE;
else else
memcpy(obj->dslots, fp->slots + depth + 1, count * sizeof(jsval)); 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. */ /* 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) if (!proto)
return NULL; return NULL;
@ -2864,65 +2984,52 @@ bad:
#define DYNAMIC_WORDS_TO_SLOTS(words) \ #define DYNAMIC_WORDS_TO_SLOTS(words) \
(JS_ASSERT((words) > 1), (words) - 1 + JS_INITIAL_NSLOTS) (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. * 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 * The limit to switch to linear allocation strategy from the power of 2
* growth no to waste too much memory. * 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 we are allocating fslots, there is nothing to do. */
if (nslots <= JS_INITIAL_NSLOTS) { 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);
}
return JS_TRUE; return JS_TRUE;
}
oslots = (old) ? (uint32)*--old : JS_INITIAL_NSLOTS; size_t nwords = SLOTS_TO_DYNAMIC_WORDS(nslots);
nwords = SLOTS_TO_DYNAMIC_WORDS(nslots);
if (nslots > oslots) {
if (!exactAllocation) {
/* /*
* Round up nslots so the number of bytes in dslots array is power * Round up nslots so the number of bytes in dslots array is power
* of 2 to ensure exponential grouth. * of 2 to ensure exponential grouth.
*/ */
uintN log;
if (nwords <= MIN_DYNAMIC_WORDS) { if (nwords <= MIN_DYNAMIC_WORDS) {
nwords = MIN_DYNAMIC_WORDS; nwords = MIN_DYNAMIC_WORDS;
} else if (nwords < LINEAR_GROWTH_STEP) { } else if (nwords < LINEAR_GROWTH_STEP) {
@ -2931,58 +3038,51 @@ js_ReallocSlots(JSContext *cx, JSObject *obj, uint32 nslots,
} else { } else {
nwords = JS_ROUNDUP(nwords, LINEAR_GROWTH_STEP); nwords = JS_ROUNDUP(nwords, LINEAR_GROWTH_STEP);
} }
}
slots = (jsval *)JS_realloc(cx, old, nwords * sizeof(jsval));
if (!slots)
return JS_FALSE;
} else {
JS_ASSERT(nslots < oslots);
if (!exactAllocation) {
owords = DYNAMIC_WORDS_TO_SLOTS(oslots);
if (owords <= MIN_DYNAMIC_WORDS)
return JS_TRUE;
if (owords < LINEAR_GROWTH_STEP * 2) {
/*
* Shrink only if 1/4 of slots are left and we need to grow
* the array at least twice to reach the current capacity. It
* prevents frequent capacity growth/shrinking when slots are
* often removed and added.
*/
if (nwords > owords / 4)
return JS_TRUE;
JS_CEILING_LOG2(log, nwords);
nwords = JS_BIT(log);
if (nwords < MIN_DYNAMIC_WORDS)
nwords = MIN_DYNAMIC_WORDS;
} else {
/*
* Shrink only if we free at least 2 linear allocation
* segments, to prevent growth/shrinking resonance.
*/
if (nwords > owords - LINEAR_GROWTH_STEP * 2)
return JS_TRUE;
nwords = JS_ROUNDUP(nwords, LINEAR_GROWTH_STEP);
}
}
/* We avoid JS_realloc not to report a failed shrink attempt. */
slots = (jsval *)realloc(old, nwords * sizeof(jsval));
if (!slots)
slots = old;
}
nslots = DYNAMIC_WORDS_TO_SLOTS(nwords); 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; obj->dslots = slots;
/* If we're extending an allocation, initialize free slots. */ /* Initialize the additional slots we added. */
for (i = oslots; i < nslots; i++) JS_ASSERT(nslots > oslots);
for (size_t i = oslots; i < nslots; i++)
slots[i - JS_INITIAL_NSLOTS] = JSVAL_VOID; slots[i - JS_INITIAL_NSLOTS] = JSVAL_VOID;
return JS_TRUE; return true;
}
#undef LINEAR_GROWTH_STEP void
#undef MIN_DYNAMIC_WORDS 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 extern JSBool
@ -3005,131 +3105,6 @@ js_GetClassId(JSContext *cx, JSClass *clasp, jsid *idp)
return JS_TRUE; 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* JSObject*
js_NewNativeObject(JSContext *cx, JSClass *clasp, JSObject *proto, uint32 slot) 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(proto->map->ops == &js_ObjectOps);
JS_ASSERT(OBJ_GET_CLASS(cx, proto) == clasp); 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) if (!obj)
return NULL; return NULL;
@ -3360,7 +3335,7 @@ js_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto,
proto = JSVAL_TO_OBJECT(rval); proto = JSVAL_TO_OBJECT(rval);
} }
obj = js_NewObject(cx, clasp, proto, parent, 0); obj = js_NewObject(cx, clasp, proto, parent);
if (!obj) if (!obj)
goto out; goto out;
@ -3413,7 +3388,7 @@ js_AllocSlot(JSContext *cx, JSObject *obj, uint32 *slotp)
} }
if (scope->freeslot >= STOBJ_NSLOTS(obj) && 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; return JS_FALSE;
} }
@ -3430,12 +3405,8 @@ js_FreeSlot(JSContext *cx, JSObject *obj, uint32 slot)
JSScope *scope = OBJ_SCOPE(obj); JSScope *scope = OBJ_SCOPE(obj);
LOCKED_OBJ_SET_SLOT(obj, slot, JSVAL_VOID); LOCKED_OBJ_SET_SLOT(obj, slot, JSVAL_VOID);
if (scope->freeslot == slot + 1) { if (scope->freeslot == slot + 1)
scope->freeslot = slot; 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); v = save = OBJECT_TO_JSVAL(obj);
switch (hint) { switch (hint) {
case JSTYPE_STRING: 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 * Propagate the exception if js_TryMethod finds an appropriate
* method, and calling that method returned failure. * 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_OBJECT(*vp));
JS_ASSERT(!JSVAL_IS_VOID(*vp)); JS_ASSERT(!JSVAL_IS_VOID(*vp));
clasp = PrimitiveClasses[JSVAL_TAG(*vp) - 1]; clasp = PrimitiveClasses[JSVAL_TAG(*vp) - 1];
obj = js_NewObject(cx, clasp, NULL, NULL, 0); obj = js_NewObject(cx, clasp, NULL, NULL);
if (!obj) if (!obj)
return JS_FALSE; return JS_FALSE;
STOBJ_SET_SLOT(obj, JSSLOT_PRIVATE, *vp); STOBJ_SET_SLOT(obj, JSSLOT_PRIVATE, *vp);
@ -5748,6 +5761,13 @@ js_TraceObject(JSTracer *trc, JSObject *obj)
} }
if (traceScope) { 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 #ifdef JS_DUMP_SCOPE_METERS
MeterEntryCount(scope->entryCount); MeterEntryCount(scope->entryCount);
#endif #endif
@ -5880,7 +5900,7 @@ js_SetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot, jsval v)
if (clasp->reserveSlots) if (clasp->reserveSlots)
nslots += clasp->reserveSlots(cx, obj); nslots += clasp->reserveSlots(cx, obj);
JS_ASSERT(slot < nslots); JS_ASSERT(slot < nslots);
if (!js_ReallocSlots(cx, obj, nslots, JS_TRUE)) { if (!js_AllocSlots(cx, obj, nslots)) {
JS_UNLOCK_SCOPE(cx, scope); JS_UNLOCK_SCOPE(cx, scope);
return JS_FALSE; return JS_FALSE;
} }

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

@ -529,18 +529,15 @@ extern JSBool
js_GetClassId(JSContext *cx, JSClass *clasp, jsid *idp); js_GetClassId(JSContext *cx, JSClass *clasp, jsid *idp);
extern JSObject * extern JSObject *
js_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent, js_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto,
uintN objectSize); JSObject *parent, size_t objectSize = 0);
/* /*
* See jsapi.h, JS_NewObjectWithGivenProto. * 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 * extern JSObject *
js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto, 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 * 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 extern void
js_FreeSlot(JSContext *cx, JSObject *obj, uint32 slot); 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 static inline void
js_FreeSlots(JSContext *cx, JSObject *obj) js_FreeSlots(JSContext *cx, JSObject *obj)
{ {
if (obj->dslots) { if (obj->dslots)
JS_ASSERT((uint32)obj->dslots[-1] > JS_INITIAL_NSLOTS); js_ShrinkSlots(cx, obj, 0);
JS_free(cx, obj->dslots - 1);
obj->dslots = NULL;
}
} }
extern jsid extern jsid

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

@ -609,7 +609,7 @@ js_Stringify(JSContext *cx, jsval *vp, JSObject *replacer, jsval space,
if (!InitializeGap(cx, space, &scx.gap)) if (!InitializeGap(cx, space, &scx.gap))
return JS_FALSE; return JS_FALSE;
JSObject *obj = js_NewObject(cx, &js_ObjectClass, NULL, NULL, 0); JSObject *obj = js_NewObject(cx, &js_ObjectClass, NULL, NULL);
if (!obj) if (!obj)
return JS_FALSE; return JS_FALSE;
@ -714,7 +714,7 @@ static JSBool
Revive(JSContext *cx, jsval reviver, jsval *vp) 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) if (!obj)
return JS_FALSE; return JS_FALSE;
@ -921,7 +921,7 @@ PushObject(JSContext *cx, JSONParser *jp, JSObject *obj)
static JSBool static JSBool
OpenObject(JSContext *cx, JSONParser *jp) 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) if (!obj)
return JS_FALSE; 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) { while ((pnu = *pnup) != NULL && pnu->pn_blockid >= start) {
JS_ASSERT(pnu->pn_used); JS_ASSERT(pnu->pn_used);
pnu->pn_lexdef = (JSDefinition *) pn; 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; 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_used);
JS_ASSERT(!pnu->pn_defn); JS_ASSERT(!pnu->pn_defn);
pnu->pn_lexdef = (JSDefinition *) pn; 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; pn->dn_uses = dn;
dn->pn_defn = false; dn->pn_defn = false;
@ -3071,7 +3071,7 @@ BindLet(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
*/ */
uintN slot = JSSLOT_FREE(&js_BlockClass) + n; uintN slot = JSSLOT_FREE(&js_BlockClass) + n;
if (slot >= STOBJ_NSLOTS(blockObj) && if (slot >= STOBJ_NSLOTS(blockObj) &&
!js_ReallocSlots(cx, blockObj, slot + 1, JS_FALSE)) { !js_GrowSlots(cx, blockObj, slot + 1)) {
return JS_FALSE; return JS_FALSE;
} }
OBJ_SCOPE(blockObj)->freeslot = slot + 1; OBJ_SCOPE(blockObj)->freeslot = slot + 1;
@ -4335,7 +4335,7 @@ RebindLets(JSParseNode *pn, JSTreeContext *tc)
JSDefinition *dn = ALE_DEFN(ale); JSDefinition *dn = ALE_DEFN(ale);
dn->pn_type = TOK_NAME; dn->pn_type = TOK_NAME;
dn->pn_op = JSOP_NOP; 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); LinkUseToDef(pn, ALE_DEFN(ale), tc);
} }
@ -6403,7 +6403,7 @@ CompExprTransplanter::transplant(JSParseNode *pn)
JSParseNode *pnu; JSParseNode *pnu;
while ((pnu = *pnup) != NULL && pnu->pn_pos >= root->pn_pos) { while ((pnu = *pnup) != NULL && pnu->pn_pos >= root->pn_pos) {
pnu->pn_lexdef = dn2; 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; pnup = &pnu->pn_link;
} }
dn2->dn_uses = dn->dn_uses; dn2->dn_uses = dn->dn_uses;

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

@ -418,6 +418,9 @@ struct JSParseNode {
#define PND_FUNARG 0x100 /* downward or upward funarg usage */ #define PND_FUNARG 0x100 /* downward or upward funarg usage */
#define PND_BOUND 0x200 /* bound to a stack or global slot */ #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. */ /* PN_LIST pn_xflags bits. */
#define PNX_STRCAT 0x01 /* TOK_PLUS list has string term */ #define PNX_STRCAT 0x01 /* TOK_PLUS list has string term */
#define PNX_CANTFOLD 0x02 /* TOK_PLUS list has unfoldable term */ #define PNX_CANTFOLD 0x02 /* TOK_PLUS list has unfoldable term */

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

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

@ -172,7 +172,7 @@ JSScope::createTable(JSContext *cx, bool report)
JS_ReportOutOfMemory(cx); JS_ReportOutOfMemory(cx);
return false; return false;
} }
js_UpdateMallocCounter(cx, JS_BIT(sizeLog2) * sizeof(JSScopeProperty *)); cx->updateMallocCounter(JS_BIT(sizeLog2) * sizeof(JSScopeProperty *));
hashShift = JS_DHASH_BITS - sizeLog2; hashShift = JS_DHASH_BITS - sizeLog2;
for (sprop = lastProp; sprop; sprop = sprop->parent) { 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 not constructing, replace obj with a new Script object. */
if (!JS_IsConstructing(cx)) { if (!JS_IsConstructing(cx)) {
obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL, 0); obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL);
if (!obj) if (!obj)
return JS_FALSE; return JS_FALSE;

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

@ -716,8 +716,8 @@ str_toSource(JSContext *cx, uintN argc, jsval *vp)
#endif /* JS_HAS_TOSOURCE */ #endif /* JS_HAS_TOSOURCE */
static JSBool JSBool
str_toString(JSContext *cx, uintN argc, jsval *vp) js_str_toString(JSContext *cx, uintN argc, jsval *vp)
{ {
return js_GetPrimitiveThis(cx, vp, &js_StringClass, vp); return js_GetPrimitiveThis(cx, vp, &js_StringClass, vp);
} }
@ -2399,7 +2399,7 @@ js_String_getelem(JSContext* cx, JSString* str, int32 i)
} }
#endif #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))) (2, (extern, STRING_RETRY, String_p_toString, CONTEXT, THIS, 1, 1)))
JS_DEFINE_TRCINFO_1(str_charAt, JS_DEFINE_TRCINFO_1(str_charAt,
(3, (extern, STRING_RETRY, js_String_getelem, CONTEXT, THIS_STRING, INT32, 1, 1))) (3, (extern, STRING_RETRY, js_String_getelem, CONTEXT, THIS_STRING, INT32, 1, 1)))
@ -2420,9 +2420,10 @@ static JSFunctionSpec string_methods[] = {
#endif #endif
/* Java-like methods. */ /* Java-like methods. */
JS_TN(js_toString_str, str_toString, 0,JSFUN_THISP_STRING, str_toString_trcinfo), JS_TN(js_toString_str, js_str_toString, 0,JSFUN_THISP_STRING,
JS_FN(js_valueOf_str, str_toString, 0,JSFUN_THISP_STRING), js_str_toString_trcinfo),
JS_FN(js_toJSON_str, str_toString, 0,JSFUN_THISP_STRING), 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("substring", str_substring, 2,GENERIC_PRIMITIVE),
JS_FN("toLowerCase", str_toLowerCase, 0,GENERIC_PRIMITIVE), JS_FN("toLowerCase", str_toLowerCase, 0,GENERIC_PRIMITIVE),
JS_FN("toUpperCase", str_toUpperCase, 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; return NULL;
} }
str = (JSString *) js_NewGCThing(cx, GCX_STRING, sizeof(JSString)); str = js_NewGCString(cx, GCX_STRING);
if (!str) if (!str)
return NULL; return NULL;
str->initFlat(chars, length); 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); 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) if (!ds)
return NULL; return NULL;
if (start == 0) 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', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'-', '_', '.', '!', '~', '*', '\'', '(', ')', 0}; '-', '_', '.', '!', '~', '*', '\'', '(', ')', 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 #define URI_CHUNK 64U
/* Concatenate jschars onto the buffer */ /* Concatenate jschars onto the buffer */

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

@ -469,11 +469,18 @@ typedef enum JSCharType {
#define JS_ISFORMAT(c) (((1 << JSCT_FORMAT) >> JS_CTYPE(c)) & 1) #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 * This table is used in JS_ISWORD. The definition has external linkage to
* "word", as far as a RegExp is concerned. If we want a Unicode-friendlier * allow the raw table data to be used in the regular expression compiler.
* definition of "word", we should rename this macro to something regexp-y.
*/ */
#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_ISIDSTART(c) (JS_ISLETTER(c) || (c) == '_' || (c) == '$')
#define JS_ISIDENT(c) (JS_ISIDPART(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, js_str_escape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval); jsval *rval);
extern JSBool
js_str_toString(JSContext *cx, uintN argc, jsval *vp);
extern JSBool extern JSBool
js_StringReplaceHelper(JSContext *cx, uintN argc, JSObject *lambda, js_StringReplaceHelper(JSContext *cx, uintN argc, JSObject *lambda,
JSString *repstr, jsval *vp); JSString *repstr, jsval *vp);

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

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

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

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

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

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

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

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

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

@ -122,15 +122,16 @@ struct JSXML {
JSObject *name; JSObject *name;
uint16 xml_class; /* discriminates u, below */ uint16 xml_class; /* discriminates u, below */
uint16 xml_flags; /* flags, see below */ uint16 xml_flags; /* flags, see below */
uint32 align;
union { union {
JSXMLListVar list; JSXMLListVar list;
JSXMLElemVar elem; JSXMLElemVar elem;
JSString *value; JSString *value;
} u; } 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 */ /* union member shorthands */
#define xml_kids u.list.kids #define xml_kids u.list.kids
#define xml_target u.list.target #define xml_target u.list.target

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

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

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

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

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

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

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

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

@ -77,11 +77,11 @@ OPDEF(unused5, 5,-1, None)
OPDEF(unused6, 6,-1, None) OPDEF(unused6, 6,-1, None)
/* non-pure operations */ /* non-pure operations */
OPDEF(addp, 7, 2, Op2) // integer addition for temporary pointer calculations OPDEF(iaddp, 7, 2, Op2) // 32-bit integer addition for temporary pointer calculations
OPDEF(param, 8, 0, P) // load a parameter OPDEF(iparam, 8, 0, P) // load a parameter (32-bit register or stack location)
OPDEF(unused9, 9,-1, None) OPDEF(unused9, 9,-1, None)
OPDEF(ld, 10, 1, Ld) // 32-bit load 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(sti, 12, 2, Sti) // 32-bit store
OPDEF(ret, 13, 1, Op1) // return a word-sized value OPDEF(ret, 13, 1, Op1) // return a word-sized value
OPDEF(live, 14, 1, Op1) // extend live range of reference 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(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) #if defined(NANOJIT_64BIT)
OPDEF(callh, 26,-1, None) // unused on 64-bit machines OPDEF(callh, 26,-1, None) // unused on 64-bit machines
#else #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(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) 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(file, 1, 2, Op1) // source filename for debug symbols
OPDEF64(line, 2, 2, Op1) // source line number 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 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. // this marker are subject to CSE.
OPDEF64(quad, LIR_int, 0, I64) // 64-bit (quad) constant value 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(unused26_64, 26,-1, None)
OPDEF64(unused27_64, 27,-1, None) OPDEF64(unused27_64, 27,-1, None)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -3596,7 +3596,7 @@ static JSFunctionSpec shell_functions[] = {
JS_FS("help", Help, 0,0,0), JS_FS("help", Help, 0,0,0),
JS_FS("quit", Quit, 0,0,0), JS_FS("quit", Quit, 0,0,0),
JS_FN("assertEq", AssertEq, 2,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("gcparam", GCParameter, 2,0),
JS_FN("countHeap", CountHeap, 0,0), JS_FN("countHeap", CountHeap, 0,0),
#ifdef JS_GC_ZEAL #ifdef JS_GC_ZEAL

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

@ -28,7 +28,7 @@ if (!('gReportSummary' in this))
var testName = null; var testName = null;
if ("arguments" in this && arguments.length > 0) if ("arguments" in this && arguments.length > 0)
testName = arguments[0]; testName = arguments[0];
var fails = [], passes=[]; var fails = [], passes = [];
function jitstatHandler(f) function jitstatHandler(f)
{ {
@ -5406,6 +5406,60 @@ function testDivisionWithNegative1() {
testDivisionWithNegative1.expected = -Infinity; testDivisionWithNegative1.expected = -Infinity;
test(testDivisionWithNegative1); 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, box_shadow,
MozBoxShadow, MozBoxShadow,
CSS_PROPERTY_APPLIES_TO_FIRST_LETTER | 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, Margin,
mBoxShadow, mBoxShadow,
eCSSType_ValueList, eCSSType_ValueList,

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

@ -9,7 +9,7 @@
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<style type="text/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; } #two { background: transparent; border: thin solid; }
#five, #six {border: thick solid red; -moz-border-start-color:green; -moz-border-end-color:blue} #five, #six {border: thick solid red; -moz-border-start-color:green; -moz-border-end-color:blue}
#seven { #seven {
@ -93,6 +93,8 @@ function part1()
"-moz-column-rule-color applies"); "-moz-column-rule-color applies");
isnot(cs1.textShadow, cs2.textShadow, isnot(cs1.textShadow, cs2.textShadow,
"text-shadow applies"); "text-shadow applies");
isnot(cs1.MozBoxShadow, cs2.MozBoxShadow,
"-moz-box-shadow applies");
is(cs1.borderTopColor, cs3.borderTopColor, "border-top-color applies"); is(cs1.borderTopColor, cs3.borderTopColor, "border-top-color applies");
is(cs1.borderRightColor, cs3.borderRightColor, is(cs1.borderRightColor, cs3.borderRightColor,
"border-right-color applies"); "border-right-color applies");
@ -102,8 +104,10 @@ function part1()
"border-top-color applies"); "border-top-color applies");
is(cs1.MozColumnRuleColor, cs3.MozColumnRuleColor, is(cs1.MozColumnRuleColor, cs3.MozColumnRuleColor,
"-moz-column-rule-color applies"); "-moz-column-rule-color applies");
is(cs1.TextShadow, cs3.TextShadow, is(cs1.textShadow, cs3.textShadow,
"text-shadow applies"); "text-shadow applies");
is(cs1.MozBoxShadow, cs3.MozBoxShadow,
"-moz-box-shadow applies");
isnot(cs5.borderRightColor, cs2.borderRightColor, isnot(cs5.borderRightColor, cs2.borderRightColor,
"-moz-border-end-color applies"); "-moz-border-end-color applies");
isnot(cs5.borderLeftColor, cs2.borderLeftColor, isnot(cs5.borderLeftColor, cs2.borderLeftColor,
@ -172,8 +176,10 @@ function part2()
"border-bottom-color is blocked"); "border-bottom-color is blocked");
is(cs1.MozColumnRuleColor, cs2.MozColumnRuleColor, is(cs1.MozColumnRuleColor, cs2.MozColumnRuleColor,
"-moz-column-rule-color is blocked"); "-moz-column-rule-color is blocked");
is(cs1.TextShadow, cs2.TextShadow, is(cs1.textShadow, cs2.textShadow,
"text-shadow is blocked"); "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.backgroundColor, cs1.backgroundColor, "background-color transparency preserved (opaque)");
is(cs3.color, cs4.color, "color is blocked"); is(cs3.color, cs4.color, "color is blocked");
is(cs3.borderTopColor, cs4.borderTopColor, "border-top-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(); SimpleTest.waitForExplicitFinish();
var iframe;
function run() { function run() {
var subdoc = document.getElementById("subdoc").contentDocument; iframe = document.getElementById("subdoc");
var subwin = document.getElementById("subdoc").contentWindow; var subdoc = iframe.contentDocument;
var subwin = iframe.contentWindow;
var style = subdoc.getElementById("style"); 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, ""); var body_cs = subdoc.defaultView.getComputedStyle(subdoc.body, "");
function query_applies(q) { function query_applies(q) {
@ -46,6 +49,16 @@ function run() {
test_serialization(q, true, false); 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 * Functions to test whether a query is parseable at all. (Should not
* be used for parse errors within expressions.) * be used for parse errors within expressions.)
@ -107,8 +120,37 @@ function run() {
if (test_application) { if (test_application) {
var applies = body_cs.getPropertyValue("text-decoration") == "underline"; var applies = body_cs.getPropertyValue("text-decoration") == "underline";
is(applies, should_apply, 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. // 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 // in this test, assume the common underlying implementation is correct
var width_val = 117; // pick two not-too-round numbers var width_val = 117; // pick two not-too-round numbers
var height_val = 76; var height_val = 76;
change_state(function() {
iframe_style.width = width_val + "px"; iframe_style.width = width_val + "px";
iframe_style.height = height_val + "px"; iframe_style.height = height_val + "px";
});
var device_width = window.screen.width; var device_width = window.screen.width;
var device_height = window.screen.height; var device_height = window.screen.height;
features = { "width": width_val, features = { "width": width_val,
@ -181,24 +225,34 @@ function run() {
(Math.floor(value/em_size) - 1) + "em)"); (Math.floor(value/em_size) - 1) + "em)");
} }
change_state(function() {
iframe_style.width = "0"; iframe_style.width = "0";
});
should_apply("all and (height)"); should_apply("all and (height)");
should_not_apply("all and (width)"); should_not_apply("all and (width)");
change_state(function() {
iframe_style.height = "0"; iframe_style.height = "0";
});
should_not_apply("all and (height)"); should_not_apply("all and (height)");
should_not_apply("all and (width)"); should_not_apply("all and (width)");
should_apply("all and (device-height)"); should_apply("all and (device-height)");
should_apply("all and (device-width)"); should_apply("all and (device-width)");
change_state(function() {
iframe_style.width = width_val + "px"; iframe_style.width = width_val + "px";
});
should_not_apply("all and (height)"); should_not_apply("all and (height)");
should_apply("all and (width)"); should_apply("all and (width)");
change_state(function() {
iframe_style.height = height_val + "px"; iframe_style.height = height_val + "px";
});
should_apply("all and (height)"); should_apply("all and (height)");
should_apply("all and (width)"); should_apply("all and (width)");
// ratio that reduces to 59/40 // ratio that reduces to 59/40
change_state(function() {
iframe_style.width = "236px"; iframe_style.width = "236px";
iframe_style.height = "160px"; iframe_style.height = "160px";
});
expression_should_be_parseable("orientation"); expression_should_be_parseable("orientation");
expression_should_be_parseable("orientation: portrait"); expression_should_be_parseable("orientation: portrait");
expression_should_be_parseable("orientation: landscape"); expression_should_be_parseable("orientation: landscape");
@ -213,7 +267,9 @@ function run() {
should_not_apply("(orientation: portrait)"); should_not_apply("(orientation: portrait)");
should_apply("not all and (orientation: portrait)"); should_apply("not all and (orientation: portrait)");
// ratio that reduces to 59/80 // ratio that reduces to 59/80
change_state(function() {
iframe_style.height = "320px"; iframe_style.height = "320px";
});
should_apply("(orientation)"); should_apply("(orientation)");
should_not_apply("(orientation: landscape)"); should_not_apply("(orientation: landscape)");
should_apply("not all and (orientation: landscape)"); should_apply("not all and (orientation: landscape)");
@ -438,16 +494,16 @@ function run() {
// Parsing tests // Parsing tests
// bug 454227 // bug 454227
should_apply("(orientation"); should_apply_unbalanced("(orientation");
should_not_apply("not all and (orientation"); should_not_apply_unbalanced("not all and (orientation");
should_not_apply("(orientation:"); should_not_apply_unbalanced("(orientation:");
should_apply("all,(orientation:"); should_apply_unbalanced("all,(orientation:");
should_not_apply("(orientation:,all"); should_not_apply_unbalanced("(orientation:,all");
should_apply("not all and (grid"); should_apply_unbalanced("not all and (grid");
should_not_apply("only all and (grid"); should_not_apply_unbalanced("only all and (grid");
should_not_apply("(grid"); should_not_apply_unbalanced("(grid");
should_apply("all,(grid"); should_apply_unbalanced("all,(grid");
should_not_apply("(grid,all"); should_not_apply_unbalanced("(grid,all");
// bug 454226 // bug 454226
should_apply(",all"); should_apply(",all");
should_apply("all,"); should_apply("all,");
@ -464,7 +520,57 @@ function run() {
should_not_apply("badmedium,[badsyntax]"); should_not_apply("badmedium,[badsyntax]");
should_not_apply("[badsyntax],badmedium"); should_not_apply("[badsyntax],badmedium");
handle_posted_items();
}
/*
* The cloning tests have to post tests that wait for onload. However,
* we also make a bunch of state changes during the tests above. So we
* always change state using the change_state call, with both makes the
* change immediately and posts an item in the same queue so that we
* make the same state change again later.
*/
var posted_items = [];
function change_state(func)
{
func();
posted_items.push({state: func});
}
function post_clone_test(docurl, testfunc)
{
posted_items.push({docurl: docurl, testfunc: testfunc});
}
function handle_posted_items()
{
if (posted_items.length == 0) {
SimpleTest.finish(); 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> </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->y_height = decoder->video_info.frame_height;
decoder->uv_width = decoder->uv_stride = decoder->video_info.frame_width / 2; decoder->uv_width = decoder->uv_stride = decoder->video_info.frame_width / 2;
decoder->uv_height = decoder->video_info.frame_height / 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) { if (--(decoder->remaining_header_packets) == 0) {
/* Ensure the offsets do not push the viewable area outside of the decoded frame. */ /* 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)|| 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 void
oggplay_data_handle_theora_frame (OggPlayTheoraDecode *decode, oggplay_data_handle_theora_frame (OggPlayTheoraDecode *decode,
yuv_buffer *buffer) { yuv_buffer *buffer) {
@ -367,8 +384,7 @@ oggplay_data_handle_theora_frame (OggPlayTheoraDecode *decode,
q += buffer->y_stride; q += buffer->y_stride;
} }
uv_offset = (decode->video_info.offset_x/(decode->y_width/decode->uv_width)) + uv_offset = get_uv_offset(decode, buffer);
(buffer->uv_stride) *(decode->video_info.offset_y/(decode->y_height/decode->uv_height));
p = data->u; p = data->u;
q = buffer->u + uv_offset; q = buffer->u + uv_offset;

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

@ -62,3 +62,4 @@ patch -p3 < bug487519.patch
patch -p3 < bug498815.patch patch -p3 < bug498815.patch
patch -p3 < bug498824.patch patch -p3 < bug498824.patch
patch -p3 < bug496529.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 * It can be used to prompt users for authentication information, either
* synchronously or asynchronously. * synchronously or asynchronously.
*/ */
[scriptable, uuid(447fc780-1d28-412a-91a1-466d48129c65)] [scriptable, uuid(651395EB-8612-4876-8AC0-A88D4DCE9E1E)]
interface nsIAuthPrompt2 : nsISupports interface nsIAuthPrompt2 : nsISupports
{ {
/** @name Security Levels */ /** @name Security Levels */
@ -110,9 +110,23 @@ interface nsIAuthPrompt2 : nsISupports
* dialog and MUST call nsIAuthPromptCallback::onAuthCancelled on the provided * dialog and MUST call nsIAuthPromptCallback::onAuthCancelled on the provided
* callback. * callback.
* *
* @throw NS_ERROR_NOT_IMPLEMENTED * This implementation may:
* Asynchronous authentication prompts are not supported; *
* the caller should fall back to promptUsernameAndPassword(). * 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, nsICancelable asyncPromptAuth(in nsIChannel aChannel,
in nsIAuthPromptCallback aCallback, in nsIAuthPromptCallback aCallback,
@ -120,5 +134,3 @@ interface nsIAuthPrompt2 : nsISupports
in PRUint32 level, in PRUint32 level,
in nsIAuthInformation authInfo); in nsIAuthInformation authInfo);
}; };

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

@ -83,6 +83,7 @@
#include "nsAuthInformationHolder.h" #include "nsAuthInformationHolder.h"
#include "nsICacheService.h" #include "nsICacheService.h"
#include "nsDNSPrefetch.h" #include "nsDNSPrefetch.h"
#include "nsNetSegmentUtils.h"
// True if the local cache should be bypassed when processing a request. // True if the local cache should be bypassed when processing a request.
#define BYPASS_LOCAL_CACHE(loadFlags) \ #define BYPASS_LOCAL_CACHE(loadFlags) \
@ -125,6 +126,7 @@ nsHttpChannel::nsHttpChannel()
, mTransactionReplaced(PR_FALSE) , mTransactionReplaced(PR_FALSE)
, mUploadStreamHasHeaders(PR_FALSE) , mUploadStreamHasHeaders(PR_FALSE)
, mAuthRetryPending(PR_FALSE) , mAuthRetryPending(PR_FALSE)
, mProxyAuth(PR_FALSE)
, mSuppressDefensiveAuth(PR_FALSE) , mSuppressDefensiveAuth(PR_FALSE)
, mResuming(PR_FALSE) , mResuming(PR_FALSE)
, mInitedCacheEntry(PR_FALSE) , mInitedCacheEntry(PR_FALSE)
@ -849,8 +851,32 @@ nsHttpChannel::CallOnStartRequest()
// install stream converter if required // install stream converter if required
rv = ApplyContentConversions(); 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 nsresult
@ -1134,28 +1160,8 @@ nsHttpChannel::ProcessNormal()
rv = InstallCacheListener(); rv = InstallCacheListener();
if (NS_FAILED(rv)) return rv; 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) { return NS_OK;
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;
} }
nsresult 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... // open input stream for reading...
nsCOMPtr<nsIInputStream> stream; nsCOMPtr<nsIInputStream> stream;
rv = mCacheEntry->OpenInputStream(0, getter_AddRefs(stream)); rv = mCacheEntry->OpenInputStream(0, getter_AddRefs(stream));
@ -3134,13 +3119,13 @@ nsHttpChannel::ProcessAuthentication(PRUint32 httpStatus)
} }
const char *challenges; const char *challenges;
PRBool proxyAuth = (httpStatus == 407); mProxyAuth = (httpStatus == 407);
nsresult rv = PrepareForAuthentication(proxyAuth); nsresult rv = PrepareForAuthentication(mProxyAuth);
if (NS_FAILED(rv)) if (NS_FAILED(rv))
return rv; return rv;
if (proxyAuth) { if (mProxyAuth) {
// only allow a proxy challenge if we have a proxy server configured. // only allow a proxy challenge if we have a proxy server configured.
// otherwise, we could inadvertantly expose the user's proxy // otherwise, we could inadvertantly expose the user's proxy
// credentials to an origin server. We could attempt to proceed as // 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); NS_ENSURE_TRUE(challenges, NS_ERROR_UNEXPECTED);
nsCAutoString creds; nsCAutoString creds;
rv = GetCredentials(challenges, proxyAuth, creds); rv = GetCredentials(challenges, mProxyAuth, creds);
if (NS_FAILED(rv)) 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")); LOG(("unable to authenticate\n"));
else { else {
// set the authentication credentials // set the authentication credentials
if (proxyAuth) if (mProxyAuth)
mRequestHead.SetHeader(nsHttp::Proxy_Authorization, creds); mRequestHead.SetHeader(nsHttp::Proxy_Authorization, creds);
else else
mRequestHead.SetHeader(nsHttp::Authorization, creds); mRequestHead.SetHeader(nsHttp::Authorization, creds);
@ -3297,6 +3294,15 @@ nsHttpChannel::GetCredentials(const char *challenges,
break; 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 // reset the auth type and continuation state
NS_IF_RELEASE(*currentContinuationState); NS_IF_RELEASE(*currentContinuationState);
@ -3316,6 +3322,43 @@ nsHttpChannel::GetCredentials(const char *challenges,
return rv; 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 nsresult
nsHttpChannel::GetCredentialsForChallenge(const char *challenge, nsHttpChannel::GetCredentialsForChallenge(const char *challenge,
const char *authType, const char *authType,
@ -3357,35 +3400,16 @@ nsHttpChannel::GetCredentialsForChallenge(const char *challenge,
PRBool identFromURI = PR_FALSE; PRBool identFromURI = PR_FALSE;
nsISupports **continuationState; nsISupports **continuationState;
if (proxyAuth) { rv = GetAuthorizationMembers(proxyAuth, scheme, host, port, path, ident, continuationState);
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; if (NS_FAILED(rv)) return rv;
if (!proxyAuth) {
// if this is the first challenge, then try using the identity // if this is the first challenge, then try using the identity
// specified in the URL. // specified in the URL.
if (mIdent.IsEmpty()) { if (mIdent.IsEmpty()) {
GetIdentityFromURI(authFlags, mIdent); GetIdentityFromURI(authFlags, mIdent);
identFromURI = !mIdent.IsEmpty(); identFromURI = !mIdent.IsEmpty();
} }
continuationState = &mAuthContinuationState;
} }
// //
@ -3639,25 +3663,165 @@ nsHttpChannel::PromptForIdentity(PRUint32 level,
nsDependentCString(authType)); nsDependentCString(authType));
if (!holder) if (!holder)
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
rv = authPrompt->AsyncPromptAuth(this, this, nsnull, level, holder,
getter_AddRefs(mAsyncPromptAuthCancelable));
if (NS_SUCCEEDED(rv)) {
// indicate using this error code that authentication prompt
// result is expected asynchronously
rv = NS_ERROR_IN_PROGRESS;
}
else {
// Fall back to synchronous prompt
PRBool retval = PR_FALSE; PRBool retval = PR_FALSE;
rv = authPrompt->PromptAuth(this, rv = authPrompt->PromptAuth(this, level, holder, &retval);
level,
holder, &retval);
if (NS_FAILED(rv)) if (NS_FAILED(rv))
return rv; return rv;
// remember that we successfully showed the user an auth dialog
if (!proxyAuth)
mSuppressDefensiveAuth = PR_TRUE;
if (!retval) if (!retval)
rv = NS_ERROR_ABORT; rv = NS_ERROR_ABORT;
else else
holder->SetToHttpAuthIdentity(authFlags, ident); holder->SetToHttpAuthIdentity(authFlags, ident);
}
// remember that we successfully showed the user an auth dialog
if (!proxyAuth)
mSuppressDefensiveAuth = PR_TRUE;
return rv; 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 PRBool
nsHttpChannel::ConfirmAuth(const nsString &bundleKey, PRBool doYesNoPrompt) 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(nsITraceableChannel)
NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheContainer) NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheContainer)
NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheChannel) NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheChannel)
NS_INTERFACE_MAP_ENTRY(nsIAuthPromptCallback)
NS_INTERFACE_MAP_END_INHERITING(nsHashPropertyBag) NS_INTERFACE_MAP_END_INHERITING(nsHashPropertyBag)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -3960,6 +4125,8 @@ nsHttpChannel::Cancel(nsresult status)
mTransactionPump->Cancel(status); mTransactionPump->Cancel(status);
if (mCachePump) if (mCachePump)
mCachePump->Cancel(status); mCachePump->Cancel(status);
if (mAsyncPromptAuthCancelable)
mAsyncPromptAuthCancelable->Cancel(status);
return NS_OK; return NS_OK;
} }
@ -4990,8 +5157,14 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult st
// keep the connection around after the transaction is finished. // keep the connection around after the transaction is finished.
// //
nsRefPtr<nsAHttpConnection> conn; nsRefPtr<nsAHttpConnection> conn;
if (authRetry && (mCaps & NS_HTTP_STICKY_CONNECTION)) if (authRetry && (mCaps & NS_HTTP_STICKY_CONNECTION)) {
conn = mTransaction->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 // at this point, we're done with the transaction
NS_RELEASE(mTransaction); NS_RELEASE(mTransaction);

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

@ -84,6 +84,7 @@
#include "nsICancelable.h" #include "nsICancelable.h"
#include "nsIProxiedChannel.h" #include "nsIProxiedChannel.h"
#include "nsITraceableChannel.h" #include "nsITraceableChannel.h"
#include "nsIAuthPromptCallback.h"
class nsHttpResponseHead; class nsHttpResponseHead;
class nsAHttpConnection; class nsAHttpConnection;
@ -109,6 +110,7 @@ class nsHttpChannel : public nsHashPropertyBag
, public nsIProxiedChannel , public nsIProxiedChannel
, public nsITraceableChannel , public nsITraceableChannel
, public nsIApplicationCacheChannel , public nsIApplicationCacheChannel
, public nsIAuthPromptCallback
{ {
public: public:
NS_DECL_ISUPPORTS_INHERITED NS_DECL_ISUPPORTS_INHERITED
@ -130,6 +132,7 @@ public:
NS_DECL_NSITRACEABLECHANNEL NS_DECL_NSITRACEABLECHANNEL
NS_DECL_NSIAPPLICATIONCACHECONTAINER NS_DECL_NSIAPPLICATIONCACHECONTAINER
NS_DECL_NSIAPPLICATIONCACHECHANNEL NS_DECL_NSIAPPLICATIONCACHECHANNEL
NS_DECL_NSIAUTHPROMPTCALLBACK
nsHttpChannel(); nsHttpChannel();
virtual ~nsHttpChannel(); virtual ~nsHttpChannel();
@ -223,19 +226,38 @@ private:
// auth specific methods // auth specific methods
nsresult PrepareForAuthentication(PRBool proxyAuth); 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 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); nsresult GetAuthenticator(const char *challenge, nsCString &scheme, nsIHttpAuthenticator **auth);
void ParseRealm(const char *challenge, nsACString &realm); void ParseRealm(const char *challenge, nsACString &realm);
void GetIdentityFromURI(PRUint32 authFlags, nsHttpAuthIdentity&); 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 &); nsresult PromptForIdentity(PRUint32 level, PRBool proxyAuth, const char *realm, const char *authType, PRUint32 authFlags, nsHttpAuthIdentity &);
PRBool ConfirmAuth(const nsString &bundleKey, PRBool doYesNoPrompt); PRBool ConfirmAuth(const nsString &bundleKey, PRBool doYesNoPrompt);
void CheckForSuperfluousAuth(); void CheckForSuperfluousAuth();
void SetAuthorizationHeader(nsHttpAuthCache *, nsHttpAtom header, const char *scheme, const char *host, PRInt32 port, const char *path, nsHttpAuthIdentity &ident); void SetAuthorizationHeader(nsHttpAuthCache *, nsHttpAtom header, const char *scheme, const char *host, PRInt32 port, const char *path, nsHttpAuthIdentity &ident);
void AddAuthorizationHeaders(); void AddAuthorizationHeaders();
nsresult GetCurrentPath(nsACString &); 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 *); nsresult DoAuthRetry(nsAHttpConnection *);
PRBool MustValidateBasedOnQueryUrl(); 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: private:
nsCOMPtr<nsIURI> mOriginalURI; nsCOMPtr<nsIURI> mOriginalURI;
@ -293,6 +315,19 @@ private:
nsHttpAuthIdentity mIdent; nsHttpAuthIdentity mIdent;
nsHttpAuthIdentity mProxyIdent; 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 // Resumable channel specific data
nsCString mEntityID; nsCString mEntityID;
PRUint64 mStartPos; PRUint64 mStartPos;
@ -329,6 +364,9 @@ private:
PRUint32 mTransactionReplaced : 1; PRUint32 mTransactionReplaced : 1;
PRUint32 mUploadStreamHasHeaders : 1; PRUint32 mUploadStreamHasHeaders : 1;
PRUint32 mAuthRetryPending : 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 mSuppressDefensiveAuth : 1;
PRUint32 mResuming : 1; PRUint32 mResuming : 1;
PRUint32 mInitedCacheEntry : 1; PRUint32 mInitedCacheEntry : 1;

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

@ -127,7 +127,7 @@ AuthPrompt2.prototype = {
}, },
asyncPromptAuth: function ap2_async(chan, cb, ctx, lvl, info) { 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) { 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) { 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; mTLSIntolerantSites = nsnull;
} }
if (mTLSTolerantSites) {
delete mTLSTolerantSites;
mTLSTolerantSites = nsnull;
}
if (mSharedPollableEvent) if (mSharedPollableEvent)
PR_DestroyPollableEvent(mSharedPollableEvent); PR_DestroyPollableEvent(mSharedPollableEvent);
@ -1622,6 +1627,18 @@ nsPSMRememberCertErrorsTable::LookupCertErrorBits(nsNSSSocketInfo* infoObject,
status->mIsUntrusted = bits.mIsUntrusted; 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. // 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. // This function will return true, if the given socket is currently using TLS.
PRBool PRBool
@ -1629,30 +1646,50 @@ nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(PRFileDesc* ssl_layer_fd, ns
{ {
PRBool currentlyUsesTLS = PR_FALSE; PRBool currentlyUsesTLS = PR_FALSE;
nsCAutoString key;
getSiteKey(socketInfo, key);
SSL_OptionGet(ssl_layer_fd, SSL_ENABLE_TLS, &currentlyUsesTLS); SSL_OptionGet(ssl_layer_fd, SSL_ENABLE_TLS, &currentlyUsesTLS);
if (!currentlyUsesTLS) if (!currentlyUsesTLS) {
// We were not using TLS but failed with an intolerant error using
// a different protocol. To give TLS a try on next connection attempt again
// drop this site from the list of intolerant sites. TLS failure might be
// caused only by a traffic congestion while the server is TLS tolerant.
removeIntolerantSite(key);
return PR_FALSE; return PR_FALSE;
}
PRBool enableSSL3 = PR_FALSE; PRBool enableSSL3 = PR_FALSE;
SSL_OptionGet(ssl_layer_fd, SSL_ENABLE_SSL3, &enableSSL3); SSL_OptionGet(ssl_layer_fd, SSL_ENABLE_SSL3, &enableSSL3);
PRBool enableSSL2 = PR_FALSE; PRBool enableSSL2 = PR_FALSE;
SSL_OptionGet(ssl_layer_fd, SSL_ENABLE_SSL2, &enableSSL2); 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. // 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); addIntolerantSite(key);
} }
return currentlyUsesTLS; return currentlyUsesTLS;
} }
void
nsSSLIOLayerHelpers::rememberTolerantSite(PRFileDesc* ssl_layer_fd,
nsNSSSocketInfo *socketInfo)
{
PRBool usingSecurity = PR_FALSE;
PRBool currentlyUsesTLS = PR_FALSE;
SSL_OptionGet(ssl_layer_fd, SSL_SECURITY, &usingSecurity);
SSL_OptionGet(ssl_layer_fd, SSL_ENABLE_TLS, &currentlyUsesTLS);
if (!usingSecurity || !currentlyUsesTLS) {
return;
}
nsCAutoString key;
getSiteKey(socketInfo, key);
nsAutoLock lock(mutex);
nsSSLIOLayerHelpers::mTLSTolerantSites->Put(key);
}
static PRStatus PR_CALLBACK static PRStatus PR_CALLBACK
nsSSLIOLayerClose(PRFileDesc *fd) nsSSLIOLayerClose(PRFileDesc *fd)
{ {
@ -1927,6 +1964,7 @@ PRDescIdentity nsSSLIOLayerHelpers::nsSSLIOLayerIdentity;
PRIOMethods nsSSLIOLayerHelpers::nsSSLIOLayerMethods; PRIOMethods nsSSLIOLayerHelpers::nsSSLIOLayerMethods;
PRLock *nsSSLIOLayerHelpers::mutex = nsnull; PRLock *nsSSLIOLayerHelpers::mutex = nsnull;
nsCStringHashSet *nsSSLIOLayerHelpers::mTLSIntolerantSites = nsnull; nsCStringHashSet *nsSSLIOLayerHelpers::mTLSIntolerantSites = nsnull;
nsCStringHashSet *nsSSLIOLayerHelpers::mTLSTolerantSites = nsnull;
nsPSMRememberCertErrorsTable *nsSSLIOLayerHelpers::mHostsWithCertErrors = nsnull; nsPSMRememberCertErrorsTable *nsSSLIOLayerHelpers::mHostsWithCertErrors = nsnull;
PRFileDesc *nsSSLIOLayerHelpers::mSharedPollableEvent = nsnull; PRFileDesc *nsSSLIOLayerHelpers::mSharedPollableEvent = nsnull;
nsNSSSocketInfo *nsSSLIOLayerHelpers::mSocketOwningPollableEvent = nsnull; nsNSSSocketInfo *nsSSLIOLayerHelpers::mSocketOwningPollableEvent = nsnull;
@ -2137,6 +2175,15 @@ nsresult nsSSLIOLayerHelpers::Init()
mTLSIntolerantSites->Init(1); 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(); mHostsWithCertErrors = new nsPSMRememberCertErrorsTable();
if (!mHostsWithCertErrors || !mHostsWithCertErrors->mErrorHosts.IsInitialized()) if (!mHostsWithCertErrors || !mHostsWithCertErrors->mErrorHosts.IsInitialized())
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
@ -2147,9 +2194,17 @@ nsresult nsSSLIOLayerHelpers::Init()
void nsSSLIOLayerHelpers::addIntolerantSite(const nsCString &str) void nsSSLIOLayerHelpers::addIntolerantSite(const nsCString &str)
{ {
nsAutoLock lock(mutex); nsAutoLock lock(mutex);
// Remember intolerant site only if it is not known as tolerant
if (!mTLSTolerantSites->Contains(str))
nsSSLIOLayerHelpers::mTLSIntolerantSites->Put(str); nsSSLIOLayerHelpers::mTLSIntolerantSites->Put(str);
} }
void nsSSLIOLayerHelpers::removeIntolerantSite(const nsCString &str)
{
nsAutoLock lock(mutex);
nsSSLIOLayerHelpers::mTLSIntolerantSites->Remove(str);
}
PRBool nsSSLIOLayerHelpers::isKnownAsIntolerantSite(const nsCString &str) PRBool nsSSLIOLayerHelpers::isKnownAsIntolerantSite(const nsCString &str)
{ {
nsAutoLock lock(mutex); nsAutoLock lock(mutex);

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

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

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

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

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

@ -50,18 +50,42 @@ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
* Invoked by NS_NewAuthPrompter2() * Invoked by NS_NewAuthPrompter2()
* [embedding/components/windowwatcher/src/nsPrompt.cpp] * [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 = { LoginManagerPromptFactory.prototype = {
classDescription : "LoginManagerPromptFactory", classDescription : "LoginManagerPromptFactory",
contractID : "@mozilla.org/passwordmanager/authpromptfactory;1", contractID : "@mozilla.org/passwordmanager/authpromptfactory;1",
classID : Components.ID("{749e62f4-60ae-4569-a8a2-de78b649660e}"), 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) { getPrompt : function (aWindow, aIID) {
var prompt = new LoginManagerPrompter().QueryInterface(aIID); var prompt = new LoginManagerPrompter().QueryInterface(aIID);
prompt.init(aWindow); prompt.init(aWindow, this);
return prompt; return prompt;
} }
}; // end of LoginManagerPromptFactory implementation }; // end of LoginManagerPromptFactory implementation
@ -98,6 +122,7 @@ LoginManagerPrompter.prototype = {
Ci.nsIAuthPrompt2, Ci.nsIAuthPrompt2,
Ci.nsILoginManagerPrompter]), Ci.nsILoginManagerPrompter]),
_factory : null,
_window : null, _window : null,
_debug : false, // mirrors signon.debug _debug : false, // mirrors signon.debug
@ -165,6 +190,14 @@ LoginManagerPrompter.prototype = {
return this.__ioService; 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, __ellipsis : null,
get _ellipsis() { get _ellipsis() {
@ -556,10 +589,114 @@ LoginManagerPrompter.prototype = {
return ok; return ok;
}, },
asyncPromptAuth : function () { asyncPromptAuth : function (aChannel, aCallback, aContext, aLevel, aAuthInfo) {
return NS_ERROR_NOT_IMPLEMENTED; 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
* *
*/ */
init : function (aWindow) { init : function (aWindow, aFactory) {
this._window = aWindow; this._window = aWindow;
this._factory = aFactory || null;
var prefBranch = Cc["@mozilla.org/preferences-service;1"]. var prefBranch = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefService).getBranch("signon."); getService(Ci.nsIPrefService).getBranch("signon.");
@ -1218,6 +1356,19 @@ LoginManagerPrompter.prototype = {
aAuthInfo.username = username; aAuthInfo.username = username;
} }
aAuthInfo.password = password; 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 }; // end of LoginManagerPrompter implementation

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

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

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

@ -11,13 +11,16 @@ function handleRequest(request, response)
function reallyHandleRequest(request, response) { function reallyHandleRequest(request, response) {
var match; var match;
var requestAuth = true; var requestAuth = true, requestProxyAuth = true;
// Allow the caller to drive how authentication is processed via the query. // Allow the caller to drive how authentication is processed via the query.
// Eg, http://localhost:8888/authenticate.sjs?user=foo&realm=bar // Eg, http://localhost:8888/authenticate.sjs?user=foo&realm=bar
var query = request.queryString; var query = request.queryString;
var expected_user = "", expected_pass = "", realm = "mochitest"; 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 // user=xxx
match = /user=([^&]*)/.exec(query); match = /user=([^&]*)/.exec(query);
if (match) if (match)
@ -33,6 +36,31 @@ function reallyHandleRequest(request, response) {
if (match) if (match)
realm = match[1]; 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. // Look for an authentication header, if any, in the request.
// //
@ -56,16 +84,40 @@ function reallyHandleRequest(request, response) {
actual_pass = match[2]; 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 // Don't request authentication if the credentials we got were what we
// expected. // expected.
if (expected_user == actual_user && if (expected_user == actual_user &&
expected_pass == actual_pass) { expected_pass == actual_pass) {
requestAuth = false; 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.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 { } else {
response.setStatusLine("1.0", 200, "OK"); response.setStatusLine("1.0", 200, "OK");
} }
@ -73,9 +125,20 @@ function reallyHandleRequest(request, response) {
response.setHeader("Content-Type", "application/xhtml+xml", false); response.setHeader("Content-Type", "application/xhtml+xml", false);
response.write("<html xmlns='http://www.w3.org/1999/xhtml'>"); 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>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>Auth: <span id='auth'>" + authHeader + "</span></p>\n");
response.write("<p>User: <span id='user'>" + actual_user + "</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"); 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>"); 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() nsChildView::~nsChildView()
{ {
// notify the children that we're gone // Notify the children that we're gone. childView->ResetParent() can change
for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) { // 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); nsChildView* childView = static_cast<nsChildView*>(kid);
kid = kid->GetPrevSibling();
childView->ResetParent(); childView->ResetParent();
} }

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

@ -161,16 +161,20 @@ nsCocoaWindow::~nsCocoaWindow()
// Notify the children that we're gone. Popup windows (e.g. tooltips) can // 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 // have nsChildView children. 'kid' is an nsChildView object if and only if
// its 'type' is 'eWindowType_child'. // its 'type' is 'eWindowType_child'. childView->ResetParent() can change
for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) { // 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; nsWindowType kidType;
kid->GetWindowType(kidType); kid->GetWindowType(kidType);
if (kidType == eWindowType_child) { if (kidType == eWindowType_child) {
nsChildView* childView = static_cast<nsChildView*>(kid); nsChildView* childView = static_cast<nsChildView*>(kid);
kid = kid->GetPrevSibling();
childView->ResetParent(); childView->ResetParent();
} else { } else {
nsCocoaWindow* childWindow = static_cast<nsCocoaWindow*>(kid); nsCocoaWindow* childWindow = static_cast<nsCocoaWindow*>(kid);
childWindow->mParent = nsnull; 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). // the NSApplication class (in header files generated using class-dump).
// This workaround was "borrowed" from the Java Embedding Plugin (which // This workaround was "borrowed" from the Java Embedding Plugin (which
// uses it for a different purpose). // uses it for a different purpose).
if (mWindowType == eWindowType_popup) { if (mWindowType == eWindowType_popup)
[NSApp _removeWindowFromCache:mWindow]; [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 // 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) // 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. * 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); PR_STATIC_ASSERT(sizeof(wchar_t) == 2);
#define NS_LL(s) L##s #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)) #endif
#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_MULTILINE_LITERAL_STRING(s) nsDependentString(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)/sizeof(wchar_t))-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; typedef nsDependentString nsLiteralString;
#else #else
#define NS_LL(s) s #define NS_LL(s) s

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

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

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

@ -78,11 +78,17 @@ literal_string( const nsACString::char_type* aPtr, PRUint32 aLength )
} }
#endif #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_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)) #endif
#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_MULTILINE_LITERAL_STRING(s) nsDependentString(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)/sizeof(wchar_t))-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; typedef nsDependentString nsLiteralString;
#else #else
#define NS_LL(s) s #define NS_LL(s) s

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

@ -560,11 +560,11 @@ class nsTXPIDLString_CharT : public nsTString_CharT
public: public:
nsTXPIDLString_CharT() 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 // copy-constructor required to avoid default
nsTXPIDLString_CharT( const self_type& str ) 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); Assign(str);
} }

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

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

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

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

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

@ -20,6 +20,9 @@
/* Define if the c++ compiler has builtin Bool type */ /* Define if the c++ compiler has builtin Bool type */
#undef HAVE_CPP_BOOL #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 */ /* Define if a dyanmic_cast to void* gives the most derived object */
#undef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR #undef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR