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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -590,7 +590,12 @@ IDBDatabase::CreateObjectStore(const nsAString& aName,
NS_WARNING("JS_ValueToString failed!");
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) {
JSBool boolVal;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -40,6 +40,7 @@
*/
#include "jsd.h"
#include "jsfriendapi.h"
/* 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) {
n += size_t(snprintf(Buf + n, sizeof(Buf) - n, "%s", "no fun"));
} else {
n += JS_PutEscapedString(Buf + n, sizeof(Buf) - n, fun, 0);
n += JS_PutEscapedFlatString(Buf + n, sizeof(Buf) - n,
JS_ASSERT_STRING_IS_FLAT(fun), 0);
Buf[sizeof(Buf) - 1] = '\0';
}
if (n + 1 < sizeof(Buf))
@ -503,7 +505,9 @@ jsd_GetScriptFunctionName(JSDContext* jsdc, JSDScript *jsdscript)
if( ! jsdscript->function )
return NULL;
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
@ -587,6 +591,17 @@ jsd_GetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc* hook, void** callerdata)
return JS_TRUE;
}
JSBool
jsd_EnableSingleStepInterrupts(JSDContext* jsdc, JSDScript* jsdscript, JSBool enable)
{
JSBool rv;
JSD_LOCK();
rv = JS_SetSingleStepMode(jsdc->dumbContext, jsdscript->script, enable);
JSD_UNLOCK();
return rv;
}
/***************************************************************************/
void
@ -751,7 +766,7 @@ jsd_TrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval,
}
JSD_ASSERT_VALID_EXEC_HOOK(jsdhook);
JS_ASSERT(jsdhook->pc == (jsuword)pc);
JS_ASSERT(!jsdhook->pc || jsdhook->pc == (jsuword)pc);
JS_ASSERT(jsdhook->jsdscript->script == script);
JS_ASSERT(jsdhook->jsdscript->jsdc == jsdc);

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

@ -40,6 +40,7 @@
*/
#include "jsd.h"
#include "jsfriendapi.h"
#ifdef DEBUG
void JSD_ASSERT_VALID_THREAD_STATE(JSDThreadState* jsdthreadstate)
@ -369,8 +370,17 @@ jsd_GetNameForStackFrame(JSDContext* jsdc,
{
JSFunction *fun = JS_GetFrameFunction (jsdthreadstate->context,
jsdframe->fp);
if (fun)
if( 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);

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

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

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

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

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

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

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

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

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

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

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

@ -134,17 +134,18 @@ CPPSRCS = \
jsbool.cpp \
jsclone.cpp \
jscntxt.cpp \
jscompartment.cpp \
jsdate.cpp \
jsdbgapi.cpp \
jsdhash.cpp \
jsdtoa.cpp \
jsemit.cpp \
jsexn.cpp \
jsfriendapi.cpp \
jsfun.cpp \
jsgc.cpp \
jsgcchunk.cpp \
jsgcstats.cpp \
jscompartment.cpp \
jshash.cpp \
jsinterp.cpp \
jsinvoke.cpp \
@ -199,6 +200,7 @@ INSTALLED_HEADERS = \
jsdtoa.h \
jsemit.h \
jsfun.h \
jsfriendapi.h \
jsgc.h \
jscell.h \
jsgcchunk.h \
@ -572,11 +574,11 @@ ifdef ENABLE_TRACEJIT
ifndef WINCE
check::
$(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::
$(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

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

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

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

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

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

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

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

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

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

@ -502,7 +502,9 @@ newdtoa(void)
DtoaState *state = (DtoaState *) MALLOC(sizeof(DtoaState));
if (state) {
memset(state, 0, sizeof(DtoaState));
#ifndef Omit_Private_Memory
state->pmem_next = state->private_mem;
#endif
}
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.
import datetime, os, re, sys, tempfile, traceback
@ -349,8 +351,8 @@ def main(argv):
help='Enable the |valgrind| flag, if valgrind is in $PATH.')
op.add_option('--valgrind-all', dest='valgrind_all', action='store_true',
help='Run all tests with valgrind, if valgrind is in $PATH.')
op.add_option('--jitflags', dest='jitflags', default='j',
help='Example: --jitflags=j,mj to run each test with -j and -m -j')
op.add_option('--jitflags', dest='jitflags', default='mjp',
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',
help='Use js-shell file indirection instead of piping stdio.')
op.add_option('--write-failure-output', dest='write_failure_output', action='store_true',

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

@ -13,7 +13,7 @@ function strictArgs(a)
}
var a1, a2, a3;
for (var i = 0; i < 5; i++)
for (var i = 0; i < HOTLOOP+1; i++)
{
a1 = strictArgs();
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() {
try {
for ( var i = 1; i > -2; i-- )
for ( var i = HOTLOOP-1; i > -2; i-- )
new Array(i).join('*');
} catch (e) {
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 \
testVersion.cpp \
testXDR.cpp \
testCustomIterator.cpp \
$(NULL)
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..

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

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

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

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

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

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

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

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

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

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

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

@ -111,6 +111,16 @@
using namespace js;
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
{
JSContext * const cx;
@ -571,17 +581,17 @@ JS_GetTypeName(JSContext *cx, JSType type)
}
JS_PUBLIC_API(JSBool)
JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2)
JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2, JSBool *equal)
{
assertSameCompartment(cx, v1, v2);
return StrictlyEqual(cx, Valueify(v1), Valueify(v2));
return StrictlyEqual(cx, Valueify(v1), Valueify(v2), equal);
}
JS_PUBLIC_API(JSBool)
JS_SameValue(JSContext *cx, jsval v1, jsval v2)
JS_SameValue(JSContext *cx, jsval v1, jsval v2, JSBool *same)
{
assertSameCompartment(cx, v1, v2);
return SameValue(Valueify(v1), Valueify(v2), cx);
return SameValue(cx, Valueify(v1), Valueify(v2), same);
}
/************************************************************************/
@ -1169,6 +1179,22 @@ JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target)
return reinterpret_cast<JSCrossCompartmentCall *>(call);
}
JS_PUBLIC_API(JSCrossCompartmentCall *)
JS_EnterCrossCompartmentCallScript(JSContext *cx, JSScript *target)
{
CHECK_REQUEST(cx);
JS_ASSERT(target);
JSObject *scriptObject = target->u.object;
if (!scriptObject) {
SwitchToCompartment sc(cx, target->compartment);
scriptObject = JS_NewGlobalObject(cx, &dummy_class);
if (!scriptObject)
return NULL;
}
return JS_EnterCrossCompartmentCall(cx, scriptObject);
}
JS_PUBLIC_API(void)
JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call)
{
@ -1190,6 +1216,18 @@ JSAutoEnterCompartment::enter(JSContext *cx, JSObject *target)
return call != NULL;
}
bool
JSAutoEnterCompartment::enter(JSContext *cx, JSScript *target)
{
JS_ASSERT(!call);
if (cx->compartment == target->compartment) {
call = reinterpret_cast<JSCrossCompartmentCall*>(1);
return true;
}
call = JS_EnterCrossCompartmentCallScript(cx, target);
return call != NULL;
}
void
JSAutoEnterCompartment::enterAndIgnoreErrors(JSContext *cx, JSObject *target)
{
@ -2199,8 +2237,14 @@ JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, ui
}
case JSTRACE_STRING:
PutEscapedString(buf, bufsize, (JSString *)thing, 0);
{
JSString *str = (JSString *)thing;
if (str->isLinear())
PutEscapedString(buf, bufsize, str->assertIsLinear(), 0);
else
JS_snprintf(buf, bufsize, "<rope: length %d>", (int)str->length());
break;
}
#if JS_HAS_XML_SUPPORT
case JSTRACE_XML:
@ -2662,7 +2706,7 @@ JS_GetGCParameterForThread(JSContext *cx, JSGCParamKey key)
{
JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES);
#ifdef JS_TRACER
return JS_THREAD_DATA(cx)->traceMonitor.maxCodeCacheBytes;
return JS_THREAD_DATA(cx)->maxCodeCacheBytes;
#else
return 0;
#endif
@ -5168,17 +5212,8 @@ JS_RestoreFrameChain(JSContext *cx, JSStackFrame *fp)
JS_PUBLIC_API(JSString *)
JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
{
jschar *js;
JSString *str;
CHECK_REQUEST(cx);
js = js_InflateString(cx, s, &n);
if (!js)
return NULL;
str = js_NewString(cx, js, n);
if (!str)
cx->free(js);
return str;
return js_NewStringCopyN(cx, s, n);
}
JS_PUBLIC_API(JSString *)
@ -5207,6 +5242,16 @@ JS_StringHasBeenInterned(JSString *str)
return str->isAtomized();
}
JS_PUBLIC_API(JSString *)
JS_InternJSString(JSContext *cx, JSString *str)
{
CHECK_REQUEST(cx);
JSAtom *atom = js_AtomizeString(cx, str, 0);
if (!atom)
return NULL;
return ATOM_TO_STRING(atom);
}
JS_PUBLIC_API(JSString *)
JS_InternString(JSContext *cx, const char *s)
{
@ -5260,45 +5305,6 @@ JS_InternUCString(JSContext *cx, const jschar *s)
return JS_InternUCStringN(cx, s, js_strlen(s));
}
JS_PUBLIC_API(jschar *)
JS_GetStringChars(JSString *str)
{
size_t n, size;
jschar *s;
str->ensureNotRope();
/*
* API botch: we have no cx to report out-of-memory when undepending
* strings, so we replace JSString::undepend with explicit malloc call and
* ignore its errors.
*
* If we fail to convert a dependent string into an independent one, our
* caller will not be guaranteed a \u0000 terminator as a backstop. This
* may break some clients who already misbehave on embedded NULs.
*
* The gain of dependent strings, which cure quadratic and cubic growth
* rate bugs in string concatenation, is worth this slight loss in API
* compatibility.
*/
if (str->isDependent()) {
n = str->dependentLength();
size = (n + 1) * sizeof(jschar);
s = (jschar *) js_malloc(size);
if (s) {
memcpy(s, str->dependentChars(), n * sizeof *s);
s[n] = 0;
str->initFlat(s, n);
} else {
s = str->dependentChars();
}
} else {
str->flatClearExtensible();
s = str->flatChars();
}
return s;
}
JS_PUBLIC_API(size_t)
JS_GetStringLength(JSString *str)
{
@ -5306,41 +5312,102 @@ JS_GetStringLength(JSString *str)
}
JS_PUBLIC_API(const jschar *)
JS_GetStringCharsAndLength(JSString *str, size_t *lengthp)
JS_GetStringCharsZ(JSContext *cx, JSString *str)
{
*lengthp = str->length();
return str->chars();
CHECK_REQUEST(cx);
assertSameCompartment(cx, str);
return str->getCharsZ(cx);
}
JS_PUBLIC_API(const jschar *)
JS_GetStringCharsZ(JSContext *cx, JSString *str)
JS_GetStringCharsZAndLength(JSContext *cx, JSString *str, size_t *plength)
{
CHECK_REQUEST(cx);
assertSameCompartment(cx, str);
return str->undepend(cx);
*plength = str->length();
return str->getCharsZ(cx);
}
JS_PUBLIC_API(intN)
JS_CompareStrings(JSString *str1, JSString *str2)
JS_PUBLIC_API(const jschar *)
JS_GetStringCharsAndLength(JSContext *cx, JSString *str, size_t *plength)
{
return js_CompareStrings(str1, str2);
CHECK_REQUEST(cx);
assertSameCompartment(cx, str);
*plength = str->length();
return str->getChars(cx);
}
JS_PUBLIC_API(const jschar *)
JS_GetInternedStringChars(JSString *str)
{
JS_ASSERT(str->isAtomized());
return str->flatChars();
}
JS_PUBLIC_API(const jschar *)
JS_GetInternedStringCharsAndLength(JSString *str, size_t *plength)
{
JS_ASSERT(str->isAtomized());
*plength = str->flatLength();
return str->flatChars();
}
extern JS_PUBLIC_API(JSFlatString *)
JS_FlattenString(JSContext *cx, JSString *str)
{
CHECK_REQUEST(cx);
assertSameCompartment(cx, str);
return str->getCharsZ(cx) ? (JSFlatString *)str : NULL;
}
extern JS_PUBLIC_API(const jschar *)
JS_GetFlatStringChars(JSFlatString *str)
{
return str->chars();
}
JS_PUBLIC_API(JSBool)
JS_MatchStringAndAscii(JSString *str, const char *asciiBytes)
JS_CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32 *result)
{
return MatchStringAndAscii(str, asciiBytes);
return CompareStrings(cx, str1, str2, result);
}
JS_PUBLIC_API(JSBool)
JS_StringEqualsAscii(JSContext *cx, JSString *str, const char *asciiBytes, JSBool *match)
{
JSLinearString *linearStr = str->ensureLinear(cx);
if (!linearStr)
return false;
*match = StringEqualsAscii(linearStr, asciiBytes);
return true;
}
JS_PUBLIC_API(JSBool)
JS_FlatStringEqualsAscii(JSFlatString *str, const char *asciiBytes)
{
return StringEqualsAscii(str, asciiBytes);
}
JS_PUBLIC_API(size_t)
JS_PutEscapedString(char *buffer, size_t size, JSString *str, char quote)
JS_PutEscapedFlatString(char *buffer, size_t size, JSFlatString *str, char quote)
{
return PutEscapedString(buffer, size, str, quote);
}
JS_PUBLIC_API(size_t)
JS_PutEscapedString(JSContext *cx, char *buffer, size_t size, JSString *str, char quote)
{
JSLinearString *linearStr = str->ensureLinear(cx);
if (!linearStr)
return size_t(-1);
return PutEscapedString(buffer, size, linearStr, quote);
}
JS_PUBLIC_API(JSBool)
JS_FileEscapedString(FILE *fp, JSString *str, char quote)
{
return FileEscapedString(fp, str, quote);
JSLinearString *linearStr = str->ensureLinear(NULL);
return linearStr && FileEscapedString(fp, linearStr, quote);
}
JS_PUBLIC_API(JSString *)
@ -5368,7 +5435,7 @@ JS_PUBLIC_API(const jschar *)
JS_UndependString(JSContext *cx, JSString *str)
{
CHECK_REQUEST(cx);
return str->undepend(cx);
return str->getCharsZ(cx);
}
JS_PUBLIC_API(JSBool)
@ -5404,13 +5471,19 @@ JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst, size_
JS_PUBLIC_API(char *)
JS_EncodeString(JSContext *cx, JSString *str)
{
return js_DeflateString(cx, str->chars(), str->length());
const jschar *chars = str->getChars(cx);
if (!chars)
return NULL;
return js_DeflateString(cx, chars, str->length());
}
JS_PUBLIC_API(size_t)
JS_GetStringEncodingLength(JSContext *cx, JSString *str)
{
return js_GetDeflatedStringLength(cx, str->chars(), str->length());
const jschar *chars = str->getChars(cx);
if (!chars)
return size_t(-1);
return js_GetDeflatedStringLength(cx, chars, str->length());
}
JS_PUBLIC_API(size_t)
@ -5422,12 +5495,15 @@ JS_EncodeStringToBuffer(JSString *str, char *buffer, size_t length)
* error.
*/
size_t writtenLength = length;
if (js_DeflateStringToBuffer(NULL, str->chars(), str->length(), buffer, &writtenLength)) {
const jschar *chars = str->getChars(NULL);
if (!chars)
return size_t(-1);
if (js_DeflateStringToBuffer(NULL, chars, str->length(), buffer, &writtenLength)) {
JS_ASSERT(writtenLength <= length);
return writtenLength;
}
JS_ASSERT(writtenLength <= length);
size_t necessaryLength = js_GetDeflatedStringLength(NULL, str->chars(), str->length());
size_t necessaryLength = js_GetDeflatedStringLength(NULL, chars, str->length());
if (necessaryLength == size_t(-1))
return size_t(-1);
if (writtenLength != length) {

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

@ -500,7 +500,7 @@ extern JS_PUBLIC_DATA(jsid) JSID_EMPTY;
#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
without creating a this object */
@ -702,10 +702,10 @@ extern JS_PUBLIC_API(const char *)
JS_GetTypeName(JSContext *cx, JSType type);
extern JS_PUBLIC_API(JSBool)
JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2);
JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2, JSBool *equal);
extern JS_PUBLIC_API(JSBool)
JS_SameValue(JSContext *cx, jsval v1, jsval v2);
JS_SameValue(JSContext *cx, jsval v1, jsval v2, JSBool *same);
/************************************************************************/
@ -979,6 +979,9 @@ JS_SetWrapObjectCallbacks(JSRuntime *rt,
extern JS_PUBLIC_API(JSCrossCompartmentCall *)
JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target);
extern JS_PUBLIC_API(JSCrossCompartmentCall *)
JS_EnterCrossCompartmentCallScript(JSContext *cx, JSScript *target);
extern JS_PUBLIC_API(void)
JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call);
@ -1009,6 +1012,8 @@ class JS_PUBLIC_API(JSAutoEnterCompartment)
bool enter(JSContext *cx, JSObject *target);
bool enter(JSContext *cx, JSScript *target);
void enterAndIgnoreErrors(JSContext *cx, JSObject *target);
bool entered() const { return call != NULL; }
@ -2931,6 +2936,9 @@ JS_NewStringCopyN(JSContext *cx, const char *s, size_t n);
extern JS_PUBLIC_API(JSString *)
JS_NewStringCopyZ(JSContext *cx, const char *s);
extern JS_PUBLIC_API(JSString *)
JS_InternJSString(JSContext *cx, JSString *str);
extern JS_PUBLIC_API(JSString *)
JS_InternString(JSContext *cx, const char *s);
@ -2949,36 +2957,106 @@ JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length);
extern JS_PUBLIC_API(JSString *)
JS_InternUCString(JSContext *cx, const jschar *s);
extern JS_PUBLIC_API(JSBool)
JS_CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32 *result);
extern JS_PUBLIC_API(JSBool)
JS_StringEqualsAscii(JSContext *cx, JSString *str, const char *asciiBytes, JSBool *match);
extern JS_PUBLIC_API(size_t)
JS_PutEscapedString(JSContext *cx, char *buffer, size_t size, JSString *str, char quote);
extern JS_PUBLIC_API(JSBool)
JS_FileEscapedString(FILE *fp, JSString *str, char quote);
/*
* Deprecated. Use JS_GetStringCharsZ() instead.
* Extracting string characters and length.
*
* While getting the length of a string is infallible, getting the chars can
* fail. As indicated by the lack of a JSContext parameter, there are two
* special cases where getting the chars is infallible:
*
* The first case is interned strings, i.e., strings from JS_InternString or
* JSID_TO_STRING(id), using JS_GetInternedStringChars*.
*
* The second case is "flat" strings that have been explicitly prepared in a
* fallible context by JS_FlattenString. To catch errors, a separate opaque
* JSFlatString type is returned by JS_FlattenString and expected by
* JS_GetFlatStringChars. Note, though, that this is purely a syntactic
* distinction: the input and output of JS_FlattenString are the same actual
* GC-thing so only one needs to be rooted. If a JSString is known to be flat,
* JS_ASSERT_STRING_IS_FLAT can be used to make a debug-checked cast. Example:
*
* // in a fallible context
* JSFlatString *fstr = JS_FlattenString(cx, str);
* if (!fstr)
* return JS_FALSE;
* JS_ASSERT(fstr == JS_ASSERT_STRING_IS_FLAT(str));
*
* // in an infallible context, for the same 'str'
* const jschar *chars = JS_GetFlatStringChars(fstr)
* JS_ASSERT(chars);
*
* The CharsZ APIs guarantee that the returned array has a null character at
* chars[length]. This can require additional copying so clients should prefer
* APIs without CharsZ if possible. The infallible functions also return
* null-terminated arrays. (There is no additional cost or non-Z alternative
* for the infallible functions, so 'Z' is left out of the identifier.)
*/
extern JS_PUBLIC_API(jschar *)
JS_GetStringChars(JSString *str);
extern JS_PUBLIC_API(size_t)
JS_GetStringLength(JSString *str);
/*
* Return the char array and length for this string. The array is not
* null-terminated.
*/
extern JS_PUBLIC_API(const jschar *)
JS_GetStringCharsAndLength(JSString *str, size_t *lengthp);
JS_GetStringCharsAndLength(JSContext *cx, JSString *str, size_t *length);
extern JS_PUBLIC_API(const jschar *)
JS_GetInternedStringChars(JSString *str);
extern JS_PUBLIC_API(const jschar *)
JS_GetInternedStringCharsAndLength(JSString *str, size_t *length);
extern JS_PUBLIC_API(const jschar *)
JS_GetStringCharsZ(JSContext *cx, JSString *str);
extern JS_PUBLIC_API(intN)
JS_CompareStrings(JSString *str1, JSString *str2);
extern JS_PUBLIC_API(const jschar *)
JS_GetStringCharsZAndLength(JSContext *cx, JSString *str, size_t *length);
extern JS_PUBLIC_API(JSFlatString *)
JS_FlattenString(JSContext *cx, JSString *str);
extern JS_PUBLIC_API(const jschar *)
JS_GetFlatStringChars(JSFlatString *str);
static JS_ALWAYS_INLINE JSFlatString *
JSID_TO_FLAT_STRING(jsid id)
{
JS_ASSERT(JSID_IS_STRING(id));
return (JSFlatString *)(JSID_BITS(id));
}
static JS_ALWAYS_INLINE JSFlatString *
JS_ASSERT_STRING_IS_FLAT(JSString *str)
{
JS_ASSERT(JS_GetFlatStringChars((JSFlatString *)str));
return (JSFlatString *)str;
}
static JS_ALWAYS_INLINE JSString *
JS_FORGET_STRING_FLATNESS(JSFlatString *fstr)
{
return (JSString *)fstr;
}
/*
* Additional APIs that avoid fallibility when given a flat string.
*/
extern JS_PUBLIC_API(JSBool)
JS_MatchStringAndAscii(JSString *str, const char *asciiBytes);
JS_FlatStringEqualsAscii(JSFlatString *str, const char *asciiBytes);
extern JS_PUBLIC_API(size_t)
JS_PutEscapedString(char *buffer, size_t size, JSString *str, char quote);
extern JS_PUBLIC_API(JSBool)
JS_FileEscapedString(FILE *fp, JSString *str, char quote);
JS_PutEscapedFlatString(char *buffer, size_t size, JSFlatString *str, char quote);
/*
* This function is now obsolete and behaves the same as JS_NewUCString. Use

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

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

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

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

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

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

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

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

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

@ -120,11 +120,11 @@ bool_valueOf(JSContext *cx, uintN argc, Value *vp)
static JSFunctionSpec boolean_methods[] = {
#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
JS_FN(js_toString_str, bool_toString, 0, JSFUN_PRIMITIVE_THIS),
JS_FN(js_valueOf_str, bool_valueOf, 0, JSFUN_PRIMITIVE_THIS),
JS_FN(js_toJSON_str, bool_valueOf, 0, JSFUN_PRIMITIVE_THIS),
JS_FN(js_toString_str, bool_toString, 0, 0),
JS_FN(js_valueOf_str, bool_valueOf, 0, 0),
JS_FN(js_toJSON_str, bool_valueOf, 0, 0),
JS_FS_END
};

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

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

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

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

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

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

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

@ -494,49 +494,28 @@ JSThreadData::init()
#endif
if (!stackSpace.init())
return false;
#ifdef JS_TRACER
if (!InitJIT(&traceMonitor)) {
finish();
return false;
}
#endif
dtoaState = js_NewDtoaState();
if (!dtoaState) {
finish();
return false;
}
nativeStackBase = GetNativeStackBase();
return true;
}
MathCache *
JSThreadData::allocMathCache(JSContext *cx)
{
JS_ASSERT(!mathCache);
mathCache = new MathCache;
if (!mathCache)
js_ReportOutOfMemory(cx);
return mathCache;
/* Set the default size for the code cache to 16MB. */
maxCodeCacheBytes = 16 * 1024 * 1024;
return true;
}
void
JSThreadData::finish()
{
#ifdef DEBUG
for (size_t i = 0; i != JS_ARRAY_LENGTH(scriptsToGC); ++i)
JS_ASSERT(!scriptsToGC[i]);
#endif
if (dtoaState)
js_DestroyDtoaState(dtoaState);
js_FinishGSNCache(&gsnCache);
propertyCache.~PropertyCache();
#if defined JS_TRACER
FinishJIT(&traceMonitor);
#endif
stackSpace.finish();
delete mathCache;
}
void
@ -553,22 +532,6 @@ JSThreadData::purge(JSContext *cx)
/* FIXME: bug 506341. */
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;
}
@ -736,7 +699,6 @@ js_PurgeThreads(JSContext *cx)
if (JS_CLIST_IS_EMPTY(&thread->contextList)) {
JS_ASSERT(cx->thread != thread);
js_DestroyScriptsToGC(cx, &thread->data);
DestroyThread(thread);
e.removeFront();
@ -921,7 +883,7 @@ DumpEvalCacheMeter(JSContext *cx)
EVAL_CACHE_METER_LIST(frob)
#undef frob
};
JSEvalCacheMeter *ecm = &JS_THREAD_DATA(cx)->evalCacheMeter;
JSEvalCacheMeter *ecm = &cx->compartment->evalCacheMeter;
static JSAutoFile fp;
if (!fp && !fp.open(filename, "w"))
@ -2316,6 +2278,15 @@ JSContext::updateJITEnabled()
namespace js {
JS_FORCES_STACK JS_FRIEND_API(void)
LeaveTrace(JSContext *cx)
{
#ifdef JS_TRACER
if (JS_ON_TRACE(cx))
DeepBail(cx);
#endif
}
void
SetPendingException(JSContext *cx, const Value &v)
{

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

@ -884,147 +884,6 @@ private:
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 */
/*
@ -1038,23 +897,6 @@ struct TraceMonitor {
# define JS_ON_TRACE(cx) false
#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
# define FUNCTION_KIND_METER_LIST(_) \
_(allfun), _(heavy), _(nofreeupvar), _(onlyfreevar), \
@ -1077,10 +919,6 @@ struct JSFunctionMeter {
#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 {
JSPendingProxyOperation *next;
JSObject *object;
@ -1118,18 +956,8 @@ struct JSThreadData {
js::PropertyCache propertyCache;
#ifdef JS_TRACER
/* Trace-tree JIT recorder/interpreter state. */
js::TraceMonitor traceMonitor;
/* 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;
/* Maximum size of the tracer's code cache before we start flushing. */
uint32 maxCodeCacheBytes;
#endif
/* State used by dtoa.c. */
@ -1149,12 +977,6 @@ struct JSThreadData {
JSString *s; // if s==NULL, d and base are not valid
} 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. */
jsuword *nativeStackBase;
@ -1163,16 +985,6 @@ struct JSThreadData {
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();
void finish();
void mark(JSTracer *trc);
@ -1322,6 +1134,7 @@ struct JSRuntime {
uint32 gcNumber;
js::GCMarker *gcMarkingTracer;
uint32 gcTriggerFactor;
int64 gcJitReleaseTime;
volatile JSBool gcIsNeeded;
/*
@ -1369,7 +1182,7 @@ struct JSRuntime {
js::Value negativeInfinityValue;
js::Value positiveInfinityValue;
JSString *emptyString;
JSFlatString *emptyString;
/* List of active contexts sharing this runtime; protected by gcLock. */
JSCList contextList;
@ -1725,14 +1538,6 @@ struct JSRuntime {
/* Common macros to access thread-local caches in JSThread or JSRuntime. */
#define JS_GSN_CACHE(cx) (JS_THREAD_DATA(cx)->gsnCache)
#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
# define JS_RUNTIME_METER(rt, which) JS_ATOMIC_INCREMENT(&(rt)->which)
@ -2369,8 +2174,7 @@ struct JSContext
void assertValidStackDepth(uintN /*depth*/) {}
#endif
private:
private:
/*
* The allocation code calls the function to indicate either OOM failure
* when p is null or that a memory pressure counter has reached some
@ -3238,50 +3042,14 @@ js_CurrentPCIsInImacro(JSContext *cx);
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
SetPendingException(JSContext *cx, const Value &v);
class RegExpStatics;
extern JS_FORCES_STACK JS_FRIEND_API(void)
LeaveTrace(JSContext *cx);
} /* namespace js */
/*

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

@ -42,6 +42,7 @@
#define jscntxtinlines_h___
#include "jscntxt.h"
#include "jscompartment.h"
#include "jsparse.h"
#include "jsstaticcheck.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);
}
#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 */
#endif /* jscntxtinlines_h___ */

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

@ -44,6 +44,7 @@
#include "jsiter.h"
#include "jsproxy.h"
#include "jsscope.h"
#include "jstracer.h"
#include "methodjit/MethodJIT.h"
#include "methodjit/PolyIC.h"
#include "methodjit/MonoIC.h"
@ -54,17 +55,36 @@ using namespace js;
using namespace js::gc;
JSCompartment::JSCompartment(JSRuntime *rt)
: rt(rt), principals(NULL), data(NULL), marked(false), debugMode(rt->debugMode),
anynameObject(NULL), functionNamespaceObject(NULL)
: rt(rt),
principals(NULL),
data(NULL),
marked(false),
active(false),
debugMode(rt->debugMode),
anynameObject(NULL),
functionNamespaceObject(NULL),
mathCache(NULL)
{
JS_INIT_CLIST(&scripts);
PodArrayZero(scriptsToGC);
}
JSCompartment::~JSCompartment()
{
#if defined JS_TRACER
FinishJIT(&traceMonitor);
#endif
#ifdef JS_METHODJIT
delete jaegerCompartment;
#endif
delete mathCache;
#ifdef DEBUG
for (size_t i = 0; i != JS_ARRAY_LENGTH(scriptsToGC); ++i)
JS_ASSERT(!scriptsToGC[i]);
#endif
}
bool
@ -81,9 +101,19 @@ JSCompartment::init()
if (!crossCompartmentWrappers.init())
return false;
#ifdef JS_METHODJIT
if (!(jaegerCompartment = new mjit::JaegerCompartment))
#ifdef JS_TRACER
if (!InitJIT(&traceMonitor)) {
return false;
}
#endif
#ifdef JS_METHODJIT
if (!(jaegerCompartment = new mjit::JaegerCompartment)) {
#ifdef JS_TRACER
FinishJIT(&traceMonitor);
#endif
return false;
}
return jaegerCompartment->Initialize();
#else
return true;
@ -204,7 +234,10 @@ JSCompartment::wrap(JSContext *cx, Value *vp)
if (vp->isString()) {
Value orig = *vp;
JSString *str = vp->toString();
JSString *wrapped = js_NewStringCopyN(cx, str->chars(), str->length());
const jschar *chars = str->getChars(cx);
if (!chars)
return false;
JSString *wrapped = js_NewStringCopyN(cx, chars, str->length());
if (!wrapped)
return false;
vp->setString(wrapped);
@ -328,8 +361,33 @@ JSCompartment::wrapException(JSContext *cx)
return true;
}
/*
* Check if the pool containing the code for jit should be destroyed, per the
* heuristics in JSCompartment::sweep.
*/
static inline bool
ScriptPoolDestroyed(JSContext *cx, mjit::JITScript *jit,
uint32 releaseInterval, uint32 &counter)
{
JSC::ExecutablePool *pool = jit->code.m_executablePool;
if (pool->m_gcNumber != cx->runtime->gcNumber) {
/*
* The m_destroy flag may have been set in a previous GC for a pool which had
* references we did not remove (e.g. from the compartment's ExecutableAllocator)
* and is still around. Forget we tried to destroy it in such cases.
*/
pool->m_destroy = false;
pool->m_gcNumber = cx->runtime->gcNumber;
if (--counter == 0) {
pool->m_destroy = true;
counter = releaseInterval;
}
}
return pool->m_destroy;
}
void
JSCompartment::sweep(JSContext *cx)
JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
{
chunk = NULL;
/* Remove dead wrappers from the table. */
@ -343,13 +401,43 @@ JSCompartment::sweep(JSContext *cx)
}
}
#ifdef JS_TRACER
traceMonitor.sweep();
#endif
#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) {
JSScript *script = reinterpret_cast<JSScript *>(cursor);
if (script->hasJITCode())
mjit::ic::SweepCallICs(script);
if (script->hasJITCode()) {
mjit::ic::SweepCallICs(script, discardScripts);
if (discardScripts) {
if (script->jitNormal &&
ScriptPoolDestroyed(cx, script->jitNormal, releaseInterval, counter)) {
mjit::ReleaseScriptCode(cx, script);
continue;
}
if (script->jitCtor &&
ScriptPoolDestroyed(cx, script->jitCtor, releaseInterval, counter)) {
mjit::ReleaseScriptCode(cx, script);
}
}
}
}
#endif
#endif /* JS_METHODJIT && JS_MONOIC */
active = false;
}
void
@ -357,6 +445,20 @@ JSCompartment::purge(JSContext *cx)
{
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
for (JSScript *script = (JSScript *)scripts.next;
&script->links != &scripts;
@ -367,8 +469,8 @@ JSCompartment::purge(JSContext *cx)
# endif
# if defined JS_MONOIC
/*
* MICs do not refer to data which can be GC'ed, but are sensitive
* to shape regeneration.
* MICs do not refer to data which can be GC'ed and do not generate stubs
* which might need to be discarded, but are sensitive to shape regeneration.
*/
if (cx->runtime->gcRegenShapes)
mjit::ic::PurgeMICs(cx, script);
@ -377,3 +479,13 @@ JSCompartment::purge(JSContext *cx)
}
#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 *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
@ -55,11 +55,210 @@
#endif
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 {
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) {
JSRuntime *rt;
JSPrincipals *principals;
@ -72,8 +271,21 @@ struct JS_FRIEND_API(JSCompartment) {
js::gc::JSGCArenaStats compartmentStats[js::gc::FINALIZE_LIMIT];
#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;
bool marked;
bool active; // GC flag, whether there are active frames
js::WrapperMap crossCompartmentWrappers;
#ifdef JS_METHODJIT
@ -93,6 +305,8 @@ struct JS_FRIEND_API(JSCompartment) {
JSObject *anynameObject;
JSObject *functionNamespaceObject;
js::NativeIterCache nativeIterCache;
JSCompartment(JSRuntime *cx);
~JSCompartment();
@ -107,12 +321,39 @@ struct JS_FRIEND_API(JSCompartment) {
bool wrap(JSContext *cx, js::AutoIdVector &props);
bool wrapException(JSContext *cx);
void sweep(JSContext *cx);
void sweep(JSContext *cx, uint32 releaseInterval);
void purge(JSContext *cx);
void finishArenaLists();
bool arenaListsAreEmpty();
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
#pragma warning(pop)
#endif

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

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

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

@ -145,7 +145,7 @@ js_SetDebugMode(JSContext *cx, JSBool debug)
for (JSScript *script = (JSScript *)cx->compartment->scripts.next;
&script->links != &cx->compartment->scripts;
script = (JSScript *)script->links.next) {
if (script->debugMode != (bool) debug &&
if (script->debugMode != !!debug &&
script->hasJITCode() &&
!IsScriptLive(cx, script)) {
/*
@ -182,6 +182,30 @@ JS_SetDebugMode(JSContext *cx, JSBool debug)
return js_SetDebugMode(cx, debug);
}
JS_FRIEND_API(JSBool)
js_SetSingleStepMode(JSContext *cx, JSScript *script, JSBool singleStep)
{
if (!script->singleStepMode == !singleStep)
return JS_TRUE;
JS_ASSERT_IF(singleStep, cx->compartment->debugMode);
#ifdef JS_METHODJIT
/* request the next recompile to inject single step interrupts */
script->singleStepMode = !!singleStep;
js::mjit::JITScript *jit = script->jitNormal ? script->jitNormal : script->jitCtor;
if (jit && script->singleStepMode != jit->singleStepMode) {
js::mjit::Recompiler recompiler(cx, script);
if (!recompiler.recompile()) {
script->singleStepMode = !singleStep;
return JS_FALSE;
}
}
#endif
return JS_TRUE;
}
static JSBool
CheckDebugMode(JSContext *cx)
{
@ -198,6 +222,15 @@ CheckDebugMode(JSContext *cx)
return debugMode;
}
JS_PUBLIC_API(JSBool)
JS_SetSingleStepMode(JSContext *cx, JSScript *script, JSBool singleStep)
{
if (!CheckDebugMode(cx))
return JS_FALSE;
return js_SetSingleStepMode(cx, script, singleStep);
}
/*
* NB: FindTrap must be called with rt->debuggerLock acquired.
*/
@ -485,17 +518,6 @@ JITInhibitingHookChange(JSRuntime *rt, bool wasInhibited)
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
JS_PUBLIC_API(JSBool)
@ -511,7 +533,6 @@ JS_SetInterrupt(JSRuntime *rt, JSInterruptHook hook, void *closure)
#ifdef JS_TRACER
JITInhibitingHookChange(rt, wasInhibited);
}
LeaveTraceRT(rt);
#endif
return JS_TRUE;
}
@ -1672,8 +1693,6 @@ JS_SetCallHook(JSRuntime *rt, JSInterpreterHook hook, void *closure)
#ifdef JS_TRACER
JITInhibitingHookChange(rt, wasInhibited);
}
if (hook)
LeaveTraceRT(rt);
#endif
return JS_TRUE;
}
@ -1995,15 +2014,13 @@ JS_FRIEND_API(JSBool)
js_DumpCallgrind(JSContext *cx, uintN argc, jsval *vp)
{
JSString *str;
char *cstr;
jsval *argv = JS_ARGV(cx, vp);
if (argc > 0 && JSVAL_IS_STRING(argv[0])) {
str = JSVAL_TO_STRING(argv[0]);
cstr = js_DeflateString(cx, str->chars(), str->length());
if (cstr) {
CALLGRIND_DUMP_STATS_AT(cstr);
cx->free(cstr);
JSAutoByteString bytes(cx, str);
if (!!bytes) {
CALLGRIND_DUMP_STATS_AT(bytes.ptr());
return JS_TRUE;
}
}
@ -2245,7 +2262,7 @@ public:
JSHashNumber hash = JS_HashString(filename);
JSHashEntry **hep = JS_HashTableRawLookup(traceVisScriptTable, hash, filename);
if (*hep != NULL)
return JS_FALSE;
return NULL;
JS_HashTableRawAdd(traceVisScriptTable, hep, hash, filename, this);

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

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

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

@ -2270,7 +2270,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
}
/* Optimize accesses to undeclared globals. */
if (!TryConvertToGname(cg, pn, &op))
if (!cg->mightAliasLocals() && !TryConvertToGname(cg, pn, &op))
return JS_TRUE;
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);
/*
* Leave pn->pn_op == JSOP_NAME if cg->fun() is heavyweight, as we
* cannot be sure cg->fun() is not something of the form:
* Leave pn->pn_op == JSOP_NAME if cg->fun is heavyweight to
* 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
* such an invocation must be 42, since the callee name is
* lexically bound in an outer declarative environment from the
* function's activation. See jsfun.cpp:call_resolve.
* ECMAScript specifies that a function expression's name is bound
* in a lexical environment distinct from that used to bind its
* named parameters, the arguments object, and its variables. The
* 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);
if (!(cg->flags & TCF_FUN_HEAVYWEIGHT)) {
@ -3764,6 +3777,13 @@ js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body)
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()) {
CG_SWITCH_TO_PROLOG(cg);
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())
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 (cg2->flags & TCF_HAS_SHARPS) {
cg2->sharpSlotBase = fun->sharpSlotBase(cx);

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

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

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

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

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());
*objp = NULL;
bool valid = false;
uintN attrs = JSPROP_SHARED;
uintN attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
if (JSID_IS_INT(id)) {
uint32 arg = uint32(JSID_TO_INT(id));
attrs = JSPROP_ENUMERATE | JSPROP_SHARED;
if (arg < obj->getArgsInitialLength() && !obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE))
valid = true;
if (arg >= obj->getArgsInitialLength() || obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE))
return true;
attrs |= JSPROP_ENUMERATE;
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
if (!obj->isArgsLengthOverridden())
valid = true;
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)) {
if (!obj->getArgsCallee().isMagic(JS_ARGS_HOLE))
valid = true;
if (obj->isArgsLengthOverridden())
return true;
} else {
if (!JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom))
return true;
if (obj->getArgsCallee().isMagic(JS_ARGS_HOLE))
return true;
}
if (valid) {
Value tmp = UndefinedValue();
if (!js_DefineProperty(cx, obj, id, &tmp, ArgGetter, ArgSetter, attrs))
return JS_FALSE;
*objp = obj;
}
Value undef = UndefinedValue();
if (!js_DefineProperty(cx, obj, id, &undef, ArgGetter, ArgSetter, attrs))
return JS_FALSE;
*objp = obj;
return true;
}
@ -707,47 +710,35 @@ strictargs_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject
JS_ASSERT(obj->isStrictArguments());
*objp = NULL;
bool valid = false;
uintN attrs = JSPROP_SHARED;
uintN attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
PropertyOp getter = StrictArgGetter;
PropertyOp setter = StrictArgSetter;
if (JSID_IS_INT(id)) {
uint32 arg = uint32(JSID_TO_INT(id));
attrs = JSPROP_SHARED | JSPROP_ENUMERATE;
if (arg < obj->getArgsInitialLength() && !obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE))
valid = true;
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
if (!obj->isArgsLengthOverridden())
valid = true;
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)) {
Value tmp = UndefinedValue();
PropertyOp throwTypeError = CastAsPropertyOp(obj->getThrowTypeError());
uintN attrs = JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED;
if (!js_DefineProperty(cx, obj, id, &tmp, throwTypeError, throwTypeError, attrs))
return false;
if (arg >= obj->getArgsInitialLength() || obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE))
return true;
*objp = obj;
return true;
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.callerAtom)) {
/*
* Strict mode arguments objects have an immutable poison-pill caller
* property that throws a TypeError on getting or setting.
*/
PropertyOp throwTypeError = CastAsPropertyOp(obj->getThrowTypeError());
Value tmp = UndefinedValue();
if (!js_DefineProperty(cx, obj, id, &tmp, throwTypeError, throwTypeError,
JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED)) {
return false;
attrs |= JSPROP_ENUMERATE;
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
if (obj->isArgsLengthOverridden())
return true;
} else {
if (!JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom) &&
!JSID_IS_ATOM(id, cx->runtime->atomState.callerAtom)) {
return true;
}
*objp = obj;
return true;
attrs = JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED;
getter = setter = CastAsPropertyOp(obj->getThrowTypeError());
}
if (valid) {
Value tmp = UndefinedValue();
if (!js_DefineProperty(cx, obj, id, &tmp, StrictArgGetter, StrictArgSetter, attrs))
return false;
*objp = obj;
}
Value undef = UndefinedValue();
if (!js_DefineProperty(cx, obj, id, &undef, getter, setter, attrs))
return false;
*objp = obj;
return true;
}
@ -1589,10 +1580,13 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
/* Censor the caller if it is from another compartment. */
if (caller.getCompartment() != cx->compartment) {
vp->setNull();
} else if (caller.isFunction() && caller.getFunctionPrivate()->inStrictMode()) {
JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
JSMSG_CALLER_IS_STRICT);
return false;
} else if (caller.isFunction()) {
JSFunction *callerFun = caller.getFunctionPrivate();
if (callerFun->isInterpreted() && callerFun->inStrictMode()) {
JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
JSMSG_CALLER_IS_STRICT);
return false;
}
}
}
break;
@ -1762,7 +1756,7 @@ fun_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
PropertyOp getter, setter;
uintN attrs = JSPROP_PERMANENT;
if (fun->inStrictMode() || obj->isBoundFunction()) {
if (fun->isInterpreted() ? fun->inStrictMode() : obj->isBoundFunction()) {
JSObject *throwTypeError = obj->getThrowTypeError();
getter = CastAsPropertyOp(throwTypeError);
@ -2060,7 +2054,7 @@ fun_finalize(JSContext *cx, JSObject *obj)
* very early.
*/
if (FUN_INTERPRETED(fun) && fun->u.i.script)
js_DestroyScriptFromGC(cx, fun->u.i.script, NULL);
js_DestroyScriptFromGC(cx, fun->u.i.script);
}
int
@ -2603,7 +2597,12 @@ Function(JSContext *cx, uintN argc, Value *vp)
for (uintN i = 0; i < n; i++) {
JSString *arg = argv[i].toString();
size_t arg_length = arg->length();
(void) js_strncpy(cp, arg->chars(), arg_length);
const jschar *arg_chars = arg->getChars(cx);
if (!arg_chars) {
JS_ARENA_RELEASE(&cx->tempPool, mark);
return JS_FALSE;
}
(void) js_strncpy(cp, arg_chars, arg_length);
cp += arg_length;
/* Add separating comma or terminating 0. */
@ -2690,8 +2689,11 @@ Function(JSContext *cx, uintN argc, Value *vp)
str = cx->runtime->emptyString;
}
return Compiler::compileFunctionBody(cx, fun, principals,
str->chars(), str->length(),
size_t length = str->length();
const jschar *chars = str->getChars(cx);
if (!chars)
return JS_FALSE;
return Compiler::compileFunctionBody(cx, fun, principals, chars, length,
filename, lineno);
}
@ -3143,54 +3145,21 @@ JSFunction::addLocal(JSContext *cx, JSAtom *atom, JSLocalKind kind)
return false;
}
Shape **listp = &u.i.names;
Shape *parent = *listp;
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) {
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);
} else {
if (kind == JSLOCAL_ARG && parent->inDictionary())
findArgInsertionPoint = true;
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 *shape = parent->getChild(cx, child, listp);
Shape *shape = u.i.names->getChild(cx, child, &u.i.names);
if (!shape)
return false;
JS_ASSERT_IF(!shape->inDictionary(), u.i.names == shape);
JS_ASSERT(u.i.names == shape);
++*indexp;
return true;
}

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

@ -180,10 +180,9 @@ struct JSFunction : public JSObject_Slots2
bool isFunctionPrototype() const { return flags & JSFUN_PROTOTYPE; }
/* Returns the strictness of this function, which must be interpreted. */
inline bool inStrictMode() const;
bool acceptsPrimitiveThis() const { return flags & JSFUN_PRIMITIVE_THIS; }
uintN countVars() const {
JS_ASSERT(FUN_INTERPRETED(this));
return u.i.nvars;
@ -215,6 +214,11 @@ struct JSFunction : public JSObject_Slots2
const js::Shape *lastVar() const;
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);
/*
@ -435,6 +439,14 @@ IsFunctionObject(const js::Value &v, JSFunction **fun)
return b;
}
extern JS_ALWAYS_INLINE bool
SameTraceType(const Value &lhs, const Value &rhs)
{
return SameType(lhs, rhs) &&
(lhs.isPrimitive() ||
lhs.toObject().isFunction() == rhs.toObject().isFunction());
}
/*
* Macro to access the private slot of the function object after the slot is
* initialized.

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

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

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

@ -492,6 +492,13 @@ js_GCThingIsMarked(void *thing, uint32 color = BLACK)
return reinterpret_cast<Cell *>(thing)->isMarked(color);
}
/*
* 1/8 life for JIT code. After this number of microseconds have passed, 1/8 of all
* JIT code is discarded in inactive compartments, regardless of how often that
* code runs.
*/
static const int64 JIT_SCRIPT_EIGHTH_LIFETIME = 120 * 1000 * 1000;
JSBool
js_InitGC(JSRuntime *rt, uint32 maxbytes)
{
@ -539,6 +546,8 @@ js_InitGC(JSRuntime *rt, uint32 maxbytes)
*/
rt->setGCLastBytes(8192);
rt->gcJitReleaseTime = PRMJ_Now() + JIT_SCRIPT_EIGHTH_LIFETIME;
METER(PodZero(&rt->gcStats));
return true;
}
@ -777,16 +786,18 @@ ConservativeGCThreadData::recordStackTop()
jsuword 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)
# pragma warning(push)
# pragma warning(disable: 4611)
#endif
setjmp(registerSnapshot.jmpbuf);
(void) setjmp(registerSnapshot.jmpbuf);
#if defined(_MSC_VER)
# pragma warning(pop)
#endif
}
static inline void
@ -1016,7 +1027,7 @@ FreeLists::purge()
*p = NULL;
}
struct JSShortString;
class JSShortString;
ArenaList *
GetFinalizableArenaList(JSCompartment *c, unsigned thingKind) {
@ -1435,8 +1446,10 @@ js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp)
MarkObject(trc, fp->callObj(), "call");
if (fp->hasArgsObj())
MarkObject(trc, fp->argsObj(), "arguments");
if (fp->isScriptFrame())
if (fp->isScriptFrame()) {
js_TraceScript(trc, fp->script());
fp->script()->compartment->active = true;
}
MarkValue(trc, fp->returnValue(), "rval");
}
@ -1732,16 +1745,16 @@ TriggerGC(JSRuntime *rt)
} /* namespace js */
void
js_DestroyScriptsToGC(JSContext *cx, JSThreadData *data)
js_DestroyScriptsToGC(JSContext *cx, JSCompartment *comp)
{
JSScript **listp, *script;
for (size_t i = 0; i != JS_ARRAY_LENGTH(data->scriptsToGC); ++i) {
listp = &data->scriptsToGC[i];
for (size_t i = 0; i != JS_ARRAY_LENGTH(comp->scriptsToGC); ++i) {
listp = &comp->scriptsToGC[i];
while ((script = *listp) != NULL) {
*listp = script->u.nextToGC;
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));
/* A stillborn string has null chars, so is not valid. */
jschar *chars = str->flatChars();
jschar *chars = const_cast<jschar *>(str->flatChars());
if (!chars)
return;
if (thingKind == FINALIZE_STRING) {
@ -2029,13 +2042,29 @@ SweepCompartments(JSContext *cx, JSGCInvocationKind gckind)
/* Delete defaultCompartment only during runtime shutdown */
rt->defaultCompartment->marked = true;
/*
* Figure out how much JIT code should be released from inactive compartments.
* If multiple eighth-lifes have passed, compound the release interval linearly;
* if enough time has passed, all inactive JIT code will be released.
*/
uint32 releaseInterval = 0;
int64 now = PRMJ_Now();
if (now >= rt->gcJitReleaseTime) {
releaseInterval = 8;
while (now >= rt->gcJitReleaseTime) {
if (--releaseInterval == 1)
rt->gcJitReleaseTime = now;
rt->gcJitReleaseTime += JIT_SCRIPT_EIGHTH_LIFETIME;
}
}
while (read < end) {
JSCompartment *compartment = (*read++);
if (compartment->marked) {
compartment->marked = false;
*write++ = compartment;
/* Remove dead wrappers from the compartment map. */
compartment->sweep(cx);
compartment->sweep(cx, releaseInterval);
} else {
JS_ASSERT(compartment->freeLists.isEmpty());
if (compartment->arenaListsAreEmpty() || gckind == GC_LAST_CONTEXT) {
@ -2047,7 +2076,7 @@ SweepCompartments(JSContext *cx, JSGCInvocationKind gckind)
} else {
compartment->marked = false;
*write++ = compartment;
compartment->sweep(cx);
compartment->sweep(cx, releaseInterval);
}
}
}
@ -2177,11 +2206,6 @@ MarkAndSweep(JSContext *cx, JSGCInvocationKind gckind GCTIMER_PARAM)
rt->liveObjectPropsPreSweep = rt->liveObjectProps;
#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
* object which properties it enumerates over to finalize the enumeration
@ -2589,6 +2613,7 @@ NewCompartment(JSContext *cx, JSPrincipals *principals)
JSRuntime *rt = cx->runtime;
JSCompartment *compartment = new JSCompartment(rt);
if (!compartment || !compartment->init()) {
delete compartment;
JS_ReportOutOfMemory(cx);
return NULL;
}

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

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

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

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

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

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

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

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

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

@ -857,13 +857,6 @@ ComputeThisFromVpInPlace(JSContext *cx, js::Value *vp)
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
* natives to js::Invoke.
@ -1030,11 +1023,11 @@ CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs,
JSObject **objp, JSProperty **propp);
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. */
extern bool
SameValue(const Value &v1, const Value &v2, JSContext *cx);
SameValue(JSContext *cx, const Value &v1, const Value &v2, JSBool *same);
extern JSType
TypeOfValue(JSContext *cx, const Value &v);

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

@ -49,6 +49,8 @@
#include "jsstr.h"
#include "methodjit/MethodJIT.h"
#include "jsfuninlines.h"
inline void
JSStackFrame::initPrev(JSContext *cx)
{
@ -356,7 +358,7 @@ JSStackFrame::computeThis(JSContext *cx)
if (thisv.isObject())
return true;
if (isFunctionFrame()) {
if (fun()->acceptsPrimitiveThis())
if (fun()->inStrictMode())
return true;
/*
* 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())
Probes::exitJSFun(cx, fp->maybeFun(), fp->maybeScript());
JSInterpreterHook hook = cx->debugHooks->callHook;
void* hookData;
JSInterpreterHook hook =
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);
/*

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

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

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

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

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

@ -315,7 +315,10 @@ num_parseFloat(JSContext *cx, uintN argc, Value *vp)
str = js_ValueToString(cx, vp[2]);
if (!str)
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))
return JS_FALSE;
if (ep == bp) {
@ -330,12 +333,15 @@ num_parseFloat(JSContext *cx, uintN argc, Value *vp)
static jsdouble FASTCALL
ParseFloat(JSContext* cx, JSString* str)
{
const jschar* bp;
const jschar* end;
const jschar* ep;
jsdouble d;
const jschar *bp = str->getChars(cx);
if (!bp) {
SetBuiltinError(cx);
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)
return js_NaN;
return d;
@ -451,8 +457,10 @@ num_parseInt(JSContext *cx, uintN argc, Value *vp)
}
/* Steps 2-5, 9-14. */
const jschar *ws, *end;
inputString->getCharsAndEnd(ws, end);
const jschar *ws = inputString->getChars(cx);
if (!ws)
return false;
const jschar *end = ws + inputString->length();
jsdouble number;
if (!ParseIntStringHelper(cx, ws, end, radix, stripPrefix, &number))
@ -467,8 +475,12 @@ num_parseInt(JSContext *cx, uintN argc, Value *vp)
static jsdouble FASTCALL
ParseInt(JSContext* cx, JSString* str)
{
const jschar *start, *end;
str->getCharsAndEnd(start, end);
const jschar *start = str->getChars(cx);
if (!start) {
SetBuiltinError(cx);
return js_NaN;
}
const jschar *end = start + str->length();
jsdouble 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)))
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 */
@ -722,7 +734,7 @@ num_toLocaleString(JSContext *cx, uintN argc, Value *vp)
const char *num, *end, *tmpSrc;
char *buf, *tmpDest;
const char *nint;
int digits, size, remainder, nrepeat;
int digits, buflen, remainder, nrepeat;
/*
* 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);
/* 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 == '.')
size += decimalLength;
buflen += decimalLength;
numGrouping = tmpGroup = rt->numGrouping;
remainder = digits;
@ -769,20 +781,20 @@ num_toLocaleString(JSContext *cx, uintN argc, Value *vp)
while (*tmpGroup != CHAR_MAX && *tmpGroup != '\0') {
if (*tmpGroup >= remainder)
break;
size += thousandsLength;
buflen += thousandsLength;
remainder -= *tmpGroup;
tmpGroup++;
}
if (*tmpGroup == '\0' && *numGrouping != '\0') {
nrepeat = (remainder - 1) / tmpGroup[-1];
size += thousandsLength * nrepeat;
buflen += thousandsLength * nrepeat;
remainder -= nrepeat * tmpGroup[-1];
} else {
nrepeat = 0;
}
tmpGroup--;
buf = (char *)cx->malloc(size + 1);
buf = (char *)cx->malloc(buflen + 1);
if (!buf)
return JS_FALSE;
@ -815,7 +827,7 @@ num_toLocaleString(JSContext *cx, uintN argc, Value *vp)
return ok;
}
str = js_NewStringCopyN(cx, buf, size);
str = js_NewStringCopyN(cx, buf, buflen);
cx->free(buf);
if (!str)
return JS_FALSE;
@ -920,15 +932,15 @@ JS_DEFINE_TRCINFO_2(num_toString,
static JSFunctionSpec number_methods[] = {
#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
JS_TN(js_toString_str, num_toString, 1, JSFUN_PRIMITIVE_THIS, &num_toString_trcinfo),
JS_FN(js_toLocaleString_str, num_toLocaleString, 0, JSFUN_PRIMITIVE_THIS),
JS_FN(js_valueOf_str, js_num_valueOf, 0, JSFUN_PRIMITIVE_THIS),
JS_FN(js_toJSON_str, js_num_valueOf, 0, JSFUN_PRIMITIVE_THIS),
JS_FN("toFixed", num_toFixed, 1, JSFUN_PRIMITIVE_THIS),
JS_FN("toExponential", num_toExponential, 1, JSFUN_PRIMITIVE_THIS),
JS_FN("toPrecision", num_toPrecision, 1, JSFUN_PRIMITIVE_THIS),
JS_TN(js_toString_str, num_toString, 1, 0, &num_toString_trcinfo),
JS_FN(js_toLocaleString_str, num_toLocaleString, 0, 0),
JS_FN(js_valueOf_str, js_num_valueOf, 0, 0),
JS_FN(js_toJSON_str, js_num_valueOf, 0, 0),
JS_FN("toFixed", num_toFixed, 1, 0),
JS_FN("toExponential", num_toExponential, 1, 0),
JS_FN("toPrecision", num_toPrecision, 1, 0),
JS_FS_END
};
@ -1187,6 +1199,14 @@ js_NumberToString(JSContext *cx, jsdouble d)
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
js_NumberValueToCharBuffer(JSContext *cx, const Value &v, JSCharBuffer &cb)
{
@ -1235,13 +1255,8 @@ ValueToNumberSlow(JSContext *cx, Value v, double *out)
return true;
}
skip_int_double:
if (v.isString()) {
jsdouble d = StringToNumberType<jsdouble>(cx, v.toString());
if (JSDOUBLE_IS_NaN(d))
break;
*out = d;
return true;
}
if (v.isString())
return StringToNumberType<jsdouble>(cx, v.toString(), out);
if (v.isBoolean()) {
if (v.toBoolean()) {
*out = 1.0;

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

@ -206,6 +206,10 @@ js_NumberValueToCharBuffer(JSContext *cx, const js::Value &v, JSCharBuffer &cb);
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
* to dynamically allocate much more. This struct encapsulates that.
@ -643,35 +647,44 @@ template<> struct NumberTraits<jsdouble> {
};
template<typename T>
static JS_ALWAYS_INLINE T
StringToNumberType(JSContext *cx, JSString *str)
static JS_ALWAYS_INLINE bool
StringToNumberType(JSContext *cx, JSString *str, T *result)
{
if (str->length() == 1) {
jschar c = str->chars()[0];
if ('0' <= c && c <= '9')
return NumberTraits<T>::toSelfType(T(c - '0'));
if (JS_ISSPACE(c))
return NumberTraits<T>::toSelfType(T(0));
return NumberTraits<T>::NaN();
size_t length = str->length();
const jschar *chars = str->getChars(NULL);
if (!chars)
return false;
if (length == 1) {
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* end;
const jschar* ep;
jsdouble d;
str->getCharsAndEnd(bp, end);
const jschar *bp = chars;
const jschar *end = chars + length;
bp = js_SkipWhiteSpace(bp, end);
/* ECMA doesn't allow signed hex numbers (bug 273467). */
if (end - bp >= 2 && bp[0] == '0' && (bp[1] == 'x' || bp[1] == 'X')) {
/* Looks like a hex number. */
const jschar *endptr;
double d;
if (!GetPrefixInteger(cx, bp + 2, end, 16, &endptr, &d) ||
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
* be treated as 0 without consuming the 'x' by js_strtod.
*/
if (!js_strtod(cx, bp, end, &ep, &d) ||
js_SkipWhiteSpace(ep, end) != end) {
return NumberTraits<T>::NaN();
const jschar *ep;
double d;
if (!js_strtod(cx, bp, end, &ep, &d) || js_SkipWhiteSpace(ep, end) != end) {
*result = NumberTraits<T>::NaN();
return true;
}
return NumberTraits<T>::toSelfType(d);
*result = NumberTraits<T>::toSelfType(d);
return true;
}
}

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

@ -484,7 +484,8 @@ obj_toSource(JSContext *cx, uintN argc, Value *vp)
JSProperty *prop;
Value *val;
JSString *gsop[2];
JSString *idstr, *valstr, *str;
JSString *valstr, *str;
JSLinearString *idstr;
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
* prefer get/set or old getter/setter syntax.
*/
idstr = js_ValueToString(cx, IdToValue(id));
if (!idstr) {
JSString *s = js_ValueToString(cx, IdToValue(id));
if (!s || !(idstr = s->ensureLinear(cx))) {
ok = JS_FALSE;
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
* integer, then it must be quoted.
*/
bool idIsLexicalIdentifier = !!js_IsIdentifier(idstr);
bool idIsLexicalIdentifier = js_IsIdentifier(idstr);
if (JSID_IS_ATOM(id)
? !idIsLexicalIdentifier
: (!JSID_IS_INT(id) || JSID_TO_INT(id) < 0)) {
idstr = js_QuoteString(cx, idstr, jschar('\''));
if (!idstr) {
s = js_QuoteString(cx, idstr, jschar('\''));
if (!s || !(idstr = s->ensureLinear(cx))) {
ok = JS_FALSE;
goto error;
}
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++) {
/*
@ -637,7 +643,12 @@ obj_toSource(JSContext *cx, uintN argc, Value *vp)
goto error;
}
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
@ -727,10 +738,8 @@ obj_toSource(JSContext *cx, uintN argc, Value *vp)
/* Allocate 1 + 1 at end for closing brace and terminating 0. */
chars = (jschar *) js_realloc((ochars = chars), curlen * sizeof(jschar));
if (!chars) {
/* Save code space on error: let JS_free ignore null vsharp. */
cx->free(vsharp);
js_free(ochars);
goto error;
chars = ochars;
goto overflow;
}
if (comma) {
@ -741,8 +750,10 @@ obj_toSource(JSContext *cx, uintN argc, Value *vp)
if (gsop[j]) {
gsoplength = gsop[j]->length();
js_strncpy(&chars[nchars], gsop[j]->chars(),
gsoplength);
const jschar *gsopchars = gsop[j]->getChars(cx);
if (!gsopchars)
goto overflow;
js_strncpy(&chars[nchars], gsopchars, gsoplength);
nchars += gsoplength;
chars[nchars++] = ' ';
}
@ -987,15 +998,14 @@ js_ComputeFilename(JSContext *cx, JSStackFrame *caller,
#endif
static inline JSScript **
EvalCacheHash(JSContext *cx, JSString *str)
EvalCacheHash(JSContext *cx, JSLinearString *str)
{
const jschar *s;
size_t n;
uint32 h;
const jschar *s = str->chars();
size_t n = str->length();
str->getCharsAndLength(s, n);
if (n > 100)
n = 100;
uint32 h;
for (h = 0; n; s++, n--)
h = JS_ROTATE_LEFT32(h, 4) ^ *s;
@ -1005,7 +1015,7 @@ EvalCacheHash(JSContext *cx, JSString *str)
}
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)
{
/*
@ -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
* strictness matches that of the new eval code. The existing code takes
* care of this, because hits are qualified by the function from which
* eval was called, whose strictness doesn't change. Scripts produced by
* calls to eval from global code are not cached.
* eval was called, whose strictness doesn't change. (We don't cache evals
* 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;
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
* 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
* 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))
return false;
const jschar *chars;
size_t length;
str->getCharsAndLength(chars, length);
JSLinearString *linearStr = str->ensureLinear(cx);
if (!linearStr)
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.
@ -1214,9 +1233,9 @@ EvalKernel(JSContext *cx, uintN argc, Value *vp, EvalType evalType, JSStackFrame
return false;
JSScript *script = NULL;
JSScript **bucket = EvalCacheHash(cx, str);
if (evalType == DIRECT_EVAL && caller->isFunctionFrame())
script = EvalCacheLookup(cx, str, caller, staticLevel, principals, scopeobj, bucket);
JSScript **bucket = EvalCacheHash(cx, linearStr);
if (evalType == DIRECT_EVAL && caller->isFunctionFrame() && !caller->isEvalFrame())
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
@ -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;
script = Compiler::compileScript(cx, scopeobj, callerFrame,
principals, tcflags,
chars, length,
filename, lineno, str, staticLevel);
principals, tcflags, chars, length,
filename, lineno, linearStr, staticLevel);
if (!script)
return false;
}
@ -1992,6 +2010,23 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc,
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. */
if (!current) {
if (!obj->isExtensible())
@ -2040,14 +2075,20 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc,
if (!shape->isAccessorDescriptor())
break;
if (desc.hasGet &&
!SameValue(desc.getterValue(), shape->getterOrUndefined(), cx)) {
break;
if (desc.hasGet) {
JSBool same;
if (!SameValue(cx, desc.getterValue(), shape->getterOrUndefined(), &same))
return JS_FALSE;
if (!same)
break;
}
if (desc.hasSet &&
!SameValue(desc.setterValue(), shape->setterOrUndefined(), cx)) {
break;
if (desc.hasSet) {
JSBool same;
if (!SameValue(cx, desc.setterValue(), shape->setterOrUndefined(), &same))
return JS_FALSE;
if (!same)
break;
}
} else {
/*
@ -2096,8 +2137,13 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc,
if (!shape->isDataDescriptor())
break;
if (desc.hasValue && !SameValue(desc.value, v, cx))
break;
JSBool same;
if (desc.hasValue) {
if (!SameValue(cx, desc.value, v, &same))
return JS_FALSE;
if (!same)
break;
}
if (desc.hasWritable && desc.writable() != shape->writable())
break;
} else {
@ -2144,9 +2190,14 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc,
/* 8.12.9 step 10. */
JS_ASSERT(shape->isDataDescriptor());
if (!shape->configurable() && !shape->writable()) {
if ((desc.hasWritable && desc.writable()) ||
(desc.hasValue && !SameValue(desc.value, v, cx))) {
if (desc.hasWritable && desc.writable())
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. */
JS_ASSERT(desc.isAccessorDescriptor() && shape->isAccessorDescriptor());
if (!shape->configurable()) {
if ((desc.hasSet &&
!SameValue(desc.setterValue(), shape->setterOrUndefined(), cx)) ||
(desc.hasGet &&
!SameValue(desc.getterValue(), shape->getterOrUndefined(), cx))) {
return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval);
if (desc.hasSet) {
JSBool same;
if (!SameValue(cx, desc.setterValue(), shape->setterOrUndefined(), &same))
return JS_FALSE;
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
JS_FN(js_toSource_str, obj_toSource, 0,0),
#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_valueOf_str, obj_valueOf, 0,0),
#if JS_HAS_OBJ_WATCHPOINT
@ -4487,7 +4547,7 @@ CallAddPropertyHook(JSContext *cx, Class *clasp, JSObject *obj, const Shape *sha
if (clasp->addProperty != PropertyStub) {
Value nominal = *vp;
if (!CallJSPropertyOp(cx, clasp->addProperty, obj, SHAPE_USERID(shape), vp))
if (!CallJSPropertyOp(cx, clasp->addProperty, obj, shape->id, vp))
return false;
if (*vp != nominal) {
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. */
if (obj->containsSlot(shape->slot))
if (obj->containsSlot(shape->slot)) {
AbortRecordingIfUnexpectedGlobalWrite(cx, obj, shape->slot);
obj->nativeSetSlot(shape->slot, value);
}
/* XXXbe called with lock held */
valueCopy = value;
@ -5091,6 +5153,7 @@ js_NativeSet(JSContext *cx, JSObject *obj, const Shape *shape, bool added, Value
if (shape->hasDefaultSetter()) {
if (!added && !obj->methodWriteBarrier(cx, *shape, *vp))
return false;
AbortRecordingIfUnexpectedGlobalWrite(cx, obj, slot);
obj->nativeSetSlot(slot, *vp);
return true;
}
@ -5117,6 +5180,7 @@ js_NativeSet(JSContext *cx, JSObject *obj, const Shape *shape, bool added, Value
obj->nativeContains(*shape))) {
if (!added && !obj->methodWriteBarrier(cx, *shape, *vp))
return false;
AbortRecordingIfUnexpectedGlobalWrite(cx, obj, slot);
obj->setSlot(slot, *vp);
}
@ -5455,10 +5519,8 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
if (pobj != obj) {
/*
* 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) {
#ifdef JS_TRACER
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);
}
/* Restore attrs to the ECMA default for new properties. */
attrs = JSPROP_ENUMERATE;
/*
* Preserve the shortid, getter, and setter when shadowing any
* property that has a shortid. An old API convention requires
* that the property's getter and setter functions receive the
* shortid, not id, when they are called on the shadow we are
* Preserve attrs except JSPROP_SHARED, getter, and setter when
* shadowing any property that has no slot (is shared). We must
* clear the shared attribute for the shadowing shape so that the
* 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.
*/
if (shape->hasShortID()) {
flags = Shape::HAS_SHORTID;
shortid = shape->shortid;
if (!shape->hasSlot()) {
defineHow &= ~JSDNP_SET_METHOD;
if (shape->hasShortID()) {
flags = Shape::HAS_SHORTID;
shortid = shape->shortid;
}
attrs &= ~JSPROP_SHARED;
getter = shape->getter();
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)) {
JS_snprintf(buf, bufsize, "%ld", (long)JSID_TO_INT(id));
} else if (JSID_IS_ATOM(id)) {
PutEscapedString(buf, bufsize, JSID_TO_STRING(id), 0);
PutEscapedString(buf, bufsize, JSID_TO_ATOM(id), 0);
} else {
JS_snprintf(buf, bufsize, "**FINALIZED ATOM KEY**");
}
@ -6501,15 +6575,22 @@ js_DumpChars(const jschar *s, size_t n)
void
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_DumpString(JSString *str)
{
fprintf(stderr, "JSString* (%p) = jschar * (%p) = ",
(void *) str, (void *) str->chars());
dumpString(str);
if (const jschar *chars = str->getChars(NULL)) {
fprintf(stderr, "JSString* (%p) = jschar * (%p) = ",
(void *) str, (void *) chars);
dumpString(str);
} else {
fprintf(stderr, "(oom in JS_DumpString)");
}
fputc('\n', stderr);
}

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

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

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