зеркало из https://github.com/mozilla/pjs.git
Merge mozilla-central to tracemonkey.
This commit is contained in:
Коммит
366ec4ad44
|
@ -114,7 +114,7 @@ static inline const PRUnichar *
|
||||||
IDToString(JSContext *cx, jsid id)
|
IDToString(JSContext *cx, jsid id)
|
||||||
{
|
{
|
||||||
if (JSID_IS_STRING(id))
|
if (JSID_IS_STRING(id))
|
||||||
return reinterpret_cast<PRUnichar*>(JS_GetStringChars(JSID_TO_STRING(id)));
|
return JS_GetInternedStringChars(JSID_TO_STRING(id));
|
||||||
|
|
||||||
JSAutoRequest ar(cx);
|
JSAutoRequest ar(cx);
|
||||||
jsval idval;
|
jsval idval;
|
||||||
|
@ -123,7 +123,7 @@ IDToString(JSContext *cx, jsid id)
|
||||||
JSString *str = JS_ValueToString(cx, idval);
|
JSString *str = JS_ValueToString(cx, idval);
|
||||||
if(!str)
|
if(!str)
|
||||||
return nsnull;
|
return nsnull;
|
||||||
return reinterpret_cast<PRUnichar*>(JS_GetStringChars(str));
|
return JS_GetStringCharsZ(cx, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
class nsAutoInPrincipalDomainOriginSetter {
|
class nsAutoInPrincipalDomainOriginSetter {
|
||||||
|
|
|
@ -95,9 +95,10 @@ static void
|
||||||
getUTF8StringArgument(JSContext *cx, JSObject *obj, PRUint16 argNum,
|
getUTF8StringArgument(JSContext *cx, JSObject *obj, PRUint16 argNum,
|
||||||
uintN argc, jsval *argv, nsCString& aRetval)
|
uintN argc, jsval *argv, nsCString& aRetval)
|
||||||
{
|
{
|
||||||
|
aRetval.Truncate();
|
||||||
|
|
||||||
if (argc <= argNum || !JSVAL_IS_STRING(argv[argNum])) {
|
if (argc <= argNum || !JSVAL_IS_STRING(argv[argNum])) {
|
||||||
JS_ReportError(cx, "String argument expected");
|
JS_ReportError(cx, "String argument expected");
|
||||||
aRetval.Truncate();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,12 +107,13 @@ getUTF8StringArgument(JSContext *cx, JSObject *obj, PRUint16 argNum,
|
||||||
* to have an object to represent a target in subsequent versions.
|
* to have an object to represent a target in subsequent versions.
|
||||||
*/
|
*/
|
||||||
JSString *str = JSVAL_TO_STRING(argv[argNum]);
|
JSString *str = JSVAL_TO_STRING(argv[argNum]);
|
||||||
if (!str) {
|
if (!str)
|
||||||
aRetval.Truncate();
|
return;
|
||||||
|
|
||||||
|
const PRUnichar *data = JS_GetStringCharsZ(cx, str);
|
||||||
|
if (!data)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
PRUnichar *data = (PRUnichar*)JS_GetStringChars(str);
|
|
||||||
CopyUTF16toUTF8(data, aRetval);
|
CopyUTF16toUTF8(data, aRetval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -208,7 +208,11 @@ nsFrameMessageManager::GetParamsForMessage(nsAString& aMessageName,
|
||||||
JSAutoRequest ar(ctx);
|
JSAutoRequest ar(ctx);
|
||||||
JSString* str;
|
JSString* str;
|
||||||
if (argc && (str = JS_ValueToString(ctx, argv[0])) && str) {
|
if (argc && (str = JS_ValueToString(ctx, argv[0])) && str) {
|
||||||
aMessageName.Assign(nsDependentJSString(str));
|
nsDependentJSString depStr;
|
||||||
|
if (!depStr.init(ctx, str)) {
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
aMessageName.Assign(depStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc >= 2) {
|
if (argc >= 2) {
|
||||||
|
|
|
@ -2957,17 +2957,27 @@ nsWebSocket::Initialize(nsISupports* aOwner,
|
||||||
if (!jsstr) {
|
if (!jsstr) {
|
||||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||||
}
|
}
|
||||||
urlParam.Assign(reinterpret_cast<const PRUnichar*>(JS_GetStringChars(jsstr)),
|
|
||||||
JS_GetStringLength(jsstr));
|
size_t length;
|
||||||
|
const jschar *chars = JS_GetStringCharsAndLength(aContext, jsstr, &length);
|
||||||
|
if (!chars) {
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
urlParam.Assign(chars, length);
|
||||||
|
|
||||||
if (aArgc == 2) {
|
if (aArgc == 2) {
|
||||||
jsstr = JS_ValueToString(aContext, aArgv[1]);
|
jsstr = JS_ValueToString(aContext, aArgv[1]);
|
||||||
if (!jsstr) {
|
if (!jsstr) {
|
||||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||||
}
|
}
|
||||||
protocolParam.
|
|
||||||
Assign(reinterpret_cast<const PRUnichar*>(JS_GetStringChars(jsstr)),
|
chars = JS_GetStringCharsAndLength(aContext, jsstr, &length);
|
||||||
JS_GetStringLength(jsstr));
|
if (!chars) {
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
protocolParam.Assign(chars, length);
|
||||||
if (protocolParam.IsEmpty()) {
|
if (protocolParam.IsEmpty()) {
|
||||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,7 +140,10 @@ nsEventListenerInfo::ToSource(nsAString& aResult)
|
||||||
if (GetJSVal(&v)) {
|
if (GetJSVal(&v)) {
|
||||||
JSString* str = JS_ValueToSource(cx, v);
|
JSString* str = JS_ValueToSource(cx, v);
|
||||||
if (str) {
|
if (str) {
|
||||||
aResult.Assign(nsDependentJSString(str));
|
nsDependentJSString depStr;
|
||||||
|
if (depStr.init(cx, str)) {
|
||||||
|
aResult.Assign(depStr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,7 +140,10 @@ nsHTMLAudioElement::Initialize(nsISupports* aOwner, JSContext* aContext,
|
||||||
if (!jsstr)
|
if (!jsstr)
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
nsDependentJSString str(jsstr);
|
nsDependentJSString str;
|
||||||
|
if (!str.init(aContext, jsstr))
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
rv = SetAttr(kNameSpaceID_None, nsGkAtoms::src, str, PR_TRUE);
|
rv = SetAttr(kNameSpaceID_None, nsGkAtoms::src, str, PR_TRUE);
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
return rv;
|
return rv;
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
#include "nsIScriptSecurityManager.h"
|
#include "nsIScriptSecurityManager.h"
|
||||||
#include "nsIXPConnect.h"
|
#include "nsIXPConnect.h"
|
||||||
#include "jsapi.h"
|
#include "jsapi.h"
|
||||||
|
#include "nsJSUtils.h"
|
||||||
|
|
||||||
#include "nsFrameManager.h"
|
#include "nsFrameManager.h"
|
||||||
#include "nsDisplayList.h"
|
#include "nsDisplayList.h"
|
||||||
|
@ -502,8 +503,11 @@ nsHTMLCanvasElement::GetContext(const nsAString& aContextId,
|
||||||
}
|
}
|
||||||
|
|
||||||
JSString *propnameString = JS_ValueToString(cx, propname);
|
JSString *propnameString = JS_ValueToString(cx, propname);
|
||||||
|
nsDependentJSString pstr;
|
||||||
nsDependentString pstr(JS_GetStringChars(propnameString), JS_GetStringLength(propnameString));
|
if (!propnameString || !pstr.init(cx, propnameString)) {
|
||||||
|
mCurrentContext = nsnull;
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
if (JSVAL_IS_BOOLEAN(propval)) {
|
if (JSVAL_IS_BOOLEAN(propval)) {
|
||||||
newProps->SetPropertyAsBool(pstr, propval == JSVAL_TRUE ? PR_TRUE : PR_FALSE);
|
newProps->SetPropertyAsBool(pstr, propval == JSVAL_TRUE ? PR_TRUE : PR_FALSE);
|
||||||
|
@ -512,8 +516,14 @@ nsHTMLCanvasElement::GetContext(const nsAString& aContextId,
|
||||||
} else if (JSVAL_IS_DOUBLE(propval)) {
|
} else if (JSVAL_IS_DOUBLE(propval)) {
|
||||||
newProps->SetPropertyAsDouble(pstr, JSVAL_TO_DOUBLE(propval));
|
newProps->SetPropertyAsDouble(pstr, JSVAL_TO_DOUBLE(propval));
|
||||||
} else if (JSVAL_IS_STRING(propval)) {
|
} else if (JSVAL_IS_STRING(propval)) {
|
||||||
newProps->SetPropertyAsAString(pstr, nsDependentString(JS_GetStringChars(JS_ValueToString(cx, propval)),
|
JSString *propvalString = JS_ValueToString(cx, propval);
|
||||||
JS_GetStringLength(JS_ValueToString(cx, propval))));
|
nsDependentJSString vstr;
|
||||||
|
if (!propvalString || !vstr.init(cx, propvalString)) {
|
||||||
|
mCurrentContext = nsnull;
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
newProps->SetPropertyAsAString(pstr, vstr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -412,10 +412,13 @@ nsHTMLOptionElement::Initialize(nsISupports* aOwner,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
textContent->SetText(reinterpret_cast<const PRUnichar*>
|
size_t length;
|
||||||
(JS_GetStringChars(jsstr)),
|
const jschar *chars = JS_GetStringCharsAndLength(aContext, jsstr, &length);
|
||||||
JS_GetStringLength(jsstr),
|
if (!chars) {
|
||||||
PR_FALSE);
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
textContent->SetText(chars, length, PR_FALSE);
|
||||||
|
|
||||||
result = AppendChildTo(textContent, PR_FALSE);
|
result = AppendChildTo(textContent, PR_FALSE);
|
||||||
if (NS_FAILED(result)) {
|
if (NS_FAILED(result)) {
|
||||||
|
@ -429,9 +432,14 @@ nsHTMLOptionElement::Initialize(nsISupports* aOwner,
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t length;
|
||||||
|
const jschar *chars = JS_GetStringCharsAndLength(aContext, jsstr, &length);
|
||||||
|
if (!chars) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
// Set the value attribute for this element
|
// Set the value attribute for this element
|
||||||
nsAutoString value(reinterpret_cast<const PRUnichar*>
|
nsAutoString value(chars, length);
|
||||||
(JS_GetStringChars(jsstr)));
|
|
||||||
|
|
||||||
result = SetAttr(kNameSpaceID_None, nsGkAtoms::value, value,
|
result = SetAttr(kNameSpaceID_None, nsGkAtoms::value, value,
|
||||||
PR_FALSE);
|
PR_FALSE);
|
||||||
|
|
|
@ -1094,16 +1094,22 @@ nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocumen
|
||||||
nsCxPusher pusher;
|
nsCxPusher pusher;
|
||||||
pusher.Push(cx);
|
pusher.Push(cx);
|
||||||
|
|
||||||
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
|
nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
|
||||||
jsval v;
|
nsIXPConnect *xpc = nsContentUtils::XPConnect();
|
||||||
nsresult rv =
|
nsresult rv =
|
||||||
nsContentUtils::WrapNative(cx, scope, mBoundElement, &v,
|
xpc->GetWrappedNativeOfNativeObject(cx, scope, mBoundElement,
|
||||||
|
NS_GET_IID(nsISupports),
|
||||||
getter_AddRefs(wrapper));
|
getter_AddRefs(wrapper));
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
JSObject* scriptObject = JSVAL_TO_OBJECT(v);
|
JSObject* scriptObject;
|
||||||
|
if (wrapper)
|
||||||
|
wrapper->GetJSObject(&scriptObject);
|
||||||
|
else
|
||||||
|
scriptObject = nsnull;
|
||||||
|
|
||||||
|
if (scriptObject) {
|
||||||
// XXX Stay in sync! What if a layered binding has an
|
// XXX Stay in sync! What if a layered binding has an
|
||||||
// <interface>?!
|
// <interface>?!
|
||||||
// XXXbz what does that comment mean, really? It seems to date
|
// XXXbz what does that comment mean, really? It seems to date
|
||||||
|
@ -1169,6 +1175,7 @@ nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocumen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Remove our event handlers
|
// Remove our event handlers
|
||||||
UnhookEventHandlers();
|
UnhookEventHandlers();
|
||||||
|
|
|
@ -89,6 +89,11 @@ CPPSRCS += txMozillaStylesheetCompiler.cpp \
|
||||||
txMozillaXSLTProcessor.cpp
|
txMozillaXSLTProcessor.cpp
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# For nsDependentJSString
|
||||||
|
LOCAL_INCLUDES += \
|
||||||
|
-I$(topsrcdir)/dom/base \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
# we don't want the shared lib, but we want to force the creation of a
|
# we don't want the shared lib, but we want to force the creation of a
|
||||||
# static lib.
|
# static lib.
|
||||||
FORCE_STATIC_LIB = 1
|
FORCE_STATIC_LIB = 1
|
||||||
|
|
|
@ -67,6 +67,7 @@
|
||||||
#include "txExprParser.h"
|
#include "txExprParser.h"
|
||||||
#include "nsIErrorService.h"
|
#include "nsIErrorService.h"
|
||||||
#include "nsIScriptSecurityManager.h"
|
#include "nsIScriptSecurityManager.h"
|
||||||
|
#include "nsJSUtils.h"
|
||||||
|
|
||||||
using namespace mozilla::dom;
|
using namespace mozilla::dom;
|
||||||
|
|
||||||
|
@ -1469,10 +1470,8 @@ txVariable::Convert(nsIVariant *aValue, txAExprResult** aResult)
|
||||||
JSString *str = JS_ValueToString(cx, OBJECT_TO_JSVAL(jsobj));
|
JSString *str = JS_ValueToString(cx, OBJECT_TO_JSVAL(jsobj));
|
||||||
NS_ENSURE_TRUE(str, NS_ERROR_FAILURE);
|
NS_ENSURE_TRUE(str, NS_ERROR_FAILURE);
|
||||||
|
|
||||||
const PRUnichar *strChars =
|
nsDependentJSString value;
|
||||||
reinterpret_cast<const PRUnichar*>
|
NS_ENSURE_TRUE(value.init(cx, str), NS_ERROR_FAILURE);
|
||||||
(::JS_GetStringChars(str));
|
|
||||||
nsDependentString value(strChars, ::JS_GetStringLength(str));
|
|
||||||
|
|
||||||
*aResult = new StringResult(value, nsnull);
|
*aResult = new StringResult(value, nsnull);
|
||||||
if (!*aResult) {
|
if (!*aResult) {
|
||||||
|
|
|
@ -5086,7 +5086,6 @@ nsWindowSH::GlobalScopePolluterNewResolve(JSContext *cx, JSObject *obj,
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject *proto = ::JS_GetPrototype(cx, obj);
|
JSObject *proto = ::JS_GetPrototype(cx, obj);
|
||||||
JSString *jsstr = JSID_TO_STRING(id);
|
|
||||||
JSBool hasProp;
|
JSBool hasProp;
|
||||||
|
|
||||||
if (!proto || !::JS_HasPropertyById(cx, proto, id, &hasProp) ||
|
if (!proto || !::JS_HasPropertyById(cx, proto, id, &hasProp) ||
|
||||||
|
@ -5097,7 +5096,7 @@ nsWindowSH::GlobalScopePolluterNewResolve(JSContext *cx, JSObject *obj,
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsDependentJSString str(jsstr);
|
nsDependentJSString str(id);
|
||||||
nsCOMPtr<nsISupports> result;
|
nsCOMPtr<nsISupports> result;
|
||||||
nsWrapperCache *cache;
|
nsWrapperCache *cache;
|
||||||
{
|
{
|
||||||
|
@ -5436,7 +5435,10 @@ nsWindowSH::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||||
vp, getter_AddRefs(holder));
|
vp, getter_AddRefs(holder));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
rv = location->SetHref(nsDependentJSString(val));
|
nsDependentJSString depStr;
|
||||||
|
NS_ENSURE_TRUE(depStr.init(cx, val), NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
|
rv = location->SetHref(depStr);
|
||||||
|
|
||||||
return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
|
return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
|
||||||
}
|
}
|
||||||
|
@ -6291,14 +6293,14 @@ ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx,
|
||||||
// static
|
// static
|
||||||
nsresult
|
nsresult
|
||||||
nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
|
nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
|
||||||
JSObject *obj, JSString *str, PRBool *did_resolve)
|
JSObject *obj, jsid id, PRBool *did_resolve)
|
||||||
{
|
{
|
||||||
*did_resolve = PR_FALSE;
|
*did_resolve = PR_FALSE;
|
||||||
|
|
||||||
nsScriptNameSpaceManager *nameSpaceManager = nsJSRuntime::GetNameSpaceManager();
|
nsScriptNameSpaceManager *nameSpaceManager = nsJSRuntime::GetNameSpaceManager();
|
||||||
NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
|
NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
|
||||||
|
|
||||||
nsDependentJSString name(str);
|
nsDependentJSString name(id);
|
||||||
|
|
||||||
const nsGlobalNameStruct *name_struct = nsnull;
|
const nsGlobalNameStruct *name_struct = nsnull;
|
||||||
const PRUnichar *class_name = nsnull;
|
const PRUnichar *class_name = nsnull;
|
||||||
|
@ -6515,9 +6517,7 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
|
||||||
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
JSBool ok = ::JS_DefineUCProperty(cx, obj, ::JS_GetStringChars(str),
|
JSBool ok = ::JS_DefinePropertyById(cx, obj, id, prop_val, nsnull, nsnull,
|
||||||
::JS_GetStringLength(str),
|
|
||||||
prop_val, nsnull, nsnull,
|
|
||||||
JSPROP_ENUMERATE);
|
JSPROP_ENUMERATE);
|
||||||
|
|
||||||
*did_resolve = PR_TRUE;
|
*did_resolve = PR_TRUE;
|
||||||
|
@ -6677,8 +6677,6 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||||
// method on an interface that would let us just call into the
|
// method on an interface that would let us just call into the
|
||||||
// window code directly...
|
// window code directly...
|
||||||
|
|
||||||
JSString *str = JSID_TO_STRING(id);
|
|
||||||
|
|
||||||
if (!xpc::WrapperFactory::IsXrayWrapper(obj) ||
|
if (!xpc::WrapperFactory::IsXrayWrapper(obj) ||
|
||||||
xpc::WrapperFactory::IsPartiallyTransparent(obj)) {
|
xpc::WrapperFactory::IsPartiallyTransparent(obj)) {
|
||||||
nsCOMPtr<nsIDocShellTreeNode> dsn(do_QueryInterface(win->GetDocShell()));
|
nsCOMPtr<nsIDocShellTreeNode> dsn(do_QueryInterface(win->GetDocShell()));
|
||||||
|
@ -6692,7 +6690,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
nsCOMPtr<nsIDocShellTreeItem> child;
|
nsCOMPtr<nsIDocShellTreeItem> child;
|
||||||
|
|
||||||
const jschar *chars = ::JS_GetStringChars(str);
|
const jschar *chars = ::JS_GetInternedStringChars(JSID_TO_STRING(id));
|
||||||
|
|
||||||
dsn->FindChildWithName(reinterpret_cast<const PRUnichar*>(chars),
|
dsn->FindChildWithName(reinterpret_cast<const PRUnichar*>(chars),
|
||||||
PR_FALSE, PR_TRUE, nsnull, nsnull,
|
PR_FALSE, PR_TRUE, nsnull, nsnull,
|
||||||
|
@ -6741,7 +6739,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||||
// which have been registered with the script namespace manager.
|
// which have been registered with the script namespace manager.
|
||||||
|
|
||||||
JSBool did_resolve = JS_FALSE;
|
JSBool did_resolve = JS_FALSE;
|
||||||
rv = GlobalResolve(win, cx, obj, str, &did_resolve);
|
rv = GlobalResolve(win, cx, obj, id, &did_resolve);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
if (did_resolve) {
|
if (did_resolve) {
|
||||||
|
@ -8414,7 +8412,10 @@ nsDocumentSH::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||||
JSString *val = ::JS_ValueToString(cx, *vp);
|
JSString *val = ::JS_ValueToString(cx, *vp);
|
||||||
NS_ENSURE_TRUE(val, NS_ERROR_UNEXPECTED);
|
NS_ENSURE_TRUE(val, NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
rv = location->SetHref(nsDependentJSString(val));
|
nsDependentJSString depStr;
|
||||||
|
NS_ENSURE_TRUE(depStr.init(cx, val), NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
|
rv = location->SetHref(depStr);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
|
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
|
||||||
|
@ -8503,7 +8504,10 @@ ResolveImpl(JSContext *cx, nsIXPConnectWrappedNative *wrapper, jsid id,
|
||||||
JSString *str = IdToString(cx, id);
|
JSString *str = IdToString(cx, id);
|
||||||
NS_ENSURE_TRUE(str, NS_ERROR_UNEXPECTED);
|
NS_ENSURE_TRUE(str, NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
return doc->ResolveName(nsDependentJSString(str), nsnull, result, aCache);
|
nsDependentJSString depStr;
|
||||||
|
NS_ENSURE_TRUE(depStr.init(cx, str), NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
|
return doc->ResolveName(depStr, nsnull, result, aCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
@ -8541,8 +8545,13 @@ nsHTMLDocumentSH::DocumentOpen(JSContext *cx, uintN argc, jsval *vp)
|
||||||
nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_OUT_OF_MEMORY);
|
nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_OUT_OF_MEMORY);
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
nsDependentJSString depStr;
|
||||||
|
if (!depStr.init(cx, jsstr)) {
|
||||||
|
nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_OUT_OF_MEMORY);
|
||||||
|
return JS_FALSE;
|
||||||
|
}
|
||||||
nsAutoString type;
|
nsAutoString type;
|
||||||
type.Assign(nsDependentJSString(jsstr));
|
type.Assign(depStr);
|
||||||
ToLowerCase(type);
|
ToLowerCase(type);
|
||||||
nsCAutoString actualType, dummy;
|
nsCAutoString actualType, dummy;
|
||||||
NS_ParseContentType(NS_ConvertUTF16toUTF8(type), actualType, dummy);
|
NS_ParseContentType(NS_ConvertUTF16toUTF8(type), actualType, dummy);
|
||||||
|
@ -8560,9 +8569,13 @@ nsHTMLDocumentSH::DocumentOpen(JSContext *cx, uintN argc, jsval *vp)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
replace = NS_LITERAL_STRING("replace").
|
const jschar *chars = ::JS_GetStringCharsZ(cx, jsstr);
|
||||||
Equals(reinterpret_cast<const PRUnichar*>
|
if (!chars) {
|
||||||
(::JS_GetStringChars(jsstr)));
|
nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_OUT_OF_MEMORY);
|
||||||
|
return JS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
replace = NS_LITERAL_STRING("replace").Equals(chars);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMDocument> retval;
|
nsCOMPtr<nsIDOMDocument> retval;
|
||||||
|
@ -8883,8 +8896,13 @@ nsHTMLDocumentSH::CallToGetPropMapper(JSContext *cx, uintN argc, jsval *vp)
|
||||||
self = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));
|
self = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));
|
||||||
}
|
}
|
||||||
|
|
||||||
return ::JS_GetUCProperty(cx, self, ::JS_GetStringChars(str),
|
size_t length;
|
||||||
::JS_GetStringLength(str), vp);
|
const jschar *chars = ::JS_GetStringCharsAndLength(cx, str, &length);
|
||||||
|
if (!chars) {
|
||||||
|
return JS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ::JS_GetUCProperty(cx, self, chars, length, vp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -9004,8 +9022,6 @@ nsHTMLDocumentSH::DocumentAllTagsNewResolve(JSContext *cx, JSObject *obj,
|
||||||
if (JSID_IS_STRING(id)) {
|
if (JSID_IS_STRING(id)) {
|
||||||
nsDocument *doc = GetDocument(cx, obj);
|
nsDocument *doc = GetDocument(cx, obj);
|
||||||
|
|
||||||
JSString *str = JSID_TO_STRING(id);
|
|
||||||
|
|
||||||
JSObject *proto = ::JS_GetPrototype(cx, obj);
|
JSObject *proto = ::JS_GetPrototype(cx, obj);
|
||||||
if (NS_UNLIKELY(!proto)) {
|
if (NS_UNLIKELY(!proto)) {
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
|
@ -9021,7 +9037,7 @@ nsHTMLDocumentSH::DocumentAllTagsNewResolve(JSContext *cx, JSObject *obj,
|
||||||
}
|
}
|
||||||
|
|
||||||
nsRefPtr<nsContentList> tags =
|
nsRefPtr<nsContentList> tags =
|
||||||
doc->GetElementsByTagName(nsDependentJSString(str));
|
doc->GetElementsByTagName(nsDependentJSString(id));
|
||||||
|
|
||||||
if (tags) {
|
if (tags) {
|
||||||
jsval v;
|
jsval v;
|
||||||
|
@ -9193,11 +9209,11 @@ nsHTMLDocumentSH::GetProperty(nsIXPConnectWrappedNative *wrapper,
|
||||||
|
|
||||||
// static
|
// static
|
||||||
nsresult
|
nsresult
|
||||||
nsHTMLFormElementSH::FindNamedItem(nsIForm *aForm, JSString *str,
|
nsHTMLFormElementSH::FindNamedItem(nsIForm *aForm, jsid id,
|
||||||
nsISupports **aResult,
|
nsISupports **aResult,
|
||||||
nsWrapperCache **aCache)
|
nsWrapperCache **aCache)
|
||||||
{
|
{
|
||||||
nsDependentJSString name(str);
|
nsDependentJSString name(id);
|
||||||
|
|
||||||
*aResult = aForm->ResolveName(name).get();
|
*aResult = aForm->ResolveName(name).get();
|
||||||
// FIXME Get the wrapper cache from nsIForm::ResolveName
|
// FIXME Get the wrapper cache from nsIForm::ResolveName
|
||||||
|
@ -9231,8 +9247,7 @@ nsHTMLFormElementSH::NewResolve(nsIXPConnectWrappedNative *wrapper,
|
||||||
nsCOMPtr<nsISupports> result;
|
nsCOMPtr<nsISupports> result;
|
||||||
nsWrapperCache *cache;
|
nsWrapperCache *cache;
|
||||||
|
|
||||||
JSString *str = JSID_TO_STRING(id);
|
FindNamedItem(form, id, getter_AddRefs(result), &cache);
|
||||||
FindNamedItem(form, str, getter_AddRefs(result), &cache);
|
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
JSAutoRequest ar(cx);
|
JSAutoRequest ar(cx);
|
||||||
|
@ -9262,8 +9277,7 @@ nsHTMLFormElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper,
|
||||||
nsCOMPtr<nsISupports> result;
|
nsCOMPtr<nsISupports> result;
|
||||||
nsWrapperCache *cache;
|
nsWrapperCache *cache;
|
||||||
|
|
||||||
JSString *str = JSID_TO_STRING(id);
|
FindNamedItem(form, id, getter_AddRefs(result), &cache);
|
||||||
FindNamedItem(form, str, getter_AddRefs(result), &cache);
|
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
// Wrap result, result can be either an element or a list of
|
// Wrap result, result can be either an element or a list of
|
||||||
|
@ -10207,11 +10221,14 @@ nsStorageSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||||
if (!jsstr)
|
if (!jsstr)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
|
nsDependentJSString depStr;
|
||||||
|
if (!depStr.init(cx, jsstr))
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
// GetItem() will return null if the caller can't access the session
|
// GetItem() will return null if the caller can't access the session
|
||||||
// storage item.
|
// storage item.
|
||||||
nsCOMPtr<nsIDOMStorageItem> item;
|
nsCOMPtr<nsIDOMStorageItem> item;
|
||||||
nsresult rv = storage->GetItem(nsDependentJSString(jsstr),
|
nsresult rv = storage->GetItem(depStr, getter_AddRefs(item));
|
||||||
getter_AddRefs(item));
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
if (item) {
|
if (item) {
|
||||||
|
@ -10246,11 +10263,16 @@ nsStorageSH::SetProperty(nsIXPConnectWrappedNative *wrapper,
|
||||||
JSString *key = IdToString(cx, id);
|
JSString *key = IdToString(cx, id);
|
||||||
NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED);
|
NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
|
nsDependentJSString keyStr;
|
||||||
|
NS_ENSURE_TRUE(keyStr.init(cx, key), NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
JSString *value = ::JS_ValueToString(cx, *vp);
|
JSString *value = ::JS_ValueToString(cx, *vp);
|
||||||
NS_ENSURE_TRUE(value, NS_ERROR_UNEXPECTED);
|
NS_ENSURE_TRUE(value, NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
nsresult rv = storage->SetItem(nsDependentJSString(key),
|
nsDependentJSString valueStr;
|
||||||
nsDependentJSString(value));
|
NS_ENSURE_TRUE(valueStr.init(cx, value), NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
|
nsresult rv = storage->SetItem(keyStr, valueStr);
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
rv = NS_SUCCESS_I_DID_SOMETHING;
|
rv = NS_SUCCESS_I_DID_SOMETHING;
|
||||||
}
|
}
|
||||||
|
@ -10269,7 +10291,10 @@ nsStorageSH::DelProperty(nsIXPConnectWrappedNative *wrapper,
|
||||||
JSString *key = IdToString(cx, id);
|
JSString *key = IdToString(cx, id);
|
||||||
NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED);
|
NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
nsresult rv = storage->RemoveItem(nsDependentJSString(key));
|
nsDependentJSString keyStr;
|
||||||
|
NS_ENSURE_TRUE(keyStr.init(cx, key), NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
|
nsresult rv = storage->RemoveItem(keyStr);
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
rv = NS_SUCCESS_I_DID_SOMETHING;
|
rv = NS_SUCCESS_I_DID_SOMETHING;
|
||||||
}
|
}
|
||||||
|
@ -10368,10 +10393,13 @@ nsStorage2SH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMStorage> storage(do_QueryWrappedNative(wrapper));
|
nsCOMPtr<nsIDOMStorage> storage(do_QueryWrappedNative(wrapper));
|
||||||
|
|
||||||
|
nsDependentJSString depStr;
|
||||||
|
NS_ENSURE_TRUE(depStr.init(cx, jsstr), NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
// GetItem() will return null if the caller can't access the session
|
// GetItem() will return null if the caller can't access the session
|
||||||
// storage item.
|
// storage item.
|
||||||
nsAutoString data;
|
nsAutoString data;
|
||||||
nsresult rv = storage->GetItem(nsDependentJSString(jsstr), data);
|
nsresult rv = storage->GetItem(depStr, data);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
if (!DOMStringIsNull(data)) {
|
if (!DOMStringIsNull(data)) {
|
||||||
|
@ -10440,11 +10468,16 @@ nsStorage2SH::SetProperty(nsIXPConnectWrappedNative *wrapper,
|
||||||
JSString *key = IdToString(cx, id);
|
JSString *key = IdToString(cx, id);
|
||||||
NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED);
|
NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
|
nsDependentJSString keyStr;
|
||||||
|
NS_ENSURE_TRUE(keyStr.init(cx, key), NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
JSString *value = ::JS_ValueToString(cx, *vp);
|
JSString *value = ::JS_ValueToString(cx, *vp);
|
||||||
NS_ENSURE_TRUE(value, NS_ERROR_UNEXPECTED);
|
NS_ENSURE_TRUE(value, NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
nsresult rv = storage->SetItem(nsDependentJSString(key),
|
nsDependentJSString valueStr;
|
||||||
nsDependentJSString(value));
|
NS_ENSURE_TRUE(valueStr.init(cx, value), NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
|
nsresult rv = storage->SetItem(keyStr, valueStr);
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
rv = NS_SUCCESS_I_DID_SOMETHING;
|
rv = NS_SUCCESS_I_DID_SOMETHING;
|
||||||
}
|
}
|
||||||
|
@ -10463,7 +10496,10 @@ nsStorage2SH::DelProperty(nsIXPConnectWrappedNative *wrapper,
|
||||||
JSString *key = IdToString(cx, id);
|
JSString *key = IdToString(cx, id);
|
||||||
NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED);
|
NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
nsresult rv = storage->RemoveItem(nsDependentJSString(key));
|
nsDependentJSString keyStr;
|
||||||
|
NS_ENSURE_TRUE(keyStr.init(cx, key), NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
|
nsresult rv = storage->RemoveItem(keyStr);
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
rv = NS_SUCCESS_I_DID_SOMETHING;
|
rv = NS_SUCCESS_I_DID_SOMETHING;
|
||||||
}
|
}
|
||||||
|
|
|
@ -463,7 +463,7 @@ protected:
|
||||||
{
|
{
|
||||||
NS_ASSERTION(JSID_IS_STRING(id), "Don't pass non-string jsid's here!");
|
NS_ASSERTION(JSID_IS_STRING(id), "Don't pass non-string jsid's here!");
|
||||||
|
|
||||||
jschar *str = ::JS_GetStringChars(JSID_TO_STRING(id));
|
const jschar *str = ::JS_GetInternedStringChars(JSID_TO_STRING(id));
|
||||||
|
|
||||||
if (str[0] == 'o' && str[1] == 'n') {
|
if (str[0] == 'o' && str[1] == 'n') {
|
||||||
return ReallyIsEventName(id, str[2]);
|
return ReallyIsEventName(id, str[2]);
|
||||||
|
@ -528,8 +528,7 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
static nsresult GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
|
static nsresult GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
|
||||||
JSObject *obj, JSString *str,
|
JSObject *obj, jsid id, PRBool *did_resolve);
|
||||||
PRBool *did_resolve);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
|
NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
|
||||||
|
@ -1046,7 +1045,7 @@ protected:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static nsresult FindNamedItem(nsIForm *aForm, JSString *str,
|
static nsresult FindNamedItem(nsIForm *aForm, jsid id,
|
||||||
nsISupports **aResult, nsWrapperCache **aCache);
|
nsISupports **aResult, nsWrapperCache **aCache);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -724,8 +724,13 @@ static JSBool
|
||||||
ChangeCase(JSContext *cx, JSString *src, jsval *rval,
|
ChangeCase(JSContext *cx, JSString *src, jsval *rval,
|
||||||
void(* changeCaseFnc)(const nsAString&, nsAString&))
|
void(* changeCaseFnc)(const nsAString&, nsAString&))
|
||||||
{
|
{
|
||||||
|
nsDependentJSString depStr;
|
||||||
|
if (!depStr.init(cx, src)) {
|
||||||
|
return JS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
nsAutoString result;
|
nsAutoString result;
|
||||||
changeCaseFnc(nsDependentJSString(src), result);
|
changeCaseFnc(depStr, result);
|
||||||
|
|
||||||
JSString *ucstr = JS_NewUCStringCopyN(cx, (jschar*)result.get(), result.Length());
|
JSString *ucstr = JS_NewUCStringCopyN(cx, (jschar*)result.get(), result.Length());
|
||||||
if (!ucstr) {
|
if (!ucstr) {
|
||||||
|
@ -779,11 +784,14 @@ LocaleCompare(JSContext *cx, JSString *src1, JSString *src2, jsval *rval)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsDependentJSString depStr1, depStr2;
|
||||||
|
if (!depStr1.init(cx, src1) || !depStr2.init(cx, src2)) {
|
||||||
|
return JS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
PRInt32 result;
|
PRInt32 result;
|
||||||
rv = gCollation->CompareString(nsICollation::kCollationStrengthDefault,
|
rv = gCollation->CompareString(nsICollation::kCollationStrengthDefault,
|
||||||
nsDependentJSString(src1),
|
depStr1, depStr2, &result);
|
||||||
nsDependentJSString(src2),
|
|
||||||
&result);
|
|
||||||
|
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
nsDOMClassInfo::ThrowJSException(cx, rv);
|
nsDOMClassInfo::ThrowJSException(cx, rv);
|
||||||
|
@ -1591,28 +1599,37 @@ JSValueToAString(JSContext *cx, jsval val, nsAString *result,
|
||||||
}
|
}
|
||||||
|
|
||||||
JSString* jsstring = ::JS_ValueToString(cx, val);
|
JSString* jsstring = ::JS_ValueToString(cx, val);
|
||||||
if (jsstring) {
|
if (!jsstring) {
|
||||||
result->Assign(reinterpret_cast<const PRUnichar*>
|
goto error;
|
||||||
(::JS_GetStringChars(jsstring)),
|
}
|
||||||
::JS_GetStringLength(jsstring));
|
|
||||||
} else {
|
|
||||||
result->Truncate();
|
|
||||||
|
|
||||||
|
size_t length;
|
||||||
|
const jschar *chars;
|
||||||
|
chars = ::JS_GetStringCharsAndLength(cx, jsstring, &length);
|
||||||
|
if (!chars) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
result->Assign(chars, length);
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
error:
|
||||||
// We failed to convert val to a string. We're either OOM, or the
|
// We failed to convert val to a string. We're either OOM, or the
|
||||||
// security manager denied access to .toString(), or somesuch, on
|
// security manager denied access to .toString(), or somesuch, on
|
||||||
// an object. Treat this case as if the result were undefined.
|
// an object. Treat this case as if the result were undefined.
|
||||||
|
|
||||||
|
result->Truncate();
|
||||||
|
|
||||||
if (isUndefined) {
|
if (isUndefined) {
|
||||||
*isUndefined = PR_TRUE;
|
*isUndefined = PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!::JS_IsExceptionPending(cx)) {
|
if (!::JS_IsExceptionPending(cx)) {
|
||||||
// JS_ValueToString() returned null w/o an exception
|
// JS_ValueToString()/JS_GetStringCharsAndLength returned null w/o an
|
||||||
// pending. That means we're OOM.
|
// exception pending. That means we're OOM.
|
||||||
|
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,7 +109,7 @@ private:
|
||||||
nsCOMPtr<nsIArray> mArgv;
|
nsCOMPtr<nsIArray> mArgv;
|
||||||
|
|
||||||
// The JS expression to evaluate or function to call, if !mExpr
|
// The JS expression to evaluate or function to call, if !mExpr
|
||||||
JSString *mExpr;
|
JSFlatString *mExpr;
|
||||||
JSObject *mFunObj;
|
JSObject *mFunObj;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -134,10 +134,10 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsJSScriptTimeoutHandler)
|
||||||
else if (tmp->mFunObj) {
|
else if (tmp->mFunObj) {
|
||||||
JSFunction* fun = (JSFunction*)tmp->mFunObj->getPrivate();
|
JSFunction* fun = (JSFunction*)tmp->mFunObj->getPrivate();
|
||||||
if (fun->atom) {
|
if (fun->atom) {
|
||||||
size_t size = 1 + JS_PutEscapedString(NULL, 0, ATOM_TO_STRING(fun->atom), 0);
|
size_t size = 1 + JS_PutEscapedFlatString(NULL, 0, ATOM_TO_STRING(fun->atom), 0);
|
||||||
char *name = new char[size];
|
char *name = new char[size];
|
||||||
if (name) {
|
if (name) {
|
||||||
JS_PutEscapedString(name, size, ATOM_TO_STRING(fun->atom), 0);
|
JS_PutEscapedFlatString(name, size, ATOM_TO_STRING(fun->atom), 0);
|
||||||
foo.AppendLiteral(" [");
|
foo.AppendLiteral(" [");
|
||||||
foo.Append(name);
|
foo.Append(name);
|
||||||
delete[] name;
|
delete[] name;
|
||||||
|
@ -232,7 +232,7 @@ nsJSScriptTimeoutHandler::Init(nsGlobalWindow *aWindow, PRBool *aIsInterval,
|
||||||
ncc->GetArgc(&argc);
|
ncc->GetArgc(&argc);
|
||||||
ncc->GetArgvPtr(&argv);
|
ncc->GetArgvPtr(&argv);
|
||||||
|
|
||||||
JSString *expr = nsnull;
|
JSFlatString *expr = nsnull;
|
||||||
JSObject *funobj = nsnull;
|
JSObject *funobj = nsnull;
|
||||||
int32 interval = 0;
|
int32 interval = 0;
|
||||||
|
|
||||||
|
@ -264,10 +264,17 @@ nsJSScriptTimeoutHandler::Init(nsGlobalWindow *aWindow, PRBool *aIsInterval,
|
||||||
|
|
||||||
case JSTYPE_STRING:
|
case JSTYPE_STRING:
|
||||||
case JSTYPE_OBJECT:
|
case JSTYPE_OBJECT:
|
||||||
expr = ::JS_ValueToString(cx, argv[0]);
|
{
|
||||||
|
JSString *str = ::JS_ValueToString(cx, argv[0]);
|
||||||
|
if (!str)
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
expr = ::JS_FlattenString(cx, str);
|
||||||
if (!expr)
|
if (!expr)
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
argv[0] = STRING_TO_JSVAL(expr);
|
|
||||||
|
argv[0] = STRING_TO_JSVAL(str);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -370,8 +377,7 @@ const PRUnichar *
|
||||||
nsJSScriptTimeoutHandler::GetHandlerText()
|
nsJSScriptTimeoutHandler::GetHandlerText()
|
||||||
{
|
{
|
||||||
NS_ASSERTION(mExpr, "No expression, so no handler text!");
|
NS_ASSERTION(mExpr, "No expression, so no handler text!");
|
||||||
return reinterpret_cast<const PRUnichar *>
|
return ::JS_GetFlatStringChars(mExpr);
|
||||||
(::JS_GetStringChars(mExpr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult NS_CreateJSTimeoutHandler(nsGlobalWindow *aWindow,
|
nsresult NS_CreateJSTimeoutHandler(nsGlobalWindow *aWindow,
|
||||||
|
|
|
@ -85,23 +85,44 @@ public:
|
||||||
class nsDependentJSString : public nsDependentString
|
class nsDependentJSString : public nsDependentString
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit nsDependentJSString(jsval v)
|
/**
|
||||||
: nsDependentString((PRUnichar *)::JS_GetStringChars(JSVAL_TO_STRING(v)),
|
* In the case of string ids, getting the string's chars is infallible, so
|
||||||
::JS_GetStringLength(JSVAL_TO_STRING(v)))
|
* the dependent string can be constructed directly.
|
||||||
{
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
explicit nsDependentJSString(jsid id)
|
explicit nsDependentJSString(jsid id)
|
||||||
: nsDependentString((PRUnichar *)::JS_GetStringChars(JSID_TO_STRING(id)),
|
: nsDependentString(JS_GetInternedStringChars(JSID_TO_STRING(id)),
|
||||||
::JS_GetStringLength(JSID_TO_STRING(id)))
|
JS_GetStringLength(JSID_TO_STRING(id)))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit nsDependentJSString(JSString *str)
|
/**
|
||||||
: nsDependentString((PRUnichar *)::JS_GetStringChars(str), ::JS_GetStringLength(str))
|
* For all other strings, the nsDependentJSString object should be default
|
||||||
|
* constructed, which leaves it empty (this->IsEmpty()), and initialized with
|
||||||
|
* one of the fallible init() methods below.
|
||||||
|
*/
|
||||||
|
|
||||||
|
nsDependentJSString()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JSBool init(JSContext* aContext, JSString* str)
|
||||||
|
{
|
||||||
|
size_t length;
|
||||||
|
const jschar* chars = JS_GetStringCharsZAndLength(aContext, str, &length);
|
||||||
|
if (!chars)
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
NS_ASSERTION(IsEmpty(), "init() on initialized string");
|
||||||
|
nsDependentString* base = this;
|
||||||
|
new(base) nsDependentString(chars, length);
|
||||||
|
return JS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSBool init(JSContext* aContext, const jsval &v)
|
||||||
|
{
|
||||||
|
return init(aContext, JSVAL_TO_STRING(v));
|
||||||
|
}
|
||||||
|
|
||||||
~nsDependentJSString()
|
~nsDependentJSString()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -447,7 +447,7 @@ IDBCursor::Continue(const jsval &aKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
Key key;
|
Key key;
|
||||||
nsresult rv = IDBObjectStore::GetKeyFromJSVal(aKey, key);
|
nsresult rv = IDBObjectStore::GetKeyFromJSVal(aKey, aCx, key);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
if (!key.IsUnset()) {
|
if (!key.IsUnset()) {
|
||||||
|
@ -555,7 +555,7 @@ IDBCursor::Update(const jsval& aValue,
|
||||||
NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||||
|
|
||||||
Key key;
|
Key key;
|
||||||
rv = IDBObjectStore::GetKeyFromJSVal(prop, key);
|
rv = IDBObjectStore::GetKeyFromJSVal(prop, aCx, key);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
|
@ -590,7 +590,12 @@ IDBDatabase::CreateObjectStore(const nsAString& aName,
|
||||||
NS_WARNING("JS_ValueToString failed!");
|
NS_WARNING("JS_ValueToString failed!");
|
||||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||||
}
|
}
|
||||||
keyPath = nsDependentJSString(str);
|
nsDependentJSString dependentKeyPath;
|
||||||
|
if (!dependentKeyPath.init(aCx, str)) {
|
||||||
|
NS_WARNING("Initializing keyPath failed!");
|
||||||
|
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||||
|
}
|
||||||
|
keyPath = dependentKeyPath;
|
||||||
}
|
}
|
||||||
else if (id == nsDOMClassInfo::sAutoIncrement_id) {
|
else if (id == nsDOMClassInfo::sAutoIncrement_id) {
|
||||||
JSBool boolVal;
|
JSBool boolVal;
|
||||||
|
|
|
@ -366,7 +366,7 @@ GetKeyFromObject(JSContext* aCx,
|
||||||
JSBool ok = JS_GetUCProperty(aCx, aObj, keyPathChars, keyPathLen, &key);
|
JSBool ok = JS_GetUCProperty(aCx, aObj, keyPathChars, keyPathLen, &key);
|
||||||
NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||||
|
|
||||||
nsresult rv = IDBObjectStore::GetKeyFromJSVal(key, aKey);
|
nsresult rv = IDBObjectStore::GetKeyFromJSVal(key, aCx, aKey);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -448,13 +448,18 @@ IDBObjectStore::GetKeyFromVariant(nsIVariant* aKeyVariant,
|
||||||
// static
|
// static
|
||||||
nsresult
|
nsresult
|
||||||
IDBObjectStore::GetKeyFromJSVal(jsval aKeyVal,
|
IDBObjectStore::GetKeyFromJSVal(jsval aKeyVal,
|
||||||
|
JSContext* aCx,
|
||||||
Key& aKey)
|
Key& aKey)
|
||||||
{
|
{
|
||||||
if (JSVAL_IS_VOID(aKeyVal)) {
|
if (JSVAL_IS_VOID(aKeyVal)) {
|
||||||
aKey = Key::UNSETKEY;
|
aKey = Key::UNSETKEY;
|
||||||
}
|
}
|
||||||
else if (JSVAL_IS_STRING(aKeyVal)) {
|
else if (JSVAL_IS_STRING(aKeyVal)) {
|
||||||
aKey = nsDependentJSString(aKeyVal);
|
nsDependentJSString depStr;
|
||||||
|
if (!depStr.init(aCx, JSVAL_TO_STRING(aKeyVal))) {
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
aKey = depStr;
|
||||||
}
|
}
|
||||||
else if (JSVAL_IS_INT(aKeyVal)) {
|
else if (JSVAL_IS_INT(aKeyVal)) {
|
||||||
aKey = JSVAL_TO_INT(aKeyVal);
|
aKey = JSVAL_TO_INT(aKeyVal);
|
||||||
|
@ -548,7 +553,7 @@ IDBObjectStore::GetKeyPathValueFromStructuredData(const PRUint8* aData,
|
||||||
JSBool ok = JS_GetUCProperty(cx, obj, keyPathChars, keyPathLen, &keyVal);
|
JSBool ok = JS_GetUCProperty(cx, obj, keyPathChars, keyPathLen, &keyVal);
|
||||||
NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||||
|
|
||||||
rv = GetKeyFromJSVal(keyVal, aValue);
|
rv = GetKeyFromJSVal(keyVal, *aCx, aValue);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
// If the object doesn't have a value that we can use for our index then we
|
// If the object doesn't have a value that we can use for our index then we
|
||||||
// leave it unset.
|
// leave it unset.
|
||||||
|
@ -589,7 +594,7 @@ IDBObjectStore::GetIndexUpdateInfo(ObjectStoreInfo* aObjectStoreInfo,
|
||||||
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
|
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
|
||||||
|
|
||||||
Key value;
|
Key value;
|
||||||
nsresult rv = GetKeyFromJSVal(keyPathValue, value);
|
nsresult rv = GetKeyFromJSVal(keyPathValue, aCx, value);
|
||||||
if (NS_FAILED(rv) || value.IsUnset()) {
|
if (NS_FAILED(rv) || value.IsUnset()) {
|
||||||
// Not a value we can do anything with, ignore it.
|
// Not a value we can do anything with, ignore it.
|
||||||
continue;
|
continue;
|
||||||
|
@ -819,7 +824,7 @@ IDBObjectStore::GetAddInfo(JSContext* aCx,
|
||||||
|
|
||||||
if (mKeyPath.IsEmpty()) {
|
if (mKeyPath.IsEmpty()) {
|
||||||
// Out-of-line keys must be passed in.
|
// Out-of-line keys must be passed in.
|
||||||
rv = GetKeyFromJSVal(aKeyVal, aKey);
|
rv = GetKeyFromJSVal(aKeyVal, aCx, aKey);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1140,7 +1145,7 @@ IDBObjectStore::Delete(const jsval& aKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
Key key;
|
Key key;
|
||||||
nsresult rv = GetKeyFromJSVal(aKey, key);
|
nsresult rv = GetKeyFromJSVal(aKey, aCx, key);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,6 +78,7 @@ public:
|
||||||
|
|
||||||
static nsresult
|
static nsresult
|
||||||
GetKeyFromJSVal(jsval aKeyVal,
|
GetKeyFromJSVal(jsval aKeyVal,
|
||||||
|
JSContext* aCx,
|
||||||
Key& aKey);
|
Key& aKey);
|
||||||
|
|
||||||
static nsresult
|
static nsresult
|
||||||
|
|
|
@ -335,7 +335,14 @@ nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel,
|
||||||
|
|
||||||
if (!isUndefined && NS_SUCCEEDED(rv)) {
|
if (!isUndefined && NS_SUCCEEDED(rv)) {
|
||||||
NS_ASSERTION(JSVAL_IS_STRING(rval), "evalInSandbox is broken");
|
NS_ASSERTION(JSVAL_IS_STRING(rval), "evalInSandbox is broken");
|
||||||
result = nsDependentJSString(JSVAL_TO_STRING(rval));
|
|
||||||
|
nsDependentJSString depStr;
|
||||||
|
if (!depStr.init(cx, JSVAL_TO_STRING(rval))) {
|
||||||
|
JS_ReportPendingException(cx);
|
||||||
|
isUndefined = PR_TRUE;
|
||||||
|
} else {
|
||||||
|
result = depStr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stack->Pop(nsnull);
|
stack->Pop(nsnull);
|
||||||
|
|
|
@ -142,10 +142,12 @@ nsDOMWorkerFunctions::Dump(JSContext* aCx,
|
||||||
|
|
||||||
JSString* str;
|
JSString* str;
|
||||||
if (aArgc && (str = JS_ValueToString(aCx, JS_ARGV(aCx, aVp)[0])) && str) {
|
if (aArgc && (str = JS_ValueToString(aCx, JS_ARGV(aCx, aVp)[0])) && str) {
|
||||||
nsDependentJSString string(str);
|
nsDependentJSString depStr;
|
||||||
fputs(NS_ConvertUTF16toUTF8(nsDependentJSString(str)).get(), stderr);
|
if (depStr.init(aCx, str)) {
|
||||||
|
fputs(NS_ConvertUTF16toUTF8(depStr).get(), stderr);
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,7 +270,12 @@ nsDOMWorkerFunctions::LoadScripts(JSContext* aCx,
|
||||||
nsString* newURL = urls.AppendElement();
|
nsString* newURL = urls.AppendElement();
|
||||||
NS_ASSERTION(newURL, "Shouldn't fail if SetCapacity succeeded above!");
|
NS_ASSERTION(newURL, "Shouldn't fail if SetCapacity succeeded above!");
|
||||||
|
|
||||||
newURL->Assign(nsDependentJSString(str));
|
nsDependentJSString depStr;
|
||||||
|
if (!depStr.init(aCx, str)) {
|
||||||
|
return JS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
newURL->Assign(depStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsRefPtr<nsDOMWorkerScriptLoader> loader =
|
nsRefPtr<nsDOMWorkerScriptLoader> loader =
|
||||||
|
@ -507,8 +514,7 @@ nsDOMWorkerFunctions::CTypesLazyGetter(JSContext* aCx,
|
||||||
{
|
{
|
||||||
NS_ASSERTION(JS_GetGlobalForObject(aCx, aObj) == aObj, "Bad object!");
|
NS_ASSERTION(JS_GetGlobalForObject(aCx, aObj) == aObj, "Bad object!");
|
||||||
NS_ASSERTION(JSID_IS_STRING(aId), "Not a string!");
|
NS_ASSERTION(JSID_IS_STRING(aId), "Not a string!");
|
||||||
JSString* str = JSID_TO_STRING(aId);
|
NS_ASSERTION(nsDependentJSString(aId).EqualsLiteral("ctypes"), "Bad id!");
|
||||||
NS_ASSERTION(nsDependentJSString(str).EqualsLiteral("ctypes"), "Bad id!");
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
nsDOMWorker* worker = static_cast<nsDOMWorker*>(JS_GetContextPrivate(aCx));
|
nsDOMWorker* worker = static_cast<nsDOMWorker*>(JS_GetContextPrivate(aCx));
|
||||||
|
@ -674,14 +680,14 @@ nsDOMWorkerScope::AddProperty(nsIXPConnectWrappedNative* aWrapper,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSString *str = JSID_TO_STRING(aId);
|
JSFlatString *str = JSID_TO_FLAT_STRING(aId);
|
||||||
|
|
||||||
// Figure out which listener we're setting.
|
// Figure out which listener we're setting.
|
||||||
SetListenerFunc func;
|
SetListenerFunc func;
|
||||||
if (JS_MatchStringAndAscii(str, "onmessage")) {
|
if (JS_FlatStringEqualsAscii(str, "onmessage")) {
|
||||||
func = &nsDOMWorkerScope::SetOnmessage;
|
func = &nsDOMWorkerScope::SetOnmessage;
|
||||||
}
|
}
|
||||||
else if (JS_MatchStringAndAscii(str, "onerror")) {
|
else if (JS_FlatStringEqualsAscii(str, "onerror")) {
|
||||||
func = &nsDOMWorkerScope::SetOnerror;
|
func = &nsDOMWorkerScope::SetOnerror;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1302,7 +1308,10 @@ nsDOMWorker::InitializeInternal(nsIScriptGlobalObject* aOwner,
|
||||||
JSString* str = JS_ValueToString(aCx, aArgv[0]);
|
JSString* str = JS_ValueToString(aCx, aArgv[0]);
|
||||||
NS_ENSURE_TRUE(str, NS_ERROR_XPC_BAD_CONVERT_JS);
|
NS_ENSURE_TRUE(str, NS_ERROR_XPC_BAD_CONVERT_JS);
|
||||||
|
|
||||||
mScriptURL.Assign(nsDependentJSString(str));
|
nsDependentJSString depStr;
|
||||||
|
NS_ENSURE_TRUE(depStr.init(aCx, str), NS_ERROR_OUT_OF_MEMORY);
|
||||||
|
|
||||||
|
mScriptURL.Assign(depStr);
|
||||||
NS_ENSURE_FALSE(mScriptURL.IsEmpty(), NS_ERROR_INVALID_ARG);
|
NS_ENSURE_FALSE(mScriptURL.IsEmpty(), NS_ERROR_INVALID_ARG);
|
||||||
|
|
||||||
mLock = nsAutoLock::NewLock("nsDOMWorker::mLock");
|
mLock = nsAutoLock::NewLock("nsDOMWorker::mLock");
|
||||||
|
|
|
@ -196,11 +196,10 @@ nsDOMWorkerTimeout::ExpressionCallback::Run(nsDOMWorkerTimeout* aTimeout,
|
||||||
JSString* expression = JS_ValueToString(aCx, mExpression);
|
JSString* expression = JS_ValueToString(aCx, mExpression);
|
||||||
NS_ENSURE_TRUE(expression, NS_ERROR_FAILURE);
|
NS_ENSURE_TRUE(expression, NS_ERROR_FAILURE);
|
||||||
|
|
||||||
jschar* string = JS_GetStringChars(expression);
|
size_t stringLength;
|
||||||
|
const jschar* string = JS_GetStringCharsAndLength(aCx, expression, &stringLength);
|
||||||
NS_ENSURE_TRUE(string, NS_ERROR_FAILURE);
|
NS_ENSURE_TRUE(string, NS_ERROR_FAILURE);
|
||||||
|
|
||||||
size_t stringLength = JS_GetStringLength(expression);
|
|
||||||
|
|
||||||
jsval rval;
|
jsval rval;
|
||||||
PRBool success = JS_EvaluateUCScriptForPrincipals(aCx, global, principal,
|
PRBool success = JS_EvaluateUCScriptForPrincipals(aCx, global, principal,
|
||||||
string, stringLength,
|
string, stringLength,
|
||||||
|
|
|
@ -1253,10 +1253,13 @@ XPCShellEnvironment::EvaluateString(const nsString& aString,
|
||||||
if (ok && result != JSVAL_VOID) {
|
if (ok && result != JSVAL_VOID) {
|
||||||
JSErrorReporter old = JS_SetErrorReporter(mCx, NULL);
|
JSErrorReporter old = JS_SetErrorReporter(mCx, NULL);
|
||||||
JSString* str = JS_ValueToString(mCx, result);
|
JSString* str = JS_ValueToString(mCx, result);
|
||||||
|
nsDependentJSString depStr;
|
||||||
|
if (str)
|
||||||
|
depStr.init(mCx, str);
|
||||||
JS_SetErrorReporter(mCx, old);
|
JS_SetErrorReporter(mCx, old);
|
||||||
|
|
||||||
if (str && aResult) {
|
if (!depStr.IsEmpty() && aResult) {
|
||||||
aResult->Assign(nsDependentJSString(str));
|
aResult->Assign(depStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,11 @@ CPPSRCS = \
|
||||||
ObjectWrapperChild.cpp \
|
ObjectWrapperChild.cpp \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
|
# For nsDependentJSString
|
||||||
|
LOCAL_INCLUDES += \
|
||||||
|
-I$(topsrcdir)/dom/base \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
include $(topsrcdir)/config/config.mk
|
include $(topsrcdir)/config/config.mk
|
||||||
include $(topsrcdir)/ipc/chromium/chromium-config.mk
|
include $(topsrcdir)/ipc/chromium/chromium-config.mk
|
||||||
include $(topsrcdir)/config/rules.mk
|
include $(topsrcdir)/config/rules.mk
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
#include "nsTArray.h"
|
#include "nsTArray.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "nsIJSContextStack.h"
|
#include "nsIJSContextStack.h"
|
||||||
|
#include "nsJSUtils.h"
|
||||||
|
|
||||||
using namespace mozilla::jsipc;
|
using namespace mozilla::jsipc;
|
||||||
using namespace js;
|
using namespace js;
|
||||||
|
@ -188,8 +189,12 @@ ObjectWrapperChild::jsval_to_JSVariant(JSContext* cx, jsval from, JSVariant* to)
|
||||||
case JSTYPE_OBJECT:
|
case JSTYPE_OBJECT:
|
||||||
return JSObject_to_JSVariant(cx, JSVAL_TO_OBJECT(from), to);
|
return JSObject_to_JSVariant(cx, JSVAL_TO_OBJECT(from), to);
|
||||||
case JSTYPE_STRING:
|
case JSTYPE_STRING:
|
||||||
*to = nsDependentString((PRUnichar*)JS_GetStringChars(JSVAL_TO_STRING(from)),
|
{
|
||||||
JS_GetStringLength(JSVAL_TO_STRING(from)));
|
nsDependentJSString depStr;
|
||||||
|
if (!depStr.init(cx, from))
|
||||||
|
return false;
|
||||||
|
*to = depStr;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
case JSTYPE_NUMBER:
|
case JSTYPE_NUMBER:
|
||||||
if (JSVAL_IS_INT(from))
|
if (JSVAL_IS_INT(from))
|
||||||
|
@ -282,10 +287,10 @@ ObjectWrapperChild::Manager()
|
||||||
static bool
|
static bool
|
||||||
jsid_to_nsString(JSContext* cx, jsid from, nsString* to)
|
jsid_to_nsString(JSContext* cx, jsid from, nsString* to)
|
||||||
{
|
{
|
||||||
jsval v;
|
if (JSID_IS_STRING(from)) {
|
||||||
if (JS_IdToValue(cx, from, &v) && JSVAL_IS_STRING(v)) {
|
size_t length;
|
||||||
*to = nsDependentString((PRUnichar*)JS_GetStringChars(JSVAL_TO_STRING(v)),
|
const jschar* chars = JS_GetInternedStringCharsAndLength(JSID_TO_STRING(from), &length);
|
||||||
JS_GetStringLength(JSVAL_TO_STRING(v)));
|
*to = nsDependentString(chars, length);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#include "mozilla/jsipc/ContextWrapperParent.h"
|
#include "mozilla/jsipc/ContextWrapperParent.h"
|
||||||
#include "mozilla/jsipc/CPOWTypes.h"
|
#include "mozilla/jsipc/CPOWTypes.h"
|
||||||
#include "mozilla/unused.h"
|
#include "mozilla/unused.h"
|
||||||
|
#include "nsJSUtils.h"
|
||||||
|
|
||||||
#include "jsobj.h"
|
#include "jsobj.h"
|
||||||
#include "jsfun.h"
|
#include "jsfun.h"
|
||||||
|
@ -265,8 +266,12 @@ ObjectWrapperParent::jsval_to_JSVariant(JSContext* cx, jsval from,
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
case JSTYPE_STRING:
|
case JSTYPE_STRING:
|
||||||
*to = nsDependentString((PRUnichar*)JS_GetStringChars(JSVAL_TO_STRING(from)),
|
{
|
||||||
JS_GetStringLength(JSVAL_TO_STRING(from)));
|
nsDependentJSString depStr;
|
||||||
|
if (!depStr.init(cx, from))
|
||||||
|
return false;
|
||||||
|
*to = depStr;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
case JSTYPE_NUMBER:
|
case JSTYPE_NUMBER:
|
||||||
if (JSVAL_IS_INT(from))
|
if (JSVAL_IS_INT(from))
|
||||||
|
@ -379,10 +384,12 @@ static bool
|
||||||
jsval_to_nsString(JSContext* cx, jsid from, nsString* to)
|
jsval_to_nsString(JSContext* cx, jsid from, nsString* to)
|
||||||
{
|
{
|
||||||
JSString* str;
|
JSString* str;
|
||||||
|
const jschar* chars;
|
||||||
jsval idval;
|
jsval idval;
|
||||||
if (JS_IdToValue(cx, from, &idval) &&
|
if (JS_IdToValue(cx, from, &idval) &&
|
||||||
(str = JS_ValueToString(cx, idval))) {
|
(str = JS_ValueToString(cx, idval)) &&
|
||||||
*to = JS_GetStringChars(str);
|
(chars = JS_GetStringCharsZ(cx, str))) {
|
||||||
|
*to = chars;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -49,6 +49,8 @@
|
||||||
#include "mozilla/jetpack/PHandleChild.h"
|
#include "mozilla/jetpack/PHandleChild.h"
|
||||||
#include "mozilla/jetpack/Handle.h"
|
#include "mozilla/jetpack/Handle.h"
|
||||||
|
|
||||||
|
#include "nsJSUtils.h"
|
||||||
|
|
||||||
using mozilla::jetpack::JetpackActorCommon;
|
using mozilla::jetpack::JetpackActorCommon;
|
||||||
using mozilla::jetpack::PHandleParent;
|
using mozilla::jetpack::PHandleParent;
|
||||||
using mozilla::jetpack::HandleParent;
|
using mozilla::jetpack::HandleParent;
|
||||||
|
@ -138,8 +140,12 @@ JetpackActorCommon::jsval_to_PrimVariant(JSContext* cx, JSType type, jsval from,
|
||||||
}
|
}
|
||||||
|
|
||||||
case JSTYPE_STRING:
|
case JSTYPE_STRING:
|
||||||
*to = nsDependentString((PRUnichar*)JS_GetStringChars(JSVAL_TO_STRING(from)),
|
{
|
||||||
JS_GetStringLength(JSVAL_TO_STRING(from)));
|
nsDependentJSString depStr;
|
||||||
|
if (!depStr.init(cx, from))
|
||||||
|
return false;
|
||||||
|
*to = depStr;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case JSTYPE_NUMBER:
|
case JSTYPE_NUMBER:
|
||||||
|
@ -223,8 +229,10 @@ JetpackActorCommon::jsval_to_CompVariant(JSContext* cx, JSType type, jsval from,
|
||||||
KeyValue kv;
|
KeyValue kv;
|
||||||
// Silently drop properties that can't be converted.
|
// Silently drop properties that can't be converted.
|
||||||
if (jsval_to_Variant(cx, val, &kv.value(), seen)) {
|
if (jsval_to_Variant(cx, val, &kv.value(), seen)) {
|
||||||
kv.key() = nsDependentString((PRUnichar*)JS_GetStringChars(idStr),
|
nsDependentJSString depStr;
|
||||||
JS_GetStringLength(idStr));
|
if (!depStr.init(cx, idStr))
|
||||||
|
return false;
|
||||||
|
kv.key() = depStr;
|
||||||
// If AppendElement fails, we lose this property, no big deal.
|
// If AppendElement fails, we lose this property, no big deal.
|
||||||
kvs.AppendElement(kv);
|
kvs.AppendElement(kv);
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,7 +96,7 @@ static char*
|
||||||
UnicodeToNative(JSContext *cx, const jschar *source, size_t slen)
|
UnicodeToNative(JSContext *cx, const jschar *source, size_t slen)
|
||||||
{
|
{
|
||||||
nsCAutoString native;
|
nsCAutoString native;
|
||||||
nsDependentString unicode(reinterpret_cast<const PRUnichar*>(source), slen);
|
nsDependentString unicode(source, slen);
|
||||||
nsresult rv = NS_CopyUnicodeToNative(unicode, native);
|
nsresult rv = NS_CopyUnicodeToNative(unicode, native);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
JS_ReportError(cx, "could not convert string to native charset");
|
JS_ReportError(cx, "could not convert string to native charset");
|
||||||
|
@ -251,8 +251,12 @@ MessageCommon(JSContext* cx, uintN argc, jsval* vp,
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
result->msgName.Assign((PRUnichar*)JS_GetStringChars(msgNameStr),
|
size_t length;
|
||||||
JS_GetStringLength(msgNameStr));
|
const jschar* chars = JS_GetStringCharsAndLength(cx, msgNameStr, &length);
|
||||||
|
if (!chars)
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
result->msgName.Assign(chars, length);
|
||||||
|
|
||||||
result->data.Clear();
|
result->data.Clear();
|
||||||
|
|
||||||
|
@ -355,8 +359,12 @@ ReceiverCommon(JSContext* cx, uintN argc, jsval* vp,
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
result->msgName.Assign((PRUnichar*)JS_GetStringChars(str),
|
size_t length;
|
||||||
JS_GetStringLength(str));
|
const jschar* chars = JS_GetStringCharsAndLength(cx, str, &length);
|
||||||
|
if (!chars)
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
result->msgName.Assign(chars, length);
|
||||||
|
|
||||||
if (arity < 2)
|
if (arity < 2)
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
|
@ -497,9 +505,13 @@ JetpackChild::EvalInSandbox(JSContext* cx, uintN argc, jsval* vp)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t length;
|
||||||
|
const jschar* chars = JS_GetStringCharsAndLength(cx, str, &length);
|
||||||
|
if (!chars)
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
js::AutoValueRooter ignored(cx);
|
js::AutoValueRooter ignored(cx);
|
||||||
return JS_EvaluateUCScript(cx, obj, JS_GetStringChars(str), JS_GetStringLength(str), "", 1,
|
return JS_EvaluateUCScript(cx, obj, chars, length, "", 1, ignored.jsval_addr());
|
||||||
ignored.jsval_addr());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JetpackChild::sReportingError;
|
bool JetpackChild::sReportingError;
|
||||||
|
|
|
@ -74,6 +74,11 @@ CPPSRCS = \
|
||||||
JetpackActorCommon.cpp \
|
JetpackActorCommon.cpp \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
|
# For nsDependentJSString
|
||||||
|
LOCAL_INCLUDES += \
|
||||||
|
-I$(topsrcdir)/dom/base \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
ifdef ENABLE_TESTS
|
ifdef ENABLE_TESTS
|
||||||
TOOL_DIRS += tests
|
TOOL_DIRS += tests
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -78,7 +78,7 @@ interface jsdIActivationCallback;
|
||||||
* Debugger service. It's not a good idea to have more than one active client of
|
* Debugger service. It's not a good idea to have more than one active client of
|
||||||
* the debugger service.
|
* the debugger service.
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(01769775-c77c-47f9-8848-0abbab404215)]
|
[scriptable, uuid(1ad86ef3-5eca-4ed7-81c5-a757d1957dff)]
|
||||||
interface jsdIDebuggerService : nsISupports
|
interface jsdIDebuggerService : nsISupports
|
||||||
{
|
{
|
||||||
/** Internal use only. */
|
/** Internal use only. */
|
||||||
|
@ -512,7 +512,7 @@ interface jsdIFilterEnumerator : nsISupports
|
||||||
/**
|
/**
|
||||||
* Pass an instance of one of these to jsdIDebuggerService::enumerateScripts.
|
* Pass an instance of one of these to jsdIDebuggerService::enumerateScripts.
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(5ba76b99-acb1-4ed8-a4e4-a716a7d9097e)]
|
[scriptable, uuid(4eef60c2-9bbc-48fa-b196-646a832c6c81)]
|
||||||
interface jsdIScriptEnumerator : nsISupports
|
interface jsdIScriptEnumerator : nsISupports
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -525,7 +525,7 @@ interface jsdIScriptEnumerator : nsISupports
|
||||||
/**
|
/**
|
||||||
* Pass an instance of one of these to jsdIDebuggerService::enumerateContexts.
|
* Pass an instance of one of these to jsdIDebuggerService::enumerateContexts.
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(d96af02e-3379-4db5-885d-fee28d178701)]
|
[scriptable, uuid(57d18286-550c-4ca9-ac33-56f12ebba91e)]
|
||||||
interface jsdIContextEnumerator : nsISupports
|
interface jsdIContextEnumerator : nsISupports
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -538,7 +538,7 @@ interface jsdIContextEnumerator : nsISupports
|
||||||
/**
|
/**
|
||||||
* Set jsdIDebuggerService::scriptHook to an instance of one of these.
|
* Set jsdIDebuggerService::scriptHook to an instance of one of these.
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(cf7ecc3f-361b-44af-84a7-4b0d6cdca204)]
|
[scriptable, uuid(bb722893-0f63-45c5-b547-7a0947c7b6b6)]
|
||||||
interface jsdIScriptHook : nsISupports
|
interface jsdIScriptHook : nsISupports
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -556,7 +556,7 @@ interface jsdIScriptHook : nsISupports
|
||||||
* Hook instances of this interface up to the
|
* Hook instances of this interface up to the
|
||||||
* jsdIDebuggerService::functionHook and toplevelHook properties.
|
* jsdIDebuggerService::functionHook and toplevelHook properties.
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(191d2738-22e8-4756-b366-6c878c87d73b)]
|
[scriptable, uuid(3eff1314-7ae3-4cf8-833b-c33c24a55633)]
|
||||||
interface jsdICallHook : nsISupports
|
interface jsdICallHook : nsISupports
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -588,7 +588,7 @@ interface jsdICallHook : nsISupports
|
||||||
void onCall (in jsdIStackFrame frame, in unsigned long type);
|
void onCall (in jsdIStackFrame frame, in unsigned long type);
|
||||||
};
|
};
|
||||||
|
|
||||||
[scriptable, uuid(cea9ab1a-4b5d-416f-a197-9ffa7046f2ce)]
|
[scriptable, uuid(e6b45eee-d974-4d85-9d9e-f5a67218deb4)]
|
||||||
interface jsdIErrorHook : nsISupports
|
interface jsdIErrorHook : nsISupports
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -880,7 +880,7 @@ interface jsdIStackFrame : jsdIEphemeral
|
||||||
* Script object. In JavaScript engine terms, there's a single script for each
|
* Script object. In JavaScript engine terms, there's a single script for each
|
||||||
* function, and one for the top level script.
|
* function, and one for the top level script.
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(7e6fb9ed-4382-421d-9a14-c80a486e983b)]
|
[scriptable, uuid(e7935220-7def-4c8e-832f-fbc948a97490)]
|
||||||
interface jsdIScript : jsdIEphemeral
|
interface jsdIScript : jsdIEphemeral
|
||||||
{
|
{
|
||||||
/** Internal use only. */
|
/** Internal use only. */
|
||||||
|
@ -1038,6 +1038,10 @@ interface jsdIScript : jsdIEphemeral
|
||||||
* Clear all breakpoints set in this script.
|
* Clear all breakpoints set in this script.
|
||||||
*/
|
*/
|
||||||
void clearAllBreakpoints ();
|
void clearAllBreakpoints ();
|
||||||
|
/**
|
||||||
|
* Call interrupt hook at least once per source line
|
||||||
|
*/
|
||||||
|
void enableSingleStepInterrupts (in PRBool mode);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1046,7 +1050,7 @@ interface jsdIScript : jsdIEphemeral
|
||||||
* jsdIValue adds a root for the underlying JavaScript value, so don't keep it
|
* jsdIValue adds a root for the underlying JavaScript value, so don't keep it
|
||||||
* if you don't need to.
|
* if you don't need to.
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(9cab158f-dc78-41dd-9d11-79e05cb3f2bd)]
|
[scriptable, uuid(fd1311f7-096c-44a3-847b-9d478c8176c3)]
|
||||||
interface jsdIValue : jsdIEphemeral
|
interface jsdIValue : jsdIEphemeral
|
||||||
{
|
{
|
||||||
/** Internal use only. */
|
/** Internal use only. */
|
||||||
|
@ -1192,7 +1196,7 @@ interface jsdIValue : jsdIEphemeral
|
||||||
* functions from jsdIValue should move to this interface. We could inherit from
|
* functions from jsdIValue should move to this interface. We could inherit from
|
||||||
* jsdIValue or use interface flattening or something.
|
* jsdIValue or use interface flattening or something.
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(a735a94c-9d41-4997-8fcb-cfa8b649a5b7)]
|
[scriptable, uuid(87d86308-7a27-4255-b23c-ce2394f02473)]
|
||||||
interface jsdIObject : nsISupports
|
interface jsdIObject : nsISupports
|
||||||
{
|
{
|
||||||
/** Internal use only. */
|
/** Internal use only. */
|
||||||
|
@ -1228,7 +1232,7 @@ interface jsdIObject : nsISupports
|
||||||
* Representation of a property of an object. When an instance is invalid, all
|
* Representation of a property of an object. When an instance is invalid, all
|
||||||
* method and property access will result in a NS_UNAVAILABLE error.
|
* method and property access will result in a NS_UNAVAILABLE error.
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(4491ecd4-fb6b-43fb-bd6f-5d1473f1df24)]
|
[scriptable, uuid(09332485-1419-42bc-ba1f-070815ed4b82)]
|
||||||
interface jsdIProperty : jsdIEphemeral
|
interface jsdIProperty : jsdIEphemeral
|
||||||
{
|
{
|
||||||
/** Internal use only. */
|
/** Internal use only. */
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "jsd.h"
|
#include "jsd.h"
|
||||||
|
#include "jsfriendapi.h"
|
||||||
|
|
||||||
/* Comment this out to disable (NT specific) dumping as we go */
|
/* Comment this out to disable (NT specific) dumping as we go */
|
||||||
/*
|
/*
|
||||||
|
@ -214,7 +215,8 @@ _dumpJSDScript(JSDContext* jsdc, JSDScript* jsdscript, const char* leadingtext)
|
||||||
if (fun) {
|
if (fun) {
|
||||||
n += size_t(snprintf(Buf + n, sizeof(Buf) - n, "%s", "no fun"));
|
n += size_t(snprintf(Buf + n, sizeof(Buf) - n, "%s", "no fun"));
|
||||||
} else {
|
} else {
|
||||||
n += JS_PutEscapedString(Buf + n, sizeof(Buf) - n, fun, 0);
|
n += JS_PutEscapedFlatString(Buf + n, sizeof(Buf) - n,
|
||||||
|
JS_ASSERT_STRING_IS_FLAT(fun), 0);
|
||||||
Buf[sizeof(Buf) - 1] = '\0';
|
Buf[sizeof(Buf) - 1] = '\0';
|
||||||
}
|
}
|
||||||
if (n + 1 < sizeof(Buf))
|
if (n + 1 < sizeof(Buf))
|
||||||
|
@ -503,7 +505,9 @@ jsd_GetScriptFunctionName(JSDContext* jsdc, JSDScript *jsdscript)
|
||||||
if( ! jsdscript->function )
|
if( ! jsdscript->function )
|
||||||
return NULL;
|
return NULL;
|
||||||
str = JS_GetFunctionId(jsdscript->function);
|
str = JS_GetFunctionId(jsdscript->function);
|
||||||
return str ? str : JS_GetEmptyString(jsdc->jsrt);
|
|
||||||
|
/* For compatibility we return "anonymous", not an empty string here. */
|
||||||
|
return str ? str : JS_GetAnonymousString(jsdc->jsrt);
|
||||||
}
|
}
|
||||||
|
|
||||||
uintN
|
uintN
|
||||||
|
@ -587,6 +591,17 @@ jsd_GetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc* hook, void** callerdata)
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JSBool
|
||||||
|
jsd_EnableSingleStepInterrupts(JSDContext* jsdc, JSDScript* jsdscript, JSBool enable)
|
||||||
|
{
|
||||||
|
JSBool rv;
|
||||||
|
JSD_LOCK();
|
||||||
|
rv = JS_SetSingleStepMode(jsdc->dumbContext, jsdscript->script, enable);
|
||||||
|
JSD_UNLOCK();
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -751,7 +766,7 @@ jsd_TrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval,
|
||||||
}
|
}
|
||||||
|
|
||||||
JSD_ASSERT_VALID_EXEC_HOOK(jsdhook);
|
JSD_ASSERT_VALID_EXEC_HOOK(jsdhook);
|
||||||
JS_ASSERT(jsdhook->pc == (jsuword)pc);
|
JS_ASSERT(!jsdhook->pc || jsdhook->pc == (jsuword)pc);
|
||||||
JS_ASSERT(jsdhook->jsdscript->script == script);
|
JS_ASSERT(jsdhook->jsdscript->script == script);
|
||||||
JS_ASSERT(jsdhook->jsdscript->jsdc == jsdc);
|
JS_ASSERT(jsdhook->jsdscript->jsdc == jsdc);
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "jsd.h"
|
#include "jsd.h"
|
||||||
|
#include "jsfriendapi.h"
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
void JSD_ASSERT_VALID_THREAD_STATE(JSDThreadState* jsdthreadstate)
|
void JSD_ASSERT_VALID_THREAD_STATE(JSDThreadState* jsdthreadstate)
|
||||||
|
@ -370,7 +371,16 @@ jsd_GetNameForStackFrame(JSDContext* jsdc,
|
||||||
JSFunction *fun = JS_GetFrameFunction (jsdthreadstate->context,
|
JSFunction *fun = JS_GetFrameFunction (jsdthreadstate->context,
|
||||||
jsdframe->fp);
|
jsdframe->fp);
|
||||||
if( fun )
|
if( fun )
|
||||||
|
{
|
||||||
rv = JS_GetFunctionId (fun);
|
rv = JS_GetFunctionId (fun);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For compatibility we return "anonymous", not an empty string
|
||||||
|
* here.
|
||||||
|
*/
|
||||||
|
if( !rv )
|
||||||
|
rv = JS_GetAnonymousString(jsdc->jsrt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JSD_UNLOCK_THREADSTATES(jsdc);
|
JSD_UNLOCK_THREADSTATES(jsdc);
|
||||||
|
|
|
@ -41,8 +41,7 @@
|
||||||
|
|
||||||
#include "jsd.h"
|
#include "jsd.h"
|
||||||
#include "jsapi.h"
|
#include "jsapi.h"
|
||||||
#include "jspubtd.h"
|
#include "jsfriendapi.h"
|
||||||
#include "jsprvtd.h"
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
void JSD_ASSERT_VALID_VALUE(JSDValue* jsdval)
|
void JSD_ASSERT_VALID_VALUE(JSDValue* jsdval)
|
||||||
|
@ -273,8 +272,10 @@ jsd_GetValueFunctionName(JSDContext* jsdc, JSDValue* jsdval)
|
||||||
if(!fun)
|
if(!fun)
|
||||||
return NULL;
|
return NULL;
|
||||||
jsdval->funName = JS_GetFunctionId(fun);
|
jsdval->funName = JS_GetFunctionId(fun);
|
||||||
|
|
||||||
|
/* For compatibility we return "anonymous", not an empty string here. */
|
||||||
if (!jsdval->funName)
|
if (!jsdval->funName)
|
||||||
jsdval->funName = JS_GetEmptyString(jsdc->jsrt);
|
jsdval->funName = JS_GetAnonymousString(jsdc->jsrt);
|
||||||
}
|
}
|
||||||
return jsdval->funName;
|
return jsdval->funName;
|
||||||
}
|
}
|
||||||
|
@ -298,7 +299,7 @@ jsd_NewValue(JSDContext* jsdc, jsval val)
|
||||||
call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, jsdc->glob);
|
call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, jsdc->glob);
|
||||||
if(!call) {
|
if(!call) {
|
||||||
JS_EndRequest(jsdc->dumbContext);
|
JS_EndRequest(jsdc->dumbContext);
|
||||||
|
free(jsdval);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -562,8 +563,11 @@ jsd_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* name)
|
||||||
while(NULL != (jsdprop = jsd_IterateProperties(jsdc, jsdval, &iter)))
|
while(NULL != (jsdprop = jsd_IterateProperties(jsdc, jsdval, &iter)))
|
||||||
{
|
{
|
||||||
JSString* propName = jsd_GetValueString(jsdc, jsdprop->name);
|
JSString* propName = jsd_GetValueString(jsdc, jsdprop->name);
|
||||||
if(propName && !JS_CompareStrings(propName, name))
|
if(propName) {
|
||||||
|
intN result;
|
||||||
|
if (JS_CompareStrings(cx, propName, name, &result) && !result)
|
||||||
return jsdprop;
|
return jsdprop;
|
||||||
|
}
|
||||||
JSD_DropProperty(jsdc, jsdprop);
|
JSD_DropProperty(jsdc, jsdprop);
|
||||||
}
|
}
|
||||||
/* Not found in property list, look it up explicitly */
|
/* Not found in property list, look it up explicitly */
|
||||||
|
@ -571,8 +575,8 @@ jsd_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* name)
|
||||||
if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
|
if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
nameChars = JS_GetStringChars(name);
|
if (!(nameChars = JS_GetStringCharsZAndLength(cx, name, &nameLen)))
|
||||||
nameLen = JS_GetStringLength(name);
|
return NULL;
|
||||||
|
|
||||||
JS_BeginRequest(cx);
|
JS_BeginRequest(cx);
|
||||||
call = JS_EnterCrossCompartmentCall(cx, obj);
|
call = JS_EnterCrossCompartmentCall(cx, obj);
|
||||||
|
|
|
@ -197,7 +197,7 @@ jsds_InvalidateAllEphemerals (LiveEphemeral **listHead)
|
||||||
LiveEphemeral *lv_record =
|
LiveEphemeral *lv_record =
|
||||||
reinterpret_cast<LiveEphemeral *>
|
reinterpret_cast<LiveEphemeral *>
|
||||||
(PR_NEXT_LINK(&(*listHead)->links));
|
(PR_NEXT_LINK(&(*listHead)->links));
|
||||||
while (*listHead)
|
do
|
||||||
{
|
{
|
||||||
LiveEphemeral *next =
|
LiveEphemeral *next =
|
||||||
reinterpret_cast<LiveEphemeral *>
|
reinterpret_cast<LiveEphemeral *>
|
||||||
|
@ -205,6 +205,7 @@ jsds_InvalidateAllEphemerals (LiveEphemeral **listHead)
|
||||||
lv_record->value->Invalidate();
|
lv_record->value->Invalidate();
|
||||||
lv_record = next;
|
lv_record = next;
|
||||||
}
|
}
|
||||||
|
while (*listHead);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1033,36 +1034,61 @@ jsdScript::CreatePPLineMap()
|
||||||
JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL);
|
JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL);
|
||||||
JSFunction *fun = JSD_GetJSFunction (mCx, mScript);
|
JSFunction *fun = JSD_GetJSFunction (mCx, mScript);
|
||||||
JSScript *script;
|
JSScript *script;
|
||||||
|
JSString *jsstr;
|
||||||
PRUint32 baseLine;
|
PRUint32 baseLine;
|
||||||
PRBool scriptOwner = PR_FALSE;
|
PRBool scriptOwner = PR_FALSE;
|
||||||
|
|
||||||
if (fun) {
|
if (fun) {
|
||||||
uintN nargs = JS_GetFunctionArgumentCount(cx, fun);
|
uintN nargs;
|
||||||
|
|
||||||
|
/* 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)
|
if (nargs > 12)
|
||||||
return nsnull;
|
return nsnull;
|
||||||
JSString *jsstr = JS_DecompileFunctionBody (cx, fun, 4);
|
jsstr = JS_DecompileFunctionBody (cx, fun, 4);
|
||||||
if (!jsstr)
|
if (!jsstr)
|
||||||
return nsnull;
|
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",
|
const char *argnames[] = {"arg1", "arg2", "arg3", "arg4",
|
||||||
"arg5", "arg6", "arg7", "arg8",
|
"arg5", "arg6", "arg7", "arg8",
|
||||||
"arg9", "arg10", "arg11", "arg12" };
|
"arg9", "arg10", "arg11", "arg12" };
|
||||||
fun = JS_CompileUCFunction (cx, obj, "ppfun", nargs, argnames,
|
fun = JS_CompileUCFunction (cx, obj, "ppfun", nargs, argnames, chars,
|
||||||
JS_GetStringChars(jsstr),
|
length, "x-jsd:ppbuffer?type=function", 3);
|
||||||
JS_GetStringLength(jsstr),
|
|
||||||
"x-jsd:ppbuffer?type=function", 3);
|
|
||||||
if (!fun || !(script = JS_GetFunctionScript(cx, fun)))
|
if (!fun || !(script = JS_GetFunctionScript(cx, fun)))
|
||||||
return nsnull;
|
return nsnull;
|
||||||
baseLine = 3;
|
baseLine = 3;
|
||||||
} else {
|
} else {
|
||||||
JSString *jsstr = JS_DecompileScript (cx, JSD_GetJSScript(mCx, mScript),
|
/* Enter a new block so we can leave before the end of this block */
|
||||||
|
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);
|
"ppscript", 4);
|
||||||
if (!jsstr)
|
if (!jsstr)
|
||||||
return nsnull;
|
return nsnull;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
script = JS_CompileUCScript (cx, obj,
|
size_t length;
|
||||||
JS_GetStringChars(jsstr),
|
const jschar *chars = JS_GetStringCharsAndLength(cx, jsstr, &length);
|
||||||
JS_GetStringLength(jsstr),
|
if (!chars)
|
||||||
|
return nsnull;
|
||||||
|
|
||||||
|
script = JS_CompileUCScript (cx, obj, chars, length,
|
||||||
"x-jsd:ppbuffer?type=script", 1);
|
"x-jsd:ppbuffer?type=script", 1);
|
||||||
if (!script)
|
if (!script)
|
||||||
return nsnull;
|
return nsnull;
|
||||||
|
@ -1284,8 +1310,7 @@ jsdScript::GetParameterNames(PRUint32* count, PRUnichar*** paramNames)
|
||||||
ret[i] = 0;
|
ret[i] = 0;
|
||||||
} else {
|
} else {
|
||||||
JSString *str = JS_AtomKey(atom);
|
JSString *str = JS_AtomKey(atom);
|
||||||
ret[i] = NS_strndup(reinterpret_cast<PRUnichar*>(JS_GetStringChars(str)),
|
ret[i] = NS_strndup(JS_GetInternedStringChars(str), JS_GetStringLength(str));
|
||||||
JS_GetStringLength(str));
|
|
||||||
if (!ret[i]) {
|
if (!ret[i]) {
|
||||||
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, ret);
|
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, ret);
|
||||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
@ -1343,23 +1368,26 @@ jsdScript::GetFunctionSource(nsAString & aFunctionSource)
|
||||||
JSAutoRequest ar(cx);
|
JSAutoRequest ar(cx);
|
||||||
|
|
||||||
JSString *jsstr;
|
JSString *jsstr;
|
||||||
if (fun) {
|
|
||||||
JSAutoEnterCompartment ac;
|
JSAutoEnterCompartment ac;
|
||||||
|
if (fun) {
|
||||||
if (!ac.enter(cx, JS_GetFunctionObject(fun)))
|
if (!ac.enter(cx, JS_GetFunctionObject(fun)))
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
jsstr = JS_DecompileFunction (cx, fun, 4);
|
jsstr = JS_DecompileFunction (cx, fun, 4);
|
||||||
} else {
|
} else {
|
||||||
JSScript *script = JSD_GetJSScript (mCx, mScript);
|
JSScript *script = JSD_GetJSScript (mCx, mScript);
|
||||||
js::SwitchToCompartment sc(cx, script->compartment);
|
if (!ac.enter(cx, script))
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
jsstr = JS_DecompileScript (cx, script, "ppscript", 4);
|
jsstr = JS_DecompileScript (cx, script, "ppscript", 4);
|
||||||
}
|
}
|
||||||
if (!jsstr)
|
if (!jsstr)
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
aFunctionSource =
|
size_t length;
|
||||||
nsDependentString(
|
const jschar *chars = JS_GetStringCharsZAndLength(cx, jsstr, &length);
|
||||||
reinterpret_cast<PRUnichar*>(JS_GetStringChars(jsstr)),
|
if (!chars)
|
||||||
JS_GetStringLength(jsstr));
|
return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
|
aFunctionSource = nsDependentString(chars, length);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1480,6 +1508,20 @@ jsdScript::LineToPc(PRUint32 aLine, PRUint32 aPcmap, PRUint32 *_rval)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
jsdScript::EnableSingleStepInterrupts(PRBool enable)
|
||||||
|
{
|
||||||
|
ASSERT_VALID_EPHEMERAL;
|
||||||
|
|
||||||
|
/* Must have set interrupt hook before enabling */
|
||||||
|
if (enable && !jsdService::GetService()->CheckInterruptHook())
|
||||||
|
return NS_ERROR_NOT_INITIALIZED;
|
||||||
|
|
||||||
|
JSD_EnableSingleStepInterrupts(mCx, mScript, enable);
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
jsdScript::IsLineExecutable(PRUint32 aLine, PRUint32 aPcmap, PRBool *_rval)
|
jsdScript::IsLineExecutable(PRUint32 aLine, PRUint32 aPcmap, PRBool *_rval)
|
||||||
{
|
{
|
||||||
|
@ -2240,12 +2282,19 @@ NS_IMETHODIMP
|
||||||
jsdValue::GetStringValue(nsACString &_rval)
|
jsdValue::GetStringValue(nsACString &_rval)
|
||||||
{
|
{
|
||||||
ASSERT_VALID_EPHEMERAL;
|
ASSERT_VALID_EPHEMERAL;
|
||||||
|
JSContext *cx = JSD_GetDefaultJSContext (mCx);
|
||||||
|
if (!cx) {
|
||||||
|
NS_WARNING("No default context !?");
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
JSString *jstr_val = JSD_GetValueString(mCx, mValue);
|
JSString *jstr_val = JSD_GetValueString(mCx, mValue);
|
||||||
if (jstr_val) {
|
if (jstr_val) {
|
||||||
nsDependentString chars(
|
size_t length;
|
||||||
reinterpret_cast<PRUnichar*>(JS_GetStringChars(jstr_val)),
|
const jschar *chars = JS_GetStringCharsZAndLength(cx, jstr_val, &length);
|
||||||
JS_GetStringLength(jstr_val));
|
if (!chars)
|
||||||
CopyUTF16toUTF8(chars, _rval);
|
return NS_ERROR_FAILURE;
|
||||||
|
nsDependentString depStr(chars, length);
|
||||||
|
CopyUTF16toUTF8(depStr, _rval);
|
||||||
} else {
|
} else {
|
||||||
_rval.Truncate();
|
_rval.Truncate();
|
||||||
}
|
}
|
||||||
|
|
|
@ -289,6 +289,8 @@ class jsdService : public jsdIDebuggerService
|
||||||
|
|
||||||
static jsdService *GetService ();
|
static jsdService *GetService ();
|
||||||
|
|
||||||
|
PRBool CheckInterruptHook() { return !!mInterruptHook; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PRBool mOn;
|
PRBool mOn;
|
||||||
PRUint32 mPauseLevel;
|
PRUint32 mPauseLevel;
|
||||||
|
|
|
@ -576,6 +576,14 @@ JSD_SetInterruptHook(JSDContext* jsdc,
|
||||||
return jsd_SetInterruptHook(jsdc, hook, callerdata);
|
return jsd_SetInterruptHook(jsdc, hook, callerdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JSD_PUBLIC_API(JSBool)
|
||||||
|
JSD_EnableSingleStepInterrupts(JSDContext* jsdc, JSDScript* jsdscript, JSBool enable)
|
||||||
|
{
|
||||||
|
JSD_ASSERT_VALID_CONTEXT(jsdc);
|
||||||
|
JSD_ASSERT_VALID_SCRIPT(jsdscript);
|
||||||
|
return jsd_EnableSingleStepInterrupts(jsdc, jsdscript, enable);
|
||||||
|
}
|
||||||
|
|
||||||
JSD_PUBLIC_API(JSBool)
|
JSD_PUBLIC_API(JSBool)
|
||||||
JSD_ClearInterruptHook(JSDContext* jsdc)
|
JSD_ClearInterruptHook(JSDContext* jsdc)
|
||||||
{
|
{
|
||||||
|
|
|
@ -803,6 +803,12 @@ JSD_SetInterruptHook(JSDContext* jsdc,
|
||||||
JSD_ExecutionHookProc hook,
|
JSD_ExecutionHookProc hook,
|
||||||
void* callerdata);
|
void* callerdata);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call the interrupt hook at least once per source line
|
||||||
|
*/
|
||||||
|
extern JSD_PUBLIC_API(JSBool)
|
||||||
|
JSD_EnableSingleStepInterrupts(JSDContext* jsdc, JSDScript *jsdscript, JSBool enable);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clear the current interrupt hook.
|
* Clear the current interrupt hook.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -134,17 +134,18 @@ CPPSRCS = \
|
||||||
jsbool.cpp \
|
jsbool.cpp \
|
||||||
jsclone.cpp \
|
jsclone.cpp \
|
||||||
jscntxt.cpp \
|
jscntxt.cpp \
|
||||||
|
jscompartment.cpp \
|
||||||
jsdate.cpp \
|
jsdate.cpp \
|
||||||
jsdbgapi.cpp \
|
jsdbgapi.cpp \
|
||||||
jsdhash.cpp \
|
jsdhash.cpp \
|
||||||
jsdtoa.cpp \
|
jsdtoa.cpp \
|
||||||
jsemit.cpp \
|
jsemit.cpp \
|
||||||
jsexn.cpp \
|
jsexn.cpp \
|
||||||
|
jsfriendapi.cpp \
|
||||||
jsfun.cpp \
|
jsfun.cpp \
|
||||||
jsgc.cpp \
|
jsgc.cpp \
|
||||||
jsgcchunk.cpp \
|
jsgcchunk.cpp \
|
||||||
jsgcstats.cpp \
|
jsgcstats.cpp \
|
||||||
jscompartment.cpp \
|
|
||||||
jshash.cpp \
|
jshash.cpp \
|
||||||
jsinterp.cpp \
|
jsinterp.cpp \
|
||||||
jsinvoke.cpp \
|
jsinvoke.cpp \
|
||||||
|
@ -199,6 +200,7 @@ INSTALLED_HEADERS = \
|
||||||
jsdtoa.h \
|
jsdtoa.h \
|
||||||
jsemit.h \
|
jsemit.h \
|
||||||
jsfun.h \
|
jsfun.h \
|
||||||
|
jsfriendapi.h \
|
||||||
jsgc.h \
|
jsgc.h \
|
||||||
jscell.h \
|
jscell.h \
|
||||||
jsgcchunk.h \
|
jsgcchunk.h \
|
||||||
|
@ -572,11 +574,11 @@ ifdef ENABLE_TRACEJIT
|
||||||
ifndef WINCE
|
ifndef WINCE
|
||||||
check::
|
check::
|
||||||
$(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/jit-test/jit_test.py \
|
$(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/jit-test/jit_test.py \
|
||||||
--no-slow --no-progress --tinderbox $(DIST)/bin/js$(BIN_SUFFIX)
|
--no-slow --no-progress --tinderbox --jitflags=m,j,mj,mjp,mjd $(DIST)/bin/js$(BIN_SUFFIX)
|
||||||
|
|
||||||
check-valgrind::
|
check-valgrind::
|
||||||
$(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/jit-test/jit_test.py \
|
$(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/jit-test/jit_test.py \
|
||||||
--valgrind --no-slow --no-progress --tinderbox $(DIST)/bin/js$(BIN_SUFFIX)
|
--valgrind --no-slow --no-progress --tinderbox --jitflags=m,j,mj,mjp,mjd $(DIST)/bin/js$(BIN_SUFFIX)
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
@ -170,6 +170,13 @@ public:
|
||||||
|
|
||||||
size_t available() const { return (m_pools.length() > 1) ? 0 : m_end - m_freePtr; }
|
size_t available() const { return (m_pools.length() > 1) ? 0 : m_end - m_freePtr; }
|
||||||
|
|
||||||
|
// Flag for downstream use, whether to try to release references to this pool.
|
||||||
|
bool m_destroy;
|
||||||
|
|
||||||
|
// GC number in which the m_destroy flag was most recently set. Used downstream to
|
||||||
|
// remember whether m_destroy was computed for the currently active GC.
|
||||||
|
size_t m_gcNumber;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// On OOM, this will return an Allocation where pages is NULL.
|
// On OOM, this will return an Allocation where pages is NULL.
|
||||||
static Allocation systemAlloc(size_t n);
|
static Allocation systemAlloc(size_t n);
|
||||||
|
@ -393,7 +400,7 @@ private:
|
||||||
|
|
||||||
// This constructor can fail due to OOM. If it does, m_freePtr will be
|
// This constructor can fail due to OOM. If it does, m_freePtr will be
|
||||||
// set to NULL.
|
// set to NULL.
|
||||||
inline ExecutablePool::ExecutablePool(size_t n) : m_refCount(1)
|
inline ExecutablePool::ExecutablePool(size_t n) : m_refCount(1), m_destroy(false), m_gcNumber(0)
|
||||||
{
|
{
|
||||||
size_t allocSize = roundUpAllocationSize(n, JIT_ALLOCATOR_PAGE_SIZE);
|
size_t allocSize = roundUpAllocationSize(n, JIT_ALLOCATOR_PAGE_SIZE);
|
||||||
if (allocSize == OVERSIZE_ALLOCATION) {
|
if (allocSize == OVERSIZE_ALLOCATION) {
|
||||||
|
|
|
@ -1292,7 +1292,10 @@ StringToInteger(JSContext* cx, JSString* string, IntegerType* result)
|
||||||
{
|
{
|
||||||
JS_STATIC_ASSERT(numeric_limits<IntegerType>::is_exact);
|
JS_STATIC_ASSERT(numeric_limits<IntegerType>::is_exact);
|
||||||
|
|
||||||
const jschar* cp = string->chars();
|
const jschar* cp = string->getChars(NULL);
|
||||||
|
if (!cp)
|
||||||
|
return false;
|
||||||
|
|
||||||
const jschar* end = cp + string->length();
|
const jschar* end = cp + string->length();
|
||||||
if (cp == end)
|
if (cp == end)
|
||||||
return false;
|
return false;
|
||||||
|
@ -1780,9 +1783,10 @@ ImplicitConvert(JSContext* cx,
|
||||||
JSString* str = JSVAL_TO_STRING(val); \
|
JSString* str = JSVAL_TO_STRING(val); \
|
||||||
if (str->length() != 1) \
|
if (str->length() != 1) \
|
||||||
return TypeError(cx, #name, val); \
|
return TypeError(cx, #name, val); \
|
||||||
\
|
const jschar *chars = str->getChars(cx); \
|
||||||
result = str->chars()[0]; \
|
if (!chars) \
|
||||||
\
|
return false; \
|
||||||
|
result = chars[0]; \
|
||||||
} else if (!jsvalToInteger(cx, val, &result)) { \
|
} else if (!jsvalToInteger(cx, val, &result)) { \
|
||||||
return TypeError(cx, #name, val); \
|
return TypeError(cx, #name, val); \
|
||||||
} \
|
} \
|
||||||
|
@ -1824,8 +1828,10 @@ ImplicitConvert(JSContext* cx,
|
||||||
// which the caller assumes ownership of.
|
// which the caller assumes ownership of.
|
||||||
// TODO: Extend this so we can safely convert strings at other times also.
|
// TODO: Extend this so we can safely convert strings at other times also.
|
||||||
JSString* sourceString = JSVAL_TO_STRING(val);
|
JSString* sourceString = JSVAL_TO_STRING(val);
|
||||||
const jschar* sourceChars = sourceString->chars();
|
|
||||||
size_t sourceLength = sourceString->length();
|
size_t sourceLength = sourceString->length();
|
||||||
|
const jschar* sourceChars = sourceString->getChars(cx);
|
||||||
|
if (!sourceChars)
|
||||||
|
return false;
|
||||||
|
|
||||||
switch (CType::GetTypeCode(cx, baseType)) {
|
switch (CType::GetTypeCode(cx, baseType)) {
|
||||||
case TYPE_char:
|
case TYPE_char:
|
||||||
|
@ -1879,8 +1885,10 @@ ImplicitConvert(JSContext* cx,
|
||||||
|
|
||||||
if (JSVAL_IS_STRING(val)) {
|
if (JSVAL_IS_STRING(val)) {
|
||||||
JSString* sourceString = JSVAL_TO_STRING(val);
|
JSString* sourceString = JSVAL_TO_STRING(val);
|
||||||
const jschar* sourceChars = sourceString->chars();
|
|
||||||
size_t sourceLength = sourceString->length();
|
size_t sourceLength = sourceString->length();
|
||||||
|
const jschar* sourceChars = sourceString->getChars(cx);
|
||||||
|
if (!sourceChars)
|
||||||
|
return false;
|
||||||
|
|
||||||
switch (CType::GetTypeCode(cx, baseType)) {
|
switch (CType::GetTypeCode(cx, baseType)) {
|
||||||
case TYPE_char:
|
case TYPE_char:
|
||||||
|
@ -1989,21 +1997,18 @@ ImplicitConvert(JSContext* cx,
|
||||||
if (JSID_IS_VOID(id))
|
if (JSID_IS_VOID(id))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
js::AutoValueRooter fieldVal(cx);
|
if (!JSID_IS_STRING(id)) {
|
||||||
JS_IdToValue(cx, id, fieldVal.jsval_addr());
|
|
||||||
if (!JSVAL_IS_STRING(fieldVal.jsval_value())) {
|
|
||||||
JS_ReportError(cx, "property name is not a string");
|
JS_ReportError(cx, "property name is not a string");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FieldInfo* field = StructType::LookupField(cx, targetType,
|
JSFlatString *name = JSID_TO_FLAT_STRING(id);
|
||||||
JSVAL_TO_STRING(fieldVal.jsval_value()));
|
const FieldInfo* field = StructType::LookupField(cx, targetType, name);
|
||||||
if (!field)
|
if (!field)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
JSString* name = JSVAL_TO_STRING(fieldVal.jsval_value());
|
|
||||||
js::AutoValueRooter prop(cx);
|
js::AutoValueRooter prop(cx);
|
||||||
if (!JS_GetUCProperty(cx, obj, name->chars(), name->length(), prop.jsval_addr()))
|
if (!JS_GetPropertyById(cx, obj, id, prop.jsval_addr()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Convert the field via ImplicitConvert().
|
// Convert the field via ImplicitConvert().
|
||||||
|
@ -3567,8 +3572,10 @@ ArrayType::ConstructData(JSContext* cx,
|
||||||
// We were given a string. Size the array to the appropriate length,
|
// We were given a string. Size the array to the appropriate length,
|
||||||
// including space for the terminator.
|
// including space for the terminator.
|
||||||
JSString* sourceString = JSVAL_TO_STRING(argv[0]);
|
JSString* sourceString = JSVAL_TO_STRING(argv[0]);
|
||||||
const jschar* sourceChars = sourceString->chars();
|
|
||||||
size_t sourceLength = sourceString->length();
|
size_t sourceLength = sourceString->length();
|
||||||
|
const jschar* sourceChars = sourceString->getChars(cx);
|
||||||
|
if (!sourceChars)
|
||||||
|
return false;
|
||||||
|
|
||||||
switch (CType::GetTypeCode(cx, baseType)) {
|
switch (CType::GetTypeCode(cx, baseType)) {
|
||||||
case TYPE_char:
|
case TYPE_char:
|
||||||
|
@ -3871,7 +3878,7 @@ ArrayType::AddressOfElement(JSContext* cx, uintN argc, jsval* vp)
|
||||||
|
|
||||||
// For a struct field descriptor 'val' of the form { name : type }, extract
|
// For a struct field descriptor 'val' of the form { name : type }, extract
|
||||||
// 'name' and 'type'.
|
// 'name' and 'type'.
|
||||||
static JSString*
|
static JSFlatString*
|
||||||
ExtractStructField(JSContext* cx, jsval val, JSObject** typeObj)
|
ExtractStructField(JSContext* cx, jsval val, JSObject** typeObj)
|
||||||
{
|
{
|
||||||
if (JSVAL_IS_PRIMITIVE(val)) {
|
if (JSVAL_IS_PRIMITIVE(val)) {
|
||||||
|
@ -3885,23 +3892,21 @@ ExtractStructField(JSContext* cx, jsval val, JSObject** typeObj)
|
||||||
return NULL;
|
return NULL;
|
||||||
js::AutoObjectRooter iterroot(cx, iter);
|
js::AutoObjectRooter iterroot(cx, iter);
|
||||||
|
|
||||||
jsid id;
|
jsid nameid;
|
||||||
if (!JS_NextProperty(cx, iter, &id))
|
if (!JS_NextProperty(cx, iter, &nameid))
|
||||||
return NULL;
|
return NULL;
|
||||||
if (JSID_IS_VOID(id)) {
|
if (JSID_IS_VOID(nameid)) {
|
||||||
JS_ReportError(cx, "struct field descriptors require a valid name and type");
|
JS_ReportError(cx, "struct field descriptors require a valid name and type");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
js::AutoValueRooter nameVal(cx);
|
if (!JSID_IS_STRING(nameid)) {
|
||||||
JS_IdToValue(cx, id, nameVal.jsval_addr());
|
|
||||||
if (!JSVAL_IS_STRING(nameVal.jsval_value())) {
|
|
||||||
JS_ReportError(cx, "struct field descriptors require a valid name and type");
|
JS_ReportError(cx, "struct field descriptors require a valid name and type");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
JSString* name = JSVAL_TO_STRING(nameVal.jsval_value());
|
|
||||||
|
|
||||||
// make sure we have one, and only one, property
|
// make sure we have one, and only one, property
|
||||||
|
jsid id;
|
||||||
if (!JS_NextProperty(cx, iter, &id))
|
if (!JS_NextProperty(cx, iter, &id))
|
||||||
return NULL;
|
return NULL;
|
||||||
if (!JSID_IS_VOID(id)) {
|
if (!JSID_IS_VOID(id)) {
|
||||||
|
@ -3910,7 +3915,7 @@ ExtractStructField(JSContext* cx, jsval val, JSObject** typeObj)
|
||||||
}
|
}
|
||||||
|
|
||||||
js::AutoValueRooter propVal(cx);
|
js::AutoValueRooter propVal(cx);
|
||||||
if (!JS_GetUCProperty(cx, obj, name->chars(), name->length(), propVal.jsval_addr()))
|
if (!JS_GetPropertyById(cx, obj, nameid, propVal.jsval_addr()))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (propVal.value().isPrimitive() ||
|
if (propVal.value().isPrimitive() ||
|
||||||
|
@ -3929,7 +3934,7 @@ ExtractStructField(JSContext* cx, jsval val, JSObject** typeObj)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return name;
|
return JSID_TO_FLAT_STRING(nameid);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For a struct field with 'name' and 'type', add an element of the form
|
// For a struct field with 'name' and 'type', add an element of the form
|
||||||
|
@ -3937,7 +3942,7 @@ ExtractStructField(JSContext* cx, jsval val, JSObject** typeObj)
|
||||||
static JSBool
|
static JSBool
|
||||||
AddFieldToArray(JSContext* cx,
|
AddFieldToArray(JSContext* cx,
|
||||||
jsval* element,
|
jsval* element,
|
||||||
JSString* name,
|
JSFlatString* name,
|
||||||
JSObject* typeObj)
|
JSObject* typeObj)
|
||||||
{
|
{
|
||||||
JSObject* fieldObj = JS_NewObject(cx, NULL, NULL, NULL);
|
JSObject* fieldObj = JS_NewObject(cx, NULL, NULL, NULL);
|
||||||
|
@ -4048,7 +4053,7 @@ StructType::DefineInternal(JSContext* cx, JSObject* typeObj, JSObject* fieldsObj
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
JSObject* fieldType = NULL;
|
JSObject* fieldType = NULL;
|
||||||
JSString* name = ExtractStructField(cx, item.jsval_value(), &fieldType);
|
JSFlatString* name = ExtractStructField(cx, item.jsval_value(), &fieldType);
|
||||||
if (!name)
|
if (!name)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
fieldRootsArray[i] = OBJECT_TO_JSVAL(fieldType);
|
fieldRootsArray[i] = OBJECT_TO_JSVAL(fieldType);
|
||||||
|
@ -4321,7 +4326,7 @@ StructType::GetFieldInfo(JSContext* cx, JSObject* obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
const FieldInfo*
|
const FieldInfo*
|
||||||
StructType::LookupField(JSContext* cx, JSObject* obj, JSString *name)
|
StructType::LookupField(JSContext* cx, JSObject* obj, JSFlatString *name)
|
||||||
{
|
{
|
||||||
JS_ASSERT(CType::IsCType(cx, obj));
|
JS_ASSERT(CType::IsCType(cx, obj));
|
||||||
JS_ASSERT(CType::GetTypeCode(cx, obj) == TYPE_struct);
|
JS_ASSERT(CType::GetTypeCode(cx, obj) == TYPE_struct);
|
||||||
|
@ -4417,7 +4422,7 @@ StructType::FieldGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FieldInfo* field = LookupField(cx, typeObj, JSID_TO_STRING(idval));
|
const FieldInfo* field = LookupField(cx, typeObj, JSID_TO_FLAT_STRING(idval));
|
||||||
if (!field)
|
if (!field)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
|
@ -4439,7 +4444,7 @@ StructType::FieldSetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FieldInfo* field = LookupField(cx, typeObj, JSID_TO_STRING(idval));
|
const FieldInfo* field = LookupField(cx, typeObj, JSID_TO_FLAT_STRING(idval));
|
||||||
if (!field)
|
if (!field)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
|
@ -4467,8 +4472,11 @@ StructType::AddressOfField(JSContext* cx, uintN argc, jsval* vp)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FieldInfo* field = LookupField(cx, typeObj,
|
JSFlatString *str = JS_FlattenString(cx, JSVAL_TO_STRING(JS_ARGV(cx, vp)[0]));
|
||||||
JSVAL_TO_STRING(JS_ARGV(cx, vp)[0]));
|
if (!str)
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
const FieldInfo* field = LookupField(cx, typeObj, str);
|
||||||
if (!field)
|
if (!field)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
|
@ -4611,18 +4619,23 @@ PrepareReturnType(JSContext* cx, jsval type)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static JS_ALWAYS_INLINE bool
|
static JS_ALWAYS_INLINE JSBool
|
||||||
IsEllipsis(jsval v)
|
IsEllipsis(JSContext* cx, jsval v, bool* isEllipsis)
|
||||||
{
|
{
|
||||||
|
*isEllipsis = false;
|
||||||
if (!JSVAL_IS_STRING(v))
|
if (!JSVAL_IS_STRING(v))
|
||||||
return false;
|
return true;
|
||||||
JSString* str = JSVAL_TO_STRING(v);
|
JSString* str = JSVAL_TO_STRING(v);
|
||||||
if (str->length() != 3)
|
if (str->length() != 3)
|
||||||
|
return true;
|
||||||
|
const jschar* chars = str->getChars(cx);
|
||||||
|
if (!chars)
|
||||||
return false;
|
return false;
|
||||||
const jschar* chars = str->chars(), dot('.');
|
jschar dot = '.';
|
||||||
return (chars[0] == dot &&
|
*isEllipsis = (chars[0] == dot &&
|
||||||
chars[1] == dot &&
|
chars[1] == dot &&
|
||||||
chars[2] == dot);
|
chars[2] == dot);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSBool
|
static JSBool
|
||||||
|
@ -4737,7 +4750,10 @@ NewFunctionInfo(JSContext* cx,
|
||||||
fninfo->mIsVariadic = false;
|
fninfo->mIsVariadic = false;
|
||||||
|
|
||||||
for (JSUint32 i = 0; i < argLength; ++i) {
|
for (JSUint32 i = 0; i < argLength; ++i) {
|
||||||
if (IsEllipsis(argTypes[i])) {
|
bool isEllipsis;
|
||||||
|
if (!IsEllipsis(cx, argTypes[i], &isEllipsis))
|
||||||
|
return false;
|
||||||
|
if (isEllipsis) {
|
||||||
fninfo->mIsVariadic = true;
|
fninfo->mIsVariadic = true;
|
||||||
if (i < 1) {
|
if (i < 1) {
|
||||||
JS_ReportError(cx, "\"...\" may not be the first and only parameter "
|
JS_ReportError(cx, "\"...\" may not be the first and only parameter "
|
||||||
|
|
|
@ -141,7 +141,10 @@ void
|
||||||
AppendString(Vector<jschar, N, AP> &v, JSString* str)
|
AppendString(Vector<jschar, N, AP> &v, JSString* str)
|
||||||
{
|
{
|
||||||
JS_ASSERT(str);
|
JS_ASSERT(str);
|
||||||
v.append(str->chars(), str->length());
|
const jschar *chars = str->getChars(NULL);
|
||||||
|
if (!chars)
|
||||||
|
return;
|
||||||
|
v.append(chars, str->length());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t N, class AP>
|
template <size_t N, class AP>
|
||||||
|
@ -154,8 +157,12 @@ AppendString(Vector<char, N, AP> &v, JSString* str)
|
||||||
if (!v.resize(vlen + alen))
|
if (!v.resize(vlen + alen))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
const jschar *chars = str->getChars(NULL);
|
||||||
|
if (!chars)
|
||||||
|
return;
|
||||||
|
|
||||||
for (size_t i = 0; i < alen; ++i)
|
for (size_t i = 0; i < alen; ++i)
|
||||||
v[i + vlen] = char(str->chars()[i]);
|
v[i + vlen] = char(chars[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T, size_t N, class AP, size_t ArrayLength>
|
template <class T, size_t N, class AP, size_t ArrayLength>
|
||||||
|
@ -186,33 +193,15 @@ PrependString(Vector<jschar, N, AP> &v, JSString* str)
|
||||||
if (!v.resize(vlen + alen))
|
if (!v.resize(vlen + alen))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
const jschar *chars = str->getChars(NULL);
|
||||||
|
if (!chars)
|
||||||
|
return;
|
||||||
|
|
||||||
// Move vector data forward. This is safe since we've already resized.
|
// Move vector data forward. This is safe since we've already resized.
|
||||||
memmove(v.begin() + alen, v.begin(), vlen * sizeof(jschar));
|
memmove(v.begin() + alen, v.begin(), vlen * sizeof(jschar));
|
||||||
|
|
||||||
// Copy data to insert.
|
// Copy data to insert.
|
||||||
memcpy(v.begin(), str->chars(), alen * sizeof(jschar));
|
memcpy(v.begin(), chars, alen * sizeof(jschar));
|
||||||
}
|
|
||||||
|
|
||||||
template <class T, size_t N, size_t M, class AP>
|
|
||||||
bool
|
|
||||||
StringsEqual(Vector<T, N, AP> &v, Vector<T, M, AP> &w)
|
|
||||||
{
|
|
||||||
if (v.length() != w.length())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return memcmp(v.begin(), w.begin(), v.length() * sizeof(T)) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <size_t N, class AP>
|
|
||||||
bool
|
|
||||||
StringsEqual(Vector<jschar, N, AP> &v, JSString* str)
|
|
||||||
{
|
|
||||||
JS_ASSERT(str);
|
|
||||||
size_t length = str->length();
|
|
||||||
if (v.length() != length)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return memcmp(v.begin(), str->chars(), length * sizeof(jschar)) == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
@ -274,7 +263,7 @@ struct FieldInfo
|
||||||
// Hash policy for FieldInfos.
|
// Hash policy for FieldInfos.
|
||||||
struct FieldHashPolicy
|
struct FieldHashPolicy
|
||||||
{
|
{
|
||||||
typedef JSString* Key;
|
typedef JSFlatString* Key;
|
||||||
typedef Key Lookup;
|
typedef Key Lookup;
|
||||||
|
|
||||||
static uint32 hash(const Lookup &l) {
|
static uint32 hash(const Lookup &l) {
|
||||||
|
@ -297,7 +286,7 @@ struct FieldHashPolicy
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef HashMap<JSString*, FieldInfo, FieldHashPolicy, SystemAllocPolicy> FieldInfoHash;
|
typedef HashMap<JSFlatString*, FieldInfo, FieldHashPolicy, SystemAllocPolicy> FieldInfoHash;
|
||||||
|
|
||||||
// Descriptor of ABI, return type, argument types, and variadicity for a
|
// Descriptor of ABI, return type, argument types, and variadicity for a
|
||||||
// FunctionType.
|
// FunctionType.
|
||||||
|
@ -482,7 +471,7 @@ namespace StructType {
|
||||||
JSBool DefineInternal(JSContext* cx, JSObject* typeObj, JSObject* fieldsObj);
|
JSBool DefineInternal(JSContext* cx, JSObject* typeObj, JSObject* fieldsObj);
|
||||||
|
|
||||||
const FieldInfoHash* GetFieldInfo(JSContext* cx, JSObject* obj);
|
const FieldInfoHash* GetFieldInfo(JSContext* cx, JSObject* obj);
|
||||||
const FieldInfo* LookupField(JSContext* cx, JSObject* obj, JSString *name);
|
const FieldInfo* LookupField(JSContext* cx, JSObject* obj, JSFlatString *name);
|
||||||
JSObject* BuildFieldsArray(JSContext* cx, JSObject* obj);
|
JSObject* BuildFieldsArray(JSContext* cx, JSObject* obj);
|
||||||
ffi_type* BuildFFIType(JSContext* cx, JSObject* obj);
|
ffi_type* BuildFFIType(JSContext* cx, JSObject* obj);
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,12 +133,13 @@ Library::Create(JSContext* cx, jsval path, JSCTypesCallbacks* callbacks)
|
||||||
}
|
}
|
||||||
|
|
||||||
PRLibSpec libSpec;
|
PRLibSpec libSpec;
|
||||||
JSString* pathStr = JSVAL_TO_STRING(path);
|
JSFlatString* pathStr = JS_FlattenString(cx, JSVAL_TO_STRING(path));
|
||||||
|
if (!pathStr)
|
||||||
|
return NULL;
|
||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
// On Windows, converting to native charset may corrupt path string.
|
// On Windows, converting to native charset may corrupt path string.
|
||||||
// So, we have to use Unicode path directly.
|
// So, we have to use Unicode path directly.
|
||||||
const PRUnichar* pathChars = reinterpret_cast<const PRUnichar*>(
|
const PRUnichar* pathChars = JS_GetFlatStringChars(pathStr);
|
||||||
JS_GetStringCharsZ(cx, pathStr));
|
|
||||||
if (!pathChars)
|
if (!pathChars)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
|
@ -502,7 +502,9 @@ newdtoa(void)
|
||||||
DtoaState *state = (DtoaState *) MALLOC(sizeof(DtoaState));
|
DtoaState *state = (DtoaState *) MALLOC(sizeof(DtoaState));
|
||||||
if (state) {
|
if (state) {
|
||||||
memset(state, 0, sizeof(DtoaState));
|
memset(state, 0, sizeof(DtoaState));
|
||||||
|
#ifndef Omit_Private_Memory
|
||||||
state->pmem_next = state->private_mem;
|
state->pmem_next = state->private_mem;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
# jit_test.py -- Python harness for JavaScript trace tests.
|
# jit_test.py -- Python harness for JavaScript trace tests.
|
||||||
|
|
||||||
import datetime, os, re, sys, tempfile, traceback
|
import datetime, os, re, sys, tempfile, traceback
|
||||||
|
@ -349,8 +351,8 @@ def main(argv):
|
||||||
help='Enable the |valgrind| flag, if valgrind is in $PATH.')
|
help='Enable the |valgrind| flag, if valgrind is in $PATH.')
|
||||||
op.add_option('--valgrind-all', dest='valgrind_all', action='store_true',
|
op.add_option('--valgrind-all', dest='valgrind_all', action='store_true',
|
||||||
help='Run all tests with valgrind, if valgrind is in $PATH.')
|
help='Run all tests with valgrind, if valgrind is in $PATH.')
|
||||||
op.add_option('--jitflags', dest='jitflags', default='j',
|
op.add_option('--jitflags', dest='jitflags', default='mjp',
|
||||||
help='Example: --jitflags=j,mj to run each test with -j and -m -j')
|
help='Example: --jitflags=j,mj,mjp to run each test with -j, -m -j, -m -j -p [default=%default]')
|
||||||
op.add_option('--avoid-stdio', dest='avoid_stdio', action='store_true',
|
op.add_option('--avoid-stdio', dest='avoid_stdio', action='store_true',
|
||||||
help='Use js-shell file indirection instead of piping stdio.')
|
help='Use js-shell file indirection instead of piping stdio.')
|
||||||
op.add_option('--write-failure-output', dest='write_failure_output', action='store_true',
|
op.add_option('--write-failure-output', dest='write_failure_output', action='store_true',
|
||||||
|
|
|
@ -13,7 +13,7 @@ function strictArgs(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
var a1, a2, a3;
|
var a1, a2, a3;
|
||||||
for (var i = 0; i < 5; i++)
|
for (var i = 0; i < HOTLOOP+1; i++)
|
||||||
{
|
{
|
||||||
a1 = strictArgs();
|
a1 = strictArgs();
|
||||||
a2 = strictArgs(1);
|
a2 = strictArgs(1);
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
|
||||||
|
var global = 0;
|
||||||
|
|
||||||
|
Object.defineProperty(Object.prototype, 0, {set: function() { global++; }});
|
||||||
|
|
||||||
|
for (var x = 0; x < 20; ++x)
|
||||||
|
[1,2];
|
||||||
|
assertEq(global, 0);
|
||||||
|
|
||||||
|
Object.defineProperty(Object.prototype, 1, {set: function() { global++; }});
|
||||||
|
|
||||||
|
for (var x = 0; x < 20; ++x)
|
||||||
|
[1,2];
|
||||||
|
assertEq(global, 0);
|
||||||
|
|
||||||
|
Object.defineProperty(Object.prototype, "b", {set: function() { global++; }});
|
||||||
|
|
||||||
|
for (var x = 0; x < 20; ++x) {
|
||||||
|
var s = { a:0, b:1, 0: 2, 1: 3 };
|
||||||
|
}
|
||||||
|
assertEq(global, 0);
|
||||||
|
|
||||||
|
assertEq([42][0], 42);
|
||||||
|
assertEq([42].length, 1);
|
|
@ -0,0 +1,22 @@
|
||||||
|
function g() {
|
||||||
|
return "global";
|
||||||
|
}
|
||||||
|
|
||||||
|
function q(fun) {
|
||||||
|
return fun();
|
||||||
|
}
|
||||||
|
|
||||||
|
function f(x) {
|
||||||
|
if (x) {
|
||||||
|
function g() {
|
||||||
|
return "local";
|
||||||
|
}
|
||||||
|
var ans = q(function() {
|
||||||
|
return g();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
g = null;
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEq(f(true), "local");
|
|
@ -0,0 +1,6 @@
|
||||||
|
// don't assert
|
||||||
|
for (a = 0; a < 9; ++a) {
|
||||||
|
M: for (let c in <x>></x>) {
|
||||||
|
break M
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
/* Touch/init early so global shape doesn't change in loop */
|
||||||
|
var SetOnIter = HOTLOOP - 1;
|
||||||
|
var x = 3;
|
||||||
|
var i = 0;
|
||||||
|
assertEq(true, true);
|
||||||
|
|
||||||
|
for (i = 0; i < SetOnIter + 10; ++i) {
|
||||||
|
x = 3;
|
||||||
|
setGlobalPropIf(i == SetOnIter, 'x', 'pretty');
|
||||||
|
assertEq(x == 'pretty', i == SetOnIter);
|
||||||
|
x = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < SetOnIter + 10; ++i) {
|
||||||
|
x = 3;
|
||||||
|
defGlobalPropIf(i == SetOnIter, 'x', { value:'pretty' });
|
||||||
|
assertEq(x == 'pretty', i == SetOnIter);
|
||||||
|
x = 3;
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
function f() {
|
function f() {
|
||||||
try {
|
try {
|
||||||
for ( var i = 1; i > -2; i-- )
|
for ( var i = HOTLOOP-1; i > -2; i-- )
|
||||||
new Array(i).join('*');
|
new Array(i).join('*');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return e instanceof RangeError;
|
return e instanceof RangeError;
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
function f() {
|
||||||
|
var o = { n: "" };
|
||||||
|
for (var i = 0; i < 2*RUNLOOP; ++i) {
|
||||||
|
o.n = "";
|
||||||
|
if (o.n++) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f();
|
||||||
|
|
||||||
|
checkStats({
|
||||||
|
recorderStarted: 1,
|
||||||
|
recorderAborted: 0,
|
||||||
|
traceCompleted: 1,
|
||||||
|
traceTriggered: 1
|
||||||
|
});
|
|
@ -0,0 +1,2 @@
|
||||||
|
var str = (3.14).toLocaleString();
|
||||||
|
assertEq(str[str.length-1], "4");
|
|
@ -0,0 +1 @@
|
||||||
|
var a = new Int32Array(); +(a[0]={});
|
|
@ -76,11 +76,12 @@ CPPSRCS = \
|
||||||
testUTF8.cpp \
|
testUTF8.cpp \
|
||||||
testVersion.cpp \
|
testVersion.cpp \
|
||||||
testXDR.cpp \
|
testXDR.cpp \
|
||||||
|
testCustomIterator.cpp \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
DEFINES += -DEXPORT_JS_API
|
DEFINES += -DEXPORT_JS_API
|
||||||
|
|
||||||
LIBS = $(NSPR_LIBS) $(DEPTH)/$(LIB_PREFIX)js_static.$(LIB_SUFFIX)
|
LIBS = $(DEPTH)/$(LIB_PREFIX)js_static.$(LIB_SUFFIX) $(NSPR_LIBS)
|
||||||
|
|
||||||
LOCAL_INCLUDES += -I$(topsrcdir) -I..
|
LOCAL_INCLUDES += -I$(topsrcdir) -I..
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
#include "tests.h"
|
||||||
|
|
||||||
|
#include "jsvalue.h"
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
static JSBool
|
||||||
|
IterNext(JSContext *cx, uintN argc, jsval *vp)
|
||||||
|
{
|
||||||
|
if (count++ == 100)
|
||||||
|
return JS_ThrowStopIteration(cx);
|
||||||
|
JS_SET_RVAL(cx, vp, INT_TO_JSVAL(count));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSObject *
|
||||||
|
IterHook(JSContext *cx, JSObject *obj, JSBool keysonly)
|
||||||
|
{
|
||||||
|
JSObject *iterObj = JS_NewObject(cx, NULL, NULL, NULL);
|
||||||
|
if (!iterObj)
|
||||||
|
return NULL;
|
||||||
|
if (!JS_DefineFunction(cx, iterObj, "next", IterNext, 0, 0))
|
||||||
|
return NULL;
|
||||||
|
return iterObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
js::Class HasCustomIterClass = {
|
||||||
|
"HasCustomIter",
|
||||||
|
0,
|
||||||
|
js::PropertyStub,
|
||||||
|
js::PropertyStub,
|
||||||
|
js::PropertyStub,
|
||||||
|
js::PropertyStub,
|
||||||
|
js::EnumerateStub,
|
||||||
|
js::ResolveStub,
|
||||||
|
js::ConvertStub,
|
||||||
|
NULL,
|
||||||
|
NULL, /* reserved0 */
|
||||||
|
NULL, /* checkAccess */
|
||||||
|
NULL, /* call */
|
||||||
|
NULL, /* construct */
|
||||||
|
NULL, /* xdrObject */
|
||||||
|
NULL, /* hasInstance */
|
||||||
|
NULL, /* mark */
|
||||||
|
{
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
IterHook,
|
||||||
|
NULL
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
JSBool
|
||||||
|
IterClassConstructor(JSContext *cx, uintN argc, jsval *vp)
|
||||||
|
{
|
||||||
|
JSObject *obj = JS_NewObjectForConstructor(cx, vp);
|
||||||
|
if (!obj)
|
||||||
|
return false;
|
||||||
|
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BEGIN_TEST(testCustomIterator_bug612523)
|
||||||
|
{
|
||||||
|
CHECK(JS_InitClass(cx, JS_GetGlobalObject(cx), NULL, Jsvalify(&HasCustomIterClass),
|
||||||
|
IterClassConstructor, 0, NULL, NULL, NULL, NULL));
|
||||||
|
|
||||||
|
jsval result;
|
||||||
|
EVAL("var o = new HasCustomIter(); \n"
|
||||||
|
"var j = 0; \n"
|
||||||
|
"for (var i in o) { ++j; }; \n"
|
||||||
|
"j;", &result);
|
||||||
|
|
||||||
|
CHECK(JSVAL_IS_INT(result));
|
||||||
|
CHECK(JSVAL_TO_INT(result) == 100);
|
||||||
|
CHECK(count == 101);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
END_TEST(testCustomIterator_bug612523)
|
|
@ -12,28 +12,28 @@ BEGIN_TEST(testIntString_bug515273)
|
||||||
EVAL("'1';", v.addr());
|
EVAL("'1';", v.addr());
|
||||||
JSString *str = JSVAL_TO_STRING(v.value());
|
JSString *str = JSVAL_TO_STRING(v.value());
|
||||||
CHECK(JSString::isStatic(str));
|
CHECK(JSString::isStatic(str));
|
||||||
CHECK(JS_MatchStringAndAscii(str, "1"));
|
CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "1"));
|
||||||
|
|
||||||
EVAL("'42';", v.addr());
|
EVAL("'42';", v.addr());
|
||||||
str = JSVAL_TO_STRING(v.value());
|
str = JSVAL_TO_STRING(v.value());
|
||||||
CHECK(JSString::isStatic(str));
|
CHECK(JSString::isStatic(str));
|
||||||
CHECK(JS_MatchStringAndAscii(str, "42"));
|
CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "42"));
|
||||||
|
|
||||||
EVAL("'111';", v.addr());
|
EVAL("'111';", v.addr());
|
||||||
str = JSVAL_TO_STRING(v.value());
|
str = JSVAL_TO_STRING(v.value());
|
||||||
CHECK(JSString::isStatic(str));
|
CHECK(JSString::isStatic(str));
|
||||||
CHECK(JS_MatchStringAndAscii(str, "111"));
|
CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "111"));
|
||||||
|
|
||||||
/* Test other types of static strings. */
|
/* Test other types of static strings. */
|
||||||
EVAL("'a';", v.addr());
|
EVAL("'a';", v.addr());
|
||||||
str = JSVAL_TO_STRING(v.value());
|
str = JSVAL_TO_STRING(v.value());
|
||||||
CHECK(JSString::isStatic(str));
|
CHECK(JSString::isStatic(str));
|
||||||
CHECK(JS_MatchStringAndAscii(str, "a"));
|
CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "a"));
|
||||||
|
|
||||||
EVAL("'bc';", v.addr());
|
EVAL("'bc';", v.addr());
|
||||||
str = JSVAL_TO_STRING(v.value());
|
str = JSVAL_TO_STRING(v.value());
|
||||||
CHECK(JSString::isStatic(str));
|
CHECK(JSString::isStatic(str));
|
||||||
CHECK(JS_MatchStringAndAscii(str, "bc"));
|
CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "bc"));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,10 @@ document_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **
|
||||||
return false;
|
return false;
|
||||||
if (JSVAL_IS_STRING(v.value())) {
|
if (JSVAL_IS_STRING(v.value())) {
|
||||||
JSString *str = JSVAL_TO_STRING(v.value());
|
JSString *str = JSVAL_TO_STRING(v.value());
|
||||||
if (JS_MatchStringAndAscii(str, "all") && !(flags & JSRESOLVE_DETECTING)) {
|
JSFlatString *flatStr = JS_FlattenString(cx, str);
|
||||||
|
if (!flatStr)
|
||||||
|
return false;
|
||||||
|
if (JS_FlatStringEqualsAscii(flatStr, "all") && !(flags & JSRESOLVE_DETECTING)) {
|
||||||
JSBool ok = JS_DefinePropertyById(cx, obj, id, JSVAL_TRUE, NULL, NULL, 0);
|
JSBool ok = JS_DefinePropertyById(cx, obj, id, JSVAL_TRUE, NULL, NULL, 0);
|
||||||
*objp = ok ? obj : NULL;
|
*objp = ok ? obj : NULL;
|
||||||
return ok;
|
return ok;
|
||||||
|
|
|
@ -16,7 +16,9 @@ BEGIN_TEST(testSameValue)
|
||||||
*/
|
*/
|
||||||
jsval v1 = DOUBLE_TO_JSVAL(0.0);
|
jsval v1 = DOUBLE_TO_JSVAL(0.0);
|
||||||
jsval v2 = DOUBLE_TO_JSVAL(-0.0);
|
jsval v2 = DOUBLE_TO_JSVAL(-0.0);
|
||||||
CHECK(!JS_SameValue(cx, v1, v2));
|
JSBool same;
|
||||||
|
CHECK(JS_SameValue(cx, v1, v2, &same));
|
||||||
|
CHECK(!same);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
END_TEST(testSameValue)
|
END_TEST(testSameValue)
|
||||||
|
|
|
@ -62,7 +62,7 @@ BEGIN_TEST(testTrap_gc)
|
||||||
|
|
||||||
JS_GC(cx);
|
JS_GC(cx);
|
||||||
|
|
||||||
CHECK(JS_MatchStringAndAscii(trapClosure, trapClosureText));
|
CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(trapClosure), trapClosureText));
|
||||||
|
|
||||||
// execute
|
// execute
|
||||||
CHECK(JS_ExecuteScript(cx, global, script, v2.addr()));
|
CHECK(JS_ExecuteScript(cx, global, script, v2.addr()));
|
||||||
|
@ -70,7 +70,7 @@ BEGIN_TEST(testTrap_gc)
|
||||||
|
|
||||||
JS_GC(cx);
|
JS_GC(cx);
|
||||||
|
|
||||||
CHECK(JS_MatchStringAndAscii(trapClosure, trapClosureText));
|
CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(trapClosure), trapClosureText));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,7 +192,8 @@ class JSAPITest
|
||||||
bool checkSame(jsval actual, jsval expected,
|
bool checkSame(jsval actual, jsval expected,
|
||||||
const char *actualExpr, const char *expectedExpr,
|
const char *actualExpr, const char *expectedExpr,
|
||||||
const char *filename, int lineno) {
|
const char *filename, int lineno) {
|
||||||
return JS_SameValue(cx, actual, expected) ||
|
JSBool same;
|
||||||
|
return (JS_SameValue(cx, actual, expected, &same) && same) ||
|
||||||
fail(JSAPITestString("CHECK_SAME failed: expected JS_SameValue(cx, ") +
|
fail(JSAPITestString("CHECK_SAME failed: expected JS_SameValue(cx, ") +
|
||||||
actualExpr + ", " + expectedExpr + "), got !JS_SameValue(cx, " +
|
actualExpr + ", " + expectedExpr + "), got !JS_SameValue(cx, " +
|
||||||
toSource(actual) + ", " + toSource(expected) + ")", filename, lineno);
|
toSource(actual) + ", " + toSource(expected) + ")", filename, lineno);
|
||||||
|
|
220
js/src/jsapi.cpp
220
js/src/jsapi.cpp
|
@ -111,6 +111,16 @@
|
||||||
using namespace js;
|
using namespace js;
|
||||||
using namespace js::gc;
|
using namespace js::gc;
|
||||||
|
|
||||||
|
static JSClass dummy_class = {
|
||||||
|
"jdummy",
|
||||||
|
JSCLASS_GLOBAL_FLAGS,
|
||||||
|
JS_PropertyStub, JS_PropertyStub,
|
||||||
|
JS_PropertyStub, JS_PropertyStub,
|
||||||
|
JS_EnumerateStub, JS_ResolveStub,
|
||||||
|
JS_ConvertStub, NULL,
|
||||||
|
JSCLASS_NO_OPTIONAL_MEMBERS
|
||||||
|
};
|
||||||
|
|
||||||
class AutoVersionAPI
|
class AutoVersionAPI
|
||||||
{
|
{
|
||||||
JSContext * const cx;
|
JSContext * const cx;
|
||||||
|
@ -571,17 +581,17 @@ JS_GetTypeName(JSContext *cx, JSType type)
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSBool)
|
JS_PUBLIC_API(JSBool)
|
||||||
JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2)
|
JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2, JSBool *equal)
|
||||||
{
|
{
|
||||||
assertSameCompartment(cx, v1, v2);
|
assertSameCompartment(cx, v1, v2);
|
||||||
return StrictlyEqual(cx, Valueify(v1), Valueify(v2));
|
return StrictlyEqual(cx, Valueify(v1), Valueify(v2), equal);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSBool)
|
JS_PUBLIC_API(JSBool)
|
||||||
JS_SameValue(JSContext *cx, jsval v1, jsval v2)
|
JS_SameValue(JSContext *cx, jsval v1, jsval v2, JSBool *same)
|
||||||
{
|
{
|
||||||
assertSameCompartment(cx, v1, v2);
|
assertSameCompartment(cx, v1, v2);
|
||||||
return SameValue(Valueify(v1), Valueify(v2), cx);
|
return SameValue(cx, Valueify(v1), Valueify(v2), same);
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
@ -1169,6 +1179,22 @@ JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target)
|
||||||
return reinterpret_cast<JSCrossCompartmentCall *>(call);
|
return reinterpret_cast<JSCrossCompartmentCall *>(call);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JS_PUBLIC_API(JSCrossCompartmentCall *)
|
||||||
|
JS_EnterCrossCompartmentCallScript(JSContext *cx, JSScript *target)
|
||||||
|
{
|
||||||
|
CHECK_REQUEST(cx);
|
||||||
|
|
||||||
|
JS_ASSERT(target);
|
||||||
|
JSObject *scriptObject = target->u.object;
|
||||||
|
if (!scriptObject) {
|
||||||
|
SwitchToCompartment sc(cx, target->compartment);
|
||||||
|
scriptObject = JS_NewGlobalObject(cx, &dummy_class);
|
||||||
|
if (!scriptObject)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return JS_EnterCrossCompartmentCall(cx, scriptObject);
|
||||||
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(void)
|
JS_PUBLIC_API(void)
|
||||||
JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call)
|
JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call)
|
||||||
{
|
{
|
||||||
|
@ -1190,6 +1216,18 @@ JSAutoEnterCompartment::enter(JSContext *cx, JSObject *target)
|
||||||
return call != NULL;
|
return call != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
JSAutoEnterCompartment::enter(JSContext *cx, JSScript *target)
|
||||||
|
{
|
||||||
|
JS_ASSERT(!call);
|
||||||
|
if (cx->compartment == target->compartment) {
|
||||||
|
call = reinterpret_cast<JSCrossCompartmentCall*>(1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
call = JS_EnterCrossCompartmentCallScript(cx, target);
|
||||||
|
return call != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
JSAutoEnterCompartment::enterAndIgnoreErrors(JSContext *cx, JSObject *target)
|
JSAutoEnterCompartment::enterAndIgnoreErrors(JSContext *cx, JSObject *target)
|
||||||
{
|
{
|
||||||
|
@ -2199,8 +2237,14 @@ JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, ui
|
||||||
}
|
}
|
||||||
|
|
||||||
case JSTRACE_STRING:
|
case JSTRACE_STRING:
|
||||||
PutEscapedString(buf, bufsize, (JSString *)thing, 0);
|
{
|
||||||
|
JSString *str = (JSString *)thing;
|
||||||
|
if (str->isLinear())
|
||||||
|
PutEscapedString(buf, bufsize, str->assertIsLinear(), 0);
|
||||||
|
else
|
||||||
|
JS_snprintf(buf, bufsize, "<rope: length %d>", (int)str->length());
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
#if JS_HAS_XML_SUPPORT
|
#if JS_HAS_XML_SUPPORT
|
||||||
case JSTRACE_XML:
|
case JSTRACE_XML:
|
||||||
|
@ -2662,7 +2706,7 @@ JS_GetGCParameterForThread(JSContext *cx, JSGCParamKey key)
|
||||||
{
|
{
|
||||||
JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES);
|
JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES);
|
||||||
#ifdef JS_TRACER
|
#ifdef JS_TRACER
|
||||||
return JS_THREAD_DATA(cx)->traceMonitor.maxCodeCacheBytes;
|
return JS_THREAD_DATA(cx)->maxCodeCacheBytes;
|
||||||
#else
|
#else
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
|
@ -5168,17 +5212,8 @@ JS_RestoreFrameChain(JSContext *cx, JSStackFrame *fp)
|
||||||
JS_PUBLIC_API(JSString *)
|
JS_PUBLIC_API(JSString *)
|
||||||
JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
|
JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
|
||||||
{
|
{
|
||||||
jschar *js;
|
|
||||||
JSString *str;
|
|
||||||
|
|
||||||
CHECK_REQUEST(cx);
|
CHECK_REQUEST(cx);
|
||||||
js = js_InflateString(cx, s, &n);
|
return js_NewStringCopyN(cx, s, n);
|
||||||
if (!js)
|
|
||||||
return NULL;
|
|
||||||
str = js_NewString(cx, js, n);
|
|
||||||
if (!str)
|
|
||||||
cx->free(js);
|
|
||||||
return str;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSString *)
|
JS_PUBLIC_API(JSString *)
|
||||||
|
@ -5207,6 +5242,16 @@ JS_StringHasBeenInterned(JSString *str)
|
||||||
return str->isAtomized();
|
return str->isAtomized();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JS_PUBLIC_API(JSString *)
|
||||||
|
JS_InternJSString(JSContext *cx, JSString *str)
|
||||||
|
{
|
||||||
|
CHECK_REQUEST(cx);
|
||||||
|
JSAtom *atom = js_AtomizeString(cx, str, 0);
|
||||||
|
if (!atom)
|
||||||
|
return NULL;
|
||||||
|
return ATOM_TO_STRING(atom);
|
||||||
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSString *)
|
JS_PUBLIC_API(JSString *)
|
||||||
JS_InternString(JSContext *cx, const char *s)
|
JS_InternString(JSContext *cx, const char *s)
|
||||||
{
|
{
|
||||||
|
@ -5260,45 +5305,6 @@ JS_InternUCString(JSContext *cx, const jschar *s)
|
||||||
return JS_InternUCStringN(cx, s, js_strlen(s));
|
return JS_InternUCStringN(cx, s, js_strlen(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(jschar *)
|
|
||||||
JS_GetStringChars(JSString *str)
|
|
||||||
{
|
|
||||||
size_t n, size;
|
|
||||||
jschar *s;
|
|
||||||
|
|
||||||
str->ensureNotRope();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* API botch: we have no cx to report out-of-memory when undepending
|
|
||||||
* strings, so we replace JSString::undepend with explicit malloc call and
|
|
||||||
* ignore its errors.
|
|
||||||
*
|
|
||||||
* If we fail to convert a dependent string into an independent one, our
|
|
||||||
* caller will not be guaranteed a \u0000 terminator as a backstop. This
|
|
||||||
* may break some clients who already misbehave on embedded NULs.
|
|
||||||
*
|
|
||||||
* The gain of dependent strings, which cure quadratic and cubic growth
|
|
||||||
* rate bugs in string concatenation, is worth this slight loss in API
|
|
||||||
* compatibility.
|
|
||||||
*/
|
|
||||||
if (str->isDependent()) {
|
|
||||||
n = str->dependentLength();
|
|
||||||
size = (n + 1) * sizeof(jschar);
|
|
||||||
s = (jschar *) js_malloc(size);
|
|
||||||
if (s) {
|
|
||||||
memcpy(s, str->dependentChars(), n * sizeof *s);
|
|
||||||
s[n] = 0;
|
|
||||||
str->initFlat(s, n);
|
|
||||||
} else {
|
|
||||||
s = str->dependentChars();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
str->flatClearExtensible();
|
|
||||||
s = str->flatChars();
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_PUBLIC_API(size_t)
|
JS_PUBLIC_API(size_t)
|
||||||
JS_GetStringLength(JSString *str)
|
JS_GetStringLength(JSString *str)
|
||||||
{
|
{
|
||||||
|
@ -5306,41 +5312,102 @@ JS_GetStringLength(JSString *str)
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(const jschar *)
|
JS_PUBLIC_API(const jschar *)
|
||||||
JS_GetStringCharsAndLength(JSString *str, size_t *lengthp)
|
JS_GetStringCharsZ(JSContext *cx, JSString *str)
|
||||||
{
|
{
|
||||||
*lengthp = str->length();
|
CHECK_REQUEST(cx);
|
||||||
return str->chars();
|
assertSameCompartment(cx, str);
|
||||||
|
return str->getCharsZ(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(const jschar *)
|
JS_PUBLIC_API(const jschar *)
|
||||||
JS_GetStringCharsZ(JSContext *cx, JSString *str)
|
JS_GetStringCharsZAndLength(JSContext *cx, JSString *str, size_t *plength)
|
||||||
{
|
{
|
||||||
|
CHECK_REQUEST(cx);
|
||||||
assertSameCompartment(cx, str);
|
assertSameCompartment(cx, str);
|
||||||
return str->undepend(cx);
|
*plength = str->length();
|
||||||
|
return str->getCharsZ(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(intN)
|
JS_PUBLIC_API(const jschar *)
|
||||||
JS_CompareStrings(JSString *str1, JSString *str2)
|
JS_GetStringCharsAndLength(JSContext *cx, JSString *str, size_t *plength)
|
||||||
{
|
{
|
||||||
return js_CompareStrings(str1, str2);
|
CHECK_REQUEST(cx);
|
||||||
|
assertSameCompartment(cx, str);
|
||||||
|
*plength = str->length();
|
||||||
|
return str->getChars(cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_PUBLIC_API(const jschar *)
|
||||||
|
JS_GetInternedStringChars(JSString *str)
|
||||||
|
{
|
||||||
|
JS_ASSERT(str->isAtomized());
|
||||||
|
return str->flatChars();
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_PUBLIC_API(const jschar *)
|
||||||
|
JS_GetInternedStringCharsAndLength(JSString *str, size_t *plength)
|
||||||
|
{
|
||||||
|
JS_ASSERT(str->isAtomized());
|
||||||
|
*plength = str->flatLength();
|
||||||
|
return str->flatChars();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern JS_PUBLIC_API(JSFlatString *)
|
||||||
|
JS_FlattenString(JSContext *cx, JSString *str)
|
||||||
|
{
|
||||||
|
CHECK_REQUEST(cx);
|
||||||
|
assertSameCompartment(cx, str);
|
||||||
|
return str->getCharsZ(cx) ? (JSFlatString *)str : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern JS_PUBLIC_API(const jschar *)
|
||||||
|
JS_GetFlatStringChars(JSFlatString *str)
|
||||||
|
{
|
||||||
|
return str->chars();
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSBool)
|
JS_PUBLIC_API(JSBool)
|
||||||
JS_MatchStringAndAscii(JSString *str, const char *asciiBytes)
|
JS_CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32 *result)
|
||||||
{
|
{
|
||||||
return MatchStringAndAscii(str, asciiBytes);
|
return CompareStrings(cx, str1, str2, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_PUBLIC_API(JSBool)
|
||||||
|
JS_StringEqualsAscii(JSContext *cx, JSString *str, const char *asciiBytes, JSBool *match)
|
||||||
|
{
|
||||||
|
JSLinearString *linearStr = str->ensureLinear(cx);
|
||||||
|
if (!linearStr)
|
||||||
|
return false;
|
||||||
|
*match = StringEqualsAscii(linearStr, asciiBytes);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_PUBLIC_API(JSBool)
|
||||||
|
JS_FlatStringEqualsAscii(JSFlatString *str, const char *asciiBytes)
|
||||||
|
{
|
||||||
|
return StringEqualsAscii(str, asciiBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(size_t)
|
JS_PUBLIC_API(size_t)
|
||||||
JS_PutEscapedString(char *buffer, size_t size, JSString *str, char quote)
|
JS_PutEscapedFlatString(char *buffer, size_t size, JSFlatString *str, char quote)
|
||||||
{
|
{
|
||||||
return PutEscapedString(buffer, size, str, quote);
|
return PutEscapedString(buffer, size, str, quote);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JS_PUBLIC_API(size_t)
|
||||||
|
JS_PutEscapedString(JSContext *cx, char *buffer, size_t size, JSString *str, char quote)
|
||||||
|
{
|
||||||
|
JSLinearString *linearStr = str->ensureLinear(cx);
|
||||||
|
if (!linearStr)
|
||||||
|
return size_t(-1);
|
||||||
|
return PutEscapedString(buffer, size, linearStr, quote);
|
||||||
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSBool)
|
JS_PUBLIC_API(JSBool)
|
||||||
JS_FileEscapedString(FILE *fp, JSString *str, char quote)
|
JS_FileEscapedString(FILE *fp, JSString *str, char quote)
|
||||||
{
|
{
|
||||||
return FileEscapedString(fp, str, quote);
|
JSLinearString *linearStr = str->ensureLinear(NULL);
|
||||||
|
return linearStr && FileEscapedString(fp, linearStr, quote);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSString *)
|
JS_PUBLIC_API(JSString *)
|
||||||
|
@ -5368,7 +5435,7 @@ JS_PUBLIC_API(const jschar *)
|
||||||
JS_UndependString(JSContext *cx, JSString *str)
|
JS_UndependString(JSContext *cx, JSString *str)
|
||||||
{
|
{
|
||||||
CHECK_REQUEST(cx);
|
CHECK_REQUEST(cx);
|
||||||
return str->undepend(cx);
|
return str->getCharsZ(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSBool)
|
JS_PUBLIC_API(JSBool)
|
||||||
|
@ -5404,13 +5471,19 @@ JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst, size_
|
||||||
JS_PUBLIC_API(char *)
|
JS_PUBLIC_API(char *)
|
||||||
JS_EncodeString(JSContext *cx, JSString *str)
|
JS_EncodeString(JSContext *cx, JSString *str)
|
||||||
{
|
{
|
||||||
return js_DeflateString(cx, str->chars(), str->length());
|
const jschar *chars = str->getChars(cx);
|
||||||
|
if (!chars)
|
||||||
|
return NULL;
|
||||||
|
return js_DeflateString(cx, chars, str->length());
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(size_t)
|
JS_PUBLIC_API(size_t)
|
||||||
JS_GetStringEncodingLength(JSContext *cx, JSString *str)
|
JS_GetStringEncodingLength(JSContext *cx, JSString *str)
|
||||||
{
|
{
|
||||||
return js_GetDeflatedStringLength(cx, str->chars(), str->length());
|
const jschar *chars = str->getChars(cx);
|
||||||
|
if (!chars)
|
||||||
|
return size_t(-1);
|
||||||
|
return js_GetDeflatedStringLength(cx, chars, str->length());
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(size_t)
|
JS_PUBLIC_API(size_t)
|
||||||
|
@ -5422,12 +5495,15 @@ JS_EncodeStringToBuffer(JSString *str, char *buffer, size_t length)
|
||||||
* error.
|
* error.
|
||||||
*/
|
*/
|
||||||
size_t writtenLength = length;
|
size_t writtenLength = length;
|
||||||
if (js_DeflateStringToBuffer(NULL, str->chars(), str->length(), buffer, &writtenLength)) {
|
const jschar *chars = str->getChars(NULL);
|
||||||
|
if (!chars)
|
||||||
|
return size_t(-1);
|
||||||
|
if (js_DeflateStringToBuffer(NULL, chars, str->length(), buffer, &writtenLength)) {
|
||||||
JS_ASSERT(writtenLength <= length);
|
JS_ASSERT(writtenLength <= length);
|
||||||
return writtenLength;
|
return writtenLength;
|
||||||
}
|
}
|
||||||
JS_ASSERT(writtenLength <= length);
|
JS_ASSERT(writtenLength <= length);
|
||||||
size_t necessaryLength = js_GetDeflatedStringLength(NULL, str->chars(), str->length());
|
size_t necessaryLength = js_GetDeflatedStringLength(NULL, chars, str->length());
|
||||||
if (necessaryLength == size_t(-1))
|
if (necessaryLength == size_t(-1))
|
||||||
return size_t(-1);
|
return size_t(-1);
|
||||||
if (writtenLength != length) {
|
if (writtenLength != length) {
|
||||||
|
|
114
js/src/jsapi.h
114
js/src/jsapi.h
|
@ -500,7 +500,7 @@ extern JS_PUBLIC_DATA(jsid) JSID_EMPTY;
|
||||||
|
|
||||||
#define JSFUN_HEAVYWEIGHT_TEST(f) ((f) & JSFUN_HEAVYWEIGHT)
|
#define JSFUN_HEAVYWEIGHT_TEST(f) ((f) & JSFUN_HEAVYWEIGHT)
|
||||||
|
|
||||||
#define JSFUN_PRIMITIVE_THIS 0x0100 /* |this| may be a primitive value */
|
/* 0x0100 is unused */
|
||||||
#define JSFUN_CONSTRUCTOR 0x0200 /* native that can be called as a ctor
|
#define JSFUN_CONSTRUCTOR 0x0200 /* native that can be called as a ctor
|
||||||
without creating a this object */
|
without creating a this object */
|
||||||
|
|
||||||
|
@ -702,10 +702,10 @@ extern JS_PUBLIC_API(const char *)
|
||||||
JS_GetTypeName(JSContext *cx, JSType type);
|
JS_GetTypeName(JSContext *cx, JSType type);
|
||||||
|
|
||||||
extern JS_PUBLIC_API(JSBool)
|
extern JS_PUBLIC_API(JSBool)
|
||||||
JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2);
|
JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2, JSBool *equal);
|
||||||
|
|
||||||
extern JS_PUBLIC_API(JSBool)
|
extern JS_PUBLIC_API(JSBool)
|
||||||
JS_SameValue(JSContext *cx, jsval v1, jsval v2);
|
JS_SameValue(JSContext *cx, jsval v1, jsval v2, JSBool *same);
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
||||||
|
@ -979,6 +979,9 @@ JS_SetWrapObjectCallbacks(JSRuntime *rt,
|
||||||
extern JS_PUBLIC_API(JSCrossCompartmentCall *)
|
extern JS_PUBLIC_API(JSCrossCompartmentCall *)
|
||||||
JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target);
|
JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target);
|
||||||
|
|
||||||
|
extern JS_PUBLIC_API(JSCrossCompartmentCall *)
|
||||||
|
JS_EnterCrossCompartmentCallScript(JSContext *cx, JSScript *target);
|
||||||
|
|
||||||
extern JS_PUBLIC_API(void)
|
extern JS_PUBLIC_API(void)
|
||||||
JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call);
|
JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call);
|
||||||
|
|
||||||
|
@ -1009,6 +1012,8 @@ class JS_PUBLIC_API(JSAutoEnterCompartment)
|
||||||
|
|
||||||
bool enter(JSContext *cx, JSObject *target);
|
bool enter(JSContext *cx, JSObject *target);
|
||||||
|
|
||||||
|
bool enter(JSContext *cx, JSScript *target);
|
||||||
|
|
||||||
void enterAndIgnoreErrors(JSContext *cx, JSObject *target);
|
void enterAndIgnoreErrors(JSContext *cx, JSObject *target);
|
||||||
|
|
||||||
bool entered() const { return call != NULL; }
|
bool entered() const { return call != NULL; }
|
||||||
|
@ -2931,6 +2936,9 @@ JS_NewStringCopyN(JSContext *cx, const char *s, size_t n);
|
||||||
extern JS_PUBLIC_API(JSString *)
|
extern JS_PUBLIC_API(JSString *)
|
||||||
JS_NewStringCopyZ(JSContext *cx, const char *s);
|
JS_NewStringCopyZ(JSContext *cx, const char *s);
|
||||||
|
|
||||||
|
extern JS_PUBLIC_API(JSString *)
|
||||||
|
JS_InternJSString(JSContext *cx, JSString *str);
|
||||||
|
|
||||||
extern JS_PUBLIC_API(JSString *)
|
extern JS_PUBLIC_API(JSString *)
|
||||||
JS_InternString(JSContext *cx, const char *s);
|
JS_InternString(JSContext *cx, const char *s);
|
||||||
|
|
||||||
|
@ -2949,36 +2957,106 @@ JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length);
|
||||||
extern JS_PUBLIC_API(JSString *)
|
extern JS_PUBLIC_API(JSString *)
|
||||||
JS_InternUCString(JSContext *cx, const jschar *s);
|
JS_InternUCString(JSContext *cx, const jschar *s);
|
||||||
|
|
||||||
|
extern JS_PUBLIC_API(JSBool)
|
||||||
|
JS_CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32 *result);
|
||||||
|
|
||||||
|
extern JS_PUBLIC_API(JSBool)
|
||||||
|
JS_StringEqualsAscii(JSContext *cx, JSString *str, const char *asciiBytes, JSBool *match);
|
||||||
|
|
||||||
|
extern JS_PUBLIC_API(size_t)
|
||||||
|
JS_PutEscapedString(JSContext *cx, char *buffer, size_t size, JSString *str, char quote);
|
||||||
|
|
||||||
|
extern JS_PUBLIC_API(JSBool)
|
||||||
|
JS_FileEscapedString(FILE *fp, JSString *str, char quote);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Deprecated. Use JS_GetStringCharsZ() instead.
|
* Extracting string characters and length.
|
||||||
|
*
|
||||||
|
* While getting the length of a string is infallible, getting the chars can
|
||||||
|
* fail. As indicated by the lack of a JSContext parameter, there are two
|
||||||
|
* special cases where getting the chars is infallible:
|
||||||
|
*
|
||||||
|
* The first case is interned strings, i.e., strings from JS_InternString or
|
||||||
|
* JSID_TO_STRING(id), using JS_GetInternedStringChars*.
|
||||||
|
*
|
||||||
|
* The second case is "flat" strings that have been explicitly prepared in a
|
||||||
|
* fallible context by JS_FlattenString. To catch errors, a separate opaque
|
||||||
|
* JSFlatString type is returned by JS_FlattenString and expected by
|
||||||
|
* JS_GetFlatStringChars. Note, though, that this is purely a syntactic
|
||||||
|
* distinction: the input and output of JS_FlattenString are the same actual
|
||||||
|
* GC-thing so only one needs to be rooted. If a JSString is known to be flat,
|
||||||
|
* JS_ASSERT_STRING_IS_FLAT can be used to make a debug-checked cast. Example:
|
||||||
|
*
|
||||||
|
* // in a fallible context
|
||||||
|
* JSFlatString *fstr = JS_FlattenString(cx, str);
|
||||||
|
* if (!fstr)
|
||||||
|
* return JS_FALSE;
|
||||||
|
* JS_ASSERT(fstr == JS_ASSERT_STRING_IS_FLAT(str));
|
||||||
|
*
|
||||||
|
* // in an infallible context, for the same 'str'
|
||||||
|
* const jschar *chars = JS_GetFlatStringChars(fstr)
|
||||||
|
* JS_ASSERT(chars);
|
||||||
|
*
|
||||||
|
* The CharsZ APIs guarantee that the returned array has a null character at
|
||||||
|
* chars[length]. This can require additional copying so clients should prefer
|
||||||
|
* APIs without CharsZ if possible. The infallible functions also return
|
||||||
|
* null-terminated arrays. (There is no additional cost or non-Z alternative
|
||||||
|
* for the infallible functions, so 'Z' is left out of the identifier.)
|
||||||
*/
|
*/
|
||||||
extern JS_PUBLIC_API(jschar *)
|
|
||||||
JS_GetStringChars(JSString *str);
|
|
||||||
|
|
||||||
extern JS_PUBLIC_API(size_t)
|
extern JS_PUBLIC_API(size_t)
|
||||||
JS_GetStringLength(JSString *str);
|
JS_GetStringLength(JSString *str);
|
||||||
|
|
||||||
/*
|
|
||||||
* Return the char array and length for this string. The array is not
|
|
||||||
* null-terminated.
|
|
||||||
*/
|
|
||||||
extern JS_PUBLIC_API(const jschar *)
|
extern JS_PUBLIC_API(const jschar *)
|
||||||
JS_GetStringCharsAndLength(JSString *str, size_t *lengthp);
|
JS_GetStringCharsAndLength(JSContext *cx, JSString *str, size_t *length);
|
||||||
|
|
||||||
|
extern JS_PUBLIC_API(const jschar *)
|
||||||
|
JS_GetInternedStringChars(JSString *str);
|
||||||
|
|
||||||
|
extern JS_PUBLIC_API(const jschar *)
|
||||||
|
JS_GetInternedStringCharsAndLength(JSString *str, size_t *length);
|
||||||
|
|
||||||
extern JS_PUBLIC_API(const jschar *)
|
extern JS_PUBLIC_API(const jschar *)
|
||||||
JS_GetStringCharsZ(JSContext *cx, JSString *str);
|
JS_GetStringCharsZ(JSContext *cx, JSString *str);
|
||||||
|
|
||||||
extern JS_PUBLIC_API(intN)
|
extern JS_PUBLIC_API(const jschar *)
|
||||||
JS_CompareStrings(JSString *str1, JSString *str2);
|
JS_GetStringCharsZAndLength(JSContext *cx, JSString *str, size_t *length);
|
||||||
|
|
||||||
|
extern JS_PUBLIC_API(JSFlatString *)
|
||||||
|
JS_FlattenString(JSContext *cx, JSString *str);
|
||||||
|
|
||||||
|
extern JS_PUBLIC_API(const jschar *)
|
||||||
|
JS_GetFlatStringChars(JSFlatString *str);
|
||||||
|
|
||||||
|
static JS_ALWAYS_INLINE JSFlatString *
|
||||||
|
JSID_TO_FLAT_STRING(jsid id)
|
||||||
|
{
|
||||||
|
JS_ASSERT(JSID_IS_STRING(id));
|
||||||
|
return (JSFlatString *)(JSID_BITS(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
static JS_ALWAYS_INLINE JSFlatString *
|
||||||
|
JS_ASSERT_STRING_IS_FLAT(JSString *str)
|
||||||
|
{
|
||||||
|
JS_ASSERT(JS_GetFlatStringChars((JSFlatString *)str));
|
||||||
|
return (JSFlatString *)str;
|
||||||
|
}
|
||||||
|
|
||||||
|
static JS_ALWAYS_INLINE JSString *
|
||||||
|
JS_FORGET_STRING_FLATNESS(JSFlatString *fstr)
|
||||||
|
{
|
||||||
|
return (JSString *)fstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Additional APIs that avoid fallibility when given a flat string.
|
||||||
|
*/
|
||||||
|
|
||||||
extern JS_PUBLIC_API(JSBool)
|
extern JS_PUBLIC_API(JSBool)
|
||||||
JS_MatchStringAndAscii(JSString *str, const char *asciiBytes);
|
JS_FlatStringEqualsAscii(JSFlatString *str, const char *asciiBytes);
|
||||||
|
|
||||||
extern JS_PUBLIC_API(size_t)
|
extern JS_PUBLIC_API(size_t)
|
||||||
JS_PutEscapedString(char *buffer, size_t size, JSString *str, char quote);
|
JS_PutEscapedFlatString(char *buffer, size_t size, JSFlatString *str, char quote);
|
||||||
|
|
||||||
extern JS_PUBLIC_API(JSBool)
|
|
||||||
JS_FileEscapedString(FILE *fp, JSString *str, char quote);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function is now obsolete and behaves the same as JS_NewUCString. Use
|
* This function is now obsolete and behaves the same as JS_NewUCString. Use
|
||||||
|
|
|
@ -143,10 +143,10 @@ ENSURE_SLOW_ARRAY(JSContext *cx, JSObject *obj)
|
||||||
* 'id' is passed as a jsboxedword since the given id need not necessarily hold
|
* 'id' is passed as a jsboxedword since the given id need not necessarily hold
|
||||||
* an atomized string.
|
* an atomized string.
|
||||||
*/
|
*/
|
||||||
JSBool
|
bool
|
||||||
js_StringIsIndex(JSString *str, jsuint *indexp)
|
js_StringIsIndex(JSLinearString *str, jsuint *indexp)
|
||||||
{
|
{
|
||||||
jschar *cp = str->chars();
|
const jschar *cp = str->chars();
|
||||||
if (JS7_ISDEC(*cp) && str->length() < sizeof(MAXSTR)) {
|
if (JS7_ISDEC(*cp) && str->length() < sizeof(MAXSTR)) {
|
||||||
jsuint index = JS7_UNDEC(*cp++);
|
jsuint index = JS7_UNDEC(*cp++);
|
||||||
jsuint oldIndex = 0;
|
jsuint oldIndex = 0;
|
||||||
|
@ -166,10 +166,10 @@ js_StringIsIndex(JSString *str, jsuint *indexp)
|
||||||
(oldIndex == (MAXINDEX / 10) && c < (MAXINDEX % 10))))
|
(oldIndex == (MAXINDEX / 10) && c < (MAXINDEX % 10))))
|
||||||
{
|
{
|
||||||
*indexp = index;
|
*indexp = index;
|
||||||
return JS_TRUE;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return JS_FALSE;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -853,21 +853,35 @@ static JSBool
|
||||||
array_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value,
|
array_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value,
|
||||||
PropertyOp getter, PropertyOp setter, uintN attrs)
|
PropertyOp getter, PropertyOp setter, uintN attrs)
|
||||||
{
|
{
|
||||||
uint32 i = 0; // init to shut GCC up
|
|
||||||
JSBool isIndex;
|
|
||||||
|
|
||||||
if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
|
if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
|
|
||||||
isIndex = js_IdIsIndex(id, &i);
|
if (!obj->isDenseArray())
|
||||||
if (!isIndex || attrs != JSPROP_ENUMERATE) {
|
|
||||||
if (!ENSURE_SLOW_ARRAY(cx, obj))
|
|
||||||
return JS_FALSE;
|
|
||||||
return js_DefineProperty(cx, obj, id, value, getter, setter, attrs);
|
return js_DefineProperty(cx, obj, id, value, getter, setter, attrs);
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value tmp = *value;
|
if (i >= obj->getArrayLength())
|
||||||
return array_setProperty(cx, obj, id, &tmp, false);
|
obj->setArrayLength(i + 1);
|
||||||
|
obj->setDenseArrayElement(i, *value);
|
||||||
|
return true;
|
||||||
|
} while (false);
|
||||||
|
|
||||||
|
if (!obj->makeDenseArraySlow(cx))
|
||||||
|
return false;
|
||||||
|
return js_DefineProperty(cx, obj, id, value, getter, setter, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSBool
|
static JSBool
|
||||||
|
@ -1149,12 +1163,13 @@ array_toSource(JSContext *cx, uintN argc, Value *vp)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
vp->setString(str);
|
vp->setString(str);
|
||||||
const jschar *chars;
|
|
||||||
size_t charlen;
|
const jschar *chars = str->getChars(cx);
|
||||||
str->getCharsAndLength(chars, charlen);
|
if (!chars)
|
||||||
|
goto out;
|
||||||
|
|
||||||
/* Append element to buffer. */
|
/* Append element to buffer. */
|
||||||
if (!cb.append(chars, charlen))
|
if (!cb.append(chars, chars + str->length()))
|
||||||
goto out;
|
goto out;
|
||||||
if (index + 1 != length) {
|
if (index + 1 != length) {
|
||||||
if (!js_AppendLiteral(cb, ", "))
|
if (!js_AppendLiteral(cb, ", "))
|
||||||
|
@ -1188,6 +1203,20 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
|
||||||
{
|
{
|
||||||
JS_CHECK_RECURSION(cx, return false);
|
JS_CHECK_RECURSION(cx, return false);
|
||||||
|
|
||||||
|
/* Get characters to use for the separator. */
|
||||||
|
static const jschar comma = ',';
|
||||||
|
const jschar *sep;
|
||||||
|
size_t seplen;
|
||||||
|
if (sepstr) {
|
||||||
|
seplen = sepstr->length();
|
||||||
|
sep = sepstr->getChars(cx);
|
||||||
|
if (!sep)
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
sep = ,
|
||||||
|
seplen = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Use HashTable entry as the cycle indicator. On first visit, create the
|
* Use HashTable entry as the cycle indicator. On first visit, create the
|
||||||
* entry, and, when leaving, remove the entry.
|
* entry, and, when leaving, remove the entry.
|
||||||
|
@ -1197,10 +1226,8 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
|
||||||
uint32 genBefore;
|
uint32 genBefore;
|
||||||
if (!hashp) {
|
if (!hashp) {
|
||||||
/* Not in hash table, so not a cycle. */
|
/* Not in hash table, so not a cycle. */
|
||||||
if (!cx->busyArrays.add(hashp, obj)) {
|
if (!cx->busyArrays.add(hashp, obj))
|
||||||
JS_ReportOutOfMemory(cx);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
genBefore = cx->busyArrays.generation();
|
genBefore = cx->busyArrays.generation();
|
||||||
} else {
|
} else {
|
||||||
/* Cycle, so return empty string. */
|
/* Cycle, so return empty string. */
|
||||||
|
@ -1214,17 +1241,6 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
|
||||||
MUST_FLOW_THROUGH("out");
|
MUST_FLOW_THROUGH("out");
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
|
|
||||||
/* Get characters to use for the separator. */
|
|
||||||
static const jschar comma = ',';
|
|
||||||
const jschar *sep;
|
|
||||||
size_t seplen;
|
|
||||||
if (sepstr) {
|
|
||||||
sepstr->getCharsAndLength(sep, seplen);
|
|
||||||
} else {
|
|
||||||
sep = ,
|
|
||||||
seplen = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This object will take responsibility for the jschar buffer until the
|
* This object will take responsibility for the jschar buffer until the
|
||||||
* buffer is transferred to the returned JSString.
|
* buffer is transferred to the returned JSString.
|
||||||
|
@ -1710,15 +1726,10 @@ comparator_stack_cast(JSRedComparator func)
|
||||||
static int
|
static int
|
||||||
sort_compare_strings(void *arg, const void *a, const void *b, int *result)
|
sort_compare_strings(void *arg, const void *a, const void *b, int *result)
|
||||||
{
|
{
|
||||||
const Value *av = (const Value *)a, *bv = (const Value *)b;
|
JSContext *cx = (JSContext *)arg;
|
||||||
|
JSString *astr = ((const Value *)a)->toString();
|
||||||
JS_ASSERT(av->isString());
|
JSString *bstr = ((const Value *)b)->toString();
|
||||||
JS_ASSERT(bv->isString());
|
return JS_CHECK_OPERATION_LIMIT(cx) && CompareStrings(cx, astr, bstr, result);
|
||||||
if (!JS_CHECK_OPERATION_LIMIT((JSContext *)arg))
|
|
||||||
return JS_FALSE;
|
|
||||||
|
|
||||||
*result = (int) js_CompareStrings(av->toString(), bv->toString());
|
|
||||||
return JS_TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JSBool
|
JSBool
|
||||||
|
@ -2615,10 +2626,15 @@ array_indexOfHelper(JSContext *cx, JSBool isLast, uintN argc, Value *vp)
|
||||||
!GetElement(cx, obj, (jsuint)i, &hole, vp)) {
|
!GetElement(cx, obj, (jsuint)i, &hole, vp)) {
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
if (!hole && StrictlyEqual(cx, *vp, tosearch)) {
|
if (!hole) {
|
||||||
|
JSBool equal;
|
||||||
|
if (!StrictlyEqual(cx, *vp, tosearch, &equal))
|
||||||
|
return JS_FALSE;
|
||||||
|
if (equal) {
|
||||||
vp->setNumber(i);
|
vp->setNumber(i);
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (i == stop)
|
if (i == stop)
|
||||||
goto not_found;
|
goto not_found;
|
||||||
i += direction;
|
i += direction;
|
||||||
|
|
|
@ -44,7 +44,9 @@
|
||||||
*/
|
*/
|
||||||
#include "jsprvtd.h"
|
#include "jsprvtd.h"
|
||||||
#include "jspubtd.h"
|
#include "jspubtd.h"
|
||||||
|
#include "jsatom.h"
|
||||||
#include "jsobj.h"
|
#include "jsobj.h"
|
||||||
|
#include "jsstr.h"
|
||||||
|
|
||||||
/* Small arrays are dense, no matter what. */
|
/* Small arrays are dense, no matter what. */
|
||||||
const uintN MIN_SPARSE_INDEX = 256;
|
const uintN MIN_SPARSE_INDEX = 256;
|
||||||
|
@ -86,8 +88,8 @@ JSObject::ensureDenseArrayElements(JSContext *cx, uintN index, uintN extra)
|
||||||
return growSlots(cx, requiredCapacity) ? ED_OK : ED_FAILED;
|
return growSlots(cx, requiredCapacity) ? ED_OK : ED_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern JSBool
|
extern bool
|
||||||
js_StringIsIndex(JSString *str, jsuint *indexp);
|
js_StringIsIndex(JSLinearString *str, jsuint *indexp);
|
||||||
|
|
||||||
inline JSBool
|
inline JSBool
|
||||||
js_IdIsIndex(jsid id, jsuint *indexp)
|
js_IdIsIndex(jsid id, jsuint *indexp)
|
||||||
|
@ -104,26 +106,36 @@ js_IdIsIndex(jsid id, jsuint *indexp)
|
||||||
if (JS_UNLIKELY(!JSID_IS_STRING(id)))
|
if (JS_UNLIKELY(!JSID_IS_STRING(id)))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
return js_StringIsIndex(JSID_TO_STRING(id), indexp);
|
return js_StringIsIndex(JSID_TO_ATOM(id), indexp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XML really wants to pretend jsvals are jsids. */
|
/* XML really wants to pretend jsvals are jsids. */
|
||||||
inline JSBool
|
inline bool
|
||||||
js_IdValIsIndex(jsval id, jsuint *indexp)
|
js_IdValIsIndex(JSContext *cx, jsval id, jsuint *indexp, bool *isIndex)
|
||||||
{
|
{
|
||||||
if (JSVAL_IS_INT(id)) {
|
if (JSVAL_IS_INT(id)) {
|
||||||
jsint i;
|
jsint i;
|
||||||
i = JSVAL_TO_INT(id);
|
i = JSVAL_TO_INT(id);
|
||||||
if (i < 0)
|
if (i < 0) {
|
||||||
return JS_FALSE;
|
*isIndex = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
*indexp = (jsuint)i;
|
*indexp = (jsuint)i;
|
||||||
return JS_TRUE;
|
*isIndex = true;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!JSVAL_IS_STRING(id))
|
if (!JSVAL_IS_STRING(id)) {
|
||||||
return JS_FALSE;
|
*isIndex = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return js_StringIsIndex(JSVAL_TO_STRING(id), indexp);
|
JSLinearString *str = JSVAL_TO_STRING(id)->ensureLinear(cx);
|
||||||
|
if (!str)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*isIndex = js_StringIsIndex(str, indexp);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern js::Class js_ArrayClass, js_SlowArrayClass;
|
extern js::Class js_ArrayClass, js_SlowArrayClass;
|
||||||
|
|
|
@ -457,17 +457,20 @@ js_SweepAtomState(JSContext *cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
JSAtom *
|
JSAtom *
|
||||||
js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
|
js_AtomizeString(JSContext *cx, JSString *strArg, uintN flags)
|
||||||
{
|
{
|
||||||
JS_ASSERT(!(flags & ~(ATOM_PINNED|ATOM_INTERNED|ATOM_TMPSTR|ATOM_NOCOPY)));
|
JS_ASSERT(!(flags & ~(ATOM_PINNED|ATOM_INTERNED|ATOM_TMPSTR|ATOM_NOCOPY)));
|
||||||
JS_ASSERT_IF(flags & ATOM_NOCOPY, flags & ATOM_TMPSTR);
|
JS_ASSERT_IF(flags & ATOM_NOCOPY, flags & ATOM_TMPSTR);
|
||||||
|
|
||||||
if (str->isAtomized())
|
if (strArg->isAtomized())
|
||||||
return STRING_TO_ATOM(str);
|
return STRING_TO_ATOM(strArg);
|
||||||
|
|
||||||
const jschar *chars;
|
JSLinearString *str = strArg->ensureLinear(cx);
|
||||||
size_t length;
|
if (!str)
|
||||||
str->getCharsAndLength(chars, length);
|
return NULL;
|
||||||
|
|
||||||
|
const jschar *chars = str->chars();
|
||||||
|
size_t length = str->length();
|
||||||
|
|
||||||
JSString *staticStr = JSString::lookupStaticString(chars, length);
|
JSString *staticStr = JSString::lookupStaticString(chars, length);
|
||||||
if (staticStr)
|
if (staticStr)
|
||||||
|
@ -482,7 +485,7 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
|
||||||
/* Hashing the string should have flattened it if it was a rope. */
|
/* Hashing the string should have flattened it if it was a rope. */
|
||||||
JS_ASSERT(str->isFlat() || str->isDependent());
|
JS_ASSERT(str->isFlat() || str->isDependent());
|
||||||
|
|
||||||
JSString *key;
|
JSLinearString *key;
|
||||||
if (p) {
|
if (p) {
|
||||||
key = AtomEntryToKey(*p);
|
key = AtomEntryToKey(*p);
|
||||||
} else {
|
} else {
|
||||||
|
@ -506,15 +509,14 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
|
||||||
} else {
|
} else {
|
||||||
if (needNewString) {
|
if (needNewString) {
|
||||||
SwitchToCompartment sc(cx, cx->runtime->defaultCompartment);
|
SwitchToCompartment sc(cx, cx->runtime->defaultCompartment);
|
||||||
jschar *chars = str->chars();
|
|
||||||
if (flags & ATOM_NOCOPY) {
|
if (flags & ATOM_NOCOPY) {
|
||||||
key = js_NewString(cx, chars, length);
|
key = js_NewString(cx, const_cast<jschar *>(str->flatChars()), length);
|
||||||
if (!key)
|
if (!key)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Finish handing off chars to the GC'ed key string. */
|
/* Finish handing off chars to the GC'ed key string. */
|
||||||
JS_ASSERT(flags & ATOM_TMPSTR);
|
JS_ASSERT(flags & ATOM_TMPSTR);
|
||||||
str->mChars = NULL;
|
str->u.chars = NULL;
|
||||||
} else {
|
} else {
|
||||||
key = js_NewStringCopyN(cx, chars, length);
|
key = js_NewStringCopyN(cx, chars, length);
|
||||||
if (!key)
|
if (!key)
|
||||||
|
@ -537,7 +539,6 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
|
||||||
|
|
||||||
AddAtomEntryFlags(*p, flags & (ATOM_PINNED | ATOM_INTERNED));
|
AddAtomEntryFlags(*p, flags & (ATOM_PINNED | ATOM_INTERNED));
|
||||||
|
|
||||||
JS_ASSERT(key->isAtomized());
|
|
||||||
JSAtom *atom = STRING_TO_ATOM(key);
|
JSAtom *atom = STRING_TO_ATOM(key);
|
||||||
return atom;
|
return atom;
|
||||||
}
|
}
|
||||||
|
@ -607,7 +608,7 @@ js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length)
|
||||||
state = &cx->runtime->atomState;
|
state = &cx->runtime->atomState;
|
||||||
|
|
||||||
JS_LOCK(cx, &state->lock);
|
JS_LOCK(cx, &state->lock);
|
||||||
AtomSet::Ptr p = state->atoms.lookup(&str);
|
AtomSet::Ptr p = state->atoms.lookup(str.assertIsFlat());
|
||||||
str2 = p ? AtomEntryToKey(*p) : NULL;
|
str2 = p ? AtomEntryToKey(*p) : NULL;
|
||||||
JS_UNLOCK(cx, &state->lock);
|
JS_UNLOCK(cx, &state->lock);
|
||||||
|
|
||||||
|
@ -628,7 +629,7 @@ js_DumpAtoms(JSContext *cx, FILE *fp)
|
||||||
if (entry == 0) {
|
if (entry == 0) {
|
||||||
fputs("<uninitialized>", fp);
|
fputs("<uninitialized>", fp);
|
||||||
} else {
|
} else {
|
||||||
JSString *key = AtomEntryToKey(entry);
|
JSAtom *key = AtomEntryToKey(entry);
|
||||||
FileEscapedString(fp, key, '"');
|
FileEscapedString(fp, key, '"');
|
||||||
uintN flags = AtomEntryFlags(entry);
|
uintN flags = AtomEntryFlags(entry);
|
||||||
if (flags != 0) {
|
if (flags != 0) {
|
||||||
|
|
|
@ -60,7 +60,7 @@
|
||||||
|
|
||||||
#define STRING_TO_ATOM(str) (JS_ASSERT(str->isAtomized()), \
|
#define STRING_TO_ATOM(str) (JS_ASSERT(str->isAtomized()), \
|
||||||
(JSAtom *)str)
|
(JSAtom *)str)
|
||||||
#define ATOM_TO_STRING(atom) ((JSString *)(atom))
|
#define ATOM_TO_STRING(atom) (atom)
|
||||||
#define ATOM_TO_JSVAL(atom) STRING_TO_JSVAL(ATOM_TO_STRING(atom))
|
#define ATOM_TO_JSVAL(atom) STRING_TO_JSVAL(ATOM_TO_STRING(atom))
|
||||||
|
|
||||||
/* Engine-internal extensions of jsid */
|
/* Engine-internal extensions of jsid */
|
||||||
|
@ -265,23 +265,23 @@ JS_STATIC_ASSERT(ATOM_ENTRY_FLAG_MASK < JS_GCTHING_ALIGN);
|
||||||
|
|
||||||
typedef uintptr_t AtomEntryType;
|
typedef uintptr_t AtomEntryType;
|
||||||
|
|
||||||
static JS_ALWAYS_INLINE JSString *
|
static JS_ALWAYS_INLINE JSAtom *
|
||||||
AtomEntryToKey(AtomEntryType entry)
|
AtomEntryToKey(AtomEntryType entry)
|
||||||
{
|
{
|
||||||
JS_ASSERT(entry != 0);
|
JS_ASSERT(entry != 0);
|
||||||
return (JSString *)(entry & ~ATOM_ENTRY_FLAG_MASK);
|
return (JSAtom *)(entry & ~ATOM_ENTRY_FLAG_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AtomHasher
|
struct AtomHasher
|
||||||
{
|
{
|
||||||
typedef JSString *Lookup;
|
typedef JSLinearString *Lookup;
|
||||||
|
|
||||||
static HashNumber hash(JSString *str) {
|
static HashNumber hash(JSLinearString *str) {
|
||||||
return js_HashString(str);
|
return js_HashString(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool match(AtomEntryType entry, JSString *lookup) {
|
static bool match(AtomEntryType entry, JSLinearString *lookup) {
|
||||||
return entry ? js_EqualStrings(AtomEntryToKey(entry), lookup) : false;
|
return entry ? EqualStrings(AtomEntryToKey(entry), lookup) : false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -120,11 +120,11 @@ bool_valueOf(JSContext *cx, uintN argc, Value *vp)
|
||||||
|
|
||||||
static JSFunctionSpec boolean_methods[] = {
|
static JSFunctionSpec boolean_methods[] = {
|
||||||
#if JS_HAS_TOSOURCE
|
#if JS_HAS_TOSOURCE
|
||||||
JS_FN(js_toSource_str, bool_toSource, 0, JSFUN_PRIMITIVE_THIS),
|
JS_FN(js_toSource_str, bool_toSource, 0, 0),
|
||||||
#endif
|
#endif
|
||||||
JS_FN(js_toString_str, bool_toString, 0, JSFUN_PRIMITIVE_THIS),
|
JS_FN(js_toString_str, bool_toString, 0, 0),
|
||||||
JS_FN(js_valueOf_str, bool_valueOf, 0, JSFUN_PRIMITIVE_THIS),
|
JS_FN(js_valueOf_str, bool_valueOf, 0, 0),
|
||||||
JS_FN(js_toJSON_str, bool_valueOf, 0, JSFUN_PRIMITIVE_THIS),
|
JS_FN(js_toJSON_str, bool_valueOf, 0, 0),
|
||||||
JS_FS_END
|
JS_FS_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -168,18 +168,22 @@ js_DoubleToUint32(jsdouble d)
|
||||||
JS_DEFINE_CALLINFO_1(extern, UINT32, js_DoubleToUint32, DOUBLE, 1, ACCSET_NONE)
|
JS_DEFINE_CALLINFO_1(extern, UINT32, js_DoubleToUint32, DOUBLE, 1, ACCSET_NONE)
|
||||||
|
|
||||||
jsdouble FASTCALL
|
jsdouble FASTCALL
|
||||||
js_StringToNumber(JSContext* cx, JSString* str)
|
js_StringToNumber(JSContext* cx, JSString* str, JSBool *ok)
|
||||||
{
|
{
|
||||||
return StringToNumberType<jsdouble>(cx, str);
|
double out = 0; /* silence warnings. */
|
||||||
|
*ok = StringToNumberType<jsdouble>(cx, str, &out);
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
JS_DEFINE_CALLINFO_2(extern, DOUBLE, js_StringToNumber, CONTEXT, STRING, 1, ACCSET_NONE)
|
JS_DEFINE_CALLINFO_3(extern, DOUBLE, js_StringToNumber, CONTEXT, STRING, BOOLPTR, 1, ACCSET_NONE)
|
||||||
|
|
||||||
int32 FASTCALL
|
int32 FASTCALL
|
||||||
js_StringToInt32(JSContext* cx, JSString* str)
|
js_StringToInt32(JSContext* cx, JSString* str, JSBool *ok)
|
||||||
{
|
{
|
||||||
return StringToNumberType<int32>(cx, str);
|
int32 out = 0; /* silence warnings. */
|
||||||
|
*ok = StringToNumberType<int32>(cx, str, &out);
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
JS_DEFINE_CALLINFO_2(extern, INT32, js_StringToInt32, CONTEXT, STRING, 1, ACCSET_NONE)
|
JS_DEFINE_CALLINFO_3(extern, INT32, js_StringToInt32, CONTEXT, STRING, BOOLPTR, 1, ACCSET_NONE)
|
||||||
|
|
||||||
/* Nb: it's always safe to set isDefinitelyAtom to false if you're unsure or don't know. */
|
/* Nb: it's always safe to set isDefinitelyAtom to false if you're unsure or don't know. */
|
||||||
static inline JSBool
|
static inline JSBool
|
||||||
|
|
|
@ -547,7 +547,7 @@ struct ClosureVarInfo;
|
||||||
#define _JS_DEFINE_CALLINFO_n(n, args) JS_DEFINE_CALLINFO_##n args
|
#define _JS_DEFINE_CALLINFO_n(n, args) JS_DEFINE_CALLINFO_##n args
|
||||||
|
|
||||||
jsdouble FASTCALL
|
jsdouble FASTCALL
|
||||||
js_StringToNumber(JSContext* cx, JSString* str);
|
js_StringToNumber(JSContext* cx, JSString* str, JSBool *ok);
|
||||||
|
|
||||||
/* Extern version of SetBuiltinError. */
|
/* Extern version of SetBuiltinError. */
|
||||||
extern JS_FRIEND_API(void)
|
extern JS_FRIEND_API(void)
|
||||||
|
@ -623,9 +623,9 @@ JS_DECLARE_CALLINFO(js_CloneRegExpObject)
|
||||||
|
|
||||||
/* Defined in jsstr.cpp. */
|
/* Defined in jsstr.cpp. */
|
||||||
JS_DECLARE_CALLINFO(js_String_tn)
|
JS_DECLARE_CALLINFO(js_String_tn)
|
||||||
JS_DECLARE_CALLINFO(js_CompareStrings)
|
JS_DECLARE_CALLINFO(js_CompareStringsOnTrace)
|
||||||
JS_DECLARE_CALLINFO(js_ConcatStrings)
|
JS_DECLARE_CALLINFO(js_ConcatStrings)
|
||||||
JS_DECLARE_CALLINFO(js_EqualStrings)
|
JS_DECLARE_CALLINFO(js_EqualStringsOnTrace)
|
||||||
JS_DECLARE_CALLINFO(js_Flatten)
|
JS_DECLARE_CALLINFO(js_Flatten)
|
||||||
|
|
||||||
/* Defined in jstypedarray.cpp. */
|
/* Defined in jstypedarray.cpp. */
|
||||||
|
|
|
@ -350,9 +350,10 @@ JS_STATIC_ASSERT(JSString::MAX_LENGTH < UINT32_MAX);
|
||||||
bool
|
bool
|
||||||
JSStructuredCloneWriter::writeString(uint32_t tag, JSString *str)
|
JSStructuredCloneWriter::writeString(uint32_t tag, JSString *str)
|
||||||
{
|
{
|
||||||
const jschar *chars;
|
size_t length = str->length();
|
||||||
size_t length;
|
const jschar *chars = str->getChars(context());
|
||||||
str->getCharsAndLength(chars, length);
|
if (!chars)
|
||||||
|
return false;
|
||||||
return out.writePair(tag, uint32_t(length)) && out.writeChars(chars, length);
|
return out.writePair(tag, uint32_t(length)) && out.writeChars(chars, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -750,9 +751,10 @@ JSStructuredCloneReader::startRead(Value *vp)
|
||||||
JSString *str = readString(nchars);
|
JSString *str = readString(nchars);
|
||||||
if (!str)
|
if (!str)
|
||||||
return false;
|
return false;
|
||||||
const jschar *chars;
|
size_t length = str->length();
|
||||||
size_t length;
|
const jschar *chars = str->getChars(context());
|
||||||
str->getCharsAndLength(chars, length);
|
if (!chars)
|
||||||
|
return false;
|
||||||
JSObject *obj = RegExp::createObjectNoStatics(context(), chars, length, data);
|
JSObject *obj = RegExp::createObjectNoStatics(context(), chars, length, data);
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -494,49 +494,28 @@ JSThreadData::init()
|
||||||
#endif
|
#endif
|
||||||
if (!stackSpace.init())
|
if (!stackSpace.init())
|
||||||
return false;
|
return false;
|
||||||
#ifdef JS_TRACER
|
|
||||||
if (!InitJIT(&traceMonitor)) {
|
|
||||||
finish();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
dtoaState = js_NewDtoaState();
|
dtoaState = js_NewDtoaState();
|
||||||
if (!dtoaState) {
|
if (!dtoaState) {
|
||||||
finish();
|
finish();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
nativeStackBase = GetNativeStackBase();
|
nativeStackBase = GetNativeStackBase();
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
MathCache *
|
/* Set the default size for the code cache to 16MB. */
|
||||||
JSThreadData::allocMathCache(JSContext *cx)
|
maxCodeCacheBytes = 16 * 1024 * 1024;
|
||||||
{
|
|
||||||
JS_ASSERT(!mathCache);
|
return true;
|
||||||
mathCache = new MathCache;
|
|
||||||
if (!mathCache)
|
|
||||||
js_ReportOutOfMemory(cx);
|
|
||||||
return mathCache;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
JSThreadData::finish()
|
JSThreadData::finish()
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
|
||||||
for (size_t i = 0; i != JS_ARRAY_LENGTH(scriptsToGC); ++i)
|
|
||||||
JS_ASSERT(!scriptsToGC[i]);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (dtoaState)
|
if (dtoaState)
|
||||||
js_DestroyDtoaState(dtoaState);
|
js_DestroyDtoaState(dtoaState);
|
||||||
|
|
||||||
js_FinishGSNCache(&gsnCache);
|
js_FinishGSNCache(&gsnCache);
|
||||||
propertyCache.~PropertyCache();
|
propertyCache.~PropertyCache();
|
||||||
#if defined JS_TRACER
|
|
||||||
FinishJIT(&traceMonitor);
|
|
||||||
#endif
|
|
||||||
stackSpace.finish();
|
stackSpace.finish();
|
||||||
delete mathCache;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -553,22 +532,6 @@ JSThreadData::purge(JSContext *cx)
|
||||||
/* FIXME: bug 506341. */
|
/* FIXME: bug 506341. */
|
||||||
propertyCache.purge(cx);
|
propertyCache.purge(cx);
|
||||||
|
|
||||||
#ifdef JS_TRACER
|
|
||||||
/*
|
|
||||||
* If we are about to regenerate shapes, we have to flush the JIT cache,
|
|
||||||
* which will eventually abort any current recording.
|
|
||||||
*/
|
|
||||||
if (cx->runtime->gcRegenShapes)
|
|
||||||
traceMonitor.needFlush = JS_TRUE;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Destroy eval'ed scripts. */
|
|
||||||
js_DestroyScriptsToGC(cx, this);
|
|
||||||
|
|
||||||
/* Purge cached native iterators. */
|
|
||||||
memset(cachedNativeIterators, 0, sizeof(cachedNativeIterators));
|
|
||||||
lastNativeIterator = NULL;
|
|
||||||
|
|
||||||
dtoaCache.s = NULL;
|
dtoaCache.s = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -736,7 +699,6 @@ js_PurgeThreads(JSContext *cx)
|
||||||
|
|
||||||
if (JS_CLIST_IS_EMPTY(&thread->contextList)) {
|
if (JS_CLIST_IS_EMPTY(&thread->contextList)) {
|
||||||
JS_ASSERT(cx->thread != thread);
|
JS_ASSERT(cx->thread != thread);
|
||||||
js_DestroyScriptsToGC(cx, &thread->data);
|
|
||||||
|
|
||||||
DestroyThread(thread);
|
DestroyThread(thread);
|
||||||
e.removeFront();
|
e.removeFront();
|
||||||
|
@ -921,7 +883,7 @@ DumpEvalCacheMeter(JSContext *cx)
|
||||||
EVAL_CACHE_METER_LIST(frob)
|
EVAL_CACHE_METER_LIST(frob)
|
||||||
#undef frob
|
#undef frob
|
||||||
};
|
};
|
||||||
JSEvalCacheMeter *ecm = &JS_THREAD_DATA(cx)->evalCacheMeter;
|
JSEvalCacheMeter *ecm = &cx->compartment->evalCacheMeter;
|
||||||
|
|
||||||
static JSAutoFile fp;
|
static JSAutoFile fp;
|
||||||
if (!fp && !fp.open(filename, "w"))
|
if (!fp && !fp.open(filename, "w"))
|
||||||
|
@ -2316,6 +2278,15 @@ JSContext::updateJITEnabled()
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
|
JS_FORCES_STACK JS_FRIEND_API(void)
|
||||||
|
LeaveTrace(JSContext *cx)
|
||||||
|
{
|
||||||
|
#ifdef JS_TRACER
|
||||||
|
if (JS_ON_TRACE(cx))
|
||||||
|
DeepBail(cx);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SetPendingException(JSContext *cx, const Value &v)
|
SetPendingException(JSContext *cx, const Value &v)
|
||||||
{
|
{
|
||||||
|
|
246
js/src/jscntxt.h
246
js/src/jscntxt.h
|
@ -884,147 +884,6 @@ private:
|
||||||
JSStackFrame *curfp;
|
JSStackFrame *curfp;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Holds the number of recording attemps for an address. */
|
|
||||||
typedef HashMap<jsbytecode*,
|
|
||||||
size_t,
|
|
||||||
DefaultHasher<jsbytecode*>,
|
|
||||||
SystemAllocPolicy> RecordAttemptMap;
|
|
||||||
|
|
||||||
/* Holds the profile data for loops. */
|
|
||||||
typedef HashMap<jsbytecode*,
|
|
||||||
LoopProfile*,
|
|
||||||
DefaultHasher<jsbytecode*>,
|
|
||||||
SystemAllocPolicy> LoopProfileMap;
|
|
||||||
|
|
||||||
class Oracle;
|
|
||||||
|
|
||||||
typedef HashSet<JSScript *,
|
|
||||||
DefaultHasher<JSScript *>,
|
|
||||||
SystemAllocPolicy> TracedScriptSet;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Trace monitor. Every JSThread (if JS_THREADSAFE) or JSRuntime (if not
|
|
||||||
* JS_THREADSAFE) has an associated trace monitor that keeps track of loop
|
|
||||||
* frequencies for all JavaScript code loaded into that runtime.
|
|
||||||
*/
|
|
||||||
struct TraceMonitor {
|
|
||||||
/*
|
|
||||||
* The context currently executing JIT-compiled code on this thread, or
|
|
||||||
* NULL if none. Among other things, this can in certain cases prevent
|
|
||||||
* last-ditch GC and suppress calls to JS_ReportOutOfMemory.
|
|
||||||
*
|
|
||||||
* !tracecx && !recorder: not on trace
|
|
||||||
* !tracecx && recorder: recording
|
|
||||||
* tracecx && !recorder: executing a trace
|
|
||||||
* tracecx && recorder: executing inner loop, recording outer loop
|
|
||||||
*/
|
|
||||||
JSContext *tracecx;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Cached storage to use when executing on trace. While we may enter nested
|
|
||||||
* traces, we always reuse the outer trace's storage, so never need more
|
|
||||||
* than of these.
|
|
||||||
*/
|
|
||||||
TraceNativeStorage *storage;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* There are 4 allocators here. This might seem like overkill, but they
|
|
||||||
* have different lifecycles, and by keeping them separate we keep the
|
|
||||||
* amount of retained memory down significantly. They are flushed (ie.
|
|
||||||
* all the allocated memory is freed) periodically.
|
|
||||||
*
|
|
||||||
* - dataAlloc has the lifecycle of the monitor. It's flushed only when
|
|
||||||
* the monitor is flushed. It's used for fragments.
|
|
||||||
*
|
|
||||||
* - traceAlloc has the same flush lifecycle as the dataAlloc, but it is
|
|
||||||
* also *marked* when a recording starts and rewinds to the mark point
|
|
||||||
* if recording aborts. So you can put things in it that are only
|
|
||||||
* reachable on a successful record/compile cycle like GuardRecords and
|
|
||||||
* SideExits.
|
|
||||||
*
|
|
||||||
* - tempAlloc is flushed after each recording, successful or not. It's
|
|
||||||
* used to store LIR code and for all other elements in the LIR
|
|
||||||
* pipeline.
|
|
||||||
*
|
|
||||||
* - codeAlloc has the same lifetime as dataAlloc, but its API is
|
|
||||||
* different (CodeAlloc vs. VMAllocator). It's used for native code.
|
|
||||||
* It's also a good idea to keep code and data separate to avoid I-cache
|
|
||||||
* vs. D-cache issues.
|
|
||||||
*/
|
|
||||||
VMAllocator* dataAlloc;
|
|
||||||
VMAllocator* traceAlloc;
|
|
||||||
VMAllocator* tempAlloc;
|
|
||||||
nanojit::CodeAlloc* codeAlloc;
|
|
||||||
nanojit::Assembler* assembler;
|
|
||||||
FrameInfoCache* frameCache;
|
|
||||||
|
|
||||||
/* This gets incremented every time the monitor is flushed. */
|
|
||||||
uintN flushEpoch;
|
|
||||||
|
|
||||||
Oracle* oracle;
|
|
||||||
TraceRecorder* recorder;
|
|
||||||
|
|
||||||
/* If we are profiling a loop, this tracks the current profile. Otherwise NULL. */
|
|
||||||
LoopProfile* profile;
|
|
||||||
|
|
||||||
GlobalState globalStates[MONITOR_N_GLOBAL_STATES];
|
|
||||||
TreeFragment* vmfragments[FRAGMENT_TABLE_SIZE];
|
|
||||||
RecordAttemptMap* recordAttempts;
|
|
||||||
|
|
||||||
/* A hashtable mapping PC values to loop profiles for those loops. */
|
|
||||||
LoopProfileMap* loopProfiles;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Maximum size of the code cache before we start flushing. 1/16 of this
|
|
||||||
* size is used as threshold for the regular expression code cache.
|
|
||||||
*/
|
|
||||||
uint32 maxCodeCacheBytes;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If nonzero, do not flush the JIT cache after a deep bail. That would
|
|
||||||
* free JITted code pages that we will later return to. Instead, set the
|
|
||||||
* needFlush flag so that it can be flushed later.
|
|
||||||
*/
|
|
||||||
JSBool needFlush;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Fragment map for the regular expression compiler.
|
|
||||||
*/
|
|
||||||
REHashMap* reFragments;
|
|
||||||
|
|
||||||
// Cached temporary typemap to avoid realloc'ing every time we create one.
|
|
||||||
// This must be used in only one place at a given time. It must be cleared
|
|
||||||
// before use.
|
|
||||||
TypeMap* cachedTempTypeMap;
|
|
||||||
|
|
||||||
/* Scripts with recorded fragments. */
|
|
||||||
TracedScriptSet tracedScripts;
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
/* Fields needed for fragment/guard profiling. */
|
|
||||||
nanojit::Seq<nanojit::Fragment*>* branches;
|
|
||||||
uint32 lastFragID;
|
|
||||||
/*
|
|
||||||
* profAlloc has a lifetime which spans exactly from js_InitJIT to
|
|
||||||
* js_FinishJIT.
|
|
||||||
*/
|
|
||||||
VMAllocator* profAlloc;
|
|
||||||
FragStatsMap* profTab;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool ontrace() const {
|
|
||||||
return !!tracecx;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Flush the JIT cache. */
|
|
||||||
void flush();
|
|
||||||
|
|
||||||
/* Sweep any cache entry pointing to dead GC things. */
|
|
||||||
void sweep();
|
|
||||||
|
|
||||||
bool outOfMemory() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
} /* namespace js */
|
} /* namespace js */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1038,23 +897,6 @@ struct TraceMonitor {
|
||||||
# define JS_ON_TRACE(cx) false
|
# define JS_ON_TRACE(cx) false
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Number of potentially reusable scriptsToGC to search for the eval cache. */
|
|
||||||
#ifndef JS_EVAL_CACHE_SHIFT
|
|
||||||
# define JS_EVAL_CACHE_SHIFT 6
|
|
||||||
#endif
|
|
||||||
#define JS_EVAL_CACHE_SIZE JS_BIT(JS_EVAL_CACHE_SHIFT)
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
# define EVAL_CACHE_METER_LIST(_) _(probe), _(hit), _(step), _(noscope)
|
|
||||||
# define identity(x) x
|
|
||||||
|
|
||||||
struct JSEvalCacheMeter {
|
|
||||||
uint64 EVAL_CACHE_METER_LIST(identity);
|
|
||||||
};
|
|
||||||
|
|
||||||
# undef identity
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
# define FUNCTION_KIND_METER_LIST(_) \
|
# define FUNCTION_KIND_METER_LIST(_) \
|
||||||
_(allfun), _(heavy), _(nofreeupvar), _(onlyfreevar), \
|
_(allfun), _(heavy), _(nofreeupvar), _(onlyfreevar), \
|
||||||
|
@ -1077,10 +919,6 @@ struct JSFunctionMeter {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define NATIVE_ITER_CACHE_LOG2 8
|
|
||||||
#define NATIVE_ITER_CACHE_MASK JS_BITMASK(NATIVE_ITER_CACHE_LOG2)
|
|
||||||
#define NATIVE_ITER_CACHE_SIZE JS_BIT(NATIVE_ITER_CACHE_LOG2)
|
|
||||||
|
|
||||||
struct JSPendingProxyOperation {
|
struct JSPendingProxyOperation {
|
||||||
JSPendingProxyOperation *next;
|
JSPendingProxyOperation *next;
|
||||||
JSObject *object;
|
JSObject *object;
|
||||||
|
@ -1118,18 +956,8 @@ struct JSThreadData {
|
||||||
js::PropertyCache propertyCache;
|
js::PropertyCache propertyCache;
|
||||||
|
|
||||||
#ifdef JS_TRACER
|
#ifdef JS_TRACER
|
||||||
/* Trace-tree JIT recorder/interpreter state. */
|
/* Maximum size of the tracer's code cache before we start flushing. */
|
||||||
js::TraceMonitor traceMonitor;
|
uint32 maxCodeCacheBytes;
|
||||||
|
|
||||||
/* Counts the number of iterations run by a trace. */
|
|
||||||
unsigned iterationCounter;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Lock-free hashed lists of scripts created by eval to garbage-collect. */
|
|
||||||
JSScript *scriptsToGC[JS_EVAL_CACHE_SIZE];
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
JSEvalCacheMeter evalCacheMeter;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* State used by dtoa.c. */
|
/* State used by dtoa.c. */
|
||||||
|
@ -1149,12 +977,6 @@ struct JSThreadData {
|
||||||
JSString *s; // if s==NULL, d and base are not valid
|
JSString *s; // if s==NULL, d and base are not valid
|
||||||
} dtoaCache;
|
} dtoaCache;
|
||||||
|
|
||||||
/* Cached native iterators. */
|
|
||||||
JSObject *cachedNativeIterators[NATIVE_ITER_CACHE_SIZE];
|
|
||||||
|
|
||||||
/* Native iterator most recently started. */
|
|
||||||
JSObject *lastNativeIterator;
|
|
||||||
|
|
||||||
/* Base address of the native stack for the current thread. */
|
/* Base address of the native stack for the current thread. */
|
||||||
jsuword *nativeStackBase;
|
jsuword *nativeStackBase;
|
||||||
|
|
||||||
|
@ -1163,16 +985,6 @@ struct JSThreadData {
|
||||||
|
|
||||||
js::ConservativeGCThreadData conservativeGC;
|
js::ConservativeGCThreadData conservativeGC;
|
||||||
|
|
||||||
private:
|
|
||||||
js::MathCache *mathCache;
|
|
||||||
|
|
||||||
js::MathCache *allocMathCache(JSContext *cx);
|
|
||||||
public:
|
|
||||||
|
|
||||||
js::MathCache *getMathCache(JSContext *cx) {
|
|
||||||
return mathCache ? mathCache : allocMathCache(cx);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool init();
|
bool init();
|
||||||
void finish();
|
void finish();
|
||||||
void mark(JSTracer *trc);
|
void mark(JSTracer *trc);
|
||||||
|
@ -1322,6 +1134,7 @@ struct JSRuntime {
|
||||||
uint32 gcNumber;
|
uint32 gcNumber;
|
||||||
js::GCMarker *gcMarkingTracer;
|
js::GCMarker *gcMarkingTracer;
|
||||||
uint32 gcTriggerFactor;
|
uint32 gcTriggerFactor;
|
||||||
|
int64 gcJitReleaseTime;
|
||||||
volatile JSBool gcIsNeeded;
|
volatile JSBool gcIsNeeded;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1369,7 +1182,7 @@ struct JSRuntime {
|
||||||
js::Value negativeInfinityValue;
|
js::Value negativeInfinityValue;
|
||||||
js::Value positiveInfinityValue;
|
js::Value positiveInfinityValue;
|
||||||
|
|
||||||
JSString *emptyString;
|
JSFlatString *emptyString;
|
||||||
|
|
||||||
/* List of active contexts sharing this runtime; protected by gcLock. */
|
/* List of active contexts sharing this runtime; protected by gcLock. */
|
||||||
JSCList contextList;
|
JSCList contextList;
|
||||||
|
@ -1725,14 +1538,6 @@ struct JSRuntime {
|
||||||
/* Common macros to access thread-local caches in JSThread or JSRuntime. */
|
/* Common macros to access thread-local caches in JSThread or JSRuntime. */
|
||||||
#define JS_GSN_CACHE(cx) (JS_THREAD_DATA(cx)->gsnCache)
|
#define JS_GSN_CACHE(cx) (JS_THREAD_DATA(cx)->gsnCache)
|
||||||
#define JS_PROPERTY_CACHE(cx) (JS_THREAD_DATA(cx)->propertyCache)
|
#define JS_PROPERTY_CACHE(cx) (JS_THREAD_DATA(cx)->propertyCache)
|
||||||
#define JS_TRACE_MONITOR(cx) (JS_THREAD_DATA(cx)->traceMonitor)
|
|
||||||
#define JS_SCRIPTS_TO_GC(cx) (JS_THREAD_DATA(cx)->scriptsToGC)
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
# define EVAL_CACHE_METER(x) (JS_THREAD_DATA(cx)->evalCacheMeter.x++)
|
|
||||||
#else
|
|
||||||
# define EVAL_CACHE_METER(x) ((void) 0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
# define JS_RUNTIME_METER(rt, which) JS_ATOMIC_INCREMENT(&(rt)->which)
|
# define JS_RUNTIME_METER(rt, which) JS_ATOMIC_INCREMENT(&(rt)->which)
|
||||||
|
@ -2370,7 +2175,6 @@ struct JSContext
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The allocation code calls the function to indicate either OOM failure
|
* The allocation code calls the function to indicate either OOM failure
|
||||||
* when p is null or that a memory pressure counter has reached some
|
* when p is null or that a memory pressure counter has reached some
|
||||||
|
@ -3238,50 +3042,14 @@ js_CurrentPCIsInImacro(JSContext *cx);
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
#ifdef JS_TRACER
|
|
||||||
/*
|
|
||||||
* Reconstruct the JS stack and clear cx->tracecx. We must be currently in a
|
|
||||||
* _FAIL builtin from trace on cx or another context on the same thread. The
|
|
||||||
* machine code for the trace remains on the C stack when js_DeepBail returns.
|
|
||||||
*
|
|
||||||
* Implemented in jstracer.cpp.
|
|
||||||
*/
|
|
||||||
JS_FORCES_STACK JS_FRIEND_API(void)
|
|
||||||
DeepBail(JSContext *cx);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static JS_FORCES_STACK JS_INLINE void
|
|
||||||
LeaveTrace(JSContext *cx)
|
|
||||||
{
|
|
||||||
#ifdef JS_TRACER
|
|
||||||
if (JS_ON_TRACE(cx))
|
|
||||||
DeepBail(cx);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static JS_INLINE void
|
|
||||||
LeaveTraceIfGlobalObject(JSContext *cx, JSObject *obj)
|
|
||||||
{
|
|
||||||
if (!obj->parent)
|
|
||||||
LeaveTrace(cx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static JS_INLINE JSBool
|
|
||||||
CanLeaveTrace(JSContext *cx)
|
|
||||||
{
|
|
||||||
JS_ASSERT(JS_ON_TRACE(cx));
|
|
||||||
#ifdef JS_TRACER
|
|
||||||
return cx->bailExit != NULL;
|
|
||||||
#else
|
|
||||||
return JS_FALSE;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
SetPendingException(JSContext *cx, const Value &v);
|
SetPendingException(JSContext *cx, const Value &v);
|
||||||
|
|
||||||
class RegExpStatics;
|
class RegExpStatics;
|
||||||
|
|
||||||
|
extern JS_FORCES_STACK JS_FRIEND_API(void)
|
||||||
|
LeaveTrace(JSContext *cx);
|
||||||
|
|
||||||
} /* namespace js */
|
} /* namespace js */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#define jscntxtinlines_h___
|
#define jscntxtinlines_h___
|
||||||
|
|
||||||
#include "jscntxt.h"
|
#include "jscntxt.h"
|
||||||
|
#include "jscompartment.h"
|
||||||
#include "jsparse.h"
|
#include "jsparse.h"
|
||||||
#include "jsstaticcheck.h"
|
#include "jsstaticcheck.h"
|
||||||
#include "jsxml.h"
|
#include "jsxml.h"
|
||||||
|
@ -753,6 +754,36 @@ CallSetter(JSContext *cx, JSObject *obj, jsid id, PropertyOp op, uintN attrs, ui
|
||||||
return CallJSPropertyOpSetter(cx, op, obj, id, vp);
|
return CallJSPropertyOpSetter(cx, op, obj, id, vp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef JS_TRACER
|
||||||
|
/*
|
||||||
|
* Reconstruct the JS stack and clear cx->tracecx. We must be currently in a
|
||||||
|
* _FAIL builtin from trace on cx or another context on the same thread. The
|
||||||
|
* machine code for the trace remains on the C stack when js_DeepBail returns.
|
||||||
|
*
|
||||||
|
* Implemented in jstracer.cpp.
|
||||||
|
*/
|
||||||
|
JS_FORCES_STACK JS_FRIEND_API(void)
|
||||||
|
DeepBail(JSContext *cx);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static JS_INLINE void
|
||||||
|
LeaveTraceIfGlobalObject(JSContext *cx, JSObject *obj)
|
||||||
|
{
|
||||||
|
if (!obj->parent)
|
||||||
|
LeaveTrace(cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static JS_INLINE JSBool
|
||||||
|
CanLeaveTrace(JSContext *cx)
|
||||||
|
{
|
||||||
|
JS_ASSERT(JS_ON_TRACE(cx));
|
||||||
|
#ifdef JS_TRACER
|
||||||
|
return cx->bailExit != NULL;
|
||||||
|
#else
|
||||||
|
return JS_FALSE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
} /* namespace js */
|
} /* namespace js */
|
||||||
|
|
||||||
#endif /* jscntxtinlines_h___ */
|
#endif /* jscntxtinlines_h___ */
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include "jsiter.h"
|
#include "jsiter.h"
|
||||||
#include "jsproxy.h"
|
#include "jsproxy.h"
|
||||||
#include "jsscope.h"
|
#include "jsscope.h"
|
||||||
|
#include "jstracer.h"
|
||||||
#include "methodjit/MethodJIT.h"
|
#include "methodjit/MethodJIT.h"
|
||||||
#include "methodjit/PolyIC.h"
|
#include "methodjit/PolyIC.h"
|
||||||
#include "methodjit/MonoIC.h"
|
#include "methodjit/MonoIC.h"
|
||||||
|
@ -54,17 +55,36 @@ using namespace js;
|
||||||
using namespace js::gc;
|
using namespace js::gc;
|
||||||
|
|
||||||
JSCompartment::JSCompartment(JSRuntime *rt)
|
JSCompartment::JSCompartment(JSRuntime *rt)
|
||||||
: rt(rt), principals(NULL), data(NULL), marked(false), debugMode(rt->debugMode),
|
: rt(rt),
|
||||||
anynameObject(NULL), functionNamespaceObject(NULL)
|
principals(NULL),
|
||||||
|
data(NULL),
|
||||||
|
marked(false),
|
||||||
|
active(false),
|
||||||
|
debugMode(rt->debugMode),
|
||||||
|
anynameObject(NULL),
|
||||||
|
functionNamespaceObject(NULL),
|
||||||
|
mathCache(NULL)
|
||||||
{
|
{
|
||||||
JS_INIT_CLIST(&scripts);
|
JS_INIT_CLIST(&scripts);
|
||||||
|
|
||||||
|
PodArrayZero(scriptsToGC);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSCompartment::~JSCompartment()
|
JSCompartment::~JSCompartment()
|
||||||
{
|
{
|
||||||
|
#if defined JS_TRACER
|
||||||
|
FinishJIT(&traceMonitor);
|
||||||
|
#endif
|
||||||
#ifdef JS_METHODJIT
|
#ifdef JS_METHODJIT
|
||||||
delete jaegerCompartment;
|
delete jaegerCompartment;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
delete mathCache;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
for (size_t i = 0; i != JS_ARRAY_LENGTH(scriptsToGC); ++i)
|
||||||
|
JS_ASSERT(!scriptsToGC[i]);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -81,9 +101,19 @@ JSCompartment::init()
|
||||||
if (!crossCompartmentWrappers.init())
|
if (!crossCompartmentWrappers.init())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
#ifdef JS_METHODJIT
|
#ifdef JS_TRACER
|
||||||
if (!(jaegerCompartment = new mjit::JaegerCompartment))
|
if (!InitJIT(&traceMonitor)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef JS_METHODJIT
|
||||||
|
if (!(jaegerCompartment = new mjit::JaegerCompartment)) {
|
||||||
|
#ifdef JS_TRACER
|
||||||
|
FinishJIT(&traceMonitor);
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return jaegerCompartment->Initialize();
|
return jaegerCompartment->Initialize();
|
||||||
#else
|
#else
|
||||||
return true;
|
return true;
|
||||||
|
@ -204,7 +234,10 @@ JSCompartment::wrap(JSContext *cx, Value *vp)
|
||||||
if (vp->isString()) {
|
if (vp->isString()) {
|
||||||
Value orig = *vp;
|
Value orig = *vp;
|
||||||
JSString *str = vp->toString();
|
JSString *str = vp->toString();
|
||||||
JSString *wrapped = js_NewStringCopyN(cx, str->chars(), str->length());
|
const jschar *chars = str->getChars(cx);
|
||||||
|
if (!chars)
|
||||||
|
return false;
|
||||||
|
JSString *wrapped = js_NewStringCopyN(cx, chars, str->length());
|
||||||
if (!wrapped)
|
if (!wrapped)
|
||||||
return false;
|
return false;
|
||||||
vp->setString(wrapped);
|
vp->setString(wrapped);
|
||||||
|
@ -328,8 +361,33 @@ JSCompartment::wrapException(JSContext *cx)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if the pool containing the code for jit should be destroyed, per the
|
||||||
|
* heuristics in JSCompartment::sweep.
|
||||||
|
*/
|
||||||
|
static inline bool
|
||||||
|
ScriptPoolDestroyed(JSContext *cx, mjit::JITScript *jit,
|
||||||
|
uint32 releaseInterval, uint32 &counter)
|
||||||
|
{
|
||||||
|
JSC::ExecutablePool *pool = jit->code.m_executablePool;
|
||||||
|
if (pool->m_gcNumber != cx->runtime->gcNumber) {
|
||||||
|
/*
|
||||||
|
* The m_destroy flag may have been set in a previous GC for a pool which had
|
||||||
|
* references we did not remove (e.g. from the compartment's ExecutableAllocator)
|
||||||
|
* and is still around. Forget we tried to destroy it in such cases.
|
||||||
|
*/
|
||||||
|
pool->m_destroy = false;
|
||||||
|
pool->m_gcNumber = cx->runtime->gcNumber;
|
||||||
|
if (--counter == 0) {
|
||||||
|
pool->m_destroy = true;
|
||||||
|
counter = releaseInterval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pool->m_destroy;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
JSCompartment::sweep(JSContext *cx)
|
JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
|
||||||
{
|
{
|
||||||
chunk = NULL;
|
chunk = NULL;
|
||||||
/* Remove dead wrappers from the table. */
|
/* Remove dead wrappers from the table. */
|
||||||
|
@ -343,13 +401,43 @@ JSCompartment::sweep(JSContext *cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef JS_TRACER
|
||||||
|
traceMonitor.sweep();
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined JS_METHODJIT && defined JS_MONOIC
|
#if defined JS_METHODJIT && defined JS_MONOIC
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The release interval is the frequency with which we should try to destroy
|
||||||
|
* executable pools by releasing all JIT code in them, zero to never destroy pools.
|
||||||
|
* Initialize counter so that the first pool will be destroyed, and eventually drive
|
||||||
|
* the amount of JIT code in never-used compartments to zero. Don't discard anything
|
||||||
|
* for compartments which currently have active stack frames.
|
||||||
|
*/
|
||||||
|
uint32 counter = 1;
|
||||||
|
bool discardScripts = !active && releaseInterval != 0;
|
||||||
|
|
||||||
for (JSCList *cursor = scripts.next; cursor != &scripts; cursor = cursor->next) {
|
for (JSCList *cursor = scripts.next; cursor != &scripts; cursor = cursor->next) {
|
||||||
JSScript *script = reinterpret_cast<JSScript *>(cursor);
|
JSScript *script = reinterpret_cast<JSScript *>(cursor);
|
||||||
if (script->hasJITCode())
|
if (script->hasJITCode()) {
|
||||||
mjit::ic::SweepCallICs(script);
|
mjit::ic::SweepCallICs(script, discardScripts);
|
||||||
|
if (discardScripts) {
|
||||||
|
if (script->jitNormal &&
|
||||||
|
ScriptPoolDestroyed(cx, script->jitNormal, releaseInterval, counter)) {
|
||||||
|
mjit::ReleaseScriptCode(cx, script);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
#endif
|
if (script->jitCtor &&
|
||||||
|
ScriptPoolDestroyed(cx, script->jitCtor, releaseInterval, counter)) {
|
||||||
|
mjit::ReleaseScriptCode(cx, script);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* JS_METHODJIT && JS_MONOIC */
|
||||||
|
|
||||||
|
active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -357,6 +445,20 @@ JSCompartment::purge(JSContext *cx)
|
||||||
{
|
{
|
||||||
freeLists.purge();
|
freeLists.purge();
|
||||||
|
|
||||||
|
/* Destroy eval'ed scripts. */
|
||||||
|
js_DestroyScriptsToGC(cx, this);
|
||||||
|
|
||||||
|
nativeIterCache.purge();
|
||||||
|
|
||||||
|
#ifdef JS_TRACER
|
||||||
|
/*
|
||||||
|
* If we are about to regenerate shapes, we have to flush the JIT cache,
|
||||||
|
* which will eventually abort any current recording.
|
||||||
|
*/
|
||||||
|
if (cx->runtime->gcRegenShapes)
|
||||||
|
traceMonitor.needFlush = JS_TRUE;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef JS_METHODJIT
|
#ifdef JS_METHODJIT
|
||||||
for (JSScript *script = (JSScript *)scripts.next;
|
for (JSScript *script = (JSScript *)scripts.next;
|
||||||
&script->links != &scripts;
|
&script->links != &scripts;
|
||||||
|
@ -367,8 +469,8 @@ JSCompartment::purge(JSContext *cx)
|
||||||
# endif
|
# endif
|
||||||
# if defined JS_MONOIC
|
# if defined JS_MONOIC
|
||||||
/*
|
/*
|
||||||
* MICs do not refer to data which can be GC'ed, but are sensitive
|
* MICs do not refer to data which can be GC'ed and do not generate stubs
|
||||||
* to shape regeneration.
|
* which might need to be discarded, but are sensitive to shape regeneration.
|
||||||
*/
|
*/
|
||||||
if (cx->runtime->gcRegenShapes)
|
if (cx->runtime->gcRegenShapes)
|
||||||
mjit::ic::PurgeMICs(cx, script);
|
mjit::ic::PurgeMICs(cx, script);
|
||||||
|
@ -377,3 +479,13 @@ JSCompartment::purge(JSContext *cx)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MathCache *
|
||||||
|
JSCompartment::allocMathCache(JSContext *cx)
|
||||||
|
{
|
||||||
|
JS_ASSERT(!mathCache);
|
||||||
|
mathCache = new MathCache;
|
||||||
|
if (!mathCache)
|
||||||
|
js_ReportOutOfMemory(cx);
|
||||||
|
return mathCache;
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||||
*
|
*
|
||||||
* ***** BEGIN LICENSE BLOCK *****
|
* ***** BEGIN LICENSE BLOCK *****
|
||||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
@ -55,11 +55,210 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
|
/* Holds the number of recording attemps for an address. */
|
||||||
|
typedef HashMap<jsbytecode*,
|
||||||
|
size_t,
|
||||||
|
DefaultHasher<jsbytecode*>,
|
||||||
|
SystemAllocPolicy> RecordAttemptMap;
|
||||||
|
|
||||||
|
/* Holds the profile data for loops. */
|
||||||
|
typedef HashMap<jsbytecode*,
|
||||||
|
LoopProfile*,
|
||||||
|
DefaultHasher<jsbytecode*>,
|
||||||
|
SystemAllocPolicy> LoopProfileMap;
|
||||||
|
|
||||||
|
class Oracle;
|
||||||
|
|
||||||
|
typedef HashSet<JSScript *,
|
||||||
|
DefaultHasher<JSScript *>,
|
||||||
|
SystemAllocPolicy> TracedScriptSet;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Trace monitor. Every JSCompartment has an associated trace monitor
|
||||||
|
* that keeps track of loop frequencies for all JavaScript code loaded
|
||||||
|
* into that runtime.
|
||||||
|
*/
|
||||||
|
struct TraceMonitor {
|
||||||
|
/*
|
||||||
|
* The context currently executing JIT-compiled code in this compartment, or
|
||||||
|
* NULL if none. Among other things, this can in certain cases prevent
|
||||||
|
* last-ditch GC and suppress calls to JS_ReportOutOfMemory.
|
||||||
|
*
|
||||||
|
* !tracecx && !recorder: not on trace
|
||||||
|
* !tracecx && recorder: recording
|
||||||
|
* tracecx && !recorder: executing a trace
|
||||||
|
* tracecx && recorder: executing inner loop, recording outer loop
|
||||||
|
*/
|
||||||
|
JSContext *tracecx;
|
||||||
|
|
||||||
|
/* Counts the number of iterations run by the currently executing trace. */
|
||||||
|
unsigned iterationCounter;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cached storage to use when executing on trace. While we may enter nested
|
||||||
|
* traces, we always reuse the outer trace's storage, so never need more
|
||||||
|
* than of these.
|
||||||
|
*/
|
||||||
|
TraceNativeStorage *storage;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* There are 4 allocators here. This might seem like overkill, but they
|
||||||
|
* have different lifecycles, and by keeping them separate we keep the
|
||||||
|
* amount of retained memory down significantly. They are flushed (ie.
|
||||||
|
* all the allocated memory is freed) periodically.
|
||||||
|
*
|
||||||
|
* - dataAlloc has the lifecycle of the monitor. It's flushed only when
|
||||||
|
* the monitor is flushed. It's used for fragments.
|
||||||
|
*
|
||||||
|
* - traceAlloc has the same flush lifecycle as the dataAlloc, but it is
|
||||||
|
* also *marked* when a recording starts and rewinds to the mark point
|
||||||
|
* if recording aborts. So you can put things in it that are only
|
||||||
|
* reachable on a successful record/compile cycle like GuardRecords and
|
||||||
|
* SideExits.
|
||||||
|
*
|
||||||
|
* - tempAlloc is flushed after each recording, successful or not. It's
|
||||||
|
* used to store LIR code and for all other elements in the LIR
|
||||||
|
* pipeline.
|
||||||
|
*
|
||||||
|
* - codeAlloc has the same lifetime as dataAlloc, but its API is
|
||||||
|
* different (CodeAlloc vs. VMAllocator). It's used for native code.
|
||||||
|
* It's also a good idea to keep code and data separate to avoid I-cache
|
||||||
|
* vs. D-cache issues.
|
||||||
|
*/
|
||||||
|
VMAllocator* dataAlloc;
|
||||||
|
VMAllocator* traceAlloc;
|
||||||
|
VMAllocator* tempAlloc;
|
||||||
|
nanojit::CodeAlloc* codeAlloc;
|
||||||
|
nanojit::Assembler* assembler;
|
||||||
|
FrameInfoCache* frameCache;
|
||||||
|
|
||||||
|
/* This gets incremented every time the monitor is flushed. */
|
||||||
|
uintN flushEpoch;
|
||||||
|
|
||||||
|
Oracle* oracle;
|
||||||
|
TraceRecorder* recorder;
|
||||||
|
|
||||||
|
/* If we are profiling a loop, this tracks the current profile. Otherwise NULL. */
|
||||||
|
LoopProfile* profile;
|
||||||
|
|
||||||
|
GlobalState globalStates[MONITOR_N_GLOBAL_STATES];
|
||||||
|
TreeFragment* vmfragments[FRAGMENT_TABLE_SIZE];
|
||||||
|
RecordAttemptMap* recordAttempts;
|
||||||
|
|
||||||
|
/* A hashtable mapping PC values to loop profiles for those loops. */
|
||||||
|
LoopProfileMap* loopProfiles;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Maximum size of the code cache before we start flushing. 1/16 of this
|
||||||
|
* size is used as threshold for the regular expression code cache.
|
||||||
|
*/
|
||||||
|
uint32 maxCodeCacheBytes;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If nonzero, do not flush the JIT cache after a deep bail. That would
|
||||||
|
* free JITted code pages that we will later return to. Instead, set the
|
||||||
|
* needFlush flag so that it can be flushed later.
|
||||||
|
*/
|
||||||
|
JSBool needFlush;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fragment map for the regular expression compiler.
|
||||||
|
*/
|
||||||
|
REHashMap* reFragments;
|
||||||
|
|
||||||
|
// Cached temporary typemap to avoid realloc'ing every time we create one.
|
||||||
|
// This must be used in only one place at a given time. It must be cleared
|
||||||
|
// before use.
|
||||||
|
TypeMap* cachedTempTypeMap;
|
||||||
|
|
||||||
|
/* Scripts with recorded fragments. */
|
||||||
|
TracedScriptSet tracedScripts;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
/* Fields needed for fragment/guard profiling. */
|
||||||
|
nanojit::Seq<nanojit::Fragment*>* branches;
|
||||||
|
uint32 lastFragID;
|
||||||
|
/*
|
||||||
|
* profAlloc has a lifetime which spans exactly from js_InitJIT to
|
||||||
|
* js_FinishJIT.
|
||||||
|
*/
|
||||||
|
VMAllocator* profAlloc;
|
||||||
|
FragStatsMap* profTab;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool ontrace() const {
|
||||||
|
return !!tracecx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flush the JIT cache. */
|
||||||
|
void flush();
|
||||||
|
|
||||||
|
/* Sweep any cache entry pointing to dead GC things. */
|
||||||
|
void sweep();
|
||||||
|
|
||||||
|
bool outOfMemory() const;
|
||||||
|
};
|
||||||
|
|
||||||
namespace mjit {
|
namespace mjit {
|
||||||
class JaegerCompartment;
|
class JaegerCompartment;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Number of potentially reusable scriptsToGC to search for the eval cache. */
|
||||||
|
#ifndef JS_EVAL_CACHE_SHIFT
|
||||||
|
# define JS_EVAL_CACHE_SHIFT 6
|
||||||
|
#endif
|
||||||
|
#define JS_EVAL_CACHE_SIZE JS_BIT(JS_EVAL_CACHE_SHIFT)
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
# define EVAL_CACHE_METER_LIST(_) _(probe), _(hit), _(step), _(noscope)
|
||||||
|
# define identity(x) x
|
||||||
|
|
||||||
|
struct JSEvalCacheMeter {
|
||||||
|
uint64 EVAL_CACHE_METER_LIST(identity);
|
||||||
|
};
|
||||||
|
|
||||||
|
# undef identity
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace js {
|
||||||
|
|
||||||
|
class NativeIterCache {
|
||||||
|
static const size_t SIZE = size_t(1) << 8;
|
||||||
|
|
||||||
|
/* Cached native iterators. */
|
||||||
|
JSObject *data[SIZE];
|
||||||
|
|
||||||
|
static size_t getIndex(uint32 key) {
|
||||||
|
return size_t(key) % SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/* Native iterator most recently started. */
|
||||||
|
JSObject *last;
|
||||||
|
|
||||||
|
NativeIterCache()
|
||||||
|
: last(NULL) {
|
||||||
|
PodArrayZero(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void purge() {
|
||||||
|
PodArrayZero(data);
|
||||||
|
last = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSObject *get(uint32 key) const {
|
||||||
|
return data[getIndex(key)];
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(uint32 key, JSObject *iterobj) {
|
||||||
|
data[getIndex(key)] = iterobj;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace js */
|
||||||
|
|
||||||
struct JS_FRIEND_API(JSCompartment) {
|
struct JS_FRIEND_API(JSCompartment) {
|
||||||
JSRuntime *rt;
|
JSRuntime *rt;
|
||||||
JSPrincipals *principals;
|
JSPrincipals *principals;
|
||||||
|
@ -72,8 +271,21 @@ struct JS_FRIEND_API(JSCompartment) {
|
||||||
js::gc::JSGCArenaStats compartmentStats[js::gc::FINALIZE_LIMIT];
|
js::gc::JSGCArenaStats compartmentStats[js::gc::FINALIZE_LIMIT];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef JS_TRACER
|
||||||
|
/* Trace-tree JIT recorder/interpreter state. */
|
||||||
|
js::TraceMonitor traceMonitor;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Hashed lists of scripts created by eval to garbage-collect. */
|
||||||
|
JSScript *scriptsToGC[JS_EVAL_CACHE_SIZE];
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
JSEvalCacheMeter evalCacheMeter;
|
||||||
|
#endif
|
||||||
|
|
||||||
void *data;
|
void *data;
|
||||||
bool marked;
|
bool marked;
|
||||||
|
bool active; // GC flag, whether there are active frames
|
||||||
js::WrapperMap crossCompartmentWrappers;
|
js::WrapperMap crossCompartmentWrappers;
|
||||||
|
|
||||||
#ifdef JS_METHODJIT
|
#ifdef JS_METHODJIT
|
||||||
|
@ -93,6 +305,8 @@ struct JS_FRIEND_API(JSCompartment) {
|
||||||
JSObject *anynameObject;
|
JSObject *anynameObject;
|
||||||
JSObject *functionNamespaceObject;
|
JSObject *functionNamespaceObject;
|
||||||
|
|
||||||
|
js::NativeIterCache nativeIterCache;
|
||||||
|
|
||||||
JSCompartment(JSRuntime *cx);
|
JSCompartment(JSRuntime *cx);
|
||||||
~JSCompartment();
|
~JSCompartment();
|
||||||
|
|
||||||
|
@ -107,12 +321,39 @@ struct JS_FRIEND_API(JSCompartment) {
|
||||||
bool wrap(JSContext *cx, js::AutoIdVector &props);
|
bool wrap(JSContext *cx, js::AutoIdVector &props);
|
||||||
bool wrapException(JSContext *cx);
|
bool wrapException(JSContext *cx);
|
||||||
|
|
||||||
void sweep(JSContext *cx);
|
void sweep(JSContext *cx, uint32 releaseInterval);
|
||||||
void purge(JSContext *cx);
|
void purge(JSContext *cx);
|
||||||
void finishArenaLists();
|
void finishArenaLists();
|
||||||
bool arenaListsAreEmpty();
|
bool arenaListsAreEmpty();
|
||||||
|
|
||||||
|
private:
|
||||||
|
js::MathCache *mathCache;
|
||||||
|
|
||||||
|
js::MathCache *allocMathCache(JSContext *cx);
|
||||||
|
|
||||||
|
public:
|
||||||
|
js::MathCache *getMathCache(JSContext *cx) {
|
||||||
|
return mathCache ? mathCache : allocMathCache(cx);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define JS_TRACE_MONITOR(cx) (cx->compartment->traceMonitor)
|
||||||
|
#define JS_SCRIPTS_TO_GC(cx) (cx->compartment->scriptsToGC)
|
||||||
|
|
||||||
|
namespace js {
|
||||||
|
static inline MathCache *
|
||||||
|
GetMathCache(JSContext *cx)
|
||||||
|
{
|
||||||
|
return cx->compartment->getMathCache(cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
# define EVAL_CACHE_METER(x) (cx->compartment->evalCacheMeter.x++)
|
||||||
|
#else
|
||||||
|
# define EVAL_CACHE_METER(x) ((void) 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -750,7 +750,7 @@ ndigits(size_t n, size_t *result, const jschar *s, size_t* i, size_t limit)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static JSBool
|
static JSBool
|
||||||
date_parseISOString(JSString *str, jsdouble *result, JSContext *cx)
|
date_parseISOString(JSLinearString *str, jsdouble *result, JSContext *cx)
|
||||||
{
|
{
|
||||||
jsdouble msec;
|
jsdouble msec;
|
||||||
|
|
||||||
|
@ -792,7 +792,8 @@ date_parseISOString(JSString *str, jsdouble *result, JSContext *cx)
|
||||||
if (!ndigits(n, &field, s, &i, limit)) { goto syntax; } \
|
if (!ndigits(n, &field, s, &i, limit)) { goto syntax; } \
|
||||||
JS_END_MACRO
|
JS_END_MACRO
|
||||||
|
|
||||||
str->getCharsAndLength(s, limit);
|
s = str->chars();
|
||||||
|
limit = str->length();
|
||||||
|
|
||||||
if (PEEK('+') || PEEK('-')) {
|
if (PEEK('+') || PEEK('-')) {
|
||||||
if (PEEK('-'))
|
if (PEEK('-'))
|
||||||
|
@ -883,7 +884,7 @@ date_parseISOString(JSString *str, jsdouble *result, JSContext *cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSBool
|
static JSBool
|
||||||
date_parseString(JSString *str, jsdouble *result, JSContext *cx)
|
date_parseString(JSLinearString *str, jsdouble *result, JSContext *cx)
|
||||||
{
|
{
|
||||||
jsdouble msec;
|
jsdouble msec;
|
||||||
|
|
||||||
|
@ -907,7 +908,8 @@ date_parseString(JSString *str, jsdouble *result, JSContext *cx)
|
||||||
if (date_parseISOString(str, result, cx))
|
if (date_parseISOString(str, result, cx))
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
|
|
||||||
str->getCharsAndLength(s, limit);
|
s = str->chars();
|
||||||
|
limit = str->length();
|
||||||
if (limit == 0)
|
if (limit == 0)
|
||||||
goto syntax;
|
goto syntax;
|
||||||
while (i < limit) {
|
while (i < limit) {
|
||||||
|
@ -1167,7 +1169,11 @@ date_parse(JSContext *cx, uintN argc, Value *vp)
|
||||||
if (!str)
|
if (!str)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
vp[2].setString(str);
|
vp[2].setString(str);
|
||||||
if (!date_parseString(str, &result, cx)) {
|
JSLinearString *linearStr = str->ensureLinear(cx);
|
||||||
|
if (!linearStr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!date_parseString(linearStr, &result, cx)) {
|
||||||
vp->setDouble(js_NaN);
|
vp->setDouble(js_NaN);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2377,8 +2383,6 @@ date_toString(JSContext *cx, uintN argc, Value *vp)
|
||||||
static JSBool
|
static JSBool
|
||||||
date_valueOf(JSContext *cx, uintN argc, Value *vp)
|
date_valueOf(JSContext *cx, uintN argc, Value *vp)
|
||||||
{
|
{
|
||||||
JSString *str, *number_str;
|
|
||||||
|
|
||||||
/* It is an error to call date_valueOf on a non-date object, but we don't
|
/* It is an error to call date_valueOf on a non-date object, but we don't
|
||||||
* need to check for that explicitly here because every path calls
|
* need to check for that explicitly here because every path calls
|
||||||
* GetUTCTime, which does the check.
|
* GetUTCTime, which does the check.
|
||||||
|
@ -2389,11 +2393,14 @@ date_valueOf(JSContext *cx, uintN argc, Value *vp)
|
||||||
return date_getTime(cx, argc, vp);
|
return date_getTime(cx, argc, vp);
|
||||||
|
|
||||||
/* Convert to number only if the hint was given, otherwise favor string. */
|
/* Convert to number only if the hint was given, otherwise favor string. */
|
||||||
str = js_ValueToString(cx, vp[2]);
|
JSString *str = js_ValueToString(cx, vp[2]);
|
||||||
if (!str)
|
if (!str)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
number_str = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER]);
|
JSLinearString *linear_str = str->ensureLinear(cx);
|
||||||
if (js_EqualStrings(str, number_str))
|
if (!linear_str)
|
||||||
|
return JS_FALSE;
|
||||||
|
JSAtom *number_str = cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER];
|
||||||
|
if (EqualStrings(linear_str, number_str))
|
||||||
return date_getTime(cx, argc, vp);
|
return date_getTime(cx, argc, vp);
|
||||||
return date_toString(cx, argc, vp);
|
return date_toString(cx, argc, vp);
|
||||||
}
|
}
|
||||||
|
@ -2487,8 +2494,11 @@ js_Date(JSContext *cx, uintN argc, Value *vp)
|
||||||
if (!str)
|
if (!str)
|
||||||
return false;
|
return false;
|
||||||
argv[0].setString(str);
|
argv[0].setString(str);
|
||||||
|
JSLinearString *linearStr = str->ensureLinear(cx);
|
||||||
|
if (!linearStr)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!date_parseString(str, &d, cx))
|
if (!date_parseString(linearStr, &d, cx))
|
||||||
d = js_NaN;
|
d = js_NaN;
|
||||||
else
|
else
|
||||||
d = TIMECLIP(d);
|
d = TIMECLIP(d);
|
||||||
|
|
|
@ -145,7 +145,7 @@ js_SetDebugMode(JSContext *cx, JSBool debug)
|
||||||
for (JSScript *script = (JSScript *)cx->compartment->scripts.next;
|
for (JSScript *script = (JSScript *)cx->compartment->scripts.next;
|
||||||
&script->links != &cx->compartment->scripts;
|
&script->links != &cx->compartment->scripts;
|
||||||
script = (JSScript *)script->links.next) {
|
script = (JSScript *)script->links.next) {
|
||||||
if (script->debugMode != (bool) debug &&
|
if (script->debugMode != !!debug &&
|
||||||
script->hasJITCode() &&
|
script->hasJITCode() &&
|
||||||
!IsScriptLive(cx, script)) {
|
!IsScriptLive(cx, script)) {
|
||||||
/*
|
/*
|
||||||
|
@ -182,6 +182,30 @@ JS_SetDebugMode(JSContext *cx, JSBool debug)
|
||||||
return js_SetDebugMode(cx, debug);
|
return js_SetDebugMode(cx, debug);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JS_FRIEND_API(JSBool)
|
||||||
|
js_SetSingleStepMode(JSContext *cx, JSScript *script, JSBool singleStep)
|
||||||
|
{
|
||||||
|
if (!script->singleStepMode == !singleStep)
|
||||||
|
return JS_TRUE;
|
||||||
|
|
||||||
|
JS_ASSERT_IF(singleStep, cx->compartment->debugMode);
|
||||||
|
|
||||||
|
#ifdef JS_METHODJIT
|
||||||
|
/* request the next recompile to inject single step interrupts */
|
||||||
|
script->singleStepMode = !!singleStep;
|
||||||
|
|
||||||
|
js::mjit::JITScript *jit = script->jitNormal ? script->jitNormal : script->jitCtor;
|
||||||
|
if (jit && script->singleStepMode != jit->singleStepMode) {
|
||||||
|
js::mjit::Recompiler recompiler(cx, script);
|
||||||
|
if (!recompiler.recompile()) {
|
||||||
|
script->singleStepMode = !singleStep;
|
||||||
|
return JS_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return JS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static JSBool
|
static JSBool
|
||||||
CheckDebugMode(JSContext *cx)
|
CheckDebugMode(JSContext *cx)
|
||||||
{
|
{
|
||||||
|
@ -198,6 +222,15 @@ CheckDebugMode(JSContext *cx)
|
||||||
return debugMode;
|
return debugMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JS_PUBLIC_API(JSBool)
|
||||||
|
JS_SetSingleStepMode(JSContext *cx, JSScript *script, JSBool singleStep)
|
||||||
|
{
|
||||||
|
if (!CheckDebugMode(cx))
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
return js_SetSingleStepMode(cx, script, singleStep);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NB: FindTrap must be called with rt->debuggerLock acquired.
|
* NB: FindTrap must be called with rt->debuggerLock acquired.
|
||||||
*/
|
*/
|
||||||
|
@ -485,17 +518,6 @@ JITInhibitingHookChange(JSRuntime *rt, bool wasInhibited)
|
||||||
js_ContextFromLinkField(cl)->traceJitEnabled = false;
|
js_ContextFromLinkField(cl)->traceJitEnabled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
LeaveTraceRT(JSRuntime *rt)
|
|
||||||
{
|
|
||||||
JSThreadData *data = js_CurrentThreadData(rt);
|
|
||||||
JSContext *cx = data ? data->traceMonitor.tracecx : NULL;
|
|
||||||
JS_UNLOCK_GC(rt);
|
|
||||||
|
|
||||||
if (cx)
|
|
||||||
LeaveTrace(cx);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
JS_PUBLIC_API(JSBool)
|
JS_PUBLIC_API(JSBool)
|
||||||
|
@ -511,7 +533,6 @@ JS_SetInterrupt(JSRuntime *rt, JSInterruptHook hook, void *closure)
|
||||||
#ifdef JS_TRACER
|
#ifdef JS_TRACER
|
||||||
JITInhibitingHookChange(rt, wasInhibited);
|
JITInhibitingHookChange(rt, wasInhibited);
|
||||||
}
|
}
|
||||||
LeaveTraceRT(rt);
|
|
||||||
#endif
|
#endif
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
@ -1672,8 +1693,6 @@ JS_SetCallHook(JSRuntime *rt, JSInterpreterHook hook, void *closure)
|
||||||
#ifdef JS_TRACER
|
#ifdef JS_TRACER
|
||||||
JITInhibitingHookChange(rt, wasInhibited);
|
JITInhibitingHookChange(rt, wasInhibited);
|
||||||
}
|
}
|
||||||
if (hook)
|
|
||||||
LeaveTraceRT(rt);
|
|
||||||
#endif
|
#endif
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
@ -1995,15 +2014,13 @@ JS_FRIEND_API(JSBool)
|
||||||
js_DumpCallgrind(JSContext *cx, uintN argc, jsval *vp)
|
js_DumpCallgrind(JSContext *cx, uintN argc, jsval *vp)
|
||||||
{
|
{
|
||||||
JSString *str;
|
JSString *str;
|
||||||
char *cstr;
|
|
||||||
|
|
||||||
jsval *argv = JS_ARGV(cx, vp);
|
jsval *argv = JS_ARGV(cx, vp);
|
||||||
if (argc > 0 && JSVAL_IS_STRING(argv[0])) {
|
if (argc > 0 && JSVAL_IS_STRING(argv[0])) {
|
||||||
str = JSVAL_TO_STRING(argv[0]);
|
str = JSVAL_TO_STRING(argv[0]);
|
||||||
cstr = js_DeflateString(cx, str->chars(), str->length());
|
JSAutoByteString bytes(cx, str);
|
||||||
if (cstr) {
|
if (!!bytes) {
|
||||||
CALLGRIND_DUMP_STATS_AT(cstr);
|
CALLGRIND_DUMP_STATS_AT(bytes.ptr());
|
||||||
cx->free(cstr);
|
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2245,7 +2262,7 @@ public:
|
||||||
JSHashNumber hash = JS_HashString(filename);
|
JSHashNumber hash = JS_HashString(filename);
|
||||||
JSHashEntry **hep = JS_HashTableRawLookup(traceVisScriptTable, hash, filename);
|
JSHashEntry **hep = JS_HashTableRawLookup(traceVisScriptTable, hash, filename);
|
||||||
if (*hep != NULL)
|
if (*hep != NULL)
|
||||||
return JS_FALSE;
|
return NULL;
|
||||||
|
|
||||||
JS_HashTableRawAdd(traceVisScriptTable, hep, hash, filename, this);
|
JS_HashTableRawAdd(traceVisScriptTable, hep, hash, filename, this);
|
||||||
|
|
||||||
|
|
|
@ -78,6 +78,14 @@ js_SetDebugMode(JSContext *cx, JSBool debug);
|
||||||
extern JS_PUBLIC_API(JSBool)
|
extern JS_PUBLIC_API(JSBool)
|
||||||
JS_SetDebugMode(JSContext *cx, JSBool debug);
|
JS_SetDebugMode(JSContext *cx, JSBool debug);
|
||||||
|
|
||||||
|
/* Turn on single step mode. Requires debug mode. */
|
||||||
|
extern JS_FRIEND_API(JSBool)
|
||||||
|
js_SetSingleStepMode(JSContext *cx, JSScript *script, JSBool singleStep);
|
||||||
|
|
||||||
|
/* Turn on single step mode. */
|
||||||
|
extern JS_PUBLIC_API(JSBool)
|
||||||
|
JS_SetSingleStepMode(JSContext *cx, JSScript *script, JSBool singleStep);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Unexported library-private helper used to unpatch all traps in a script.
|
* Unexported library-private helper used to unpatch all traps in a script.
|
||||||
* Returns script->code if script has no traps, else a JS_malloc'ed copy of
|
* Returns script->code if script has no traps, else a JS_malloc'ed copy of
|
||||||
|
|
|
@ -2270,7 +2270,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Optimize accesses to undeclared globals. */
|
/* Optimize accesses to undeclared globals. */
|
||||||
if (!TryConvertToGname(cg, pn, &op))
|
if (!cg->mightAliasLocals() && !TryConvertToGname(cg, pn, &op))
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
|
|
||||||
ale = cg->atomList.add(cg->parser, atom);
|
ale = cg->atomList.add(cg->parser, atom);
|
||||||
|
@ -2500,15 +2500,28 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
JS_ASSERT((cg->fun()->flags & JSFUN_LAMBDA) && atom == cg->fun()->atom);
|
JS_ASSERT((cg->fun()->flags & JSFUN_LAMBDA) && atom == cg->fun()->atom);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Leave pn->pn_op == JSOP_NAME if cg->fun() is heavyweight, as we
|
* Leave pn->pn_op == JSOP_NAME if cg->fun is heavyweight to
|
||||||
* cannot be sure cg->fun() is not something of the form:
|
* address two cases: a new binding introduced by eval, and
|
||||||
|
* assignment to the name in strict mode.
|
||||||
*
|
*
|
||||||
* var ff = (function f(s) { eval(s); return f; });
|
* var fun = (function f(s) { eval(s); return f; });
|
||||||
|
* assertEq(fun("var f = 42"), 42);
|
||||||
*
|
*
|
||||||
* where a caller invokes ff("var f = 42"). The result returned for
|
* ECMAScript specifies that a function expression's name is bound
|
||||||
* such an invocation must be 42, since the callee name is
|
* in a lexical environment distinct from that used to bind its
|
||||||
* lexically bound in an outer declarative environment from the
|
* named parameters, the arguments object, and its variables. The
|
||||||
* function's activation. See jsfun.cpp:call_resolve.
|
* new binding for "var f = 42" shadows the binding for the
|
||||||
|
* function itself, so the name of the function will not refer to
|
||||||
|
* the function.
|
||||||
|
*
|
||||||
|
* (function f() { "use strict"; f = 12; })();
|
||||||
|
*
|
||||||
|
* Outside strict mode, assignment to a function expression's name
|
||||||
|
* has no effect. But in strict mode, this attempt to mutate an
|
||||||
|
* immutable binding must throw a TypeError. We implement this by
|
||||||
|
* not optimizing such assignments and by marking such functions as
|
||||||
|
* heavyweight, ensuring that the function name is represented in
|
||||||
|
* the scope chain so that assignment will throw a TypeError.
|
||||||
*/
|
*/
|
||||||
JS_ASSERT(op != JSOP_DELNAME);
|
JS_ASSERT(op != JSOP_DELNAME);
|
||||||
if (!(cg->flags & TCF_FUN_HEAVYWEIGHT)) {
|
if (!(cg->flags & TCF_FUN_HEAVYWEIGHT)) {
|
||||||
|
@ -3764,6 +3777,13 @@ js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body)
|
||||||
CG_SWITCH_TO_MAIN(cg);
|
CG_SWITCH_TO_MAIN(cg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Strict mode functions' arguments objects copy initial parameter values.
|
||||||
|
* We create arguments objects lazily -- but that doesn't work for strict
|
||||||
|
* mode functions where a parameter might be modified and arguments might
|
||||||
|
* be accessed. For such functions we synthesize an access to arguments to
|
||||||
|
* initialize it with the original parameter values.
|
||||||
|
*/
|
||||||
if (cg->needsEagerArguments()) {
|
if (cg->needsEagerArguments()) {
|
||||||
CG_SWITCH_TO_PROLOG(cg);
|
CG_SWITCH_TO_PROLOG(cg);
|
||||||
if (js_Emit1(cx, cg, JSOP_ARGUMENTS) < 0 || js_Emit1(cx, cg, JSOP_POP) < 0)
|
if (js_Emit1(cx, cg, JSOP_ARGUMENTS) < 0 || js_Emit1(cx, cg, JSOP_POP) < 0)
|
||||||
|
@ -4613,7 +4633,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
if (!cg2->init())
|
if (!cg2->init())
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
cg2->flags = pn->pn_funbox->tcflags | TCF_COMPILING | TCF_IN_FUNCTION;
|
cg2->flags = pn->pn_funbox->tcflags | TCF_COMPILING | TCF_IN_FUNCTION |
|
||||||
|
(cg->flags & TCF_FUN_MIGHT_ALIAS_LOCALS);
|
||||||
#if JS_HAS_SHARP_VARS
|
#if JS_HAS_SHARP_VARS
|
||||||
if (cg2->flags & TCF_HAS_SHARPS) {
|
if (cg2->flags & TCF_HAS_SHARPS) {
|
||||||
cg2->sharpSlotBase = fun->sharpSlotBase(cx);
|
cg2->sharpSlotBase = fun->sharpSlotBase(cx);
|
||||||
|
|
|
@ -252,10 +252,8 @@ struct JSStmtInfo {
|
||||||
#define TCF_COMPILE_FOR_EVAL 0x2000000
|
#define TCF_COMPILE_FOR_EVAL 0x2000000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The function has broken or incorrect def-use information, and it cannot
|
* The function or a function that encloses it may define new local names
|
||||||
* safely optimize free variables to global names. This can happen because
|
* at runtime through means other than calling eval.
|
||||||
* of a named function statement not at the top level (emitting a DEFFUN),
|
|
||||||
* or a variable declaration inside a "with".
|
|
||||||
*/
|
*/
|
||||||
#define TCF_FUN_MIGHT_ALIAS_LOCALS 0x4000000
|
#define TCF_FUN_MIGHT_ALIAS_LOCALS 0x4000000
|
||||||
|
|
||||||
|
|
|
@ -612,10 +612,11 @@ StackTraceToString(JSContext *cx, JSExnPrivate *priv)
|
||||||
#define APPEND_STRING_TO_STACK(str) \
|
#define APPEND_STRING_TO_STACK(str) \
|
||||||
JS_BEGIN_MACRO \
|
JS_BEGIN_MACRO \
|
||||||
JSString *str_ = str; \
|
JSString *str_ = str; \
|
||||||
const jschar *chars_; \
|
size_t length_ = str_->length(); \
|
||||||
size_t length_; \
|
const jschar *chars_ = str_->getChars(cx); \
|
||||||
|
if (!chars_) \
|
||||||
|
goto bad; \
|
||||||
\
|
\
|
||||||
str_->getCharsAndLength(chars_, length_); \
|
|
||||||
if (length_ > stackmax - stacklen) { \
|
if (length_ > stackmax - stacklen) { \
|
||||||
void *ptr_; \
|
void *ptr_; \
|
||||||
if (stackmax >= STACK_LENGTH_LIMIT || \
|
if (stackmax >= STACK_LENGTH_LIMIT || \
|
||||||
|
@ -813,11 +814,17 @@ exn_toString(JSContext *cx, uintN argc, Value *vp)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
if (name_length) {
|
if (name_length) {
|
||||||
js_strncpy(cp, name->chars(), name_length);
|
const jschar *name_chars = name->getChars(cx);
|
||||||
|
if (!name_chars)
|
||||||
|
return JS_FALSE;
|
||||||
|
js_strncpy(cp, name_chars, name_length);
|
||||||
cp += name_length;
|
cp += name_length;
|
||||||
*cp++ = ':'; *cp++ = ' ';
|
*cp++ = ':'; *cp++ = ' ';
|
||||||
}
|
}
|
||||||
js_strncpy(cp, message->chars(), message_length);
|
const jschar *message_chars = message->getChars(cx);
|
||||||
|
if (!message_chars)
|
||||||
|
return JS_FALSE;
|
||||||
|
js_strncpy(cp, message_chars, message_length);
|
||||||
cp += message_length;
|
cp += message_length;
|
||||||
*cp = 0;
|
*cp = 0;
|
||||||
|
|
||||||
|
@ -917,18 +924,27 @@ exn_toSource(JSContext *cx, uintN argc, Value *vp)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
*cp++ = '('; *cp++ = 'n'; *cp++ = 'e'; *cp++ = 'w'; *cp++ = ' ';
|
*cp++ = '('; *cp++ = 'n'; *cp++ = 'e'; *cp++ = 'w'; *cp++ = ' ';
|
||||||
js_strncpy(cp, name->chars(), name_length);
|
const jschar *name_chars = name->getChars(cx);
|
||||||
|
if (!name_chars)
|
||||||
|
return false;
|
||||||
|
js_strncpy(cp, name_chars, name_length);
|
||||||
cp += name_length;
|
cp += name_length;
|
||||||
*cp++ = '(';
|
*cp++ = '(';
|
||||||
|
const jschar *message_chars = message->getChars(cx);
|
||||||
|
if (!message_chars)
|
||||||
|
return false;
|
||||||
if (message_length != 0) {
|
if (message_length != 0) {
|
||||||
js_strncpy(cp, message->chars(), message_length);
|
js_strncpy(cp, message_chars, message_length);
|
||||||
cp += message_length;
|
cp += message_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filename_length != 0) {
|
if (filename_length != 0) {
|
||||||
/* append filename as ``, {filename}'' */
|
/* append filename as ``, {filename}'' */
|
||||||
*cp++ = ','; *cp++ = ' ';
|
*cp++ = ','; *cp++ = ' ';
|
||||||
js_strncpy(cp, filename->chars(), filename_length);
|
const jschar *filename_chars = filename->getChars(cx);
|
||||||
|
if (!filename_chars)
|
||||||
|
return false;
|
||||||
|
js_strncpy(cp, filename_chars, filename_length);
|
||||||
cp += filename_length;
|
cp += filename_length;
|
||||||
} else {
|
} else {
|
||||||
if (lineno_as_str) {
|
if (lineno_as_str) {
|
||||||
|
@ -942,7 +958,10 @@ exn_toSource(JSContext *cx, uintN argc, Value *vp)
|
||||||
if (lineno_as_str) {
|
if (lineno_as_str) {
|
||||||
/* append lineno as ``, {lineno_as_str}'' */
|
/* append lineno as ``, {lineno_as_str}'' */
|
||||||
*cp++ = ','; *cp++ = ' ';
|
*cp++ = ','; *cp++ = ' ';
|
||||||
js_strncpy(cp, lineno_as_str->chars(), lineno_length);
|
const jschar *lineno_chars = lineno_as_str->getChars(cx);
|
||||||
|
if (!lineno_chars)
|
||||||
|
return false;
|
||||||
|
js_strncpy(cp, lineno_chars, lineno_length);
|
||||||
cp += lineno_length;
|
cp += lineno_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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___ */
|
145
js/src/jsfun.cpp
145
js/src/jsfun.cpp
|
@ -598,27 +598,30 @@ args_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
||||||
JS_ASSERT(obj->isNormalArguments());
|
JS_ASSERT(obj->isNormalArguments());
|
||||||
|
|
||||||
*objp = NULL;
|
*objp = NULL;
|
||||||
bool valid = false;
|
|
||||||
uintN attrs = JSPROP_SHARED;
|
uintN attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
|
||||||
if (JSID_IS_INT(id)) {
|
if (JSID_IS_INT(id)) {
|
||||||
uint32 arg = uint32(JSID_TO_INT(id));
|
uint32 arg = uint32(JSID_TO_INT(id));
|
||||||
attrs = JSPROP_ENUMERATE | JSPROP_SHARED;
|
if (arg >= obj->getArgsInitialLength() || obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE))
|
||||||
if (arg < obj->getArgsInitialLength() && !obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE))
|
return true;
|
||||||
valid = true;
|
|
||||||
|
attrs |= JSPROP_ENUMERATE;
|
||||||
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
|
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
|
||||||
if (!obj->isArgsLengthOverridden())
|
if (obj->isArgsLengthOverridden())
|
||||||
valid = true;
|
return true;
|
||||||
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)) {
|
} else {
|
||||||
if (!obj->getArgsCallee().isMagic(JS_ARGS_HOLE))
|
if (!JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom))
|
||||||
valid = true;
|
return true;
|
||||||
|
|
||||||
|
if (obj->getArgsCallee().isMagic(JS_ARGS_HOLE))
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (valid) {
|
Value undef = UndefinedValue();
|
||||||
Value tmp = UndefinedValue();
|
if (!js_DefineProperty(cx, obj, id, &undef, ArgGetter, ArgSetter, attrs))
|
||||||
if (!js_DefineProperty(cx, obj, id, &tmp, ArgGetter, ArgSetter, attrs))
|
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
*objp = obj;
|
*objp = obj;
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -707,47 +710,35 @@ strictargs_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject
|
||||||
JS_ASSERT(obj->isStrictArguments());
|
JS_ASSERT(obj->isStrictArguments());
|
||||||
|
|
||||||
*objp = NULL;
|
*objp = NULL;
|
||||||
bool valid = false;
|
|
||||||
uintN attrs = JSPROP_SHARED;
|
uintN attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
|
||||||
|
PropertyOp getter = StrictArgGetter;
|
||||||
|
PropertyOp setter = StrictArgSetter;
|
||||||
|
|
||||||
if (JSID_IS_INT(id)) {
|
if (JSID_IS_INT(id)) {
|
||||||
uint32 arg = uint32(JSID_TO_INT(id));
|
uint32 arg = uint32(JSID_TO_INT(id));
|
||||||
attrs = JSPROP_SHARED | JSPROP_ENUMERATE;
|
if (arg >= obj->getArgsInitialLength() || obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE))
|
||||||
if (arg < obj->getArgsInitialLength() && !obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE))
|
return true;
|
||||||
valid = true;
|
|
||||||
|
attrs |= JSPROP_ENUMERATE;
|
||||||
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
|
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
|
||||||
if (!obj->isArgsLengthOverridden())
|
if (obj->isArgsLengthOverridden())
|
||||||
valid = true;
|
|
||||||
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)) {
|
|
||||||
Value tmp = UndefinedValue();
|
|
||||||
PropertyOp throwTypeError = CastAsPropertyOp(obj->getThrowTypeError());
|
|
||||||
uintN attrs = JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED;
|
|
||||||
if (!js_DefineProperty(cx, obj, id, &tmp, throwTypeError, throwTypeError, attrs))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
*objp = obj;
|
|
||||||
return true;
|
return true;
|
||||||
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.callerAtom)) {
|
} else {
|
||||||
/*
|
if (!JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom) &&
|
||||||
* Strict mode arguments objects have an immutable poison-pill caller
|
!JSID_IS_ATOM(id, cx->runtime->atomState.callerAtom)) {
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
*objp = obj;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (valid) {
|
attrs = JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED;
|
||||||
Value tmp = UndefinedValue();
|
getter = setter = CastAsPropertyOp(obj->getThrowTypeError());
|
||||||
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1589,12 +1580,15 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||||
/* Censor the caller if it is from another compartment. */
|
/* Censor the caller if it is from another compartment. */
|
||||||
if (caller.getCompartment() != cx->compartment) {
|
if (caller.getCompartment() != cx->compartment) {
|
||||||
vp->setNull();
|
vp->setNull();
|
||||||
} else if (caller.isFunction() && caller.getFunctionPrivate()->inStrictMode()) {
|
} else if (caller.isFunction()) {
|
||||||
|
JSFunction *callerFun = caller.getFunctionPrivate();
|
||||||
|
if (callerFun->isInterpreted() && callerFun->inStrictMode()) {
|
||||||
JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
|
JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
|
||||||
JSMSG_CALLER_IS_STRICT);
|
JSMSG_CALLER_IS_STRICT);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1762,7 +1756,7 @@ fun_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
||||||
|
|
||||||
PropertyOp getter, setter;
|
PropertyOp getter, setter;
|
||||||
uintN attrs = JSPROP_PERMANENT;
|
uintN attrs = JSPROP_PERMANENT;
|
||||||
if (fun->inStrictMode() || obj->isBoundFunction()) {
|
if (fun->isInterpreted() ? fun->inStrictMode() : obj->isBoundFunction()) {
|
||||||
JSObject *throwTypeError = obj->getThrowTypeError();
|
JSObject *throwTypeError = obj->getThrowTypeError();
|
||||||
|
|
||||||
getter = CastAsPropertyOp(throwTypeError);
|
getter = CastAsPropertyOp(throwTypeError);
|
||||||
|
@ -2060,7 +2054,7 @@ fun_finalize(JSContext *cx, JSObject *obj)
|
||||||
* very early.
|
* very early.
|
||||||
*/
|
*/
|
||||||
if (FUN_INTERPRETED(fun) && fun->u.i.script)
|
if (FUN_INTERPRETED(fun) && fun->u.i.script)
|
||||||
js_DestroyScriptFromGC(cx, fun->u.i.script, NULL);
|
js_DestroyScriptFromGC(cx, fun->u.i.script);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -2603,7 +2597,12 @@ Function(JSContext *cx, uintN argc, Value *vp)
|
||||||
for (uintN i = 0; i < n; i++) {
|
for (uintN i = 0; i < n; i++) {
|
||||||
JSString *arg = argv[i].toString();
|
JSString *arg = argv[i].toString();
|
||||||
size_t arg_length = arg->length();
|
size_t arg_length = arg->length();
|
||||||
(void) js_strncpy(cp, arg->chars(), arg_length);
|
const jschar *arg_chars = arg->getChars(cx);
|
||||||
|
if (!arg_chars) {
|
||||||
|
JS_ARENA_RELEASE(&cx->tempPool, mark);
|
||||||
|
return JS_FALSE;
|
||||||
|
}
|
||||||
|
(void) js_strncpy(cp, arg_chars, arg_length);
|
||||||
cp += arg_length;
|
cp += arg_length;
|
||||||
|
|
||||||
/* Add separating comma or terminating 0. */
|
/* Add separating comma or terminating 0. */
|
||||||
|
@ -2690,8 +2689,11 @@ Function(JSContext *cx, uintN argc, Value *vp)
|
||||||
str = cx->runtime->emptyString;
|
str = cx->runtime->emptyString;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Compiler::compileFunctionBody(cx, fun, principals,
|
size_t length = str->length();
|
||||||
str->chars(), str->length(),
|
const jschar *chars = str->getChars(cx);
|
||||||
|
if (!chars)
|
||||||
|
return JS_FALSE;
|
||||||
|
return Compiler::compileFunctionBody(cx, fun, principals, chars, length,
|
||||||
filename, lineno);
|
filename, lineno);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3143,54 +3145,21 @@ JSFunction::addLocal(JSContext *cx, JSAtom *atom, JSLocalKind kind)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Shape **listp = &u.i.names;
|
|
||||||
Shape *parent = *listp;
|
|
||||||
jsid id;
|
jsid id;
|
||||||
|
|
||||||
/*
|
|
||||||
* The destructuring formal parameter parser adds a null atom, which we
|
|
||||||
* encode as an INT id. The parser adds such locals after adding vars for
|
|
||||||
* the destructured-to parameter bindings -- those must be vars to avoid
|
|
||||||
* aliasing arguments[i] for any i -- so we must switch u.i.names to a
|
|
||||||
* dictionary list to cope with insertion "in the middle" of an index-named
|
|
||||||
* shape for the object or array argument.
|
|
||||||
*/
|
|
||||||
bool findArgInsertionPoint = false;
|
|
||||||
if (!atom) {
|
if (!atom) {
|
||||||
JS_ASSERT(kind == JSLOCAL_ARG);
|
JS_ASSERT(kind == JSLOCAL_ARG);
|
||||||
if (u.i.nvars != 0) {
|
|
||||||
/*
|
|
||||||
* A dictionary list needed only if the destructing pattern wasn't
|
|
||||||
* empty, i.e., there were vars for its destructured-to bindings.
|
|
||||||
*/
|
|
||||||
if (!parent->inDictionary() && !(parent = Shape::newDictionaryList(cx, listp)))
|
|
||||||
return false;
|
|
||||||
findArgInsertionPoint = true;
|
|
||||||
}
|
|
||||||
id = INT_TO_JSID(nargs);
|
id = INT_TO_JSID(nargs);
|
||||||
} else {
|
} else {
|
||||||
if (kind == JSLOCAL_ARG && parent->inDictionary())
|
|
||||||
findArgInsertionPoint = true;
|
|
||||||
id = ATOM_TO_JSID(atom);
|
id = ATOM_TO_JSID(atom);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (findArgInsertionPoint) {
|
|
||||||
while (parent->parent && parent->getter() != GetCallArg) {
|
|
||||||
++parent->slot;
|
|
||||||
JS_ASSERT(parent->slot == parent->slotSpan);
|
|
||||||
++parent->slotSpan;
|
|
||||||
listp = &parent->parent;
|
|
||||||
parent = *listp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Shape child(id, getter, setter, slot, attrs, Shape::HAS_SHORTID, *indexp);
|
Shape child(id, getter, setter, slot, attrs, Shape::HAS_SHORTID, *indexp);
|
||||||
|
|
||||||
Shape *shape = parent->getChild(cx, child, listp);
|
Shape *shape = u.i.names->getChild(cx, child, &u.i.names);
|
||||||
if (!shape)
|
if (!shape)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
JS_ASSERT_IF(!shape->inDictionary(), u.i.names == shape);
|
JS_ASSERT(u.i.names == shape);
|
||||||
++*indexp;
|
++*indexp;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,10 +180,9 @@ struct JSFunction : public JSObject_Slots2
|
||||||
|
|
||||||
bool isFunctionPrototype() const { return flags & JSFUN_PROTOTYPE; }
|
bool isFunctionPrototype() const { return flags & JSFUN_PROTOTYPE; }
|
||||||
|
|
||||||
|
/* Returns the strictness of this function, which must be interpreted. */
|
||||||
inline bool inStrictMode() const;
|
inline bool inStrictMode() const;
|
||||||
|
|
||||||
bool acceptsPrimitiveThis() const { return flags & JSFUN_PRIMITIVE_THIS; }
|
|
||||||
|
|
||||||
uintN countVars() const {
|
uintN countVars() const {
|
||||||
JS_ASSERT(FUN_INTERPRETED(this));
|
JS_ASSERT(FUN_INTERPRETED(this));
|
||||||
return u.i.nvars;
|
return u.i.nvars;
|
||||||
|
@ -215,6 +214,11 @@ struct JSFunction : public JSObject_Slots2
|
||||||
const js::Shape *lastVar() const;
|
const js::Shape *lastVar() const;
|
||||||
const js::Shape *lastUpvar() const { return u.i.names; }
|
const js::Shape *lastUpvar() const { return u.i.names; }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The parser builds shape paths for functions, usable by Call objects at
|
||||||
|
* runtime, by calling addLocal. All locals of ARG kind must be addLocal'ed
|
||||||
|
* before any VAR kind, and VAR before UPVAR.
|
||||||
|
*/
|
||||||
bool addLocal(JSContext *cx, JSAtom *atom, JSLocalKind kind);
|
bool addLocal(JSContext *cx, JSAtom *atom, JSLocalKind kind);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -435,6 +439,14 @@ IsFunctionObject(const js::Value &v, JSFunction **fun)
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern JS_ALWAYS_INLINE bool
|
||||||
|
SameTraceType(const Value &lhs, const Value &rhs)
|
||||||
|
{
|
||||||
|
return SameType(lhs, rhs) &&
|
||||||
|
(lhs.isPrimitive() ||
|
||||||
|
lhs.toObject().isFunction() == rhs.toObject().isFunction());
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Macro to access the private slot of the function object after the slot is
|
* Macro to access the private slot of the function object after the slot is
|
||||||
* initialized.
|
* initialized.
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
inline bool
|
inline bool
|
||||||
JSFunction::inStrictMode() const
|
JSFunction::inStrictMode() const
|
||||||
{
|
{
|
||||||
return isInterpreted() && u.i.script->strictModeCode;
|
return script()->strictModeCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* jsfuninlines_h___ */
|
#endif /* jsfuninlines_h___ */
|
||||||
|
|
|
@ -492,6 +492,13 @@ js_GCThingIsMarked(void *thing, uint32 color = BLACK)
|
||||||
return reinterpret_cast<Cell *>(thing)->isMarked(color);
|
return reinterpret_cast<Cell *>(thing)->isMarked(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 1/8 life for JIT code. After this number of microseconds have passed, 1/8 of all
|
||||||
|
* JIT code is discarded in inactive compartments, regardless of how often that
|
||||||
|
* code runs.
|
||||||
|
*/
|
||||||
|
static const int64 JIT_SCRIPT_EIGHTH_LIFETIME = 120 * 1000 * 1000;
|
||||||
|
|
||||||
JSBool
|
JSBool
|
||||||
js_InitGC(JSRuntime *rt, uint32 maxbytes)
|
js_InitGC(JSRuntime *rt, uint32 maxbytes)
|
||||||
{
|
{
|
||||||
|
@ -539,6 +546,8 @@ js_InitGC(JSRuntime *rt, uint32 maxbytes)
|
||||||
*/
|
*/
|
||||||
rt->setGCLastBytes(8192);
|
rt->setGCLastBytes(8192);
|
||||||
|
|
||||||
|
rt->gcJitReleaseTime = PRMJ_Now() + JIT_SCRIPT_EIGHTH_LIFETIME;
|
||||||
|
|
||||||
METER(PodZero(&rt->gcStats));
|
METER(PodZero(&rt->gcStats));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -777,16 +786,18 @@ ConservativeGCThreadData::recordStackTop()
|
||||||
jsuword dummy;
|
jsuword dummy;
|
||||||
nativeStackTop = &dummy;
|
nativeStackTop = &dummy;
|
||||||
|
|
||||||
/* Update the register snapshot with the latest values. */
|
/*
|
||||||
|
* To record and update the register snapshot for the conservative
|
||||||
|
* scanning with the latest values we use setjmp.
|
||||||
|
*/
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
# pragma warning(push)
|
# pragma warning(push)
|
||||||
# pragma warning(disable: 4611)
|
# pragma warning(disable: 4611)
|
||||||
#endif
|
#endif
|
||||||
setjmp(registerSnapshot.jmpbuf);
|
(void) setjmp(registerSnapshot.jmpbuf);
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
# pragma warning(pop)
|
# pragma warning(pop)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
@ -1016,7 +1027,7 @@ FreeLists::purge()
|
||||||
*p = NULL;
|
*p = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct JSShortString;
|
class JSShortString;
|
||||||
|
|
||||||
ArenaList *
|
ArenaList *
|
||||||
GetFinalizableArenaList(JSCompartment *c, unsigned thingKind) {
|
GetFinalizableArenaList(JSCompartment *c, unsigned thingKind) {
|
||||||
|
@ -1435,8 +1446,10 @@ js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp)
|
||||||
MarkObject(trc, fp->callObj(), "call");
|
MarkObject(trc, fp->callObj(), "call");
|
||||||
if (fp->hasArgsObj())
|
if (fp->hasArgsObj())
|
||||||
MarkObject(trc, fp->argsObj(), "arguments");
|
MarkObject(trc, fp->argsObj(), "arguments");
|
||||||
if (fp->isScriptFrame())
|
if (fp->isScriptFrame()) {
|
||||||
js_TraceScript(trc, fp->script());
|
js_TraceScript(trc, fp->script());
|
||||||
|
fp->script()->compartment->active = true;
|
||||||
|
}
|
||||||
|
|
||||||
MarkValue(trc, fp->returnValue(), "rval");
|
MarkValue(trc, fp->returnValue(), "rval");
|
||||||
}
|
}
|
||||||
|
@ -1732,16 +1745,16 @@ TriggerGC(JSRuntime *rt)
|
||||||
} /* namespace js */
|
} /* namespace js */
|
||||||
|
|
||||||
void
|
void
|
||||||
js_DestroyScriptsToGC(JSContext *cx, JSThreadData *data)
|
js_DestroyScriptsToGC(JSContext *cx, JSCompartment *comp)
|
||||||
{
|
{
|
||||||
JSScript **listp, *script;
|
JSScript **listp, *script;
|
||||||
|
|
||||||
for (size_t i = 0; i != JS_ARRAY_LENGTH(data->scriptsToGC); ++i) {
|
for (size_t i = 0; i != JS_ARRAY_LENGTH(comp->scriptsToGC); ++i) {
|
||||||
listp = &data->scriptsToGC[i];
|
listp = &comp->scriptsToGC[i];
|
||||||
while ((script = *listp) != NULL) {
|
while ((script = *listp) != NULL) {
|
||||||
*listp = script->u.nextToGC;
|
*listp = script->u.nextToGC;
|
||||||
script->u.nextToGC = NULL;
|
script->u.nextToGC = NULL;
|
||||||
js_DestroyScriptFromGC(cx, script, data);
|
js_DestroyScriptFromGC(cx, script);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1767,7 +1780,7 @@ js_FinalizeStringRT(JSRuntime *rt, JSString *str)
|
||||||
JS_ASSERT(IsFinalizableStringKind(thingKind));
|
JS_ASSERT(IsFinalizableStringKind(thingKind));
|
||||||
|
|
||||||
/* A stillborn string has null chars, so is not valid. */
|
/* A stillborn string has null chars, so is not valid. */
|
||||||
jschar *chars = str->flatChars();
|
jschar *chars = const_cast<jschar *>(str->flatChars());
|
||||||
if (!chars)
|
if (!chars)
|
||||||
return;
|
return;
|
||||||
if (thingKind == FINALIZE_STRING) {
|
if (thingKind == FINALIZE_STRING) {
|
||||||
|
@ -2029,13 +2042,29 @@ SweepCompartments(JSContext *cx, JSGCInvocationKind gckind)
|
||||||
/* Delete defaultCompartment only during runtime shutdown */
|
/* Delete defaultCompartment only during runtime shutdown */
|
||||||
rt->defaultCompartment->marked = true;
|
rt->defaultCompartment->marked = true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Figure out how much JIT code should be released from inactive compartments.
|
||||||
|
* If multiple eighth-lifes have passed, compound the release interval linearly;
|
||||||
|
* if enough time has passed, all inactive JIT code will be released.
|
||||||
|
*/
|
||||||
|
uint32 releaseInterval = 0;
|
||||||
|
int64 now = PRMJ_Now();
|
||||||
|
if (now >= rt->gcJitReleaseTime) {
|
||||||
|
releaseInterval = 8;
|
||||||
|
while (now >= rt->gcJitReleaseTime) {
|
||||||
|
if (--releaseInterval == 1)
|
||||||
|
rt->gcJitReleaseTime = now;
|
||||||
|
rt->gcJitReleaseTime += JIT_SCRIPT_EIGHTH_LIFETIME;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (read < end) {
|
while (read < end) {
|
||||||
JSCompartment *compartment = (*read++);
|
JSCompartment *compartment = (*read++);
|
||||||
if (compartment->marked) {
|
if (compartment->marked) {
|
||||||
compartment->marked = false;
|
compartment->marked = false;
|
||||||
*write++ = compartment;
|
*write++ = compartment;
|
||||||
/* Remove dead wrappers from the compartment map. */
|
/* Remove dead wrappers from the compartment map. */
|
||||||
compartment->sweep(cx);
|
compartment->sweep(cx, releaseInterval);
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(compartment->freeLists.isEmpty());
|
JS_ASSERT(compartment->freeLists.isEmpty());
|
||||||
if (compartment->arenaListsAreEmpty() || gckind == GC_LAST_CONTEXT) {
|
if (compartment->arenaListsAreEmpty() || gckind == GC_LAST_CONTEXT) {
|
||||||
|
@ -2047,7 +2076,7 @@ SweepCompartments(JSContext *cx, JSGCInvocationKind gckind)
|
||||||
} else {
|
} else {
|
||||||
compartment->marked = false;
|
compartment->marked = false;
|
||||||
*write++ = compartment;
|
*write++ = compartment;
|
||||||
compartment->sweep(cx);
|
compartment->sweep(cx, releaseInterval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2177,11 +2206,6 @@ MarkAndSweep(JSContext *cx, JSGCInvocationKind gckind GCTIMER_PARAM)
|
||||||
rt->liveObjectPropsPreSweep = rt->liveObjectProps;
|
rt->liveObjectPropsPreSweep = rt->liveObjectProps;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef JS_TRACER
|
|
||||||
for (ThreadDataIter i(rt); !i.empty(); i.popFront())
|
|
||||||
i.threadData()->traceMonitor.sweep();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We finalize iterators before other objects so the iterator can use the
|
* We finalize iterators before other objects so the iterator can use the
|
||||||
* object which properties it enumerates over to finalize the enumeration
|
* object which properties it enumerates over to finalize the enumeration
|
||||||
|
@ -2589,6 +2613,7 @@ NewCompartment(JSContext *cx, JSPrincipals *principals)
|
||||||
JSRuntime *rt = cx->runtime;
|
JSRuntime *rt = cx->runtime;
|
||||||
JSCompartment *compartment = new JSCompartment(rt);
|
JSCompartment *compartment = new JSCompartment(rt);
|
||||||
if (!compartment || !compartment->init()) {
|
if (!compartment || !compartment->init()) {
|
||||||
|
delete compartment;
|
||||||
JS_ReportOutOfMemory(cx);
|
JS_ReportOutOfMemory(cx);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -827,7 +827,7 @@ js_WaitForGC(JSRuntime *rt);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
js_DestroyScriptsToGC(JSContext *cx, JSThreadData *data);
|
js_DestroyScriptsToGC(JSContext *cx, JSCompartment *comp);
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
|
|
|
@ -272,8 +272,6 @@ MarkChildren(JSTracer *trc, JSString *str)
|
||||||
if (str->isDependent())
|
if (str->isDependent())
|
||||||
MarkString(trc, str->dependentBase(), "base");
|
MarkString(trc, str->dependentBase(), "base");
|
||||||
else if (str->isRope()) {
|
else if (str->isRope()) {
|
||||||
if (str->isInteriorNode())
|
|
||||||
MarkString(trc, str->interiorNodeParent(), "parent");
|
|
||||||
MarkString(trc, str->ropeLeft(), "left child");
|
MarkString(trc, str->ropeLeft(), "left child");
|
||||||
MarkString(trc, str->ropeRight(), "right child");
|
MarkString(trc, str->ropeRight(), "right child");
|
||||||
}
|
}
|
||||||
|
@ -347,37 +345,116 @@ TypedMarker(JSTracer *trc, JSFunction *thing)
|
||||||
static JS_ALWAYS_INLINE void
|
static JS_ALWAYS_INLINE void
|
||||||
TypedMarker(JSTracer *trc, JSShortString *thing)
|
TypedMarker(JSTracer *trc, JSShortString *thing)
|
||||||
{
|
{
|
||||||
thing->asCell()->markIfUnmarked();
|
/*
|
||||||
|
* A short string cannot refer to other GC things so we don't have
|
||||||
|
* anything to mark if the string was unmarked and ignore the
|
||||||
|
* markIfUnmarked result.
|
||||||
|
*/
|
||||||
|
(void) thing->asCell()->markIfUnmarked();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} /* namespace gc */
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
static JS_ALWAYS_INLINE JSString *
|
||||||
|
Tag(JSString *str)
|
||||||
|
{
|
||||||
|
JS_ASSERT(!(size_t(str) & 1));
|
||||||
|
return (JSString *)(size_t(str) | 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static JS_ALWAYS_INLINE bool
|
||||||
|
Tagged(JSString *str)
|
||||||
|
{
|
||||||
|
return (size_t(str) & 1) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static JS_ALWAYS_INLINE JSString *
|
||||||
|
Untag(JSString *str)
|
||||||
|
{
|
||||||
|
JS_ASSERT((size_t(str) & 1) == 1);
|
||||||
|
return (JSString *)(size_t(str) & ~size_t(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
static JS_ALWAYS_INLINE void
|
||||||
|
NonRopeTypedMarker(JSString *str)
|
||||||
|
{
|
||||||
|
JS_ASSERT(!str->isRope());
|
||||||
|
if (JSString::isStatic(str) ||
|
||||||
|
!str->asCell()->markIfUnmarked() ||
|
||||||
|
!str->isDependent()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
JSString *base = str->dependentBase();
|
||||||
|
if (JSString::isStatic(base))
|
||||||
|
return;
|
||||||
|
base->asCell()->markIfUnmarked();
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace detail */
|
||||||
|
|
||||||
|
namespace gc {
|
||||||
|
|
||||||
static JS_ALWAYS_INLINE void
|
static JS_ALWAYS_INLINE void
|
||||||
TypedMarker(JSTracer *trc, JSString *str)
|
TypedMarker(JSTracer *trc, JSString *str)
|
||||||
{
|
{
|
||||||
/*
|
using namespace detail;
|
||||||
* When marking any node of a rope, mark the entire rope. This means if
|
|
||||||
* a given rope node is already marked, we are done.
|
if (!str->isRope()) {
|
||||||
*/
|
NonRopeTypedMarker(str);
|
||||||
JSRopeNodeIterator iter;
|
|
||||||
if (str->isRope()) {
|
|
||||||
if (str->asCell()->isMarked())
|
|
||||||
return;
|
return;
|
||||||
str = iter.init(str);
|
|
||||||
goto not_static;
|
|
||||||
}
|
}
|
||||||
do {
|
|
||||||
for (;;) {
|
/*
|
||||||
if (JSString::isStatic(str))
|
* This function must not fail, so a simple stack-based traversal must not
|
||||||
break;
|
* be used (since it may oom if the stack grows large). Instead, strings
|
||||||
not_static:
|
* are temporarily mutated to embed parent pointers as they are traversed.
|
||||||
JS_ASSERT(JSTRACE_STRING == GetFinalizableTraceKind(str->asCell()->arena()->header()->thingKind));
|
* This algorithm is homomorphic to JSString::flatten.
|
||||||
|
*/
|
||||||
|
JSString *parent = NULL;
|
||||||
|
first_visit_node: {
|
||||||
if (!str->asCell()->markIfUnmarked())
|
if (!str->asCell()->markIfUnmarked())
|
||||||
break;
|
goto finish_node;
|
||||||
if (!str->isDependent())
|
JSString *left = str->ropeLeft();
|
||||||
break;
|
if (left->isRope()) {
|
||||||
str = str->dependentBase();
|
JS_ASSERT(!Tagged(str->u.left) && !Tagged(str->s.right));
|
||||||
|
str->u.left = Tag(parent);
|
||||||
|
parent = str;
|
||||||
|
str = left;
|
||||||
|
goto first_visit_node;
|
||||||
|
}
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
str = iter.next();
|
|
||||||
} while (str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
|
|
@ -362,9 +362,13 @@ GCMarker::dumpConservativeRoots()
|
||||||
}
|
}
|
||||||
case JSTRACE_STRING: {
|
case JSTRACE_STRING: {
|
||||||
JSString *str = (JSString *) i->thing;
|
JSString *str = (JSString *) i->thing;
|
||||||
|
if (str->isLinear()) {
|
||||||
char buf[50];
|
char buf[50];
|
||||||
PutEscapedString(buf, sizeof buf, str, '"');
|
PutEscapedString(buf, sizeof buf, str->assertIsLinear(), '"');
|
||||||
fprintf(fp, "string %s", buf);
|
fprintf(fp, "string %s", buf);
|
||||||
|
} else {
|
||||||
|
fprintf(fp, "rope: length %d", (int)str->length());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
# if JS_HAS_XML_SUPPORT
|
# if JS_HAS_XML_SUPPORT
|
||||||
|
|
|
@ -1000,21 +1000,12 @@ Execute(JSContext *cx, JSObject *chain, JSScript *script,
|
||||||
|
|
||||||
Probes::startExecution(cx, script);
|
Probes::startExecution(cx, script);
|
||||||
|
|
||||||
void *hookData = NULL;
|
|
||||||
if (JSInterpreterHook hook = cx->debugHooks->executeHook)
|
|
||||||
hookData = hook(cx, frame.fp(), JS_TRUE, 0, cx->debugHooks->executeHookData);
|
|
||||||
|
|
||||||
/* Run script until JSOP_STOP or error. */
|
/* Run script until JSOP_STOP or error. */
|
||||||
AutoPreserveEnumerators preserve(cx);
|
AutoPreserveEnumerators preserve(cx);
|
||||||
JSBool ok = RunScript(cx, script, frame.fp());
|
JSBool ok = RunScript(cx, script, frame.fp());
|
||||||
if (result)
|
if (result)
|
||||||
*result = frame.fp()->returnValue();
|
*result = frame.fp()->returnValue();
|
||||||
|
|
||||||
if (hookData) {
|
|
||||||
if (JSInterpreterHook hook = cx->debugHooks->executeHook)
|
|
||||||
hook(cx, frame.fp(), JS_FALSE, &ok, hookData);
|
|
||||||
}
|
|
||||||
|
|
||||||
Probes::stopExecution(cx, script);
|
Probes::stopExecution(cx, script);
|
||||||
|
|
||||||
return !!ok;
|
return !!ok;
|
||||||
|
@ -1143,40 +1134,44 @@ HasInstance(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static JS_ALWAYS_INLINE bool
|
|
||||||
EqualObjects(JSContext *cx, JSObject *lobj, JSObject *robj)
|
|
||||||
{
|
|
||||||
return lobj == robj;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
StrictlyEqual(JSContext *cx, const Value &lref, const Value &rref)
|
StrictlyEqual(JSContext *cx, const Value &lref, const Value &rref, JSBool *equal)
|
||||||
{
|
{
|
||||||
Value lval = lref, rval = rref;
|
Value lval = lref, rval = rref;
|
||||||
if (SameType(lval, rval)) {
|
if (SameType(lval, rval)) {
|
||||||
if (lval.isString())
|
if (lval.isString())
|
||||||
return js_EqualStrings(lval.toString(), rval.toString());
|
return EqualStrings(cx, lval.toString(), rval.toString(), equal);
|
||||||
if (lval.isDouble())
|
if (lval.isDouble()) {
|
||||||
return JSDOUBLE_COMPARE(lval.toDouble(), ==, rval.toDouble(), JS_FALSE);
|
*equal = JSDOUBLE_COMPARE(lval.toDouble(), ==, rval.toDouble(), JS_FALSE);
|
||||||
if (lval.isObject())
|
return true;
|
||||||
return EqualObjects(cx, &lval.toObject(), &rval.toObject());
|
}
|
||||||
if (lval.isUndefined())
|
if (lval.isObject()) {
|
||||||
|
*equal = &lval.toObject() == &rval.toObject();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (lval.isUndefined()) {
|
||||||
|
*equal = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
*equal = lval.payloadAsRawUint32() == rval.payloadAsRawUint32();
|
||||||
return true;
|
return true;
|
||||||
return lval.payloadAsRawUint32() == rval.payloadAsRawUint32();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lval.isDouble() && rval.isInt32()) {
|
if (lval.isDouble() && rval.isInt32()) {
|
||||||
double ld = lval.toDouble();
|
double ld = lval.toDouble();
|
||||||
double rd = rval.toInt32();
|
double rd = rval.toInt32();
|
||||||
return JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE);
|
*equal = JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
if (lval.isInt32() && rval.isDouble()) {
|
if (lval.isInt32() && rval.isDouble()) {
|
||||||
double ld = lval.toInt32();
|
double ld = lval.toInt32();
|
||||||
double rd = rval.toDouble();
|
double rd = rval.toDouble();
|
||||||
return JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE);
|
*equal = JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
*equal = false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
|
@ -1192,15 +1187,21 @@ IsNaN(const Value &v)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SameValue(const Value &v1, const Value &v2, JSContext *cx)
|
SameValue(JSContext *cx, const Value &v1, const Value &v2, JSBool *same)
|
||||||
{
|
{
|
||||||
if (IsNegativeZero(v1))
|
if (IsNegativeZero(v1)) {
|
||||||
return IsNegativeZero(v2);
|
*same = IsNegativeZero(v2);
|
||||||
if (IsNegativeZero(v2))
|
|
||||||
return false;
|
|
||||||
if (IsNaN(v1) && IsNaN(v2))
|
|
||||||
return true;
|
return true;
|
||||||
return StrictlyEqual(cx, v1, v2);
|
}
|
||||||
|
if (IsNegativeZero(v2)) {
|
||||||
|
*same = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (IsNaN(v1) && IsNaN(v2)) {
|
||||||
|
*same = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return StrictlyEqual(cx, v1, v2, same);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSType
|
JSType
|
||||||
|
@ -1529,7 +1530,6 @@ js_LogOpcode(JSContext *cx)
|
||||||
JSStackFrame *fp;
|
JSStackFrame *fp;
|
||||||
JSFrameRegs *regs;
|
JSFrameRegs *regs;
|
||||||
intN ndefs, n, nuses;
|
intN ndefs, n, nuses;
|
||||||
JSString *str;
|
|
||||||
JSOp op;
|
JSOp op;
|
||||||
|
|
||||||
logfp = (FILE *) cx->logfp;
|
logfp = (FILE *) cx->logfp;
|
||||||
|
@ -1575,12 +1575,13 @@ js_LogOpcode(JSContext *cx)
|
||||||
*/
|
*/
|
||||||
fputs("<call>", logfp);
|
fputs("<call>", logfp);
|
||||||
} else {
|
} else {
|
||||||
str = js_ValueToString(cx, *siter);
|
JSString *str = js_ValueToString(cx, *siter);
|
||||||
if (!str) {
|
JSLinearString *linearStr = str ? str->ensureLinear(cx) : NULL;
|
||||||
|
if (!linearStr) {
|
||||||
fputs("<null>", logfp);
|
fputs("<null>", logfp);
|
||||||
} else {
|
|
||||||
JS_ClearPendingException(cx);
|
JS_ClearPendingException(cx);
|
||||||
FileEscapedString(logfp, str, 0);
|
} else {
|
||||||
|
FileEscapedString(logfp, linearStr, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fputc(' ', logfp);
|
fputc(' ', logfp);
|
||||||
|
@ -2203,12 +2204,14 @@ ScriptPrologue(JSContext *cx, JSStackFrame *fp)
|
||||||
return false;
|
return false;
|
||||||
fp->functionThis().setObject(*obj);
|
fp->functionThis().setObject(*obj);
|
||||||
}
|
}
|
||||||
JSInterpreterHook hook = cx->debugHooks->callHook;
|
if (fp->isExecuteFrame()) {
|
||||||
if (JS_UNLIKELY(hook != NULL) && !fp->isExecuteFrame())
|
if (JSInterpreterHook hook = cx->debugHooks->executeHook)
|
||||||
|
fp->setHookData(hook(cx, fp, JS_TRUE, 0, cx->debugHooks->executeHookData));
|
||||||
|
} else {
|
||||||
|
if (JSInterpreterHook hook = cx->debugHooks->callHook)
|
||||||
fp->setHookData(hook(cx, fp, JS_TRUE, 0, cx->debugHooks->callHookData));
|
fp->setHookData(hook(cx, fp, JS_TRUE, 0, cx->debugHooks->callHookData));
|
||||||
|
|
||||||
if (!fp->isExecuteFrame())
|
|
||||||
Probes::enterJSFun(cx, fp->maybeFun(), fp->maybeScript());
|
Probes::enterJSFun(cx, fp->maybeFun(), fp->maybeScript());
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -3093,8 +3096,6 @@ BEGIN_CASE(JSOP_MOREITER)
|
||||||
if (!IteratorMore(cx, ®s.sp[-2].toObject(), &cond, ®s.sp[-1]))
|
if (!IteratorMore(cx, ®s.sp[-2].toObject(), &cond, ®s.sp[-1]))
|
||||||
goto error;
|
goto error;
|
||||||
CHECK_INTERRUPT_HANDLER();
|
CHECK_INTERRUPT_HANDLER();
|
||||||
TRY_BRANCH_AFTER_COND(cond, 1);
|
|
||||||
JS_ASSERT(regs.pc[1] == JSOP_IFNEX);
|
|
||||||
regs.sp[-1].setBoolean(cond);
|
regs.sp[-1].setBoolean(cond);
|
||||||
}
|
}
|
||||||
END_CASE(JSOP_MOREITER)
|
END_CASE(JSOP_MOREITER)
|
||||||
|
@ -3421,7 +3422,10 @@ END_CASE(JSOP_BITAND)
|
||||||
if (SameType(lval, rval)) { \
|
if (SameType(lval, rval)) { \
|
||||||
if (lval.isString()) { \
|
if (lval.isString()) { \
|
||||||
JSString *l = lval.toString(), *r = rval.toString(); \
|
JSString *l = lval.toString(), *r = rval.toString(); \
|
||||||
cond = js_EqualStrings(l, r) OP JS_TRUE; \
|
JSBool equal; \
|
||||||
|
if (!EqualStrings(cx, l, r, &equal)) \
|
||||||
|
goto error; \
|
||||||
|
cond = equal OP JS_TRUE; \
|
||||||
} else if (lval.isDouble()) { \
|
} else if (lval.isDouble()) { \
|
||||||
double l = lval.toDouble(), r = rval.toDouble(); \
|
double l = lval.toDouble(), r = rval.toDouble(); \
|
||||||
cond = JSDOUBLE_COMPARE(l, OP, r, IFNAN); \
|
cond = JSDOUBLE_COMPARE(l, OP, r, IFNAN); \
|
||||||
|
@ -3450,7 +3454,10 @@ END_CASE(JSOP_BITAND)
|
||||||
DEFAULT_VALUE(cx, -1, JSTYPE_VOID, rval); \
|
DEFAULT_VALUE(cx, -1, JSTYPE_VOID, rval); \
|
||||||
if (lval.isString() && rval.isString()) { \
|
if (lval.isString() && rval.isString()) { \
|
||||||
JSString *l = lval.toString(), *r = rval.toString(); \
|
JSString *l = lval.toString(), *r = rval.toString(); \
|
||||||
cond = js_EqualStrings(l, r) OP JS_TRUE; \
|
JSBool equal; \
|
||||||
|
if (!EqualStrings(cx, l, r, &equal)) \
|
||||||
|
goto error; \
|
||||||
|
cond = equal OP JS_TRUE; \
|
||||||
} else { \
|
} else { \
|
||||||
double l, r; \
|
double l, r; \
|
||||||
if (!ValueToNumber(cx, lval, &l) || \
|
if (!ValueToNumber(cx, lval, &l) || \
|
||||||
|
@ -3482,7 +3489,10 @@ END_CASE(JSOP_NE)
|
||||||
JS_BEGIN_MACRO \
|
JS_BEGIN_MACRO \
|
||||||
const Value &rref = regs.sp[-1]; \
|
const Value &rref = regs.sp[-1]; \
|
||||||
const Value &lref = regs.sp[-2]; \
|
const Value &lref = regs.sp[-2]; \
|
||||||
COND = StrictlyEqual(cx, lref, rref) OP true; \
|
JSBool equal; \
|
||||||
|
if (!StrictlyEqual(cx, lref, rref, &equal)) \
|
||||||
|
goto error; \
|
||||||
|
COND = equal OP JS_TRUE; \
|
||||||
regs.sp--; \
|
regs.sp--; \
|
||||||
JS_END_MACRO
|
JS_END_MACRO
|
||||||
|
|
||||||
|
@ -3543,7 +3553,10 @@ END_CASE(JSOP_CASEX)
|
||||||
DEFAULT_VALUE(cx, -1, JSTYPE_NUMBER, rval); \
|
DEFAULT_VALUE(cx, -1, JSTYPE_NUMBER, rval); \
|
||||||
if (lval.isString() && rval.isString()) { \
|
if (lval.isString() && rval.isString()) { \
|
||||||
JSString *l = lval.toString(), *r = rval.toString(); \
|
JSString *l = lval.toString(), *r = rval.toString(); \
|
||||||
cond = js_CompareStrings(l, r) OP 0; \
|
int32 result; \
|
||||||
|
if (!CompareStrings(cx, l, r, &result)) \
|
||||||
|
goto error; \
|
||||||
|
cond = result OP 0; \
|
||||||
} else { \
|
} else { \
|
||||||
double l, r; \
|
double l, r; \
|
||||||
if (!ValueToNumber(cx, lval, &l) || \
|
if (!ValueToNumber(cx, lval, &l) || \
|
||||||
|
@ -5126,12 +5139,14 @@ BEGIN_CASE(JSOP_LOOKUPSWITCH)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lval.isString()) {
|
if (lval.isString()) {
|
||||||
JSString *str = lval.toString();
|
JSLinearString *str = lval.toString()->ensureLinear(cx);
|
||||||
JSString *str2;
|
if (!str)
|
||||||
|
goto error;
|
||||||
|
JSLinearString *str2;
|
||||||
SEARCH_PAIRS(
|
SEARCH_PAIRS(
|
||||||
match = (rval.isString() &&
|
match = (rval.isString() &&
|
||||||
((str2 = rval.toString()) == str ||
|
((str2 = rval.toString()->assertIsLinear()) == str ||
|
||||||
js_EqualStrings(str2, str)));
|
EqualStrings(str2, str)));
|
||||||
)
|
)
|
||||||
} else if (lval.isNumber()) {
|
} else if (lval.isNumber()) {
|
||||||
double ldbl = lval.toNumber();
|
double ldbl = lval.toNumber();
|
||||||
|
|
|
@ -857,13 +857,6 @@ ComputeThisFromVpInPlace(JSContext *cx, js::Value *vp)
|
||||||
return ComputeThisFromArgv(cx, vp + 2);
|
return ComputeThisFromArgv(cx, vp + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return true if |fun| would accept |v| as its |this|, without being wrapped. */
|
|
||||||
JS_ALWAYS_INLINE bool
|
|
||||||
PrimitiveThisTest(JSFunction *fun, const Value &v)
|
|
||||||
{
|
|
||||||
return !v.isPrimitive() || fun->acceptsPrimitiveThis();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Abstracts the layout of the stack passed to natives from the engine and from
|
* Abstracts the layout of the stack passed to natives from the engine and from
|
||||||
* natives to js::Invoke.
|
* natives to js::Invoke.
|
||||||
|
@ -1030,11 +1023,11 @@ CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs,
|
||||||
JSObject **objp, JSProperty **propp);
|
JSObject **objp, JSProperty **propp);
|
||||||
|
|
||||||
extern bool
|
extern bool
|
||||||
StrictlyEqual(JSContext *cx, const Value &lval, const Value &rval);
|
StrictlyEqual(JSContext *cx, const Value &lval, const Value &rval, JSBool *equal);
|
||||||
|
|
||||||
/* === except that NaN is the same as NaN and -0 is not the same as +0. */
|
/* === except that NaN is the same as NaN and -0 is not the same as +0. */
|
||||||
extern bool
|
extern bool
|
||||||
SameValue(const Value &v1, const Value &v2, JSContext *cx);
|
SameValue(JSContext *cx, const Value &v1, const Value &v2, JSBool *same);
|
||||||
|
|
||||||
extern JSType
|
extern JSType
|
||||||
TypeOfValue(JSContext *cx, const Value &v);
|
TypeOfValue(JSContext *cx, const Value &v);
|
||||||
|
|
|
@ -49,6 +49,8 @@
|
||||||
#include "jsstr.h"
|
#include "jsstr.h"
|
||||||
#include "methodjit/MethodJIT.h"
|
#include "methodjit/MethodJIT.h"
|
||||||
|
|
||||||
|
#include "jsfuninlines.h"
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
JSStackFrame::initPrev(JSContext *cx)
|
JSStackFrame::initPrev(JSContext *cx)
|
||||||
{
|
{
|
||||||
|
@ -356,7 +358,7 @@ JSStackFrame::computeThis(JSContext *cx)
|
||||||
if (thisv.isObject())
|
if (thisv.isObject())
|
||||||
return true;
|
return true;
|
||||||
if (isFunctionFrame()) {
|
if (isFunctionFrame()) {
|
||||||
if (fun()->acceptsPrimitiveThis())
|
if (fun()->inStrictMode())
|
||||||
return true;
|
return true;
|
||||||
/*
|
/*
|
||||||
* Eval function frames have their own |this| slot, which is a copy of the function's
|
* Eval function frames have their own |this| slot, which is a copy of the function's
|
||||||
|
@ -713,10 +715,11 @@ ScriptEpilogue(JSContext *cx, JSStackFrame *fp, JSBool ok)
|
||||||
if (!fp->isExecuteFrame())
|
if (!fp->isExecuteFrame())
|
||||||
Probes::exitJSFun(cx, fp->maybeFun(), fp->maybeScript());
|
Probes::exitJSFun(cx, fp->maybeFun(), fp->maybeScript());
|
||||||
|
|
||||||
JSInterpreterHook hook = cx->debugHooks->callHook;
|
JSInterpreterHook hook =
|
||||||
void* hookData;
|
fp->isExecuteFrame() ? cx->debugHooks->executeHook : cx->debugHooks->callHook;
|
||||||
|
|
||||||
if (hook && (hookData = fp->maybeHookData()) && !fp->isExecuteFrame())
|
void* hookData;
|
||||||
|
if (JS_UNLIKELY(hook != NULL) && (hookData = fp->maybeHookData()))
|
||||||
hook(cx, fp, JS_FALSE, &ok, hookData);
|
hook(cx, fp, JS_FALSE, &ok, hookData);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -626,8 +626,6 @@ UpdateNativeIterator(NativeIterator *ni, JSObject *obj)
|
||||||
bool
|
bool
|
||||||
GetIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp)
|
GetIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp)
|
||||||
{
|
{
|
||||||
uint32 hash;
|
|
||||||
JSObject **hp;
|
|
||||||
Vector<uint32, 8> shapes(cx);
|
Vector<uint32, 8> shapes(cx);
|
||||||
uint32 key = 0;
|
uint32 key = 0;
|
||||||
|
|
||||||
|
@ -651,7 +649,7 @@ GetIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp)
|
||||||
* objects here, as they are not inserted into the cache and
|
* objects here, as they are not inserted into the cache and
|
||||||
* will result in a miss.
|
* will result in a miss.
|
||||||
*/
|
*/
|
||||||
JSObject *last = JS_THREAD_DATA(cx)->lastNativeIterator;
|
JSObject *last = cx->compartment->nativeIterCache.last;
|
||||||
JSObject *proto = obj->getProto();
|
JSObject *proto = obj->getProto();
|
||||||
if (last) {
|
if (last) {
|
||||||
NativeIterator *lastni = last->getNativeIterator();
|
NativeIterator *lastni = last->getNativeIterator();
|
||||||
|
@ -689,9 +687,7 @@ GetIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp)
|
||||||
pobj = pobj->getProto();
|
pobj = pobj->getProto();
|
||||||
} while (pobj);
|
} while (pobj);
|
||||||
|
|
||||||
hash = key % JS_ARRAY_LENGTH(JS_THREAD_DATA(cx)->cachedNativeIterators);
|
JSObject *iterobj = cx->compartment->nativeIterCache.get(key);
|
||||||
hp = &JS_THREAD_DATA(cx)->cachedNativeIterators[hash];
|
|
||||||
JSObject *iterobj = *hp;
|
|
||||||
if (iterobj) {
|
if (iterobj) {
|
||||||
NativeIterator *ni = iterobj->getNativeIterator();
|
NativeIterator *ni = iterobj->getNativeIterator();
|
||||||
if (!(ni->flags & JSITER_ACTIVE) &&
|
if (!(ni->flags & JSITER_ACTIVE) &&
|
||||||
|
@ -703,7 +699,7 @@ GetIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp)
|
||||||
UpdateNativeIterator(ni, obj);
|
UpdateNativeIterator(ni, obj);
|
||||||
RegisterEnumerator(cx, iterobj, ni);
|
RegisterEnumerator(cx, iterobj, ni);
|
||||||
if (shapes.length() == 2)
|
if (shapes.length() == 2)
|
||||||
JS_THREAD_DATA(cx)->lastNativeIterator = iterobj;
|
cx->compartment->nativeIterCache.last = iterobj;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -738,14 +734,11 @@ GetIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp)
|
||||||
JSObject *iterobj = &vp->toObject();
|
JSObject *iterobj = &vp->toObject();
|
||||||
|
|
||||||
/* Cache the iterator object if possible. */
|
/* Cache the iterator object if possible. */
|
||||||
if (shapes.length()) {
|
if (shapes.length())
|
||||||
uint32 hash = key % NATIVE_ITER_CACHE_SIZE;
|
cx->compartment->nativeIterCache.set(key, iterobj);
|
||||||
JSObject **hp = &JS_THREAD_DATA(cx)->cachedNativeIterators[hash];
|
|
||||||
*hp = iterobj;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shapes.length() == 2)
|
if (shapes.length() == 2)
|
||||||
JS_THREAD_DATA(cx)->lastNativeIterator = iterobj;
|
cx->compartment->nativeIterCache.last = iterobj;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@
|
||||||
#include "jsmath.h"
|
#include "jsmath.h"
|
||||||
#include "jsnum.h"
|
#include "jsnum.h"
|
||||||
#include "jslibmath.h"
|
#include "jslibmath.h"
|
||||||
|
#include "jscompartment.h"
|
||||||
|
|
||||||
using namespace js;
|
using namespace js;
|
||||||
|
|
||||||
|
@ -148,7 +149,7 @@ math_acos(JSContext *cx, uintN argc, Value *vp)
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
MathCache *mathCache = JS_THREAD_DATA(cx)->getMathCache(cx);
|
MathCache *mathCache = GetMathCache(cx);
|
||||||
if (!mathCache)
|
if (!mathCache)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
z = mathCache->lookup(acos, x);
|
z = mathCache->lookup(acos, x);
|
||||||
|
@ -173,7 +174,7 @@ math_asin(JSContext *cx, uintN argc, Value *vp)
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
MathCache *mathCache = JS_THREAD_DATA(cx)->getMathCache(cx);
|
MathCache *mathCache = GetMathCache(cx);
|
||||||
if (!mathCache)
|
if (!mathCache)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
z = mathCache->lookup(asin, x);
|
z = mathCache->lookup(asin, x);
|
||||||
|
@ -192,7 +193,7 @@ math_atan(JSContext *cx, uintN argc, Value *vp)
|
||||||
}
|
}
|
||||||
if (!ValueToNumber(cx, vp[2], &x))
|
if (!ValueToNumber(cx, vp[2], &x))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
MathCache *mathCache = JS_THREAD_DATA(cx)->getMathCache(cx);
|
MathCache *mathCache = GetMathCache(cx);
|
||||||
if (!mathCache)
|
if (!mathCache)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
z = mathCache->lookup(atan, x);
|
z = mathCache->lookup(atan, x);
|
||||||
|
@ -285,7 +286,7 @@ math_cos(JSContext *cx, uintN argc, Value *vp)
|
||||||
}
|
}
|
||||||
if (!ValueToNumber(cx, vp[2], &x))
|
if (!ValueToNumber(cx, vp[2], &x))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
MathCache *mathCache = JS_THREAD_DATA(cx)->getMathCache(cx);
|
MathCache *mathCache = GetMathCache(cx);
|
||||||
if (!mathCache)
|
if (!mathCache)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
z = mathCache->lookup(cos, x);
|
z = mathCache->lookup(cos, x);
|
||||||
|
@ -318,7 +319,7 @@ math_exp(JSContext *cx, uintN argc, Value *vp)
|
||||||
}
|
}
|
||||||
if (!ValueToNumber(cx, vp[2], &x))
|
if (!ValueToNumber(cx, vp[2], &x))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
MathCache *mathCache = JS_THREAD_DATA(cx)->getMathCache(cx);
|
MathCache *mathCache = GetMathCache(cx);
|
||||||
if (!mathCache)
|
if (!mathCache)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
z = mathCache->lookup(math_exp_body, x);
|
z = mathCache->lookup(math_exp_body, x);
|
||||||
|
@ -365,7 +366,7 @@ math_log(JSContext *cx, uintN argc, Value *vp)
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
MathCache *mathCache = JS_THREAD_DATA(cx)->getMathCache(cx);
|
MathCache *mathCache = GetMathCache(cx);
|
||||||
if (!mathCache)
|
if (!mathCache)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
z = mathCache->lookup(log, x);
|
z = mathCache->lookup(log, x);
|
||||||
|
@ -612,7 +613,7 @@ math_sin(JSContext *cx, uintN argc, Value *vp)
|
||||||
}
|
}
|
||||||
if (!ValueToNumber(cx, vp[2], &x))
|
if (!ValueToNumber(cx, vp[2], &x))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
MathCache *mathCache = JS_THREAD_DATA(cx)->getMathCache(cx);
|
MathCache *mathCache = GetMathCache(cx);
|
||||||
if (!mathCache)
|
if (!mathCache)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
z = mathCache->lookup(sin, x);
|
z = mathCache->lookup(sin, x);
|
||||||
|
@ -631,7 +632,7 @@ math_sqrt(JSContext *cx, uintN argc, Value *vp)
|
||||||
}
|
}
|
||||||
if (!ValueToNumber(cx, vp[2], &x))
|
if (!ValueToNumber(cx, vp[2], &x))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
MathCache *mathCache = JS_THREAD_DATA(cx)->getMathCache(cx);
|
MathCache *mathCache = GetMathCache(cx);
|
||||||
if (!mathCache)
|
if (!mathCache)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
z = mathCache->lookup(sqrt, x);
|
z = mathCache->lookup(sqrt, x);
|
||||||
|
@ -650,7 +651,7 @@ math_tan(JSContext *cx, uintN argc, Value *vp)
|
||||||
}
|
}
|
||||||
if (!ValueToNumber(cx, vp[2], &x))
|
if (!ValueToNumber(cx, vp[2], &x))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
MathCache *mathCache = JS_THREAD_DATA(cx)->getMathCache(cx);
|
MathCache *mathCache = GetMathCache(cx);
|
||||||
if (!mathCache)
|
if (!mathCache)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
z = mathCache->lookup(tan, x);
|
z = mathCache->lookup(tan, x);
|
||||||
|
|
|
@ -315,7 +315,10 @@ num_parseFloat(JSContext *cx, uintN argc, Value *vp)
|
||||||
str = js_ValueToString(cx, vp[2]);
|
str = js_ValueToString(cx, vp[2]);
|
||||||
if (!str)
|
if (!str)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
str->getCharsAndEnd(bp, end);
|
bp = str->getChars(cx);
|
||||||
|
if (!bp)
|
||||||
|
return JS_FALSE;
|
||||||
|
end = bp + str->length();
|
||||||
if (!js_strtod(cx, bp, end, &ep, &d))
|
if (!js_strtod(cx, bp, end, &ep, &d))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
if (ep == bp) {
|
if (ep == bp) {
|
||||||
|
@ -330,12 +333,15 @@ num_parseFloat(JSContext *cx, uintN argc, Value *vp)
|
||||||
static jsdouble FASTCALL
|
static jsdouble FASTCALL
|
||||||
ParseFloat(JSContext* cx, JSString* str)
|
ParseFloat(JSContext* cx, JSString* str)
|
||||||
{
|
{
|
||||||
const jschar* bp;
|
const jschar *bp = str->getChars(cx);
|
||||||
const jschar* end;
|
if (!bp) {
|
||||||
const jschar* ep;
|
SetBuiltinError(cx);
|
||||||
jsdouble d;
|
return js_NaN;
|
||||||
|
}
|
||||||
|
const jschar *end = bp + str->length();
|
||||||
|
|
||||||
str->getCharsAndEnd(bp, end);
|
const jschar *ep;
|
||||||
|
double d;
|
||||||
if (!js_strtod(cx, bp, end, &ep, &d) || ep == bp)
|
if (!js_strtod(cx, bp, end, &ep, &d) || ep == bp)
|
||||||
return js_NaN;
|
return js_NaN;
|
||||||
return d;
|
return d;
|
||||||
|
@ -451,8 +457,10 @@ num_parseInt(JSContext *cx, uintN argc, Value *vp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Steps 2-5, 9-14. */
|
/* Steps 2-5, 9-14. */
|
||||||
const jschar *ws, *end;
|
const jschar *ws = inputString->getChars(cx);
|
||||||
inputString->getCharsAndEnd(ws, end);
|
if (!ws)
|
||||||
|
return false;
|
||||||
|
const jschar *end = ws + inputString->length();
|
||||||
|
|
||||||
jsdouble number;
|
jsdouble number;
|
||||||
if (!ParseIntStringHelper(cx, ws, end, radix, stripPrefix, &number))
|
if (!ParseIntStringHelper(cx, ws, end, radix, stripPrefix, &number))
|
||||||
|
@ -467,8 +475,12 @@ num_parseInt(JSContext *cx, uintN argc, Value *vp)
|
||||||
static jsdouble FASTCALL
|
static jsdouble FASTCALL
|
||||||
ParseInt(JSContext* cx, JSString* str)
|
ParseInt(JSContext* cx, JSString* str)
|
||||||
{
|
{
|
||||||
const jschar *start, *end;
|
const jschar *start = str->getChars(cx);
|
||||||
str->getCharsAndEnd(start, end);
|
if (!start) {
|
||||||
|
SetBuiltinError(cx);
|
||||||
|
return js_NaN;
|
||||||
|
}
|
||||||
|
const jschar *end = start + str->length();
|
||||||
|
|
||||||
jsdouble d;
|
jsdouble d;
|
||||||
if (!ParseIntStringHelper(cx, start, end, 0, true, &d)) {
|
if (!ParseIntStringHelper(cx, start, end, 0, true, &d)) {
|
||||||
|
@ -499,7 +511,7 @@ JS_DEFINE_TRCINFO_2(num_parseInt,
|
||||||
(1, (static, DOUBLE, ParseIntDouble, DOUBLE, 1, nanojit::ACCSET_NONE)))
|
(1, (static, DOUBLE, ParseIntDouble, DOUBLE, 1, nanojit::ACCSET_NONE)))
|
||||||
|
|
||||||
JS_DEFINE_TRCINFO_1(num_parseFloat,
|
JS_DEFINE_TRCINFO_1(num_parseFloat,
|
||||||
(2, (static, DOUBLE, ParseFloat, CONTEXT, STRING, 1, nanojit::ACCSET_NONE)))
|
(2, (static, DOUBLE_FAIL, ParseFloat, CONTEXT, STRING, 1, nanojit::ACCSET_NONE)))
|
||||||
|
|
||||||
#endif /* JS_TRACER */
|
#endif /* JS_TRACER */
|
||||||
|
|
||||||
|
@ -722,7 +734,7 @@ num_toLocaleString(JSContext *cx, uintN argc, Value *vp)
|
||||||
const char *num, *end, *tmpSrc;
|
const char *num, *end, *tmpSrc;
|
||||||
char *buf, *tmpDest;
|
char *buf, *tmpDest;
|
||||||
const char *nint;
|
const char *nint;
|
||||||
int digits, size, remainder, nrepeat;
|
int digits, buflen, remainder, nrepeat;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create the string, move back to bytes to make string twiddling
|
* Create the string, move back to bytes to make string twiddling
|
||||||
|
@ -757,9 +769,9 @@ num_toLocaleString(JSContext *cx, uintN argc, Value *vp)
|
||||||
decimalLength = strlen(rt->decimalSeparator);
|
decimalLength = strlen(rt->decimalSeparator);
|
||||||
|
|
||||||
/* Figure out how long resulting string will be. */
|
/* Figure out how long resulting string will be. */
|
||||||
size = digits + (*nint ? strlen(nint + 1) + 1 : 0);
|
buflen = digits + (*nint ? strlen(nint + 1) : 0);
|
||||||
if (*nint == '.')
|
if (*nint == '.')
|
||||||
size += decimalLength;
|
buflen += decimalLength;
|
||||||
|
|
||||||
numGrouping = tmpGroup = rt->numGrouping;
|
numGrouping = tmpGroup = rt->numGrouping;
|
||||||
remainder = digits;
|
remainder = digits;
|
||||||
|
@ -769,20 +781,20 @@ num_toLocaleString(JSContext *cx, uintN argc, Value *vp)
|
||||||
while (*tmpGroup != CHAR_MAX && *tmpGroup != '\0') {
|
while (*tmpGroup != CHAR_MAX && *tmpGroup != '\0') {
|
||||||
if (*tmpGroup >= remainder)
|
if (*tmpGroup >= remainder)
|
||||||
break;
|
break;
|
||||||
size += thousandsLength;
|
buflen += thousandsLength;
|
||||||
remainder -= *tmpGroup;
|
remainder -= *tmpGroup;
|
||||||
tmpGroup++;
|
tmpGroup++;
|
||||||
}
|
}
|
||||||
if (*tmpGroup == '\0' && *numGrouping != '\0') {
|
if (*tmpGroup == '\0' && *numGrouping != '\0') {
|
||||||
nrepeat = (remainder - 1) / tmpGroup[-1];
|
nrepeat = (remainder - 1) / tmpGroup[-1];
|
||||||
size += thousandsLength * nrepeat;
|
buflen += thousandsLength * nrepeat;
|
||||||
remainder -= nrepeat * tmpGroup[-1];
|
remainder -= nrepeat * tmpGroup[-1];
|
||||||
} else {
|
} else {
|
||||||
nrepeat = 0;
|
nrepeat = 0;
|
||||||
}
|
}
|
||||||
tmpGroup--;
|
tmpGroup--;
|
||||||
|
|
||||||
buf = (char *)cx->malloc(size + 1);
|
buf = (char *)cx->malloc(buflen + 1);
|
||||||
if (!buf)
|
if (!buf)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
|
@ -815,7 +827,7 @@ num_toLocaleString(JSContext *cx, uintN argc, Value *vp)
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
str = js_NewStringCopyN(cx, buf, size);
|
str = js_NewStringCopyN(cx, buf, buflen);
|
||||||
cx->free(buf);
|
cx->free(buf);
|
||||||
if (!str)
|
if (!str)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
@ -920,15 +932,15 @@ JS_DEFINE_TRCINFO_2(num_toString,
|
||||||
|
|
||||||
static JSFunctionSpec number_methods[] = {
|
static JSFunctionSpec number_methods[] = {
|
||||||
#if JS_HAS_TOSOURCE
|
#if JS_HAS_TOSOURCE
|
||||||
JS_FN(js_toSource_str, num_toSource, 0, JSFUN_PRIMITIVE_THIS),
|
JS_FN(js_toSource_str, num_toSource, 0, 0),
|
||||||
#endif
|
#endif
|
||||||
JS_TN(js_toString_str, num_toString, 1, JSFUN_PRIMITIVE_THIS, &num_toString_trcinfo),
|
JS_TN(js_toString_str, num_toString, 1, 0, &num_toString_trcinfo),
|
||||||
JS_FN(js_toLocaleString_str, num_toLocaleString, 0, JSFUN_PRIMITIVE_THIS),
|
JS_FN(js_toLocaleString_str, num_toLocaleString, 0, 0),
|
||||||
JS_FN(js_valueOf_str, js_num_valueOf, 0, JSFUN_PRIMITIVE_THIS),
|
JS_FN(js_valueOf_str, js_num_valueOf, 0, 0),
|
||||||
JS_FN(js_toJSON_str, js_num_valueOf, 0, JSFUN_PRIMITIVE_THIS),
|
JS_FN(js_toJSON_str, js_num_valueOf, 0, 0),
|
||||||
JS_FN("toFixed", num_toFixed, 1, JSFUN_PRIMITIVE_THIS),
|
JS_FN("toFixed", num_toFixed, 1, 0),
|
||||||
JS_FN("toExponential", num_toExponential, 1, JSFUN_PRIMITIVE_THIS),
|
JS_FN("toExponential", num_toExponential, 1, 0),
|
||||||
JS_FN("toPrecision", num_toPrecision, 1, JSFUN_PRIMITIVE_THIS),
|
JS_FN("toPrecision", num_toPrecision, 1, 0),
|
||||||
JS_FS_END
|
JS_FS_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1187,6 +1199,14 @@ js_NumberToString(JSContext *cx, jsdouble d)
|
||||||
return js_NumberToStringWithBase(cx, d, 10);
|
return js_NumberToStringWithBase(cx, d, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JSFlatString *
|
||||||
|
js::NumberToString(JSContext *cx, jsdouble d)
|
||||||
|
{
|
||||||
|
if (JSString *str = js_NumberToStringWithBase(cx, d, 10))
|
||||||
|
return str->assertIsFlat();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
JSBool JS_FASTCALL
|
JSBool JS_FASTCALL
|
||||||
js_NumberValueToCharBuffer(JSContext *cx, const Value &v, JSCharBuffer &cb)
|
js_NumberValueToCharBuffer(JSContext *cx, const Value &v, JSCharBuffer &cb)
|
||||||
{
|
{
|
||||||
|
@ -1235,13 +1255,8 @@ ValueToNumberSlow(JSContext *cx, Value v, double *out)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
skip_int_double:
|
skip_int_double:
|
||||||
if (v.isString()) {
|
if (v.isString())
|
||||||
jsdouble d = StringToNumberType<jsdouble>(cx, v.toString());
|
return StringToNumberType<jsdouble>(cx, v.toString(), out);
|
||||||
if (JSDOUBLE_IS_NaN(d))
|
|
||||||
break;
|
|
||||||
*out = d;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (v.isBoolean()) {
|
if (v.isBoolean()) {
|
||||||
if (v.toBoolean()) {
|
if (v.toBoolean()) {
|
||||||
*out = 1.0;
|
*out = 1.0;
|
||||||
|
|
|
@ -206,6 +206,10 @@ js_NumberValueToCharBuffer(JSContext *cx, const js::Value &v, JSCharBuffer &cb);
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
|
/* Same as js_NumberToString, different signature. */
|
||||||
|
extern JSFlatString *
|
||||||
|
NumberToString(JSContext *cx, jsdouble d);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Usually a small amount of static storage is enough, but sometimes we need
|
* Usually a small amount of static storage is enough, but sometimes we need
|
||||||
* to dynamically allocate much more. This struct encapsulates that.
|
* to dynamically allocate much more. This struct encapsulates that.
|
||||||
|
@ -643,35 +647,44 @@ template<> struct NumberTraits<jsdouble> {
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static JS_ALWAYS_INLINE T
|
static JS_ALWAYS_INLINE bool
|
||||||
StringToNumberType(JSContext *cx, JSString *str)
|
StringToNumberType(JSContext *cx, JSString *str, T *result)
|
||||||
{
|
{
|
||||||
if (str->length() == 1) {
|
size_t length = str->length();
|
||||||
jschar c = str->chars()[0];
|
const jschar *chars = str->getChars(NULL);
|
||||||
if ('0' <= c && c <= '9')
|
if (!chars)
|
||||||
return NumberTraits<T>::toSelfType(T(c - '0'));
|
return false;
|
||||||
if (JS_ISSPACE(c))
|
|
||||||
return NumberTraits<T>::toSelfType(T(0));
|
if (length == 1) {
|
||||||
return NumberTraits<T>::NaN();
|
jschar c = chars[0];
|
||||||
|
if ('0' <= c && c <= '9') {
|
||||||
|
*result = NumberTraits<T>::toSelfType(T(c - '0'));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (JS_ISSPACE(c)) {
|
||||||
|
*result = NumberTraits<T>::toSelfType(T(0));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
*result = NumberTraits<T>::NaN();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const jschar* bp;
|
const jschar *bp = chars;
|
||||||
const jschar* end;
|
const jschar *end = chars + length;
|
||||||
const jschar* ep;
|
|
||||||
jsdouble d;
|
|
||||||
|
|
||||||
str->getCharsAndEnd(bp, end);
|
|
||||||
bp = js_SkipWhiteSpace(bp, end);
|
bp = js_SkipWhiteSpace(bp, end);
|
||||||
|
|
||||||
/* ECMA doesn't allow signed hex numbers (bug 273467). */
|
/* ECMA doesn't allow signed hex numbers (bug 273467). */
|
||||||
if (end - bp >= 2 && bp[0] == '0' && (bp[1] == 'x' || bp[1] == 'X')) {
|
if (end - bp >= 2 && bp[0] == '0' && (bp[1] == 'x' || bp[1] == 'X')) {
|
||||||
/* Looks like a hex number. */
|
/* Looks like a hex number. */
|
||||||
const jschar *endptr;
|
const jschar *endptr;
|
||||||
|
double d;
|
||||||
if (!GetPrefixInteger(cx, bp + 2, end, 16, &endptr, &d) ||
|
if (!GetPrefixInteger(cx, bp + 2, end, 16, &endptr, &d) ||
|
||||||
js_SkipWhiteSpace(endptr, end) != end) {
|
js_SkipWhiteSpace(endptr, end) != end) {
|
||||||
return NumberTraits<T>::NaN();
|
*result = NumberTraits<T>::NaN();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return NumberTraits<T>::toSelfType(d);
|
*result = NumberTraits<T>::toSelfType(d);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -681,12 +694,14 @@ StringToNumberType(JSContext *cx, JSString *str)
|
||||||
* that have made it here (which can only be negative ones) will
|
* that have made it here (which can only be negative ones) will
|
||||||
* be treated as 0 without consuming the 'x' by js_strtod.
|
* be treated as 0 without consuming the 'x' by js_strtod.
|
||||||
*/
|
*/
|
||||||
if (!js_strtod(cx, bp, end, &ep, &d) ||
|
const jschar *ep;
|
||||||
js_SkipWhiteSpace(ep, end) != end) {
|
double d;
|
||||||
return NumberTraits<T>::NaN();
|
if (!js_strtod(cx, bp, end, &ep, &d) || js_SkipWhiteSpace(ep, end) != end) {
|
||||||
|
*result = NumberTraits<T>::NaN();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
*result = NumberTraits<T>::toSelfType(d);
|
||||||
return NumberTraits<T>::toSelfType(d);
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
201
js/src/jsobj.cpp
201
js/src/jsobj.cpp
|
@ -484,7 +484,8 @@ obj_toSource(JSContext *cx, uintN argc, Value *vp)
|
||||||
JSProperty *prop;
|
JSProperty *prop;
|
||||||
Value *val;
|
Value *val;
|
||||||
JSString *gsop[2];
|
JSString *gsop[2];
|
||||||
JSString *idstr, *valstr, *str;
|
JSString *valstr, *str;
|
||||||
|
JSLinearString *idstr;
|
||||||
|
|
||||||
JS_CHECK_RECURSION(cx, return JS_FALSE);
|
JS_CHECK_RECURSION(cx, return JS_FALSE);
|
||||||
|
|
||||||
|
@ -570,8 +571,8 @@ obj_toSource(JSContext *cx, uintN argc, Value *vp)
|
||||||
* Convert id to a value and then to a string. Decide early whether we
|
* Convert id to a value and then to a string. Decide early whether we
|
||||||
* prefer get/set or old getter/setter syntax.
|
* prefer get/set or old getter/setter syntax.
|
||||||
*/
|
*/
|
||||||
idstr = js_ValueToString(cx, IdToValue(id));
|
JSString *s = js_ValueToString(cx, IdToValue(id));
|
||||||
if (!idstr) {
|
if (!s || !(idstr = s->ensureLinear(cx))) {
|
||||||
ok = JS_FALSE;
|
ok = JS_FALSE;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -609,18 +610,23 @@ obj_toSource(JSContext *cx, uintN argc, Value *vp)
|
||||||
* If id is a string that's not an identifier, or if it's a negative
|
* If id is a string that's not an identifier, or if it's a negative
|
||||||
* integer, then it must be quoted.
|
* integer, then it must be quoted.
|
||||||
*/
|
*/
|
||||||
bool idIsLexicalIdentifier = !!js_IsIdentifier(idstr);
|
bool idIsLexicalIdentifier = js_IsIdentifier(idstr);
|
||||||
if (JSID_IS_ATOM(id)
|
if (JSID_IS_ATOM(id)
|
||||||
? !idIsLexicalIdentifier
|
? !idIsLexicalIdentifier
|
||||||
: (!JSID_IS_INT(id) || JSID_TO_INT(id) < 0)) {
|
: (!JSID_IS_INT(id) || JSID_TO_INT(id) < 0)) {
|
||||||
idstr = js_QuoteString(cx, idstr, jschar('\''));
|
s = js_QuoteString(cx, idstr, jschar('\''));
|
||||||
if (!idstr) {
|
if (!s || !(idstr = s->ensureLinear(cx))) {
|
||||||
ok = JS_FALSE;
|
ok = JS_FALSE;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
vp->setString(idstr); /* local root */
|
vp->setString(idstr); /* local root */
|
||||||
}
|
}
|
||||||
idstr->getCharsAndLength(idstrchars, idstrlength);
|
idstrlength = idstr->length();
|
||||||
|
idstrchars = idstr->getChars(cx);
|
||||||
|
if (!idstrchars) {
|
||||||
|
ok = JS_FALSE;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
for (jsint j = 0; j < valcnt; j++) {
|
for (jsint j = 0; j < valcnt; j++) {
|
||||||
/*
|
/*
|
||||||
|
@ -637,7 +643,12 @@ obj_toSource(JSContext *cx, uintN argc, Value *vp)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
localroot[j].setString(valstr); /* local root */
|
localroot[j].setString(valstr); /* local root */
|
||||||
valstr->getCharsAndLength(vchars, vlength);
|
vchars = valstr->getChars(cx);
|
||||||
|
if (!vchars) {
|
||||||
|
ok = JS_FALSE;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
vlength = valstr->length();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If val[j] is a non-sharp object, and we're not serializing an
|
* If val[j] is a non-sharp object, and we're not serializing an
|
||||||
|
@ -727,10 +738,8 @@ obj_toSource(JSContext *cx, uintN argc, Value *vp)
|
||||||
/* Allocate 1 + 1 at end for closing brace and terminating 0. */
|
/* Allocate 1 + 1 at end for closing brace and terminating 0. */
|
||||||
chars = (jschar *) js_realloc((ochars = chars), curlen * sizeof(jschar));
|
chars = (jschar *) js_realloc((ochars = chars), curlen * sizeof(jschar));
|
||||||
if (!chars) {
|
if (!chars) {
|
||||||
/* Save code space on error: let JS_free ignore null vsharp. */
|
chars = ochars;
|
||||||
cx->free(vsharp);
|
goto overflow;
|
||||||
js_free(ochars);
|
|
||||||
goto error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (comma) {
|
if (comma) {
|
||||||
|
@ -741,8 +750,10 @@ obj_toSource(JSContext *cx, uintN argc, Value *vp)
|
||||||
|
|
||||||
if (gsop[j]) {
|
if (gsop[j]) {
|
||||||
gsoplength = gsop[j]->length();
|
gsoplength = gsop[j]->length();
|
||||||
js_strncpy(&chars[nchars], gsop[j]->chars(),
|
const jschar *gsopchars = gsop[j]->getChars(cx);
|
||||||
gsoplength);
|
if (!gsopchars)
|
||||||
|
goto overflow;
|
||||||
|
js_strncpy(&chars[nchars], gsopchars, gsoplength);
|
||||||
nchars += gsoplength;
|
nchars += gsoplength;
|
||||||
chars[nchars++] = ' ';
|
chars[nchars++] = ' ';
|
||||||
}
|
}
|
||||||
|
@ -987,15 +998,14 @@ js_ComputeFilename(JSContext *cx, JSStackFrame *caller,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline JSScript **
|
static inline JSScript **
|
||||||
EvalCacheHash(JSContext *cx, JSString *str)
|
EvalCacheHash(JSContext *cx, JSLinearString *str)
|
||||||
{
|
{
|
||||||
const jschar *s;
|
const jschar *s = str->chars();
|
||||||
size_t n;
|
size_t n = str->length();
|
||||||
uint32 h;
|
|
||||||
|
|
||||||
str->getCharsAndLength(s, n);
|
|
||||||
if (n > 100)
|
if (n > 100)
|
||||||
n = 100;
|
n = 100;
|
||||||
|
uint32 h;
|
||||||
for (h = 0; n; s++, n--)
|
for (h = 0; n; s++, n--)
|
||||||
h = JS_ROTATE_LEFT32(h, 4) ^ *s;
|
h = JS_ROTATE_LEFT32(h, 4) ^ *s;
|
||||||
|
|
||||||
|
@ -1005,7 +1015,7 @@ EvalCacheHash(JSContext *cx, JSString *str)
|
||||||
}
|
}
|
||||||
|
|
||||||
static JS_ALWAYS_INLINE JSScript *
|
static JS_ALWAYS_INLINE JSScript *
|
||||||
EvalCacheLookup(JSContext *cx, JSString *str, JSStackFrame *caller, uintN staticLevel,
|
EvalCacheLookup(JSContext *cx, JSLinearString *str, JSStackFrame *caller, uintN staticLevel,
|
||||||
JSPrincipals *principals, JSObject *scopeobj, JSScript **bucket)
|
JSPrincipals *principals, JSObject *scopeobj, JSScript **bucket)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -1014,8 +1024,15 @@ EvalCacheLookup(JSContext *cx, JSString *str, JSStackFrame *caller, uintN static
|
||||||
* An eval cache entry should never be considered a hit unless its
|
* An eval cache entry should never be considered a hit unless its
|
||||||
* strictness matches that of the new eval code. The existing code takes
|
* strictness matches that of the new eval code. The existing code takes
|
||||||
* care of this, because hits are qualified by the function from which
|
* care of this, because hits are qualified by the function from which
|
||||||
* eval was called, whose strictness doesn't change. Scripts produced by
|
* eval was called, whose strictness doesn't change. (We don't cache evals
|
||||||
* calls to eval from global code are not cached.
|
* in eval code, so the calling function corresponds to the calling script,
|
||||||
|
* and its strictness never varies.) Scripts produced by calls to eval from
|
||||||
|
* global code aren't cached.
|
||||||
|
*
|
||||||
|
* FIXME bug 620141: Qualify hits by calling script rather than function.
|
||||||
|
* Then we wouldn't need the unintuitive !isEvalFrame() hack in EvalKernel
|
||||||
|
* to avoid caching nested evals in functions (thus potentially mismatching
|
||||||
|
* on strict mode), and we could cache evals in global code if desired.
|
||||||
*/
|
*/
|
||||||
uintN count = 0;
|
uintN count = 0;
|
||||||
JSScript **scriptp = bucket;
|
JSScript **scriptp = bucket;
|
||||||
|
@ -1041,9 +1058,9 @@ EvalCacheLookup(JSContext *cx, JSString *str, JSStackFrame *caller, uintN static
|
||||||
* Get the source string passed for safekeeping in the
|
* Get the source string passed for safekeeping in the
|
||||||
* atom map by the prior eval to Compiler::compileScript.
|
* atom map by the prior eval to Compiler::compileScript.
|
||||||
*/
|
*/
|
||||||
JSString *src = ATOM_TO_STRING(script->atomMap.vector[0]);
|
JSAtom *src = script->atomMap.vector[0];
|
||||||
|
|
||||||
if (src == str || js_EqualStrings(src, str)) {
|
if (src == str || EqualStrings(src, str)) {
|
||||||
/*
|
/*
|
||||||
* Source matches, qualify by comparing scopeobj to the
|
* Source matches, qualify by comparing scopeobj to the
|
||||||
* COMPILE_N_GO-memoized parent of the first literal
|
* COMPILE_N_GO-memoized parent of the first literal
|
||||||
|
@ -1184,9 +1201,11 @@ EvalKernel(JSContext *cx, uintN argc, Value *vp, EvalType evalType, JSStackFrame
|
||||||
if (!CheckScopeChainValidity(cx, scopeobj))
|
if (!CheckScopeChainValidity(cx, scopeobj))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const jschar *chars;
|
JSLinearString *linearStr = str->ensureLinear(cx);
|
||||||
size_t length;
|
if (!linearStr)
|
||||||
str->getCharsAndLength(chars, length);
|
return false;
|
||||||
|
const jschar *chars = linearStr->chars();
|
||||||
|
size_t length = linearStr->length();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the eval string starts with '(' and ends with ')', it may be JSON.
|
* If the eval string starts with '(' and ends with ')', it may be JSON.
|
||||||
|
@ -1214,9 +1233,9 @@ EvalKernel(JSContext *cx, uintN argc, Value *vp, EvalType evalType, JSStackFrame
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
JSScript *script = NULL;
|
JSScript *script = NULL;
|
||||||
JSScript **bucket = EvalCacheHash(cx, str);
|
JSScript **bucket = EvalCacheHash(cx, linearStr);
|
||||||
if (evalType == DIRECT_EVAL && caller->isFunctionFrame())
|
if (evalType == DIRECT_EVAL && caller->isFunctionFrame() && !caller->isEvalFrame())
|
||||||
script = EvalCacheLookup(cx, str, caller, staticLevel, principals, scopeobj, bucket);
|
script = EvalCacheLookup(cx, linearStr, caller, staticLevel, principals, scopeobj, bucket);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can't have a callerFrame (down in js::Execute's terms) if we're in
|
* We can't have a callerFrame (down in js::Execute's terms) if we're in
|
||||||
|
@ -1229,9 +1248,8 @@ EvalKernel(JSContext *cx, uintN argc, Value *vp, EvalType evalType, JSStackFrame
|
||||||
|
|
||||||
uint32 tcflags = TCF_COMPILE_N_GO | TCF_NEED_MUTABLE_SCRIPT | TCF_COMPILE_FOR_EVAL;
|
uint32 tcflags = TCF_COMPILE_N_GO | TCF_NEED_MUTABLE_SCRIPT | TCF_COMPILE_FOR_EVAL;
|
||||||
script = Compiler::compileScript(cx, scopeobj, callerFrame,
|
script = Compiler::compileScript(cx, scopeobj, callerFrame,
|
||||||
principals, tcflags,
|
principals, tcflags, chars, length,
|
||||||
chars, length,
|
filename, lineno, linearStr, staticLevel);
|
||||||
filename, lineno, str, staticLevel);
|
|
||||||
if (!script)
|
if (!script)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1992,6 +2010,23 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc,
|
||||||
|
|
||||||
JS_ASSERT(!obj->getOps()->defineProperty);
|
JS_ASSERT(!obj->getOps()->defineProperty);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we find a shared permanent property in a different object obj2 from
|
||||||
|
* obj, then if the property is shared permanent (an old hack to optimize
|
||||||
|
* per-object properties into one prototype property), ignore that lookup
|
||||||
|
* result (null current).
|
||||||
|
*
|
||||||
|
* FIXME: bug 575997 (see also bug 607863).
|
||||||
|
*/
|
||||||
|
if (current && obj2 != obj && obj2->isNative()) {
|
||||||
|
/* See same assertion with comment further below. */
|
||||||
|
JS_ASSERT(obj2->getClass() == obj->getClass());
|
||||||
|
|
||||||
|
Shape *shape = (Shape *) current;
|
||||||
|
if (shape->isSharedPermanent())
|
||||||
|
current = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* 8.12.9 steps 2-4. */
|
/* 8.12.9 steps 2-4. */
|
||||||
if (!current) {
|
if (!current) {
|
||||||
if (!obj->isExtensible())
|
if (!obj->isExtensible())
|
||||||
|
@ -2040,13 +2075,19 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc,
|
||||||
if (!shape->isAccessorDescriptor())
|
if (!shape->isAccessorDescriptor())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (desc.hasGet &&
|
if (desc.hasGet) {
|
||||||
!SameValue(desc.getterValue(), shape->getterOrUndefined(), cx)) {
|
JSBool same;
|
||||||
|
if (!SameValue(cx, desc.getterValue(), shape->getterOrUndefined(), &same))
|
||||||
|
return JS_FALSE;
|
||||||
|
if (!same)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (desc.hasSet &&
|
if (desc.hasSet) {
|
||||||
!SameValue(desc.setterValue(), shape->setterOrUndefined(), cx)) {
|
JSBool same;
|
||||||
|
if (!SameValue(cx, desc.setterValue(), shape->setterOrUndefined(), &same))
|
||||||
|
return JS_FALSE;
|
||||||
|
if (!same)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -2096,8 +2137,13 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc,
|
||||||
if (!shape->isDataDescriptor())
|
if (!shape->isDataDescriptor())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (desc.hasValue && !SameValue(desc.value, v, cx))
|
JSBool same;
|
||||||
|
if (desc.hasValue) {
|
||||||
|
if (!SameValue(cx, desc.value, v, &same))
|
||||||
|
return JS_FALSE;
|
||||||
|
if (!same)
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
if (desc.hasWritable && desc.writable() != shape->writable())
|
if (desc.hasWritable && desc.writable() != shape->writable())
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
@ -2144,8 +2190,13 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc,
|
||||||
/* 8.12.9 step 10. */
|
/* 8.12.9 step 10. */
|
||||||
JS_ASSERT(shape->isDataDescriptor());
|
JS_ASSERT(shape->isDataDescriptor());
|
||||||
if (!shape->configurable() && !shape->writable()) {
|
if (!shape->configurable() && !shape->writable()) {
|
||||||
if ((desc.hasWritable && desc.writable()) ||
|
if (desc.hasWritable && desc.writable())
|
||||||
(desc.hasValue && !SameValue(desc.value, v, cx))) {
|
return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval);
|
||||||
|
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);
|
return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2155,10 +2206,19 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc,
|
||||||
/* 8.12.9 step 11. */
|
/* 8.12.9 step 11. */
|
||||||
JS_ASSERT(desc.isAccessorDescriptor() && shape->isAccessorDescriptor());
|
JS_ASSERT(desc.isAccessorDescriptor() && shape->isAccessorDescriptor());
|
||||||
if (!shape->configurable()) {
|
if (!shape->configurable()) {
|
||||||
if ((desc.hasSet &&
|
if (desc.hasSet) {
|
||||||
!SameValue(desc.setterValue(), shape->setterOrUndefined(), cx)) ||
|
JSBool same;
|
||||||
(desc.hasGet &&
|
if (!SameValue(cx, desc.setterValue(), shape->setterOrUndefined(), &same))
|
||||||
!SameValue(desc.getterValue(), shape->getterOrUndefined(), cx))) {
|
return JS_FALSE;
|
||||||
|
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);
|
return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2697,7 +2757,7 @@ static JSFunctionSpec object_methods[] = {
|
||||||
#if JS_HAS_TOSOURCE
|
#if JS_HAS_TOSOURCE
|
||||||
JS_FN(js_toSource_str, obj_toSource, 0,0),
|
JS_FN(js_toSource_str, obj_toSource, 0,0),
|
||||||
#endif
|
#endif
|
||||||
JS_FN(js_toString_str, obj_toString, 0,JSFUN_PRIMITIVE_THIS),
|
JS_FN(js_toString_str, obj_toString, 0,0),
|
||||||
JS_FN(js_toLocaleString_str, obj_toLocaleString, 0,0),
|
JS_FN(js_toLocaleString_str, obj_toLocaleString, 0,0),
|
||||||
JS_FN(js_valueOf_str, obj_valueOf, 0,0),
|
JS_FN(js_valueOf_str, obj_valueOf, 0,0),
|
||||||
#if JS_HAS_OBJ_WATCHPOINT
|
#if JS_HAS_OBJ_WATCHPOINT
|
||||||
|
@ -4487,7 +4547,7 @@ CallAddPropertyHook(JSContext *cx, Class *clasp, JSObject *obj, const Shape *sha
|
||||||
if (clasp->addProperty != PropertyStub) {
|
if (clasp->addProperty != PropertyStub) {
|
||||||
Value nominal = *vp;
|
Value nominal = *vp;
|
||||||
|
|
||||||
if (!CallJSPropertyOp(cx, clasp->addProperty, obj, SHAPE_USERID(shape), vp))
|
if (!CallJSPropertyOp(cx, clasp->addProperty, obj, shape->id, vp))
|
||||||
return false;
|
return false;
|
||||||
if (*vp != nominal) {
|
if (*vp != nominal) {
|
||||||
if (obj->containsSlot(shape->slot))
|
if (obj->containsSlot(shape->slot))
|
||||||
|
@ -4616,8 +4676,10 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const Value &valu
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Store value before calling addProperty, in case the latter GC's. */
|
/* Store value before calling addProperty, in case the latter GC's. */
|
||||||
if (obj->containsSlot(shape->slot))
|
if (obj->containsSlot(shape->slot)) {
|
||||||
|
AbortRecordingIfUnexpectedGlobalWrite(cx, obj, shape->slot);
|
||||||
obj->nativeSetSlot(shape->slot, value);
|
obj->nativeSetSlot(shape->slot, value);
|
||||||
|
}
|
||||||
|
|
||||||
/* XXXbe called with lock held */
|
/* XXXbe called with lock held */
|
||||||
valueCopy = value;
|
valueCopy = value;
|
||||||
|
@ -5091,6 +5153,7 @@ js_NativeSet(JSContext *cx, JSObject *obj, const Shape *shape, bool added, Value
|
||||||
if (shape->hasDefaultSetter()) {
|
if (shape->hasDefaultSetter()) {
|
||||||
if (!added && !obj->methodWriteBarrier(cx, *shape, *vp))
|
if (!added && !obj->methodWriteBarrier(cx, *shape, *vp))
|
||||||
return false;
|
return false;
|
||||||
|
AbortRecordingIfUnexpectedGlobalWrite(cx, obj, slot);
|
||||||
obj->nativeSetSlot(slot, *vp);
|
obj->nativeSetSlot(slot, *vp);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -5117,6 +5180,7 @@ js_NativeSet(JSContext *cx, JSObject *obj, const Shape *shape, bool added, Value
|
||||||
obj->nativeContains(*shape))) {
|
obj->nativeContains(*shape))) {
|
||||||
if (!added && !obj->methodWriteBarrier(cx, *shape, *vp))
|
if (!added && !obj->methodWriteBarrier(cx, *shape, *vp))
|
||||||
return false;
|
return false;
|
||||||
|
AbortRecordingIfUnexpectedGlobalWrite(cx, obj, slot);
|
||||||
obj->setSlot(slot, *vp);
|
obj->setSlot(slot, *vp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5455,10 +5519,8 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
||||||
if (pobj != obj) {
|
if (pobj != obj) {
|
||||||
/*
|
/*
|
||||||
* We found id in a prototype object: prepare to share or shadow.
|
* We found id in a prototype object: prepare to share or shadow.
|
||||||
*
|
|
||||||
* Don't clone a prototype property that doesn't have a slot.
|
|
||||||
*/
|
*/
|
||||||
if (!shape->hasSlot()) {
|
if (!shape->shadowable()) {
|
||||||
if (defineHow & JSDNP_CACHE_RESULT) {
|
if (defineHow & JSDNP_CACHE_RESULT) {
|
||||||
#ifdef JS_TRACER
|
#ifdef JS_TRACER
|
||||||
JS_ASSERT_NOT_ON_TRACE(cx);
|
JS_ASSERT_NOT_ON_TRACE(cx);
|
||||||
|
@ -5474,21 +5536,33 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
||||||
return shape->set(cx, obj, vp);
|
return shape->set(cx, obj, vp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Restore attrs to the ECMA default for new properties. */
|
|
||||||
attrs = JSPROP_ENUMERATE;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Preserve the shortid, getter, and setter when shadowing any
|
* Preserve attrs except JSPROP_SHARED, getter, and setter when
|
||||||
* property that has a shortid. An old API convention requires
|
* shadowing any property that has no slot (is shared). We must
|
||||||
* that the property's getter and setter functions receive the
|
* clear the shared attribute for the shadowing shape so that the
|
||||||
* shortid, not id, when they are called on the shadow we are
|
* property in obj that it defines has a slot to retain the value
|
||||||
|
* being set, in case the setter simply cannot operate on instances
|
||||||
|
* of obj's class by storing the value in some class-specific
|
||||||
|
* location.
|
||||||
|
*
|
||||||
|
* A subset of slotless shared properties is the set of properties
|
||||||
|
* with shortids, which must be preserved too. An old API requires
|
||||||
|
* that the property's getter and setter receive the shortid, not
|
||||||
|
* id, when they are called on the shadowing property that we are
|
||||||
* about to create in obj.
|
* about to create in obj.
|
||||||
*/
|
*/
|
||||||
|
if (!shape->hasSlot()) {
|
||||||
|
defineHow &= ~JSDNP_SET_METHOD;
|
||||||
if (shape->hasShortID()) {
|
if (shape->hasShortID()) {
|
||||||
flags = Shape::HAS_SHORTID;
|
flags = Shape::HAS_SHORTID;
|
||||||
shortid = shape->shortid;
|
shortid = shape->shortid;
|
||||||
|
}
|
||||||
|
attrs &= ~JSPROP_SHARED;
|
||||||
getter = shape->getter();
|
getter = shape->getter();
|
||||||
setter = shape->setter();
|
setter = shape->setter();
|
||||||
|
} else {
|
||||||
|
/* Restore attrs to the ECMA default for new properties. */
|
||||||
|
attrs = JSPROP_ENUMERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -6308,7 +6382,7 @@ js_PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize)
|
||||||
if (JSID_IS_INT(id)) {
|
if (JSID_IS_INT(id)) {
|
||||||
JS_snprintf(buf, bufsize, "%ld", (long)JSID_TO_INT(id));
|
JS_snprintf(buf, bufsize, "%ld", (long)JSID_TO_INT(id));
|
||||||
} else if (JSID_IS_ATOM(id)) {
|
} else if (JSID_IS_ATOM(id)) {
|
||||||
PutEscapedString(buf, bufsize, JSID_TO_STRING(id), 0);
|
PutEscapedString(buf, bufsize, JSID_TO_ATOM(id), 0);
|
||||||
} else {
|
} else {
|
||||||
JS_snprintf(buf, bufsize, "**FINALIZED ATOM KEY**");
|
JS_snprintf(buf, bufsize, "**FINALIZED ATOM KEY**");
|
||||||
}
|
}
|
||||||
|
@ -6501,15 +6575,22 @@ js_DumpChars(const jschar *s, size_t n)
|
||||||
void
|
void
|
||||||
dumpString(JSString *str)
|
dumpString(JSString *str)
|
||||||
{
|
{
|
||||||
dumpChars(str->chars(), str->length());
|
if (const jschar *chars = str->getChars(NULL))
|
||||||
|
dumpChars(chars, str->length());
|
||||||
|
else
|
||||||
|
fprintf(stderr, "(oom in dumpString)");
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_FRIEND_API(void)
|
JS_FRIEND_API(void)
|
||||||
js_DumpString(JSString *str)
|
js_DumpString(JSString *str)
|
||||||
{
|
{
|
||||||
|
if (const jschar *chars = str->getChars(NULL)) {
|
||||||
fprintf(stderr, "JSString* (%p) = jschar * (%p) = ",
|
fprintf(stderr, "JSString* (%p) = jschar * (%p) = ",
|
||||||
(void *) str, (void *) str->chars());
|
(void *) str, (void *) chars);
|
||||||
dumpString(str);
|
dumpString(str);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "(oom in JS_DumpString)");
|
||||||
|
}
|
||||||
fputc('\n', stderr);
|
fputc('\n', stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -992,17 +992,21 @@ struct JSObject : js::gc::Cell {
|
||||||
static const uint32 NAMESPACE_CLASS_RESERVED_SLOTS = 3;
|
static const uint32 NAMESPACE_CLASS_RESERVED_SLOTS = 3;
|
||||||
static const uint32 QNAME_CLASS_RESERVED_SLOTS = 3;
|
static const uint32 QNAME_CLASS_RESERVED_SLOTS = 3;
|
||||||
|
|
||||||
inline jsval getNamePrefix() const;
|
inline JSLinearString *getNamePrefix() const;
|
||||||
inline void setNamePrefix(jsval prefix);
|
inline jsval getNamePrefixVal() const;
|
||||||
|
inline void setNamePrefix(JSLinearString *prefix);
|
||||||
|
inline void clearNamePrefix();
|
||||||
|
|
||||||
inline jsval getNameURI() const;
|
inline JSLinearString *getNameURI() const;
|
||||||
inline void setNameURI(jsval uri);
|
inline jsval getNameURIVal() const;
|
||||||
|
inline void setNameURI(JSLinearString *uri);
|
||||||
|
|
||||||
inline jsval getNamespaceDeclared() const;
|
inline jsval getNamespaceDeclared() const;
|
||||||
inline void setNamespaceDeclared(jsval decl);
|
inline void setNamespaceDeclared(jsval decl);
|
||||||
|
|
||||||
inline jsval getQNameLocalName() const;
|
inline JSLinearString *getQNameLocalName() const;
|
||||||
inline void setQNameLocalName(jsval decl);
|
inline jsval getQNameLocalNameVal() const;
|
||||||
|
inline void setQNameLocalName(JSLinearString *name);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Proxy-specific getters and setters.
|
* Proxy-specific getters and setters.
|
||||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче