Merge TM -> JM

This commit is contained in:
Brian Hackett 2010-12-20 09:06:43 -08:00
commit 89bb1d08e8
209 changed files with 6318 additions and 4217 deletions

View File

@ -114,7 +114,7 @@ static inline const PRUnichar *
IDToString(JSContext *cx, jsid id)
{
if (JSID_IS_STRING(id))
return reinterpret_cast<PRUnichar*>(JS_GetStringChars(JSID_TO_STRING(id)));
return JS_GetInternedStringChars(JSID_TO_STRING(id));
JSAutoRequest ar(cx);
jsval idval;
@ -123,7 +123,7 @@ IDToString(JSContext *cx, jsid id)
JSString *str = JS_ValueToString(cx, idval);
if(!str)
return nsnull;
return reinterpret_cast<PRUnichar*>(JS_GetStringChars(str));
return JS_GetStringCharsZ(cx, str);
}
class nsAutoInPrincipalDomainOriginSetter {

View File

@ -95,9 +95,10 @@ static void
getUTF8StringArgument(JSContext *cx, JSObject *obj, PRUint16 argNum,
uintN argc, jsval *argv, nsCString& aRetval)
{
aRetval.Truncate();
if (argc <= argNum || !JSVAL_IS_STRING(argv[argNum])) {
JS_ReportError(cx, "String argument expected");
aRetval.Truncate();
return;
}
@ -106,12 +107,13 @@ getUTF8StringArgument(JSContext *cx, JSObject *obj, PRUint16 argNum,
* to have an object to represent a target in subsequent versions.
*/
JSString *str = JSVAL_TO_STRING(argv[argNum]);
if (!str) {
aRetval.Truncate();
if (!str)
return;
const PRUnichar *data = JS_GetStringCharsZ(cx, str);
if (!data)
return;
}
PRUnichar *data = (PRUnichar*)JS_GetStringChars(str);
CopyUTF16toUTF8(data, aRetval);
}

View File

@ -1915,13 +1915,13 @@ case "$host" in
esac
dnl We require version 2.5 or newer of Python to build.
AC_MSG_CHECKING([for minimum required Python version >= $PYTHON_VERSION])
AC_MSG_CHECKING([for Python version >= $PYTHON_VERSION but not 3.x])
changequote(,)
$PYTHON -c "import sys; sys.exit(sys.version[:3] < sys.argv[1])" $PYTHON_VERSION
$PYTHON -c "import sys; sys.exit(sys.version[:3] < sys.argv[1] or sys.version[:2] != '2.')" $PYTHON_VERSION
_python_res=$?
changequote([,])
if test "$_python_res" != 0; then
AC_MSG_ERROR([Python $PYTHON_VERSION or higher is required.])
AC_MSG_ERROR([Python $PYTHON_VERSION or higher (but not Python 3.x) is required.])
fi
AC_MSG_RESULT([yes])

View File

@ -208,7 +208,11 @@ nsFrameMessageManager::GetParamsForMessage(nsAString& aMessageName,
JSAutoRequest ar(ctx);
JSString* str;
if (argc && (str = JS_ValueToString(ctx, argv[0])) && str) {
aMessageName.Assign(nsDependentJSString(str));
nsDependentJSString depStr;
if (!depStr.init(ctx, str)) {
return NS_ERROR_OUT_OF_MEMORY;
}
aMessageName.Assign(depStr);
}
if (argc >= 2) {

View File

@ -2940,17 +2940,27 @@ nsWebSocket::Initialize(nsISupports* aOwner,
if (!jsstr) {
return NS_ERROR_DOM_SYNTAX_ERR;
}
urlParam.Assign(reinterpret_cast<const PRUnichar*>(JS_GetStringChars(jsstr)),
JS_GetStringLength(jsstr));
size_t length;
const jschar *chars = JS_GetStringCharsAndLength(aContext, jsstr, &length);
if (!chars) {
return NS_ERROR_OUT_OF_MEMORY;
}
urlParam.Assign(chars, length);
if (aArgc == 2) {
jsstr = JS_ValueToString(aContext, aArgv[1]);
if (!jsstr) {
return NS_ERROR_DOM_SYNTAX_ERR;
}
protocolParam.
Assign(reinterpret_cast<const PRUnichar*>(JS_GetStringChars(jsstr)),
JS_GetStringLength(jsstr));
chars = JS_GetStringCharsAndLength(aContext, jsstr, &length);
if (!chars) {
return NS_ERROR_OUT_OF_MEMORY;
}
protocolParam.Assign(chars, length);
if (protocolParam.IsEmpty()) {
return NS_ERROR_DOM_SYNTAX_ERR;
}

View File

@ -895,8 +895,9 @@ helper_nsIDOMWebGLRenderingContext_Uniform_x_iv_tn(JSContext *cx, JSObject *obj,
nsIDOMWebGLRenderingContext *self;
xpc_qsSelfRef selfref;
xpc_qsArgValArray<3> vp(cx);
if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, &vp.array[0], nsnull)) {
js::Anchor<jsval> self_anchor;
if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr,
&self_anchor.get(), nsnull)) {
js_SetTraceableNativeFailed(cx);
return;
}
@ -910,8 +911,11 @@ helper_nsIDOMWebGLRenderingContext_Uniform_x_iv_tn(JSContext *cx, JSObject *obj,
nsIWebGLUniformLocation *location;
xpc_qsSelfRef location_selfref;
js::Anchor<jsval> location_anchor;
nsresult rv_convert_arg0
= xpc_qsUnwrapThis(cx, locationobj, nsnull, &location, &location_selfref.ptr, &vp.array[1], nsnull);
= xpc_qsUnwrapThis(cx, locationobj, nsnull, &location,
&location_selfref.ptr, &location_anchor.get(),
nsnull);
if (NS_FAILED(rv_convert_arg0)) {
js_SetTraceableNativeFailed(cx);
return;
@ -963,8 +967,9 @@ helper_nsIDOMWebGLRenderingContext_Uniform_x_fv_tn(JSContext *cx, JSObject *obj,
nsIDOMWebGLRenderingContext *self;
xpc_qsSelfRef selfref;
xpc_qsArgValArray<3> vp(cx);
if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, &vp.array[0], nsnull)) {
js::Anchor<jsval> self_anchor;
if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr,
&self_anchor.get(), nsnull)) {
js_SetTraceableNativeFailed(cx);
return;
}
@ -978,8 +983,11 @@ helper_nsIDOMWebGLRenderingContext_Uniform_x_fv_tn(JSContext *cx, JSObject *obj,
nsIWebGLUniformLocation *location;
xpc_qsSelfRef location_selfref;
js::Anchor<jsval> location_anchor;
nsresult rv_convert_arg0
= xpc_qsUnwrapThis(cx, locationobj, nsnull, &location, &location_selfref.ptr, &vp.array[1], nsnull);
= xpc_qsUnwrapThis(cx, locationobj, nsnull, &location,
&location_selfref.ptr, &location_anchor.get(),
nsnull);
if (NS_FAILED(rv_convert_arg0)) {
js_SetTraceableNativeFailed(cx);
return;
@ -1033,8 +1041,9 @@ helper_nsIDOMWebGLRenderingContext_UniformMatrix_x_fv_tn(JSContext *cx, JSObject
nsIDOMWebGLRenderingContext *self;
xpc_qsSelfRef selfref;
xpc_qsArgValArray<4> vp(cx);
if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, &vp.array[0], nsnull)) {
js::Anchor<jsval> self_anchor;
if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr,
&self_anchor.get(), nsnull)) {
js_SetTraceableNativeFailed(cx);
return;
}
@ -1048,8 +1057,11 @@ helper_nsIDOMWebGLRenderingContext_UniformMatrix_x_fv_tn(JSContext *cx, JSObject
nsIWebGLUniformLocation *location;
xpc_qsSelfRef location_selfref;
js::Anchor<jsval> location_anchor;
nsresult rv_convert_arg0
= xpc_qsUnwrapThis(cx, locationobj, nsnull, &location, &location_selfref.ptr, &vp.array[1], nsnull);
= xpc_qsUnwrapThis(cx, locationobj, nsnull, &location,
&location_selfref.ptr, &location_anchor.get(),
nsnull);
if (NS_FAILED(rv_convert_arg0)) {
js_SetTraceableNativeFailed(cx);
return;

View File

@ -140,7 +140,10 @@ nsEventListenerInfo::ToSource(nsAString& aResult)
if (GetJSVal(&v)) {
JSString* str = JS_ValueToSource(cx, v);
if (str) {
aResult.Assign(nsDependentJSString(str));
nsDependentJSString depStr;
if (depStr.init(cx, str)) {
aResult.Assign(depStr);
}
}
}
}

View File

@ -140,7 +140,10 @@ nsHTMLAudioElement::Initialize(nsISupports* aOwner, JSContext* aContext,
if (!jsstr)
return NS_ERROR_FAILURE;
nsDependentJSString str(jsstr);
nsDependentJSString str;
if (!str.init(aContext, jsstr))
return NS_ERROR_FAILURE;
rv = SetAttr(kNameSpaceID_None, nsGkAtoms::src, str, PR_TRUE);
if (NS_FAILED(rv))
return rv;

View File

@ -46,6 +46,7 @@
#include "nsIScriptSecurityManager.h"
#include "nsIXPConnect.h"
#include "jsapi.h"
#include "nsJSUtils.h"
#include "nsFrameManager.h"
#include "nsDisplayList.h"
@ -502,8 +503,11 @@ nsHTMLCanvasElement::GetContext(const nsAString& aContextId,
}
JSString *propnameString = JS_ValueToString(cx, propname);
nsDependentString pstr(JS_GetStringChars(propnameString), JS_GetStringLength(propnameString));
nsDependentJSString pstr;
if (!propnameString || !pstr.init(cx, propnameString)) {
mCurrentContext = nsnull;
return NS_ERROR_FAILURE;
}
if (JSVAL_IS_BOOLEAN(propval)) {
newProps->SetPropertyAsBool(pstr, propval == JSVAL_TRUE ? PR_TRUE : PR_FALSE);
@ -512,8 +516,14 @@ nsHTMLCanvasElement::GetContext(const nsAString& aContextId,
} else if (JSVAL_IS_DOUBLE(propval)) {
newProps->SetPropertyAsDouble(pstr, JSVAL_TO_DOUBLE(propval));
} else if (JSVAL_IS_STRING(propval)) {
newProps->SetPropertyAsAString(pstr, nsDependentString(JS_GetStringChars(JS_ValueToString(cx, propval)),
JS_GetStringLength(JS_ValueToString(cx, propval))));
JSString *propvalString = JS_ValueToString(cx, propval);
nsDependentJSString vstr;
if (!propvalString || !vstr.init(cx, propvalString)) {
mCurrentContext = nsnull;
return NS_ERROR_FAILURE;
}
newProps->SetPropertyAsAString(pstr, vstr);
}
}
}

View File

@ -412,10 +412,13 @@ nsHTMLOptionElement::Initialize(nsISupports* aOwner,
return result;
}
textContent->SetText(reinterpret_cast<const PRUnichar*>
(JS_GetStringChars(jsstr)),
JS_GetStringLength(jsstr),
PR_FALSE);
size_t length;
const jschar *chars = JS_GetStringCharsAndLength(aContext, jsstr, &length);
if (!chars) {
return NS_ERROR_FAILURE;
}
textContent->SetText(chars, length, PR_FALSE);
result = AppendChildTo(textContent, PR_FALSE);
if (NS_FAILED(result)) {
@ -429,9 +432,14 @@ nsHTMLOptionElement::Initialize(nsISupports* aOwner,
return NS_ERROR_FAILURE;
}
size_t length;
const jschar *chars = JS_GetStringCharsAndLength(aContext, jsstr, &length);
if (!chars) {
return NS_ERROR_FAILURE;
}
// Set the value attribute for this element
nsAutoString value(reinterpret_cast<const PRUnichar*>
(JS_GetStringChars(jsstr)));
nsAutoString value(chars, length);
result = SetAttr(kNameSpaceID_None, nsGkAtoms::value, value,
PR_FALSE);

View File

@ -1094,78 +1094,85 @@ nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocumen
nsCxPusher pusher;
pusher.Push(cx);
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
jsval v;
nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
nsIXPConnect *xpc = nsContentUtils::XPConnect();
nsresult rv =
nsContentUtils::WrapNative(cx, scope, mBoundElement, &v,
getter_AddRefs(wrapper));
xpc->GetWrappedNativeOfNativeObject(cx, scope, mBoundElement,
NS_GET_IID(nsISupports),
getter_AddRefs(wrapper));
if (NS_FAILED(rv))
return;
JSObject* scriptObject = JSVAL_TO_OBJECT(v);
JSObject* scriptObject;
if (wrapper)
wrapper->GetJSObject(&scriptObject);
else
scriptObject = nsnull;
// XXX Stay in sync! What if a layered binding has an
// <interface>?!
// XXXbz what does that comment mean, really? It seems to date
// back to when there was such a thing as an <interface>, whever
// that was...
if (scriptObject) {
// XXX Stay in sync! What if a layered binding has an
// <interface>?!
// XXXbz what does that comment mean, really? It seems to date
// back to when there was such a thing as an <interface>, whever
// that was...
// Find the right prototype.
JSObject* base = scriptObject;
JSObject* proto;
JSAutoRequest ar(cx);
JSAutoEnterCompartment ac;
if (!ac.enter(cx, scriptObject)) {
return;
}
// Find the right prototype.
JSObject* base = scriptObject;
JSObject* proto;
JSAutoRequest ar(cx);
JSAutoEnterCompartment ac;
if (!ac.enter(cx, scriptObject)) {
return;
}
for ( ; true; base = proto) { // Will break out on null proto
proto = ::JS_GetPrototype(cx, base);
if (!proto) {
for ( ; true; base = proto) { // Will break out on null proto
proto = ::JS_GetPrototype(cx, base);
if (!proto) {
break;
}
JSClass* clazz = ::JS_GET_CLASS(cx, proto);
if (!clazz ||
(~clazz->flags &
(JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS)) ||
JSCLASS_RESERVED_SLOTS(clazz) != 1 ||
clazz->resolve != (JSResolveOp)XBLResolve ||
clazz->finalize != XBLFinalize) {
// Clearly not the right class
continue;
}
nsRefPtr<nsXBLDocumentInfo> docInfo =
static_cast<nsXBLDocumentInfo*>(::JS_GetPrivate(cx, proto));
if (!docInfo) {
// Not the proto we seek
continue;
}
jsval protoBinding;
if (!::JS_GetReservedSlot(cx, proto, 0, &protoBinding)) {
NS_ERROR("Really shouldn't happen");
continue;
}
if (JSVAL_TO_PRIVATE(protoBinding) != mPrototypeBinding) {
// Not the right binding
continue;
}
// Alright! This is the right prototype. Pull it out of the
// proto chain.
JSObject* grandProto = ::JS_GetPrototype(cx, proto);
::JS_SetPrototype(cx, base, grandProto);
break;
}
JSClass* clazz = ::JS_GET_CLASS(cx, proto);
if (!clazz ||
(~clazz->flags &
(JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS)) ||
JSCLASS_RESERVED_SLOTS(clazz) != 1 ||
clazz->resolve != (JSResolveOp)XBLResolve ||
clazz->finalize != XBLFinalize) {
// Clearly not the right class
continue;
}
mPrototypeBinding->UndefineFields(cx, scriptObject);
nsRefPtr<nsXBLDocumentInfo> docInfo =
static_cast<nsXBLDocumentInfo*>(::JS_GetPrivate(cx, proto));
if (!docInfo) {
// Not the proto we seek
continue;
}
jsval protoBinding;
if (!::JS_GetReservedSlot(cx, proto, 0, &protoBinding)) {
NS_ERROR("Really shouldn't happen");
continue;
}
if (JSVAL_TO_PRIVATE(protoBinding) != mPrototypeBinding) {
// Not the right binding
continue;
}
// Alright! This is the right prototype. Pull it out of the
// proto chain.
JSObject* grandProto = ::JS_GetPrototype(cx, proto);
::JS_SetPrototype(cx, base, grandProto);
break;
// Don't remove the reference from the document to the
// wrapper here since it'll be removed by the element
// itself when that's taken out of the document.
}
mPrototypeBinding->UndefineFields(cx, scriptObject);
// Don't remove the reference from the document to the
// wrapper here since it'll be removed by the element
// itself when that's taken out of the document.
}
}
}

View File

@ -89,6 +89,11 @@ CPPSRCS += txMozillaStylesheetCompiler.cpp \
txMozillaXSLTProcessor.cpp
endif
# For nsDependentJSString
LOCAL_INCLUDES += \
-I$(topsrcdir)/dom/base \
$(NULL)
# we don't want the shared lib, but we want to force the creation of a
# static lib.
FORCE_STATIC_LIB = 1

View File

@ -67,6 +67,7 @@
#include "txExprParser.h"
#include "nsIErrorService.h"
#include "nsIScriptSecurityManager.h"
#include "nsJSUtils.h"
using namespace mozilla::dom;
@ -1465,10 +1466,8 @@ txVariable::Convert(nsIVariant *aValue, txAExprResult** aResult)
JSString *str = JS_ValueToString(cx, OBJECT_TO_JSVAL(jsobj));
NS_ENSURE_TRUE(str, NS_ERROR_FAILURE);
const PRUnichar *strChars =
reinterpret_cast<const PRUnichar*>
(::JS_GetStringChars(str));
nsDependentString value(strChars, ::JS_GetStringLength(str));
nsDependentJSString value;
NS_ENSURE_TRUE(value.init(cx, str), NS_ERROR_FAILURE);
*aResult = new StringResult(value, nsnull);
if (!*aResult) {

View File

@ -5064,7 +5064,6 @@ nsWindowSH::GlobalScopePolluterNewResolve(JSContext *cx, JSObject *obj,
}
JSObject *proto = ::JS_GetPrototype(cx, obj);
JSString *jsstr = JSID_TO_STRING(id);
JSBool hasProp;
if (!proto || !::JS_HasPropertyById(cx, proto, id, &hasProp) ||
@ -5075,7 +5074,7 @@ nsWindowSH::GlobalScopePolluterNewResolve(JSContext *cx, JSObject *obj,
return JS_TRUE;
}
nsDependentJSString str(jsstr);
nsDependentJSString str(id);
nsCOMPtr<nsISupports> result;
nsWrapperCache *cache;
{
@ -5414,7 +5413,10 @@ nsWindowSH::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
vp, getter_AddRefs(holder));
NS_ENSURE_SUCCESS(rv, rv);
rv = location->SetHref(nsDependentJSString(val));
nsDependentJSString depStr;
NS_ENSURE_TRUE(depStr.init(cx, val), NS_ERROR_UNEXPECTED);
rv = location->SetHref(depStr);
return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
}
@ -6269,14 +6271,14 @@ ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx,
// static
nsresult
nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
JSObject *obj, JSString *str, PRBool *did_resolve)
JSObject *obj, jsid id, PRBool *did_resolve)
{
*did_resolve = PR_FALSE;
nsScriptNameSpaceManager *nameSpaceManager = nsJSRuntime::GetNameSpaceManager();
NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
nsDependentJSString name(str);
nsDependentJSString name(id);
const nsGlobalNameStruct *name_struct = nsnull;
const PRUnichar *class_name = nsnull;
@ -6486,10 +6488,8 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
NS_ENSURE_SUCCESS(rv, rv);
JSBool ok = ::JS_DefineUCProperty(cx, obj, ::JS_GetStringChars(str),
::JS_GetStringLength(str),
prop_val, nsnull, nsnull,
JSPROP_ENUMERATE);
JSBool ok = ::JS_DefinePropertyById(cx, obj, id, prop_val, nsnull, nsnull,
JSPROP_ENUMERATE);
*did_resolve = PR_TRUE;
@ -6648,8 +6648,6 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
// method on an interface that would let us just call into the
// window code directly...
JSString *str = JSID_TO_STRING(id);
if (!xpc::WrapperFactory::IsXrayWrapper(obj) ||
xpc::WrapperFactory::IsPartiallyTransparent(obj)) {
nsCOMPtr<nsIDocShellTreeNode> dsn(do_QueryInterface(win->GetDocShell()));
@ -6663,7 +6661,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
if (count > 0) {
nsCOMPtr<nsIDocShellTreeItem> child;
const jschar *chars = ::JS_GetStringChars(str);
const jschar *chars = ::JS_GetInternedStringChars(JSID_TO_STRING(id));
dsn->FindChildWithName(reinterpret_cast<const PRUnichar*>(chars),
PR_FALSE, PR_TRUE, nsnull, nsnull,
@ -6712,7 +6710,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
// which have been registered with the script namespace manager.
JSBool did_resolve = JS_FALSE;
rv = GlobalResolve(win, cx, obj, str, &did_resolve);
rv = GlobalResolve(win, cx, obj, id, &did_resolve);
NS_ENSURE_SUCCESS(rv, rv);
if (did_resolve) {
@ -8382,7 +8380,10 @@ nsDocumentSH::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSString *val = ::JS_ValueToString(cx, *vp);
NS_ENSURE_TRUE(val, NS_ERROR_UNEXPECTED);
rv = location->SetHref(nsDependentJSString(val));
nsDependentJSString depStr;
NS_ENSURE_TRUE(depStr.init(cx, val), NS_ERROR_UNEXPECTED);
rv = location->SetHref(depStr);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
@ -8471,7 +8472,10 @@ ResolveImpl(JSContext *cx, nsIXPConnectWrappedNative *wrapper, jsid id,
JSString *str = IdToString(cx, id);
NS_ENSURE_TRUE(str, NS_ERROR_UNEXPECTED);
return doc->ResolveName(nsDependentJSString(str), nsnull, result, aCache);
nsDependentJSString depStr;
NS_ENSURE_TRUE(depStr.init(cx, str), NS_ERROR_UNEXPECTED);
return doc->ResolveName(depStr, nsnull, result, aCache);
}
// static
@ -8509,8 +8513,13 @@ nsHTMLDocumentSH::DocumentOpen(JSContext *cx, uintN argc, jsval *vp)
nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_OUT_OF_MEMORY);
return JS_FALSE;
}
nsDependentJSString depStr;
if (!depStr.init(cx, jsstr)) {
nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_OUT_OF_MEMORY);
return JS_FALSE;
}
nsAutoString type;
type.Assign(nsDependentJSString(jsstr));
type.Assign(depStr);
ToLowerCase(type);
nsCAutoString actualType, dummy;
NS_ParseContentType(NS_ConvertUTF16toUTF8(type), actualType, dummy);
@ -8528,9 +8537,13 @@ nsHTMLDocumentSH::DocumentOpen(JSContext *cx, uintN argc, jsval *vp)
return JS_FALSE;
}
replace = NS_LITERAL_STRING("replace").
Equals(reinterpret_cast<const PRUnichar*>
(::JS_GetStringChars(jsstr)));
const jschar *chars = ::JS_GetStringCharsZ(cx, jsstr);
if (!chars) {
nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_OUT_OF_MEMORY);
return JS_FALSE;
}
replace = NS_LITERAL_STRING("replace").Equals(chars);
}
nsCOMPtr<nsIDOMDocument> retval;
@ -8849,8 +8862,13 @@ nsHTMLDocumentSH::CallToGetPropMapper(JSContext *cx, uintN argc, jsval *vp)
self = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));
}
return ::JS_GetUCProperty(cx, self, ::JS_GetStringChars(str),
::JS_GetStringLength(str), vp);
size_t length;
const jschar *chars = ::JS_GetStringCharsAndLength(cx, str, &length);
if (!chars) {
return JS_FALSE;
}
return ::JS_GetUCProperty(cx, self, chars, length, vp);
}
@ -8970,8 +8988,6 @@ nsHTMLDocumentSH::DocumentAllTagsNewResolve(JSContext *cx, JSObject *obj,
if (JSID_IS_STRING(id)) {
nsDocument *doc = GetDocument(cx, obj);
JSString *str = JSID_TO_STRING(id);
JSObject *proto = ::JS_GetPrototype(cx, obj);
if (NS_UNLIKELY(!proto)) {
return JS_TRUE;
@ -8987,7 +9003,7 @@ nsHTMLDocumentSH::DocumentAllTagsNewResolve(JSContext *cx, JSObject *obj,
}
nsRefPtr<nsContentList> tags =
doc->GetElementsByTagName(nsDependentJSString(str));
doc->GetElementsByTagName(nsDependentJSString(id));
if (tags) {
jsval v;
@ -9159,11 +9175,11 @@ nsHTMLDocumentSH::GetProperty(nsIXPConnectWrappedNative *wrapper,
// static
nsresult
nsHTMLFormElementSH::FindNamedItem(nsIForm *aForm, JSString *str,
nsHTMLFormElementSH::FindNamedItem(nsIForm *aForm, jsid id,
nsISupports **aResult,
nsWrapperCache **aCache)
{
nsDependentJSString name(str);
nsDependentJSString name(id);
*aResult = aForm->ResolveName(name).get();
// FIXME Get the wrapper cache from nsIForm::ResolveName
@ -9197,8 +9213,7 @@ nsHTMLFormElementSH::NewResolve(nsIXPConnectWrappedNative *wrapper,
nsCOMPtr<nsISupports> result;
nsWrapperCache *cache;
JSString *str = JSID_TO_STRING(id);
FindNamedItem(form, str, getter_AddRefs(result), &cache);
FindNamedItem(form, id, getter_AddRefs(result), &cache);
if (result) {
JSAutoRequest ar(cx);
@ -9228,8 +9243,7 @@ nsHTMLFormElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper,
nsCOMPtr<nsISupports> result;
nsWrapperCache *cache;
JSString *str = JSID_TO_STRING(id);
FindNamedItem(form, str, getter_AddRefs(result), &cache);
FindNamedItem(form, id, getter_AddRefs(result), &cache);
if (result) {
// Wrap result, result can be either an element or a list of
@ -10173,11 +10187,14 @@ nsStorageSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
if (!jsstr)
return JS_FALSE;
nsDependentJSString depStr;
if (!depStr.init(cx, jsstr))
return JS_FALSE;
// GetItem() will return null if the caller can't access the session
// storage item.
nsCOMPtr<nsIDOMStorageItem> item;
nsresult rv = storage->GetItem(nsDependentJSString(jsstr),
getter_AddRefs(item));
nsresult rv = storage->GetItem(depStr, getter_AddRefs(item));
NS_ENSURE_SUCCESS(rv, rv);
if (item) {
@ -10212,11 +10229,16 @@ nsStorageSH::SetProperty(nsIXPConnectWrappedNative *wrapper,
JSString *key = IdToString(cx, id);
NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED);
nsDependentJSString keyStr;
NS_ENSURE_TRUE(keyStr.init(cx, key), NS_ERROR_UNEXPECTED);
JSString *value = ::JS_ValueToString(cx, *vp);
NS_ENSURE_TRUE(value, NS_ERROR_UNEXPECTED);
nsresult rv = storage->SetItem(nsDependentJSString(key),
nsDependentJSString(value));
nsDependentJSString valueStr;
NS_ENSURE_TRUE(valueStr.init(cx, value), NS_ERROR_UNEXPECTED);
nsresult rv = storage->SetItem(keyStr, valueStr);
if (NS_SUCCEEDED(rv)) {
rv = NS_SUCCESS_I_DID_SOMETHING;
}
@ -10235,7 +10257,10 @@ nsStorageSH::DelProperty(nsIXPConnectWrappedNative *wrapper,
JSString *key = IdToString(cx, id);
NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED);
nsresult rv = storage->RemoveItem(nsDependentJSString(key));
nsDependentJSString keyStr;
NS_ENSURE_TRUE(keyStr.init(cx, key), NS_ERROR_UNEXPECTED);
nsresult rv = storage->RemoveItem(keyStr);
if (NS_SUCCEEDED(rv)) {
rv = NS_SUCCESS_I_DID_SOMETHING;
}
@ -10334,10 +10359,13 @@ nsStorage2SH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
nsCOMPtr<nsIDOMStorage> storage(do_QueryWrappedNative(wrapper));
nsDependentJSString depStr;
NS_ENSURE_TRUE(depStr.init(cx, jsstr), NS_ERROR_UNEXPECTED);
// GetItem() will return null if the caller can't access the session
// storage item.
nsAutoString data;
nsresult rv = storage->GetItem(nsDependentJSString(jsstr), data);
nsresult rv = storage->GetItem(depStr, data);
NS_ENSURE_SUCCESS(rv, rv);
if (!DOMStringIsNull(data)) {
@ -10406,11 +10434,16 @@ nsStorage2SH::SetProperty(nsIXPConnectWrappedNative *wrapper,
JSString *key = IdToString(cx, id);
NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED);
nsDependentJSString keyStr;
NS_ENSURE_TRUE(keyStr.init(cx, key), NS_ERROR_UNEXPECTED);
JSString *value = ::JS_ValueToString(cx, *vp);
NS_ENSURE_TRUE(value, NS_ERROR_UNEXPECTED);
nsresult rv = storage->SetItem(nsDependentJSString(key),
nsDependentJSString(value));
nsDependentJSString valueStr;
NS_ENSURE_TRUE(valueStr.init(cx, value), NS_ERROR_UNEXPECTED);
nsresult rv = storage->SetItem(keyStr, valueStr);
if (NS_SUCCEEDED(rv)) {
rv = NS_SUCCESS_I_DID_SOMETHING;
}
@ -10429,7 +10462,10 @@ nsStorage2SH::DelProperty(nsIXPConnectWrappedNative *wrapper,
JSString *key = IdToString(cx, id);
NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED);
nsresult rv = storage->RemoveItem(nsDependentJSString(key));
nsDependentJSString keyStr;
NS_ENSURE_TRUE(keyStr.init(cx, key), NS_ERROR_UNEXPECTED);
nsresult rv = storage->RemoveItem(keyStr);
if (NS_SUCCEEDED(rv)) {
rv = NS_SUCCESS_I_DID_SOMETHING;
}

View File

@ -454,7 +454,7 @@ protected:
{
NS_ASSERTION(JSID_IS_STRING(id), "Don't pass non-string jsid's here!");
jschar *str = ::JS_GetStringChars(JSID_TO_STRING(id));
const jschar *str = ::JS_GetInternedStringChars(JSID_TO_STRING(id));
if (str[0] == 'o' && str[1] == 'n') {
return ReallyIsEventName(id, str[2]);
@ -519,8 +519,7 @@ protected:
}
static nsresult GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
JSObject *obj, JSString *str,
PRBool *did_resolve);
JSObject *obj, jsid id, PRBool *did_resolve);
public:
NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
@ -1037,7 +1036,7 @@ protected:
{
}
static nsresult FindNamedItem(nsIForm *aForm, JSString *str,
static nsresult FindNamedItem(nsIForm *aForm, jsid id,
nsISupports **aResult, nsWrapperCache **aCache);
public:

View File

@ -724,8 +724,13 @@ static JSBool
ChangeCase(JSContext *cx, JSString *src, jsval *rval,
void(* changeCaseFnc)(const nsAString&, nsAString&))
{
nsDependentJSString depStr;
if (!depStr.init(cx, src)) {
return JS_FALSE;
}
nsAutoString result;
changeCaseFnc(nsDependentJSString(src), result);
changeCaseFnc(depStr, result);
JSString *ucstr = JS_NewUCStringCopyN(cx, (jschar*)result.get(), result.Length());
if (!ucstr) {
@ -779,11 +784,14 @@ LocaleCompare(JSContext *cx, JSString *src1, JSString *src2, jsval *rval)
}
}
nsDependentJSString depStr1, depStr2;
if (!depStr1.init(cx, src1) || !depStr2.init(cx, src2)) {
return JS_FALSE;
}
PRInt32 result;
rv = gCollation->CompareString(nsICollation::kCollationStrengthDefault,
nsDependentJSString(src1),
nsDependentJSString(src2),
&result);
depStr1, depStr2, &result);
if (NS_FAILED(rv)) {
nsDOMClassInfo::ThrowJSException(cx, rv);
@ -1591,27 +1599,36 @@ JSValueToAString(JSContext *cx, jsval val, nsAString *result,
}
JSString* jsstring = ::JS_ValueToString(cx, val);
if (jsstring) {
result->Assign(reinterpret_cast<const PRUnichar*>
(::JS_GetStringChars(jsstring)),
::JS_GetStringLength(jsstring));
} else {
result->Truncate();
if (!jsstring) {
goto error;
}
// We failed to convert val to a string. We're either OOM, or the
// security manager denied access to .toString(), or somesuch, on
// an object. Treat this case as if the result were undefined.
size_t length;
const jschar *chars;
chars = ::JS_GetStringCharsAndLength(cx, jsstring, &length);
if (!chars) {
goto error;
}
if (isUndefined) {
*isUndefined = PR_TRUE;
}
result->Assign(chars, length);
return NS_OK;
if (!::JS_IsExceptionPending(cx)) {
// JS_ValueToString() returned null w/o an exception
// pending. That means we're OOM.
error:
// We failed to convert val to a string. We're either OOM, or the
// security manager denied access to .toString(), or somesuch, on
// an object. Treat this case as if the result were undefined.
return NS_ERROR_OUT_OF_MEMORY;
}
result->Truncate();
if (isUndefined) {
*isUndefined = PR_TRUE;
}
if (!::JS_IsExceptionPending(cx)) {
// JS_ValueToString()/JS_GetStringCharsAndLength returned null w/o an
// exception pending. That means we're OOM.
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
@ -2548,37 +2565,14 @@ nsJSContext::ConnectToInner(nsIScriptGlobalObject *aNewInner, void *aOuterGlobal
JSObject *newInnerJSObject = (JSObject *)aNewInner->GetScriptGlobal(JAVASCRIPT);
JSObject *outerGlobal = (JSObject *)aOuterGlobal;
// Make the inner and outer window both share the same
// prototype. The prototype we share is the outer window's
// prototype, this way XPConnect can still find the wrapper to
// use when making a call like alert() (w/o qualifying it with
// "window."). XPConnect looks up the wrapper based on the
// function object's parent, which is the object the function
// was called on, and when calling alert() we'll be calling the
// alert() function from the outer window's prototype off of the
// inner window. In this case XPConnect is able to find the
// outer (through the JSExtendedClass hook outerObject), so this
// prototype sharing works.
// Now that we're connecting the outer global to the inner one,
// we must have transplanted it. The JS engine tries to maintain
// the global object's compartment as its default compartment,
// so update that now since it might have changed.
JS_SetGlobalObject(mContext, outerGlobal);
// We do *not* want to use anything else out of the outer
// object's prototype chain than the first prototype, which is
// the XPConnect prototype. The rest we want from the inner
// window's prototype, i.e. the global scope polluter and
// Object.prototype. This way the outer also gets the benefits
// of the global scope polluter, and the inner window's
// Object.prototype.
JSObject *proto = JS_GetPrototype(mContext, outerGlobal);
JSObject *innerProto = JS_GetPrototype(mContext, newInnerJSObject);
JSObject *innerProtoProto = JS_GetPrototype(mContext, innerProto);
JS_SetPrototype(mContext, newInnerJSObject, proto);
JS_SetPrototype(mContext, proto, innerProtoProto);
NS_ASSERTION(JS_GetPrototype(mContext, outerGlobal) ==
JS_GetPrototype(mContext, newInnerJSObject),
"outer and inner globals should have the same prototype");
return NS_OK;
}
@ -2626,19 +2620,6 @@ nsJSContext::CreateOuterObject(nsIScriptGlobalObject *aGlobalObject,
JS_SetOptions(mContext, JS_GetOptions(mContext) | JSOPTION_XML);
}
nsIXPConnect *xpc = nsContentUtils::XPConnect();
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
nsresult rv = xpc->WrapNative(mContext, aCurrentInner->GetGlobalJSObject(),
aCurrentInner, NS_GET_IID(nsISupports),
getter_AddRefs(holder));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIXPConnectWrappedNative> wrapper(do_QueryInterface(holder));
NS_ABORT_IF_FALSE(wrapper, "bad wrapper");
wrapper->RefreshPrototype();
JSObject *outer =
NS_NewOuterWindowProxy(mContext, aCurrentInner->GetGlobalJSObject());
if (!outer) {
@ -2655,6 +2636,20 @@ nsJSContext::SetOuterObject(void *aOuterObject)
// Force our context's global object to be the outer.
JS_SetGlobalObject(mContext, outer);
// NB: JS_SetGlobalObject sets mContext->compartment.
JSObject *inner = JS_GetParent(mContext, outer);
nsIXPConnect *xpc = nsContentUtils::XPConnect();
nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
nsresult rv = xpc->GetWrappedNativeOfJSObject(mContext, inner,
getter_AddRefs(wrapper));
NS_ENSURE_SUCCESS(rv, rv);
NS_ABORT_IF_FALSE(wrapper, "bad wrapper");
wrapper->RefreshPrototype();
JS_SetPrototype(mContext, outer, JS_GetPrototype(mContext, inner));
return NS_OK;
}

View File

@ -109,7 +109,7 @@ private:
nsCOMPtr<nsIArray> mArgv;
// The JS expression to evaluate or function to call, if !mExpr
JSString *mExpr;
JSFlatString *mExpr;
JSObject *mFunObj;
};
@ -134,10 +134,10 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsJSScriptTimeoutHandler)
else if (tmp->mFunObj) {
JSFunction* fun = (JSFunction*)tmp->mFunObj->getPrivate();
if (fun->atom) {
size_t size = 1 + JS_PutEscapedString(NULL, 0, ATOM_TO_STRING(fun->atom), 0);
size_t size = 1 + JS_PutEscapedFlatString(NULL, 0, ATOM_TO_STRING(fun->atom), 0);
char *name = new char[size];
if (name) {
JS_PutEscapedString(name, size, ATOM_TO_STRING(fun->atom), 0);
JS_PutEscapedFlatString(name, size, ATOM_TO_STRING(fun->atom), 0);
foo.AppendLiteral(" [");
foo.Append(name);
delete[] name;
@ -232,7 +232,7 @@ nsJSScriptTimeoutHandler::Init(nsGlobalWindow *aWindow, PRBool *aIsInterval,
ncc->GetArgc(&argc);
ncc->GetArgvPtr(&argv);
JSString *expr = nsnull;
JSFlatString *expr = nsnull;
JSObject *funobj = nsnull;
int32 interval = 0;
@ -264,10 +264,17 @@ nsJSScriptTimeoutHandler::Init(nsGlobalWindow *aWindow, PRBool *aIsInterval,
case JSTYPE_STRING:
case JSTYPE_OBJECT:
expr = ::JS_ValueToString(cx, argv[0]);
if (!expr)
return NS_ERROR_OUT_OF_MEMORY;
argv[0] = STRING_TO_JSVAL(expr);
{
JSString *str = ::JS_ValueToString(cx, argv[0]);
if (!str)
return NS_ERROR_OUT_OF_MEMORY;
expr = ::JS_FlattenString(cx, str);
if (!expr)
return NS_ERROR_OUT_OF_MEMORY;
argv[0] = STRING_TO_JSVAL(str);
}
break;
default:
@ -370,8 +377,7 @@ const PRUnichar *
nsJSScriptTimeoutHandler::GetHandlerText()
{
NS_ASSERTION(mExpr, "No expression, so no handler text!");
return reinterpret_cast<const PRUnichar *>
(::JS_GetStringChars(mExpr));
return ::JS_GetFlatStringChars(mExpr);
}
nsresult NS_CreateJSTimeoutHandler(nsGlobalWindow *aWindow,

View File

@ -75,23 +75,44 @@ public:
class nsDependentJSString : public nsDependentString
{
public:
explicit nsDependentJSString(jsval v)
: nsDependentString((PRUnichar *)::JS_GetStringChars(JSVAL_TO_STRING(v)),
::JS_GetStringLength(JSVAL_TO_STRING(v)))
{
}
/**
* In the case of string ids, getting the string's chars is infallible, so
* the dependent string can be constructed directly.
*/
explicit nsDependentJSString(jsid id)
: nsDependentString((PRUnichar *)::JS_GetStringChars(JSID_TO_STRING(id)),
::JS_GetStringLength(JSID_TO_STRING(id)))
: nsDependentString(JS_GetInternedStringChars(JSID_TO_STRING(id)),
JS_GetStringLength(JSID_TO_STRING(id)))
{
}
explicit nsDependentJSString(JSString *str)
: nsDependentString((PRUnichar *)::JS_GetStringChars(str), ::JS_GetStringLength(str))
/**
* For all other strings, the nsDependentJSString object should be default
* constructed, which leaves it empty (this->IsEmpty()), and initialized with
* one of the fallible init() methods below.
*/
nsDependentJSString()
{
}
JSBool init(JSContext* aContext, JSString* str)
{
size_t length;
const jschar* chars = JS_GetStringCharsZAndLength(aContext, str, &length);
if (!chars)
return JS_FALSE;
NS_ASSERTION(IsEmpty(), "init() on initialized string");
nsDependentString* base = this;
new(base) nsDependentString(chars, length);
return JS_TRUE;
}
JSBool init(JSContext* aContext, const jsval &v)
{
return init(aContext, JSVAL_TO_STRING(v));
}
~nsDependentJSString()
{
}

View File

@ -425,7 +425,7 @@ IDBCursor::Continue(const jsval &aKey,
}
Key key;
nsresult rv = IDBObjectStore::GetKeyFromJSVal(aKey, key);
nsresult rv = IDBObjectStore::GetKeyFromJSVal(aKey, aCx, key);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR);
if (key.IsNull()) {
@ -504,7 +504,7 @@ IDBCursor::Update(const jsval& aValue,
}
else {
Key newKey;
rv = IDBObjectStore::GetKeyFromJSVal(prop.jsval_value(), newKey);
rv = IDBObjectStore::GetKeyFromJSVal(prop.jsval_value(), aCx, newKey);
NS_ENSURE_SUCCESS(rv, rv);
if (newKey.IsUnset() || newKey.IsNull() || newKey != key) {

View File

@ -357,7 +357,7 @@ GetKeyFromObject(JSContext* aCx,
JSBool ok = JS_GetUCProperty(aCx, aObj, keyPathChars, keyPathLen, &key);
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
nsresult rv = IDBObjectStore::GetKeyFromJSVal(key, aKey);
nsresult rv = IDBObjectStore::GetKeyFromJSVal(key, aCx, aKey);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
@ -442,6 +442,7 @@ IDBObjectStore::GetKeyFromVariant(nsIVariant* aKeyVariant,
// static
nsresult
IDBObjectStore::GetKeyFromJSVal(jsval aKeyVal,
JSContext* aCx,
Key& aKey)
{
if (JSVAL_IS_VOID(aKeyVal)) {
@ -451,7 +452,11 @@ IDBObjectStore::GetKeyFromJSVal(jsval aKeyVal,
aKey = Key::NULLKEY;
}
else if (JSVAL_IS_STRING(aKeyVal)) {
aKey = nsDependentJSString(aKeyVal);
nsDependentJSString depStr;
if (!depStr.init(aCx, JSVAL_TO_STRING(aKeyVal))) {
return NS_ERROR_OUT_OF_MEMORY;
}
aKey = depStr;
}
else if (JSVAL_IS_INT(aKeyVal)) {
aKey = JSVAL_TO_INT(aKeyVal);
@ -586,7 +591,12 @@ IDBObjectStore::GetKeyPathValueFromJSON(const nsAString& aJSON,
value.jsval_addr());
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
rv = GetKeyFromJSVal(value.jsval_value(), aValue);
rv = GetKeyFromJSVal(value.jsval_value(), *aCx, aValue);
if (rv == NS_ERROR_OUT_OF_MEMORY) {
NS_ASSERTION(JS_IsExceptionPending(*aCx), "OOM from JS should throw");
return NS_ERROR_OUT_OF_MEMORY;
}
if (NS_FAILED(rv) || aValue.IsNull()) {
// If the object doesn't have a value that we can use for our index then we
// leave it unset.
@ -627,7 +637,12 @@ IDBObjectStore::GetIndexUpdateInfo(ObjectStoreInfo* aObjectStoreInfo,
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
Key value;
nsresult rv = GetKeyFromJSVal(keyPathValue, value);
nsresult rv = GetKeyFromJSVal(keyPathValue, aCx, value);
if (rv == NS_ERROR_OUT_OF_MEMORY) {
NS_ASSERTION(JS_IsExceptionPending(aCx), "OOM from JS should throw");
return NS_ERROR_OUT_OF_MEMORY;
}
if (NS_FAILED(rv) || value.IsUnset() || value.IsNull()) {
// Not a value we can do anything with, ignore it.
continue;
@ -794,7 +809,7 @@ IDBObjectStore::GetAddInfo(JSContext* aCx,
JSAutoRequest ar(aCx);
if (mKeyPath.IsEmpty()) {
rv = GetKeyFromJSVal(aKeyVal, aKey);
rv = GetKeyFromJSVal(aKeyVal, aCx, aKey);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR);
}
else {

View File

@ -78,6 +78,7 @@ public:
static nsresult
GetKeyFromJSVal(jsval aKeyVal,
JSContext* aCx,
Key& aKey);
static nsresult

View File

@ -335,7 +335,14 @@ nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel,
if (!isUndefined && NS_SUCCEEDED(rv)) {
NS_ASSERTION(JSVAL_IS_STRING(rval), "evalInSandbox is broken");
result = nsDependentJSString(JSVAL_TO_STRING(rval));
nsDependentJSString depStr;
if (!depStr.init(cx, JSVAL_TO_STRING(rval))) {
JS_ReportPendingException(cx);
isUndefined = PR_TRUE;
} else {
result = depStr;
}
}
stack->Pop(nsnull);

View File

@ -142,9 +142,11 @@ nsDOMWorkerFunctions::Dump(JSContext* aCx,
JSString* str;
if (aArgc && (str = JS_ValueToString(aCx, JS_ARGV(aCx, aVp)[0])) && str) {
nsDependentJSString string(str);
fputs(NS_ConvertUTF16toUTF8(nsDependentJSString(str)).get(), stderr);
fflush(stderr);
nsDependentJSString depStr;
if (depStr.init(aCx, str)) {
fputs(NS_ConvertUTF16toUTF8(depStr).get(), stderr);
fflush(stderr);
}
}
return JS_TRUE;
}
@ -268,7 +270,12 @@ nsDOMWorkerFunctions::LoadScripts(JSContext* aCx,
nsString* newURL = urls.AppendElement();
NS_ASSERTION(newURL, "Shouldn't fail if SetCapacity succeeded above!");
newURL->Assign(nsDependentJSString(str));
nsDependentJSString depStr;
if (!depStr.init(aCx, str)) {
return JS_FALSE;
}
newURL->Assign(depStr);
}
nsRefPtr<nsDOMWorkerScriptLoader> loader =
@ -367,39 +374,8 @@ nsDOMWorkerFunctions::AtoB(JSContext* aCx,
return JS_FALSE;
}
JSString* str = JS_ValueToString(aCx, JS_ARGV(aCx, aVp)[0]);
if (!str) {
NS_ASSERTION(JS_IsExceptionPending(aCx), "Need to set an exception!");
return JS_FALSE;
}
size_t len = JS_GetStringEncodingLength(aCx, str);
if (len == size_t(-1))
return JS_FALSE;
JSUint32 alloc_len = (len + 1) * sizeof(char);
char *buffer = static_cast<char *>(nsMemory::Alloc(alloc_len));
if (!buffer)
return JS_FALSE;
JS_EncodeStringToBuffer(str, buffer, len);
buffer[len] = '\0';
nsDependentCString string(buffer, len);
nsCAutoString result;
if (NS_FAILED(nsXPConnect::Base64Decode(string, result))) {
JS_ReportError(aCx, "Failed to decode base64 string!");
return JS_FALSE;
}
str = JS_NewStringCopyN(aCx, result.get(), result.Length());
if (!str) {
return JS_FALSE;
}
JS_SET_RVAL(aCx, aVp, STRING_TO_JSVAL(str));
return JS_TRUE;
return nsXPConnect::Base64Decode(aCx, JS_ARGV(aCx, aVp)[0],
&JS_RVAL(aCx, aVp));
}
JSBool
@ -419,39 +395,8 @@ nsDOMWorkerFunctions::BtoA(JSContext* aCx,
return JS_FALSE;
}
JSString* str = JS_ValueToString(aCx, JS_ARGV(aCx, aVp)[0]);
if (!str) {
NS_ASSERTION(JS_IsExceptionPending(aCx), "Need to set an exception!");
return JS_FALSE;
}
size_t len = JS_GetStringEncodingLength(aCx, str);
if (len == size_t(-1))
return JS_FALSE;
JSUint32 alloc_len = (len + 1) * sizeof(char);
char *buffer = static_cast<char *>(nsMemory::Alloc(alloc_len));
if (!buffer)
return JS_FALSE;
JS_EncodeStringToBuffer(str, buffer, len);
buffer[len] = '\0';
nsDependentCString string(buffer, len);
nsCAutoString result;
if (NS_FAILED(nsXPConnect::Base64Encode(string, result))) {
JS_ReportError(aCx, "Failed to encode base64 data!");
return JS_FALSE;
}
str = JS_NewStringCopyN(aCx, result.get(), result.Length());
if (!str) {
return JS_FALSE;
}
JS_SET_RVAL(aCx, aVp, STRING_TO_JSVAL(str));
return JS_TRUE;
return nsXPConnect::Base64Encode(aCx, JS_ARGV(aCx, aVp)[0],
&JS_RVAL(aCx, aVp));
}
JSBool
@ -569,8 +514,7 @@ nsDOMWorkerFunctions::CTypesLazyGetter(JSContext* aCx,
{
NS_ASSERTION(JS_GetGlobalForObject(aCx, aObj) == aObj, "Bad object!");
NS_ASSERTION(JSID_IS_STRING(aId), "Not a string!");
JSString* str = JSID_TO_STRING(aId);
NS_ASSERTION(nsDependentJSString(str).EqualsLiteral("ctypes"), "Bad id!");
NS_ASSERTION(nsDependentJSString(aId).EqualsLiteral("ctypes"), "Bad id!");
}
#endif
nsDOMWorker* worker = static_cast<nsDOMWorker*>(JS_GetContextPrivate(aCx));
@ -736,14 +680,14 @@ nsDOMWorkerScope::AddProperty(nsIXPConnectWrappedNative* aWrapper,
return NS_OK;
}
JSString *str = JSID_TO_STRING(aId);
JSFlatString *str = JSID_TO_FLAT_STRING(aId);
// Figure out which listener we're setting.
SetListenerFunc func;
if (JS_MatchStringAndAscii(str, "onmessage")) {
if (JS_FlatStringEqualsAscii(str, "onmessage")) {
func = &nsDOMWorkerScope::SetOnmessage;
}
else if (JS_MatchStringAndAscii(str, "onerror")) {
else if (JS_FlatStringEqualsAscii(str, "onerror")) {
func = &nsDOMWorkerScope::SetOnerror;
}
else {
@ -1364,7 +1308,10 @@ nsDOMWorker::InitializeInternal(nsIScriptGlobalObject* aOwner,
JSString* str = JS_ValueToString(aCx, aArgv[0]);
NS_ENSURE_TRUE(str, NS_ERROR_XPC_BAD_CONVERT_JS);
mScriptURL.Assign(nsDependentJSString(str));
nsDependentJSString depStr;
NS_ENSURE_TRUE(depStr.init(aCx, str), NS_ERROR_OUT_OF_MEMORY);
mScriptURL.Assign(depStr);
NS_ENSURE_FALSE(mScriptURL.IsEmpty(), NS_ERROR_INVALID_ARG);
mLock = nsAutoLock::NewLock("nsDOMWorker::mLock");

View File

@ -196,11 +196,10 @@ nsDOMWorkerTimeout::ExpressionCallback::Run(nsDOMWorkerTimeout* aTimeout,
JSString* expression = JS_ValueToString(aCx, mExpression);
NS_ENSURE_TRUE(expression, NS_ERROR_FAILURE);
jschar* string = JS_GetStringChars(expression);
size_t stringLength;
const jschar* string = JS_GetStringCharsAndLength(aCx, expression, &stringLength);
NS_ENSURE_TRUE(string, NS_ERROR_FAILURE);
size_t stringLength = JS_GetStringLength(expression);
jsval rval;
PRBool success = JS_EvaluateUCScriptForPrincipals(aCx, global, principal,
string, stringLength,

View File

@ -1,7 +1,5 @@
var data = [ -1, 0, 1, 1.5, undefined, true, false ];
// XXXbent window.atob treats |null| as the empty string, whereas worker.atob
// and the js component loader treat it as the string 'null'. Meh.
var data = [ -1, 0, 1, 1.5, null, undefined, true, false, "foo",
"123456789012345", "1234567890123456", "12345678901234567"];
var str = "";
for (var i = 0; i < 30; i++) {

View File

@ -126,6 +126,7 @@ _TEST_FILES = \
test_bug369306.html \
test_bug61098.html \
test_bug597809.html \
test_bug612267.html \
$(NULL)
libs:: $(_TEST_FILES)

View File

@ -0,0 +1,28 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=612267
-->
<head>
<title>Test for Bug 393974</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=612267">Mozilla Bug 612267</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
Window.prototype.test = 'PASS';
is(window.test, 'PASS', "setting Window.prototype affects window.__proto__");
is(test, 'PASS', "setting Window.prototype affects the inner window lookup for sure");
</script>
</pre>
</body>
</html>

View File

@ -278,20 +278,23 @@ SetProtocol(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
JSAutoRequest ar(cx);
JSString *protocol = JS_ValueToString(cx, argv[0]);
JSString *str = JS_ValueToString(cx, argv[0]);
if (!str) return JS_FALSE;
JSFlatString *protocol = JS_FlattenString(cx, str);
if (!protocol) return JS_FALSE;
if (JS_MatchStringAndAscii(protocol, "interactive")) {
if (JS_FlatStringEqualsAscii(protocol, "interactive")) {
shell->mEmitHeader = PR_FALSE;
shell->mPrompt = NS_LITERAL_CSTRING("\n> ");
shell->mProtocol = protocol;
}
else if (JS_MatchStringAndAscii(protocol, "synchronous")) {
else if (JS_FlatStringEqualsAscii(protocol, "synchronous")) {
shell->mEmitHeader = PR_TRUE;
shell->mPrompt = NS_LITERAL_CSTRING("\n> ");
shell->mProtocol = protocol;
}
else if (JS_MatchStringAndAscii(protocol, "plain")) {
else if (JS_FlatStringEqualsAscii(protocol, "plain")) {
shell->mEmitHeader = PR_FALSE;
shell->mPrompt = NS_LITERAL_CSTRING("\n");
shell->mProtocol = protocol;

View File

@ -1253,10 +1253,13 @@ XPCShellEnvironment::EvaluateString(const nsString& aString,
if (ok && result != JSVAL_VOID) {
JSErrorReporter old = JS_SetErrorReporter(mCx, NULL);
JSString* str = JS_ValueToString(mCx, result);
nsDependentJSString depStr;
if (str)
depStr.init(mCx, str);
JS_SetErrorReporter(mCx, old);
if (str && aResult) {
aResult->Assign(nsDependentJSString(str));
if (!depStr.IsEmpty() && aResult) {
aResult->Assign(depStr);
}
}
}

View File

@ -63,6 +63,11 @@ CPPSRCS = \
ObjectWrapperChild.cpp \
$(NULL)
# For nsDependentJSString
LOCAL_INCLUDES += \
-I$(topsrcdir)/dom/base \
$(NULL)
include $(topsrcdir)/config/config.mk
include $(topsrcdir)/ipc/chromium/chromium-config.mk
include $(topsrcdir)/config/rules.mk

View File

@ -50,6 +50,7 @@
#include "nsTArray.h"
#include "nsContentUtils.h"
#include "nsIJSContextStack.h"
#include "nsJSUtils.h"
using namespace mozilla::jsipc;
using namespace js;
@ -188,8 +189,12 @@ ObjectWrapperChild::jsval_to_JSVariant(JSContext* cx, jsval from, JSVariant* to)
case JSTYPE_OBJECT:
return JSObject_to_JSVariant(cx, JSVAL_TO_OBJECT(from), to);
case JSTYPE_STRING:
*to = nsDependentString((PRUnichar*)JS_GetStringChars(JSVAL_TO_STRING(from)),
JS_GetStringLength(JSVAL_TO_STRING(from)));
{
nsDependentJSString depStr;
if (!depStr.init(cx, from))
return false;
*to = depStr;
}
return true;
case JSTYPE_NUMBER:
if (JSVAL_IS_INT(from))
@ -282,10 +287,10 @@ ObjectWrapperChild::Manager()
static bool
jsid_to_nsString(JSContext* cx, jsid from, nsString* to)
{
jsval v;
if (JS_IdToValue(cx, from, &v) && JSVAL_IS_STRING(v)) {
*to = nsDependentString((PRUnichar*)JS_GetStringChars(JSVAL_TO_STRING(v)),
JS_GetStringLength(JSVAL_TO_STRING(v)));
if (JSID_IS_STRING(from)) {
size_t length;
const jschar* chars = JS_GetInternedStringCharsAndLength(JSID_TO_STRING(from), &length);
*to = nsDependentString(chars, length);
return true;
}
return false;

View File

@ -42,6 +42,7 @@
#include "mozilla/jsipc/ContextWrapperParent.h"
#include "mozilla/jsipc/CPOWTypes.h"
#include "mozilla/unused.h"
#include "nsJSUtils.h"
#include "jsobj.h"
#include "jsfun.h"
@ -265,8 +266,12 @@ ObjectWrapperParent::jsval_to_JSVariant(JSContext* cx, jsval from,
}
return true;
case JSTYPE_STRING:
*to = nsDependentString((PRUnichar*)JS_GetStringChars(JSVAL_TO_STRING(from)),
JS_GetStringLength(JSVAL_TO_STRING(from)));
{
nsDependentJSString depStr;
if (!depStr.init(cx, from))
return false;
*to = depStr;
}
return true;
case JSTYPE_NUMBER:
if (JSVAL_IS_INT(from))
@ -379,10 +384,12 @@ static bool
jsval_to_nsString(JSContext* cx, jsid from, nsString* to)
{
JSString* str;
const jschar* chars;
jsval idval;
if (JS_IdToValue(cx, from, &idval) &&
(str = JS_ValueToString(cx, idval))) {
*to = JS_GetStringChars(str);
(str = JS_ValueToString(cx, idval)) &&
(chars = JS_GetStringCharsZ(cx, str))) {
*to = chars;
return true;
}
return false;

View File

@ -49,6 +49,8 @@
#include "mozilla/jetpack/PHandleChild.h"
#include "mozilla/jetpack/Handle.h"
#include "nsJSUtils.h"
using mozilla::jetpack::JetpackActorCommon;
using mozilla::jetpack::PHandleParent;
using mozilla::jetpack::HandleParent;
@ -138,8 +140,12 @@ JetpackActorCommon::jsval_to_PrimVariant(JSContext* cx, JSType type, jsval from,
}
case JSTYPE_STRING:
*to = nsDependentString((PRUnichar*)JS_GetStringChars(JSVAL_TO_STRING(from)),
JS_GetStringLength(JSVAL_TO_STRING(from)));
{
nsDependentJSString depStr;
if (!depStr.init(cx, from))
return false;
*to = depStr;
}
return true;
case JSTYPE_NUMBER:
@ -223,8 +229,10 @@ JetpackActorCommon::jsval_to_CompVariant(JSContext* cx, JSType type, jsval from,
KeyValue kv;
// Silently drop properties that can't be converted.
if (jsval_to_Variant(cx, val, &kv.value(), seen)) {
kv.key() = nsDependentString((PRUnichar*)JS_GetStringChars(idStr),
JS_GetStringLength(idStr));
nsDependentJSString depStr;
if (!depStr.init(cx, idStr))
return false;
kv.key() = depStr;
// If AppendElement fails, we lose this property, no big deal.
kvs.AppendElement(kv);
}

View File

@ -96,7 +96,7 @@ static char*
UnicodeToNative(JSContext *cx, const jschar *source, size_t slen)
{
nsCAutoString native;
nsDependentString unicode(reinterpret_cast<const PRUnichar*>(source), slen);
nsDependentString unicode(source, slen);
nsresult rv = NS_CopyUnicodeToNative(unicode, native);
if (NS_FAILED(rv)) {
JS_ReportError(cx, "could not convert string to native charset");
@ -251,8 +251,12 @@ MessageCommon(JSContext* cx, uintN argc, jsval* vp,
return JS_FALSE;
}
result->msgName.Assign((PRUnichar*)JS_GetStringChars(msgNameStr),
JS_GetStringLength(msgNameStr));
size_t length;
const jschar* chars = JS_GetStringCharsAndLength(cx, msgNameStr, &length);
if (!chars)
return JS_FALSE;
result->msgName.Assign(chars, length);
result->data.Clear();
@ -355,8 +359,12 @@ ReceiverCommon(JSContext* cx, uintN argc, jsval* vp,
return JS_FALSE;
}
result->msgName.Assign((PRUnichar*)JS_GetStringChars(str),
JS_GetStringLength(str));
size_t length;
const jschar* chars = JS_GetStringCharsAndLength(cx, str, &length);
if (!chars)
return JS_FALSE;
result->msgName.Assign(chars, length);
if (arity < 2)
return JS_TRUE;
@ -497,9 +505,13 @@ JetpackChild::EvalInSandbox(JSContext* cx, uintN argc, jsval* vp)
return JS_FALSE;
}
size_t length;
const jschar* chars = JS_GetStringCharsAndLength(cx, str, &length);
if (!chars)
return JS_FALSE;
js::AutoValueRooter ignored(cx);
return JS_EvaluateUCScript(cx, obj, JS_GetStringChars(str), JS_GetStringLength(str), "", 1,
ignored.jsval_addr());
return JS_EvaluateUCScript(cx, obj, chars, length, "", 1, ignored.jsval_addr());
}
bool JetpackChild::sReportingError;

View File

@ -74,6 +74,11 @@ CPPSRCS = \
JetpackActorCommon.cpp \
$(NULL)
# For nsDependentJSString
LOCAL_INCLUDES += \
-I$(topsrcdir)/dom/base \
$(NULL)
ifdef ENABLE_TESTS
TOOL_DIRS += tests
endif

View File

@ -78,7 +78,7 @@ interface jsdIActivationCallback;
* Debugger service. It's not a good idea to have more than one active client of
* the debugger service.
*/
[scriptable, uuid(01769775-c77c-47f9-8848-0abbab404215)]
[scriptable, uuid(1ad86ef3-5eca-4ed7-81c5-a757d1957dff)]
interface jsdIDebuggerService : nsISupports
{
/** Internal use only. */
@ -512,7 +512,7 @@ interface jsdIFilterEnumerator : nsISupports
/**
* Pass an instance of one of these to jsdIDebuggerService::enumerateScripts.
*/
[scriptable, uuid(5ba76b99-acb1-4ed8-a4e4-a716a7d9097e)]
[scriptable, uuid(4eef60c2-9bbc-48fa-b196-646a832c6c81)]
interface jsdIScriptEnumerator : nsISupports
{
/**
@ -525,7 +525,7 @@ interface jsdIScriptEnumerator : nsISupports
/**
* Pass an instance of one of these to jsdIDebuggerService::enumerateContexts.
*/
[scriptable, uuid(d96af02e-3379-4db5-885d-fee28d178701)]
[scriptable, uuid(57d18286-550c-4ca9-ac33-56f12ebba91e)]
interface jsdIContextEnumerator : nsISupports
{
/**
@ -538,7 +538,7 @@ interface jsdIContextEnumerator : nsISupports
/**
* Set jsdIDebuggerService::scriptHook to an instance of one of these.
*/
[scriptable, uuid(cf7ecc3f-361b-44af-84a7-4b0d6cdca204)]
[scriptable, uuid(bb722893-0f63-45c5-b547-7a0947c7b6b6)]
interface jsdIScriptHook : nsISupports
{
/**
@ -556,7 +556,7 @@ interface jsdIScriptHook : nsISupports
* Hook instances of this interface up to the
* jsdIDebuggerService::functionHook and toplevelHook properties.
*/
[scriptable, uuid(191d2738-22e8-4756-b366-6c878c87d73b)]
[scriptable, uuid(3eff1314-7ae3-4cf8-833b-c33c24a55633)]
interface jsdICallHook : nsISupports
{
/**
@ -588,7 +588,7 @@ interface jsdICallHook : nsISupports
void onCall (in jsdIStackFrame frame, in unsigned long type);
};
[scriptable, uuid(cea9ab1a-4b5d-416f-a197-9ffa7046f2ce)]
[scriptable, uuid(e6b45eee-d974-4d85-9d9e-f5a67218deb4)]
interface jsdIErrorHook : nsISupports
{
/**
@ -880,7 +880,7 @@ interface jsdIStackFrame : jsdIEphemeral
* Script object. In JavaScript engine terms, there's a single script for each
* function, and one for the top level script.
*/
[scriptable, uuid(7e6fb9ed-4382-421d-9a14-c80a486e983b)]
[scriptable, uuid(e7935220-7def-4c8e-832f-fbc948a97490)]
interface jsdIScript : jsdIEphemeral
{
/** Internal use only. */
@ -1038,6 +1038,10 @@ interface jsdIScript : jsdIEphemeral
* Clear all breakpoints set in this script.
*/
void clearAllBreakpoints ();
/**
* Call interrupt hook at least once per source line
*/
void enableSingleStepInterrupts (in PRBool mode);
};
/**
@ -1046,7 +1050,7 @@ interface jsdIScript : jsdIEphemeral
* jsdIValue adds a root for the underlying JavaScript value, so don't keep it
* if you don't need to.
*/
[scriptable, uuid(9cab158f-dc78-41dd-9d11-79e05cb3f2bd)]
[scriptable, uuid(fd1311f7-096c-44a3-847b-9d478c8176c3)]
interface jsdIValue : jsdIEphemeral
{
/** Internal use only. */
@ -1192,7 +1196,7 @@ interface jsdIValue : jsdIEphemeral
* functions from jsdIValue should move to this interface. We could inherit from
* jsdIValue or use interface flattening or something.
*/
[scriptable, uuid(a735a94c-9d41-4997-8fcb-cfa8b649a5b7)]
[scriptable, uuid(87d86308-7a27-4255-b23c-ce2394f02473)]
interface jsdIObject : nsISupports
{
/** Internal use only. */
@ -1228,7 +1232,7 @@ interface jsdIObject : nsISupports
* Representation of a property of an object. When an instance is invalid, all
* method and property access will result in a NS_UNAVAILABLE error.
*/
[scriptable, uuid(4491ecd4-fb6b-43fb-bd6f-5d1473f1df24)]
[scriptable, uuid(09332485-1419-42bc-ba1f-070815ed4b82)]
interface jsdIProperty : jsdIEphemeral
{
/** Internal use only. */

View File

@ -214,7 +214,8 @@ _dumpJSDScript(JSDContext* jsdc, JSDScript* jsdscript, const char* leadingtext)
if (fun) {
n += size_t(snprintf(Buf + n, sizeof(Buf) - n, "%s", "no fun"));
} else {
n += JS_PutEscapedString(Buf + n, sizeof(Buf) - n, fun, 0);
n += JS_PutEscapedFlatString(Buf + n, sizeof(Buf) - n,
JS_ASSERT_STRING_IS_FLAT(fun), 0);
Buf[sizeof(Buf) - 1] = '\0';
}
if (n + 1 < sizeof(Buf))
@ -587,6 +588,17 @@ jsd_GetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc* hook, void** callerdata)
return JS_TRUE;
}
JSBool
jsd_EnableSingleStepInterrupts(JSDContext* jsdc, JSDScript* jsdscript, JSBool enable)
{
JSBool rv;
JSD_LOCK();
rv = JS_SetSingleStepMode(jsdc->dumbContext, jsdscript->script, enable);
JSD_UNLOCK();
return rv;
}
/***************************************************************************/
void
@ -751,7 +763,7 @@ jsd_TrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval,
}
JSD_ASSERT_VALID_EXEC_HOOK(jsdhook);
JS_ASSERT(jsdhook->pc == (jsuword)pc);
JS_ASSERT(!jsdhook->pc || jsdhook->pc == (jsuword)pc);
JS_ASSERT(jsdhook->jsdscript->script == script);
JS_ASSERT(jsdhook->jsdscript->jsdc == jsdc);

View File

@ -562,8 +562,11 @@ jsd_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* name)
while(NULL != (jsdprop = jsd_IterateProperties(jsdc, jsdval, &iter)))
{
JSString* propName = jsd_GetValueString(jsdc, jsdprop->name);
if(propName && !JS_CompareStrings(propName, name))
return jsdprop;
if(propName) {
intN result;
if (JS_CompareStrings(cx, propName, name, &result) && !result)
return jsdprop;
}
JSD_DropProperty(jsdc, jsdprop);
}
/* Not found in property list, look it up explicitly */
@ -571,8 +574,8 @@ jsd_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* name)
if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
return NULL;
nameChars = JS_GetStringChars(name);
nameLen = JS_GetStringLength(name);
if (!(nameChars = JS_GetStringCharsZAndLength(cx, name, &nameLen)))
return NULL;
JS_BeginRequest(cx);
call = JS_EnterCrossCompartmentCall(cx, obj);

View File

@ -1033,36 +1033,61 @@ jsdScript::CreatePPLineMap()
JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL);
JSFunction *fun = JSD_GetJSFunction (mCx, mScript);
JSScript *script;
JSString *jsstr;
PRUint32 baseLine;
PRBool scriptOwner = PR_FALSE;
if (fun) {
uintN nargs = JS_GetFunctionArgumentCount(cx, fun);
if (nargs > 12)
return nsnull;
JSString *jsstr = JS_DecompileFunctionBody (cx, fun, 4);
if (!jsstr)
uintN nargs;
/* Enter a new block so we can leave before the end of this block */
do {
JSAutoEnterCompartment ac;
if (!ac.enter(cx, JS_GetFunctionObject(fun)))
return nsnull;
nargs = JS_GetFunctionArgumentCount(cx, fun);
if (nargs > 12)
return nsnull;
jsstr = JS_DecompileFunctionBody (cx, fun, 4);
if (!jsstr)
return nsnull;
} while(false);
size_t length;
const jschar *chars = JS_GetStringCharsAndLength(cx, jsstr, &length);
if (!chars)
return nsnull;
const char *argnames[] = {"arg1", "arg2", "arg3", "arg4",
"arg5", "arg6", "arg7", "arg8",
"arg9", "arg10", "arg11", "arg12" };
fun = JS_CompileUCFunction (cx, obj, "ppfun", nargs, argnames,
JS_GetStringChars(jsstr),
JS_GetStringLength(jsstr),
"x-jsd:ppbuffer?type=function", 3);
fun = JS_CompileUCFunction (cx, obj, "ppfun", nargs, argnames, chars,
length, "x-jsd:ppbuffer?type=function", 3);
if (!fun || !(script = JS_GetFunctionScript(cx, fun)))
return nsnull;
baseLine = 3;
} else {
JSString *jsstr = JS_DecompileScript (cx, JSD_GetJSScript(mCx, mScript),
"ppscript", 4);
if (!jsstr)
/* Enter a new block so we can leave before the end of this block */
do {
script = JSD_GetJSScript(mCx, mScript);
JSAutoEnterCompartment ac;
if (!ac.enter(cx, script))
return nsnull;
jsstr = JS_DecompileScript (cx, JSD_GetJSScript(mCx, mScript),
"ppscript", 4);
if (!jsstr)
return nsnull;
} while(false);
size_t length;
const jschar *chars = JS_GetStringCharsAndLength(cx, jsstr, &length);
if (!chars)
return nsnull;
script = JS_CompileUCScript (cx, obj,
JS_GetStringChars(jsstr),
JS_GetStringLength(jsstr),
script = JS_CompileUCScript (cx, obj, chars, length,
"x-jsd:ppbuffer?type=script", 1);
if (!script)
return nsnull;
@ -1284,8 +1309,7 @@ jsdScript::GetParameterNames(PRUint32* count, PRUnichar*** paramNames)
ret[i] = 0;
} else {
JSString *str = JS_AtomKey(atom);
ret[i] = NS_strndup(reinterpret_cast<PRUnichar*>(JS_GetStringChars(str)),
JS_GetStringLength(str));
ret[i] = NS_strndup(JS_GetInternedStringChars(str), JS_GetStringLength(str));
if (!ret[i]) {
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, ret);
rv = NS_ERROR_OUT_OF_MEMORY;
@ -1343,23 +1367,26 @@ jsdScript::GetFunctionSource(nsAString & aFunctionSource)
JSAutoRequest ar(cx);
JSString *jsstr;
JSAutoEnterCompartment ac;
if (fun) {
JSAutoEnterCompartment ac;
if (!ac.enter(cx, JS_GetFunctionObject(fun)))
return NS_ERROR_FAILURE;
jsstr = JS_DecompileFunction (cx, fun, 4);
} else {
JSScript *script = JSD_GetJSScript (mCx, mScript);
js::SwitchToCompartment sc(cx, script->compartment);
if (!ac.enter(cx, script))
return NS_ERROR_FAILURE;
jsstr = JS_DecompileScript (cx, script, "ppscript", 4);
}
if (!jsstr)
return NS_ERROR_FAILURE;
aFunctionSource =
nsDependentString(
reinterpret_cast<PRUnichar*>(JS_GetStringChars(jsstr)),
JS_GetStringLength(jsstr));
size_t length;
const jschar *chars = JS_GetStringCharsZAndLength(cx, jsstr, &length);
if (!chars)
return NS_ERROR_FAILURE;
aFunctionSource = nsDependentString(chars, length);
return NS_OK;
}
@ -1480,6 +1507,20 @@ jsdScript::LineToPc(PRUint32 aLine, PRUint32 aPcmap, PRUint32 *_rval)
return NS_OK;
}
NS_IMETHODIMP
jsdScript::EnableSingleStepInterrupts(PRBool enable)
{
ASSERT_VALID_EPHEMERAL;
/* Must have set interrupt hook before enabling */
if (enable && !jsdService::GetService()->CheckInterruptHook())
return NS_ERROR_NOT_INITIALIZED;
JSD_EnableSingleStepInterrupts(mCx, mScript, enable);
return NS_OK;
}
NS_IMETHODIMP
jsdScript::IsLineExecutable(PRUint32 aLine, PRUint32 aPcmap, PRBool *_rval)
{
@ -2240,12 +2281,19 @@ NS_IMETHODIMP
jsdValue::GetStringValue(nsACString &_rval)
{
ASSERT_VALID_EPHEMERAL;
JSContext *cx = JSD_GetDefaultJSContext (mCx);
if (!cx) {
NS_WARNING("No default context !?");
return NS_ERROR_FAILURE;
}
JSString *jstr_val = JSD_GetValueString(mCx, mValue);
if (jstr_val) {
nsDependentString chars(
reinterpret_cast<PRUnichar*>(JS_GetStringChars(jstr_val)),
JS_GetStringLength(jstr_val));
CopyUTF16toUTF8(chars, _rval);
size_t length;
const jschar *chars = JS_GetStringCharsZAndLength(cx, jstr_val, &length);
if (!chars)
return NS_ERROR_FAILURE;
nsDependentString depStr(chars, length);
CopyUTF16toUTF8(depStr, _rval);
} else {
_rval.Truncate();
}

View File

@ -288,6 +288,8 @@ class jsdService : public jsdIDebuggerService
virtual ~jsdService();
static jsdService *GetService ();
PRBool CheckInterruptHook() { return !!mInterruptHook; }
private:
PRBool mOn;

View File

@ -576,6 +576,14 @@ JSD_SetInterruptHook(JSDContext* jsdc,
return jsd_SetInterruptHook(jsdc, hook, callerdata);
}
JSD_PUBLIC_API(JSBool)
JSD_EnableSingleStepInterrupts(JSDContext* jsdc, JSDScript* jsdscript, JSBool enable)
{
JSD_ASSERT_VALID_CONTEXT(jsdc);
JSD_ASSERT_VALID_SCRIPT(jsdscript);
return jsd_EnableSingleStepInterrupts(jsdc, jsdscript, enable);
}
JSD_PUBLIC_API(JSBool)
JSD_ClearInterruptHook(JSDContext* jsdc)
{

View File

@ -803,6 +803,12 @@ JSD_SetInterruptHook(JSDContext* jsdc,
JSD_ExecutionHookProc hook,
void* callerdata);
/*
* Call the interrupt hook at least once per source line
*/
extern JSD_PUBLIC_API(JSBool)
JSD_EnableSingleStepInterrupts(JSDContext* jsdc, JSDScript *jsdscript, JSBool enable);
/*
* Clear the current interrupt hook.
*/

View File

@ -1168,6 +1168,19 @@ private:
);
#endif
#elif WTF_COMPILER_SUNPRO
#if WTF_CPU_X86_64
asm (
"movl $0x1, %%eax;"
"pushq %%rbx;"
"cpuid;"
"popq %%rbx;"
"movl %%ecx, (%rsi);"
"movl %%edx, (%rdi);"
:
: "S" (&flags_ecx), "D" (&flags_edx)
: "%eax", "%ecx", "%edx"
);
#else
asm (
"movl $0x1, %eax;"
"pushl %ebx;"
@ -1179,6 +1192,7 @@ private:
: "S" (&flags_ecx), "D" (&flags_edx)
: "%eax", "%ecx", "%edx"
);
#endif
#endif
static const int SSEFeatureBit = 1 << 25;
static const int SSE2FeatureBit = 1 << 26;

View File

@ -170,6 +170,13 @@ public:
size_t available() const { return (m_pools.length() > 1) ? 0 : m_end - m_freePtr; }
// Flag for downstream use, whether to try to release references to this pool.
bool m_destroy;
// GC number in which the m_destroy flag was most recently set. Used downstream to
// remember whether m_destroy was computed for the currently active GC.
size_t m_gcNumber;
private:
// On OOM, this will return an Allocation where pages is NULL.
static Allocation systemAlloc(size_t n);
@ -393,7 +400,7 @@ private:
// This constructor can fail due to OOM. If it does, m_freePtr will be
// set to NULL.
inline ExecutablePool::ExecutablePool(size_t n) : m_refCount(1)
inline ExecutablePool::ExecutablePool(size_t n) : m_refCount(1), m_destroy(false), m_gcNumber(0)
{
size_t allocSize = roundUpAllocationSize(n, JIT_ALLOCATOR_PAGE_SIZE);
if (allocSize == OVERSIZE_ALLOCATION) {

View File

@ -990,7 +990,7 @@ else
AC_MSG_RESULT([yes])
fi
MOZ_PATH_PROGS(PYTHON, $PYTHON python2.6 python2.5 python2.4 python)
MOZ_PATH_PROGS(PYTHON, $PYTHON python2.7 python2.6 python2.5 python)
if test -z "$PYTHON"; then
AC_MSG_ERROR([python was not found in \$PATH])
fi
@ -1904,13 +1904,13 @@ esac
dnl We require version 2.4 or newer of Python to build,
dnl and 2.5 or newer on Windows.
AC_MSG_CHECKING([for minimum required Python version >= $PYTHON_VERSION])
AC_MSG_CHECKING([for Python version >= $PYTHON_VERSION but not 3.x])
changequote(,)
$PYTHON -c "import sys; sys.exit(sys.version[:3] < sys.argv[1])" $PYTHON_VERSION
$PYTHON -c "import sys; sys.exit(sys.version[:3] < sys.argv[1] or sys.version[:2] != '2.')" $PYTHON_VERSION
_python_res=$?
changequote([,])
if test "$_python_res" != 0; then
AC_MSG_ERROR([Python $PYTHON_VERSION or higher is required.])
AC_MSG_ERROR([Python $PYTHON_VERSION or higher (but not Python 3.x) is required.])
fi
AC_MSG_RESULT([yes])

View File

@ -1292,7 +1292,10 @@ StringToInteger(JSContext* cx, JSString* string, IntegerType* result)
{
JS_STATIC_ASSERT(numeric_limits<IntegerType>::is_exact);
const jschar* cp = string->chars();
const jschar* cp = string->getChars(NULL);
if (!cp)
return false;
const jschar* end = cp + string->length();
if (cp == end)
return false;
@ -1780,9 +1783,10 @@ ImplicitConvert(JSContext* cx,
JSString* str = JSVAL_TO_STRING(val); \
if (str->length() != 1) \
return TypeError(cx, #name, val); \
\
result = str->chars()[0]; \
\
const jschar *chars = str->getChars(cx); \
if (!chars) \
return false; \
result = chars[0]; \
} else if (!jsvalToInteger(cx, val, &result)) { \
return TypeError(cx, #name, val); \
} \
@ -1824,8 +1828,10 @@ ImplicitConvert(JSContext* cx,
// which the caller assumes ownership of.
// TODO: Extend this so we can safely convert strings at other times also.
JSString* sourceString = JSVAL_TO_STRING(val);
const jschar* sourceChars = sourceString->chars();
size_t sourceLength = sourceString->length();
const jschar* sourceChars = sourceString->getChars(cx);
if (!sourceChars)
return false;
switch (CType::GetTypeCode(cx, baseType)) {
case TYPE_char:
@ -1879,8 +1885,10 @@ ImplicitConvert(JSContext* cx,
if (JSVAL_IS_STRING(val)) {
JSString* sourceString = JSVAL_TO_STRING(val);
const jschar* sourceChars = sourceString->chars();
size_t sourceLength = sourceString->length();
const jschar* sourceChars = sourceString->getChars(cx);
if (!sourceChars)
return false;
switch (CType::GetTypeCode(cx, baseType)) {
case TYPE_char:
@ -1989,21 +1997,18 @@ ImplicitConvert(JSContext* cx,
if (JSID_IS_VOID(id))
break;
js::AutoValueRooter fieldVal(cx);
JS_IdToValue(cx, id, fieldVal.jsval_addr());
if (!JSVAL_IS_STRING(fieldVal.jsval_value())) {
if (!JSID_IS_STRING(id)) {
JS_ReportError(cx, "property name is not a string");
return false;
}
const FieldInfo* field = StructType::LookupField(cx, targetType,
JSVAL_TO_STRING(fieldVal.jsval_value()));
JSFlatString *name = JSID_TO_FLAT_STRING(id);
const FieldInfo* field = StructType::LookupField(cx, targetType, name);
if (!field)
return false;
JSString* name = JSVAL_TO_STRING(fieldVal.jsval_value());
js::AutoValueRooter prop(cx);
if (!JS_GetUCProperty(cx, obj, name->chars(), name->length(), prop.jsval_addr()))
if (!JS_GetPropertyById(cx, obj, id, prop.jsval_addr()))
return false;
// Convert the field via ImplicitConvert().
@ -3567,8 +3572,10 @@ ArrayType::ConstructData(JSContext* cx,
// We were given a string. Size the array to the appropriate length,
// including space for the terminator.
JSString* sourceString = JSVAL_TO_STRING(argv[0]);
const jschar* sourceChars = sourceString->chars();
size_t sourceLength = sourceString->length();
const jschar* sourceChars = sourceString->getChars(cx);
if (!sourceChars)
return false;
switch (CType::GetTypeCode(cx, baseType)) {
case TYPE_char:
@ -3871,7 +3878,7 @@ ArrayType::AddressOfElement(JSContext* cx, uintN argc, jsval* vp)
// For a struct field descriptor 'val' of the form { name : type }, extract
// 'name' and 'type'.
static JSString*
static JSFlatString*
ExtractStructField(JSContext* cx, jsval val, JSObject** typeObj)
{
if (JSVAL_IS_PRIMITIVE(val)) {
@ -3885,23 +3892,21 @@ ExtractStructField(JSContext* cx, jsval val, JSObject** typeObj)
return NULL;
js::AutoObjectRooter iterroot(cx, iter);
jsid id;
if (!JS_NextProperty(cx, iter, &id))
jsid nameid;
if (!JS_NextProperty(cx, iter, &nameid))
return NULL;
if (JSID_IS_VOID(id)) {
if (JSID_IS_VOID(nameid)) {
JS_ReportError(cx, "struct field descriptors require a valid name and type");
return NULL;
}
js::AutoValueRooter nameVal(cx);
JS_IdToValue(cx, id, nameVal.jsval_addr());
if (!JSVAL_IS_STRING(nameVal.jsval_value())) {
if (!JSID_IS_STRING(nameid)) {
JS_ReportError(cx, "struct field descriptors require a valid name and type");
return NULL;
}
JSString* name = JSVAL_TO_STRING(nameVal.jsval_value());
// make sure we have one, and only one, property
jsid id;
if (!JS_NextProperty(cx, iter, &id))
return NULL;
if (!JSID_IS_VOID(id)) {
@ -3910,7 +3915,7 @@ ExtractStructField(JSContext* cx, jsval val, JSObject** typeObj)
}
js::AutoValueRooter propVal(cx);
if (!JS_GetUCProperty(cx, obj, name->chars(), name->length(), propVal.jsval_addr()))
if (!JS_GetPropertyById(cx, obj, nameid, propVal.jsval_addr()))
return NULL;
if (propVal.value().isPrimitive() ||
@ -3929,7 +3934,7 @@ ExtractStructField(JSContext* cx, jsval val, JSObject** typeObj)
return NULL;
}
return name;
return JSID_TO_FLAT_STRING(nameid);
}
// For a struct field with 'name' and 'type', add an element of the form
@ -3937,7 +3942,7 @@ ExtractStructField(JSContext* cx, jsval val, JSObject** typeObj)
static JSBool
AddFieldToArray(JSContext* cx,
jsval* element,
JSString* name,
JSFlatString* name,
JSObject* typeObj)
{
JSObject* fieldObj = JS_NewObject(cx, NULL, NULL, NULL);
@ -4048,7 +4053,7 @@ StructType::DefineInternal(JSContext* cx, JSObject* typeObj, JSObject* fieldsObj
return JS_FALSE;
JSObject* fieldType = NULL;
JSString* name = ExtractStructField(cx, item.jsval_value(), &fieldType);
JSFlatString* name = ExtractStructField(cx, item.jsval_value(), &fieldType);
if (!name)
return JS_FALSE;
fieldRootsArray[i] = OBJECT_TO_JSVAL(fieldType);
@ -4321,7 +4326,7 @@ StructType::GetFieldInfo(JSContext* cx, JSObject* obj)
}
const FieldInfo*
StructType::LookupField(JSContext* cx, JSObject* obj, JSString *name)
StructType::LookupField(JSContext* cx, JSObject* obj, JSFlatString *name)
{
JS_ASSERT(CType::IsCType(cx, obj));
JS_ASSERT(CType::GetTypeCode(cx, obj) == TYPE_struct);
@ -4417,7 +4422,7 @@ StructType::FieldGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp)
return JS_FALSE;
}
const FieldInfo* field = LookupField(cx, typeObj, JSID_TO_STRING(idval));
const FieldInfo* field = LookupField(cx, typeObj, JSID_TO_FLAT_STRING(idval));
if (!field)
return JS_FALSE;
@ -4439,7 +4444,7 @@ StructType::FieldSetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp)
return JS_FALSE;
}
const FieldInfo* field = LookupField(cx, typeObj, JSID_TO_STRING(idval));
const FieldInfo* field = LookupField(cx, typeObj, JSID_TO_FLAT_STRING(idval));
if (!field)
return JS_FALSE;
@ -4467,8 +4472,11 @@ StructType::AddressOfField(JSContext* cx, uintN argc, jsval* vp)
return JS_FALSE;
}
const FieldInfo* field = LookupField(cx, typeObj,
JSVAL_TO_STRING(JS_ARGV(cx, vp)[0]));
JSFlatString *str = JS_FlattenString(cx, JSVAL_TO_STRING(JS_ARGV(cx, vp)[0]));
if (!str)
return JS_FALSE;
const FieldInfo* field = LookupField(cx, typeObj, str);
if (!field)
return JS_FALSE;
@ -4611,18 +4619,23 @@ PrepareReturnType(JSContext* cx, jsval type)
return result;
}
static JS_ALWAYS_INLINE bool
IsEllipsis(jsval v)
static JS_ALWAYS_INLINE JSBool
IsEllipsis(JSContext* cx, jsval v, bool* isEllipsis)
{
*isEllipsis = false;
if (!JSVAL_IS_STRING(v))
return false;
return true;
JSString* str = JSVAL_TO_STRING(v);
if (str->length() != 3)
return true;
const jschar* chars = str->getChars(cx);
if (!chars)
return false;
const jschar* chars = str->chars(), dot('.');
return (chars[0] == dot &&
chars[1] == dot &&
chars[2] == dot);
jschar dot = '.';
*isEllipsis = (chars[0] == dot &&
chars[1] == dot &&
chars[2] == dot);
return true;
}
static JSBool
@ -4737,7 +4750,10 @@ NewFunctionInfo(JSContext* cx,
fninfo->mIsVariadic = false;
for (JSUint32 i = 0; i < argLength; ++i) {
if (IsEllipsis(argTypes[i])) {
bool isEllipsis;
if (!IsEllipsis(cx, argTypes[i], &isEllipsis))
return false;
if (isEllipsis) {
fninfo->mIsVariadic = true;
if (i < 1) {
JS_ReportError(cx, "\"...\" may not be the first and only parameter "

View File

@ -141,7 +141,10 @@ void
AppendString(Vector<jschar, N, AP> &v, JSString* str)
{
JS_ASSERT(str);
v.append(str->chars(), str->length());
const jschar *chars = str->getChars(NULL);
if (!chars)
return;
v.append(chars, str->length());
}
template <size_t N, class AP>
@ -154,8 +157,12 @@ AppendString(Vector<char, N, AP> &v, JSString* str)
if (!v.resize(vlen + alen))
return;
const jschar *chars = str->getChars(NULL);
if (!chars)
return;
for (size_t i = 0; i < alen; ++i)
v[i + vlen] = char(str->chars()[i]);
v[i + vlen] = char(chars[i]);
}
template <class T, size_t N, class AP, size_t ArrayLength>
@ -186,33 +193,15 @@ PrependString(Vector<jschar, N, AP> &v, JSString* str)
if (!v.resize(vlen + alen))
return;
const jschar *chars = str->getChars(NULL);
if (!chars)
return;
// Move vector data forward. This is safe since we've already resized.
memmove(v.begin() + alen, v.begin(), vlen * sizeof(jschar));
// Copy data to insert.
memcpy(v.begin(), str->chars(), alen * sizeof(jschar));
}
template <class T, size_t N, size_t M, class AP>
bool
StringsEqual(Vector<T, N, AP> &v, Vector<T, M, AP> &w)
{
if (v.length() != w.length())
return false;
return memcmp(v.begin(), w.begin(), v.length() * sizeof(T)) == 0;
}
template <size_t N, class AP>
bool
StringsEqual(Vector<jschar, N, AP> &v, JSString* str)
{
JS_ASSERT(str);
size_t length = str->length();
if (v.length() != length)
return false;
return memcmp(v.begin(), str->chars(), length * sizeof(jschar)) == 0;
memcpy(v.begin(), chars, alen * sizeof(jschar));
}
/*******************************************************************************
@ -274,7 +263,7 @@ struct FieldInfo
// Hash policy for FieldInfos.
struct FieldHashPolicy
{
typedef JSString* Key;
typedef JSFlatString* Key;
typedef Key Lookup;
static uint32 hash(const Lookup &l) {
@ -297,7 +286,7 @@ struct FieldHashPolicy
}
};
typedef HashMap<JSString*, FieldInfo, FieldHashPolicy, SystemAllocPolicy> FieldInfoHash;
typedef HashMap<JSFlatString*, FieldInfo, FieldHashPolicy, SystemAllocPolicy> FieldInfoHash;
// Descriptor of ABI, return type, argument types, and variadicity for a
// FunctionType.
@ -482,7 +471,7 @@ namespace StructType {
JSBool DefineInternal(JSContext* cx, JSObject* typeObj, JSObject* fieldsObj);
const FieldInfoHash* GetFieldInfo(JSContext* cx, JSObject* obj);
const FieldInfo* LookupField(JSContext* cx, JSObject* obj, JSString *name);
const FieldInfo* LookupField(JSContext* cx, JSObject* obj, JSFlatString *name);
JSObject* BuildFieldsArray(JSContext* cx, JSObject* obj);
ffi_type* BuildFFIType(JSContext* cx, JSObject* obj);
}

View File

@ -133,12 +133,13 @@ Library::Create(JSContext* cx, jsval path, JSCTypesCallbacks* callbacks)
}
PRLibSpec libSpec;
JSString* pathStr = JSVAL_TO_STRING(path);
JSFlatString* pathStr = JS_FlattenString(cx, JSVAL_TO_STRING(path));
if (!pathStr)
return NULL;
#ifdef XP_WIN
// On Windows, converting to native charset may corrupt path string.
// So, we have to use Unicode path directly.
const PRUnichar* pathChars = reinterpret_cast<const PRUnichar*>(
JS_GetStringCharsZ(cx, pathStr));
const PRUnichar* pathChars = JS_GetFlatStringChars(pathStr);
if (!pathChars)
return NULL;

View File

@ -0,0 +1,12 @@
function s(f) { this._m = f; }
function C() {
Object.defineProperty(this, "m", {set: s});
this.m = function () {};
}
var last = {};
for (var i = 0; i < 20; i++) {
var a = new C;
assertEq(a._m === last._m, false);
last = a;
}

View File

@ -0,0 +1,9 @@
for(var i = 0; i < RUNLOOP; i++) {
x = ''.charCodeAt(NaN);
}
for(var i = 0; i < RUNLOOP; i++) {
x = ''.charAt(NaN);
}
// Don't assert

View File

@ -0,0 +1,5 @@
for (var i = 0; i < RUNLOOP; i++) {
Math.abs(-2147483648)
}
// Don't assert

View File

@ -0,0 +1,11 @@
{
function a() {}
}
Math.floor(Math.d)
function c() {}
c()
for each(let b in [0, 0, 0, 0, 0, 0, 0, -2147483648]) {
print(Math.abs(b))
}
// Don't assert

View File

@ -0,0 +1,26 @@
// vim: set ts=4 sw=4 tw=99 et:
document = {
ready: function (x) {
this.exec = x;
}
};
var $ = function (x) {
return document;
};
(function ($) {
eval("(function(){\n" +
" var Private={};\n" +
" $(document).ready(function(){\n" +
" init()\n" +
" });\n" +
" function init(){\n" +
" $(Private)\n" +
" };\n" +
"})();");
})($);
document.exec();
// Don't crash or assert.

View File

@ -0,0 +1,24 @@
var global = 0;
Object.defineProperty(Object.prototype, 0, {set: function() { global++; }});
for (var x = 0; x < 20; ++x)
[1,2];
assertEq(global, 0);
Object.defineProperty(Object.prototype, 1, {set: function() { global++; }});
for (var x = 0; x < 20; ++x)
[1,2];
assertEq(global, 0);
Object.defineProperty(Object.prototype, "b", {set: function() { global++; }});
for (var x = 0; x < 20; ++x) {
var s = { a:0, b:1, 0: 2, 1: 3 };
}
assertEq(global, 0);
assertEq([42][0], 42);
assertEq([42].length, 1);

View File

@ -0,0 +1,5 @@
var x = Uint32Array();
for (var i = 0; i < 100; i++)
x[77] = x[77];
// Don't assert.

View File

@ -0,0 +1,10 @@
/* Bug 614653 - This test .2 seconds with the fix, 20 minutes without. */
for (var i = 0; i < 100; ++i) {
var arr = [];
var s = "abcdefghijklmnop";
for (var i = 0; i < 50000; ++i) {
s = "<" + s + ">";
arr.push(s);
}
gc();
}

View File

@ -0,0 +1,6 @@
// don't assert
for (a = 0; a < 9; ++a) {
M: for (let c in <x>></x>) {
break M
}
}

View File

@ -0,0 +1,19 @@
/* Touch/init early so global shape doesn't change in loop */
var SetOnIter = HOTLOOP - 1;
var x = 3;
var i = 0;
assertEq(true, true);
for (i = 0; i < SetOnIter + 10; ++i) {
x = 3;
setGlobalPropIf(i == SetOnIter, 'x', 'pretty');
assertEq(x == 'pretty', i == SetOnIter);
x = 3;
}
for (i = 0; i < SetOnIter + 10; ++i) {
x = 3;
defGlobalPropIf(i == SetOnIter, 'x', { value:'pretty' });
assertEq(x == 'pretty', i == SetOnIter);
x = 3;
}

View File

@ -0,0 +1,8 @@
function f() {
var a = [], i, N = HOTLOOP + 2;
for (i = 0; i < N; i++)
a[i] = {m: i, m: function() { return 0; }};
assertEq(a[N - 2].m === a[N - 1].m, false);
}
f();
f();

View File

@ -0,0 +1,15 @@
function f() {
var a = [], i, N = HOTLOOP + 2;
for (i = 0; i < N; i++) {
a[i] = {};
a[i].m = function() { return 0; };
a[i].m = function() { return 1; };
}
assertEq(a[N - 2].m === a[N - 1].m, false);
for (i = 0; i < N; i++) {
var f = a[i].m;
assertEq(f(), 1);
}
}
f();
f();

View File

@ -0,0 +1,12 @@
function f() {
var a = [], i, N = HOTLOOP + 2;
for (i = 0; i < N; i++)
a[i] = {m: function() { return 0; }, m: function() { return 1; }};
assertEq(a[N - 2].m === a[N - 1].m, false);
for (i = 0; i < N; i++) {
var f = a[i].m;
assertEq(f(), 1);
}
}
f();
f();

View File

@ -1,17 +1,10 @@
function f() {
var a = [{m: 0}, {m: 1}, {m: 2}, {m: 3}, {m: 4}];
var b = [{}, {}, {}, {}, {}];
for (var i = 0; i < a.length; i++) {
a[i].m = function() { return 0; };
b[i].m = function() { return 1; };
}
assertEq(false, a[0].m === a[1].m);
assertEq(false, a[0].m === a[2].m);
assertEq(false, a[0].m === a[3].m);
assertEq(false, a[0].m === a[4].m);
assertEq(false, b[0].m === b[1].m);
assertEq(false, b[0].m === b[2].m);
assertEq(false, b[0].m === b[3].m);
assertEq(false, b[0].m === b[4].m);
var a = [], i, N = HOTLOOP + 2;
for (i = 0; i < N; i++)
a[i] = {m: i};
for (i = 0; i < N; i++)
a[i].m = function() { return 0; };
assertEq(a[N - 2].m === a[N - 1].m, false);
}
f();
f();

View File

@ -0,0 +1,9 @@
function f() {
var MAX_HEIGHT = 64;
var obj = {};
for (var i = 0; i < MAX_HEIGHT; i++)
obj['a' + i] = i;
obj.m = function () { return 0; };
}
f();
f();

View File

@ -115,7 +115,7 @@ TypeIdStringImpl(jsid id)
static char bufs[4][100];
static unsigned which = 0;
which = (which + 1) & 3;
PutEscapedString(bufs[which], 100, JSID_TO_STRING(id), 0);
PutEscapedString(bufs[which], 100, JSID_TO_FLAT_STRING(id), 0);
return bufs[which];
}
@ -634,6 +634,9 @@ Script::analyze(JSContext *cx)
if (forwardCatch)
code->inTryBlock = true;
if (untrap.trap)
code->safePoint = true;
unsigned stackDepth = code->stackDepth;
uint32 *defineArray = code->defineArray;
unsigned defineCount = code->defineCount;
@ -693,8 +696,10 @@ Script::analyze(JSContext *cx)
bool newArray = (op == JSOP_NEWARRAY) || (op == JSOP_NEWINIT && pc[1] == JSProto_Array);
types::TypeObject *object;
if (initializerStack && initializerStack->initObject &&
initializerStack->initArray == newArray) {
if (!script->compileAndGo) {
object = NULL;
} else if (initializerStack && initializerStack->initObject &&
initializerStack->initArray == newArray) {
object = initializerStack->initObject;
if (newArray)
code->initArray = object;
@ -762,6 +767,7 @@ Script::analyze(JSContext *cx)
return;
}
getCode(defaultOffset).switchTarget = true;
getCode(defaultOffset).safePoint = true;
for (jsint i = low; i <= high; i++) {
unsigned targetOffset = offset + GetJumpOffset(pc, pc2);
@ -772,6 +778,7 @@ Script::analyze(JSContext *cx)
}
}
getCode(targetOffset).switchTarget = true;
getCode(targetOffset).safePoint = true;
pc2 += jmplen;
}
break;
@ -791,6 +798,7 @@ Script::analyze(JSContext *cx)
return;
}
getCode(defaultOffset).switchTarget = true;
getCode(defaultOffset).safePoint = true;
while (npairs) {
pc2 += INDEX_LEN;
@ -800,6 +808,7 @@ Script::analyze(JSContext *cx)
return;
}
getCode(targetOffset).switchTarget = true;
getCode(targetOffset).safePoint = true;
pc2 += jmplen;
npairs--;
}
@ -830,6 +839,7 @@ Script::analyze(JSContext *cx)
return;
}
getCode(catchOffset).exceptionEntry = true;
getCode(catchOffset).safePoint = true;
}
}
}

View File

@ -82,6 +82,9 @@ struct Bytecode
/* Whether this is in a try block. */
bool inTryBlock : 1;
/* Method JIT safe point. */
bool safePoint : 1;
/*
* For type inference, whether this bytecode needs to have its effects monitored dynamically.
* This is limited to property/name sets and calls.

View File

@ -76,6 +76,7 @@ CPPSRCS = \
testUTF8.cpp \
testVersion.cpp \
testXDR.cpp \
testCustomIterator.cpp \
$(NULL)
DEFINES += -DEXPORT_JS_API

View File

@ -58,3 +58,23 @@ bool checkObjectFields(JSObject *savedCopy, JSObject *obj)
}
END_TEST(testConservativeGC)
BEGIN_TEST(testDerivedValues)
{
JSString *str = JS_NewStringCopyZ(cx, "once upon a midnight dreary");
js::Anchor<JSString *> str_anchor(str);
static const jschar expected[] = { 'o', 'n', 'c', 'e' };
const jschar *ch = JS_GetStringCharsZ(cx, str);
str = NULL;
/* Do a lot of allocation and collection. */
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 1000; j++)
JS_NewStringCopyZ(cx, "as I pondered weak and weary");
JS_GC(cx);
}
CHECK(!memcmp(ch, expected, sizeof(expected)));
return true;
}
END_TEST(testDerivedValues)

View File

@ -0,0 +1,81 @@
#include "tests.h"
#include "jsvalue.h"
int count = 0;
static JSBool
IterNext(JSContext *cx, uintN argc, jsval *vp)
{
if (count++ == 100)
return JS_ThrowStopIteration(cx);
JS_SET_RVAL(cx, vp, INT_TO_JSVAL(count));
return true;
}
static JSObject *
IterHook(JSContext *cx, JSObject *obj, JSBool keysonly)
{
JSObject *iterObj = JS_NewObject(cx, NULL, NULL, NULL);
if (!iterObj)
return NULL;
if (!JS_DefineFunction(cx, iterObj, "next", IterNext, 0, 0))
return NULL;
return iterObj;
}
js::Class HasCustomIterClass = {
"HasCustomIter",
0,
js::PropertyStub,
js::PropertyStub,
js::PropertyStub,
js::PropertyStub,
js::EnumerateStub,
js::ResolveStub,
js::ConvertStub,
NULL,
NULL, /* reserved0 */
NULL, /* checkAccess */
NULL, /* call */
NULL, /* construct */
NULL, /* xdrObject */
NULL, /* hasInstance */
NULL, /* mark */
{
NULL,
NULL,
NULL,
IterHook,
NULL
}
};
JSBool
IterClassConstructor(JSContext *cx, uintN argc, jsval *vp)
{
JSObject *obj = JS_NewObjectForConstructor(cx, vp);
if (!obj)
return false;
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
return true;
}
BEGIN_TEST(testCustomIterator_bug612523)
{
CHECK(JS_InitClass(cx, JS_GetGlobalObject(cx), NULL, Jsvalify(&HasCustomIterClass),
IterClassConstructor, 0, NULL, NULL, NULL, NULL));
jsval result;
EVAL("var o = new HasCustomIter(); \n"
"var j = 0; \n"
"for (var i in o) { ++j; }; \n"
"j;", &result);
CHECK(JSVAL_IS_INT(result));
CHECK(JSVAL_TO_INT(result) == 100);
CHECK(count == 101);
return true;
}
END_TEST(testCustomIterator_bug612523)

View File

@ -10,11 +10,7 @@
static JSBool
stringToId(JSContext *cx, const char *s, jsid *idp)
{
char *buf = JS_strdup(cx, s);
if (!buf)
return false;
JSString *str = JS_NewString(cx, buf, strlen(s));
JSString *str = JS_NewStringCopyZ(cx, s);
if (!str)
return false;

View File

@ -12,28 +12,28 @@ BEGIN_TEST(testIntString_bug515273)
EVAL("'1';", v.addr());
JSString *str = JSVAL_TO_STRING(v.value());
CHECK(JSString::isStatic(str));
CHECK(JS_MatchStringAndAscii(str, "1"));
CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "1"));
EVAL("'42';", v.addr());
str = JSVAL_TO_STRING(v.value());
CHECK(JSString::isStatic(str));
CHECK(JS_MatchStringAndAscii(str, "42"));
CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "42"));
EVAL("'111';", v.addr());
str = JSVAL_TO_STRING(v.value());
CHECK(JSString::isStatic(str));
CHECK(JS_MatchStringAndAscii(str, "111"));
CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "111"));
/* Test other types of static strings. */
EVAL("'a';", v.addr());
str = JSVAL_TO_STRING(v.value());
CHECK(JSString::isStatic(str));
CHECK(JS_MatchStringAndAscii(str, "a"));
CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "a"));
EVAL("'bc';", v.addr());
str = JSVAL_TO_STRING(v.value());
CHECK(JSString::isStatic(str));
CHECK(JS_MatchStringAndAscii(str, "bc"));
CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "bc"));
return true;
}

View File

@ -41,7 +41,10 @@ document_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **
return false;
if (JSVAL_IS_STRING(v.value())) {
JSString *str = JSVAL_TO_STRING(v.value());
if (JS_MatchStringAndAscii(str, "all") && !(flags & JSRESOLVE_DETECTING)) {
JSFlatString *flatStr = JS_FlattenString(cx, str);
if (!flatStr)
return false;
if (JS_FlatStringEqualsAscii(flatStr, "all") && !(flags & JSRESOLVE_DETECTING)) {
JSBool ok = JS_DefinePropertyById(cx, obj, id, JSVAL_TRUE, NULL, NULL, 0);
*objp = ok ? obj : NULL;
return ok;

View File

@ -16,7 +16,9 @@ BEGIN_TEST(testSameValue)
*/
jsval v1 = DOUBLE_TO_JSVAL(0.0);
jsval v2 = DOUBLE_TO_JSVAL(-0.0);
CHECK(!JS_SameValue(cx, v1, v2));
JSBool same;
CHECK(JS_SameValue(cx, v1, v2, &same));
CHECK(!same);
return true;
}
END_TEST(testSameValue)

View File

@ -62,7 +62,7 @@ BEGIN_TEST(testTrap_gc)
JS_GC(cx);
CHECK(JS_MatchStringAndAscii(trapClosure, trapClosureText));
CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(trapClosure), trapClosureText));
// execute
CHECK(JS_ExecuteScript(cx, global, script, v2.addr()));
@ -70,7 +70,7 @@ BEGIN_TEST(testTrap_gc)
JS_GC(cx);
CHECK(JS_MatchStringAndAscii(trapClosure, trapClosureText));
CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(trapClosure), trapClosureText));
return true;
}

View File

@ -95,36 +95,3 @@ BEGIN_TEST(testXDR_bug516827)
return true;
}
END_TEST(testXDR_bug516827)
BEGIN_TEST(testXDR_bug525481)
{
// get the empty script const singleton
JSScript *script = JSScript::emptyScript();
CHECK(script);
// freeze with junk after the empty script shorthand
JSXDRState *w = JS_XDRNewMem(cx, JSXDR_ENCODE);
CHECK(w);
CHECK(JS_XDRScript(w, &script));
const char s[] = "don't decode me; don't encode me";
char b[sizeof s - 1];
memcpy(b, s, sizeof b);
CHECK(JS_XDRBytes(w, b, sizeof b));
uint32 nbytes;
void *p = JS_XDRMemGetData(w, &nbytes);
CHECK(p);
void *frozen = JS_malloc(cx, nbytes);
CHECK(frozen);
memcpy(frozen, p, nbytes);
JS_XDRDestroy(w);
// thaw, reading junk if bug 525481 is not patched
script = NULL;
JSXDRState *r = JS_XDRNewMem(cx, JSXDR_DECODE);
JS_XDRMemSetData(r, frozen, nbytes);
CHECK(JS_XDRScript(r, &script));
JS_DestroyScript(cx, script);
JS_XDRDestroy(r); // this frees `frozen`
return true;
}
END_TEST(testXDR_bug525481)

View File

@ -192,7 +192,8 @@ class JSAPITest
bool checkSame(jsval actual, jsval expected,
const char *actualExpr, const char *expectedExpr,
const char *filename, int lineno) {
return JS_SameValue(cx, actual, expected) ||
JSBool same;
return (JS_SameValue(cx, actual, expected, &same) && same) ||
fail(JSAPITestString("CHECK_SAME failed: expected JS_SameValue(cx, ") +
actualExpr + ", " + expectedExpr + "), got !JS_SameValue(cx, " +
toSource(actual) + ", " + toSource(expected) + ")", filename, lineno);

View File

@ -113,6 +113,16 @@ using namespace js;
using namespace js::gc;
using namespace js::types;
static JSClass dummy_class = {
"jdummy",
JSCLASS_GLOBAL_FLAGS,
JS_PropertyStub, JS_PropertyStub,
JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub,
JS_ConvertStub, NULL,
JSCLASS_NO_OPTIONAL_MEMBERS
};
class AutoVersionAPI
{
JSContext * const cx;
@ -573,17 +583,17 @@ JS_GetTypeName(JSContext *cx, JSType type)
}
JS_PUBLIC_API(JSBool)
JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2)
JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2, JSBool *equal)
{
assertSameCompartment(cx, v1, v2);
return StrictlyEqual(cx, Valueify(v1), Valueify(v2));
return StrictlyEqual(cx, Valueify(v1), Valueify(v2), equal);
}
JS_PUBLIC_API(JSBool)
JS_SameValue(JSContext *cx, jsval v1, jsval v2)
JS_SameValue(JSContext *cx, jsval v1, jsval v2, JSBool *same)
{
assertSameCompartment(cx, v1, v2);
return SameValue(Valueify(v1), Valueify(v2), cx);
return SameValue(cx, Valueify(v1), Valueify(v2), same);
}
/************************************************************************/
@ -1171,6 +1181,22 @@ JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target)
return reinterpret_cast<JSCrossCompartmentCall *>(call);
}
JS_PUBLIC_API(JSCrossCompartmentCall *)
JS_EnterCrossCompartmentCallScript(JSContext *cx, JSScript *target)
{
CHECK_REQUEST(cx);
JS_ASSERT(target);
JSObject *scriptObject = target->u.object;
if (!scriptObject) {
SwitchToCompartment sc(cx, target->compartment);
scriptObject = JS_NewGlobalObject(cx, &dummy_class);
if (!scriptObject)
return NULL;
}
return JS_EnterCrossCompartmentCall(cx, scriptObject);
}
JS_PUBLIC_API(void)
JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call)
{
@ -1192,6 +1218,18 @@ JSAutoEnterCompartment::enter(JSContext *cx, JSObject *target)
return call != NULL;
}
bool
JSAutoEnterCompartment::enter(JSContext *cx, JSScript *target)
{
JS_ASSERT(!call);
if (cx->compartment == target->compartment) {
call = reinterpret_cast<JSCrossCompartmentCall*>(1);
return true;
}
call = JS_EnterCrossCompartmentCallScript(cx, target);
return call != NULL;
}
void
JSAutoEnterCompartment::enterAndIgnoreErrors(JSContext *cx, JSObject *target)
{
@ -2201,8 +2239,14 @@ JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, ui
}
case JSTRACE_STRING:
PutEscapedString(buf, bufsize, (JSString *)thing, 0);
{
JSString *str = (JSString *)thing;
if (str->isLinear())
PutEscapedString(buf, bufsize, str->assertIsLinear(), 0);
else
JS_snprintf(buf, bufsize, "<rope: length %d>", (int)str->length());
break;
}
#if JS_HAS_XML_SUPPORT
case JSTRACE_XML:
@ -3324,6 +3368,7 @@ DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, const Value &value,
return !!js_DefineNativeProperty(cx, obj, id, value, getter, setter,
attrs, flags, tinyid, NULL);
}
return obj->defineProperty(cx, id, value, getter, setter, attrs);
}
@ -3794,6 +3839,8 @@ JS_SetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj, id);
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
cx->addTypePropertyId(obj->getType(), id, Valueify(*vp));
return obj->setProperty(cx, id, Valueify(vp), false);
}
@ -4069,7 +4116,13 @@ JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector)
CHECK_REQUEST(cx);
/* NB: jsuint cast does ToUint32. */
assertSameCompartment(cx, JSValueArray(vector, vector ? (jsuint)length : 0));
return js_NewArrayObject(cx, (jsuint)length, Valueify(vector));
#ifdef DEBUG
for (int i = 0; i < length; i++)
JS_ASSERT(!Valueify(vector[i]).isMagic(JS_ARRAY_HOLE));
#endif
return NewDenseCopiedArray(cx, (jsuint)length, Valueify(vector));
}
JS_PUBLIC_API(JSBool)
@ -4853,7 +4906,6 @@ JS_NewScriptObject(JSContext *cx, JSScript *script)
* described in the comment for JSScript::u.object.
*/
JS_ASSERT(script->u.object);
JS_ASSERT(script != JSScript::emptyScript());
return script->u.object;
}
@ -5070,7 +5122,7 @@ JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval)
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj, script);
/* This should receive only scripts handed out via the JSAPI. */
JS_ASSERT(script == JSScript::emptyScript() || script->u.object);
JS_ASSERT(script->u.object);
ok = Execute(cx, obj, script, NULL, 0, Valueify(rval));
LAST_FRAME_CHECKS(cx, ok);
return ok;
@ -5353,42 +5405,11 @@ JS_RestoreFrameChain(JSContext *cx, JSStackFrame *fp)
}
/************************************************************************/
JS_PUBLIC_API(JSString *)
JS_NewString(JSContext *cx, char *bytes, size_t nbytes)
{
size_t length = nbytes;
jschar *chars;
JSString *str;
CHECK_REQUEST(cx);
/* Make a UTF-16 vector from the 8-bit char codes in bytes. */
chars = js_InflateString(cx, bytes, &length);
if (!chars)
return NULL;
/* Free chars (but not bytes, which caller frees on error) if we fail. */
str = js_NewString(cx, chars, length);
if (!str)
cx->free(chars);
return str;
}
JS_PUBLIC_API(JSString *)
JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
{
jschar *js;
JSString *str;
CHECK_REQUEST(cx);
js = js_InflateString(cx, s, &n);
if (!js)
return NULL;
str = js_NewString(cx, js, n);
if (!str)
cx->free(js);
return str;
return js_NewStringCopyN(cx, s, n);
}
JS_PUBLIC_API(JSString *)
@ -5417,6 +5438,16 @@ JS_StringHasBeenInterned(JSString *str)
return str->isAtomized();
}
JS_PUBLIC_API(JSString *)
JS_InternJSString(JSContext *cx, JSString *str)
{
CHECK_REQUEST(cx);
JSAtom *atom = js_AtomizeString(cx, str, 0);
if (!atom)
return NULL;
return ATOM_TO_STRING(atom);
}
JS_PUBLIC_API(JSString *)
JS_InternString(JSContext *cx, const char *s)
{
@ -5470,45 +5501,6 @@ JS_InternUCString(JSContext *cx, const jschar *s)
return JS_InternUCStringN(cx, s, js_strlen(s));
}
JS_PUBLIC_API(jschar *)
JS_GetStringChars(JSString *str)
{
size_t n, size;
jschar *s;
str->ensureNotRope();
/*
* API botch: we have no cx to report out-of-memory when undepending
* strings, so we replace JSString::undepend with explicit malloc call and
* ignore its errors.
*
* If we fail to convert a dependent string into an independent one, our
* caller will not be guaranteed a \u0000 terminator as a backstop. This
* may break some clients who already misbehave on embedded NULs.
*
* The gain of dependent strings, which cure quadratic and cubic growth
* rate bugs in string concatenation, is worth this slight loss in API
* compatibility.
*/
if (str->isDependent()) {
n = str->dependentLength();
size = (n + 1) * sizeof(jschar);
s = (jschar *) js_malloc(size);
if (s) {
memcpy(s, str->dependentChars(), n * sizeof *s);
s[n] = 0;
str->initFlat(s, n);
} else {
s = str->dependentChars();
}
} else {
str->flatClearExtensible();
s = str->flatChars();
}
return s;
}
JS_PUBLIC_API(size_t)
JS_GetStringLength(JSString *str)
{
@ -5516,41 +5508,102 @@ JS_GetStringLength(JSString *str)
}
JS_PUBLIC_API(const jschar *)
JS_GetStringCharsAndLength(JSString *str, size_t *lengthp)
JS_GetStringCharsZ(JSContext *cx, JSString *str)
{
*lengthp = str->length();
return str->chars();
CHECK_REQUEST(cx);
assertSameCompartment(cx, str);
return str->getCharsZ(cx);
}
JS_PUBLIC_API(const jschar *)
JS_GetStringCharsZ(JSContext *cx, JSString *str)
JS_GetStringCharsZAndLength(JSContext *cx, JSString *str, size_t *plength)
{
CHECK_REQUEST(cx);
assertSameCompartment(cx, str);
return str->undepend(cx);
*plength = str->length();
return str->getCharsZ(cx);
}
JS_PUBLIC_API(intN)
JS_CompareStrings(JSString *str1, JSString *str2)
JS_PUBLIC_API(const jschar *)
JS_GetStringCharsAndLength(JSContext *cx, JSString *str, size_t *plength)
{
return js_CompareStrings(str1, str2);
CHECK_REQUEST(cx);
assertSameCompartment(cx, str);
*plength = str->length();
return str->getChars(cx);
}
JS_PUBLIC_API(const jschar *)
JS_GetInternedStringChars(JSString *str)
{
JS_ASSERT(str->isAtomized());
return str->flatChars();
}
JS_PUBLIC_API(const jschar *)
JS_GetInternedStringCharsAndLength(JSString *str, size_t *plength)
{
JS_ASSERT(str->isAtomized());
*plength = str->flatLength();
return str->flatChars();
}
extern JS_PUBLIC_API(JSFlatString *)
JS_FlattenString(JSContext *cx, JSString *str)
{
CHECK_REQUEST(cx);
assertSameCompartment(cx, str);
return str->getCharsZ(cx) ? (JSFlatString *)str : NULL;
}
extern JS_PUBLIC_API(const jschar *)
JS_GetFlatStringChars(JSFlatString *str)
{
return str->chars();
}
JS_PUBLIC_API(JSBool)
JS_MatchStringAndAscii(JSString *str, const char *asciiBytes)
JS_CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32 *result)
{
return MatchStringAndAscii(str, asciiBytes);
return CompareStrings(cx, str1, str2, result);
}
JS_PUBLIC_API(JSBool)
JS_StringEqualsAscii(JSContext *cx, JSString *str, const char *asciiBytes, JSBool *match)
{
JSLinearString *linearStr = str->ensureLinear(cx);
if (!linearStr)
return false;
*match = StringEqualsAscii(linearStr, asciiBytes);
return true;
}
JS_PUBLIC_API(JSBool)
JS_FlatStringEqualsAscii(JSFlatString *str, const char *asciiBytes)
{
return StringEqualsAscii(str, asciiBytes);
}
JS_PUBLIC_API(size_t)
JS_PutEscapedString(char *buffer, size_t size, JSString *str, char quote)
JS_PutEscapedFlatString(char *buffer, size_t size, JSFlatString *str, char quote)
{
return PutEscapedString(buffer, size, str, quote);
}
JS_PUBLIC_API(size_t)
JS_PutEscapedString(JSContext *cx, char *buffer, size_t size, JSString *str, char quote)
{
JSLinearString *linearStr = str->ensureLinear(cx);
if (!linearStr)
return size_t(-1);
return PutEscapedString(buffer, size, linearStr, quote);
}
JS_PUBLIC_API(JSBool)
JS_FileEscapedString(FILE *fp, JSString *str, char quote)
{
return FileEscapedString(fp, str, quote);
JSLinearString *linearStr = str->ensureLinear(NULL);
return linearStr && FileEscapedString(fp, linearStr, quote);
}
JS_PUBLIC_API(JSString *)
@ -5578,7 +5631,7 @@ JS_PUBLIC_API(const jschar *)
JS_UndependString(JSContext *cx, JSString *str)
{
CHECK_REQUEST(cx);
return str->undepend(cx);
return str->getCharsZ(cx);
}
JS_PUBLIC_API(JSBool)
@ -5614,13 +5667,19 @@ JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst, size_
JS_PUBLIC_API(char *)
JS_EncodeString(JSContext *cx, JSString *str)
{
return js_DeflateString(cx, str->chars(), str->length());
const jschar *chars = str->getChars(cx);
if (!chars)
return NULL;
return js_DeflateString(cx, chars, str->length());
}
JS_PUBLIC_API(size_t)
JS_GetStringEncodingLength(JSContext *cx, JSString *str)
{
return js_GetDeflatedStringLength(cx, str->chars(), str->length());
const jschar *chars = str->getChars(cx);
if (!chars)
return size_t(-1);
return js_GetDeflatedStringLength(cx, chars, str->length());
}
JS_PUBLIC_API(size_t)
@ -5632,12 +5691,15 @@ JS_EncodeStringToBuffer(JSString *str, char *buffer, size_t length)
* error.
*/
size_t writtenLength = length;
if (js_DeflateStringToBuffer(NULL, str->chars(), str->length(), buffer, &writtenLength)) {
const jschar *chars = str->getChars(NULL);
if (!chars)
return size_t(-1);
if (js_DeflateStringToBuffer(NULL, chars, str->length(), buffer, &writtenLength)) {
JS_ASSERT(writtenLength <= length);
return writtenLength;
}
JS_ASSERT(writtenLength <= length);
size_t necessaryLength = js_GetDeflatedStringLength(NULL, str->chars(), str->length());
size_t necessaryLength = js_GetDeflatedStringLength(NULL, chars, str->length());
if (necessaryLength == size_t(-1))
return size_t(-1);
if (writtenLength != length) {

View File

@ -702,10 +702,10 @@ extern JS_PUBLIC_API(const char *)
JS_GetTypeName(JSContext *cx, JSType type);
extern JS_PUBLIC_API(JSBool)
JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2);
JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2, JSBool *equal);
extern JS_PUBLIC_API(JSBool)
JS_SameValue(JSContext *cx, jsval v1, jsval v2);
JS_SameValue(JSContext *cx, jsval v1, jsval v2, JSBool *same);
/************************************************************************/
@ -979,6 +979,9 @@ JS_SetWrapObjectCallbacks(JSRuntime *rt,
extern JS_PUBLIC_API(JSCrossCompartmentCall *)
JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target);
extern JS_PUBLIC_API(JSCrossCompartmentCall *)
JS_EnterCrossCompartmentCallScript(JSContext *cx, JSScript *target);
extern JS_PUBLIC_API(void)
JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call);
@ -1009,6 +1012,8 @@ class JS_PUBLIC_API(JSAutoEnterCompartment)
bool enter(JSContext *cx, JSObject *target);
bool enter(JSContext *cx, JSScript *target);
void enterAndIgnoreErrors(JSContext *cx, JSObject *target);
bool entered() const { return call != NULL; }
@ -1269,6 +1274,167 @@ js_AddGCThingRootRT(JSRuntime *rt, void **rp, const char *name);
extern JS_FRIEND_API(JSBool)
js_RemoveRoot(JSRuntime *rt, void *rp);
#ifdef __cplusplus
JS_END_EXTERN_C
namespace js {
/*
* Protecting non-jsval, non-JSObject *, non-JSString * values from collection
*
* Most of the time, the garbage collector's conservative stack scanner works
* behind the scenes, finding all live values and protecting them from being
* collected. However, when JSAPI client code obtains a pointer to data the
* scanner does not know about, owned by an object the scanner does know about,
* Care Must Be Taken.
*
* The scanner recognizes only a select set of types: pointers to JSObjects and
* similar things (JSFunctions, and so on), pointers to JSStrings, and jsvals.
* So while the scanner finds all live |JSString| pointers, it does not notice
* |jschar| pointers.
*
* So suppose we have:
*
* void f(JSString *str) {
* const jschar *ch = JS_GetStringCharsZ(str);
* ... do stuff with ch, but no uses of str ...;
* }
*
* After the call to |JS_GetStringCharsZ|, there are no further uses of
* |str|, which means that the compiler is within its rights to not store
* it anywhere. But because the stack scanner will not notice |ch|, there
* is no longer any live value in this frame that would keep the string
* alive. If |str| is the last reference to that |JSString|, and the
* collector runs while we are using |ch|, the string's array of |jschar|s
* may be freed out from under us.
*
* Note that there is only an issue when 1) we extract a thing X the scanner
* doesn't recognize from 2) a thing Y the scanner does recognize, and 3) if Y
* gets garbage-collected, then X gets freed. If we have code like this:
*
* void g(JSObject *obj) {
* jsval x;
* JS_GetProperty(obj, "x", &x);
* ... do stuff with x ...
* }
*
* there's no problem, because the value we've extracted, x, is a jsval, a
* type that the conservative scanner recognizes.
*
* Conservative GC frees us from the obligation to explicitly root the types it
* knows about, but when we work with derived values like |ch|, we must root
* their owners, as the derived value alone won't keep them alive.
*
* A js::Anchor is a kind of GC root that allows us to keep the owners of
* derived values like |ch| alive throughout the Anchor's lifetime. We could
* fix the above code as follows:
*
* void f(JSString *str) {
* js::Anchor<JSString *> a_str(str);
* const jschar *ch = JS_GetStringCharsZ(str);
* ... do stuff with ch, but no uses of str ...;
* }
*
* This simply ensures that |str| will be live until |a_str| goes out of scope.
* As long as we don't retain a pointer to the string's characters for longer
* than that, we have avoided all garbage collection hazards.
*/
template<typename T> class AnchorPermitted;
template<> class AnchorPermitted<JSObject *> { };
template<> class AnchorPermitted<const JSObject *> { };
template<> class AnchorPermitted<JSFunction *> { };
template<> class AnchorPermitted<const JSFunction *> { };
template<> class AnchorPermitted<JSString *> { };
template<> class AnchorPermitted<const JSString *> { };
template<> class AnchorPermitted<jsval> { };
template<typename T>
class Anchor: AnchorPermitted<T> {
public:
Anchor() { }
explicit Anchor(T t) { hold = t; }
inline ~Anchor();
T &get() { return hold; }
void set(const T &t) { hold = t; }
void clear() { hold = 0; }
private:
T hold;
/* Anchors should not be assigned or passed to functions. */
Anchor(const Anchor &);
const Anchor &operator=(const Anchor &);
};
#ifdef __GNUC__
template<typename T>
inline Anchor<T>::~Anchor() {
/*
* No code is generated for this. But because this is marked 'volatile', G++ will
* assume it has important side-effects, and won't delete it. (G++ never looks at
* the actual text and notices it's empty.) And because we have passed |hold| to
* it, GCC will keep |hold| alive until this point.
*
* The "memory" clobber operand ensures that G++ will not move prior memory
* accesses after the asm --- it's a barrier. Unfortunately, it also means that
* G++ will assume that all memory has changed after the asm, as it would for a
* call to an unknown function. I don't know of a way to avoid that consequence.
*/
asm volatile("":: "g" (hold) : "memory");
}
#else
template<typename T>
inline Anchor<T>::~Anchor() {
/*
* An adequate portable substitute, for non-structure types.
*
* The compiler promises that, by the end of an expression statement, the
* last-stored value to a volatile object is the same as it would be in an
* unoptimized, direct implementation (the "abstract machine" whose behavior the
* language spec describes). However, the compiler is still free to reorder
* non-volatile accesses across this store --- which is what we must prevent. So
* assigning the held value to a volatile variable, as we do here, is not enough.
*
* In our case, however, garbage collection only occurs at function calls, so it
* is sufficient to ensure that the destructor's store isn't moved earlier across
* any function calls that could collect. It is hard to imagine the compiler
* analyzing the program so thoroughly that it could prove that such motion was
* safe. In practice, compilers treat calls to the collector as opaque operations
* --- in particular, as operations which could access volatile variables, across
* which this destructor must not be moved.
*
* ("Objection, your honor! *Alleged* killer whale!")
*
* The disadvantage of this approach is that it does generate code for the store.
* We do need to use Anchors in some cases where cycles are tight.
*/
volatile T sink;
sink = hold;
}
#ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES
/*
* The default assignment operator for |struct C| has the signature:
*
* C& C::operator=(const C&)
*
* And in particular requires implicit conversion of |this| to type |C| for the return
* value. But |volatile C| cannot thus be converted to |C|, so just doing |sink = hold| as
* in the non-specialized version would fail to compile. Do the assignment on asBits
* instead, since I don't think we want to give jsval_layout an assignment operator
* returning |volatile jsval_layout|.
*/
template<>
inline Anchor<jsval>::~Anchor() {
volatile jsval sink;
sink.asBits = hold.asBits;
}
#endif
#endif
} /* namespace js */
JS_BEGIN_EXTERN_C
#endif
/*
* This symbol may be used by embedders to detect the change from the old
* JS_AddRoot(JSContext *, void *) APIs to the new ones above.
@ -2891,21 +3057,21 @@ JS_RestoreFrameChain(JSContext *cx, JSStackFrame *fp);
/*
* Strings.
*
* NB: JS_NewString takes ownership of bytes on success, avoiding a copy; but
* on error (signified by null return), it leaves bytes owned by the caller.
* So the caller must free bytes in the error case, if it has no use for them.
* In contrast, all the JS_New*StringCopy* functions do not take ownership of
* the character memory passed to them -- they copy it.
* NB: JS_NewUCString takes ownership of bytes on success, avoiding a copy;
* but on error (signified by null return), it leaves chars owned by the
* caller. So the caller must free bytes in the error case, if it has no use
* for them. In contrast, all the JS_New*StringCopy* functions do not take
* ownership of the character memory passed to them -- they copy it.
*/
extern JS_PUBLIC_API(JSString *)
JS_NewString(JSContext *cx, char *bytes, size_t length);
extern JS_PUBLIC_API(JSString *)
JS_NewStringCopyN(JSContext *cx, const char *s, size_t n);
extern JS_PUBLIC_API(JSString *)
JS_NewStringCopyZ(JSContext *cx, const char *s);
extern JS_PUBLIC_API(JSString *)
JS_InternJSString(JSContext *cx, JSString *str);
extern JS_PUBLIC_API(JSString *)
JS_InternString(JSContext *cx, const char *s);
@ -2924,36 +3090,106 @@ JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length);
extern JS_PUBLIC_API(JSString *)
JS_InternUCString(JSContext *cx, const jschar *s);
extern JS_PUBLIC_API(JSBool)
JS_CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32 *result);
extern JS_PUBLIC_API(JSBool)
JS_StringEqualsAscii(JSContext *cx, JSString *str, const char *asciiBytes, JSBool *match);
extern JS_PUBLIC_API(size_t)
JS_PutEscapedString(JSContext *cx, char *buffer, size_t size, JSString *str, char quote);
extern JS_PUBLIC_API(JSBool)
JS_FileEscapedString(FILE *fp, JSString *str, char quote);
/*
* Deprecated. Use JS_GetStringCharsZ() instead.
* Extracting string characters and length.
*
* While getting the length of a string is infallible, getting the chars can
* fail. As indicated by the lack of a JSContext parameter, there are two
* special cases where getting the chars is infallible:
*
* The first case is interned strings, i.e., strings from JS_InternString or
* JSID_TO_STRING(id), using JS_GetInternedStringChars*.
*
* The second case is "flat" strings that have been explicitly prepared in a
* fallible context by JS_FlattenString. To catch errors, a separate opaque
* JSFlatString type is returned by JS_FlattenString and expected by
* JS_GetFlatStringChars. Note, though, that this is purely a syntactic
* distinction: the input and output of JS_FlattenString are the same actual
* GC-thing so only one needs to be rooted. If a JSString is known to be flat,
* JS_ASSERT_STRING_IS_FLAT can be used to make a debug-checked cast. Example:
*
* // in a fallible context
* JSFlatString *fstr = JS_FlattenString(cx, str);
* if (!fstr)
* return JS_FALSE;
* JS_ASSERT(fstr == JS_ASSERT_STRING_IS_FLAT(str));
*
* // in an infallible context, for the same 'str'
* const jschar *chars = JS_GetFlatStringChars(fstr)
* JS_ASSERT(chars);
*
* The CharsZ APIs guarantee that the returned array has a null character at
* chars[length]. This can require additional copying so clients should prefer
* APIs without CharsZ if possible. The infallible functions also return
* null-terminated arrays. (There is no additional cost or non-Z alternative
* for the infallible functions, so 'Z' is left out of the identifier.)
*/
extern JS_PUBLIC_API(jschar *)
JS_GetStringChars(JSString *str);
extern JS_PUBLIC_API(size_t)
JS_GetStringLength(JSString *str);
/*
* Return the char array and length for this string. The array is not
* null-terminated.
*/
extern JS_PUBLIC_API(const jschar *)
JS_GetStringCharsAndLength(JSString *str, size_t *lengthp);
JS_GetStringCharsAndLength(JSContext *cx, JSString *str, size_t *length);
extern JS_PUBLIC_API(const jschar *)
JS_GetInternedStringChars(JSString *str);
extern JS_PUBLIC_API(const jschar *)
JS_GetInternedStringCharsAndLength(JSString *str, size_t *length);
extern JS_PUBLIC_API(const jschar *)
JS_GetStringCharsZ(JSContext *cx, JSString *str);
extern JS_PUBLIC_API(intN)
JS_CompareStrings(JSString *str1, JSString *str2);
extern JS_PUBLIC_API(const jschar *)
JS_GetStringCharsZAndLength(JSContext *cx, JSString *str, size_t *length);
extern JS_PUBLIC_API(JSFlatString *)
JS_FlattenString(JSContext *cx, JSString *str);
extern JS_PUBLIC_API(const jschar *)
JS_GetFlatStringChars(JSFlatString *str);
static JS_ALWAYS_INLINE JSFlatString *
JSID_TO_FLAT_STRING(jsid id)
{
JS_ASSERT(JSID_IS_STRING(id));
return (JSFlatString *)(JSID_BITS(id));
}
static JS_ALWAYS_INLINE JSFlatString *
JS_ASSERT_STRING_IS_FLAT(JSString *str)
{
JS_ASSERT(JS_GetFlatStringChars((JSFlatString *)str));
return (JSFlatString *)str;
}
static JS_ALWAYS_INLINE JSString *
JS_FORGET_STRING_FLATNESS(JSFlatString *fstr)
{
return (JSString *)fstr;
}
/*
* Additional APIs that avoid fallibility when given a flat string.
*/
extern JS_PUBLIC_API(JSBool)
JS_MatchStringAndAscii(JSString *str, const char *asciiBytes);
JS_FlatStringEqualsAscii(JSFlatString *str, const char *asciiBytes);
extern JS_PUBLIC_API(size_t)
JS_PutEscapedString(char *buffer, size_t size, JSString *str, char quote);
extern JS_PUBLIC_API(JSBool)
JS_FileEscapedString(FILE *fp, JSString *str, char quote);
JS_PutEscapedFlatString(char *buffer, size_t size, JSFlatString *str, char quote);
/*
* This function is now obsolete and behaves the same as JS_NewUCString. Use
@ -3107,6 +3343,12 @@ class JSAutoByteString {
js_free(mBytes);
}
/* Take ownership of the given byte array. */
void initBytes(char *bytes) {
JS_ASSERT(!mBytes);
mBytes = bytes;
}
char *encode(JSContext *cx, JSString *str) {
JS_ASSERT(!mBytes);
JS_ASSERT(cx);

View File

@ -53,16 +53,18 @@
* getDenseArrayCapacity().
* - The array's initialized length, accessible with getDenseArrayInitializedLength().
*
* In dense mode, holes in the array are represented by (JS_ARRAY_HOLE) invalid
* values. Elements between the initialized length and the length property
* are left uninitialized, but are conceptually holes. Arrays with no holes
* below the initialized length are "packed" arrays.
* In dense mode, holes in the array are represented by
* MagicValue(JS_ARRAY_HOLE) invalid values. Elements between the initialized
* length and the length property are left uninitialized, but are conceptually holes.
* Arrays with no holes below the initialized length are "packed" arrays.
*
* NB: the capacity and length of a dense array are entirely unrelated! The
* length may be greater than, less than, or equal to the capacity. See
* array_length_setter for an explanation of how the first, most surprising
* case may occur. The initialized length is always less than or equal to both
* the length and capacity.
* length may be greater than, less than, or equal to the capacity. The first
* case may occur when the user writes "new Array(100), in which case the
* length is 100 while the capacity remains 0 (indices below length and above
* capacity must be treated as holes). See array_length_setter for another
* explanation of how the first case may occur. The initialized length is always
* less than or equal to both the length and capacity.
*
* Arrays are converted to use js_SlowArrayClass when any of these conditions
* are met:
@ -149,10 +151,10 @@ ENSURE_SLOW_ARRAY(JSContext *cx, JSObject *obj)
* 'id' is passed as a jsboxedword since the given id need not necessarily hold
* an atomized string.
*/
JSBool
js_StringIsIndex(JSString *str, jsuint *indexp)
bool
js_StringIsIndex(JSLinearString *str, jsuint *indexp)
{
jschar *cp = str->chars();
const jschar *cp = str->chars();
if (JS7_ISDEC(*cp) && str->length() < sizeof(MAXSTR)) {
jsuint index = JS7_UNDEC(*cp++);
jsuint oldIndex = 0;
@ -172,20 +174,22 @@ js_StringIsIndex(JSString *str, jsuint *indexp)
(oldIndex == (MAXINDEX / 10) && c < (MAXINDEX % 10))))
{
*indexp = index;
return JS_TRUE;
return true;
}
}
return JS_FALSE;
return false;
}
static jsuint
ValueIsLength(JSContext *cx, Value* vp)
static bool
ValueToLength(JSContext *cx, Value* vp, jsuint* plength)
{
if (vp->isInt32()) {
int32_t i = vp->toInt32();
if (i < 0)
goto error;
return (jsuint) i;
*plength = (jsuint)(i);
return true;
}
jsdouble d;
@ -194,18 +198,20 @@ ValueIsLength(JSContext *cx, Value* vp)
if (JSDOUBLE_IS_NaN(d))
goto error;
jsuint length;
length = (jsuint) d;
if (d != (jsdouble) length)
goto error;
vp->setNumber(length);
return length;
error:
*plength = length;
return true;
error:
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_BAD_ARRAY_LENGTH);
vp->setNull();
return 0;
return false;
}
JSBool
@ -575,8 +581,10 @@ js_HasLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
if (!ok)
return false;
*lengthp = ValueIsLength(cx, tvr.addr());
return !tvr.value().isNull();
if (!ValueToLength(cx, tvr.addr(), lengthp))
return false;
return true;
}
/*
@ -599,27 +607,20 @@ array_length_getter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
}
static JSBool
array_length_setter(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
array_length_setter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{
jsuint newlen, oldlen, gap, index;
Value junk;
/* Check for a sealed object first. */
if (!obj->isExtensible()) {
return js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_READ_ONLY,
JSDVG_IGNORE_STACK, IdToValue(id), NULL,
NULL, NULL);
}
if (!obj->isArray()) {
jsid lengthId = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
return obj->defineProperty(cx, lengthId, *vp, NULL, NULL, JSPROP_ENUMERATE);
}
newlen = ValueIsLength(cx, vp);
if (vp->isNull())
if (!ValueToLength(cx, vp, &newlen))
return false;
oldlen = obj->getArrayLength();
if (oldlen == newlen)
@ -654,8 +655,6 @@ array_length_setter(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool str
}
if (!DeleteArrayElement(cx, obj, oldlen, true)) {
obj->setArrayLength(cx, oldlen + 1);
if (strict)
return false;
JS_ClearPendingException(cx);
return true;
}
@ -817,7 +816,7 @@ array_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool stric
uint32 i;
if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
return array_length_setter(cx, obj, id, vp, strict);
return array_length_setter(cx, obj, id, vp);
if (!obj->isDenseArray())
return js_SetProperty(cx, obj, id, vp, strict);
@ -847,17 +846,6 @@ array_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool stric
return js_SetProperty(cx, obj, id, vp, strict);
}
static JSBool
slowarray_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
{
JS_ASSERT(obj->isSlowArray());
if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
return array_length_setter(cx, obj, id, vp, strict);
return js_SetProperty(cx, obj, id, vp, strict);
}
JSBool
js_PrototypeHasIndexedProperties(JSContext *cx, JSObject *obj)
{
@ -884,21 +872,35 @@ static JSBool
array_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value,
PropertyOp getter, PropertyOp setter, uintN attrs)
{
uint32 i = 0; // init to shut GCC up
JSBool isIndex;
if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
return JS_TRUE;
isIndex = js_IdIsIndex(id, &i);
if (!isIndex || attrs != JSPROP_ENUMERATE) {
if (!ENSURE_SLOW_ARRAY(cx, obj))
return JS_FALSE;
if (!obj->isDenseArray())
return js_DefineProperty(cx, obj, id, value, getter, setter, attrs);
}
Value tmp = *value;
return array_setProperty(cx, obj, id, &tmp, false);
do {
uint32 i = 0; // init to shut GCC up
bool isIndex = js_IdIsIndex(id, &i);
if (!isIndex || attrs != JSPROP_ENUMERATE)
break;
JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, i, 1);
if (result != JSObject::ED_OK) {
if (result == JSObject::ED_FAILED)
return false;
JS_ASSERT(result == JSObject::ED_SPARSE);
break;
}
if (i >= obj->getArrayLength())
obj->setArrayLength(cx, i + 1);
obj->setDenseArrayElement(i, *value);
return true;
} while (false);
if (!obj->makeDenseArraySlow(cx))
return false;
return js_DefineProperty(cx, obj, id, value, getter, setter, attrs);
}
static JSBool
@ -1017,34 +1019,7 @@ Class js_SlowArrayClass = {
PropertyStub, /* setProperty */
EnumerateStub,
ResolveStub,
js_TryValueOf,
NULL, /* finalize */
NULL, /* reserved0 */
NULL, /* checkAccess */
NULL, /* call */
NULL, /* construct */
NULL, /* xdrObject */
NULL, /* hasInstance */
NULL, /* mark */
JS_NULL_CLASS_EXT,
{
NULL, /* lookupProperty */
NULL, /* defineProperty */
NULL, /* getProperty */
/*
* For assignments to 'length', we need to know the setter's strictness. A property's
* setter isn't passed that, but the ObjectOps member is, so use that.
*/
slowarray_setProperty,
NULL, /* getAttributes */
NULL, /* setAttributes */
NULL, /* deleteProperty */
NULL, /* enumerate */
NULL, /* typeOf */
NULL, /* trace */
NULL, /* thisObject */
NULL, /* clear */
}
js_TryValueOf
};
/*
@ -1076,7 +1051,7 @@ JSObject::makeDenseArraySlow(JSContext *cx)
* The getter/setter here will directly access the object's private value.
*/
if (!addProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom),
array_length_getter, NULL,
array_length_getter, array_length_setter,
SHAPE_INVALID_SLOT, JSPROP_PERMANENT | JSPROP_SHARED, 0, 0)) {
setMap(oldMap);
return false;
@ -1215,12 +1190,13 @@ array_toSource(JSContext *cx, uintN argc, Value *vp)
goto out;
}
vp->setString(str);
const jschar *chars;
size_t charlen;
str->getCharsAndLength(chars, charlen);
const jschar *chars = str->getChars(cx);
if (!chars)
goto out;
/* Append element to buffer. */
if (!cb.append(chars, charlen))
if (!cb.append(chars, chars + str->length()))
goto out;
if (index + 1 != length) {
if (!js_AppendLiteral(cb, ", "))
@ -1254,6 +1230,20 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
{
JS_CHECK_RECURSION(cx, return false);
/* Get characters to use for the separator. */
static const jschar comma = ',';
const jschar *sep;
size_t seplen;
if (sepstr) {
seplen = sepstr->length();
sep = sepstr->getChars(cx);
if (!sep)
return false;
} else {
sep = &comma;
seplen = 1;
}
/*
* Use HashTable entry as the cycle indicator. On first visit, create the
* entry, and, when leaving, remove the entry.
@ -1263,10 +1253,8 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
uint32 genBefore;
if (!hashp) {
/* Not in hash table, so not a cycle. */
if (!cx->busyArrays.add(hashp, obj)) {
JS_ReportOutOfMemory(cx);
if (!cx->busyArrays.add(hashp, obj))
return false;
}
genBefore = cx->busyArrays.generation();
} else {
/* Cycle, so return empty string. */
@ -1280,17 +1268,6 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
MUST_FLOW_THROUGH("out");
bool ok = false;
/* Get characters to use for the separator. */
static const jschar comma = ',';
const jschar *sep;
size_t seplen;
if (sepstr) {
sepstr->getCharsAndLength(sep, seplen);
} else {
sep = &comma;
seplen = 1;
}
/*
* This object will take responsibility for the jschar buffer until the
* buffer is transferred to the returned JSString.
@ -1792,15 +1769,10 @@ comparator_stack_cast(JSRedComparator func)
static int
sort_compare_strings(void *arg, const void *a, const void *b, int *result)
{
const Value *av = (const Value *)a, *bv = (const Value *)b;
JS_ASSERT(av->isString());
JS_ASSERT(bv->isString());
if (!JS_CHECK_OPERATION_LIMIT((JSContext *)arg))
return JS_FALSE;
*result = (int) js_CompareStrings(av->toString(), bv->toString());
return JS_TRUE;
JSContext *cx = (JSContext *)arg;
JSString *astr = ((const Value *)a)->toString();
JSString *bstr = ((const Value *)b)->toString();
return JS_CHECK_OPERATION_LIMIT(cx) && CompareStrings(cx, astr, bstr, result);
}
JSBool
@ -2367,7 +2339,7 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
* arguments. We think this is best because it eliminates the need
* for callers to do an extra test to handle the empty splice case.
*/
JSObject *obj2 = js_NewArrayObject(cx, 0, NULL);
JSObject *obj2 = NewDenseEmptyArray(cx);
if (!obj2)
return JS_FALSE;
obj2->setType(type);
@ -2421,7 +2393,6 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
/* If there are elements to remove, put them into the return value. */
if (count > 0) {
if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) &&
!js_PrototypeHasIndexedProperties(cx, obj2) &&
end <= obj->getDenseArrayCapacity()) {
if (!InitArrayObject(cx, obj2, count, obj->getDenseArrayElements() + begin))
return JS_FALSE;
@ -2535,7 +2506,7 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
if (aobj->isDenseArray()) {
length = aobj->getArrayLength();
jsuint initlen = aobj->getDenseArrayInitializedLength();
nobj = js_NewArrayObject(cx, initlen, aobj->getDenseArrayElements());
nobj = NewDenseCopiedArray(cx, initlen, aobj->getDenseArrayElements());
if (!nobj)
return JS_FALSE;
nobj->setArrayLength(cx, length);
@ -2545,7 +2516,7 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
argc--;
p++;
} else {
nobj = js_NewArrayObject(cx, 0, NULL);
nobj = NewDenseEmptyArray(cx);
if (!nobj)
return JS_FALSE;
vp->setObject(*nobj);
@ -2556,9 +2527,13 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
TypeObject *ntype = cx->getTypeCallerInitObject(true);
if (!ntype)
return JS_FALSE;
nobj->setType(ntype);
if (cx->isTypeCallerMonitored())
cx->markTypeObjectUnknownProperties(ntype);
if (aobj->isDenseArray() && !aobj->isPackedDenseArray())
nobj->setDenseArrayNotPacked(cx);
AutoValueRooter tvr(cx);
/* Loop over [0, argc] to concat args into nobj, expanding all Arrays. */
@ -2573,8 +2548,8 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
jsid id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
if (!aobj->getProperty(cx, id, tvr.addr()))
return false;
jsuint alength = ValueIsLength(cx, tvr.addr());
if (tvr.value().isNull())
jsuint alength;
if (!ValueToLength(cx, tvr.addr(), &alength))
return false;
for (jsuint slot = 0; slot < alength; slot++) {
JSBool hole;
@ -2680,16 +2655,18 @@ array_slice(JSContext *cx, uintN argc, Value *vp)
if (obj->isDenseArray() && end <= obj->getDenseArrayCapacity() &&
!js_PrototypeHasIndexedProperties(cx, obj)) {
nobj = js_NewArrayObject(cx, end - begin, obj->getDenseArrayElements() + begin);
nobj = NewDenseCopiedArray(cx, end - begin, obj->getDenseArrayElements() + begin);
if (!nobj)
return JS_FALSE;
nobj->setType(type);
if (!obj->isPackedDenseArray())
nobj->setDenseArrayNotPacked(cx);
vp->setObject(*nobj);
return JS_TRUE;
}
/* Create a new Array object and root it using *vp. */
nobj = js_NewArrayObject(cx, 0, NULL);
nobj = NewDenseAllocatedArray(cx, end - begin);
if (!nobj)
return JS_FALSE;
nobj->setType(type);
@ -2705,7 +2682,7 @@ array_slice(JSContext *cx, uintN argc, Value *vp)
return JS_FALSE;
}
return js_SetLengthProperty(cx, nobj, end - begin);
return JS_TRUE;
}
#if JS_HAS_ARRAY_EXTRAS
@ -2765,11 +2742,16 @@ array_indexOfHelper(JSContext *cx, JSBool isLast, uintN argc, Value *vp)
!GetElement(cx, obj, (jsuint)i, &hole, vp)) {
return JS_FALSE;
}
if (!hole && StrictlyEqual(cx, *vp, tosearch)) {
vp->setNumber(i);
if (!vp->isInt32())
cx->markTypeCallerOverflow();
return JS_TRUE;
if (!hole) {
JSBool equal;
if (!StrictlyEqual(cx, *vp, tosearch, &equal))
return JS_FALSE;
if (equal) {
vp->setNumber(i);
if (!vp->isInt32())
cx->markTypeCallerOverflow();
return JS_TRUE;
}
}
if (i == stop)
goto not_found;
@ -2870,7 +2852,7 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp)
case MAP:
case FILTER:
newlen = (mode == MAP) ? length : 0;
newarr = js_NewArrayObject(cx, newlen, NULL);
newarr = NewDenseAllocatedArray(cx, newlen);
if (!newarr)
return JS_FALSE;
newtype = cx->getTypeCallerInitObject(true);
@ -3123,6 +3105,12 @@ static void array_TypeConcat(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsit
#ifdef JS_TYPE_INFERENCE
TypeCallsite *site = Valueify(jssite);
if (!site->compileAndGo()) {
if (site->returnTypes)
site->returnTypes->addType(cx, TYPE_UNKNOWN);
return;
}
/* Treat the returned array as a new allocation site. */
TypeObject *object = site->getInitObject(cx, true);
@ -3205,27 +3193,30 @@ static void array_TypeExtra(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite
break;
}
case MAP: {
/* Makes a new array whose element type is the return value of the argument function. */
TypeObject *object = site->getInitObject(cx, true);
extraSite->returnTypes = object->getProperty(cx, JSID_VOID, true);
site->returnTypes->addType(cx, (jstype) object);
case MAP:
if (site->compileAndGo()) {
/* Makes a new array whose element type is the return value of the argument function. */
TypeObject *object = site->getInitObject(cx, true);
extraSite->returnTypes = object->getProperty(cx, JSID_VOID, true);
site->returnTypes->addType(cx, (jstype) object);
} else {
site->returnTypes->addType(cx, TYPE_UNKNOWN);
}
break;
}
case FILTER: {
/*
* Makes a new array, whose element type is the same as the element type of the
* 'this' array. TODO: could use the same type information as the 'this' array,
* but might run into problems when we're able to handle receiver types other than arrays.
*/
TypeObject *object = site->getInitObject(cx, true);
elemTypes->addSubset(cx, pool, object->getProperty(cx, JSID_VOID, true));
site->returnTypes->addType(cx, (jstype) object);
case FILTER:
if (site->compileAndGo()) {
/*
* Makes a new array, whose element type is the same as the element type
* of the 'this' array.
*/
TypeObject *object = site->getInitObject(cx, true);
elemTypes->addSubset(cx, pool, object->getProperty(cx, JSID_VOID, true));
site->returnTypes->addType(cx, (jstype) object);
} else {
site->returnTypes->addType(cx, TYPE_UNKNOWN);
}
break;
}
case SOME:
site->returnTypes->addType(cx, TYPE_BOOLEAN);
@ -3328,104 +3319,42 @@ static JSFunctionSpec array_static_methods[] = {
JS_FS_END
};
/* The count here is a guess for the final capacity. */
static inline JSObject *
NewDenseArrayObject(JSContext *cx, jsuint count)
{
gc::FinalizeKind kind = GuessObjectGCKind(count, true);
return NewNonFunction<WithProto::Class>(cx, &js_ArrayClass, NULL, NULL, kind);
}
JSBool
js_Array(JSContext *cx, uintN argc, Value *vp)
{
jsuint length;
const Value *vector;
JSObject *obj;
TypeObject *type = cx->getTypeCallerInitObject(true);
if (!type)
return JS_FALSE;
if (argc == 0) {
length = 0;
vector = NULL;
obj = NewDenseEmptyArray(cx);
} else if (argc > 1) {
length = (jsuint) argc;
vector = vp + 2;
obj = NewDenseCopiedArray(cx, argc, vp + 2);
} else if (!vp[2].isNumber()) {
length = 1;
vector = vp + 2;
/* Unexpected case for type inference. */
cx->addTypeProperty(type, NULL, vp[2]);
obj = NewDenseCopiedArray(cx, 1, vp + 2);
} else {
length = ValueIsLength(cx, vp + 2);
if (vp[2].isNull())
jsuint length;
if (!ValueToLength(cx, vp + 2, &length))
return JS_FALSE;
vector = NULL;
obj = NewDenseUnallocatedArray(cx, length);
}
if (cx->isTypeCallerMonitored() && vector)
cx->markTypeObjectUnknownProperties(type);
/* Whether called with 'new' or not, use a new Array object. */
JSObject *obj = NewDenseArrayObject(cx, length);
if (!obj)
return JS_FALSE;
obj->setType(type);
if (cx->isTypeCallerMonitored())
cx->markTypeObjectUnknownProperties(type);
vp->setObject(*obj);
return InitArrayObject(cx, obj, length, vector);
return JS_TRUE;
}
JSObject* JS_FASTCALL
js_NewEmptyArray(JSContext* cx, JSObject* proto, int32 len)
{
if (len < 0)
return NULL;
JS_ASSERT(proto->isArray());
TypeObject *type = proto->getNewType(cx);
if (!type)
return NULL;
gc::FinalizeKind kind = GuessObjectGCKind(len, true);
JSObject* obj = js_NewGCObject(cx, kind);
if (!obj)
return NULL;
/* Initialize all fields, calling init before setting obj->map. */
obj->init(cx, &js_ArrayClass, type, proto->getParent(), (void*) len, true);
obj->setSharedNonNativeMap();
return obj;
}
#ifdef JS_TRACER
JS_DEFINE_CALLINFO_3(extern, OBJECT, js_NewEmptyArray, CONTEXT, OBJECT, INT32, 0,
nanojit::ACCSET_STORE_ANY)
#endif
JSObject* JS_FASTCALL
js_NewPreallocatedArray(JSContext* cx, JSObject* proto, int32 len)
{
/* :FIXME: new Arrays do not have the right type when created on trace. */
JSObject *obj = js_NewEmptyArray(cx, proto, len);
if (!obj)
return NULL;
/* Avoid ensureDenseArrayElements to skip sparse array checks there. */
if (!obj->ensureSlots(cx, len))
return NULL;
ClearValueRange(obj->getDenseArrayElements(), len, true);
obj->setDenseArrayInitializedLength(len);
obj->setDenseArrayNotPacked(cx);
return obj;
}
#ifdef JS_TRACER
JS_DEFINE_CALLINFO_3(extern, OBJECT, js_NewPreallocatedArray, CONTEXT, OBJECT, INT32,
0, nanojit::ACCSET_STORE_ANY)
#endif
// specialized handler for Array() that propagates arguments into indexes
// of the resulting array.
static void array_TypeNew(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
@ -3433,6 +3362,12 @@ static void array_TypeNew(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *
#ifdef JS_TYPE_INFERENCE
TypeCallsite *site = Valueify(jssite);
if (!site->compileAndGo()) {
if (site->returnTypes)
site->returnTypes->addType(cx, TYPE_UNKNOWN);
return;
}
TypeObject *object = site->getInitObject(cx, true);
if (site->returnTypes)
site->returnTypes->addType(cx, (jstype) object);
@ -3467,31 +3402,98 @@ js_InitArrayClass(JSContext *cx, JSObject *obj)
return proto;
}
JSObject *
js_NewArrayObject(JSContext *cx, jsuint length, const Value *vector)
/*
* Array allocation functions.
*/
namespace js {
template<bool allocateCapacity>
static JS_ALWAYS_INLINE JSObject *
NewArray(JSContext *cx, jsuint length, JSObject *proto)
{
JSObject *obj = NewDenseArrayObject(cx, length);
JS_ASSERT_IF(proto, proto->isArray());
gc::FinalizeKind kind = GuessObjectGCKind(length, true);
JSObject *obj = detail::NewObject<WithProto::Class, false>(cx, &js_ArrayClass, proto, NULL, kind);
obj->setArrayLength(cx, length);
if (allocateCapacity && !obj->ensureSlots(cx, length))
return NULL;
return obj;
}
JSObject * JS_FASTCALL
NewDenseEmptyArray(JSContext *cx, JSObject *proto)
{
return NewArray<false>(cx, 0, proto);
}
JSObject * JS_FASTCALL
NewDenseAllocatedArray(JSContext *cx, uint32 length, JSObject *proto)
{
return NewArray<true>(cx, length, proto);
}
JSObject * JS_FASTCALL
NewDenseAllocatedEmptyArray(JSContext *cx, uint length, JSObject *proto)
{
JSObject *obj = NewArray<true>(cx, length, proto);
if (!obj)
return NULL;
obj->setDenseArrayInitializedLength(length);
obj->setDenseArrayNotPacked(cx);
ClearValueRange(obj->getSlots(), length, true);
return obj;
}
JSObject * JS_FASTCALL
NewDenseUnallocatedArray(JSContext *cx, uint32 length, JSObject *proto)
{
return NewArray<false>(cx, length, proto);
}
JSObject *
NewDenseCopiedArray(JSContext *cx, uintN length, Value *vp, JSObject *proto)
{
JSObject* obj = NewArray<true>(cx, length, proto);
JS_ASSERT(obj->getDenseArrayCapacity() >= length);
if (vp)
memcpy(obj->getDenseArrayElements(), vp, length * sizeof(Value));
obj->setDenseArrayInitializedLength(length);
return obj;
}
#ifdef JS_TRACER
JS_DEFINE_CALLINFO_2(extern, OBJECT, NewDenseEmptyArray, CONTEXT, OBJECT, 0,
nanojit::ACCSET_STORE_ANY)
JS_DEFINE_CALLINFO_3(extern, OBJECT, NewDenseAllocatedArray, CONTEXT, UINT32, OBJECT, 0,
nanojit::ACCSET_STORE_ANY)
JS_DEFINE_CALLINFO_3(extern, OBJECT, NewDenseAllocatedEmptyArray, CONTEXT, UINT32, OBJECT, 0,
nanojit::ACCSET_STORE_ANY)
JS_DEFINE_CALLINFO_3(extern, OBJECT, NewDenseUnallocatedArray, CONTEXT, UINT32, OBJECT, 0,
nanojit::ACCSET_STORE_ANY)
#endif
JSObject *
NewSlowEmptyArray(JSContext *cx)
{
JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_SlowArrayClass, NULL, NULL);
if (!obj)
return NULL;
/*
* If this fails, the global object was not initialized and its class does
* not have JSCLASS_IS_GLOBAL.
*/
JS_ASSERT(obj->getProto());
return InitArrayObject(cx, obj, length, vector) ? obj : NULL;
}
JSObject *
js_NewSlowArrayObject(JSContext *cx)
{
JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_SlowArrayClass, NULL, NULL);
if (obj)
obj->setArrayLength(cx, 0);
obj->setArrayLength(cx, 0);
return obj;
}
}
#ifdef DEBUG
JSBool
js_ArrayInfo(JSContext *cx, uintN argc, jsval *vp)
@ -3639,10 +3641,14 @@ js_CloneDensePrimitiveArray(JSContext *cx, JSObject *obj, JSObject **clone)
vector.append(val);
}
*clone = js_NewArrayObject(cx, initlen, vector.begin());
*clone = NewDenseCopiedArray(cx, initlen, vector.begin());
if (!*clone)
return JS_FALSE;
(*clone)->setArrayLength(cx, length);
if (!obj->isPackedDenseArray())
(*clone)->setDenseArrayNotPacked(cx);
/* The length will be set to the initlen, above, but length might be larger. */
(*clone)->setArrayLength(cx, length);
return JS_TRUE;
}

View File

@ -45,7 +45,9 @@
#include "jscntxt.h"
#include "jsprvtd.h"
#include "jspubtd.h"
#include "jsatom.h"
#include "jsobj.h"
#include "jsstr.h"
/* Small arrays are dense, no matter what. */
const uintN MIN_SPARSE_INDEX = 256;
@ -145,8 +147,8 @@ JSObject::ensureDenseArrayElements(JSContext *cx, uintN index, uintN extra)
return ED_OK;
}
extern JSBool
js_StringIsIndex(JSString *str, jsuint *indexp);
extern bool
js_StringIsIndex(JSLinearString *str, jsuint *indexp);
inline JSBool
js_IdIsIndex(jsid id, jsuint *indexp)
@ -163,26 +165,36 @@ js_IdIsIndex(jsid id, jsuint *indexp)
if (JS_UNLIKELY(!JSID_IS_STRING(id)))
return JS_FALSE;
return js_StringIsIndex(JSID_TO_STRING(id), indexp);
return js_StringIsIndex(JSID_TO_ATOM(id), indexp);
}
/* XML really wants to pretend jsvals are jsids. */
inline JSBool
js_IdValIsIndex(jsval id, jsuint *indexp)
inline bool
js_IdValIsIndex(JSContext *cx, jsval id, jsuint *indexp, bool *isIndex)
{
if (JSVAL_IS_INT(id)) {
jsint i;
i = JSVAL_TO_INT(id);
if (i < 0)
return JS_FALSE;
if (i < 0) {
*isIndex = false;
return true;
}
*indexp = (jsuint)i;
return JS_TRUE;
*isIndex = true;
return true;
}
if (!JSVAL_IS_STRING(id))
return JS_FALSE;
if (!JSVAL_IS_STRING(id)) {
*isIndex = false;
return true;
}
return js_StringIsIndex(JSVAL_TO_STRING(id), indexp);
JSLinearString *str = JSVAL_TO_STRING(id)->ensureLinear(cx);
if (!str)
return false;
*isIndex = js_StringIsIndex(str, indexp);
return true;
}
extern js::Class js_ArrayClass, js_SlowArrayClass;
@ -233,12 +245,41 @@ js_InitArrayClass(JSContext *cx, JSObject *obj);
extern bool
js_InitContextBusyArrayTable(JSContext *cx);
extern JSObject *
js_NewArrayObject(JSContext *cx, jsuint length, const js::Value *vector);
namespace js
{
/* Create an array object that starts out already made slow/sparse. */
/* Create a dense array with no capacity allocated, length set to 0. */
extern JSObject * JS_FASTCALL
NewDenseEmptyArray(JSContext *cx, JSObject *proto=NULL);
/* Create a dense array with length and capacity == 'length', initialized length set to 0. */
extern JSObject * JS_FASTCALL
NewDenseAllocatedArray(JSContext *cx, uint length, JSObject *proto=NULL);
/*
* Create a dense array with length, capacity and initialized length == 'length', and filled with holes.
* This is a kludge, as the tracer doesn't yet track/update initialized length when initializing
* array elements.
*/
extern JSObject * JS_FASTCALL
NewDenseAllocatedEmptyArray(JSContext *cx, uint length, JSObject *proto=NULL);
/*
* Create a dense array with a set length, but without allocating space for the
* contents. This is useful, e.g., when accepting length from the user.
*/
extern JSObject * JS_FASTCALL
NewDenseUnallocatedArray(JSContext *cx, uint length, JSObject *proto=NULL);
/* Create a dense array with a copy of vp. */
extern JSObject *
js_NewSlowArrayObject(JSContext *cx);
NewDenseCopiedArray(JSContext *cx, uint length, Value *vp, JSObject *proto=NULL);
/* Create a sparse array. */
extern JSObject *
NewSlowEmptyArray(JSContext *cx);
}
extern JSBool
js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp);
@ -339,25 +380,6 @@ js_GetDenseArrayElementValue(JSContext *cx, JSObject *obj, jsid id,
JSBool
js_Array(JSContext *cx, uintN argc, js::Value *vp);
/*
* Friend api function that allows direct creation of an array object with a
* given capacity. Non-null return value means allocation of the internal
* buffer for a capacity of at least |capacity| succeeded. A pointer to the
* first element of this internal buffer is returned in the |vector| out
* parameter. The caller promises to fill in the first |capacity| values
* starting from that pointer immediately after this function returns and
* without triggering GC (so this method is allowed to leave those
* uninitialized) and to set them to non-JS_ARRAY_HOLE-magic-why values, so
* that the resulting array has length and count both equal to |capacity|.
*
* FIXME: for some strange reason, when this file is included from
* dom/ipc/TabParent.cpp in MSVC, jsuint resolves to a slightly different
* builtin than when mozjs.dll is built, resulting in a link error in xul.dll.
* It would be useful to find out what is causing this insanity.
*/
JS_FRIEND_API(JSObject *)
js_NewArrayObjectWithCapacity(JSContext *cx, uint32_t capacity, jsval **vector);
/*
* Makes a fast clone of a dense array as long as the array only contains
* primitive values.

View File

@ -457,25 +457,20 @@ js_SweepAtomState(JSContext *cx)
}
JSAtom *
js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
js_AtomizeString(JSContext *cx, JSString *strArg, uintN flags)
{
JS_ASSERT(!(flags & ~(ATOM_PINNED|ATOM_INTERNED|ATOM_TMPSTR|ATOM_NOCOPY)));
JS_ASSERT_IF(flags & ATOM_NOCOPY, flags & ATOM_TMPSTR);
if (str->isAtomized()) {
JSAtomState *state = &cx->runtime->atomState;
AtomSet &atoms = state->atoms;
if (strArg->isAtomized())
return STRING_TO_ATOM(strArg);
AutoLockDefaultCompartment lock(cx);
AtomSet::AddPtr p = atoms.lookupForAdd(str);
JSLinearString *str = strArg->ensureLinear(cx);
if (!str)
return NULL;
AddAtomEntryFlags(*p, flags & (ATOM_PINNED | ATOM_INTERNED));
return STRING_TO_ATOM(str);
}
const jschar *chars;
size_t length;
str->getCharsAndLength(chars, length);
const jschar *chars = str->chars();
size_t length = str->length();
JSString *staticStr = JSString::lookupStaticString(chars, length);
if (staticStr)
@ -490,7 +485,7 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
/* Hashing the string should have flattened it if it was a rope. */
JS_ASSERT(str->isFlat() || str->isDependent());
JSString *key;
JSLinearString *key;
if (p) {
key = AtomEntryToKey(*p);
} else {
@ -514,15 +509,14 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
} else {
if (needNewString) {
SwitchToCompartment sc(cx, cx->runtime->defaultCompartment);
jschar *chars = str->chars();
if (flags & ATOM_NOCOPY) {
key = js_NewString(cx, chars, length);
key = js_NewString(cx, const_cast<jschar *>(str->flatChars()), length);
if (!key)
return NULL;
/* Finish handing off chars to the GC'ed key string. */
JS_ASSERT(flags & ATOM_TMPSTR);
str->mChars = NULL;
str->u.chars = NULL;
} else {
key = js_NewStringCopyN(cx, chars, length);
if (!key)
@ -545,7 +539,6 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
AddAtomEntryFlags(*p, flags & (ATOM_PINNED | ATOM_INTERNED));
JS_ASSERT(key->isAtomized());
JSAtom *atom = STRING_TO_ATOM(key);
return atom;
}
@ -595,7 +588,7 @@ js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, uintN flags)
JSString str;
CHECK_REQUEST(cx);
str.initFlat((jschar *)chars, length);
str.initFlatNotTerminated((jschar *)chars, length);
return js_AtomizeString(cx, &str, ATOM_TMPSTR | flags);
}
@ -611,11 +604,11 @@ js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length)
return STRING_TO_ATOM(JSString::unitString(c));
}
str.initFlat((jschar *)chars, length);
str.initFlatNotTerminated((jschar *)chars, length);
state = &cx->runtime->atomState;
JS_LOCK(cx, &state->lock);
AtomSet::Ptr p = state->atoms.lookup(&str);
AtomSet::Ptr p = state->atoms.lookup(str.assertIsFlat());
str2 = p ? AtomEntryToKey(*p) : NULL;
JS_UNLOCK(cx, &state->lock);
@ -636,7 +629,7 @@ js_DumpAtoms(JSContext *cx, FILE *fp)
if (entry == 0) {
fputs("<uninitialized>", fp);
} else {
JSString *key = AtomEntryToKey(entry);
JSAtom *key = AtomEntryToKey(entry);
FileEscapedString(fp, key, '"');
uintN flags = AtomEntryFlags(entry);
if (flags != 0) {

View File

@ -60,7 +60,7 @@
#define STRING_TO_ATOM(str) (JS_ASSERT(str->isAtomized()), \
(JSAtom *)str)
#define ATOM_TO_STRING(atom) ((JSString *)(atom))
#define ATOM_TO_STRING(atom) (atom)
#define ATOM_TO_JSVAL(atom) STRING_TO_JSVAL(ATOM_TO_STRING(atom))
/* Engine-internal extensions of jsid */
@ -265,23 +265,23 @@ JS_STATIC_ASSERT(ATOM_ENTRY_FLAG_MASK < JS_GCTHING_ALIGN);
typedef uintptr_t AtomEntryType;
static JS_ALWAYS_INLINE JSString *
static JS_ALWAYS_INLINE JSAtom *
AtomEntryToKey(AtomEntryType entry)
{
JS_ASSERT(entry != 0);
return (JSString *)(entry & ~ATOM_ENTRY_FLAG_MASK);
return (JSAtom *)(entry & ~ATOM_ENTRY_FLAG_MASK);
}
struct AtomHasher
{
typedef JSString *Lookup;
typedef JSLinearString *Lookup;
static HashNumber hash(JSString *str) {
static HashNumber hash(JSLinearString *str) {
return js_HashString(str);
}
static bool match(AtomEntryType entry, JSString *lookup) {
return entry ? js_EqualStrings(AtomEntryToKey(entry), lookup) : false;
static bool match(AtomEntryType entry, JSLinearString *lookup) {
return entry ? EqualStrings(AtomEntryToKey(entry), lookup) : false;
}
};

View File

@ -168,18 +168,22 @@ js_DoubleToUint32(jsdouble d)
JS_DEFINE_CALLINFO_1(extern, UINT32, js_DoubleToUint32, DOUBLE, 1, ACCSET_NONE)
jsdouble FASTCALL
js_StringToNumber(JSContext* cx, JSString* str)
js_StringToNumber(JSContext* cx, JSString* str, JSBool *ok)
{
return StringToNumberType<jsdouble>(cx, str);
double out = 0; /* silence warnings. */
*ok = StringToNumberType<jsdouble>(cx, str, &out);
return out;
}
JS_DEFINE_CALLINFO_2(extern, DOUBLE, js_StringToNumber, CONTEXT, STRING, 1, ACCSET_NONE)
JS_DEFINE_CALLINFO_3(extern, DOUBLE, js_StringToNumber, CONTEXT, STRING, BOOLPTR, 1, ACCSET_NONE)
int32 FASTCALL
js_StringToInt32(JSContext* cx, JSString* str)
js_StringToInt32(JSContext* cx, JSString* str, JSBool *ok)
{
return StringToNumberType<int32>(cx, str);
int32 out = 0; /* silence warnings. */
*ok = StringToNumberType<int32>(cx, str, &out);
return out;
}
JS_DEFINE_CALLINFO_2(extern, INT32, js_StringToInt32, CONTEXT, STRING, 1, ACCSET_NONE)
JS_DEFINE_CALLINFO_3(extern, INT32, js_StringToInt32, CONTEXT, STRING, BOOLPTR, 1, ACCSET_NONE)
/* Nb: it's always safe to set isDefinitelyAtom to false if you're unsure or don't know. */
static inline JSBool

View File

@ -547,7 +547,7 @@ struct ClosureVarInfo;
#define _JS_DEFINE_CALLINFO_n(n, args) JS_DEFINE_CALLINFO_##n args
jsdouble FASTCALL
js_StringToNumber(JSContext* cx, JSString* str);
js_StringToNumber(JSContext* cx, JSString* str, JSBool *ok);
/* Extern version of SetBuiltinError. */
extern JS_FRIEND_API(void)
@ -575,8 +575,12 @@ js_dmod(jsdouble a, jsdouble b);
#endif /* !JS_TRACER */
/* Defined in jsarray.cpp. */
JS_DECLARE_CALLINFO(js_NewEmptyArray)
JS_DECLARE_CALLINFO(js_NewPreallocatedArray)
namespace js {
JS_DECLARE_CALLINFO(NewDenseEmptyArray)
JS_DECLARE_CALLINFO(NewDenseAllocatedArray)
JS_DECLARE_CALLINFO(NewDenseUnallocatedArray)
JS_DECLARE_CALLINFO(NewDenseAllocatedEmptyArray)
}
JS_DECLARE_CALLINFO(js_ArrayCompPush_tn)
JS_DECLARE_CALLINFO(js_EnsureDenseArrayCapacity)
@ -620,9 +624,9 @@ JS_DECLARE_CALLINFO(js_CloneRegExpObject)
/* Defined in jsstr.cpp. */
JS_DECLARE_CALLINFO(js_String_tn)
JS_DECLARE_CALLINFO(js_CompareStrings)
JS_DECLARE_CALLINFO(js_CompareStringsOnTrace)
JS_DECLARE_CALLINFO(js_ConcatStrings)
JS_DECLARE_CALLINFO(js_EqualStrings)
JS_DECLARE_CALLINFO(js_EqualStringsOnTrace)
JS_DECLARE_CALLINFO(js_Flatten)
/* Defined in jstypedarray.cpp. */

View File

@ -350,9 +350,10 @@ JS_STATIC_ASSERT(JSString::MAX_LENGTH < UINT32_MAX);
bool
JSStructuredCloneWriter::writeString(uint32_t tag, JSString *str)
{
const jschar *chars;
size_t length;
str->getCharsAndLength(chars, length);
size_t length = str->length();
const jschar *chars = str->getChars(context());
if (!chars)
return false;
return out.writePair(tag, uint32_t(length)) && out.writeChars(chars, length);
}
@ -604,9 +605,14 @@ class Chars {
bool allocate(JSContext *cx, size_t len) {
JS_ASSERT(!p);
p = (jschar *) cx->malloc(len * sizeof(jschar));
// We're going to null-terminate!
p = (jschar *) cx->malloc((len + 1) * sizeof(jschar));
this->cx = cx;
return p != NULL;
if (p) {
p[len] = jschar(0);
return true;
}
return false;
}
jschar *get() { return p; }
void forget() { p = NULL; }
@ -745,9 +751,10 @@ JSStructuredCloneReader::startRead(Value *vp)
JSString *str = readString(nchars);
if (!str)
return false;
const jschar *chars;
size_t length;
str->getCharsAndLength(chars, length);
size_t length = str->length();
const jschar *chars = str->getChars(context());
if (!chars)
return false;
JSObject *obj = RegExp::createObjectNoStatics(context(), chars, length, data);
if (!obj)
return false;
@ -755,16 +762,11 @@ JSStructuredCloneReader::startRead(Value *vp)
break;
}
case SCTAG_ARRAY_OBJECT: {
JSObject *obj = js_NewArrayObject(context(), 0, NULL);
if (!obj || !objs.append(ObjectValue(*obj)))
return false;
vp->setObject(*obj);
break;
}
case SCTAG_ARRAY_OBJECT:
case SCTAG_OBJECT_OBJECT: {
JSObject *obj = NewBuiltinClassInstance(context(), &js_ObjectClass);
JSObject *obj = (tag == SCTAG_ARRAY_OBJECT)
? NewDenseEmptyArray(context())
: NewBuiltinClassInstance(context(), &js_ObjectClass);
if (!obj || !objs.append(ObjectValue(*obj)))
return false;
vp->setObject(*obj);

View File

@ -1322,6 +1322,7 @@ struct JSRuntime {
uint32 gcNumber;
js::GCMarker *gcMarkingTracer;
uint32 gcTriggerFactor;
int64 gcJitReleaseTime;
volatile JSBool gcIsNeeded;
/*
@ -1369,7 +1370,7 @@ struct JSRuntime {
js::Value negativeInfinityValue;
js::Value positiveInfinityValue;
JSString *emptyString;
JSFlatString *emptyString;
/* List of active contexts sharing this runtime; protected by gcLock. */
JSCList contextList;
@ -1656,6 +1657,13 @@ struct JSRuntime {
return JS_LIKELY(!!p) ? p : onOutOfMemory(reinterpret_cast<void *>(1), bytes, cx);
}
void* realloc(void* p, size_t oldBytes, size_t newBytes, JSContext *cx = NULL) {
JS_ASSERT(oldBytes < newBytes);
updateMallocCounter(newBytes - oldBytes);
void *p2 = ::js_realloc(p, newBytes);
return JS_LIKELY(!!p2) ? p2 : onOutOfMemory(p, newBytes, cx);
}
void* realloc(void* p, size_t bytes, JSContext *cx = NULL) {
/*
* For compatibility we do not account for realloc that increases
@ -2295,6 +2303,10 @@ struct JSContext
return runtime->realloc(p, bytes, this);
}
inline void* realloc(void* p, size_t oldBytes, size_t newBytes) {
return runtime->realloc(p, oldBytes, newBytes, this);
}
inline void free(void* p) {
#ifdef JS_THREADSAFE
if (gcBackgroundFree) {
@ -2375,10 +2387,10 @@ struct JSContext
#ifdef XP_WIN
volatile DollarPath *dollarPath;
volatile JSSubString *sub;
volatile jschar *blackBox;
volatile jschar **repstrChars;
volatile jschar **repstrDollar;
volatile jschar **repstrDollarEnd;
volatile const jschar *blackBox;
volatile const jschar **repstrChars;
volatile const jschar **repstrDollar;
volatile const jschar **repstrDollarEnd;
volatile size_t *peekLen;
#endif

View File

@ -591,7 +591,7 @@ class CompartmentChecker
}
void check(JSScript *script) {
if (script && script != JSScript::emptyScript()) {
if (script) {
check(script->compartment);
if (script->u.object)
check(script->u.object);

View File

@ -54,7 +54,7 @@ using namespace js;
using namespace js::gc;
JSCompartment::JSCompartment(JSRuntime *rt)
: rt(rt), principals(NULL), data(NULL), marked(false), debugMode(rt->debugMode),
: rt(rt), principals(NULL), data(NULL), marked(false), active(false), debugMode(rt->debugMode),
anynameObject(NULL), functionNamespaceObject(NULL)
{
JS_INIT_CLIST(&scripts);
@ -205,7 +205,10 @@ JSCompartment::wrap(JSContext *cx, Value *vp)
if (vp->isString()) {
Value orig = *vp;
JSString *str = vp->toString();
JSString *wrapped = js_NewStringCopyN(cx, str->chars(), str->length());
const jschar *chars = str->getChars(cx);
if (!chars)
return false;
JSString *wrapped = js_NewStringCopyN(cx, chars, str->length());
if (!wrapped)
return false;
vp->setString(wrapped);
@ -328,8 +331,33 @@ JSCompartment::wrapException(JSContext *cx)
return true;
}
/*
* Check if the pool containing the code for jit should be destroyed, per the
* heuristics in JSCompartment::sweep.
*/
static inline bool
ScriptPoolDestroyed(JSContext *cx, mjit::JITScript *jit,
uint32 releaseInterval, uint32 &counter)
{
JSC::ExecutablePool *pool = jit->code.m_executablePool;
if (pool->m_gcNumber != cx->runtime->gcNumber) {
/*
* The m_destroy flag may have been set in a previous GC for a pool which had
* references we did not remove (e.g. from the compartment's ExecutableAllocator)
* and is still around. Forget we tried to destroy it in such cases.
*/
pool->m_destroy = false;
pool->m_gcNumber = cx->runtime->gcNumber;
if (--counter == 0) {
pool->m_destroy = true;
counter = releaseInterval;
}
}
return pool->m_destroy;
}
void
JSCompartment::sweep(JSContext *cx)
JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
{
chunk = NULL;
/* Remove dead wrappers from the table. */
@ -343,17 +371,41 @@ JSCompartment::sweep(JSContext *cx)
}
}
/*
* The release interval is the frequency with which we should try to destroy
* executable pools by releasing all JIT code in them, zero to never destroy pools.
* Initialize counter so that the first pool will be destroyed, and eventually drive
* the amount of JIT code in never-used compartments to zero. Don't discard anything
* for compartments which currently have active stack frames.
*/
uint32 counter = 1;
bool discardScripts = !active && releaseInterval != 0;
for (JSCList *cursor = scripts.next; cursor != &scripts; cursor = cursor->next) {
JSScript *script = reinterpret_cast<JSScript *>(cursor);
#if defined JS_METHODJIT && defined JS_MONOIC
if (script->hasJITCode())
mjit::ic::SweepCallICs(script);
#endif
if (script->analysis)
script->analysis->sweep(cx);
#if defined JS_METHODJIT && defined JS_MONOIC
if (script->hasJITCode()) {
mjit::ic::SweepCallICs(script, discardScripts);
if (discardScripts) {
if (script->jitNormal &&
ScriptPoolDestroyed(cx, script->jitNormal, releaseInterval, counter)) {
mjit::ReleaseScriptCode(cx, script);
continue;
}
if (script->jitCtor &&
ScriptPoolDestroyed(cx, script->jitCtor, releaseInterval, counter)) {
mjit::ReleaseScriptCode(cx, script);
}
}
}
#endif
}
types.sweep(cx);
active = false;
}
void
@ -371,8 +423,8 @@ JSCompartment::purge(JSContext *cx)
# endif
# if defined JS_MONOIC
/*
* MICs do not refer to data which can be GC'ed, but are sensitive
* to shape regeneration.
* MICs do not refer to data which can be GC'ed and do not generate stubs
* which might need to be discarded, but are sensitive to shape regeneration.
*/
if (cx->runtime->gcRegenShapes)
mjit::ic::PurgeMICs(cx, script);

View File

@ -77,6 +77,7 @@ struct JS_FRIEND_API(JSCompartment) {
void *data;
bool marked;
bool active; // GC flag, whether there are active frames
js::WrapperMap crossCompartmentWrappers;
#ifdef JS_METHODJIT
@ -110,7 +111,7 @@ struct JS_FRIEND_API(JSCompartment) {
bool wrap(JSContext *cx, js::AutoIdVector &props);
bool wrapException(JSContext *cx);
void sweep(JSContext *cx);
void sweep(JSContext *cx, uint32 releaseInterval);
void purge(JSContext *cx);
void finishArenaLists();
bool arenaListsAreEmpty();

View File

@ -752,7 +752,7 @@ ndigits(size_t n, size_t *result, const jschar *s, size_t* i, size_t limit)
*/
static JSBool
date_parseISOString(JSString *str, jsdouble *result, JSContext *cx)
date_parseISOString(JSLinearString *str, jsdouble *result, JSContext *cx)
{
jsdouble msec;
@ -794,7 +794,8 @@ date_parseISOString(JSString *str, jsdouble *result, JSContext *cx)
if (!ndigits(n, &field, s, &i, limit)) { goto syntax; } \
JS_END_MACRO
str->getCharsAndLength(s, limit);
s = str->chars();
limit = str->length();
if (PEEK('+') || PEEK('-')) {
if (PEEK('-'))
@ -885,7 +886,7 @@ date_parseISOString(JSString *str, jsdouble *result, JSContext *cx)
}
static JSBool
date_parseString(JSString *str, jsdouble *result, JSContext *cx)
date_parseString(JSLinearString *str, jsdouble *result, JSContext *cx)
{
jsdouble msec;
@ -909,7 +910,8 @@ date_parseString(JSString *str, jsdouble *result, JSContext *cx)
if (date_parseISOString(str, result, cx))
return JS_TRUE;
str->getCharsAndLength(s, limit);
s = str->chars();
limit = str->length();
if (limit == 0)
goto syntax;
while (i < limit) {
@ -1169,7 +1171,11 @@ date_parse(JSContext *cx, uintN argc, Value *vp)
if (!str)
return JS_FALSE;
vp[2].setString(str);
if (!date_parseString(str, &result, cx)) {
JSLinearString *linearStr = str->ensureLinear(cx);
if (!linearStr)
return false;
if (!date_parseString(linearStr, &result, cx)) {
vp->setDouble(js_NaN);
return true;
}
@ -2390,11 +2396,10 @@ date_toSource(JSContext *cx, uintN argc, Value *vp)
return JS_FALSE;
}
str = JS_NewString(cx, bytes, strlen(bytes));
if (!str) {
js_free(bytes);
str = JS_NewStringCopyZ(cx, bytes);
js_free(bytes);
if (!str)
return JS_FALSE;
}
vp->setString(str);
return JS_TRUE;
}
@ -2413,8 +2418,6 @@ date_toString(JSContext *cx, uintN argc, Value *vp)
static JSBool
date_valueOf(JSContext *cx, uintN argc, Value *vp)
{
JSString *str, *number_str;
/* It is an error to call date_valueOf on a non-date object, but we don't
* need to check for that explicitly here because every path calls
* GetUTCTime, which does the check.
@ -2425,11 +2428,14 @@ date_valueOf(JSContext *cx, uintN argc, Value *vp)
return date_getTime(cx, argc, vp);
/* Convert to number only if the hint was given, otherwise favor string. */
str = js_ValueToString(cx, vp[2]);
JSString *str = js_ValueToString(cx, vp[2]);
if (!str)
return JS_FALSE;
number_str = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER]);
if (js_EqualStrings(str, number_str))
JSLinearString *linear_str = str->ensureLinear(cx);
if (!linear_str)
return JS_FALSE;
JSAtom *number_str = cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER];
if (EqualStrings(linear_str, number_str))
return date_getTime(cx, argc, vp);
return date_toString(cx, argc, vp);
}
@ -2523,8 +2529,11 @@ js_Date(JSContext *cx, uintN argc, Value *vp)
if (!str)
return false;
argv[0].setString(str);
JSLinearString *linearStr = str->ensureLinear(cx);
if (!linearStr)
return false;
if (!date_parseString(str, &d, cx))
if (!date_parseString(linearStr, &d, cx))
d = js_NaN;
else
d = TIMECLIP(d);

View File

@ -146,7 +146,7 @@ js_SetDebugMode(JSContext *cx, JSBool debug)
for (JSScript *script = (JSScript *)cx->compartment->scripts.next;
&script->links != &cx->compartment->scripts;
script = (JSScript *)script->links.next) {
if (script->debugMode != (bool) debug &&
if (script->debugMode != !!debug &&
script->hasJITCode() &&
!IsScriptLive(cx, script)) {
/*
@ -183,6 +183,30 @@ JS_SetDebugMode(JSContext *cx, JSBool debug)
return js_SetDebugMode(cx, debug);
}
JS_FRIEND_API(JSBool)
js_SetSingleStepMode(JSContext *cx, JSScript *script, JSBool singleStep)
{
if (!script->singleStepMode == !singleStep)
return JS_TRUE;
JS_ASSERT_IF(singleStep, cx->compartment->debugMode);
#ifdef JS_METHODJIT
/* request the next recompile to inject single step interrupts */
script->singleStepMode = !!singleStep;
js::mjit::JITScript *jit = script->jitNormal ? script->jitNormal : script->jitCtor;
if (jit && script->singleStepMode != jit->singleStepMode) {
js::mjit::Recompiler recompiler(cx, script);
if (!recompiler.recompile()) {
script->singleStepMode = !singleStep;
return JS_FALSE;
}
}
#endif
return JS_TRUE;
}
static JSBool
CheckDebugMode(JSContext *cx)
{
@ -199,6 +223,15 @@ CheckDebugMode(JSContext *cx)
return debugMode;
}
JS_PUBLIC_API(JSBool)
JS_SetSingleStepMode(JSContext *cx, JSScript *script, JSBool singleStep)
{
if (!CheckDebugMode(cx))
return JS_FALSE;
return js_SetSingleStepMode(cx, script, singleStep);
}
/*
* NB: FindTrap must be called with rt->debuggerLock acquired.
*/
@ -266,12 +299,6 @@ JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
if (!CheckDebugMode(cx))
return JS_FALSE;
if (script == JSScript::emptyScript()) {
JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage,
NULL, JSMSG_READ_ONLY, "empty script");
return JS_FALSE;
}
JS_ASSERT((JSOp) *pc != JSOP_TRAP);
junk = NULL;
rt = cx->runtime;
@ -1764,7 +1791,7 @@ JS_GetScriptTotalSize(JSContext *cx, JSScript *script)
continue;
nbytes += (sn - notes + 1) * sizeof *sn;
if (script->objectsOffset != 0) {
if (JSScript::isValidOffset(script->objectsOffset)) {
objarray = script->objects();
i = objarray->length;
nbytes += sizeof *objarray + i * sizeof objarray->vector[0];
@ -1773,7 +1800,7 @@ JS_GetScriptTotalSize(JSContext *cx, JSScript *script)
} while (i != 0);
}
if (script->regexpsOffset != 0) {
if (JSScript::isValidOffset(script->regexpsOffset)) {
objarray = script->regexps();
i = objarray->length;
nbytes += sizeof *objarray + i * sizeof objarray->vector[0];
@ -1782,7 +1809,7 @@ JS_GetScriptTotalSize(JSContext *cx, JSScript *script)
} while (i != 0);
}
if (script->trynotesOffset != 0) {
if (JSScript::isValidOffset(script->trynotesOffset)) {
nbytes += sizeof(JSTryNoteArray) +
script->trynotes()->length * sizeof(JSTryNote);
}
@ -2004,15 +2031,13 @@ JS_FRIEND_API(JSBool)
js_DumpCallgrind(JSContext *cx, uintN argc, jsval *vp)
{
JSString *str;
char *cstr;
jsval *argv = JS_ARGV(cx, vp);
if (argc > 0 && JSVAL_IS_STRING(argv[0])) {
str = JSVAL_TO_STRING(argv[0]);
cstr = js_DeflateString(cx, str->chars(), str->length());
if (cstr) {
CALLGRIND_DUMP_STATS_AT(cstr);
cx->free(cstr);
JSAutoByteString bytes(cx, str);
if (!!bytes) {
CALLGRIND_DUMP_STATS_AT(bytes.ptr());
return JS_TRUE;
}
}

View File

@ -78,6 +78,14 @@ js_SetDebugMode(JSContext *cx, JSBool debug);
extern JS_PUBLIC_API(JSBool)
JS_SetDebugMode(JSContext *cx, JSBool debug);
/* Turn on single step mode. Requires debug mode. */
extern JS_FRIEND_API(JSBool)
js_SetSingleStepMode(JSContext *cx, JSScript *script, JSBool singleStep);
/* Turn on single step mode. */
extern JS_PUBLIC_API(JSBool)
JS_SetSingleStepMode(JSContext *cx, JSScript *script, JSBool singleStep);
/*
* Unexported library-private helper used to unpatch all traps in a script.
* Returns script->code if script has no traps, else a JS_malloc'ed copy of

View File

@ -1737,7 +1737,7 @@ LookupCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom,
break;
}
}
} while ((cg = (JSCodeGenerator *) cg->parent) != NULL);
} while (cg->parent && (cg = cg->parent->asCodeGenerator()));
return JS_TRUE;
}
@ -2161,13 +2161,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
*
* Turn JSOP_DELNAME into JSOP_FALSE if dn is known, as all declared
* bindings visible to the compiler are permanent in JS unless the
* declaration originates in eval code. We detect eval code by testing
* cg->parser->callerFrame, which is set only by eval or a debugger
* equivalent.
*
* Note that this callerFrame non-null test must be qualified by testing
* !cg->funbox to exclude function code nested in eval code, which is not
* subject to the deletable binding exception.
* declaration originates at top level in eval code.
*/
switch (op) {
case JSOP_NAME:
@ -2175,7 +2169,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
break;
case JSOP_DELNAME:
if (dn_kind != JSDefinition::UNKNOWN) {
if (cg->parser->callerFrame && !cg->funbox)
if (cg->parser->callerFrame && dn->isTopLevel())
JS_ASSERT(cg->compileAndGo());
else
pn->pn_op = JSOP_FALSE;
@ -2240,6 +2234,27 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
if (op != JSOP_NAME)
return JS_TRUE;
/*
* It is illegal to add upvars to heavyweight functions (and
* unnecessary, since the optimization avoids creating call
* objects). Take the following code as an eval string:
*
* (function () {
* $(init);
* function init() {
* $();
* }
* })();
*
* The first instance of "$" cannot be an upvar, because the
* outermost lambda is on "init"'s scope chain, which escapes.
*
* A similar restriction exists for upvars which do not cross
* eval (see the end of BindNameToSlot and bug 616762).
*/
if (cg->flags & TCF_FUN_HEAVYWEIGHT)
return JS_TRUE;
/*
* Generator functions may be resumed from any call stack, which
* defeats the display optimization to static link searching used
@ -2332,9 +2347,8 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
JSTreeContext *tc = cg;
while (tc->staticLevel != level)
tc = tc->parent;
JS_ASSERT(tc->compiling());
JSCodeGenerator *evalcg = (JSCodeGenerator *) tc;
JSCodeGenerator *evalcg = tc->asCodeGenerator();
JS_ASSERT(evalcg->compileAndGo());
JS_ASSERT(caller->isFunctionFrame());
JS_ASSERT(cg->parser->callerVarObj == evalcg->scopeChain());
@ -2412,10 +2426,9 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
JS_ASSERT(index == cg->upvarList.count - 1);
UpvarCookie *vector = cg->upvarMap.vector;
if (!vector) {
uint32 length = cg->lexdeps.count;
vector = (UpvarCookie *) js_calloc(length * sizeof *vector);
uint32 length = cg->lexdeps.count;
if (!vector || cg->upvarMap.length != length) {
vector = (UpvarCookie *) js_realloc(vector, length * sizeof *vector);
if (!vector) {
JS_ReportOutOfMemory(cx);
return JS_FALSE;
@ -2434,6 +2447,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
slot += tc->fun()->nargs;
}
JS_ASSERT(index < cg->upvarMap.length);
vector[index].set(skip, slot);
}
@ -4580,11 +4594,6 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
break;
}
JS_ASSERT_IF(cx->options & JSOPTION_ANONFUNFIX,
pn->pn_defn ||
(!pn->pn_used && !pn->isTopLevel()) ||
(fun->flags & JSFUN_LAMBDA));
JS_ASSERT_IF(pn->pn_funbox->tcflags & TCF_FUN_HEAVYWEIGHT,
FUN_KIND(fun) == JSFUN_INTERPRETED);
@ -4604,7 +4613,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
if (!cg2->init())
return JS_FALSE;
cg2->flags = pn->pn_funbox->tcflags | TCF_IN_FUNCTION;
cg2->flags = pn->pn_funbox->tcflags | TCF_COMPILING | TCF_IN_FUNCTION;
#if JS_HAS_SHARP_VARS
if (cg2->flags & TCF_HAS_SHARPS) {
cg2->sharpSlotBase = fun->sharpSlotBase(cx);

View File

@ -364,8 +364,16 @@ struct JSTreeContext { /* tree context for semantic checks */
JSObject *blockChain() {
return blockChainBox ? blockChainBox->object : NULL;
}
bool atTopLevel() { return !topStmt || (topStmt->flags & SIF_BODY_BLOCK); }
/*
* True if we are at the topmost level of a entire script or function body.
* For example, while parsing this code we would encounter f1 and f2 at
* body level, but we would not encounter f3 or f4 at body level:
*
* function f1() { function f2() { } }
* if (cond) { function f3() { if (cond) { function f4() { } } } }
*/
bool atBodyLevel() { return !topStmt || (topStmt->flags & SIF_BODY_BLOCK); }
/* Test whether we're in a statement of given type. */
bool inStatement(JSStmtType type);
@ -392,7 +400,9 @@ struct JSTreeContext { /* tree context for semantic checks */
bool compileAndGo() const { return flags & TCF_COMPILE_N_GO; }
bool inFunction() const { return flags & TCF_IN_FUNCTION; }
bool compiling() const { return flags & TCF_COMPILING; }
inline JSCodeGenerator *asCodeGenerator();
bool usesArguments() const {
return flags & TCF_FUN_USES_ARGUMENTS;
@ -594,7 +604,7 @@ struct JSCodeGenerator : public JSTreeContext
SlotVector closedVars;
uint16 traceIndex; /* index for the next JSOP_TRACE instruction */
/*
* Initialize cg to allocate bytecode space from codePool, source note
* space from notePool, and all other arena-allocated temporaries from
@ -668,6 +678,13 @@ struct JSCodeGenerator : public JSTreeContext
#define CG_SWITCH_TO_MAIN(cg) ((cg)->current = &(cg)->main)
#define CG_SWITCH_TO_PROLOG(cg) ((cg)->current = &(cg)->prolog)
inline JSCodeGenerator *
JSTreeContext::asCodeGenerator()
{
JS_ASSERT(compiling());
return static_cast<JSCodeGenerator *>(this);
}
/*
* Emit one bytecode.
*/

View File

@ -614,10 +614,11 @@ StackTraceToString(JSContext *cx, JSExnPrivate *priv)
#define APPEND_STRING_TO_STACK(str) \
JS_BEGIN_MACRO \
JSString *str_ = str; \
const jschar *chars_; \
size_t length_; \
size_t length_ = str_->length(); \
const jschar *chars_ = str_->getChars(cx); \
if (!chars_) \
goto bad; \
\
str_->getCharsAndLength(chars_, length_); \
if (length_ > stackmax - stacklen) { \
void *ptr_; \
if (stackmax >= STACK_LENGTH_LIMIT || \
@ -815,11 +816,17 @@ exn_toString(JSContext *cx, uintN argc, Value *vp)
return JS_FALSE;
if (name_length) {
js_strncpy(cp, name->chars(), name_length);
const jschar *name_chars = name->getChars(cx);
if (!name_chars)
return JS_FALSE;
js_strncpy(cp, name_chars, name_length);
cp += name_length;
*cp++ = ':'; *cp++ = ' ';
}
js_strncpy(cp, message->chars(), message_length);
const jschar *message_chars = message->getChars(cx);
if (!message_chars)
return JS_FALSE;
js_strncpy(cp, message_chars, message_length);
cp += message_length;
*cp = 0;
@ -919,18 +926,27 @@ exn_toSource(JSContext *cx, uintN argc, Value *vp)
return false;
*cp++ = '('; *cp++ = 'n'; *cp++ = 'e'; *cp++ = 'w'; *cp++ = ' ';
js_strncpy(cp, name->chars(), name_length);
const jschar *name_chars = name->getChars(cx);
if (!name_chars)
return false;
js_strncpy(cp, name_chars, name_length);
cp += name_length;
*cp++ = '(';
const jschar *message_chars = message->getChars(cx);
if (!message_chars)
return false;
if (message_length != 0) {
js_strncpy(cp, message->chars(), message_length);
js_strncpy(cp, message_chars, message_length);
cp += message_length;
}
if (filename_length != 0) {
/* append filename as ``, {filename}'' */
*cp++ = ','; *cp++ = ' ';
js_strncpy(cp, filename->chars(), filename_length);
const jschar *filename_chars = filename->getChars(cx);
if (!filename_chars)
return false;
js_strncpy(cp, filename_chars, filename_length);
cp += filename_length;
} else {
if (lineno_as_str) {
@ -944,7 +960,10 @@ exn_toSource(JSContext *cx, uintN argc, Value *vp)
if (lineno_as_str) {
/* append lineno as ``, {lineno_as_str}'' */
*cp++ = ','; *cp++ = ' ';
js_strncpy(cp, lineno_as_str->chars(), lineno_length);
const jschar *lineno_chars = lineno_as_str->getChars(cx);
if (!lineno_chars)
return false;
js_strncpy(cp, lineno_chars, lineno_length);
cp += lineno_length;
}

View File

@ -397,20 +397,20 @@ WrapEscapingClosure(JSContext *cx, JSStackFrame *fp, JSFunction *fun)
/* NB: GC must not occur before wscript is homed in wfun->u.i.script. */
JSScript *wscript = JSScript::NewScript(cx, script->length, nsrcnotes,
script->atomMap.length,
(script->objectsOffset != 0)
JSScript::isValidOffset(script->objectsOffset)
? script->objects()->length
: 0,
fun->u.i.nupvars,
(script->regexpsOffset != 0)
JSScript::isValidOffset(script->regexpsOffset)
? script->regexps()->length
: 0,
(script->trynotesOffset != 0)
JSScript::isValidOffset(script->trynotesOffset)
? script->trynotes()->length
: 0,
(script->constOffset != 0)
JSScript::isValidOffset(script->constOffset)
? script->consts()->length
: 0,
(script->globalsOffset != 0)
JSScript::isValidOffset(script->globalsOffset)
? script->globals()->length
: 0,
script->nClosedArgs,
@ -424,19 +424,19 @@ WrapEscapingClosure(JSContext *cx, JSStackFrame *fp, JSFunction *fun)
memcpy(wscript->notes(), snbase, nsrcnotes * sizeof(jssrcnote));
memcpy(wscript->atomMap.vector, script->atomMap.vector,
wscript->atomMap.length * sizeof(JSAtom *));
if (script->objectsOffset != 0) {
if (JSScript::isValidOffset(script->objectsOffset)) {
memcpy(wscript->objects()->vector, script->objects()->vector,
wscript->objects()->length * sizeof(JSObject *));
}
if (script->regexpsOffset != 0) {
if (JSScript::isValidOffset(script->regexpsOffset)) {
memcpy(wscript->regexps()->vector, script->regexps()->vector,
wscript->regexps()->length * sizeof(JSObject *));
}
if (script->trynotesOffset != 0) {
if (JSScript::isValidOffset(script->trynotesOffset)) {
memcpy(wscript->trynotes()->vector, script->trynotes()->vector,
wscript->trynotes()->length * sizeof(JSTryNote));
}
if (script->globalsOffset != 0) {
if (JSScript::isValidOffset(script->globalsOffset)) {
memcpy(wscript->globals()->vector, script->globals()->vector,
wscript->globals()->length * sizeof(GlobalSlotArray::Entry));
}
@ -611,27 +611,30 @@ args_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
JS_ASSERT(obj->isNormalArguments());
*objp = NULL;
bool valid = false;
uintN attrs = JSPROP_SHARED;
uintN attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
if (JSID_IS_INT(id)) {
uint32 arg = uint32(JSID_TO_INT(id));
attrs = JSPROP_ENUMERATE | JSPROP_SHARED;
if (arg < obj->getArgsInitialLength() && !obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE))
valid = true;
if (arg >= obj->getArgsInitialLength() || obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE))
return true;
attrs |= JSPROP_ENUMERATE;
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
if (!obj->isArgsLengthOverridden())
valid = true;
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)) {
if (!obj->getArgsCallee().isMagic(JS_ARGS_HOLE))
valid = true;
if (obj->isArgsLengthOverridden())
return true;
} else {
if (!JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom))
return true;
if (obj->getArgsCallee().isMagic(JS_ARGS_HOLE))
return true;
}
if (valid) {
Value tmp = UndefinedValue();
if (!js_DefineProperty(cx, obj, id, &tmp, ArgGetter, ArgSetter, attrs))
return JS_FALSE;
*objp = obj;
}
Value undef = UndefinedValue();
if (!js_DefineProperty(cx, obj, id, &undef, ArgGetter, ArgSetter, attrs))
return JS_FALSE;
*objp = obj;
return true;
}
@ -720,47 +723,35 @@ strictargs_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject
JS_ASSERT(obj->isStrictArguments());
*objp = NULL;
bool valid = false;
uintN attrs = JSPROP_SHARED;
uintN attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
PropertyOp getter = StrictArgGetter;
PropertyOp setter = StrictArgSetter;
if (JSID_IS_INT(id)) {
uint32 arg = uint32(JSID_TO_INT(id));
attrs = JSPROP_SHARED | JSPROP_ENUMERATE;
if (arg < obj->getArgsInitialLength() && !obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE))
valid = true;
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
if (!obj->isArgsLengthOverridden())
valid = true;
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)) {
Value tmp = UndefinedValue();
PropertyOp throwTypeError = CastAsPropertyOp(obj->getThrowTypeError());
uintN attrs = JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED;
if (!js_DefineProperty(cx, obj, id, &tmp, throwTypeError, throwTypeError, attrs))
return false;
if (arg >= obj->getArgsInitialLength() || obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE))
return true;
*objp = obj;
return true;
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.callerAtom)) {
/*
* Strict mode arguments objects have an immutable poison-pill caller
* property that throws a TypeError on getting or setting.
*/
PropertyOp throwTypeError = CastAsPropertyOp(obj->getThrowTypeError());
Value tmp = UndefinedValue();
if (!js_DefineProperty(cx, obj, id, &tmp, throwTypeError, throwTypeError,
JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED)) {
return false;
attrs |= JSPROP_ENUMERATE;
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
if (obj->isArgsLengthOverridden())
return true;
} else {
if (!JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom) &&
!JSID_IS_ATOM(id, cx->runtime->atomState.callerAtom)) {
return true;
}
*objp = obj;
return true;
attrs = JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED;
getter = setter = CastAsPropertyOp(obj->getThrowTypeError());
}
if (valid) {
Value tmp = UndefinedValue();
if (!js_DefineProperty(cx, obj, id, &tmp, StrictArgGetter, StrictArgSetter, attrs))
return false;
*objp = obj;
}
Value undef = UndefinedValue();
if (!js_DefineProperty(cx, obj, id, &undef, getter, setter, attrs))
return false;
*objp = obj;
return true;
}
@ -1714,10 +1705,6 @@ fun_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
JS_ASSERT(!IsInternalFunctionObject(obj));
JS_ASSERT(!obj->isBoundFunction());
/* No need to reflect fun.prototype in 'fun.prototype = ... '. */
if (flags & JSRESOLVE_ASSIGNING)
return true;
/*
* Make the prototype object an instance of Object with the same parent
* as the function object itself.
@ -1984,19 +1971,16 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
fun->freezeLocalNames(cx);
}
if (!js_XDRScript(xdr, &fun->u.i.script, false, NULL))
if (!js_XDRScript(xdr, &fun->u.i.script, NULL))
return false;
if (xdr->mode == JSXDR_DECODE) {
*objp = FUN_OBJECT(fun);
if (fun->u.i.script != JSScript::emptyScript()) {
#ifdef CHECK_SCRIPT_OWNER
fun->u.i.script->owner = NULL;
fun->script()->owner = NULL;
#endif
js_CallNewScriptHook(cx, fun->u.i.script, fun);
}
cx->setTypeFunctionScript(fun, fun->u.i.script);
js_CallNewScriptHook(cx, fun->script(), fun);
}
return true;
@ -2633,7 +2617,12 @@ Function(JSContext *cx, uintN argc, Value *vp)
for (uintN i = 0; i < n; i++) {
JSString *arg = argv[i].toString();
size_t arg_length = arg->length();
(void) js_strncpy(cp, arg->chars(), arg_length);
const jschar *arg_chars = arg->getChars(cx);
if (!arg_chars) {
JS_ARENA_RELEASE(&cx->tempPool, mark);
return JS_FALSE;
}
(void) js_strncpy(cp, arg_chars, arg_length);
cp += arg_length;
/* Add separating comma or terminating 0. */
@ -2720,8 +2709,11 @@ Function(JSContext *cx, uintN argc, Value *vp)
str = cx->runtime->emptyString;
}
JSBool res = Compiler::compileFunctionBody(cx, fun, principals,
str->chars(), str->length(),
size_t length = str->length();
const jschar *chars = str->getChars(cx);
if (!chars)
return JS_FALSE;
JSBool res = Compiler::compileFunctionBody(cx, fun, principals, chars, length,
filename, lineno);
if (res)
fun->u.i.script->setTypeNesting(caller->script(), caller->pc(cx));
@ -2748,7 +2740,18 @@ js_InitFunctionClass(JSContext *cx, JSObject *obj)
if (!fun)
return NULL;
fun->flags |= JSFUN_PROTOTYPE;
fun->u.i.script = JSScript::emptyScript();
JSScript *script = JSScript::NewScript(cx, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0);
if (!script)
return NULL;
script->setVersion(JSVERSION_DEFAULT);
script->noScriptRval = true;
script->code[0] = JSOP_STOP;
script->code[1] = SRC_NULL;
#ifdef CHECK_SCRIPT_OWNER
script->owner = NULL;
#endif
fun->u.i.script = script;
if (obj->getClass()->flags & JSCLASS_IS_GLOBAL) {
/* ES5 13.2.3: Construct the unique [[ThrowTypeError]] function object. */
@ -2877,18 +2880,16 @@ js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
if (cfun->isInterpreted()) {
JSScript *script = cfun->u.i.script;
JS_ASSERT(script);
if (script != JSScript::emptyScript()) {
JS_ASSERT(script->compartment == fun->compartment());
JS_ASSERT(script->compartment != cx->compartment);
cfun->u.i.script = js_CloneScript(cx, script);
if (!cfun->u.i.script)
return NULL;
JS_ASSERT(cfun->u.i.script != JSScript::emptyScript());
JS_ASSERT(script->compartment == fun->compartment());
JS_ASSERT(script->compartment != cx->compartment);
cfun->u.i.script = js_CloneScript(cx, script);
if (!cfun->u.i.script)
return NULL;
#ifdef CHECK_SCRIPT_OWNER
cfun->u.i.script->owner = NULL;
cfun->script()->owner = NULL;
#endif
js_CallNewScriptHook(cx, cfun->u.i.script, cfun);
}
js_CallNewScriptHook(cx, cfun->script(), cfun);
}
}
return clone;
@ -2908,7 +2909,7 @@ JSObject * JS_FASTCALL
js_AllocFlatClosure(JSContext *cx, JSFunction *fun, JSObject *scopeChain)
{
JS_ASSERT(FUN_FLAT_CLOSURE(fun));
JS_ASSERT((fun->u.i.script->upvarsOffset
JS_ASSERT((JSScript::isValidOffset(fun->u.i.script->upvarsOffset)
? fun->u.i.script->upvars()->length
: 0) == fun->u.i.nupvars);

View File

@ -435,6 +435,14 @@ IsFunctionObject(const js::Value &v, JSFunction **fun)
return b;
}
extern JS_ALWAYS_INLINE bool
SameTraceType(const Value &lhs, const Value &rhs)
{
return SameType(lhs, rhs) &&
(lhs.isPrimitive() ||
lhs.toObject().isFunction() == rhs.toObject().isFunction());
}
/*
* Macro to access the private slot of the function object after the slot is
* initialized.

View File

@ -492,6 +492,13 @@ js_GCThingIsMarked(void *thing, uint32 color = BLACK)
return reinterpret_cast<Cell *>(thing)->isMarked(color);
}
/*
* 1/8 life for JIT code. After this number of microseconds have passed, 1/8 of all
* JIT code is discarded in inactive compartments, regardless of how often that
* code runs.
*/
static const int64 JIT_SCRIPT_EIGHTH_LIFETIME = 120 * 1000 * 1000;
JSBool
js_InitGC(JSRuntime *rt, uint32 maxbytes)
{
@ -539,6 +546,8 @@ js_InitGC(JSRuntime *rt, uint32 maxbytes)
*/
rt->setGCLastBytes(8192);
rt->gcJitReleaseTime = PRMJ_Now() + JIT_SCRIPT_EIGHTH_LIFETIME;
METER(PodZero(&rt->gcStats));
return true;
}
@ -1435,8 +1444,10 @@ js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp)
MarkObject(trc, fp->callObj(), "call");
if (fp->hasArgsObj())
MarkObject(trc, fp->argsObj(), "arguments");
if (fp->isScriptFrame())
if (fp->isScriptFrame()) {
js_TraceScript(trc, fp->script());
fp->script()->compartment->active = true;
}
MarkValue(trc, fp->returnValue(), "rval");
}
@ -1773,7 +1784,7 @@ js_FinalizeStringRT(JSRuntime *rt, JSString *str)
JS_ASSERT(IsFinalizableStringKind(thingKind));
/* A stillborn string has null chars, so is not valid. */
jschar *chars = str->flatChars();
jschar *chars = const_cast<jschar *>(str->flatChars());
if (!chars)
return;
if (thingKind == FINALIZE_STRING) {
@ -2035,12 +2046,29 @@ SweepCompartments(JSContext *cx, JSGCInvocationKind gckind)
/* Delete defaultCompartment only during runtime shutdown */
rt->defaultCompartment->marked = true;
/*
* Figure out how much JIT code should be released from inactive compartments.
* If multiple eighth-lifes have passed, compound the release interval linearly;
* if enough time has passed, all inactive JIT code will be released.
*/
uint32 releaseInterval = 0;
int64 now = PRMJ_Now();
if (now >= rt->gcJitReleaseTime) {
releaseInterval = 8;
while (now >= rt->gcJitReleaseTime) {
if (--releaseInterval == 1)
rt->gcJitReleaseTime = now;
rt->gcJitReleaseTime += JIT_SCRIPT_EIGHTH_LIFETIME;
}
}
while (read < end) {
JSCompartment *compartment = (*read++);
if (compartment->marked) {
compartment->marked = false;
*write++ = compartment;
compartment->sweep(cx);
/* Remove dead wrappers from the compartment map. */
compartment->sweep(cx, releaseInterval);
} else {
JS_ASSERT(compartment->freeLists.isEmpty());
if (compartment->arenaListsAreEmpty() || gckind == GC_LAST_CONTEXT) {
@ -2052,7 +2080,7 @@ SweepCompartments(JSContext *cx, JSGCInvocationKind gckind)
} else {
compartment->marked = false;
*write++ = compartment;
compartment->sweep(cx);
compartment->sweep(cx, releaseInterval);
}
}
}

View File

@ -266,8 +266,6 @@ MarkChildren(JSTracer *trc, JSString *str)
if (str->isDependent())
MarkString(trc, str->dependentBase(), "base");
else if (str->isRope()) {
if (str->isInteriorNode())
MarkString(trc, str->interiorNodeParent(), "parent");
MarkString(trc, str->ropeLeft(), "left child");
MarkString(trc, str->ropeRight(), "right child");
}
@ -344,28 +342,108 @@ TypedMarker(JSTracer *trc, JSShortString *thing)
thing->asCell()->markIfUnmarked();
}
static JS_ALWAYS_INLINE void
TypedMarker(JSTracer *trc, JSString *thing)
} /* namespace gc */
namespace detail {
static JS_ALWAYS_INLINE JSString *
Tag(JSString *str)
{
JS_ASSERT(!(size_t(str) & 1));
return (JSString *)(size_t(str) | 1);
}
static JS_ALWAYS_INLINE bool
Tagged(JSString *str)
{
return (size_t(str) & 1) != 0;
}
static JS_ALWAYS_INLINE JSString *
Untag(JSString *str)
{
JS_ASSERT((size_t(str) & 1) == 1);
return (JSString *)(size_t(str) & ~size_t(1));
}
static JS_ALWAYS_INLINE void
NonRopeTypedMarker(JSString *str)
{
JS_ASSERT(!str->isRope());
if (JSString::isStatic(str) ||
!str->asCell()->markIfUnmarked() ||
!str->isDependent()) {
return;
}
JSString *base = str->dependentBase();
if (JSString::isStatic(base))
return;
base->asCell()->markIfUnmarked();
}
} /* namespace detail */
namespace gc {
static JS_ALWAYS_INLINE void
TypedMarker(JSTracer *trc, JSString *str)
{
using namespace detail;
if (!str->isRope()) {
NonRopeTypedMarker(str);
return;
}
/*
* Iterate through all nodes and leaves in the rope if this is part of a
* rope; otherwise, we only iterate once: on the string itself.
* This function must not fail, so a simple stack-based traversal must not
* be used (since it may oom if the stack grows large). Instead, strings
* are temporarily mutated to embed parent pointers as they are traversed.
* This algorithm is homomorphic to JSString::flatten.
*/
JSRopeNodeIterator iter(thing);
JSString *str = iter.init();
do {
for (;;) {
if (JSString::isStatic(str))
break;
JS_ASSERT(JSTRACE_STRING == GetFinalizableTraceKind(str->asCell()->arena()->header()->thingKind));
if (!str->asCell()->markIfUnmarked())
break;
if (!str->isDependent())
break;
str = str->dependentBase();
JSString *parent = NULL;
first_visit_node: {
if (!str->asCell()->markIfUnmarked())
goto finish_node;
JSString *left = str->ropeLeft();
if (left->isRope()) {
JS_ASSERT(!Tagged(str->u.left) && !Tagged(str->s.right));
str->u.left = Tag(parent);
parent = str;
str = left;
goto first_visit_node;
}
str = iter.next();
} while (str);
NonRopeTypedMarker(left);
}
visit_right_child: {
JSString *right = str->ropeRight();
if (right->isRope()) {
JS_ASSERT(!Tagged(str->u.left) && !Tagged(str->s.right));
str->s.right = Tag(parent);
parent = str;
str = right;
goto first_visit_node;
}
NonRopeTypedMarker(right);
}
finish_node: {
if (!parent)
return;
if (Tagged(parent->u.left)) {
JS_ASSERT(!Tagged(parent->s.right));
JSString *nextParent = Untag(parent->u.left);
parent->u.left = str;
str = parent;
parent = nextParent;
goto visit_right_child;
}
JS_ASSERT(Tagged(parent->s.right));
JSString *nextParent = Untag(parent->s.right);
parent->s.right = str;
str = parent;
parent = nextParent;
goto finish_node;
}
}
static inline void

Some files were not shown because too many files have changed in this diff Show More