Merge mozilla-central to tracemonkey.

This commit is contained in:
Chris Leary 2010-12-29 19:25:04 -05:00
Родитель 51c8be07cd 1647079040
Коммит 366ec4ad44
186 изменённых файлов: 5712 добавлений и 3448 удалений

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

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

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

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

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

@ -208,7 +208,11 @@ nsFrameMessageManager::GetParamsForMessage(nsAString& aMessageName,
JSAutoRequest ar(ctx); JSAutoRequest ar(ctx);
JSString* str; JSString* str;
if (argc && (str = JS_ValueToString(ctx, argv[0])) && 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) { if (argc >= 2) {

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

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

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

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

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

@ -140,7 +140,10 @@ nsHTMLAudioElement::Initialize(nsISupports* aOwner, JSContext* aContext,
if (!jsstr) if (!jsstr)
return NS_ERROR_FAILURE; 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); rv = SetAttr(kNameSpaceID_None, nsGkAtoms::src, str, PR_TRUE);
if (NS_FAILED(rv)) if (NS_FAILED(rv))
return rv; return rv;

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

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

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

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

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

@ -1094,78 +1094,85 @@ nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocumen
nsCxPusher pusher; nsCxPusher pusher;
pusher.Push(cx); pusher.Push(cx);
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper; nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
jsval v; nsIXPConnect *xpc = nsContentUtils::XPConnect();
nsresult rv = nsresult rv =
nsContentUtils::WrapNative(cx, scope, mBoundElement, &v, xpc->GetWrappedNativeOfNativeObject(cx, scope, mBoundElement,
getter_AddRefs(wrapper)); NS_GET_IID(nsISupports),
getter_AddRefs(wrapper));
if (NS_FAILED(rv)) if (NS_FAILED(rv))
return; 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 if (scriptObject) {
// <interface>?! // XXX Stay in sync! What if a layered binding has an
// XXXbz what does that comment mean, really? It seems to date // <interface>?!
// back to when there was such a thing as an <interface>, whever // XXXbz what does that comment mean, really? It seems to date
// that was... // back to when there was such a thing as an <interface>, whever
// that was...
// Find the right prototype. // Find the right prototype.
JSObject* base = scriptObject; JSObject* base = scriptObject;
JSObject* proto; JSObject* proto;
JSAutoRequest ar(cx); JSAutoRequest ar(cx);
JSAutoEnterCompartment ac; JSAutoEnterCompartment ac;
if (!ac.enter(cx, scriptObject)) { if (!ac.enter(cx, scriptObject)) {
return; return;
} }
for ( ; true; base = proto) { // Will break out on null proto for ( ; true; base = proto) { // Will break out on null proto
proto = ::JS_GetPrototype(cx, base); proto = ::JS_GetPrototype(cx, base);
if (!proto) { 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; break;
} }
JSClass* clazz = ::JS_GET_CLASS(cx, proto); mPrototypeBinding->UndefineFields(cx, scriptObject);
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 = // Don't remove the reference from the document to the
static_cast<nsXBLDocumentInfo*>(::JS_GetPrivate(cx, proto)); // wrapper here since it'll be removed by the element
if (!docInfo) { // itself when that's taken out of the document.
// 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;
} }
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.
} }
} }
} }

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

@ -89,6 +89,11 @@ CPPSRCS += txMozillaStylesheetCompiler.cpp \
txMozillaXSLTProcessor.cpp txMozillaXSLTProcessor.cpp
endif 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 # we don't want the shared lib, but we want to force the creation of a
# static lib. # static lib.
FORCE_STATIC_LIB = 1 FORCE_STATIC_LIB = 1

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

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

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

@ -5086,7 +5086,6 @@ nsWindowSH::GlobalScopePolluterNewResolve(JSContext *cx, JSObject *obj,
} }
JSObject *proto = ::JS_GetPrototype(cx, obj); JSObject *proto = ::JS_GetPrototype(cx, obj);
JSString *jsstr = JSID_TO_STRING(id);
JSBool hasProp; JSBool hasProp;
if (!proto || !::JS_HasPropertyById(cx, proto, id, &hasProp) || if (!proto || !::JS_HasPropertyById(cx, proto, id, &hasProp) ||
@ -5097,7 +5096,7 @@ nsWindowSH::GlobalScopePolluterNewResolve(JSContext *cx, JSObject *obj,
return JS_TRUE; return JS_TRUE;
} }
nsDependentJSString str(jsstr); nsDependentJSString str(id);
nsCOMPtr<nsISupports> result; nsCOMPtr<nsISupports> result;
nsWrapperCache *cache; nsWrapperCache *cache;
{ {
@ -5436,7 +5435,10 @@ nsWindowSH::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
vp, getter_AddRefs(holder)); vp, getter_AddRefs(holder));
NS_ENSURE_SUCCESS(rv, rv); 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; return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
} }
@ -6291,14 +6293,14 @@ ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx,
// static // static
nsresult nsresult
nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx, nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
JSObject *obj, JSString *str, PRBool *did_resolve) JSObject *obj, jsid id, PRBool *did_resolve)
{ {
*did_resolve = PR_FALSE; *did_resolve = PR_FALSE;
nsScriptNameSpaceManager *nameSpaceManager = nsJSRuntime::GetNameSpaceManager(); nsScriptNameSpaceManager *nameSpaceManager = nsJSRuntime::GetNameSpaceManager();
NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED); NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
nsDependentJSString name(str); nsDependentJSString name(id);
const nsGlobalNameStruct *name_struct = nsnull; const nsGlobalNameStruct *name_struct = nsnull;
const PRUnichar *class_name = nsnull; const PRUnichar *class_name = nsnull;
@ -6515,10 +6517,8 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
JSBool ok = ::JS_DefineUCProperty(cx, obj, ::JS_GetStringChars(str), JSBool ok = ::JS_DefinePropertyById(cx, obj, id, prop_val, nsnull, nsnull,
::JS_GetStringLength(str), JSPROP_ENUMERATE);
prop_val, nsnull, nsnull,
JSPROP_ENUMERATE);
*did_resolve = PR_TRUE; *did_resolve = PR_TRUE;
@ -6677,8 +6677,6 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
// method on an interface that would let us just call into the // method on an interface that would let us just call into the
// window code directly... // window code directly...
JSString *str = JSID_TO_STRING(id);
if (!xpc::WrapperFactory::IsXrayWrapper(obj) || if (!xpc::WrapperFactory::IsXrayWrapper(obj) ||
xpc::WrapperFactory::IsPartiallyTransparent(obj)) { xpc::WrapperFactory::IsPartiallyTransparent(obj)) {
nsCOMPtr<nsIDocShellTreeNode> dsn(do_QueryInterface(win->GetDocShell())); nsCOMPtr<nsIDocShellTreeNode> dsn(do_QueryInterface(win->GetDocShell()));
@ -6692,7 +6690,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
if (count > 0) { if (count > 0) {
nsCOMPtr<nsIDocShellTreeItem> child; 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), dsn->FindChildWithName(reinterpret_cast<const PRUnichar*>(chars),
PR_FALSE, PR_TRUE, nsnull, nsnull, PR_FALSE, PR_TRUE, nsnull, nsnull,
@ -6741,7 +6739,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
// which have been registered with the script namespace manager. // which have been registered with the script namespace manager.
JSBool did_resolve = JS_FALSE; 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); NS_ENSURE_SUCCESS(rv, rv);
if (did_resolve) { if (did_resolve) {
@ -8414,7 +8412,10 @@ nsDocumentSH::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSString *val = ::JS_ValueToString(cx, *vp); JSString *val = ::JS_ValueToString(cx, *vp);
NS_ENSURE_TRUE(val, NS_ERROR_UNEXPECTED); 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); NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIXPConnectJSObjectHolder> holder; nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
@ -8503,7 +8504,10 @@ ResolveImpl(JSContext *cx, nsIXPConnectWrappedNative *wrapper, jsid id,
JSString *str = IdToString(cx, id); JSString *str = IdToString(cx, id);
NS_ENSURE_TRUE(str, NS_ERROR_UNEXPECTED); 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 // static
@ -8541,8 +8545,13 @@ nsHTMLDocumentSH::DocumentOpen(JSContext *cx, uintN argc, jsval *vp)
nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_OUT_OF_MEMORY); nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_OUT_OF_MEMORY);
return JS_FALSE; return JS_FALSE;
} }
nsDependentJSString depStr;
if (!depStr.init(cx, jsstr)) {
nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_OUT_OF_MEMORY);
return JS_FALSE;
}
nsAutoString type; nsAutoString type;
type.Assign(nsDependentJSString(jsstr)); type.Assign(depStr);
ToLowerCase(type); ToLowerCase(type);
nsCAutoString actualType, dummy; nsCAutoString actualType, dummy;
NS_ParseContentType(NS_ConvertUTF16toUTF8(type), actualType, dummy); NS_ParseContentType(NS_ConvertUTF16toUTF8(type), actualType, dummy);
@ -8560,9 +8569,13 @@ nsHTMLDocumentSH::DocumentOpen(JSContext *cx, uintN argc, jsval *vp)
return JS_FALSE; return JS_FALSE;
} }
replace = NS_LITERAL_STRING("replace"). const jschar *chars = ::JS_GetStringCharsZ(cx, jsstr);
Equals(reinterpret_cast<const PRUnichar*> if (!chars) {
(::JS_GetStringChars(jsstr))); nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_OUT_OF_MEMORY);
return JS_FALSE;
}
replace = NS_LITERAL_STRING("replace").Equals(chars);
} }
nsCOMPtr<nsIDOMDocument> retval; nsCOMPtr<nsIDOMDocument> retval;
@ -8883,8 +8896,13 @@ nsHTMLDocumentSH::CallToGetPropMapper(JSContext *cx, uintN argc, jsval *vp)
self = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)); self = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));
} }
return ::JS_GetUCProperty(cx, self, ::JS_GetStringChars(str), size_t length;
::JS_GetStringLength(str), vp); const jschar *chars = ::JS_GetStringCharsAndLength(cx, str, &length);
if (!chars) {
return JS_FALSE;
}
return ::JS_GetUCProperty(cx, self, chars, length, vp);
} }
@ -9004,8 +9022,6 @@ nsHTMLDocumentSH::DocumentAllTagsNewResolve(JSContext *cx, JSObject *obj,
if (JSID_IS_STRING(id)) { if (JSID_IS_STRING(id)) {
nsDocument *doc = GetDocument(cx, obj); nsDocument *doc = GetDocument(cx, obj);
JSString *str = JSID_TO_STRING(id);
JSObject *proto = ::JS_GetPrototype(cx, obj); JSObject *proto = ::JS_GetPrototype(cx, obj);
if (NS_UNLIKELY(!proto)) { if (NS_UNLIKELY(!proto)) {
return JS_TRUE; return JS_TRUE;
@ -9021,7 +9037,7 @@ nsHTMLDocumentSH::DocumentAllTagsNewResolve(JSContext *cx, JSObject *obj,
} }
nsRefPtr<nsContentList> tags = nsRefPtr<nsContentList> tags =
doc->GetElementsByTagName(nsDependentJSString(str)); doc->GetElementsByTagName(nsDependentJSString(id));
if (tags) { if (tags) {
jsval v; jsval v;
@ -9193,11 +9209,11 @@ nsHTMLDocumentSH::GetProperty(nsIXPConnectWrappedNative *wrapper,
// static // static
nsresult nsresult
nsHTMLFormElementSH::FindNamedItem(nsIForm *aForm, JSString *str, nsHTMLFormElementSH::FindNamedItem(nsIForm *aForm, jsid id,
nsISupports **aResult, nsISupports **aResult,
nsWrapperCache **aCache) nsWrapperCache **aCache)
{ {
nsDependentJSString name(str); nsDependentJSString name(id);
*aResult = aForm->ResolveName(name).get(); *aResult = aForm->ResolveName(name).get();
// FIXME Get the wrapper cache from nsIForm::ResolveName // FIXME Get the wrapper cache from nsIForm::ResolveName
@ -9231,8 +9247,7 @@ nsHTMLFormElementSH::NewResolve(nsIXPConnectWrappedNative *wrapper,
nsCOMPtr<nsISupports> result; nsCOMPtr<nsISupports> result;
nsWrapperCache *cache; nsWrapperCache *cache;
JSString *str = JSID_TO_STRING(id); FindNamedItem(form, id, getter_AddRefs(result), &cache);
FindNamedItem(form, str, getter_AddRefs(result), &cache);
if (result) { if (result) {
JSAutoRequest ar(cx); JSAutoRequest ar(cx);
@ -9262,8 +9277,7 @@ nsHTMLFormElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper,
nsCOMPtr<nsISupports> result; nsCOMPtr<nsISupports> result;
nsWrapperCache *cache; nsWrapperCache *cache;
JSString *str = JSID_TO_STRING(id); FindNamedItem(form, id, getter_AddRefs(result), &cache);
FindNamedItem(form, str, getter_AddRefs(result), &cache);
if (result) { if (result) {
// Wrap result, result can be either an element or a list of // Wrap result, result can be either an element or a list of
@ -10207,11 +10221,14 @@ nsStorageSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
if (!jsstr) if (!jsstr)
return JS_FALSE; 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 // GetItem() will return null if the caller can't access the session
// storage item. // storage item.
nsCOMPtr<nsIDOMStorageItem> item; nsCOMPtr<nsIDOMStorageItem> item;
nsresult rv = storage->GetItem(nsDependentJSString(jsstr), nsresult rv = storage->GetItem(depStr, getter_AddRefs(item));
getter_AddRefs(item));
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
if (item) { if (item) {
@ -10246,11 +10263,16 @@ nsStorageSH::SetProperty(nsIXPConnectWrappedNative *wrapper,
JSString *key = IdToString(cx, id); JSString *key = IdToString(cx, id);
NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED); 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); JSString *value = ::JS_ValueToString(cx, *vp);
NS_ENSURE_TRUE(value, NS_ERROR_UNEXPECTED); NS_ENSURE_TRUE(value, NS_ERROR_UNEXPECTED);
nsresult rv = storage->SetItem(nsDependentJSString(key), nsDependentJSString valueStr;
nsDependentJSString(value)); NS_ENSURE_TRUE(valueStr.init(cx, value), NS_ERROR_UNEXPECTED);
nsresult rv = storage->SetItem(keyStr, valueStr);
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv)) {
rv = NS_SUCCESS_I_DID_SOMETHING; rv = NS_SUCCESS_I_DID_SOMETHING;
} }
@ -10269,7 +10291,10 @@ nsStorageSH::DelProperty(nsIXPConnectWrappedNative *wrapper,
JSString *key = IdToString(cx, id); JSString *key = IdToString(cx, id);
NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED); 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)) { if (NS_SUCCEEDED(rv)) {
rv = NS_SUCCESS_I_DID_SOMETHING; rv = NS_SUCCESS_I_DID_SOMETHING;
} }
@ -10368,10 +10393,13 @@ nsStorage2SH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
nsCOMPtr<nsIDOMStorage> storage(do_QueryWrappedNative(wrapper)); 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 // GetItem() will return null if the caller can't access the session
// storage item. // storage item.
nsAutoString data; nsAutoString data;
nsresult rv = storage->GetItem(nsDependentJSString(jsstr), data); nsresult rv = storage->GetItem(depStr, data);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
if (!DOMStringIsNull(data)) { if (!DOMStringIsNull(data)) {
@ -10440,11 +10468,16 @@ nsStorage2SH::SetProperty(nsIXPConnectWrappedNative *wrapper,
JSString *key = IdToString(cx, id); JSString *key = IdToString(cx, id);
NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED); 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); JSString *value = ::JS_ValueToString(cx, *vp);
NS_ENSURE_TRUE(value, NS_ERROR_UNEXPECTED); NS_ENSURE_TRUE(value, NS_ERROR_UNEXPECTED);
nsresult rv = storage->SetItem(nsDependentJSString(key), nsDependentJSString valueStr;
nsDependentJSString(value)); NS_ENSURE_TRUE(valueStr.init(cx, value), NS_ERROR_UNEXPECTED);
nsresult rv = storage->SetItem(keyStr, valueStr);
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv)) {
rv = NS_SUCCESS_I_DID_SOMETHING; rv = NS_SUCCESS_I_DID_SOMETHING;
} }
@ -10463,7 +10496,10 @@ nsStorage2SH::DelProperty(nsIXPConnectWrappedNative *wrapper,
JSString *key = IdToString(cx, id); JSString *key = IdToString(cx, id);
NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED); 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)) { if (NS_SUCCEEDED(rv)) {
rv = NS_SUCCESS_I_DID_SOMETHING; rv = NS_SUCCESS_I_DID_SOMETHING;
} }

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

@ -463,7 +463,7 @@ protected:
{ {
NS_ASSERTION(JSID_IS_STRING(id), "Don't pass non-string jsid's here!"); 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') { if (str[0] == 'o' && str[1] == 'n') {
return ReallyIsEventName(id, str[2]); return ReallyIsEventName(id, str[2]);
@ -528,8 +528,7 @@ protected:
} }
static nsresult GlobalResolve(nsGlobalWindow *aWin, JSContext *cx, static nsresult GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
JSObject *obj, JSString *str, JSObject *obj, jsid id, PRBool *did_resolve);
PRBool *did_resolve);
public: public:
NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx, NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
@ -1046,7 +1045,7 @@ protected:
{ {
} }
static nsresult FindNamedItem(nsIForm *aForm, JSString *str, static nsresult FindNamedItem(nsIForm *aForm, jsid id,
nsISupports **aResult, nsWrapperCache **aCache); nsISupports **aResult, nsWrapperCache **aCache);
public: public:

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

@ -724,8 +724,13 @@ static JSBool
ChangeCase(JSContext *cx, JSString *src, jsval *rval, ChangeCase(JSContext *cx, JSString *src, jsval *rval,
void(* changeCaseFnc)(const nsAString&, nsAString&)) void(* changeCaseFnc)(const nsAString&, nsAString&))
{ {
nsDependentJSString depStr;
if (!depStr.init(cx, src)) {
return JS_FALSE;
}
nsAutoString result; nsAutoString result;
changeCaseFnc(nsDependentJSString(src), result); changeCaseFnc(depStr, result);
JSString *ucstr = JS_NewUCStringCopyN(cx, (jschar*)result.get(), result.Length()); JSString *ucstr = JS_NewUCStringCopyN(cx, (jschar*)result.get(), result.Length());
if (!ucstr) { 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; PRInt32 result;
rv = gCollation->CompareString(nsICollation::kCollationStrengthDefault, rv = gCollation->CompareString(nsICollation::kCollationStrengthDefault,
nsDependentJSString(src1), depStr1, depStr2, &result);
nsDependentJSString(src2),
&result);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
nsDOMClassInfo::ThrowJSException(cx, rv); nsDOMClassInfo::ThrowJSException(cx, rv);
@ -1591,27 +1599,36 @@ JSValueToAString(JSContext *cx, jsval val, nsAString *result,
} }
JSString* jsstring = ::JS_ValueToString(cx, val); JSString* jsstring = ::JS_ValueToString(cx, val);
if (jsstring) { if (!jsstring) {
result->Assign(reinterpret_cast<const PRUnichar*> goto error;
(::JS_GetStringChars(jsstring)), }
::JS_GetStringLength(jsstring));
} else {
result->Truncate();
// We failed to convert val to a string. We're either OOM, or the size_t length;
// security manager denied access to .toString(), or somesuch, on const jschar *chars;
// an object. Treat this case as if the result were undefined. chars = ::JS_GetStringCharsAndLength(cx, jsstring, &length);
if (!chars) {
goto error;
}
if (isUndefined) { result->Assign(chars, length);
*isUndefined = PR_TRUE; return NS_OK;
}
if (!::JS_IsExceptionPending(cx)) { error:
// JS_ValueToString() returned null w/o an exception // We failed to convert val to a string. We're either OOM, or the
// pending. That means we're OOM. // 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; return NS_OK;

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

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

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

@ -85,23 +85,44 @@ public:
class nsDependentJSString : public nsDependentString class nsDependentJSString : public nsDependentString
{ {
public: public:
explicit nsDependentJSString(jsval v) /**
: nsDependentString((PRUnichar *)::JS_GetStringChars(JSVAL_TO_STRING(v)), * In the case of string ids, getting the string's chars is infallible, so
::JS_GetStringLength(JSVAL_TO_STRING(v))) * the dependent string can be constructed directly.
{ */
}
explicit nsDependentJSString(jsid id) explicit nsDependentJSString(jsid id)
: nsDependentString((PRUnichar *)::JS_GetStringChars(JSID_TO_STRING(id)), : nsDependentString(JS_GetInternedStringChars(JSID_TO_STRING(id)),
::JS_GetStringLength(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() ~nsDependentJSString()
{ {
} }

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

@ -447,7 +447,7 @@ IDBCursor::Continue(const jsval &aKey,
} }
Key key; Key key;
nsresult rv = IDBObjectStore::GetKeyFromJSVal(aKey, key); nsresult rv = IDBObjectStore::GetKeyFromJSVal(aKey, aCx, key);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
if (!key.IsUnset()) { if (!key.IsUnset()) {
@ -555,7 +555,7 @@ IDBCursor::Update(const jsval& aValue,
NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
Key key; Key key;
rv = IDBObjectStore::GetKeyFromJSVal(prop, key); rv = IDBObjectStore::GetKeyFromJSVal(prop, aCx, key);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
return rv; return rv;
} }

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

@ -590,7 +590,12 @@ IDBDatabase::CreateObjectStore(const nsAString& aName,
NS_WARNING("JS_ValueToString failed!"); NS_WARNING("JS_ValueToString failed!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
} }
keyPath = nsDependentJSString(str); nsDependentJSString dependentKeyPath;
if (!dependentKeyPath.init(aCx, str)) {
NS_WARNING("Initializing keyPath failed!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
keyPath = dependentKeyPath;
} }
else if (id == nsDOMClassInfo::sAutoIncrement_id) { else if (id == nsDOMClassInfo::sAutoIncrement_id) {
JSBool boolVal; JSBool boolVal;

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

@ -366,7 +366,7 @@ GetKeyFromObject(JSContext* aCx,
JSBool ok = JS_GetUCProperty(aCx, aObj, keyPathChars, keyPathLen, &key); JSBool ok = JS_GetUCProperty(aCx, aObj, keyPathChars, keyPathLen, &key);
NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
nsresult rv = IDBObjectStore::GetKeyFromJSVal(key, aKey); nsresult rv = IDBObjectStore::GetKeyFromJSVal(key, aCx, aKey);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
return NS_OK; return NS_OK;
@ -448,13 +448,18 @@ IDBObjectStore::GetKeyFromVariant(nsIVariant* aKeyVariant,
// static // static
nsresult nsresult
IDBObjectStore::GetKeyFromJSVal(jsval aKeyVal, IDBObjectStore::GetKeyFromJSVal(jsval aKeyVal,
JSContext* aCx,
Key& aKey) Key& aKey)
{ {
if (JSVAL_IS_VOID(aKeyVal)) { if (JSVAL_IS_VOID(aKeyVal)) {
aKey = Key::UNSETKEY; aKey = Key::UNSETKEY;
} }
else if (JSVAL_IS_STRING(aKeyVal)) { 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)) { else if (JSVAL_IS_INT(aKeyVal)) {
aKey = JSVAL_TO_INT(aKeyVal); aKey = JSVAL_TO_INT(aKeyVal);
@ -548,7 +553,7 @@ IDBObjectStore::GetKeyPathValueFromStructuredData(const PRUint8* aData,
JSBool ok = JS_GetUCProperty(cx, obj, keyPathChars, keyPathLen, &keyVal); JSBool ok = JS_GetUCProperty(cx, obj, keyPathChars, keyPathLen, &keyVal);
NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = GetKeyFromJSVal(keyVal, aValue); rv = GetKeyFromJSVal(keyVal, *aCx, aValue);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
// If the object doesn't have a value that we can use for our index then we // If the object doesn't have a value that we can use for our index then we
// leave it unset. // leave it unset.
@ -589,7 +594,7 @@ IDBObjectStore::GetIndexUpdateInfo(ObjectStoreInfo* aObjectStoreInfo,
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
Key value; Key value;
nsresult rv = GetKeyFromJSVal(keyPathValue, value); nsresult rv = GetKeyFromJSVal(keyPathValue, aCx, value);
if (NS_FAILED(rv) || value.IsUnset()) { if (NS_FAILED(rv) || value.IsUnset()) {
// Not a value we can do anything with, ignore it. // Not a value we can do anything with, ignore it.
continue; continue;
@ -819,7 +824,7 @@ IDBObjectStore::GetAddInfo(JSContext* aCx,
if (mKeyPath.IsEmpty()) { if (mKeyPath.IsEmpty()) {
// Out-of-line keys must be passed in. // Out-of-line keys must be passed in.
rv = GetKeyFromJSVal(aKeyVal, aKey); rv = GetKeyFromJSVal(aKeyVal, aCx, aKey);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
} }
else { else {
@ -1140,7 +1145,7 @@ IDBObjectStore::Delete(const jsval& aKey,
} }
Key key; Key key;
nsresult rv = GetKeyFromJSVal(aKey, key); nsresult rv = GetKeyFromJSVal(aKey, aCx, key);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
return rv; return rv;
} }

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

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

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

@ -335,7 +335,14 @@ nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel,
if (!isUndefined && NS_SUCCEEDED(rv)) { if (!isUndefined && NS_SUCCEEDED(rv)) {
NS_ASSERTION(JSVAL_IS_STRING(rval), "evalInSandbox is broken"); 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); stack->Pop(nsnull);

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

@ -142,9 +142,11 @@ nsDOMWorkerFunctions::Dump(JSContext* aCx,
JSString* str; JSString* str;
if (aArgc && (str = JS_ValueToString(aCx, JS_ARGV(aCx, aVp)[0])) && str) { if (aArgc && (str = JS_ValueToString(aCx, JS_ARGV(aCx, aVp)[0])) && str) {
nsDependentJSString string(str); nsDependentJSString depStr;
fputs(NS_ConvertUTF16toUTF8(nsDependentJSString(str)).get(), stderr); if (depStr.init(aCx, str)) {
fflush(stderr); fputs(NS_ConvertUTF16toUTF8(depStr).get(), stderr);
fflush(stderr);
}
} }
return JS_TRUE; return JS_TRUE;
} }
@ -268,7 +270,12 @@ nsDOMWorkerFunctions::LoadScripts(JSContext* aCx,
nsString* newURL = urls.AppendElement(); nsString* newURL = urls.AppendElement();
NS_ASSERTION(newURL, "Shouldn't fail if SetCapacity succeeded above!"); 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 = nsRefPtr<nsDOMWorkerScriptLoader> loader =
@ -507,8 +514,7 @@ nsDOMWorkerFunctions::CTypesLazyGetter(JSContext* aCx,
{ {
NS_ASSERTION(JS_GetGlobalForObject(aCx, aObj) == aObj, "Bad object!"); NS_ASSERTION(JS_GetGlobalForObject(aCx, aObj) == aObj, "Bad object!");
NS_ASSERTION(JSID_IS_STRING(aId), "Not a string!"); NS_ASSERTION(JSID_IS_STRING(aId), "Not a string!");
JSString* str = JSID_TO_STRING(aId); NS_ASSERTION(nsDependentJSString(aId).EqualsLiteral("ctypes"), "Bad id!");
NS_ASSERTION(nsDependentJSString(str).EqualsLiteral("ctypes"), "Bad id!");
} }
#endif #endif
nsDOMWorker* worker = static_cast<nsDOMWorker*>(JS_GetContextPrivate(aCx)); nsDOMWorker* worker = static_cast<nsDOMWorker*>(JS_GetContextPrivate(aCx));
@ -674,14 +680,14 @@ nsDOMWorkerScope::AddProperty(nsIXPConnectWrappedNative* aWrapper,
return NS_OK; return NS_OK;
} }
JSString *str = JSID_TO_STRING(aId); JSFlatString *str = JSID_TO_FLAT_STRING(aId);
// Figure out which listener we're setting. // Figure out which listener we're setting.
SetListenerFunc func; SetListenerFunc func;
if (JS_MatchStringAndAscii(str, "onmessage")) { if (JS_FlatStringEqualsAscii(str, "onmessage")) {
func = &nsDOMWorkerScope::SetOnmessage; func = &nsDOMWorkerScope::SetOnmessage;
} }
else if (JS_MatchStringAndAscii(str, "onerror")) { else if (JS_FlatStringEqualsAscii(str, "onerror")) {
func = &nsDOMWorkerScope::SetOnerror; func = &nsDOMWorkerScope::SetOnerror;
} }
else { else {
@ -1302,7 +1308,10 @@ nsDOMWorker::InitializeInternal(nsIScriptGlobalObject* aOwner,
JSString* str = JS_ValueToString(aCx, aArgv[0]); JSString* str = JS_ValueToString(aCx, aArgv[0]);
NS_ENSURE_TRUE(str, NS_ERROR_XPC_BAD_CONVERT_JS); 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); NS_ENSURE_FALSE(mScriptURL.IsEmpty(), NS_ERROR_INVALID_ARG);
mLock = nsAutoLock::NewLock("nsDOMWorker::mLock"); mLock = nsAutoLock::NewLock("nsDOMWorker::mLock");

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

@ -196,11 +196,10 @@ nsDOMWorkerTimeout::ExpressionCallback::Run(nsDOMWorkerTimeout* aTimeout,
JSString* expression = JS_ValueToString(aCx, mExpression); JSString* expression = JS_ValueToString(aCx, mExpression);
NS_ENSURE_TRUE(expression, NS_ERROR_FAILURE); 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); NS_ENSURE_TRUE(string, NS_ERROR_FAILURE);
size_t stringLength = JS_GetStringLength(expression);
jsval rval; jsval rval;
PRBool success = JS_EvaluateUCScriptForPrincipals(aCx, global, principal, PRBool success = JS_EvaluateUCScriptForPrincipals(aCx, global, principal,
string, stringLength, string, stringLength,

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -78,7 +78,7 @@ interface jsdIActivationCallback;
* Debugger service. It's not a good idea to have more than one active client of * Debugger service. It's not a good idea to have more than one active client of
* the debugger service. * the debugger service.
*/ */
[scriptable, uuid(01769775-c77c-47f9-8848-0abbab404215)] [scriptable, uuid(1ad86ef3-5eca-4ed7-81c5-a757d1957dff)]
interface jsdIDebuggerService : nsISupports interface jsdIDebuggerService : nsISupports
{ {
/** Internal use only. */ /** Internal use only. */
@ -512,7 +512,7 @@ interface jsdIFilterEnumerator : nsISupports
/** /**
* Pass an instance of one of these to jsdIDebuggerService::enumerateScripts. * 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 interface jsdIScriptEnumerator : nsISupports
{ {
/** /**
@ -525,7 +525,7 @@ interface jsdIScriptEnumerator : nsISupports
/** /**
* Pass an instance of one of these to jsdIDebuggerService::enumerateContexts. * 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 interface jsdIContextEnumerator : nsISupports
{ {
/** /**
@ -538,7 +538,7 @@ interface jsdIContextEnumerator : nsISupports
/** /**
* Set jsdIDebuggerService::scriptHook to an instance of one of these. * 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 interface jsdIScriptHook : nsISupports
{ {
/** /**
@ -556,7 +556,7 @@ interface jsdIScriptHook : nsISupports
* Hook instances of this interface up to the * Hook instances of this interface up to the
* jsdIDebuggerService::functionHook and toplevelHook properties. * jsdIDebuggerService::functionHook and toplevelHook properties.
*/ */
[scriptable, uuid(191d2738-22e8-4756-b366-6c878c87d73b)] [scriptable, uuid(3eff1314-7ae3-4cf8-833b-c33c24a55633)]
interface jsdICallHook : nsISupports interface jsdICallHook : nsISupports
{ {
/** /**
@ -588,7 +588,7 @@ interface jsdICallHook : nsISupports
void onCall (in jsdIStackFrame frame, in unsigned long type); 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 interface jsdIErrorHook : nsISupports
{ {
/** /**
@ -880,7 +880,7 @@ interface jsdIStackFrame : jsdIEphemeral
* Script object. In JavaScript engine terms, there's a single script for each * Script object. In JavaScript engine terms, there's a single script for each
* function, and one for the top level script. * 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 interface jsdIScript : jsdIEphemeral
{ {
/** Internal use only. */ /** Internal use only. */
@ -1038,6 +1038,10 @@ interface jsdIScript : jsdIEphemeral
* Clear all breakpoints set in this script. * Clear all breakpoints set in this script.
*/ */
void clearAllBreakpoints (); 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 * jsdIValue adds a root for the underlying JavaScript value, so don't keep it
* if you don't need to. * if you don't need to.
*/ */
[scriptable, uuid(9cab158f-dc78-41dd-9d11-79e05cb3f2bd)] [scriptable, uuid(fd1311f7-096c-44a3-847b-9d478c8176c3)]
interface jsdIValue : jsdIEphemeral interface jsdIValue : jsdIEphemeral
{ {
/** Internal use only. */ /** Internal use only. */
@ -1192,7 +1196,7 @@ interface jsdIValue : jsdIEphemeral
* functions from jsdIValue should move to this interface. We could inherit from * functions from jsdIValue should move to this interface. We could inherit from
* jsdIValue or use interface flattening or something. * jsdIValue or use interface flattening or something.
*/ */
[scriptable, uuid(a735a94c-9d41-4997-8fcb-cfa8b649a5b7)] [scriptable, uuid(87d86308-7a27-4255-b23c-ce2394f02473)]
interface jsdIObject : nsISupports interface jsdIObject : nsISupports
{ {
/** Internal use only. */ /** Internal use only. */
@ -1228,7 +1232,7 @@ interface jsdIObject : nsISupports
* Representation of a property of an object. When an instance is invalid, all * Representation of a property of an object. When an instance is invalid, all
* method and property access will result in a NS_UNAVAILABLE error. * 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 interface jsdIProperty : jsdIEphemeral
{ {
/** Internal use only. */ /** Internal use only. */

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

@ -40,6 +40,7 @@
*/ */
#include "jsd.h" #include "jsd.h"
#include "jsfriendapi.h"
/* Comment this out to disable (NT specific) dumping as we go */ /* Comment this out to disable (NT specific) dumping as we go */
/* /*
@ -214,7 +215,8 @@ _dumpJSDScript(JSDContext* jsdc, JSDScript* jsdscript, const char* leadingtext)
if (fun) { if (fun) {
n += size_t(snprintf(Buf + n, sizeof(Buf) - n, "%s", "no fun")); n += size_t(snprintf(Buf + n, sizeof(Buf) - n, "%s", "no fun"));
} else { } 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'; Buf[sizeof(Buf) - 1] = '\0';
} }
if (n + 1 < sizeof(Buf)) if (n + 1 < sizeof(Buf))
@ -503,7 +505,9 @@ jsd_GetScriptFunctionName(JSDContext* jsdc, JSDScript *jsdscript)
if( ! jsdscript->function ) if( ! jsdscript->function )
return NULL; return NULL;
str = JS_GetFunctionId(jsdscript->function); str = JS_GetFunctionId(jsdscript->function);
return str ? str : JS_GetEmptyString(jsdc->jsrt);
/* For compatibility we return "anonymous", not an empty string here. */
return str ? str : JS_GetAnonymousString(jsdc->jsrt);
} }
uintN uintN
@ -587,6 +591,17 @@ jsd_GetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc* hook, void** callerdata)
return JS_TRUE; 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 void
@ -751,7 +766,7 @@ jsd_TrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval,
} }
JSD_ASSERT_VALID_EXEC_HOOK(jsdhook); 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->script == script);
JS_ASSERT(jsdhook->jsdscript->jsdc == jsdc); JS_ASSERT(jsdhook->jsdscript->jsdc == jsdc);

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

@ -40,6 +40,7 @@
*/ */
#include "jsd.h" #include "jsd.h"
#include "jsfriendapi.h"
#ifdef DEBUG #ifdef DEBUG
void JSD_ASSERT_VALID_THREAD_STATE(JSDThreadState* jsdthreadstate) void JSD_ASSERT_VALID_THREAD_STATE(JSDThreadState* jsdthreadstate)
@ -369,8 +370,17 @@ jsd_GetNameForStackFrame(JSDContext* jsdc,
{ {
JSFunction *fun = JS_GetFrameFunction (jsdthreadstate->context, JSFunction *fun = JS_GetFrameFunction (jsdthreadstate->context,
jsdframe->fp); jsdframe->fp);
if (fun) if( fun )
{
rv = JS_GetFunctionId (fun); rv = JS_GetFunctionId (fun);
/*
* For compatibility we return "anonymous", not an empty string
* here.
*/
if( !rv )
rv = JS_GetAnonymousString(jsdc->jsrt);
}
} }
JSD_UNLOCK_THREADSTATES(jsdc); JSD_UNLOCK_THREADSTATES(jsdc);

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

@ -41,8 +41,7 @@
#include "jsd.h" #include "jsd.h"
#include "jsapi.h" #include "jsapi.h"
#include "jspubtd.h" #include "jsfriendapi.h"
#include "jsprvtd.h"
#ifdef DEBUG #ifdef DEBUG
void JSD_ASSERT_VALID_VALUE(JSDValue* jsdval) void JSD_ASSERT_VALID_VALUE(JSDValue* jsdval)
@ -273,8 +272,10 @@ jsd_GetValueFunctionName(JSDContext* jsdc, JSDValue* jsdval)
if(!fun) if(!fun)
return NULL; return NULL;
jsdval->funName = JS_GetFunctionId(fun); jsdval->funName = JS_GetFunctionId(fun);
/* For compatibility we return "anonymous", not an empty string here. */
if (!jsdval->funName) if (!jsdval->funName)
jsdval->funName = JS_GetEmptyString(jsdc->jsrt); jsdval->funName = JS_GetAnonymousString(jsdc->jsrt);
} }
return jsdval->funName; return jsdval->funName;
} }
@ -298,7 +299,7 @@ jsd_NewValue(JSDContext* jsdc, jsval val)
call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, jsdc->glob); call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, jsdc->glob);
if(!call) { if(!call) {
JS_EndRequest(jsdc->dumbContext); JS_EndRequest(jsdc->dumbContext);
free(jsdval);
return NULL; return NULL;
} }
@ -562,8 +563,11 @@ jsd_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* name)
while(NULL != (jsdprop = jsd_IterateProperties(jsdc, jsdval, &iter))) while(NULL != (jsdprop = jsd_IterateProperties(jsdc, jsdval, &iter)))
{ {
JSString* propName = jsd_GetValueString(jsdc, jsdprop->name); JSString* propName = jsd_GetValueString(jsdc, jsdprop->name);
if(propName && !JS_CompareStrings(propName, name)) if(propName) {
return jsdprop; intN result;
if (JS_CompareStrings(cx, propName, name, &result) && !result)
return jsdprop;
}
JSD_DropProperty(jsdc, jsdprop); JSD_DropProperty(jsdc, jsdprop);
} }
/* Not found in property list, look it up explicitly */ /* Not found in property list, look it up explicitly */
@ -571,8 +575,8 @@ jsd_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* name)
if(!(obj = JSVAL_TO_OBJECT(jsdval->val))) if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
return NULL; return NULL;
nameChars = JS_GetStringChars(name); if (!(nameChars = JS_GetStringCharsZAndLength(cx, name, &nameLen)))
nameLen = JS_GetStringLength(name); return NULL;
JS_BeginRequest(cx); JS_BeginRequest(cx);
call = JS_EnterCrossCompartmentCall(cx, obj); call = JS_EnterCrossCompartmentCall(cx, obj);

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

@ -197,7 +197,7 @@ jsds_InvalidateAllEphemerals (LiveEphemeral **listHead)
LiveEphemeral *lv_record = LiveEphemeral *lv_record =
reinterpret_cast<LiveEphemeral *> reinterpret_cast<LiveEphemeral *>
(PR_NEXT_LINK(&(*listHead)->links)); (PR_NEXT_LINK(&(*listHead)->links));
while (*listHead) do
{ {
LiveEphemeral *next = LiveEphemeral *next =
reinterpret_cast<LiveEphemeral *> reinterpret_cast<LiveEphemeral *>
@ -205,6 +205,7 @@ jsds_InvalidateAllEphemerals (LiveEphemeral **listHead)
lv_record->value->Invalidate(); lv_record->value->Invalidate();
lv_record = next; lv_record = next;
} }
while (*listHead);
} }
void void
@ -1033,36 +1034,61 @@ jsdScript::CreatePPLineMap()
JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL); JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL);
JSFunction *fun = JSD_GetJSFunction (mCx, mScript); JSFunction *fun = JSD_GetJSFunction (mCx, mScript);
JSScript *script; JSScript *script;
JSString *jsstr;
PRUint32 baseLine; PRUint32 baseLine;
PRBool scriptOwner = PR_FALSE; PRBool scriptOwner = PR_FALSE;
if (fun) { if (fun) {
uintN nargs = JS_GetFunctionArgumentCount(cx, fun); uintN nargs;
if (nargs > 12)
return nsnull; /* Enter a new block so we can leave before the end of this block */
JSString *jsstr = JS_DecompileFunctionBody (cx, fun, 4); do {
if (!jsstr) 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; return nsnull;
const char *argnames[] = {"arg1", "arg2", "arg3", "arg4", const char *argnames[] = {"arg1", "arg2", "arg3", "arg4",
"arg5", "arg6", "arg7", "arg8", "arg5", "arg6", "arg7", "arg8",
"arg9", "arg10", "arg11", "arg12" }; "arg9", "arg10", "arg11", "arg12" };
fun = JS_CompileUCFunction (cx, obj, "ppfun", nargs, argnames, fun = JS_CompileUCFunction (cx, obj, "ppfun", nargs, argnames, chars,
JS_GetStringChars(jsstr), length, "x-jsd:ppbuffer?type=function", 3);
JS_GetStringLength(jsstr),
"x-jsd:ppbuffer?type=function", 3);
if (!fun || !(script = JS_GetFunctionScript(cx, fun))) if (!fun || !(script = JS_GetFunctionScript(cx, fun)))
return nsnull; return nsnull;
baseLine = 3; baseLine = 3;
} else { } else {
JSString *jsstr = JS_DecompileScript (cx, JSD_GetJSScript(mCx, mScript), /* Enter a new block so we can leave before the end of this block */
"ppscript", 4); do {
if (!jsstr) 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; return nsnull;
script = JS_CompileUCScript (cx, obj, script = JS_CompileUCScript (cx, obj, chars, length,
JS_GetStringChars(jsstr),
JS_GetStringLength(jsstr),
"x-jsd:ppbuffer?type=script", 1); "x-jsd:ppbuffer?type=script", 1);
if (!script) if (!script)
return nsnull; return nsnull;
@ -1284,8 +1310,7 @@ jsdScript::GetParameterNames(PRUint32* count, PRUnichar*** paramNames)
ret[i] = 0; ret[i] = 0;
} else { } else {
JSString *str = JS_AtomKey(atom); JSString *str = JS_AtomKey(atom);
ret[i] = NS_strndup(reinterpret_cast<PRUnichar*>(JS_GetStringChars(str)), ret[i] = NS_strndup(JS_GetInternedStringChars(str), JS_GetStringLength(str));
JS_GetStringLength(str));
if (!ret[i]) { if (!ret[i]) {
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, ret); NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, ret);
rv = NS_ERROR_OUT_OF_MEMORY; rv = NS_ERROR_OUT_OF_MEMORY;
@ -1343,23 +1368,26 @@ jsdScript::GetFunctionSource(nsAString & aFunctionSource)
JSAutoRequest ar(cx); JSAutoRequest ar(cx);
JSString *jsstr; JSString *jsstr;
JSAutoEnterCompartment ac;
if (fun) { if (fun) {
JSAutoEnterCompartment ac;
if (!ac.enter(cx, JS_GetFunctionObject(fun))) if (!ac.enter(cx, JS_GetFunctionObject(fun)))
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
jsstr = JS_DecompileFunction (cx, fun, 4); jsstr = JS_DecompileFunction (cx, fun, 4);
} else { } else {
JSScript *script = JSD_GetJSScript (mCx, mScript); 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); jsstr = JS_DecompileScript (cx, script, "ppscript", 4);
} }
if (!jsstr) if (!jsstr)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
aFunctionSource = size_t length;
nsDependentString( const jschar *chars = JS_GetStringCharsZAndLength(cx, jsstr, &length);
reinterpret_cast<PRUnichar*>(JS_GetStringChars(jsstr)), if (!chars)
JS_GetStringLength(jsstr)); return NS_ERROR_FAILURE;
aFunctionSource = nsDependentString(chars, length);
return NS_OK; return NS_OK;
} }
@ -1480,6 +1508,20 @@ jsdScript::LineToPc(PRUint32 aLine, PRUint32 aPcmap, PRUint32 *_rval)
return NS_OK; 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 NS_IMETHODIMP
jsdScript::IsLineExecutable(PRUint32 aLine, PRUint32 aPcmap, PRBool *_rval) jsdScript::IsLineExecutable(PRUint32 aLine, PRUint32 aPcmap, PRBool *_rval)
{ {
@ -2240,12 +2282,19 @@ NS_IMETHODIMP
jsdValue::GetStringValue(nsACString &_rval) jsdValue::GetStringValue(nsACString &_rval)
{ {
ASSERT_VALID_EPHEMERAL; 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); JSString *jstr_val = JSD_GetValueString(mCx, mValue);
if (jstr_val) { if (jstr_val) {
nsDependentString chars( size_t length;
reinterpret_cast<PRUnichar*>(JS_GetStringChars(jstr_val)), const jschar *chars = JS_GetStringCharsZAndLength(cx, jstr_val, &length);
JS_GetStringLength(jstr_val)); if (!chars)
CopyUTF16toUTF8(chars, _rval); return NS_ERROR_FAILURE;
nsDependentString depStr(chars, length);
CopyUTF16toUTF8(depStr, _rval);
} else { } else {
_rval.Truncate(); _rval.Truncate();
} }

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

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

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

@ -576,6 +576,14 @@ JSD_SetInterruptHook(JSDContext* jsdc,
return jsd_SetInterruptHook(jsdc, hook, callerdata); 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_PUBLIC_API(JSBool)
JSD_ClearInterruptHook(JSDContext* jsdc) JSD_ClearInterruptHook(JSDContext* jsdc)
{ {

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

@ -803,6 +803,12 @@ JSD_SetInterruptHook(JSDContext* jsdc,
JSD_ExecutionHookProc hook, JSD_ExecutionHookProc hook,
void* callerdata); 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. * Clear the current interrupt hook.
*/ */

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

@ -134,17 +134,18 @@ CPPSRCS = \
jsbool.cpp \ jsbool.cpp \
jsclone.cpp \ jsclone.cpp \
jscntxt.cpp \ jscntxt.cpp \
jscompartment.cpp \
jsdate.cpp \ jsdate.cpp \
jsdbgapi.cpp \ jsdbgapi.cpp \
jsdhash.cpp \ jsdhash.cpp \
jsdtoa.cpp \ jsdtoa.cpp \
jsemit.cpp \ jsemit.cpp \
jsexn.cpp \ jsexn.cpp \
jsfriendapi.cpp \
jsfun.cpp \ jsfun.cpp \
jsgc.cpp \ jsgc.cpp \
jsgcchunk.cpp \ jsgcchunk.cpp \
jsgcstats.cpp \ jsgcstats.cpp \
jscompartment.cpp \
jshash.cpp \ jshash.cpp \
jsinterp.cpp \ jsinterp.cpp \
jsinvoke.cpp \ jsinvoke.cpp \
@ -199,6 +200,7 @@ INSTALLED_HEADERS = \
jsdtoa.h \ jsdtoa.h \
jsemit.h \ jsemit.h \
jsfun.h \ jsfun.h \
jsfriendapi.h \
jsgc.h \ jsgc.h \
jscell.h \ jscell.h \
jsgcchunk.h \ jsgcchunk.h \
@ -572,11 +574,11 @@ ifdef ENABLE_TRACEJIT
ifndef WINCE ifndef WINCE
check:: check::
$(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/jit-test/jit_test.py \ $(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/jit-test/jit_test.py \
--no-slow --no-progress --tinderbox $(DIST)/bin/js$(BIN_SUFFIX) --no-slow --no-progress --tinderbox --jitflags=m,j,mj,mjp,mjd $(DIST)/bin/js$(BIN_SUFFIX)
check-valgrind:: check-valgrind::
$(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/jit-test/jit_test.py \ $(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/jit-test/jit_test.py \
--valgrind --no-slow --no-progress --tinderbox $(DIST)/bin/js$(BIN_SUFFIX) --valgrind --no-slow --no-progress --tinderbox --jitflags=m,j,mj,mjp,mjd $(DIST)/bin/js$(BIN_SUFFIX)
endif endif
endif endif

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

@ -170,6 +170,13 @@ public:
size_t available() const { return (m_pools.length() > 1) ? 0 : m_end - m_freePtr; } 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: private:
// On OOM, this will return an Allocation where pages is NULL. // On OOM, this will return an Allocation where pages is NULL.
static Allocation systemAlloc(size_t n); 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 // This constructor can fail due to OOM. If it does, m_freePtr will be
// set to NULL. // 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); size_t allocSize = roundUpAllocationSize(n, JIT_ALLOCATOR_PAGE_SIZE);
if (allocSize == OVERSIZE_ALLOCATION) { if (allocSize == OVERSIZE_ALLOCATION) {

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

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

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

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

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

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

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

@ -502,7 +502,9 @@ newdtoa(void)
DtoaState *state = (DtoaState *) MALLOC(sizeof(DtoaState)); DtoaState *state = (DtoaState *) MALLOC(sizeof(DtoaState));
if (state) { if (state) {
memset(state, 0, sizeof(DtoaState)); memset(state, 0, sizeof(DtoaState));
#ifndef Omit_Private_Memory
state->pmem_next = state->private_mem; state->pmem_next = state->private_mem;
#endif
} }
return state; return state;
} }

6
js/src/jit-test/jit_test.py Normal file → Executable file
Просмотреть файл

@ -1,3 +1,5 @@
#!/usr/bin/env python
# jit_test.py -- Python harness for JavaScript trace tests. # jit_test.py -- Python harness for JavaScript trace tests.
import datetime, os, re, sys, tempfile, traceback import datetime, os, re, sys, tempfile, traceback
@ -349,8 +351,8 @@ def main(argv):
help='Enable the |valgrind| flag, if valgrind is in $PATH.') help='Enable the |valgrind| flag, if valgrind is in $PATH.')
op.add_option('--valgrind-all', dest='valgrind_all', action='store_true', op.add_option('--valgrind-all', dest='valgrind_all', action='store_true',
help='Run all tests with valgrind, if valgrind is in $PATH.') help='Run all tests with valgrind, if valgrind is in $PATH.')
op.add_option('--jitflags', dest='jitflags', default='j', op.add_option('--jitflags', dest='jitflags', default='mjp',
help='Example: --jitflags=j,mj to run each test with -j and -m -j') help='Example: --jitflags=j,mj,mjp to run each test with -j, -m -j, -m -j -p [default=%default]')
op.add_option('--avoid-stdio', dest='avoid_stdio', action='store_true', op.add_option('--avoid-stdio', dest='avoid_stdio', action='store_true',
help='Use js-shell file indirection instead of piping stdio.') help='Use js-shell file indirection instead of piping stdio.')
op.add_option('--write-failure-output', dest='write_failure_output', action='store_true', op.add_option('--write-failure-output', dest='write_failure_output', action='store_true',

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

@ -13,7 +13,7 @@ function strictArgs(a)
} }
var a1, a2, a3; var a1, a2, a3;
for (var i = 0; i < 5; i++) for (var i = 0; i < HOTLOOP+1; i++)
{ {
a1 = strictArgs(); a1 = strictArgs();
a2 = strictArgs(1); a2 = strictArgs(1);

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

@ -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);

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

@ -0,0 +1,22 @@
function g() {
return "global";
}
function q(fun) {
return fun();
}
function f(x) {
if (x) {
function g() {
return "local";
}
var ans = q(function() {
return g();
});
}
g = null;
return ans;
}
assertEq(f(true), "local");

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

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

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

@ -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;
}

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

@ -1,6 +1,6 @@
function f() { function f() {
try { try {
for ( var i = 1; i > -2; i-- ) for ( var i = HOTLOOP-1; i > -2; i-- )
new Array(i).join('*'); new Array(i).join('*');
} catch (e) { } catch (e) {
return e instanceof RangeError; return e instanceof RangeError;

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

@ -0,0 +1,16 @@
function f() {
var o = { n: "" };
for (var i = 0; i < 2*RUNLOOP; ++i) {
o.n = "";
if (o.n++) { }
}
}
f();
checkStats({
recorderStarted: 1,
recorderAborted: 0,
traceCompleted: 1,
traceTriggered: 1
});

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

@ -0,0 +1,2 @@
var str = (3.14).toLocaleString();
assertEq(str[str.length-1], "4");

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

@ -0,0 +1 @@
var a = new Int32Array(); +(a[0]={});

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

@ -76,11 +76,12 @@ CPPSRCS = \
testUTF8.cpp \ testUTF8.cpp \
testVersion.cpp \ testVersion.cpp \
testXDR.cpp \ testXDR.cpp \
testCustomIterator.cpp \
$(NULL) $(NULL)
DEFINES += -DEXPORT_JS_API DEFINES += -DEXPORT_JS_API
LIBS = $(NSPR_LIBS) $(DEPTH)/$(LIB_PREFIX)js_static.$(LIB_SUFFIX) LIBS = $(DEPTH)/$(LIB_PREFIX)js_static.$(LIB_SUFFIX) $(NSPR_LIBS)
LOCAL_INCLUDES += -I$(topsrcdir) -I.. LOCAL_INCLUDES += -I$(topsrcdir) -I..

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

@ -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)

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

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

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

@ -41,7 +41,10 @@ document_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **
return false; return false;
if (JSVAL_IS_STRING(v.value())) { if (JSVAL_IS_STRING(v.value())) {
JSString *str = JSVAL_TO_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); JSBool ok = JS_DefinePropertyById(cx, obj, id, JSVAL_TRUE, NULL, NULL, 0);
*objp = ok ? obj : NULL; *objp = ok ? obj : NULL;
return ok; return ok;

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

@ -16,7 +16,9 @@ BEGIN_TEST(testSameValue)
*/ */
jsval v1 = DOUBLE_TO_JSVAL(0.0); jsval v1 = DOUBLE_TO_JSVAL(0.0);
jsval v2 = 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; return true;
} }
END_TEST(testSameValue) END_TEST(testSameValue)

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

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

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

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

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

@ -111,6 +111,16 @@
using namespace js; using namespace js;
using namespace js::gc; using namespace js::gc;
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 class AutoVersionAPI
{ {
JSContext * const cx; JSContext * const cx;
@ -571,17 +581,17 @@ JS_GetTypeName(JSContext *cx, JSType type)
} }
JS_PUBLIC_API(JSBool) 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); assertSameCompartment(cx, v1, v2);
return StrictlyEqual(cx, Valueify(v1), Valueify(v2)); return StrictlyEqual(cx, Valueify(v1), Valueify(v2), equal);
} }
JS_PUBLIC_API(JSBool) 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); assertSameCompartment(cx, v1, v2);
return SameValue(Valueify(v1), Valueify(v2), cx); return SameValue(cx, Valueify(v1), Valueify(v2), same);
} }
/************************************************************************/ /************************************************************************/
@ -1169,6 +1179,22 @@ JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target)
return reinterpret_cast<JSCrossCompartmentCall *>(call); 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_PUBLIC_API(void)
JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call) JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call)
{ {
@ -1190,6 +1216,18 @@ JSAutoEnterCompartment::enter(JSContext *cx, JSObject *target)
return call != NULL; 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 void
JSAutoEnterCompartment::enterAndIgnoreErrors(JSContext *cx, JSObject *target) JSAutoEnterCompartment::enterAndIgnoreErrors(JSContext *cx, JSObject *target)
{ {
@ -2199,8 +2237,14 @@ JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, ui
} }
case JSTRACE_STRING: 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; break;
}
#if JS_HAS_XML_SUPPORT #if JS_HAS_XML_SUPPORT
case JSTRACE_XML: case JSTRACE_XML:
@ -2662,7 +2706,7 @@ JS_GetGCParameterForThread(JSContext *cx, JSGCParamKey key)
{ {
JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES); JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES);
#ifdef JS_TRACER #ifdef JS_TRACER
return JS_THREAD_DATA(cx)->traceMonitor.maxCodeCacheBytes; return JS_THREAD_DATA(cx)->maxCodeCacheBytes;
#else #else
return 0; return 0;
#endif #endif
@ -5168,17 +5212,8 @@ JS_RestoreFrameChain(JSContext *cx, JSStackFrame *fp)
JS_PUBLIC_API(JSString *) JS_PUBLIC_API(JSString *)
JS_NewStringCopyN(JSContext *cx, const char *s, size_t n) JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
{ {
jschar *js;
JSString *str;
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
js = js_InflateString(cx, s, &n); return js_NewStringCopyN(cx, s, n);
if (!js)
return NULL;
str = js_NewString(cx, js, n);
if (!str)
cx->free(js);
return str;
} }
JS_PUBLIC_API(JSString *) JS_PUBLIC_API(JSString *)
@ -5207,6 +5242,16 @@ JS_StringHasBeenInterned(JSString *str)
return str->isAtomized(); 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_PUBLIC_API(JSString *)
JS_InternString(JSContext *cx, const char *s) JS_InternString(JSContext *cx, const char *s)
{ {
@ -5260,45 +5305,6 @@ JS_InternUCString(JSContext *cx, const jschar *s)
return JS_InternUCStringN(cx, s, js_strlen(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_PUBLIC_API(size_t)
JS_GetStringLength(JSString *str) JS_GetStringLength(JSString *str)
{ {
@ -5306,41 +5312,102 @@ JS_GetStringLength(JSString *str)
} }
JS_PUBLIC_API(const jschar *) JS_PUBLIC_API(const jschar *)
JS_GetStringCharsAndLength(JSString *str, size_t *lengthp) JS_GetStringCharsZ(JSContext *cx, JSString *str)
{ {
*lengthp = str->length(); CHECK_REQUEST(cx);
return str->chars(); assertSameCompartment(cx, str);
return str->getCharsZ(cx);
} }
JS_PUBLIC_API(const jschar *) 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); assertSameCompartment(cx, str);
return str->undepend(cx); *plength = str->length();
return str->getCharsZ(cx);
} }
JS_PUBLIC_API(intN) JS_PUBLIC_API(const jschar *)
JS_CompareStrings(JSString *str1, JSString *str2) 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_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_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); 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_PUBLIC_API(JSBool)
JS_FileEscapedString(FILE *fp, JSString *str, char quote) 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 *) JS_PUBLIC_API(JSString *)
@ -5368,7 +5435,7 @@ JS_PUBLIC_API(const jschar *)
JS_UndependString(JSContext *cx, JSString *str) JS_UndependString(JSContext *cx, JSString *str)
{ {
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
return str->undepend(cx); return str->getCharsZ(cx);
} }
JS_PUBLIC_API(JSBool) JS_PUBLIC_API(JSBool)
@ -5404,13 +5471,19 @@ JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst, size_
JS_PUBLIC_API(char *) JS_PUBLIC_API(char *)
JS_EncodeString(JSContext *cx, JSString *str) 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_PUBLIC_API(size_t)
JS_GetStringEncodingLength(JSContext *cx, JSString *str) 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) JS_PUBLIC_API(size_t)
@ -5422,12 +5495,15 @@ JS_EncodeStringToBuffer(JSString *str, char *buffer, size_t length)
* error. * error.
*/ */
size_t writtenLength = length; 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); JS_ASSERT(writtenLength <= length);
return writtenLength; return writtenLength;
} }
JS_ASSERT(writtenLength <= length); 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)) if (necessaryLength == size_t(-1))
return size_t(-1); return size_t(-1);
if (writtenLength != length) { if (writtenLength != length) {

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

@ -500,7 +500,7 @@ extern JS_PUBLIC_DATA(jsid) JSID_EMPTY;
#define JSFUN_HEAVYWEIGHT_TEST(f) ((f) & JSFUN_HEAVYWEIGHT) #define JSFUN_HEAVYWEIGHT_TEST(f) ((f) & JSFUN_HEAVYWEIGHT)
#define JSFUN_PRIMITIVE_THIS 0x0100 /* |this| may be a primitive value */ /* 0x0100 is unused */
#define JSFUN_CONSTRUCTOR 0x0200 /* native that can be called as a ctor #define JSFUN_CONSTRUCTOR 0x0200 /* native that can be called as a ctor
without creating a this object */ without creating a this object */
@ -702,10 +702,10 @@ extern JS_PUBLIC_API(const char *)
JS_GetTypeName(JSContext *cx, JSType type); JS_GetTypeName(JSContext *cx, JSType type);
extern JS_PUBLIC_API(JSBool) 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) 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 *) extern JS_PUBLIC_API(JSCrossCompartmentCall *)
JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target); JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target);
extern JS_PUBLIC_API(JSCrossCompartmentCall *)
JS_EnterCrossCompartmentCallScript(JSContext *cx, JSScript *target);
extern JS_PUBLIC_API(void) extern JS_PUBLIC_API(void)
JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call); JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call);
@ -1009,6 +1012,8 @@ class JS_PUBLIC_API(JSAutoEnterCompartment)
bool enter(JSContext *cx, JSObject *target); bool enter(JSContext *cx, JSObject *target);
bool enter(JSContext *cx, JSScript *target);
void enterAndIgnoreErrors(JSContext *cx, JSObject *target); void enterAndIgnoreErrors(JSContext *cx, JSObject *target);
bool entered() const { return call != NULL; } bool entered() const { return call != NULL; }
@ -2931,6 +2936,9 @@ JS_NewStringCopyN(JSContext *cx, const char *s, size_t n);
extern JS_PUBLIC_API(JSString *) extern JS_PUBLIC_API(JSString *)
JS_NewStringCopyZ(JSContext *cx, const char *s); JS_NewStringCopyZ(JSContext *cx, const char *s);
extern JS_PUBLIC_API(JSString *)
JS_InternJSString(JSContext *cx, JSString *str);
extern JS_PUBLIC_API(JSString *) extern JS_PUBLIC_API(JSString *)
JS_InternString(JSContext *cx, const char *s); JS_InternString(JSContext *cx, const char *s);
@ -2949,36 +2957,106 @@ JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length);
extern JS_PUBLIC_API(JSString *) extern JS_PUBLIC_API(JSString *)
JS_InternUCString(JSContext *cx, const jschar *s); 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) extern JS_PUBLIC_API(size_t)
JS_GetStringLength(JSString *str); 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 *) 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 *) extern JS_PUBLIC_API(const jschar *)
JS_GetStringCharsZ(JSContext *cx, JSString *str); JS_GetStringCharsZ(JSContext *cx, JSString *str);
extern JS_PUBLIC_API(intN) extern JS_PUBLIC_API(const jschar *)
JS_CompareStrings(JSString *str1, JSString *str2); 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) 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) extern 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);
extern JS_PUBLIC_API(JSBool)
JS_FileEscapedString(FILE *fp, JSString *str, char quote);
/* /*
* This function is now obsolete and behaves the same as JS_NewUCString. Use * This function is now obsolete and behaves the same as JS_NewUCString. Use

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

@ -143,10 +143,10 @@ ENSURE_SLOW_ARRAY(JSContext *cx, JSObject *obj)
* 'id' is passed as a jsboxedword since the given id need not necessarily hold * 'id' is passed as a jsboxedword since the given id need not necessarily hold
* an atomized string. * an atomized string.
*/ */
JSBool bool
js_StringIsIndex(JSString *str, jsuint *indexp) js_StringIsIndex(JSLinearString *str, jsuint *indexp)
{ {
jschar *cp = str->chars(); const jschar *cp = str->chars();
if (JS7_ISDEC(*cp) && str->length() < sizeof(MAXSTR)) { if (JS7_ISDEC(*cp) && str->length() < sizeof(MAXSTR)) {
jsuint index = JS7_UNDEC(*cp++); jsuint index = JS7_UNDEC(*cp++);
jsuint oldIndex = 0; jsuint oldIndex = 0;
@ -166,10 +166,10 @@ js_StringIsIndex(JSString *str, jsuint *indexp)
(oldIndex == (MAXINDEX / 10) && c < (MAXINDEX % 10)))) (oldIndex == (MAXINDEX / 10) && c < (MAXINDEX % 10))))
{ {
*indexp = index; *indexp = index;
return JS_TRUE; return true;
} }
} }
return JS_FALSE; return false;
} }
static bool static bool
@ -853,21 +853,35 @@ static JSBool
array_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value, array_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value,
PropertyOp getter, PropertyOp setter, uintN attrs) 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)) if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
return JS_TRUE; return JS_TRUE;
isIndex = js_IdIsIndex(id, &i); if (!obj->isDenseArray())
if (!isIndex || attrs != JSPROP_ENUMERATE) {
if (!ENSURE_SLOW_ARRAY(cx, obj))
return JS_FALSE;
return js_DefineProperty(cx, obj, id, value, getter, setter, attrs); return js_DefineProperty(cx, obj, id, value, getter, setter, attrs);
}
Value tmp = *value; do {
return array_setProperty(cx, obj, id, &tmp, false); 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(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 static JSBool
@ -1149,12 +1163,13 @@ array_toSource(JSContext *cx, uintN argc, Value *vp)
goto out; goto out;
} }
vp->setString(str); vp->setString(str);
const jschar *chars;
size_t charlen; const jschar *chars = str->getChars(cx);
str->getCharsAndLength(chars, charlen); if (!chars)
goto out;
/* Append element to buffer. */ /* Append element to buffer. */
if (!cb.append(chars, charlen)) if (!cb.append(chars, chars + str->length()))
goto out; goto out;
if (index + 1 != length) { if (index + 1 != length) {
if (!js_AppendLiteral(cb, ", ")) if (!js_AppendLiteral(cb, ", "))
@ -1188,6 +1203,20 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
{ {
JS_CHECK_RECURSION(cx, return false); 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 * Use HashTable entry as the cycle indicator. On first visit, create the
* entry, and, when leaving, remove the entry. * entry, and, when leaving, remove the entry.
@ -1197,10 +1226,8 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
uint32 genBefore; uint32 genBefore;
if (!hashp) { if (!hashp) {
/* Not in hash table, so not a cycle. */ /* Not in hash table, so not a cycle. */
if (!cx->busyArrays.add(hashp, obj)) { if (!cx->busyArrays.add(hashp, obj))
JS_ReportOutOfMemory(cx);
return false; return false;
}
genBefore = cx->busyArrays.generation(); genBefore = cx->busyArrays.generation();
} else { } else {
/* Cycle, so return empty string. */ /* Cycle, so return empty string. */
@ -1214,17 +1241,6 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
MUST_FLOW_THROUGH("out"); MUST_FLOW_THROUGH("out");
bool ok = false; 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 * This object will take responsibility for the jschar buffer until the
* buffer is transferred to the returned JSString. * buffer is transferred to the returned JSString.
@ -1710,15 +1726,10 @@ comparator_stack_cast(JSRedComparator func)
static int static int
sort_compare_strings(void *arg, const void *a, const void *b, int *result) sort_compare_strings(void *arg, const void *a, const void *b, int *result)
{ {
const Value *av = (const Value *)a, *bv = (const Value *)b; JSContext *cx = (JSContext *)arg;
JSString *astr = ((const Value *)a)->toString();
JS_ASSERT(av->isString()); JSString *bstr = ((const Value *)b)->toString();
JS_ASSERT(bv->isString()); return JS_CHECK_OPERATION_LIMIT(cx) && CompareStrings(cx, astr, bstr, result);
if (!JS_CHECK_OPERATION_LIMIT((JSContext *)arg))
return JS_FALSE;
*result = (int) js_CompareStrings(av->toString(), bv->toString());
return JS_TRUE;
} }
JSBool JSBool
@ -2615,9 +2626,14 @@ array_indexOfHelper(JSContext *cx, JSBool isLast, uintN argc, Value *vp)
!GetElement(cx, obj, (jsuint)i, &hole, vp)) { !GetElement(cx, obj, (jsuint)i, &hole, vp)) {
return JS_FALSE; return JS_FALSE;
} }
if (!hole && StrictlyEqual(cx, *vp, tosearch)) { if (!hole) {
vp->setNumber(i); JSBool equal;
return JS_TRUE; if (!StrictlyEqual(cx, *vp, tosearch, &equal))
return JS_FALSE;
if (equal) {
vp->setNumber(i);
return JS_TRUE;
}
} }
if (i == stop) if (i == stop)
goto not_found; goto not_found;

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

@ -44,7 +44,9 @@
*/ */
#include "jsprvtd.h" #include "jsprvtd.h"
#include "jspubtd.h" #include "jspubtd.h"
#include "jsatom.h"
#include "jsobj.h" #include "jsobj.h"
#include "jsstr.h"
/* Small arrays are dense, no matter what. */ /* Small arrays are dense, no matter what. */
const uintN MIN_SPARSE_INDEX = 256; const uintN MIN_SPARSE_INDEX = 256;
@ -86,8 +88,8 @@ JSObject::ensureDenseArrayElements(JSContext *cx, uintN index, uintN extra)
return growSlots(cx, requiredCapacity) ? ED_OK : ED_FAILED; return growSlots(cx, requiredCapacity) ? ED_OK : ED_FAILED;
} }
extern JSBool extern bool
js_StringIsIndex(JSString *str, jsuint *indexp); js_StringIsIndex(JSLinearString *str, jsuint *indexp);
inline JSBool inline JSBool
js_IdIsIndex(jsid id, jsuint *indexp) js_IdIsIndex(jsid id, jsuint *indexp)
@ -104,26 +106,36 @@ js_IdIsIndex(jsid id, jsuint *indexp)
if (JS_UNLIKELY(!JSID_IS_STRING(id))) if (JS_UNLIKELY(!JSID_IS_STRING(id)))
return JS_FALSE; 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. */ /* XML really wants to pretend jsvals are jsids. */
inline JSBool inline bool
js_IdValIsIndex(jsval id, jsuint *indexp) js_IdValIsIndex(JSContext *cx, jsval id, jsuint *indexp, bool *isIndex)
{ {
if (JSVAL_IS_INT(id)) { if (JSVAL_IS_INT(id)) {
jsint i; jsint i;
i = JSVAL_TO_INT(id); i = JSVAL_TO_INT(id);
if (i < 0) if (i < 0) {
return JS_FALSE; *isIndex = false;
return true;
}
*indexp = (jsuint)i; *indexp = (jsuint)i;
return JS_TRUE; *isIndex = true;
return true;
} }
if (!JSVAL_IS_STRING(id)) if (!JSVAL_IS_STRING(id)) {
return JS_FALSE; *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; extern js::Class js_ArrayClass, js_SlowArrayClass;

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

@ -457,17 +457,20 @@ js_SweepAtomState(JSContext *cx)
} }
JSAtom * 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(!(flags & ~(ATOM_PINNED|ATOM_INTERNED|ATOM_TMPSTR|ATOM_NOCOPY)));
JS_ASSERT_IF(flags & ATOM_NOCOPY, flags & ATOM_TMPSTR); JS_ASSERT_IF(flags & ATOM_NOCOPY, flags & ATOM_TMPSTR);
if (str->isAtomized()) if (strArg->isAtomized())
return STRING_TO_ATOM(str); return STRING_TO_ATOM(strArg);
const jschar *chars; JSLinearString *str = strArg->ensureLinear(cx);
size_t length; if (!str)
str->getCharsAndLength(chars, length); return NULL;
const jschar *chars = str->chars();
size_t length = str->length();
JSString *staticStr = JSString::lookupStaticString(chars, length); JSString *staticStr = JSString::lookupStaticString(chars, length);
if (staticStr) if (staticStr)
@ -482,7 +485,7 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
/* Hashing the string should have flattened it if it was a rope. */ /* Hashing the string should have flattened it if it was a rope. */
JS_ASSERT(str->isFlat() || str->isDependent()); JS_ASSERT(str->isFlat() || str->isDependent());
JSString *key; JSLinearString *key;
if (p) { if (p) {
key = AtomEntryToKey(*p); key = AtomEntryToKey(*p);
} else { } else {
@ -506,15 +509,14 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
} else { } else {
if (needNewString) { if (needNewString) {
SwitchToCompartment sc(cx, cx->runtime->defaultCompartment); SwitchToCompartment sc(cx, cx->runtime->defaultCompartment);
jschar *chars = str->chars();
if (flags & ATOM_NOCOPY) { if (flags & ATOM_NOCOPY) {
key = js_NewString(cx, chars, length); key = js_NewString(cx, const_cast<jschar *>(str->flatChars()), length);
if (!key) if (!key)
return NULL; return NULL;
/* Finish handing off chars to the GC'ed key string. */ /* Finish handing off chars to the GC'ed key string. */
JS_ASSERT(flags & ATOM_TMPSTR); JS_ASSERT(flags & ATOM_TMPSTR);
str->mChars = NULL; str->u.chars = NULL;
} else { } else {
key = js_NewStringCopyN(cx, chars, length); key = js_NewStringCopyN(cx, chars, length);
if (!key) if (!key)
@ -537,7 +539,6 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
AddAtomEntryFlags(*p, flags & (ATOM_PINNED | ATOM_INTERNED)); AddAtomEntryFlags(*p, flags & (ATOM_PINNED | ATOM_INTERNED));
JS_ASSERT(key->isAtomized());
JSAtom *atom = STRING_TO_ATOM(key); JSAtom *atom = STRING_TO_ATOM(key);
return atom; return atom;
} }
@ -607,7 +608,7 @@ js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length)
state = &cx->runtime->atomState; state = &cx->runtime->atomState;
JS_LOCK(cx, &state->lock); 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; str2 = p ? AtomEntryToKey(*p) : NULL;
JS_UNLOCK(cx, &state->lock); JS_UNLOCK(cx, &state->lock);
@ -628,7 +629,7 @@ js_DumpAtoms(JSContext *cx, FILE *fp)
if (entry == 0) { if (entry == 0) {
fputs("<uninitialized>", fp); fputs("<uninitialized>", fp);
} else { } else {
JSString *key = AtomEntryToKey(entry); JSAtom *key = AtomEntryToKey(entry);
FileEscapedString(fp, key, '"'); FileEscapedString(fp, key, '"');
uintN flags = AtomEntryFlags(entry); uintN flags = AtomEntryFlags(entry);
if (flags != 0) { if (flags != 0) {

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

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

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

@ -120,11 +120,11 @@ bool_valueOf(JSContext *cx, uintN argc, Value *vp)
static JSFunctionSpec boolean_methods[] = { static JSFunctionSpec boolean_methods[] = {
#if JS_HAS_TOSOURCE #if JS_HAS_TOSOURCE
JS_FN(js_toSource_str, bool_toSource, 0, JSFUN_PRIMITIVE_THIS), JS_FN(js_toSource_str, bool_toSource, 0, 0),
#endif #endif
JS_FN(js_toString_str, bool_toString, 0, JSFUN_PRIMITIVE_THIS), JS_FN(js_toString_str, bool_toString, 0, 0),
JS_FN(js_valueOf_str, bool_valueOf, 0, JSFUN_PRIMITIVE_THIS), JS_FN(js_valueOf_str, bool_valueOf, 0, 0),
JS_FN(js_toJSON_str, bool_valueOf, 0, JSFUN_PRIMITIVE_THIS), JS_FN(js_toJSON_str, bool_valueOf, 0, 0),
JS_FS_END JS_FS_END
}; };

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

@ -168,18 +168,22 @@ js_DoubleToUint32(jsdouble d)
JS_DEFINE_CALLINFO_1(extern, UINT32, js_DoubleToUint32, DOUBLE, 1, ACCSET_NONE) JS_DEFINE_CALLINFO_1(extern, UINT32, js_DoubleToUint32, DOUBLE, 1, ACCSET_NONE)
jsdouble FASTCALL 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 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. */ /* Nb: it's always safe to set isDefinitelyAtom to false if you're unsure or don't know. */
static inline JSBool static inline JSBool

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

@ -547,7 +547,7 @@ struct ClosureVarInfo;
#define _JS_DEFINE_CALLINFO_n(n, args) JS_DEFINE_CALLINFO_##n args #define _JS_DEFINE_CALLINFO_n(n, args) JS_DEFINE_CALLINFO_##n args
jsdouble FASTCALL jsdouble FASTCALL
js_StringToNumber(JSContext* cx, JSString* str); js_StringToNumber(JSContext* cx, JSString* str, JSBool *ok);
/* Extern version of SetBuiltinError. */ /* Extern version of SetBuiltinError. */
extern JS_FRIEND_API(void) extern JS_FRIEND_API(void)
@ -623,9 +623,9 @@ JS_DECLARE_CALLINFO(js_CloneRegExpObject)
/* Defined in jsstr.cpp. */ /* Defined in jsstr.cpp. */
JS_DECLARE_CALLINFO(js_String_tn) 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_ConcatStrings)
JS_DECLARE_CALLINFO(js_EqualStrings) JS_DECLARE_CALLINFO(js_EqualStringsOnTrace)
JS_DECLARE_CALLINFO(js_Flatten) JS_DECLARE_CALLINFO(js_Flatten)
/* Defined in jstypedarray.cpp. */ /* Defined in jstypedarray.cpp. */

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

@ -350,9 +350,10 @@ JS_STATIC_ASSERT(JSString::MAX_LENGTH < UINT32_MAX);
bool bool
JSStructuredCloneWriter::writeString(uint32_t tag, JSString *str) JSStructuredCloneWriter::writeString(uint32_t tag, JSString *str)
{ {
const jschar *chars; size_t length = str->length();
size_t length; const jschar *chars = str->getChars(context());
str->getCharsAndLength(chars, length); if (!chars)
return false;
return out.writePair(tag, uint32_t(length)) && out.writeChars(chars, length); return out.writePair(tag, uint32_t(length)) && out.writeChars(chars, length);
} }
@ -750,9 +751,10 @@ JSStructuredCloneReader::startRead(Value *vp)
JSString *str = readString(nchars); JSString *str = readString(nchars);
if (!str) if (!str)
return false; return false;
const jschar *chars; size_t length = str->length();
size_t length; const jschar *chars = str->getChars(context());
str->getCharsAndLength(chars, length); if (!chars)
return false;
JSObject *obj = RegExp::createObjectNoStatics(context(), chars, length, data); JSObject *obj = RegExp::createObjectNoStatics(context(), chars, length, data);
if (!obj) if (!obj)
return false; return false;

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

@ -494,49 +494,28 @@ JSThreadData::init()
#endif #endif
if (!stackSpace.init()) if (!stackSpace.init())
return false; return false;
#ifdef JS_TRACER
if (!InitJIT(&traceMonitor)) {
finish();
return false;
}
#endif
dtoaState = js_NewDtoaState(); dtoaState = js_NewDtoaState();
if (!dtoaState) { if (!dtoaState) {
finish(); finish();
return false; return false;
} }
nativeStackBase = GetNativeStackBase(); nativeStackBase = GetNativeStackBase();
return true;
}
MathCache * /* Set the default size for the code cache to 16MB. */
JSThreadData::allocMathCache(JSContext *cx) maxCodeCacheBytes = 16 * 1024 * 1024;
{
JS_ASSERT(!mathCache); return true;
mathCache = new MathCache;
if (!mathCache)
js_ReportOutOfMemory(cx);
return mathCache;
} }
void void
JSThreadData::finish() JSThreadData::finish()
{ {
#ifdef DEBUG
for (size_t i = 0; i != JS_ARRAY_LENGTH(scriptsToGC); ++i)
JS_ASSERT(!scriptsToGC[i]);
#endif
if (dtoaState) if (dtoaState)
js_DestroyDtoaState(dtoaState); js_DestroyDtoaState(dtoaState);
js_FinishGSNCache(&gsnCache); js_FinishGSNCache(&gsnCache);
propertyCache.~PropertyCache(); propertyCache.~PropertyCache();
#if defined JS_TRACER
FinishJIT(&traceMonitor);
#endif
stackSpace.finish(); stackSpace.finish();
delete mathCache;
} }
void void
@ -553,22 +532,6 @@ JSThreadData::purge(JSContext *cx)
/* FIXME: bug 506341. */ /* FIXME: bug 506341. */
propertyCache.purge(cx); propertyCache.purge(cx);
#ifdef JS_TRACER
/*
* If we are about to regenerate shapes, we have to flush the JIT cache,
* which will eventually abort any current recording.
*/
if (cx->runtime->gcRegenShapes)
traceMonitor.needFlush = JS_TRUE;
#endif
/* Destroy eval'ed scripts. */
js_DestroyScriptsToGC(cx, this);
/* Purge cached native iterators. */
memset(cachedNativeIterators, 0, sizeof(cachedNativeIterators));
lastNativeIterator = NULL;
dtoaCache.s = NULL; dtoaCache.s = NULL;
} }
@ -736,7 +699,6 @@ js_PurgeThreads(JSContext *cx)
if (JS_CLIST_IS_EMPTY(&thread->contextList)) { if (JS_CLIST_IS_EMPTY(&thread->contextList)) {
JS_ASSERT(cx->thread != thread); JS_ASSERT(cx->thread != thread);
js_DestroyScriptsToGC(cx, &thread->data);
DestroyThread(thread); DestroyThread(thread);
e.removeFront(); e.removeFront();
@ -921,7 +883,7 @@ DumpEvalCacheMeter(JSContext *cx)
EVAL_CACHE_METER_LIST(frob) EVAL_CACHE_METER_LIST(frob)
#undef frob #undef frob
}; };
JSEvalCacheMeter *ecm = &JS_THREAD_DATA(cx)->evalCacheMeter; JSEvalCacheMeter *ecm = &cx->compartment->evalCacheMeter;
static JSAutoFile fp; static JSAutoFile fp;
if (!fp && !fp.open(filename, "w")) if (!fp && !fp.open(filename, "w"))
@ -2316,6 +2278,15 @@ JSContext::updateJITEnabled()
namespace js { namespace js {
JS_FORCES_STACK JS_FRIEND_API(void)
LeaveTrace(JSContext *cx)
{
#ifdef JS_TRACER
if (JS_ON_TRACE(cx))
DeepBail(cx);
#endif
}
void void
SetPendingException(JSContext *cx, const Value &v) SetPendingException(JSContext *cx, const Value &v)
{ {

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

@ -884,147 +884,6 @@ private:
JSStackFrame *curfp; JSStackFrame *curfp;
}; };
/* Holds the number of recording attemps for an address. */
typedef HashMap<jsbytecode*,
size_t,
DefaultHasher<jsbytecode*>,
SystemAllocPolicy> RecordAttemptMap;
/* Holds the profile data for loops. */
typedef HashMap<jsbytecode*,
LoopProfile*,
DefaultHasher<jsbytecode*>,
SystemAllocPolicy> LoopProfileMap;
class Oracle;
typedef HashSet<JSScript *,
DefaultHasher<JSScript *>,
SystemAllocPolicy> TracedScriptSet;
/*
* Trace monitor. Every JSThread (if JS_THREADSAFE) or JSRuntime (if not
* JS_THREADSAFE) has an associated trace monitor that keeps track of loop
* frequencies for all JavaScript code loaded into that runtime.
*/
struct TraceMonitor {
/*
* The context currently executing JIT-compiled code on this thread, or
* NULL if none. Among other things, this can in certain cases prevent
* last-ditch GC and suppress calls to JS_ReportOutOfMemory.
*
* !tracecx && !recorder: not on trace
* !tracecx && recorder: recording
* tracecx && !recorder: executing a trace
* tracecx && recorder: executing inner loop, recording outer loop
*/
JSContext *tracecx;
/*
* Cached storage to use when executing on trace. While we may enter nested
* traces, we always reuse the outer trace's storage, so never need more
* than of these.
*/
TraceNativeStorage *storage;
/*
* There are 4 allocators here. This might seem like overkill, but they
* have different lifecycles, and by keeping them separate we keep the
* amount of retained memory down significantly. They are flushed (ie.
* all the allocated memory is freed) periodically.
*
* - dataAlloc has the lifecycle of the monitor. It's flushed only when
* the monitor is flushed. It's used for fragments.
*
* - traceAlloc has the same flush lifecycle as the dataAlloc, but it is
* also *marked* when a recording starts and rewinds to the mark point
* if recording aborts. So you can put things in it that are only
* reachable on a successful record/compile cycle like GuardRecords and
* SideExits.
*
* - tempAlloc is flushed after each recording, successful or not. It's
* used to store LIR code and for all other elements in the LIR
* pipeline.
*
* - codeAlloc has the same lifetime as dataAlloc, but its API is
* different (CodeAlloc vs. VMAllocator). It's used for native code.
* It's also a good idea to keep code and data separate to avoid I-cache
* vs. D-cache issues.
*/
VMAllocator* dataAlloc;
VMAllocator* traceAlloc;
VMAllocator* tempAlloc;
nanojit::CodeAlloc* codeAlloc;
nanojit::Assembler* assembler;
FrameInfoCache* frameCache;
/* This gets incremented every time the monitor is flushed. */
uintN flushEpoch;
Oracle* oracle;
TraceRecorder* recorder;
/* If we are profiling a loop, this tracks the current profile. Otherwise NULL. */
LoopProfile* profile;
GlobalState globalStates[MONITOR_N_GLOBAL_STATES];
TreeFragment* vmfragments[FRAGMENT_TABLE_SIZE];
RecordAttemptMap* recordAttempts;
/* A hashtable mapping PC values to loop profiles for those loops. */
LoopProfileMap* loopProfiles;
/*
* Maximum size of the code cache before we start flushing. 1/16 of this
* size is used as threshold for the regular expression code cache.
*/
uint32 maxCodeCacheBytes;
/*
* If nonzero, do not flush the JIT cache after a deep bail. That would
* free JITted code pages that we will later return to. Instead, set the
* needFlush flag so that it can be flushed later.
*/
JSBool needFlush;
/*
* Fragment map for the regular expression compiler.
*/
REHashMap* reFragments;
// Cached temporary typemap to avoid realloc'ing every time we create one.
// This must be used in only one place at a given time. It must be cleared
// before use.
TypeMap* cachedTempTypeMap;
/* Scripts with recorded fragments. */
TracedScriptSet tracedScripts;
#ifdef DEBUG
/* Fields needed for fragment/guard profiling. */
nanojit::Seq<nanojit::Fragment*>* branches;
uint32 lastFragID;
/*
* profAlloc has a lifetime which spans exactly from js_InitJIT to
* js_FinishJIT.
*/
VMAllocator* profAlloc;
FragStatsMap* profTab;
#endif
bool ontrace() const {
return !!tracecx;
}
/* Flush the JIT cache. */
void flush();
/* Sweep any cache entry pointing to dead GC things. */
void sweep();
bool outOfMemory() const;
};
} /* namespace js */ } /* namespace js */
/* /*
@ -1038,23 +897,6 @@ struct TraceMonitor {
# define JS_ON_TRACE(cx) false # define JS_ON_TRACE(cx) false
#endif #endif
/* Number of potentially reusable scriptsToGC to search for the eval cache. */
#ifndef JS_EVAL_CACHE_SHIFT
# define JS_EVAL_CACHE_SHIFT 6
#endif
#define JS_EVAL_CACHE_SIZE JS_BIT(JS_EVAL_CACHE_SHIFT)
#ifdef DEBUG
# define EVAL_CACHE_METER_LIST(_) _(probe), _(hit), _(step), _(noscope)
# define identity(x) x
struct JSEvalCacheMeter {
uint64 EVAL_CACHE_METER_LIST(identity);
};
# undef identity
#endif
#ifdef DEBUG #ifdef DEBUG
# define FUNCTION_KIND_METER_LIST(_) \ # define FUNCTION_KIND_METER_LIST(_) \
_(allfun), _(heavy), _(nofreeupvar), _(onlyfreevar), \ _(allfun), _(heavy), _(nofreeupvar), _(onlyfreevar), \
@ -1077,10 +919,6 @@ struct JSFunctionMeter {
#endif #endif
#define NATIVE_ITER_CACHE_LOG2 8
#define NATIVE_ITER_CACHE_MASK JS_BITMASK(NATIVE_ITER_CACHE_LOG2)
#define NATIVE_ITER_CACHE_SIZE JS_BIT(NATIVE_ITER_CACHE_LOG2)
struct JSPendingProxyOperation { struct JSPendingProxyOperation {
JSPendingProxyOperation *next; JSPendingProxyOperation *next;
JSObject *object; JSObject *object;
@ -1118,18 +956,8 @@ struct JSThreadData {
js::PropertyCache propertyCache; js::PropertyCache propertyCache;
#ifdef JS_TRACER #ifdef JS_TRACER
/* Trace-tree JIT recorder/interpreter state. */ /* Maximum size of the tracer's code cache before we start flushing. */
js::TraceMonitor traceMonitor; uint32 maxCodeCacheBytes;
/* Counts the number of iterations run by a trace. */
unsigned iterationCounter;
#endif
/* Lock-free hashed lists of scripts created by eval to garbage-collect. */
JSScript *scriptsToGC[JS_EVAL_CACHE_SIZE];
#ifdef DEBUG
JSEvalCacheMeter evalCacheMeter;
#endif #endif
/* State used by dtoa.c. */ /* State used by dtoa.c. */
@ -1149,12 +977,6 @@ struct JSThreadData {
JSString *s; // if s==NULL, d and base are not valid JSString *s; // if s==NULL, d and base are not valid
} dtoaCache; } dtoaCache;
/* Cached native iterators. */
JSObject *cachedNativeIterators[NATIVE_ITER_CACHE_SIZE];
/* Native iterator most recently started. */
JSObject *lastNativeIterator;
/* Base address of the native stack for the current thread. */ /* Base address of the native stack for the current thread. */
jsuword *nativeStackBase; jsuword *nativeStackBase;
@ -1163,16 +985,6 @@ struct JSThreadData {
js::ConservativeGCThreadData conservativeGC; js::ConservativeGCThreadData conservativeGC;
private:
js::MathCache *mathCache;
js::MathCache *allocMathCache(JSContext *cx);
public:
js::MathCache *getMathCache(JSContext *cx) {
return mathCache ? mathCache : allocMathCache(cx);
}
bool init(); bool init();
void finish(); void finish();
void mark(JSTracer *trc); void mark(JSTracer *trc);
@ -1322,6 +1134,7 @@ struct JSRuntime {
uint32 gcNumber; uint32 gcNumber;
js::GCMarker *gcMarkingTracer; js::GCMarker *gcMarkingTracer;
uint32 gcTriggerFactor; uint32 gcTriggerFactor;
int64 gcJitReleaseTime;
volatile JSBool gcIsNeeded; volatile JSBool gcIsNeeded;
/* /*
@ -1369,7 +1182,7 @@ struct JSRuntime {
js::Value negativeInfinityValue; js::Value negativeInfinityValue;
js::Value positiveInfinityValue; js::Value positiveInfinityValue;
JSString *emptyString; JSFlatString *emptyString;
/* List of active contexts sharing this runtime; protected by gcLock. */ /* List of active contexts sharing this runtime; protected by gcLock. */
JSCList contextList; JSCList contextList;
@ -1725,14 +1538,6 @@ struct JSRuntime {
/* Common macros to access thread-local caches in JSThread or JSRuntime. */ /* Common macros to access thread-local caches in JSThread or JSRuntime. */
#define JS_GSN_CACHE(cx) (JS_THREAD_DATA(cx)->gsnCache) #define JS_GSN_CACHE(cx) (JS_THREAD_DATA(cx)->gsnCache)
#define JS_PROPERTY_CACHE(cx) (JS_THREAD_DATA(cx)->propertyCache) #define JS_PROPERTY_CACHE(cx) (JS_THREAD_DATA(cx)->propertyCache)
#define JS_TRACE_MONITOR(cx) (JS_THREAD_DATA(cx)->traceMonitor)
#define JS_SCRIPTS_TO_GC(cx) (JS_THREAD_DATA(cx)->scriptsToGC)
#ifdef DEBUG
# define EVAL_CACHE_METER(x) (JS_THREAD_DATA(cx)->evalCacheMeter.x++)
#else
# define EVAL_CACHE_METER(x) ((void) 0)
#endif
#ifdef DEBUG #ifdef DEBUG
# define JS_RUNTIME_METER(rt, which) JS_ATOMIC_INCREMENT(&(rt)->which) # define JS_RUNTIME_METER(rt, which) JS_ATOMIC_INCREMENT(&(rt)->which)
@ -2369,8 +2174,7 @@ struct JSContext
void assertValidStackDepth(uintN /*depth*/) {} void assertValidStackDepth(uintN /*depth*/) {}
#endif #endif
private: private:
/* /*
* The allocation code calls the function to indicate either OOM failure * The allocation code calls the function to indicate either OOM failure
* when p is null or that a memory pressure counter has reached some * when p is null or that a memory pressure counter has reached some
@ -3238,50 +3042,14 @@ js_CurrentPCIsInImacro(JSContext *cx);
namespace js { namespace js {
#ifdef JS_TRACER
/*
* Reconstruct the JS stack and clear cx->tracecx. We must be currently in a
* _FAIL builtin from trace on cx or another context on the same thread. The
* machine code for the trace remains on the C stack when js_DeepBail returns.
*
* Implemented in jstracer.cpp.
*/
JS_FORCES_STACK JS_FRIEND_API(void)
DeepBail(JSContext *cx);
#endif
static JS_FORCES_STACK JS_INLINE void
LeaveTrace(JSContext *cx)
{
#ifdef JS_TRACER
if (JS_ON_TRACE(cx))
DeepBail(cx);
#endif
}
static JS_INLINE void
LeaveTraceIfGlobalObject(JSContext *cx, JSObject *obj)
{
if (!obj->parent)
LeaveTrace(cx);
}
static JS_INLINE JSBool
CanLeaveTrace(JSContext *cx)
{
JS_ASSERT(JS_ON_TRACE(cx));
#ifdef JS_TRACER
return cx->bailExit != NULL;
#else
return JS_FALSE;
#endif
}
extern void extern void
SetPendingException(JSContext *cx, const Value &v); SetPendingException(JSContext *cx, const Value &v);
class RegExpStatics; class RegExpStatics;
extern JS_FORCES_STACK JS_FRIEND_API(void)
LeaveTrace(JSContext *cx);
} /* namespace js */ } /* namespace js */
/* /*

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

@ -42,6 +42,7 @@
#define jscntxtinlines_h___ #define jscntxtinlines_h___
#include "jscntxt.h" #include "jscntxt.h"
#include "jscompartment.h"
#include "jsparse.h" #include "jsparse.h"
#include "jsstaticcheck.h" #include "jsstaticcheck.h"
#include "jsxml.h" #include "jsxml.h"
@ -753,6 +754,36 @@ CallSetter(JSContext *cx, JSObject *obj, jsid id, PropertyOp op, uintN attrs, ui
return CallJSPropertyOpSetter(cx, op, obj, id, vp); return CallJSPropertyOpSetter(cx, op, obj, id, vp);
} }
#ifdef JS_TRACER
/*
* Reconstruct the JS stack and clear cx->tracecx. We must be currently in a
* _FAIL builtin from trace on cx or another context on the same thread. The
* machine code for the trace remains on the C stack when js_DeepBail returns.
*
* Implemented in jstracer.cpp.
*/
JS_FORCES_STACK JS_FRIEND_API(void)
DeepBail(JSContext *cx);
#endif
static JS_INLINE void
LeaveTraceIfGlobalObject(JSContext *cx, JSObject *obj)
{
if (!obj->parent)
LeaveTrace(cx);
}
static JS_INLINE JSBool
CanLeaveTrace(JSContext *cx)
{
JS_ASSERT(JS_ON_TRACE(cx));
#ifdef JS_TRACER
return cx->bailExit != NULL;
#else
return JS_FALSE;
#endif
}
} /* namespace js */ } /* namespace js */
#endif /* jscntxtinlines_h___ */ #endif /* jscntxtinlines_h___ */

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

@ -44,6 +44,7 @@
#include "jsiter.h" #include "jsiter.h"
#include "jsproxy.h" #include "jsproxy.h"
#include "jsscope.h" #include "jsscope.h"
#include "jstracer.h"
#include "methodjit/MethodJIT.h" #include "methodjit/MethodJIT.h"
#include "methodjit/PolyIC.h" #include "methodjit/PolyIC.h"
#include "methodjit/MonoIC.h" #include "methodjit/MonoIC.h"
@ -54,17 +55,36 @@ using namespace js;
using namespace js::gc; using namespace js::gc;
JSCompartment::JSCompartment(JSRuntime *rt) JSCompartment::JSCompartment(JSRuntime *rt)
: rt(rt), principals(NULL), data(NULL), marked(false), debugMode(rt->debugMode), : rt(rt),
anynameObject(NULL), functionNamespaceObject(NULL) principals(NULL),
data(NULL),
marked(false),
active(false),
debugMode(rt->debugMode),
anynameObject(NULL),
functionNamespaceObject(NULL),
mathCache(NULL)
{ {
JS_INIT_CLIST(&scripts); JS_INIT_CLIST(&scripts);
PodArrayZero(scriptsToGC);
} }
JSCompartment::~JSCompartment() JSCompartment::~JSCompartment()
{ {
#if defined JS_TRACER
FinishJIT(&traceMonitor);
#endif
#ifdef JS_METHODJIT #ifdef JS_METHODJIT
delete jaegerCompartment; delete jaegerCompartment;
#endif #endif
delete mathCache;
#ifdef DEBUG
for (size_t i = 0; i != JS_ARRAY_LENGTH(scriptsToGC); ++i)
JS_ASSERT(!scriptsToGC[i]);
#endif
} }
bool bool
@ -81,9 +101,19 @@ JSCompartment::init()
if (!crossCompartmentWrappers.init()) if (!crossCompartmentWrappers.init())
return false; return false;
#ifdef JS_METHODJIT #ifdef JS_TRACER
if (!(jaegerCompartment = new mjit::JaegerCompartment)) if (!InitJIT(&traceMonitor)) {
return false; return false;
}
#endif
#ifdef JS_METHODJIT
if (!(jaegerCompartment = new mjit::JaegerCompartment)) {
#ifdef JS_TRACER
FinishJIT(&traceMonitor);
#endif
return false;
}
return jaegerCompartment->Initialize(); return jaegerCompartment->Initialize();
#else #else
return true; return true;
@ -204,7 +234,10 @@ JSCompartment::wrap(JSContext *cx, Value *vp)
if (vp->isString()) { if (vp->isString()) {
Value orig = *vp; Value orig = *vp;
JSString *str = vp->toString(); 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) if (!wrapped)
return false; return false;
vp->setString(wrapped); vp->setString(wrapped);
@ -328,8 +361,33 @@ JSCompartment::wrapException(JSContext *cx)
return true; 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 void
JSCompartment::sweep(JSContext *cx) JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
{ {
chunk = NULL; chunk = NULL;
/* Remove dead wrappers from the table. */ /* Remove dead wrappers from the table. */
@ -343,13 +401,43 @@ JSCompartment::sweep(JSContext *cx)
} }
} }
#ifdef JS_TRACER
traceMonitor.sweep();
#endif
#if defined JS_METHODJIT && defined JS_MONOIC #if defined JS_METHODJIT && defined JS_MONOIC
/*
* 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) { for (JSCList *cursor = scripts.next; cursor != &scripts; cursor = cursor->next) {
JSScript *script = reinterpret_cast<JSScript *>(cursor); JSScript *script = reinterpret_cast<JSScript *>(cursor);
if (script->hasJITCode()) if (script->hasJITCode()) {
mjit::ic::SweepCallICs(script); 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
#endif /* JS_METHODJIT && JS_MONOIC */
active = false;
} }
void void
@ -357,6 +445,20 @@ JSCompartment::purge(JSContext *cx)
{ {
freeLists.purge(); freeLists.purge();
/* Destroy eval'ed scripts. */
js_DestroyScriptsToGC(cx, this);
nativeIterCache.purge();
#ifdef JS_TRACER
/*
* If we are about to regenerate shapes, we have to flush the JIT cache,
* which will eventually abort any current recording.
*/
if (cx->runtime->gcRegenShapes)
traceMonitor.needFlush = JS_TRUE;
#endif
#ifdef JS_METHODJIT #ifdef JS_METHODJIT
for (JSScript *script = (JSScript *)scripts.next; for (JSScript *script = (JSScript *)scripts.next;
&script->links != &scripts; &script->links != &scripts;
@ -367,8 +469,8 @@ JSCompartment::purge(JSContext *cx)
# endif # endif
# if defined JS_MONOIC # if defined JS_MONOIC
/* /*
* MICs do not refer to data which can be GC'ed, but are sensitive * MICs do not refer to data which can be GC'ed and do not generate stubs
* to shape regeneration. * which might need to be discarded, but are sensitive to shape regeneration.
*/ */
if (cx->runtime->gcRegenShapes) if (cx->runtime->gcRegenShapes)
mjit::ic::PurgeMICs(cx, script); mjit::ic::PurgeMICs(cx, script);
@ -377,3 +479,13 @@ JSCompartment::purge(JSContext *cx)
} }
#endif #endif
} }
MathCache *
JSCompartment::allocMathCache(JSContext *cx)
{
JS_ASSERT(!mathCache);
mathCache = new MathCache;
if (!mathCache)
js_ReportOutOfMemory(cx);
return mathCache;
}

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

@ -1,4 +1,4 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* *
* ***** BEGIN LICENSE BLOCK ***** * ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
@ -55,11 +55,210 @@
#endif #endif
namespace js { namespace js {
/* Holds the number of recording attemps for an address. */
typedef HashMap<jsbytecode*,
size_t,
DefaultHasher<jsbytecode*>,
SystemAllocPolicy> RecordAttemptMap;
/* Holds the profile data for loops. */
typedef HashMap<jsbytecode*,
LoopProfile*,
DefaultHasher<jsbytecode*>,
SystemAllocPolicy> LoopProfileMap;
class Oracle;
typedef HashSet<JSScript *,
DefaultHasher<JSScript *>,
SystemAllocPolicy> TracedScriptSet;
/*
* Trace monitor. Every JSCompartment has an associated trace monitor
* that keeps track of loop frequencies for all JavaScript code loaded
* into that runtime.
*/
struct TraceMonitor {
/*
* The context currently executing JIT-compiled code in this compartment, or
* NULL if none. Among other things, this can in certain cases prevent
* last-ditch GC and suppress calls to JS_ReportOutOfMemory.
*
* !tracecx && !recorder: not on trace
* !tracecx && recorder: recording
* tracecx && !recorder: executing a trace
* tracecx && recorder: executing inner loop, recording outer loop
*/
JSContext *tracecx;
/* Counts the number of iterations run by the currently executing trace. */
unsigned iterationCounter;
/*
* Cached storage to use when executing on trace. While we may enter nested
* traces, we always reuse the outer trace's storage, so never need more
* than of these.
*/
TraceNativeStorage *storage;
/*
* There are 4 allocators here. This might seem like overkill, but they
* have different lifecycles, and by keeping them separate we keep the
* amount of retained memory down significantly. They are flushed (ie.
* all the allocated memory is freed) periodically.
*
* - dataAlloc has the lifecycle of the monitor. It's flushed only when
* the monitor is flushed. It's used for fragments.
*
* - traceAlloc has the same flush lifecycle as the dataAlloc, but it is
* also *marked* when a recording starts and rewinds to the mark point
* if recording aborts. So you can put things in it that are only
* reachable on a successful record/compile cycle like GuardRecords and
* SideExits.
*
* - tempAlloc is flushed after each recording, successful or not. It's
* used to store LIR code and for all other elements in the LIR
* pipeline.
*
* - codeAlloc has the same lifetime as dataAlloc, but its API is
* different (CodeAlloc vs. VMAllocator). It's used for native code.
* It's also a good idea to keep code and data separate to avoid I-cache
* vs. D-cache issues.
*/
VMAllocator* dataAlloc;
VMAllocator* traceAlloc;
VMAllocator* tempAlloc;
nanojit::CodeAlloc* codeAlloc;
nanojit::Assembler* assembler;
FrameInfoCache* frameCache;
/* This gets incremented every time the monitor is flushed. */
uintN flushEpoch;
Oracle* oracle;
TraceRecorder* recorder;
/* If we are profiling a loop, this tracks the current profile. Otherwise NULL. */
LoopProfile* profile;
GlobalState globalStates[MONITOR_N_GLOBAL_STATES];
TreeFragment* vmfragments[FRAGMENT_TABLE_SIZE];
RecordAttemptMap* recordAttempts;
/* A hashtable mapping PC values to loop profiles for those loops. */
LoopProfileMap* loopProfiles;
/*
* Maximum size of the code cache before we start flushing. 1/16 of this
* size is used as threshold for the regular expression code cache.
*/
uint32 maxCodeCacheBytes;
/*
* If nonzero, do not flush the JIT cache after a deep bail. That would
* free JITted code pages that we will later return to. Instead, set the
* needFlush flag so that it can be flushed later.
*/
JSBool needFlush;
/*
* Fragment map for the regular expression compiler.
*/
REHashMap* reFragments;
// Cached temporary typemap to avoid realloc'ing every time we create one.
// This must be used in only one place at a given time. It must be cleared
// before use.
TypeMap* cachedTempTypeMap;
/* Scripts with recorded fragments. */
TracedScriptSet tracedScripts;
#ifdef DEBUG
/* Fields needed for fragment/guard profiling. */
nanojit::Seq<nanojit::Fragment*>* branches;
uint32 lastFragID;
/*
* profAlloc has a lifetime which spans exactly from js_InitJIT to
* js_FinishJIT.
*/
VMAllocator* profAlloc;
FragStatsMap* profTab;
#endif
bool ontrace() const {
return !!tracecx;
}
/* Flush the JIT cache. */
void flush();
/* Sweep any cache entry pointing to dead GC things. */
void sweep();
bool outOfMemory() const;
};
namespace mjit { namespace mjit {
class JaegerCompartment; class JaegerCompartment;
} }
} }
/* Number of potentially reusable scriptsToGC to search for the eval cache. */
#ifndef JS_EVAL_CACHE_SHIFT
# define JS_EVAL_CACHE_SHIFT 6
#endif
#define JS_EVAL_CACHE_SIZE JS_BIT(JS_EVAL_CACHE_SHIFT)
#ifdef DEBUG
# define EVAL_CACHE_METER_LIST(_) _(probe), _(hit), _(step), _(noscope)
# define identity(x) x
struct JSEvalCacheMeter {
uint64 EVAL_CACHE_METER_LIST(identity);
};
# undef identity
#endif
namespace js {
class NativeIterCache {
static const size_t SIZE = size_t(1) << 8;
/* Cached native iterators. */
JSObject *data[SIZE];
static size_t getIndex(uint32 key) {
return size_t(key) % SIZE;
}
public:
/* Native iterator most recently started. */
JSObject *last;
NativeIterCache()
: last(NULL) {
PodArrayZero(data);
}
void purge() {
PodArrayZero(data);
last = NULL;
}
JSObject *get(uint32 key) const {
return data[getIndex(key)];
}
void set(uint32 key, JSObject *iterobj) {
data[getIndex(key)] = iterobj;
}
};
} /* namespace js */
struct JS_FRIEND_API(JSCompartment) { struct JS_FRIEND_API(JSCompartment) {
JSRuntime *rt; JSRuntime *rt;
JSPrincipals *principals; JSPrincipals *principals;
@ -72,8 +271,21 @@ struct JS_FRIEND_API(JSCompartment) {
js::gc::JSGCArenaStats compartmentStats[js::gc::FINALIZE_LIMIT]; js::gc::JSGCArenaStats compartmentStats[js::gc::FINALIZE_LIMIT];
#endif #endif
#ifdef JS_TRACER
/* Trace-tree JIT recorder/interpreter state. */
js::TraceMonitor traceMonitor;
#endif
/* Hashed lists of scripts created by eval to garbage-collect. */
JSScript *scriptsToGC[JS_EVAL_CACHE_SIZE];
#ifdef DEBUG
JSEvalCacheMeter evalCacheMeter;
#endif
void *data; void *data;
bool marked; bool marked;
bool active; // GC flag, whether there are active frames
js::WrapperMap crossCompartmentWrappers; js::WrapperMap crossCompartmentWrappers;
#ifdef JS_METHODJIT #ifdef JS_METHODJIT
@ -93,6 +305,8 @@ struct JS_FRIEND_API(JSCompartment) {
JSObject *anynameObject; JSObject *anynameObject;
JSObject *functionNamespaceObject; JSObject *functionNamespaceObject;
js::NativeIterCache nativeIterCache;
JSCompartment(JSRuntime *cx); JSCompartment(JSRuntime *cx);
~JSCompartment(); ~JSCompartment();
@ -107,12 +321,39 @@ struct JS_FRIEND_API(JSCompartment) {
bool wrap(JSContext *cx, js::AutoIdVector &props); bool wrap(JSContext *cx, js::AutoIdVector &props);
bool wrapException(JSContext *cx); bool wrapException(JSContext *cx);
void sweep(JSContext *cx); void sweep(JSContext *cx, uint32 releaseInterval);
void purge(JSContext *cx); void purge(JSContext *cx);
void finishArenaLists(); void finishArenaLists();
bool arenaListsAreEmpty(); bool arenaListsAreEmpty();
private:
js::MathCache *mathCache;
js::MathCache *allocMathCache(JSContext *cx);
public:
js::MathCache *getMathCache(JSContext *cx) {
return mathCache ? mathCache : allocMathCache(cx);
}
}; };
#define JS_TRACE_MONITOR(cx) (cx->compartment->traceMonitor)
#define JS_SCRIPTS_TO_GC(cx) (cx->compartment->scriptsToGC)
namespace js {
static inline MathCache *
GetMathCache(JSContext *cx)
{
return cx->compartment->getMathCache(cx);
}
}
#ifdef DEBUG
# define EVAL_CACHE_METER(x) (cx->compartment->evalCacheMeter.x++)
#else
# define EVAL_CACHE_METER(x) ((void) 0)
#endif
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(pop) #pragma warning(pop)
#endif #endif

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

@ -750,7 +750,7 @@ ndigits(size_t n, size_t *result, const jschar *s, size_t* i, size_t limit)
*/ */
static JSBool static JSBool
date_parseISOString(JSString *str, jsdouble *result, JSContext *cx) date_parseISOString(JSLinearString *str, jsdouble *result, JSContext *cx)
{ {
jsdouble msec; jsdouble msec;
@ -792,7 +792,8 @@ date_parseISOString(JSString *str, jsdouble *result, JSContext *cx)
if (!ndigits(n, &field, s, &i, limit)) { goto syntax; } \ if (!ndigits(n, &field, s, &i, limit)) { goto syntax; } \
JS_END_MACRO JS_END_MACRO
str->getCharsAndLength(s, limit); s = str->chars();
limit = str->length();
if (PEEK('+') || PEEK('-')) { if (PEEK('+') || PEEK('-')) {
if (PEEK('-')) if (PEEK('-'))
@ -883,7 +884,7 @@ date_parseISOString(JSString *str, jsdouble *result, JSContext *cx)
} }
static JSBool static JSBool
date_parseString(JSString *str, jsdouble *result, JSContext *cx) date_parseString(JSLinearString *str, jsdouble *result, JSContext *cx)
{ {
jsdouble msec; jsdouble msec;
@ -907,7 +908,8 @@ date_parseString(JSString *str, jsdouble *result, JSContext *cx)
if (date_parseISOString(str, result, cx)) if (date_parseISOString(str, result, cx))
return JS_TRUE; return JS_TRUE;
str->getCharsAndLength(s, limit); s = str->chars();
limit = str->length();
if (limit == 0) if (limit == 0)
goto syntax; goto syntax;
while (i < limit) { while (i < limit) {
@ -1167,7 +1169,11 @@ date_parse(JSContext *cx, uintN argc, Value *vp)
if (!str) if (!str)
return JS_FALSE; return JS_FALSE;
vp[2].setString(str); 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); vp->setDouble(js_NaN);
return true; return true;
} }
@ -2377,8 +2383,6 @@ date_toString(JSContext *cx, uintN argc, Value *vp)
static JSBool static JSBool
date_valueOf(JSContext *cx, uintN argc, Value *vp) 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 /* 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 * need to check for that explicitly here because every path calls
* GetUTCTime, which does the check. * GetUTCTime, which does the check.
@ -2389,11 +2393,14 @@ date_valueOf(JSContext *cx, uintN argc, Value *vp)
return date_getTime(cx, argc, vp); return date_getTime(cx, argc, vp);
/* Convert to number only if the hint was given, otherwise favor string. */ /* 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) if (!str)
return JS_FALSE; return JS_FALSE;
number_str = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER]); JSLinearString *linear_str = str->ensureLinear(cx);
if (js_EqualStrings(str, number_str)) 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_getTime(cx, argc, vp);
return date_toString(cx, argc, vp); return date_toString(cx, argc, vp);
} }
@ -2487,8 +2494,11 @@ js_Date(JSContext *cx, uintN argc, Value *vp)
if (!str) if (!str)
return false; return false;
argv[0].setString(str); 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; d = js_NaN;
else else
d = TIMECLIP(d); d = TIMECLIP(d);

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

@ -145,7 +145,7 @@ js_SetDebugMode(JSContext *cx, JSBool debug)
for (JSScript *script = (JSScript *)cx->compartment->scripts.next; for (JSScript *script = (JSScript *)cx->compartment->scripts.next;
&script->links != &cx->compartment->scripts; &script->links != &cx->compartment->scripts;
script = (JSScript *)script->links.next) { script = (JSScript *)script->links.next) {
if (script->debugMode != (bool) debug && if (script->debugMode != !!debug &&
script->hasJITCode() && script->hasJITCode() &&
!IsScriptLive(cx, script)) { !IsScriptLive(cx, script)) {
/* /*
@ -182,6 +182,30 @@ JS_SetDebugMode(JSContext *cx, JSBool debug)
return js_SetDebugMode(cx, 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 static JSBool
CheckDebugMode(JSContext *cx) CheckDebugMode(JSContext *cx)
{ {
@ -198,6 +222,15 @@ CheckDebugMode(JSContext *cx)
return debugMode; 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. * NB: FindTrap must be called with rt->debuggerLock acquired.
*/ */
@ -485,17 +518,6 @@ JITInhibitingHookChange(JSRuntime *rt, bool wasInhibited)
js_ContextFromLinkField(cl)->traceJitEnabled = false; js_ContextFromLinkField(cl)->traceJitEnabled = false;
} }
} }
static void
LeaveTraceRT(JSRuntime *rt)
{
JSThreadData *data = js_CurrentThreadData(rt);
JSContext *cx = data ? data->traceMonitor.tracecx : NULL;
JS_UNLOCK_GC(rt);
if (cx)
LeaveTrace(cx);
}
#endif #endif
JS_PUBLIC_API(JSBool) JS_PUBLIC_API(JSBool)
@ -511,7 +533,6 @@ JS_SetInterrupt(JSRuntime *rt, JSInterruptHook hook, void *closure)
#ifdef JS_TRACER #ifdef JS_TRACER
JITInhibitingHookChange(rt, wasInhibited); JITInhibitingHookChange(rt, wasInhibited);
} }
LeaveTraceRT(rt);
#endif #endif
return JS_TRUE; return JS_TRUE;
} }
@ -1672,8 +1693,6 @@ JS_SetCallHook(JSRuntime *rt, JSInterpreterHook hook, void *closure)
#ifdef JS_TRACER #ifdef JS_TRACER
JITInhibitingHookChange(rt, wasInhibited); JITInhibitingHookChange(rt, wasInhibited);
} }
if (hook)
LeaveTraceRT(rt);
#endif #endif
return JS_TRUE; return JS_TRUE;
} }
@ -1995,15 +2014,13 @@ JS_FRIEND_API(JSBool)
js_DumpCallgrind(JSContext *cx, uintN argc, jsval *vp) js_DumpCallgrind(JSContext *cx, uintN argc, jsval *vp)
{ {
JSString *str; JSString *str;
char *cstr;
jsval *argv = JS_ARGV(cx, vp); jsval *argv = JS_ARGV(cx, vp);
if (argc > 0 && JSVAL_IS_STRING(argv[0])) { if (argc > 0 && JSVAL_IS_STRING(argv[0])) {
str = JSVAL_TO_STRING(argv[0]); str = JSVAL_TO_STRING(argv[0]);
cstr = js_DeflateString(cx, str->chars(), str->length()); JSAutoByteString bytes(cx, str);
if (cstr) { if (!!bytes) {
CALLGRIND_DUMP_STATS_AT(cstr); CALLGRIND_DUMP_STATS_AT(bytes.ptr());
cx->free(cstr);
return JS_TRUE; return JS_TRUE;
} }
} }
@ -2245,7 +2262,7 @@ public:
JSHashNumber hash = JS_HashString(filename); JSHashNumber hash = JS_HashString(filename);
JSHashEntry **hep = JS_HashTableRawLookup(traceVisScriptTable, hash, filename); JSHashEntry **hep = JS_HashTableRawLookup(traceVisScriptTable, hash, filename);
if (*hep != NULL) if (*hep != NULL)
return JS_FALSE; return NULL;
JS_HashTableRawAdd(traceVisScriptTable, hep, hash, filename, this); JS_HashTableRawAdd(traceVisScriptTable, hep, hash, filename, this);

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

@ -78,6 +78,14 @@ js_SetDebugMode(JSContext *cx, JSBool debug);
extern JS_PUBLIC_API(JSBool) extern JS_PUBLIC_API(JSBool)
JS_SetDebugMode(JSContext *cx, JSBool debug); 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. * 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 * Returns script->code if script has no traps, else a JS_malloc'ed copy of

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

@ -2270,7 +2270,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
} }
/* Optimize accesses to undeclared globals. */ /* Optimize accesses to undeclared globals. */
if (!TryConvertToGname(cg, pn, &op)) if (!cg->mightAliasLocals() && !TryConvertToGname(cg, pn, &op))
return JS_TRUE; return JS_TRUE;
ale = cg->atomList.add(cg->parser, atom); ale = cg->atomList.add(cg->parser, atom);
@ -2500,15 +2500,28 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
JS_ASSERT((cg->fun()->flags & JSFUN_LAMBDA) && atom == cg->fun()->atom); JS_ASSERT((cg->fun()->flags & JSFUN_LAMBDA) && atom == cg->fun()->atom);
/* /*
* Leave pn->pn_op == JSOP_NAME if cg->fun() is heavyweight, as we * Leave pn->pn_op == JSOP_NAME if cg->fun is heavyweight to
* cannot be sure cg->fun() is not something of the form: * address two cases: a new binding introduced by eval, and
* assignment to the name in strict mode.
* *
* var ff = (function f(s) { eval(s); return f; }); * var fun = (function f(s) { eval(s); return f; });
* assertEq(fun("var f = 42"), 42);
* *
* where a caller invokes ff("var f = 42"). The result returned for * ECMAScript specifies that a function expression's name is bound
* such an invocation must be 42, since the callee name is * in a lexical environment distinct from that used to bind its
* lexically bound in an outer declarative environment from the * named parameters, the arguments object, and its variables. The
* function's activation. See jsfun.cpp:call_resolve. * new binding for "var f = 42" shadows the binding for the
* function itself, so the name of the function will not refer to
* the function.
*
* (function f() { "use strict"; f = 12; })();
*
* Outside strict mode, assignment to a function expression's name
* has no effect. But in strict mode, this attempt to mutate an
* immutable binding must throw a TypeError. We implement this by
* not optimizing such assignments and by marking such functions as
* heavyweight, ensuring that the function name is represented in
* the scope chain so that assignment will throw a TypeError.
*/ */
JS_ASSERT(op != JSOP_DELNAME); JS_ASSERT(op != JSOP_DELNAME);
if (!(cg->flags & TCF_FUN_HEAVYWEIGHT)) { if (!(cg->flags & TCF_FUN_HEAVYWEIGHT)) {
@ -3764,6 +3777,13 @@ js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body)
CG_SWITCH_TO_MAIN(cg); CG_SWITCH_TO_MAIN(cg);
} }
/*
* Strict mode functions' arguments objects copy initial parameter values.
* We create arguments objects lazily -- but that doesn't work for strict
* mode functions where a parameter might be modified and arguments might
* be accessed. For such functions we synthesize an access to arguments to
* initialize it with the original parameter values.
*/
if (cg->needsEagerArguments()) { if (cg->needsEagerArguments()) {
CG_SWITCH_TO_PROLOG(cg); CG_SWITCH_TO_PROLOG(cg);
if (js_Emit1(cx, cg, JSOP_ARGUMENTS) < 0 || js_Emit1(cx, cg, JSOP_POP) < 0) if (js_Emit1(cx, cg, JSOP_ARGUMENTS) < 0 || js_Emit1(cx, cg, JSOP_POP) < 0)
@ -4613,7 +4633,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
if (!cg2->init()) if (!cg2->init())
return JS_FALSE; return JS_FALSE;
cg2->flags = pn->pn_funbox->tcflags | TCF_COMPILING | TCF_IN_FUNCTION; cg2->flags = pn->pn_funbox->tcflags | TCF_COMPILING | TCF_IN_FUNCTION |
(cg->flags & TCF_FUN_MIGHT_ALIAS_LOCALS);
#if JS_HAS_SHARP_VARS #if JS_HAS_SHARP_VARS
if (cg2->flags & TCF_HAS_SHARPS) { if (cg2->flags & TCF_HAS_SHARPS) {
cg2->sharpSlotBase = fun->sharpSlotBase(cx); cg2->sharpSlotBase = fun->sharpSlotBase(cx);

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

@ -252,10 +252,8 @@ struct JSStmtInfo {
#define TCF_COMPILE_FOR_EVAL 0x2000000 #define TCF_COMPILE_FOR_EVAL 0x2000000
/* /*
* The function has broken or incorrect def-use information, and it cannot * The function or a function that encloses it may define new local names
* safely optimize free variables to global names. This can happen because * at runtime through means other than calling eval.
* of a named function statement not at the top level (emitting a DEFFUN),
* or a variable declaration inside a "with".
*/ */
#define TCF_FUN_MIGHT_ALIAS_LOCALS 0x4000000 #define TCF_FUN_MIGHT_ALIAS_LOCALS 0x4000000

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

@ -612,10 +612,11 @@ StackTraceToString(JSContext *cx, JSExnPrivate *priv)
#define APPEND_STRING_TO_STACK(str) \ #define APPEND_STRING_TO_STACK(str) \
JS_BEGIN_MACRO \ JS_BEGIN_MACRO \
JSString *str_ = str; \ JSString *str_ = str; \
const jschar *chars_; \ size_t length_ = str_->length(); \
size_t length_; \ const jschar *chars_ = str_->getChars(cx); \
if (!chars_) \
goto bad; \
\ \
str_->getCharsAndLength(chars_, length_); \
if (length_ > stackmax - stacklen) { \ if (length_ > stackmax - stacklen) { \
void *ptr_; \ void *ptr_; \
if (stackmax >= STACK_LENGTH_LIMIT || \ if (stackmax >= STACK_LENGTH_LIMIT || \
@ -813,11 +814,17 @@ exn_toString(JSContext *cx, uintN argc, Value *vp)
return JS_FALSE; return JS_FALSE;
if (name_length) { 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 += name_length;
*cp++ = ':'; *cp++ = ' '; *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 += message_length;
*cp = 0; *cp = 0;
@ -917,18 +924,27 @@ exn_toSource(JSContext *cx, uintN argc, Value *vp)
return false; return false;
*cp++ = '('; *cp++ = 'n'; *cp++ = 'e'; *cp++ = 'w'; *cp++ = ' '; *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 += name_length;
*cp++ = '('; *cp++ = '(';
const jschar *message_chars = message->getChars(cx);
if (!message_chars)
return false;
if (message_length != 0) { if (message_length != 0) {
js_strncpy(cp, message->chars(), message_length); js_strncpy(cp, message_chars, message_length);
cp += message_length; cp += message_length;
} }
if (filename_length != 0) { if (filename_length != 0) {
/* append filename as ``, {filename}'' */ /* append filename as ``, {filename}'' */
*cp++ = ','; *cp++ = ' '; *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; cp += filename_length;
} else { } else {
if (lineno_as_str) { if (lineno_as_str) {
@ -942,7 +958,10 @@ exn_toSource(JSContext *cx, uintN argc, Value *vp)
if (lineno_as_str) { if (lineno_as_str) {
/* append lineno as ``, {lineno_as_str}'' */ /* append lineno as ``, {lineno_as_str}'' */
*cp++ = ','; *cp++ = ' '; *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; cp += lineno_length;
} }

48
js/src/jsfriendapi.cpp Normal file
Просмотреть файл

@ -0,0 +1,48 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=4 sw=4 et tw=99:
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is SpiderMonkey code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "jscntxt.h"
#include "jsfriendapi.h"
JS_FRIEND_API(JSString *)
JS_GetAnonymousString(JSRuntime *rt)
{
JS_ASSERT(rt->state == JSRTS_UP);
return ATOM_TO_STRING(rt->atomState.anonymousAtom);
}

53
js/src/jsfriendapi.h Normal file
Просмотреть файл

@ -0,0 +1,53 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
*
* The Original Code is SpiderMonkey code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef jsfriendapi_h___
#define jsfriendapi_h___
#include "jspubtd.h"
#include "jsprvtd.h"
JS_BEGIN_EXTERN_C
extern JS_FRIEND_API(JSString *)
JS_GetAnonymousString(JSRuntime *rt);
JS_END_EXTERN_C
#endif /* jsfriendapi_h___ */

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

@ -598,27 +598,30 @@ args_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
JS_ASSERT(obj->isNormalArguments()); JS_ASSERT(obj->isNormalArguments());
*objp = NULL; *objp = NULL;
bool valid = false;
uintN attrs = JSPROP_SHARED; uintN attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
if (JSID_IS_INT(id)) { if (JSID_IS_INT(id)) {
uint32 arg = uint32(JSID_TO_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))
if (arg < obj->getArgsInitialLength() && !obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE)) return true;
valid = true;
attrs |= JSPROP_ENUMERATE;
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
if (!obj->isArgsLengthOverridden()) if (obj->isArgsLengthOverridden())
valid = true; return true;
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)) { } else {
if (!obj->getArgsCallee().isMagic(JS_ARGS_HOLE)) if (!JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom))
valid = true; return true;
if (obj->getArgsCallee().isMagic(JS_ARGS_HOLE))
return true;
} }
if (valid) { Value undef = UndefinedValue();
Value tmp = UndefinedValue(); if (!js_DefineProperty(cx, obj, id, &undef, ArgGetter, ArgSetter, attrs))
if (!js_DefineProperty(cx, obj, id, &tmp, ArgGetter, ArgSetter, attrs)) return JS_FALSE;
return JS_FALSE;
*objp = obj; *objp = obj;
}
return true; return true;
} }
@ -707,47 +710,35 @@ strictargs_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject
JS_ASSERT(obj->isStrictArguments()); JS_ASSERT(obj->isStrictArguments());
*objp = NULL; *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)) { if (JSID_IS_INT(id)) {
uint32 arg = uint32(JSID_TO_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))
if (arg < obj->getArgsInitialLength() && !obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE)) return true;
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;
*objp = obj; attrs |= JSPROP_ENUMERATE;
return true; } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.callerAtom)) { if (obj->isArgsLengthOverridden())
/* return true;
* Strict mode arguments objects have an immutable poison-pill caller } else {
* property that throws a TypeError on getting or setting. if (!JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom) &&
*/ !JSID_IS_ATOM(id, cx->runtime->atomState.callerAtom)) {
PropertyOp throwTypeError = CastAsPropertyOp(obj->getThrowTypeError()); return true;
Value tmp = UndefinedValue();
if (!js_DefineProperty(cx, obj, id, &tmp, throwTypeError, throwTypeError,
JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED)) {
return false;
} }
*objp = obj; attrs = JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED;
return true; getter = setter = CastAsPropertyOp(obj->getThrowTypeError());
} }
if (valid) { Value undef = UndefinedValue();
Value tmp = UndefinedValue(); if (!js_DefineProperty(cx, obj, id, &undef, getter, setter, attrs))
if (!js_DefineProperty(cx, obj, id, &tmp, StrictArgGetter, StrictArgSetter, attrs)) return false;
return false;
*objp = obj; *objp = obj;
}
return true; return true;
} }
@ -1589,10 +1580,13 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
/* Censor the caller if it is from another compartment. */ /* Censor the caller if it is from another compartment. */
if (caller.getCompartment() != cx->compartment) { if (caller.getCompartment() != cx->compartment) {
vp->setNull(); vp->setNull();
} else if (caller.isFunction() && caller.getFunctionPrivate()->inStrictMode()) { } else if (caller.isFunction()) {
JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL, JSFunction *callerFun = caller.getFunctionPrivate();
JSMSG_CALLER_IS_STRICT); if (callerFun->isInterpreted() && callerFun->inStrictMode()) {
return false; JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
JSMSG_CALLER_IS_STRICT);
return false;
}
} }
} }
break; break;
@ -1762,7 +1756,7 @@ fun_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
PropertyOp getter, setter; PropertyOp getter, setter;
uintN attrs = JSPROP_PERMANENT; uintN attrs = JSPROP_PERMANENT;
if (fun->inStrictMode() || obj->isBoundFunction()) { if (fun->isInterpreted() ? fun->inStrictMode() : obj->isBoundFunction()) {
JSObject *throwTypeError = obj->getThrowTypeError(); JSObject *throwTypeError = obj->getThrowTypeError();
getter = CastAsPropertyOp(throwTypeError); getter = CastAsPropertyOp(throwTypeError);
@ -2060,7 +2054,7 @@ fun_finalize(JSContext *cx, JSObject *obj)
* very early. * very early.
*/ */
if (FUN_INTERPRETED(fun) && fun->u.i.script) if (FUN_INTERPRETED(fun) && fun->u.i.script)
js_DestroyScriptFromGC(cx, fun->u.i.script, NULL); js_DestroyScriptFromGC(cx, fun->u.i.script);
} }
int int
@ -2603,7 +2597,12 @@ Function(JSContext *cx, uintN argc, Value *vp)
for (uintN i = 0; i < n; i++) { for (uintN i = 0; i < n; i++) {
JSString *arg = argv[i].toString(); JSString *arg = argv[i].toString();
size_t arg_length = arg->length(); 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; cp += arg_length;
/* Add separating comma or terminating 0. */ /* Add separating comma or terminating 0. */
@ -2690,8 +2689,11 @@ Function(JSContext *cx, uintN argc, Value *vp)
str = cx->runtime->emptyString; str = cx->runtime->emptyString;
} }
return Compiler::compileFunctionBody(cx, fun, principals, size_t length = str->length();
str->chars(), str->length(), const jschar *chars = str->getChars(cx);
if (!chars)
return JS_FALSE;
return Compiler::compileFunctionBody(cx, fun, principals, chars, length,
filename, lineno); filename, lineno);
} }
@ -3143,54 +3145,21 @@ JSFunction::addLocal(JSContext *cx, JSAtom *atom, JSLocalKind kind)
return false; return false;
} }
Shape **listp = &u.i.names;
Shape *parent = *listp;
jsid id; jsid id;
/*
* The destructuring formal parameter parser adds a null atom, which we
* encode as an INT id. The parser adds such locals after adding vars for
* the destructured-to parameter bindings -- those must be vars to avoid
* aliasing arguments[i] for any i -- so we must switch u.i.names to a
* dictionary list to cope with insertion "in the middle" of an index-named
* shape for the object or array argument.
*/
bool findArgInsertionPoint = false;
if (!atom) { if (!atom) {
JS_ASSERT(kind == JSLOCAL_ARG); JS_ASSERT(kind == JSLOCAL_ARG);
if (u.i.nvars != 0) {
/*
* A dictionary list needed only if the destructing pattern wasn't
* empty, i.e., there were vars for its destructured-to bindings.
*/
if (!parent->inDictionary() && !(parent = Shape::newDictionaryList(cx, listp)))
return false;
findArgInsertionPoint = true;
}
id = INT_TO_JSID(nargs); id = INT_TO_JSID(nargs);
} else { } else {
if (kind == JSLOCAL_ARG && parent->inDictionary())
findArgInsertionPoint = true;
id = ATOM_TO_JSID(atom); id = ATOM_TO_JSID(atom);
} }
if (findArgInsertionPoint) {
while (parent->parent && parent->getter() != GetCallArg) {
++parent->slot;
JS_ASSERT(parent->slot == parent->slotSpan);
++parent->slotSpan;
listp = &parent->parent;
parent = *listp;
}
}
Shape child(id, getter, setter, slot, attrs, Shape::HAS_SHORTID, *indexp); Shape child(id, getter, setter, slot, attrs, Shape::HAS_SHORTID, *indexp);
Shape *shape = parent->getChild(cx, child, listp); Shape *shape = u.i.names->getChild(cx, child, &u.i.names);
if (!shape) if (!shape)
return false; return false;
JS_ASSERT_IF(!shape->inDictionary(), u.i.names == shape); JS_ASSERT(u.i.names == shape);
++*indexp; ++*indexp;
return true; return true;
} }

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

@ -180,10 +180,9 @@ struct JSFunction : public JSObject_Slots2
bool isFunctionPrototype() const { return flags & JSFUN_PROTOTYPE; } bool isFunctionPrototype() const { return flags & JSFUN_PROTOTYPE; }
/* Returns the strictness of this function, which must be interpreted. */
inline bool inStrictMode() const; inline bool inStrictMode() const;
bool acceptsPrimitiveThis() const { return flags & JSFUN_PRIMITIVE_THIS; }
uintN countVars() const { uintN countVars() const {
JS_ASSERT(FUN_INTERPRETED(this)); JS_ASSERT(FUN_INTERPRETED(this));
return u.i.nvars; return u.i.nvars;
@ -215,6 +214,11 @@ struct JSFunction : public JSObject_Slots2
const js::Shape *lastVar() const; const js::Shape *lastVar() const;
const js::Shape *lastUpvar() const { return u.i.names; } const js::Shape *lastUpvar() const { return u.i.names; }
/*
* The parser builds shape paths for functions, usable by Call objects at
* runtime, by calling addLocal. All locals of ARG kind must be addLocal'ed
* before any VAR kind, and VAR before UPVAR.
*/
bool addLocal(JSContext *cx, JSAtom *atom, JSLocalKind kind); bool addLocal(JSContext *cx, JSAtom *atom, JSLocalKind kind);
/* /*
@ -435,6 +439,14 @@ IsFunctionObject(const js::Value &v, JSFunction **fun)
return b; 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 * Macro to access the private slot of the function object after the slot is
* initialized. * initialized.

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

@ -46,7 +46,7 @@
inline bool inline bool
JSFunction::inStrictMode() const JSFunction::inStrictMode() const
{ {
return isInterpreted() && u.i.script->strictModeCode; return script()->strictModeCode;
} }
#endif /* jsfuninlines_h___ */ #endif /* jsfuninlines_h___ */

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

@ -492,6 +492,13 @@ js_GCThingIsMarked(void *thing, uint32 color = BLACK)
return reinterpret_cast<Cell *>(thing)->isMarked(color); 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 JSBool
js_InitGC(JSRuntime *rt, uint32 maxbytes) js_InitGC(JSRuntime *rt, uint32 maxbytes)
{ {
@ -539,6 +546,8 @@ js_InitGC(JSRuntime *rt, uint32 maxbytes)
*/ */
rt->setGCLastBytes(8192); rt->setGCLastBytes(8192);
rt->gcJitReleaseTime = PRMJ_Now() + JIT_SCRIPT_EIGHTH_LIFETIME;
METER(PodZero(&rt->gcStats)); METER(PodZero(&rt->gcStats));
return true; return true;
} }
@ -777,16 +786,18 @@ ConservativeGCThreadData::recordStackTop()
jsuword dummy; jsuword dummy;
nativeStackTop = &dummy; nativeStackTop = &dummy;
/* Update the register snapshot with the latest values. */ /*
* To record and update the register snapshot for the conservative
* scanning with the latest values we use setjmp.
*/
#if defined(_MSC_VER) #if defined(_MSC_VER)
# pragma warning(push) # pragma warning(push)
# pragma warning(disable: 4611) # pragma warning(disable: 4611)
#endif #endif
setjmp(registerSnapshot.jmpbuf); (void) setjmp(registerSnapshot.jmpbuf);
#if defined(_MSC_VER) #if defined(_MSC_VER)
# pragma warning(pop) # pragma warning(pop)
#endif #endif
} }
static inline void static inline void
@ -1016,7 +1027,7 @@ FreeLists::purge()
*p = NULL; *p = NULL;
} }
struct JSShortString; class JSShortString;
ArenaList * ArenaList *
GetFinalizableArenaList(JSCompartment *c, unsigned thingKind) { GetFinalizableArenaList(JSCompartment *c, unsigned thingKind) {
@ -1435,8 +1446,10 @@ js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp)
MarkObject(trc, fp->callObj(), "call"); MarkObject(trc, fp->callObj(), "call");
if (fp->hasArgsObj()) if (fp->hasArgsObj())
MarkObject(trc, fp->argsObj(), "arguments"); MarkObject(trc, fp->argsObj(), "arguments");
if (fp->isScriptFrame()) if (fp->isScriptFrame()) {
js_TraceScript(trc, fp->script()); js_TraceScript(trc, fp->script());
fp->script()->compartment->active = true;
}
MarkValue(trc, fp->returnValue(), "rval"); MarkValue(trc, fp->returnValue(), "rval");
} }
@ -1732,16 +1745,16 @@ TriggerGC(JSRuntime *rt)
} /* namespace js */ } /* namespace js */
void void
js_DestroyScriptsToGC(JSContext *cx, JSThreadData *data) js_DestroyScriptsToGC(JSContext *cx, JSCompartment *comp)
{ {
JSScript **listp, *script; JSScript **listp, *script;
for (size_t i = 0; i != JS_ARRAY_LENGTH(data->scriptsToGC); ++i) { for (size_t i = 0; i != JS_ARRAY_LENGTH(comp->scriptsToGC); ++i) {
listp = &data->scriptsToGC[i]; listp = &comp->scriptsToGC[i];
while ((script = *listp) != NULL) { while ((script = *listp) != NULL) {
*listp = script->u.nextToGC; *listp = script->u.nextToGC;
script->u.nextToGC = NULL; script->u.nextToGC = NULL;
js_DestroyScriptFromGC(cx, script, data); js_DestroyScriptFromGC(cx, script);
} }
} }
} }
@ -1767,7 +1780,7 @@ js_FinalizeStringRT(JSRuntime *rt, JSString *str)
JS_ASSERT(IsFinalizableStringKind(thingKind)); JS_ASSERT(IsFinalizableStringKind(thingKind));
/* A stillborn string has null chars, so is not valid. */ /* A stillborn string has null chars, so is not valid. */
jschar *chars = str->flatChars(); jschar *chars = const_cast<jschar *>(str->flatChars());
if (!chars) if (!chars)
return; return;
if (thingKind == FINALIZE_STRING) { if (thingKind == FINALIZE_STRING) {
@ -2029,13 +2042,29 @@ SweepCompartments(JSContext *cx, JSGCInvocationKind gckind)
/* Delete defaultCompartment only during runtime shutdown */ /* Delete defaultCompartment only during runtime shutdown */
rt->defaultCompartment->marked = true; 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) { while (read < end) {
JSCompartment *compartment = (*read++); JSCompartment *compartment = (*read++);
if (compartment->marked) { if (compartment->marked) {
compartment->marked = false; compartment->marked = false;
*write++ = compartment; *write++ = compartment;
/* Remove dead wrappers from the compartment map. */ /* Remove dead wrappers from the compartment map. */
compartment->sweep(cx); compartment->sweep(cx, releaseInterval);
} else { } else {
JS_ASSERT(compartment->freeLists.isEmpty()); JS_ASSERT(compartment->freeLists.isEmpty());
if (compartment->arenaListsAreEmpty() || gckind == GC_LAST_CONTEXT) { if (compartment->arenaListsAreEmpty() || gckind == GC_LAST_CONTEXT) {
@ -2047,7 +2076,7 @@ SweepCompartments(JSContext *cx, JSGCInvocationKind gckind)
} else { } else {
compartment->marked = false; compartment->marked = false;
*write++ = compartment; *write++ = compartment;
compartment->sweep(cx); compartment->sweep(cx, releaseInterval);
} }
} }
} }
@ -2177,11 +2206,6 @@ MarkAndSweep(JSContext *cx, JSGCInvocationKind gckind GCTIMER_PARAM)
rt->liveObjectPropsPreSweep = rt->liveObjectProps; rt->liveObjectPropsPreSweep = rt->liveObjectProps;
#endif #endif
#ifdef JS_TRACER
for (ThreadDataIter i(rt); !i.empty(); i.popFront())
i.threadData()->traceMonitor.sweep();
#endif
/* /*
* We finalize iterators before other objects so the iterator can use the * We finalize iterators before other objects so the iterator can use the
* object which properties it enumerates over to finalize the enumeration * object which properties it enumerates over to finalize the enumeration
@ -2589,6 +2613,7 @@ NewCompartment(JSContext *cx, JSPrincipals *principals)
JSRuntime *rt = cx->runtime; JSRuntime *rt = cx->runtime;
JSCompartment *compartment = new JSCompartment(rt); JSCompartment *compartment = new JSCompartment(rt);
if (!compartment || !compartment->init()) { if (!compartment || !compartment->init()) {
delete compartment;
JS_ReportOutOfMemory(cx); JS_ReportOutOfMemory(cx);
return NULL; return NULL;
} }

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

@ -827,7 +827,7 @@ js_WaitForGC(JSRuntime *rt);
#endif #endif
extern void extern void
js_DestroyScriptsToGC(JSContext *cx, JSThreadData *data); js_DestroyScriptsToGC(JSContext *cx, JSCompartment *comp);
namespace js { namespace js {

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

@ -272,8 +272,6 @@ MarkChildren(JSTracer *trc, JSString *str)
if (str->isDependent()) if (str->isDependent())
MarkString(trc, str->dependentBase(), "base"); MarkString(trc, str->dependentBase(), "base");
else if (str->isRope()) { else if (str->isRope()) {
if (str->isInteriorNode())
MarkString(trc, str->interiorNodeParent(), "parent");
MarkString(trc, str->ropeLeft(), "left child"); MarkString(trc, str->ropeLeft(), "left child");
MarkString(trc, str->ropeRight(), "right child"); MarkString(trc, str->ropeRight(), "right child");
} }
@ -347,37 +345,116 @@ TypedMarker(JSTracer *trc, JSFunction *thing)
static JS_ALWAYS_INLINE void static JS_ALWAYS_INLINE void
TypedMarker(JSTracer *trc, JSShortString *thing) TypedMarker(JSTracer *trc, JSShortString *thing)
{ {
thing->asCell()->markIfUnmarked(); /*
* A short string cannot refer to other GC things so we don't have
* anything to mark if the string was unmarked and ignore the
* markIfUnmarked result.
*/
(void) thing->asCell()->markIfUnmarked();
} }
} /* 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 static JS_ALWAYS_INLINE void
TypedMarker(JSTracer *trc, JSString *str) TypedMarker(JSTracer *trc, JSString *str)
{ {
/* using namespace detail;
* When marking any node of a rope, mark the entire rope. This means if
* a given rope node is already marked, we are done. if (!str->isRope()) {
*/ NonRopeTypedMarker(str);
JSRopeNodeIterator iter; return;
if (str->isRope()) {
if (str->asCell()->isMarked())
return;
str = iter.init(str);
goto not_static;
} }
do {
for (;;) { /*
if (JSString::isStatic(str)) * This function must not fail, so a simple stack-based traversal must not
break; * be used (since it may oom if the stack grows large). Instead, strings
not_static: * are temporarily mutated to embed parent pointers as they are traversed.
JS_ASSERT(JSTRACE_STRING == GetFinalizableTraceKind(str->asCell()->arena()->header()->thingKind)); * This algorithm is homomorphic to JSString::flatten.
if (!str->asCell()->markIfUnmarked()) */
break; JSString *parent = NULL;
if (!str->isDependent()) first_visit_node: {
break; if (!str->asCell()->markIfUnmarked())
str = str->dependentBase(); 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(); NonRopeTypedMarker(left);
} while (str); }
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 static inline void

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

@ -362,9 +362,13 @@ GCMarker::dumpConservativeRoots()
} }
case JSTRACE_STRING: { case JSTRACE_STRING: {
JSString *str = (JSString *) i->thing; JSString *str = (JSString *) i->thing;
char buf[50]; if (str->isLinear()) {
PutEscapedString(buf, sizeof buf, str, '"'); char buf[50];
fprintf(fp, "string %s", buf); PutEscapedString(buf, sizeof buf, str->assertIsLinear(), '"');
fprintf(fp, "string %s", buf);
} else {
fprintf(fp, "rope: length %d", (int)str->length());
}
break; break;
} }
# if JS_HAS_XML_SUPPORT # if JS_HAS_XML_SUPPORT

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

@ -1000,21 +1000,12 @@ Execute(JSContext *cx, JSObject *chain, JSScript *script,
Probes::startExecution(cx, script); Probes::startExecution(cx, script);
void *hookData = NULL;
if (JSInterpreterHook hook = cx->debugHooks->executeHook)
hookData = hook(cx, frame.fp(), JS_TRUE, 0, cx->debugHooks->executeHookData);
/* Run script until JSOP_STOP or error. */ /* Run script until JSOP_STOP or error. */
AutoPreserveEnumerators preserve(cx); AutoPreserveEnumerators preserve(cx);
JSBool ok = RunScript(cx, script, frame.fp()); JSBool ok = RunScript(cx, script, frame.fp());
if (result) if (result)
*result = frame.fp()->returnValue(); *result = frame.fp()->returnValue();
if (hookData) {
if (JSInterpreterHook hook = cx->debugHooks->executeHook)
hook(cx, frame.fp(), JS_FALSE, &ok, hookData);
}
Probes::stopExecution(cx, script); Probes::stopExecution(cx, script);
return !!ok; return !!ok;
@ -1143,40 +1134,44 @@ HasInstance(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp)
return JS_FALSE; return JS_FALSE;
} }
static JS_ALWAYS_INLINE bool
EqualObjects(JSContext *cx, JSObject *lobj, JSObject *robj)
{
return lobj == robj;
}
bool bool
StrictlyEqual(JSContext *cx, const Value &lref, const Value &rref) StrictlyEqual(JSContext *cx, const Value &lref, const Value &rref, JSBool *equal)
{ {
Value lval = lref, rval = rref; Value lval = lref, rval = rref;
if (SameType(lval, rval)) { if (SameType(lval, rval)) {
if (lval.isString()) if (lval.isString())
return js_EqualStrings(lval.toString(), rval.toString()); return EqualStrings(cx, lval.toString(), rval.toString(), equal);
if (lval.isDouble()) if (lval.isDouble()) {
return JSDOUBLE_COMPARE(lval.toDouble(), ==, rval.toDouble(), JS_FALSE); *equal = JSDOUBLE_COMPARE(lval.toDouble(), ==, rval.toDouble(), JS_FALSE);
if (lval.isObject()) return true;
return EqualObjects(cx, &lval.toObject(), &rval.toObject()); }
if (lval.isUndefined()) if (lval.isObject()) {
return true; *equal = &lval.toObject() == &rval.toObject();
return lval.payloadAsRawUint32() == rval.payloadAsRawUint32(); return true;
}
if (lval.isUndefined()) {
*equal = true;
return true;
}
*equal = lval.payloadAsRawUint32() == rval.payloadAsRawUint32();
return true;
} }
if (lval.isDouble() && rval.isInt32()) { if (lval.isDouble() && rval.isInt32()) {
double ld = lval.toDouble(); double ld = lval.toDouble();
double rd = rval.toInt32(); double rd = rval.toInt32();
return JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE); *equal = JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE);
return true;
} }
if (lval.isInt32() && rval.isDouble()) { if (lval.isInt32() && rval.isDouble()) {
double ld = lval.toInt32(); double ld = lval.toInt32();
double rd = rval.toDouble(); double rd = rval.toDouble();
return JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE); *equal = JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE);
return true;
} }
return false; *equal = false;
return true;
} }
static inline bool static inline bool
@ -1192,15 +1187,21 @@ IsNaN(const Value &v)
} }
bool bool
SameValue(const Value &v1, const Value &v2, JSContext *cx) SameValue(JSContext *cx, const Value &v1, const Value &v2, JSBool *same)
{ {
if (IsNegativeZero(v1)) if (IsNegativeZero(v1)) {
return IsNegativeZero(v2); *same = IsNegativeZero(v2);
if (IsNegativeZero(v2))
return false;
if (IsNaN(v1) && IsNaN(v2))
return true; return true;
return StrictlyEqual(cx, v1, v2); }
if (IsNegativeZero(v2)) {
*same = false;
return true;
}
if (IsNaN(v1) && IsNaN(v2)) {
*same = true;
return true;
}
return StrictlyEqual(cx, v1, v2, same);
} }
JSType JSType
@ -1529,7 +1530,6 @@ js_LogOpcode(JSContext *cx)
JSStackFrame *fp; JSStackFrame *fp;
JSFrameRegs *regs; JSFrameRegs *regs;
intN ndefs, n, nuses; intN ndefs, n, nuses;
JSString *str;
JSOp op; JSOp op;
logfp = (FILE *) cx->logfp; logfp = (FILE *) cx->logfp;
@ -1575,12 +1575,13 @@ js_LogOpcode(JSContext *cx)
*/ */
fputs("<call>", logfp); fputs("<call>", logfp);
} else { } else {
str = js_ValueToString(cx, *siter); JSString *str = js_ValueToString(cx, *siter);
if (!str) { JSLinearString *linearStr = str ? str->ensureLinear(cx) : NULL;
if (!linearStr) {
fputs("<null>", logfp); fputs("<null>", logfp);
} else {
JS_ClearPendingException(cx); JS_ClearPendingException(cx);
FileEscapedString(logfp, str, 0); } else {
FileEscapedString(logfp, linearStr, 0);
} }
} }
fputc(' ', logfp); fputc(' ', logfp);
@ -2203,12 +2204,14 @@ ScriptPrologue(JSContext *cx, JSStackFrame *fp)
return false; return false;
fp->functionThis().setObject(*obj); fp->functionThis().setObject(*obj);
} }
JSInterpreterHook hook = cx->debugHooks->callHook; if (fp->isExecuteFrame()) {
if (JS_UNLIKELY(hook != NULL) && !fp->isExecuteFrame()) if (JSInterpreterHook hook = cx->debugHooks->executeHook)
fp->setHookData(hook(cx, fp, JS_TRUE, 0, cx->debugHooks->callHookData)); fp->setHookData(hook(cx, fp, JS_TRUE, 0, cx->debugHooks->executeHookData));
} else {
if (!fp->isExecuteFrame()) if (JSInterpreterHook hook = cx->debugHooks->callHook)
fp->setHookData(hook(cx, fp, JS_TRUE, 0, cx->debugHooks->callHookData));
Probes::enterJSFun(cx, fp->maybeFun(), fp->maybeScript()); Probes::enterJSFun(cx, fp->maybeFun(), fp->maybeScript());
}
return true; return true;
} }
@ -3093,8 +3096,6 @@ BEGIN_CASE(JSOP_MOREITER)
if (!IteratorMore(cx, &regs.sp[-2].toObject(), &cond, &regs.sp[-1])) if (!IteratorMore(cx, &regs.sp[-2].toObject(), &cond, &regs.sp[-1]))
goto error; goto error;
CHECK_INTERRUPT_HANDLER(); CHECK_INTERRUPT_HANDLER();
TRY_BRANCH_AFTER_COND(cond, 1);
JS_ASSERT(regs.pc[1] == JSOP_IFNEX);
regs.sp[-1].setBoolean(cond); regs.sp[-1].setBoolean(cond);
} }
END_CASE(JSOP_MOREITER) END_CASE(JSOP_MOREITER)
@ -3421,7 +3422,10 @@ END_CASE(JSOP_BITAND)
if (SameType(lval, rval)) { \ if (SameType(lval, rval)) { \
if (lval.isString()) { \ if (lval.isString()) { \
JSString *l = lval.toString(), *r = rval.toString(); \ JSString *l = lval.toString(), *r = rval.toString(); \
cond = js_EqualStrings(l, r) OP JS_TRUE; \ JSBool equal; \
if (!EqualStrings(cx, l, r, &equal)) \
goto error; \
cond = equal OP JS_TRUE; \
} else if (lval.isDouble()) { \ } else if (lval.isDouble()) { \
double l = lval.toDouble(), r = rval.toDouble(); \ double l = lval.toDouble(), r = rval.toDouble(); \
cond = JSDOUBLE_COMPARE(l, OP, r, IFNAN); \ cond = JSDOUBLE_COMPARE(l, OP, r, IFNAN); \
@ -3450,7 +3454,10 @@ END_CASE(JSOP_BITAND)
DEFAULT_VALUE(cx, -1, JSTYPE_VOID, rval); \ DEFAULT_VALUE(cx, -1, JSTYPE_VOID, rval); \
if (lval.isString() && rval.isString()) { \ if (lval.isString() && rval.isString()) { \
JSString *l = lval.toString(), *r = rval.toString(); \ JSString *l = lval.toString(), *r = rval.toString(); \
cond = js_EqualStrings(l, r) OP JS_TRUE; \ JSBool equal; \
if (!EqualStrings(cx, l, r, &equal)) \
goto error; \
cond = equal OP JS_TRUE; \
} else { \ } else { \
double l, r; \ double l, r; \
if (!ValueToNumber(cx, lval, &l) || \ if (!ValueToNumber(cx, lval, &l) || \
@ -3482,7 +3489,10 @@ END_CASE(JSOP_NE)
JS_BEGIN_MACRO \ JS_BEGIN_MACRO \
const Value &rref = regs.sp[-1]; \ const Value &rref = regs.sp[-1]; \
const Value &lref = regs.sp[-2]; \ const Value &lref = regs.sp[-2]; \
COND = StrictlyEqual(cx, lref, rref) OP true; \ JSBool equal; \
if (!StrictlyEqual(cx, lref, rref, &equal)) \
goto error; \
COND = equal OP JS_TRUE; \
regs.sp--; \ regs.sp--; \
JS_END_MACRO JS_END_MACRO
@ -3543,7 +3553,10 @@ END_CASE(JSOP_CASEX)
DEFAULT_VALUE(cx, -1, JSTYPE_NUMBER, rval); \ DEFAULT_VALUE(cx, -1, JSTYPE_NUMBER, rval); \
if (lval.isString() && rval.isString()) { \ if (lval.isString() && rval.isString()) { \
JSString *l = lval.toString(), *r = rval.toString(); \ JSString *l = lval.toString(), *r = rval.toString(); \
cond = js_CompareStrings(l, r) OP 0; \ int32 result; \
if (!CompareStrings(cx, l, r, &result)) \
goto error; \
cond = result OP 0; \
} else { \ } else { \
double l, r; \ double l, r; \
if (!ValueToNumber(cx, lval, &l) || \ if (!ValueToNumber(cx, lval, &l) || \
@ -5126,12 +5139,14 @@ BEGIN_CASE(JSOP_LOOKUPSWITCH)
} }
if (lval.isString()) { if (lval.isString()) {
JSString *str = lval.toString(); JSLinearString *str = lval.toString()->ensureLinear(cx);
JSString *str2; if (!str)
goto error;
JSLinearString *str2;
SEARCH_PAIRS( SEARCH_PAIRS(
match = (rval.isString() && match = (rval.isString() &&
((str2 = rval.toString()) == str || ((str2 = rval.toString()->assertIsLinear()) == str ||
js_EqualStrings(str2, str))); EqualStrings(str2, str)));
) )
} else if (lval.isNumber()) { } else if (lval.isNumber()) {
double ldbl = lval.toNumber(); double ldbl = lval.toNumber();

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

@ -857,13 +857,6 @@ ComputeThisFromVpInPlace(JSContext *cx, js::Value *vp)
return ComputeThisFromArgv(cx, vp + 2); return ComputeThisFromArgv(cx, vp + 2);
} }
/* Return true if |fun| would accept |v| as its |this|, without being wrapped. */
JS_ALWAYS_INLINE bool
PrimitiveThisTest(JSFunction *fun, const Value &v)
{
return !v.isPrimitive() || fun->acceptsPrimitiveThis();
}
/* /*
* Abstracts the layout of the stack passed to natives from the engine and from * Abstracts the layout of the stack passed to natives from the engine and from
* natives to js::Invoke. * natives to js::Invoke.
@ -1030,11 +1023,11 @@ CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs,
JSObject **objp, JSProperty **propp); JSObject **objp, JSProperty **propp);
extern bool extern bool
StrictlyEqual(JSContext *cx, const Value &lval, const Value &rval); StrictlyEqual(JSContext *cx, const Value &lval, const Value &rval, JSBool *equal);
/* === except that NaN is the same as NaN and -0 is not the same as +0. */ /* === except that NaN is the same as NaN and -0 is not the same as +0. */
extern bool extern bool
SameValue(const Value &v1, const Value &v2, JSContext *cx); SameValue(JSContext *cx, const Value &v1, const Value &v2, JSBool *same);
extern JSType extern JSType
TypeOfValue(JSContext *cx, const Value &v); TypeOfValue(JSContext *cx, const Value &v);

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

@ -49,6 +49,8 @@
#include "jsstr.h" #include "jsstr.h"
#include "methodjit/MethodJIT.h" #include "methodjit/MethodJIT.h"
#include "jsfuninlines.h"
inline void inline void
JSStackFrame::initPrev(JSContext *cx) JSStackFrame::initPrev(JSContext *cx)
{ {
@ -356,7 +358,7 @@ JSStackFrame::computeThis(JSContext *cx)
if (thisv.isObject()) if (thisv.isObject())
return true; return true;
if (isFunctionFrame()) { if (isFunctionFrame()) {
if (fun()->acceptsPrimitiveThis()) if (fun()->inStrictMode())
return true; return true;
/* /*
* Eval function frames have their own |this| slot, which is a copy of the function's * Eval function frames have their own |this| slot, which is a copy of the function's
@ -713,10 +715,11 @@ ScriptEpilogue(JSContext *cx, JSStackFrame *fp, JSBool ok)
if (!fp->isExecuteFrame()) if (!fp->isExecuteFrame())
Probes::exitJSFun(cx, fp->maybeFun(), fp->maybeScript()); Probes::exitJSFun(cx, fp->maybeFun(), fp->maybeScript());
JSInterpreterHook hook = cx->debugHooks->callHook; JSInterpreterHook hook =
void* hookData; fp->isExecuteFrame() ? cx->debugHooks->executeHook : cx->debugHooks->callHook;
if (hook && (hookData = fp->maybeHookData()) && !fp->isExecuteFrame()) void* hookData;
if (JS_UNLIKELY(hook != NULL) && (hookData = fp->maybeHookData()))
hook(cx, fp, JS_FALSE, &ok, hookData); hook(cx, fp, JS_FALSE, &ok, hookData);
/* /*

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

@ -626,8 +626,6 @@ UpdateNativeIterator(NativeIterator *ni, JSObject *obj)
bool bool
GetIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp) GetIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp)
{ {
uint32 hash;
JSObject **hp;
Vector<uint32, 8> shapes(cx); Vector<uint32, 8> shapes(cx);
uint32 key = 0; uint32 key = 0;
@ -651,7 +649,7 @@ GetIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp)
* objects here, as they are not inserted into the cache and * objects here, as they are not inserted into the cache and
* will result in a miss. * will result in a miss.
*/ */
JSObject *last = JS_THREAD_DATA(cx)->lastNativeIterator; JSObject *last = cx->compartment->nativeIterCache.last;
JSObject *proto = obj->getProto(); JSObject *proto = obj->getProto();
if (last) { if (last) {
NativeIterator *lastni = last->getNativeIterator(); NativeIterator *lastni = last->getNativeIterator();
@ -689,9 +687,7 @@ GetIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp)
pobj = pobj->getProto(); pobj = pobj->getProto();
} while (pobj); } while (pobj);
hash = key % JS_ARRAY_LENGTH(JS_THREAD_DATA(cx)->cachedNativeIterators); JSObject *iterobj = cx->compartment->nativeIterCache.get(key);
hp = &JS_THREAD_DATA(cx)->cachedNativeIterators[hash];
JSObject *iterobj = *hp;
if (iterobj) { if (iterobj) {
NativeIterator *ni = iterobj->getNativeIterator(); NativeIterator *ni = iterobj->getNativeIterator();
if (!(ni->flags & JSITER_ACTIVE) && if (!(ni->flags & JSITER_ACTIVE) &&
@ -703,7 +699,7 @@ GetIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp)
UpdateNativeIterator(ni, obj); UpdateNativeIterator(ni, obj);
RegisterEnumerator(cx, iterobj, ni); RegisterEnumerator(cx, iterobj, ni);
if (shapes.length() == 2) if (shapes.length() == 2)
JS_THREAD_DATA(cx)->lastNativeIterator = iterobj; cx->compartment->nativeIterCache.last = iterobj;
return true; return true;
} }
} }
@ -738,14 +734,11 @@ GetIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp)
JSObject *iterobj = &vp->toObject(); JSObject *iterobj = &vp->toObject();
/* Cache the iterator object if possible. */ /* Cache the iterator object if possible. */
if (shapes.length()) { if (shapes.length())
uint32 hash = key % NATIVE_ITER_CACHE_SIZE; cx->compartment->nativeIterCache.set(key, iterobj);
JSObject **hp = &JS_THREAD_DATA(cx)->cachedNativeIterators[hash];
*hp = iterobj;
}
if (shapes.length() == 2) if (shapes.length() == 2)
JS_THREAD_DATA(cx)->lastNativeIterator = iterobj; cx->compartment->nativeIterCache.last = iterobj;
return true; return true;
} }

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

@ -54,6 +54,7 @@
#include "jsmath.h" #include "jsmath.h"
#include "jsnum.h" #include "jsnum.h"
#include "jslibmath.h" #include "jslibmath.h"
#include "jscompartment.h"
using namespace js; using namespace js;
@ -148,7 +149,7 @@ math_acos(JSContext *cx, uintN argc, Value *vp)
return JS_TRUE; return JS_TRUE;
} }
#endif #endif
MathCache *mathCache = JS_THREAD_DATA(cx)->getMathCache(cx); MathCache *mathCache = GetMathCache(cx);
if (!mathCache) if (!mathCache)
return JS_FALSE; return JS_FALSE;
z = mathCache->lookup(acos, x); z = mathCache->lookup(acos, x);
@ -173,7 +174,7 @@ math_asin(JSContext *cx, uintN argc, Value *vp)
return JS_TRUE; return JS_TRUE;
} }
#endif #endif
MathCache *mathCache = JS_THREAD_DATA(cx)->getMathCache(cx); MathCache *mathCache = GetMathCache(cx);
if (!mathCache) if (!mathCache)
return JS_FALSE; return JS_FALSE;
z = mathCache->lookup(asin, x); z = mathCache->lookup(asin, x);
@ -192,7 +193,7 @@ math_atan(JSContext *cx, uintN argc, Value *vp)
} }
if (!ValueToNumber(cx, vp[2], &x)) if (!ValueToNumber(cx, vp[2], &x))
return JS_FALSE; return JS_FALSE;
MathCache *mathCache = JS_THREAD_DATA(cx)->getMathCache(cx); MathCache *mathCache = GetMathCache(cx);
if (!mathCache) if (!mathCache)
return JS_FALSE; return JS_FALSE;
z = mathCache->lookup(atan, x); z = mathCache->lookup(atan, x);
@ -285,7 +286,7 @@ math_cos(JSContext *cx, uintN argc, Value *vp)
} }
if (!ValueToNumber(cx, vp[2], &x)) if (!ValueToNumber(cx, vp[2], &x))
return JS_FALSE; return JS_FALSE;
MathCache *mathCache = JS_THREAD_DATA(cx)->getMathCache(cx); MathCache *mathCache = GetMathCache(cx);
if (!mathCache) if (!mathCache)
return JS_FALSE; return JS_FALSE;
z = mathCache->lookup(cos, x); z = mathCache->lookup(cos, x);
@ -318,7 +319,7 @@ math_exp(JSContext *cx, uintN argc, Value *vp)
} }
if (!ValueToNumber(cx, vp[2], &x)) if (!ValueToNumber(cx, vp[2], &x))
return JS_FALSE; return JS_FALSE;
MathCache *mathCache = JS_THREAD_DATA(cx)->getMathCache(cx); MathCache *mathCache = GetMathCache(cx);
if (!mathCache) if (!mathCache)
return JS_FALSE; return JS_FALSE;
z = mathCache->lookup(math_exp_body, x); z = mathCache->lookup(math_exp_body, x);
@ -365,7 +366,7 @@ math_log(JSContext *cx, uintN argc, Value *vp)
return JS_TRUE; return JS_TRUE;
} }
#endif #endif
MathCache *mathCache = JS_THREAD_DATA(cx)->getMathCache(cx); MathCache *mathCache = GetMathCache(cx);
if (!mathCache) if (!mathCache)
return JS_FALSE; return JS_FALSE;
z = mathCache->lookup(log, x); z = mathCache->lookup(log, x);
@ -612,7 +613,7 @@ math_sin(JSContext *cx, uintN argc, Value *vp)
} }
if (!ValueToNumber(cx, vp[2], &x)) if (!ValueToNumber(cx, vp[2], &x))
return JS_FALSE; return JS_FALSE;
MathCache *mathCache = JS_THREAD_DATA(cx)->getMathCache(cx); MathCache *mathCache = GetMathCache(cx);
if (!mathCache) if (!mathCache)
return JS_FALSE; return JS_FALSE;
z = mathCache->lookup(sin, x); z = mathCache->lookup(sin, x);
@ -631,7 +632,7 @@ math_sqrt(JSContext *cx, uintN argc, Value *vp)
} }
if (!ValueToNumber(cx, vp[2], &x)) if (!ValueToNumber(cx, vp[2], &x))
return JS_FALSE; return JS_FALSE;
MathCache *mathCache = JS_THREAD_DATA(cx)->getMathCache(cx); MathCache *mathCache = GetMathCache(cx);
if (!mathCache) if (!mathCache)
return JS_FALSE; return JS_FALSE;
z = mathCache->lookup(sqrt, x); z = mathCache->lookup(sqrt, x);
@ -650,7 +651,7 @@ math_tan(JSContext *cx, uintN argc, Value *vp)
} }
if (!ValueToNumber(cx, vp[2], &x)) if (!ValueToNumber(cx, vp[2], &x))
return JS_FALSE; return JS_FALSE;
MathCache *mathCache = JS_THREAD_DATA(cx)->getMathCache(cx); MathCache *mathCache = GetMathCache(cx);
if (!mathCache) if (!mathCache)
return JS_FALSE; return JS_FALSE;
z = mathCache->lookup(tan, x); z = mathCache->lookup(tan, x);

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

@ -315,7 +315,10 @@ num_parseFloat(JSContext *cx, uintN argc, Value *vp)
str = js_ValueToString(cx, vp[2]); str = js_ValueToString(cx, vp[2]);
if (!str) if (!str)
return JS_FALSE; return JS_FALSE;
str->getCharsAndEnd(bp, end); bp = str->getChars(cx);
if (!bp)
return JS_FALSE;
end = bp + str->length();
if (!js_strtod(cx, bp, end, &ep, &d)) if (!js_strtod(cx, bp, end, &ep, &d))
return JS_FALSE; return JS_FALSE;
if (ep == bp) { if (ep == bp) {
@ -330,12 +333,15 @@ num_parseFloat(JSContext *cx, uintN argc, Value *vp)
static jsdouble FASTCALL static jsdouble FASTCALL
ParseFloat(JSContext* cx, JSString* str) ParseFloat(JSContext* cx, JSString* str)
{ {
const jschar* bp; const jschar *bp = str->getChars(cx);
const jschar* end; if (!bp) {
const jschar* ep; SetBuiltinError(cx);
jsdouble d; return js_NaN;
}
const jschar *end = bp + str->length();
str->getCharsAndEnd(bp, end); const jschar *ep;
double d;
if (!js_strtod(cx, bp, end, &ep, &d) || ep == bp) if (!js_strtod(cx, bp, end, &ep, &d) || ep == bp)
return js_NaN; return js_NaN;
return d; return d;
@ -451,8 +457,10 @@ num_parseInt(JSContext *cx, uintN argc, Value *vp)
} }
/* Steps 2-5, 9-14. */ /* Steps 2-5, 9-14. */
const jschar *ws, *end; const jschar *ws = inputString->getChars(cx);
inputString->getCharsAndEnd(ws, end); if (!ws)
return false;
const jschar *end = ws + inputString->length();
jsdouble number; jsdouble number;
if (!ParseIntStringHelper(cx, ws, end, radix, stripPrefix, &number)) if (!ParseIntStringHelper(cx, ws, end, radix, stripPrefix, &number))
@ -467,8 +475,12 @@ num_parseInt(JSContext *cx, uintN argc, Value *vp)
static jsdouble FASTCALL static jsdouble FASTCALL
ParseInt(JSContext* cx, JSString* str) ParseInt(JSContext* cx, JSString* str)
{ {
const jschar *start, *end; const jschar *start = str->getChars(cx);
str->getCharsAndEnd(start, end); if (!start) {
SetBuiltinError(cx);
return js_NaN;
}
const jschar *end = start + str->length();
jsdouble d; jsdouble d;
if (!ParseIntStringHelper(cx, start, end, 0, true, &d)) { if (!ParseIntStringHelper(cx, start, end, 0, true, &d)) {
@ -499,7 +511,7 @@ JS_DEFINE_TRCINFO_2(num_parseInt,
(1, (static, DOUBLE, ParseIntDouble, DOUBLE, 1, nanojit::ACCSET_NONE))) (1, (static, DOUBLE, ParseIntDouble, DOUBLE, 1, nanojit::ACCSET_NONE)))
JS_DEFINE_TRCINFO_1(num_parseFloat, JS_DEFINE_TRCINFO_1(num_parseFloat,
(2, (static, DOUBLE, ParseFloat, CONTEXT, STRING, 1, nanojit::ACCSET_NONE))) (2, (static, DOUBLE_FAIL, ParseFloat, CONTEXT, STRING, 1, nanojit::ACCSET_NONE)))
#endif /* JS_TRACER */ #endif /* JS_TRACER */
@ -722,7 +734,7 @@ num_toLocaleString(JSContext *cx, uintN argc, Value *vp)
const char *num, *end, *tmpSrc; const char *num, *end, *tmpSrc;
char *buf, *tmpDest; char *buf, *tmpDest;
const char *nint; const char *nint;
int digits, size, remainder, nrepeat; int digits, buflen, remainder, nrepeat;
/* /*
* Create the string, move back to bytes to make string twiddling * Create the string, move back to bytes to make string twiddling
@ -757,9 +769,9 @@ num_toLocaleString(JSContext *cx, uintN argc, Value *vp)
decimalLength = strlen(rt->decimalSeparator); decimalLength = strlen(rt->decimalSeparator);
/* Figure out how long resulting string will be. */ /* Figure out how long resulting string will be. */
size = digits + (*nint ? strlen(nint + 1) + 1 : 0); buflen = digits + (*nint ? strlen(nint + 1) : 0);
if (*nint == '.') if (*nint == '.')
size += decimalLength; buflen += decimalLength;
numGrouping = tmpGroup = rt->numGrouping; numGrouping = tmpGroup = rt->numGrouping;
remainder = digits; remainder = digits;
@ -769,20 +781,20 @@ num_toLocaleString(JSContext *cx, uintN argc, Value *vp)
while (*tmpGroup != CHAR_MAX && *tmpGroup != '\0') { while (*tmpGroup != CHAR_MAX && *tmpGroup != '\0') {
if (*tmpGroup >= remainder) if (*tmpGroup >= remainder)
break; break;
size += thousandsLength; buflen += thousandsLength;
remainder -= *tmpGroup; remainder -= *tmpGroup;
tmpGroup++; tmpGroup++;
} }
if (*tmpGroup == '\0' && *numGrouping != '\0') { if (*tmpGroup == '\0' && *numGrouping != '\0') {
nrepeat = (remainder - 1) / tmpGroup[-1]; nrepeat = (remainder - 1) / tmpGroup[-1];
size += thousandsLength * nrepeat; buflen += thousandsLength * nrepeat;
remainder -= nrepeat * tmpGroup[-1]; remainder -= nrepeat * tmpGroup[-1];
} else { } else {
nrepeat = 0; nrepeat = 0;
} }
tmpGroup--; tmpGroup--;
buf = (char *)cx->malloc(size + 1); buf = (char *)cx->malloc(buflen + 1);
if (!buf) if (!buf)
return JS_FALSE; return JS_FALSE;
@ -815,7 +827,7 @@ num_toLocaleString(JSContext *cx, uintN argc, Value *vp)
return ok; return ok;
} }
str = js_NewStringCopyN(cx, buf, size); str = js_NewStringCopyN(cx, buf, buflen);
cx->free(buf); cx->free(buf);
if (!str) if (!str)
return JS_FALSE; return JS_FALSE;
@ -920,15 +932,15 @@ JS_DEFINE_TRCINFO_2(num_toString,
static JSFunctionSpec number_methods[] = { static JSFunctionSpec number_methods[] = {
#if JS_HAS_TOSOURCE #if JS_HAS_TOSOURCE
JS_FN(js_toSource_str, num_toSource, 0, JSFUN_PRIMITIVE_THIS), JS_FN(js_toSource_str, num_toSource, 0, 0),
#endif #endif
JS_TN(js_toString_str, num_toString, 1, JSFUN_PRIMITIVE_THIS, &num_toString_trcinfo), JS_TN(js_toString_str, num_toString, 1, 0, &num_toString_trcinfo),
JS_FN(js_toLocaleString_str, num_toLocaleString, 0, JSFUN_PRIMITIVE_THIS), JS_FN(js_toLocaleString_str, num_toLocaleString, 0, 0),
JS_FN(js_valueOf_str, js_num_valueOf, 0, JSFUN_PRIMITIVE_THIS), JS_FN(js_valueOf_str, js_num_valueOf, 0, 0),
JS_FN(js_toJSON_str, js_num_valueOf, 0, JSFUN_PRIMITIVE_THIS), JS_FN(js_toJSON_str, js_num_valueOf, 0, 0),
JS_FN("toFixed", num_toFixed, 1, JSFUN_PRIMITIVE_THIS), JS_FN("toFixed", num_toFixed, 1, 0),
JS_FN("toExponential", num_toExponential, 1, JSFUN_PRIMITIVE_THIS), JS_FN("toExponential", num_toExponential, 1, 0),
JS_FN("toPrecision", num_toPrecision, 1, JSFUN_PRIMITIVE_THIS), JS_FN("toPrecision", num_toPrecision, 1, 0),
JS_FS_END JS_FS_END
}; };
@ -1187,6 +1199,14 @@ js_NumberToString(JSContext *cx, jsdouble d)
return js_NumberToStringWithBase(cx, d, 10); return js_NumberToStringWithBase(cx, d, 10);
} }
JSFlatString *
js::NumberToString(JSContext *cx, jsdouble d)
{
if (JSString *str = js_NumberToStringWithBase(cx, d, 10))
return str->assertIsFlat();
return NULL;
}
JSBool JS_FASTCALL JSBool JS_FASTCALL
js_NumberValueToCharBuffer(JSContext *cx, const Value &v, JSCharBuffer &cb) js_NumberValueToCharBuffer(JSContext *cx, const Value &v, JSCharBuffer &cb)
{ {
@ -1235,13 +1255,8 @@ ValueToNumberSlow(JSContext *cx, Value v, double *out)
return true; return true;
} }
skip_int_double: skip_int_double:
if (v.isString()) { if (v.isString())
jsdouble d = StringToNumberType<jsdouble>(cx, v.toString()); return StringToNumberType<jsdouble>(cx, v.toString(), out);
if (JSDOUBLE_IS_NaN(d))
break;
*out = d;
return true;
}
if (v.isBoolean()) { if (v.isBoolean()) {
if (v.toBoolean()) { if (v.toBoolean()) {
*out = 1.0; *out = 1.0;

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

@ -206,6 +206,10 @@ js_NumberValueToCharBuffer(JSContext *cx, const js::Value &v, JSCharBuffer &cb);
namespace js { namespace js {
/* Same as js_NumberToString, different signature. */
extern JSFlatString *
NumberToString(JSContext *cx, jsdouble d);
/* /*
* Usually a small amount of static storage is enough, but sometimes we need * Usually a small amount of static storage is enough, but sometimes we need
* to dynamically allocate much more. This struct encapsulates that. * to dynamically allocate much more. This struct encapsulates that.
@ -643,35 +647,44 @@ template<> struct NumberTraits<jsdouble> {
}; };
template<typename T> template<typename T>
static JS_ALWAYS_INLINE T static JS_ALWAYS_INLINE bool
StringToNumberType(JSContext *cx, JSString *str) StringToNumberType(JSContext *cx, JSString *str, T *result)
{ {
if (str->length() == 1) { size_t length = str->length();
jschar c = str->chars()[0]; const jschar *chars = str->getChars(NULL);
if ('0' <= c && c <= '9') if (!chars)
return NumberTraits<T>::toSelfType(T(c - '0')); return false;
if (JS_ISSPACE(c))
return NumberTraits<T>::toSelfType(T(0)); if (length == 1) {
return NumberTraits<T>::NaN(); jschar c = chars[0];
if ('0' <= c && c <= '9') {
*result = NumberTraits<T>::toSelfType(T(c - '0'));
return true;
}
if (JS_ISSPACE(c)) {
*result = NumberTraits<T>::toSelfType(T(0));
return true;
}
*result = NumberTraits<T>::NaN();
return true;
} }
const jschar* bp; const jschar *bp = chars;
const jschar* end; const jschar *end = chars + length;
const jschar* ep;
jsdouble d;
str->getCharsAndEnd(bp, end);
bp = js_SkipWhiteSpace(bp, end); bp = js_SkipWhiteSpace(bp, end);
/* ECMA doesn't allow signed hex numbers (bug 273467). */ /* ECMA doesn't allow signed hex numbers (bug 273467). */
if (end - bp >= 2 && bp[0] == '0' && (bp[1] == 'x' || bp[1] == 'X')) { if (end - bp >= 2 && bp[0] == '0' && (bp[1] == 'x' || bp[1] == 'X')) {
/* Looks like a hex number. */ /* Looks like a hex number. */
const jschar *endptr; const jschar *endptr;
double d;
if (!GetPrefixInteger(cx, bp + 2, end, 16, &endptr, &d) || if (!GetPrefixInteger(cx, bp + 2, end, 16, &endptr, &d) ||
js_SkipWhiteSpace(endptr, end) != end) { js_SkipWhiteSpace(endptr, end) != end) {
return NumberTraits<T>::NaN(); *result = NumberTraits<T>::NaN();
return true;
} }
return NumberTraits<T>::toSelfType(d); *result = NumberTraits<T>::toSelfType(d);
return true;
} }
/* /*
@ -681,12 +694,14 @@ StringToNumberType(JSContext *cx, JSString *str)
* that have made it here (which can only be negative ones) will * that have made it here (which can only be negative ones) will
* be treated as 0 without consuming the 'x' by js_strtod. * be treated as 0 without consuming the 'x' by js_strtod.
*/ */
if (!js_strtod(cx, bp, end, &ep, &d) || const jschar *ep;
js_SkipWhiteSpace(ep, end) != end) { double d;
return NumberTraits<T>::NaN(); if (!js_strtod(cx, bp, end, &ep, &d) || js_SkipWhiteSpace(ep, end) != end) {
*result = NumberTraits<T>::NaN();
return true;
} }
*result = NumberTraits<T>::toSelfType(d);
return NumberTraits<T>::toSelfType(d); return true;
} }
} }

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

@ -484,7 +484,8 @@ obj_toSource(JSContext *cx, uintN argc, Value *vp)
JSProperty *prop; JSProperty *prop;
Value *val; Value *val;
JSString *gsop[2]; JSString *gsop[2];
JSString *idstr, *valstr, *str; JSString *valstr, *str;
JSLinearString *idstr;
JS_CHECK_RECURSION(cx, return JS_FALSE); JS_CHECK_RECURSION(cx, return JS_FALSE);
@ -570,8 +571,8 @@ obj_toSource(JSContext *cx, uintN argc, Value *vp)
* Convert id to a value and then to a string. Decide early whether we * Convert id to a value and then to a string. Decide early whether we
* prefer get/set or old getter/setter syntax. * prefer get/set or old getter/setter syntax.
*/ */
idstr = js_ValueToString(cx, IdToValue(id)); JSString *s = js_ValueToString(cx, IdToValue(id));
if (!idstr) { if (!s || !(idstr = s->ensureLinear(cx))) {
ok = JS_FALSE; ok = JS_FALSE;
goto error; goto error;
} }
@ -609,18 +610,23 @@ obj_toSource(JSContext *cx, uintN argc, Value *vp)
* If id is a string that's not an identifier, or if it's a negative * If id is a string that's not an identifier, or if it's a negative
* integer, then it must be quoted. * integer, then it must be quoted.
*/ */
bool idIsLexicalIdentifier = !!js_IsIdentifier(idstr); bool idIsLexicalIdentifier = js_IsIdentifier(idstr);
if (JSID_IS_ATOM(id) if (JSID_IS_ATOM(id)
? !idIsLexicalIdentifier ? !idIsLexicalIdentifier
: (!JSID_IS_INT(id) || JSID_TO_INT(id) < 0)) { : (!JSID_IS_INT(id) || JSID_TO_INT(id) < 0)) {
idstr = js_QuoteString(cx, idstr, jschar('\'')); s = js_QuoteString(cx, idstr, jschar('\''));
if (!idstr) { if (!s || !(idstr = s->ensureLinear(cx))) {
ok = JS_FALSE; ok = JS_FALSE;
goto error; goto error;
} }
vp->setString(idstr); /* local root */ vp->setString(idstr); /* local root */
} }
idstr->getCharsAndLength(idstrchars, idstrlength); idstrlength = idstr->length();
idstrchars = idstr->getChars(cx);
if (!idstrchars) {
ok = JS_FALSE;
goto error;
}
for (jsint j = 0; j < valcnt; j++) { for (jsint j = 0; j < valcnt; j++) {
/* /*
@ -637,7 +643,12 @@ obj_toSource(JSContext *cx, uintN argc, Value *vp)
goto error; goto error;
} }
localroot[j].setString(valstr); /* local root */ localroot[j].setString(valstr); /* local root */
valstr->getCharsAndLength(vchars, vlength); vchars = valstr->getChars(cx);
if (!vchars) {
ok = JS_FALSE;
goto error;
}
vlength = valstr->length();
/* /*
* If val[j] is a non-sharp object, and we're not serializing an * If val[j] is a non-sharp object, and we're not serializing an
@ -727,10 +738,8 @@ obj_toSource(JSContext *cx, uintN argc, Value *vp)
/* Allocate 1 + 1 at end for closing brace and terminating 0. */ /* Allocate 1 + 1 at end for closing brace and terminating 0. */
chars = (jschar *) js_realloc((ochars = chars), curlen * sizeof(jschar)); chars = (jschar *) js_realloc((ochars = chars), curlen * sizeof(jschar));
if (!chars) { if (!chars) {
/* Save code space on error: let JS_free ignore null vsharp. */ chars = ochars;
cx->free(vsharp); goto overflow;
js_free(ochars);
goto error;
} }
if (comma) { if (comma) {
@ -741,8 +750,10 @@ obj_toSource(JSContext *cx, uintN argc, Value *vp)
if (gsop[j]) { if (gsop[j]) {
gsoplength = gsop[j]->length(); gsoplength = gsop[j]->length();
js_strncpy(&chars[nchars], gsop[j]->chars(), const jschar *gsopchars = gsop[j]->getChars(cx);
gsoplength); if (!gsopchars)
goto overflow;
js_strncpy(&chars[nchars], gsopchars, gsoplength);
nchars += gsoplength; nchars += gsoplength;
chars[nchars++] = ' '; chars[nchars++] = ' ';
} }
@ -987,15 +998,14 @@ js_ComputeFilename(JSContext *cx, JSStackFrame *caller,
#endif #endif
static inline JSScript ** static inline JSScript **
EvalCacheHash(JSContext *cx, JSString *str) EvalCacheHash(JSContext *cx, JSLinearString *str)
{ {
const jschar *s; const jschar *s = str->chars();
size_t n; size_t n = str->length();
uint32 h;
str->getCharsAndLength(s, n);
if (n > 100) if (n > 100)
n = 100; n = 100;
uint32 h;
for (h = 0; n; s++, n--) for (h = 0; n; s++, n--)
h = JS_ROTATE_LEFT32(h, 4) ^ *s; h = JS_ROTATE_LEFT32(h, 4) ^ *s;
@ -1005,7 +1015,7 @@ EvalCacheHash(JSContext *cx, JSString *str)
} }
static JS_ALWAYS_INLINE JSScript * static JS_ALWAYS_INLINE JSScript *
EvalCacheLookup(JSContext *cx, JSString *str, JSStackFrame *caller, uintN staticLevel, EvalCacheLookup(JSContext *cx, JSLinearString *str, JSStackFrame *caller, uintN staticLevel,
JSPrincipals *principals, JSObject *scopeobj, JSScript **bucket) JSPrincipals *principals, JSObject *scopeobj, JSScript **bucket)
{ {
/* /*
@ -1014,8 +1024,15 @@ EvalCacheLookup(JSContext *cx, JSString *str, JSStackFrame *caller, uintN static
* An eval cache entry should never be considered a hit unless its * An eval cache entry should never be considered a hit unless its
* strictness matches that of the new eval code. The existing code takes * strictness matches that of the new eval code. The existing code takes
* care of this, because hits are qualified by the function from which * care of this, because hits are qualified by the function from which
* eval was called, whose strictness doesn't change. Scripts produced by * eval was called, whose strictness doesn't change. (We don't cache evals
* calls to eval from global code are not cached. * in eval code, so the calling function corresponds to the calling script,
* and its strictness never varies.) Scripts produced by calls to eval from
* global code aren't cached.
*
* FIXME bug 620141: Qualify hits by calling script rather than function.
* Then we wouldn't need the unintuitive !isEvalFrame() hack in EvalKernel
* to avoid caching nested evals in functions (thus potentially mismatching
* on strict mode), and we could cache evals in global code if desired.
*/ */
uintN count = 0; uintN count = 0;
JSScript **scriptp = bucket; JSScript **scriptp = bucket;
@ -1041,9 +1058,9 @@ EvalCacheLookup(JSContext *cx, JSString *str, JSStackFrame *caller, uintN static
* Get the source string passed for safekeeping in the * Get the source string passed for safekeeping in the
* atom map by the prior eval to Compiler::compileScript. * atom map by the prior eval to Compiler::compileScript.
*/ */
JSString *src = ATOM_TO_STRING(script->atomMap.vector[0]); JSAtom *src = script->atomMap.vector[0];
if (src == str || js_EqualStrings(src, str)) { if (src == str || EqualStrings(src, str)) {
/* /*
* Source matches, qualify by comparing scopeobj to the * Source matches, qualify by comparing scopeobj to the
* COMPILE_N_GO-memoized parent of the first literal * COMPILE_N_GO-memoized parent of the first literal
@ -1184,9 +1201,11 @@ EvalKernel(JSContext *cx, uintN argc, Value *vp, EvalType evalType, JSStackFrame
if (!CheckScopeChainValidity(cx, scopeobj)) if (!CheckScopeChainValidity(cx, scopeobj))
return false; return false;
const jschar *chars; JSLinearString *linearStr = str->ensureLinear(cx);
size_t length; if (!linearStr)
str->getCharsAndLength(chars, length); return false;
const jschar *chars = linearStr->chars();
size_t length = linearStr->length();
/* /*
* If the eval string starts with '(' and ends with ')', it may be JSON. * If the eval string starts with '(' and ends with ')', it may be JSON.
@ -1214,9 +1233,9 @@ EvalKernel(JSContext *cx, uintN argc, Value *vp, EvalType evalType, JSStackFrame
return false; return false;
JSScript *script = NULL; JSScript *script = NULL;
JSScript **bucket = EvalCacheHash(cx, str); JSScript **bucket = EvalCacheHash(cx, linearStr);
if (evalType == DIRECT_EVAL && caller->isFunctionFrame()) if (evalType == DIRECT_EVAL && caller->isFunctionFrame() && !caller->isEvalFrame())
script = EvalCacheLookup(cx, str, caller, staticLevel, principals, scopeobj, bucket); script = EvalCacheLookup(cx, linearStr, caller, staticLevel, principals, scopeobj, bucket);
/* /*
* We can't have a callerFrame (down in js::Execute's terms) if we're in * We can't have a callerFrame (down in js::Execute's terms) if we're in
@ -1229,9 +1248,8 @@ EvalKernel(JSContext *cx, uintN argc, Value *vp, EvalType evalType, JSStackFrame
uint32 tcflags = TCF_COMPILE_N_GO | TCF_NEED_MUTABLE_SCRIPT | TCF_COMPILE_FOR_EVAL; uint32 tcflags = TCF_COMPILE_N_GO | TCF_NEED_MUTABLE_SCRIPT | TCF_COMPILE_FOR_EVAL;
script = Compiler::compileScript(cx, scopeobj, callerFrame, script = Compiler::compileScript(cx, scopeobj, callerFrame,
principals, tcflags, principals, tcflags, chars, length,
chars, length, filename, lineno, linearStr, staticLevel);
filename, lineno, str, staticLevel);
if (!script) if (!script)
return false; return false;
} }
@ -1992,6 +2010,23 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc,
JS_ASSERT(!obj->getOps()->defineProperty); JS_ASSERT(!obj->getOps()->defineProperty);
/*
* If we find a shared permanent property in a different object obj2 from
* obj, then if the property is shared permanent (an old hack to optimize
* per-object properties into one prototype property), ignore that lookup
* result (null current).
*
* FIXME: bug 575997 (see also bug 607863).
*/
if (current && obj2 != obj && obj2->isNative()) {
/* See same assertion with comment further below. */
JS_ASSERT(obj2->getClass() == obj->getClass());
Shape *shape = (Shape *) current;
if (shape->isSharedPermanent())
current = NULL;
}
/* 8.12.9 steps 2-4. */ /* 8.12.9 steps 2-4. */
if (!current) { if (!current) {
if (!obj->isExtensible()) if (!obj->isExtensible())
@ -2040,14 +2075,20 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc,
if (!shape->isAccessorDescriptor()) if (!shape->isAccessorDescriptor())
break; break;
if (desc.hasGet && if (desc.hasGet) {
!SameValue(desc.getterValue(), shape->getterOrUndefined(), cx)) { JSBool same;
break; if (!SameValue(cx, desc.getterValue(), shape->getterOrUndefined(), &same))
return JS_FALSE;
if (!same)
break;
} }
if (desc.hasSet && if (desc.hasSet) {
!SameValue(desc.setterValue(), shape->setterOrUndefined(), cx)) { JSBool same;
break; if (!SameValue(cx, desc.setterValue(), shape->setterOrUndefined(), &same))
return JS_FALSE;
if (!same)
break;
} }
} else { } else {
/* /*
@ -2096,8 +2137,13 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc,
if (!shape->isDataDescriptor()) if (!shape->isDataDescriptor())
break; break;
if (desc.hasValue && !SameValue(desc.value, v, cx)) JSBool same;
break; if (desc.hasValue) {
if (!SameValue(cx, desc.value, v, &same))
return JS_FALSE;
if (!same)
break;
}
if (desc.hasWritable && desc.writable() != shape->writable()) if (desc.hasWritable && desc.writable() != shape->writable())
break; break;
} else { } else {
@ -2144,9 +2190,14 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc,
/* 8.12.9 step 10. */ /* 8.12.9 step 10. */
JS_ASSERT(shape->isDataDescriptor()); JS_ASSERT(shape->isDataDescriptor());
if (!shape->configurable() && !shape->writable()) { if (!shape->configurable() && !shape->writable()) {
if ((desc.hasWritable && desc.writable()) || if (desc.hasWritable && desc.writable())
(desc.hasValue && !SameValue(desc.value, v, cx))) {
return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval); return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval);
if (desc.hasValue) {
JSBool same;
if (!SameValue(cx, desc.value, v, &same))
return JS_FALSE;
if (!same)
return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval);
} }
} }
@ -2155,11 +2206,20 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc,
/* 8.12.9 step 11. */ /* 8.12.9 step 11. */
JS_ASSERT(desc.isAccessorDescriptor() && shape->isAccessorDescriptor()); JS_ASSERT(desc.isAccessorDescriptor() && shape->isAccessorDescriptor());
if (!shape->configurable()) { if (!shape->configurable()) {
if ((desc.hasSet && if (desc.hasSet) {
!SameValue(desc.setterValue(), shape->setterOrUndefined(), cx)) || JSBool same;
(desc.hasGet && if (!SameValue(cx, desc.setterValue(), shape->setterOrUndefined(), &same))
!SameValue(desc.getterValue(), shape->getterOrUndefined(), cx))) { return JS_FALSE;
return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval); if (!same)
return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval);
}
if (desc.hasGet) {
JSBool same;
if (!SameValue(cx, desc.getterValue(), shape->getterOrUndefined(), &same))
return JS_FALSE;
if (!same)
return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval);
} }
} }
} }
@ -2697,7 +2757,7 @@ static JSFunctionSpec object_methods[] = {
#if JS_HAS_TOSOURCE #if JS_HAS_TOSOURCE
JS_FN(js_toSource_str, obj_toSource, 0,0), JS_FN(js_toSource_str, obj_toSource, 0,0),
#endif #endif
JS_FN(js_toString_str, obj_toString, 0,JSFUN_PRIMITIVE_THIS), JS_FN(js_toString_str, obj_toString, 0,0),
JS_FN(js_toLocaleString_str, obj_toLocaleString, 0,0), JS_FN(js_toLocaleString_str, obj_toLocaleString, 0,0),
JS_FN(js_valueOf_str, obj_valueOf, 0,0), JS_FN(js_valueOf_str, obj_valueOf, 0,0),
#if JS_HAS_OBJ_WATCHPOINT #if JS_HAS_OBJ_WATCHPOINT
@ -4487,7 +4547,7 @@ CallAddPropertyHook(JSContext *cx, Class *clasp, JSObject *obj, const Shape *sha
if (clasp->addProperty != PropertyStub) { if (clasp->addProperty != PropertyStub) {
Value nominal = *vp; Value nominal = *vp;
if (!CallJSPropertyOp(cx, clasp->addProperty, obj, SHAPE_USERID(shape), vp)) if (!CallJSPropertyOp(cx, clasp->addProperty, obj, shape->id, vp))
return false; return false;
if (*vp != nominal) { if (*vp != nominal) {
if (obj->containsSlot(shape->slot)) if (obj->containsSlot(shape->slot))
@ -4616,8 +4676,10 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const Value &valu
} }
/* Store value before calling addProperty, in case the latter GC's. */ /* Store value before calling addProperty, in case the latter GC's. */
if (obj->containsSlot(shape->slot)) if (obj->containsSlot(shape->slot)) {
AbortRecordingIfUnexpectedGlobalWrite(cx, obj, shape->slot);
obj->nativeSetSlot(shape->slot, value); obj->nativeSetSlot(shape->slot, value);
}
/* XXXbe called with lock held */ /* XXXbe called with lock held */
valueCopy = value; valueCopy = value;
@ -5091,6 +5153,7 @@ js_NativeSet(JSContext *cx, JSObject *obj, const Shape *shape, bool added, Value
if (shape->hasDefaultSetter()) { if (shape->hasDefaultSetter()) {
if (!added && !obj->methodWriteBarrier(cx, *shape, *vp)) if (!added && !obj->methodWriteBarrier(cx, *shape, *vp))
return false; return false;
AbortRecordingIfUnexpectedGlobalWrite(cx, obj, slot);
obj->nativeSetSlot(slot, *vp); obj->nativeSetSlot(slot, *vp);
return true; return true;
} }
@ -5117,6 +5180,7 @@ js_NativeSet(JSContext *cx, JSObject *obj, const Shape *shape, bool added, Value
obj->nativeContains(*shape))) { obj->nativeContains(*shape))) {
if (!added && !obj->methodWriteBarrier(cx, *shape, *vp)) if (!added && !obj->methodWriteBarrier(cx, *shape, *vp))
return false; return false;
AbortRecordingIfUnexpectedGlobalWrite(cx, obj, slot);
obj->setSlot(slot, *vp); obj->setSlot(slot, *vp);
} }
@ -5455,10 +5519,8 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
if (pobj != obj) { if (pobj != obj) {
/* /*
* We found id in a prototype object: prepare to share or shadow. * We found id in a prototype object: prepare to share or shadow.
*
* Don't clone a prototype property that doesn't have a slot.
*/ */
if (!shape->hasSlot()) { if (!shape->shadowable()) {
if (defineHow & JSDNP_CACHE_RESULT) { if (defineHow & JSDNP_CACHE_RESULT) {
#ifdef JS_TRACER #ifdef JS_TRACER
JS_ASSERT_NOT_ON_TRACE(cx); JS_ASSERT_NOT_ON_TRACE(cx);
@ -5474,21 +5536,33 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
return shape->set(cx, obj, vp); return shape->set(cx, obj, vp);
} }
/* Restore attrs to the ECMA default for new properties. */
attrs = JSPROP_ENUMERATE;
/* /*
* Preserve the shortid, getter, and setter when shadowing any * Preserve attrs except JSPROP_SHARED, getter, and setter when
* property that has a shortid. An old API convention requires * shadowing any property that has no slot (is shared). We must
* that the property's getter and setter functions receive the * clear the shared attribute for the shadowing shape so that the
* shortid, not id, when they are called on the shadow we are * property in obj that it defines has a slot to retain the value
* being set, in case the setter simply cannot operate on instances
* of obj's class by storing the value in some class-specific
* location.
*
* A subset of slotless shared properties is the set of properties
* with shortids, which must be preserved too. An old API requires
* that the property's getter and setter receive the shortid, not
* id, when they are called on the shadowing property that we are
* about to create in obj. * about to create in obj.
*/ */
if (shape->hasShortID()) { if (!shape->hasSlot()) {
flags = Shape::HAS_SHORTID; defineHow &= ~JSDNP_SET_METHOD;
shortid = shape->shortid; if (shape->hasShortID()) {
flags = Shape::HAS_SHORTID;
shortid = shape->shortid;
}
attrs &= ~JSPROP_SHARED;
getter = shape->getter(); getter = shape->getter();
setter = shape->setter(); setter = shape->setter();
} else {
/* Restore attrs to the ECMA default for new properties. */
attrs = JSPROP_ENUMERATE;
} }
/* /*
@ -6308,7 +6382,7 @@ js_PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize)
if (JSID_IS_INT(id)) { if (JSID_IS_INT(id)) {
JS_snprintf(buf, bufsize, "%ld", (long)JSID_TO_INT(id)); JS_snprintf(buf, bufsize, "%ld", (long)JSID_TO_INT(id));
} else if (JSID_IS_ATOM(id)) { } else if (JSID_IS_ATOM(id)) {
PutEscapedString(buf, bufsize, JSID_TO_STRING(id), 0); PutEscapedString(buf, bufsize, JSID_TO_ATOM(id), 0);
} else { } else {
JS_snprintf(buf, bufsize, "**FINALIZED ATOM KEY**"); JS_snprintf(buf, bufsize, "**FINALIZED ATOM KEY**");
} }
@ -6501,15 +6575,22 @@ js_DumpChars(const jschar *s, size_t n)
void void
dumpString(JSString *str) dumpString(JSString *str)
{ {
dumpChars(str->chars(), str->length()); if (const jschar *chars = str->getChars(NULL))
dumpChars(chars, str->length());
else
fprintf(stderr, "(oom in dumpString)");
} }
JS_FRIEND_API(void) JS_FRIEND_API(void)
js_DumpString(JSString *str) js_DumpString(JSString *str)
{ {
fprintf(stderr, "JSString* (%p) = jschar * (%p) = ", if (const jschar *chars = str->getChars(NULL)) {
(void *) str, (void *) str->chars()); fprintf(stderr, "JSString* (%p) = jschar * (%p) = ",
dumpString(str); (void *) str, (void *) chars);
dumpString(str);
} else {
fprintf(stderr, "(oom in JS_DumpString)");
}
fputc('\n', stderr); fputc('\n', stderr);
} }

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

@ -992,17 +992,21 @@ struct JSObject : js::gc::Cell {
static const uint32 NAMESPACE_CLASS_RESERVED_SLOTS = 3; static const uint32 NAMESPACE_CLASS_RESERVED_SLOTS = 3;
static const uint32 QNAME_CLASS_RESERVED_SLOTS = 3; static const uint32 QNAME_CLASS_RESERVED_SLOTS = 3;
inline jsval getNamePrefix() const; inline JSLinearString *getNamePrefix() const;
inline void setNamePrefix(jsval prefix); inline jsval getNamePrefixVal() const;
inline void setNamePrefix(JSLinearString *prefix);
inline void clearNamePrefix();
inline jsval getNameURI() const; inline JSLinearString *getNameURI() const;
inline void setNameURI(jsval uri); inline jsval getNameURIVal() const;
inline void setNameURI(JSLinearString *uri);
inline jsval getNamespaceDeclared() const; inline jsval getNamespaceDeclared() const;
inline void setNamespaceDeclared(jsval decl); inline void setNamespaceDeclared(jsval decl);
inline jsval getQNameLocalName() const; inline JSLinearString *getQNameLocalName() const;
inline void setQNameLocalName(jsval decl); inline jsval getQNameLocalNameVal() const;
inline void setQNameLocalName(JSLinearString *name);
/* /*
* Proxy-specific getters and setters. * Proxy-specific getters and setters.

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше