Merge tracemonkey to mozilla-centra. a=blockers.

This commit is contained in:
Robert Sayre 2010-11-17 13:55:14 -08:00
commit 4945f654ff
257 changed files with 10983 additions and 5395 deletions

View File

@ -68,7 +68,7 @@ nsSecurityNameSet::~nsSecurityNameSet()
NS_IMPL_ISUPPORTS1(nsSecurityNameSet, nsIScriptExternalNameSet)
static char *
static JSString *
getStringArgument(JSContext *cx, JSObject *obj, PRUint16 argNum, uintN argc, jsval *argv)
{
if (argc <= argNum || !JSVAL_IS_STRING(argv[argNum])) {
@ -80,11 +80,15 @@ getStringArgument(JSContext *cx, JSObject *obj, PRUint16 argNum, uintN argc, jsv
* We don't want to use JS_ValueToString because we want to be able
* to have an object to represent a target in subsequent versions.
*/
JSString *str = JSVAL_TO_STRING(argv[argNum]);
if (!str)
return nsnull;
return JSVAL_TO_STRING(argv[argNum]);
}
return JS_GetStringBytes(str);
static bool
getBytesArgument(JSContext *cx, JSObject *obj, PRUint16 argNum, uintN argc, jsval *argv,
JSAutoByteString *bytes)
{
JSString *str = getStringArgument(cx, obj, argNum, argc, argv);
return str && bytes->encode(cx, str);
}
static void
@ -119,15 +123,18 @@ netscape_security_isPrivilegeEnabled(JSContext *cx, uintN argc, jsval *vp)
return JS_FALSE;
JSBool result = JS_FALSE;
char *cap = getStringArgument(cx, obj, 0, argc, JS_ARGV(cx, vp));
if (cap) {
if (JSString *str = getStringArgument(cx, obj, 0, argc, JS_ARGV(cx, vp))) {
JSAutoByteString cap(cx, str);
if (!cap)
return JS_FALSE;
nsresult rv;
nsCOMPtr<nsIScriptSecurityManager> securityManager =
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv)) {
// NS_ASSERTION(cx == GetCurrentContext(), "unexpected context");
rv = securityManager->IsCapabilityEnabled(cap, &result);
rv = securityManager->IsCapabilityEnabled(cap.ptr(), &result);
if (NS_FAILED(rv))
result = JS_FALSE;
}
@ -144,8 +151,8 @@ netscape_security_enablePrivilege(JSContext *cx, uintN argc, jsval *vp)
if (!obj)
return JS_FALSE;
char *cap = getStringArgument(cx, obj, 0, argc, JS_ARGV(cx, vp));
if (!cap)
JSAutoByteString cap;
if (!getBytesArgument(cx, obj, 0, argc, JS_ARGV(cx, vp), &cap))
return JS_FALSE;
nsresult rv;
@ -156,7 +163,7 @@ netscape_security_enablePrivilege(JSContext *cx, uintN argc, jsval *vp)
// NS_ASSERTION(cx == GetCurrentContext(), "unexpected context");
rv = securityManager->EnableCapability(cap);
rv = securityManager->EnableCapability(cap.ptr());
if (NS_FAILED(rv))
return JS_FALSE;
JS_SET_RVAL(cx, vp, JSVAL_VOID);
@ -170,8 +177,8 @@ netscape_security_disablePrivilege(JSContext *cx, uintN argc, jsval *vp)
if (!obj)
return JS_FALSE;
char *cap = getStringArgument(cx, obj, 0, argc, JS_ARGV(cx, vp));
if (!cap)
JSAutoByteString cap;
if (!getBytesArgument(cx, obj, 0, argc, JS_ARGV(cx, vp), &cap))
return JS_FALSE;
nsresult rv;
@ -182,7 +189,7 @@ netscape_security_disablePrivilege(JSContext *cx, uintN argc, jsval *vp)
// NS_ASSERTION(cx == GetCurrentContext(), "unexpected context");
rv = securityManager->DisableCapability(cap);
rv = securityManager->DisableCapability(cap.ptr());
if (NS_FAILED(rv))
return JS_FALSE;
JS_SET_RVAL(cx, vp, JSVAL_VOID);
@ -196,8 +203,8 @@ netscape_security_revertPrivilege(JSContext *cx, uintN argc, jsval *vp)
if (!obj)
return JS_FALSE;
char *cap = getStringArgument(cx, obj, 0, argc, JS_ARGV(cx, vp));
if (!cap)
JSAutoByteString cap;
if (!getBytesArgument(cx, obj, 0, argc, JS_ARGV(cx, vp), &cap))
return JS_FALSE;
nsresult rv;
@ -208,7 +215,7 @@ netscape_security_revertPrivilege(JSContext *cx, uintN argc, jsval *vp)
// NS_ASSERTION(cx == GetCurrentContext(), "unexpected context");
rv = securityManager->RevertCapability(cap);
rv = securityManager->RevertCapability(cap.ptr());
if (NS_FAILED(rv))
return JS_FALSE;
JS_SET_RVAL(cx, vp, JSVAL_VOID);
@ -225,7 +232,8 @@ netscape_security_setCanEnablePrivilege(JSContext *cx, uintN argc, jsval *vp)
if (argc < 2) return JS_FALSE;
nsCAutoString principalFingerprint;
getUTF8StringArgument(cx, obj, 0, argc, JS_ARGV(cx, vp), principalFingerprint);
char *cap = getStringArgument(cx, obj, 1, argc, JS_ARGV(cx, vp));
JSAutoByteString cap;
getBytesArgument(cx, obj, 1, argc, JS_ARGV(cx, vp), &cap);
if (principalFingerprint.IsEmpty() || !cap)
return JS_FALSE;
@ -237,7 +245,8 @@ netscape_security_setCanEnablePrivilege(JSContext *cx, uintN argc, jsval *vp)
// NS_ASSERTION(cx == GetCurrentContext(), "unexpected context");
rv = securityManager->SetCanEnableCapability(principalFingerprint, cap,
rv = securityManager->SetCanEnableCapability(principalFingerprint,
cap.ptr(),
nsIPrincipal::ENABLE_GRANTED);
if (NS_FAILED(rv))
return JS_FALSE;

View File

@ -404,8 +404,7 @@ DocumentInfoHashtableTraverser(nsIURI* key,
nsCycleCollectionTraversalCallback *cb =
static_cast<nsCycleCollectionTraversalCallback*>(userArg);
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mDocumentTable value");
nsCOMPtr<nsISupports> iface = do_QueryObject(di);
cb->NoteXPCOMChild(iface);
cb->NoteXPCOMChild(static_cast<nsIScriptGlobalObjectOwner*>(di));
return PL_DHASH_NEXT;
}

View File

@ -316,8 +316,8 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(nsXBLBinding)
// XXX What about mNextBinding and mInsertionPointTable?
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(nsXBLBinding)
nsCOMPtr<nsISupports> iface = do_QueryObject(tmp->mPrototypeBinding->XBLDocumentInfo());
cb.NoteXPCOMChild(iface);
cb.NoteXPCOMChild(static_cast<nsIScriptGlobalObjectOwner*>(
tmp->mPrototypeBinding->XBLDocumentInfo()));
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mNextBinding, nsXBLBinding)
if (tmp->mInsertionPointTable)

View File

@ -3953,8 +3953,7 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(ChromeWorker, nsIChromeWorker)
DOM_CLASSINFO_MAP_ENTRY(nsIChromeWorker)
DOM_CLASSINFO_MAP_BEGIN(ChromeWorker, nsIWorker)
DOM_CLASSINFO_MAP_ENTRY(nsIWorker)
DOM_CLASSINFO_MAP_ENTRY(nsIAbstractWorker)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSEventTarget)
@ -6890,8 +6889,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
win->InitJavaProperties();
PRBool hasProp;
PRBool ok = ::JS_HasProperty(cx, obj, ::JS_GetStringBytes(str),
&hasProp);
PRBool ok = ::JS_HasPropertyById(cx, obj, id, &hasProp);
isResolvingJavaProperties = PR_FALSE;
@ -8737,10 +8735,8 @@ nsHTMLDocumentSH::DocumentAllNewResolve(JSContext *cx, JSObject *obj, jsid id,
if (id == sItem_id || id == sNamedItem_id) {
// Define the item() or namedItem() method.
JSFunction *fnc =
::JS_DefineFunction(cx, obj, ::JS_GetStringBytes(JSID_TO_STRING(id)),
CallToGetPropMapper, 0, JSPROP_ENUMERATE);
JSFunction *fnc = ::JS_DefineFunctionById(cx, obj, id, CallToGetPropMapper,
0, JSPROP_ENUMERATE);
*objp = obj;
return fnc != nsnull;
@ -9037,11 +9033,8 @@ nsHTMLDocumentSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
}
if (id == sOpen_id) {
JSString *str = JSID_TO_STRING(id);
JSFunction *fnc =
::JS_DefineFunction(cx, obj, ::JS_GetStringBytes(str),
DocumentOpen, 0, JSPROP_ENUMERATE);
JSFunction *fnc =::JS_DefineFunctionById(cx, obj, id, DocumentOpen, 0,
JSPROP_ENUMERATE);
*objp = obj;
return fnc ? NS_OK : NS_ERROR_UNEXPECTED;

View File

@ -942,9 +942,9 @@ nsGlobalWindow::CleanupCachedXBLHandlers(nsGlobalWindow* aWindow)
aWindow->mCachedXBLPrototypeHandlers.Count() > 0) {
aWindow->mCachedXBLPrototypeHandlers.Clear();
nsCOMPtr<nsISupports> supports;
nsISupports* supports;
aWindow->QueryInterface(NS_GET_IID(nsCycleCollectionISupports),
getter_AddRefs(supports));
reinterpret_cast<void**>(&supports));
NS_ASSERTION(supports, "Failed to QI to nsCycleCollectionISupports?!");
nsContentUtils::DropJSObjects(supports);
@ -6386,9 +6386,9 @@ nsGlobalWindow::CacheXBLPrototypeHandler(nsXBLPrototypeHandler* aKey,
NS_ASSERTION(participant,
"Failed to QI to nsXPCOMCycleCollectionParticipant!");
nsCOMPtr<nsISupports> thisSupports;
nsISupports* thisSupports;
QueryInterface(NS_GET_IID(nsCycleCollectionISupports),
getter_AddRefs(thisSupports));
reinterpret_cast<void**>(&thisSupports));
NS_ASSERTION(thisSupports, "Failed to QI to nsCycleCollectionISupports!");
nsresult rv = nsContentUtils::HoldJSObjects(thisSupports, participant);

View File

@ -1119,7 +1119,7 @@ nsJSContext::DOMOperationCallback(JSContext *cx)
cx->debugHooks->
debuggerHandlerData)) {
case JSTRAP_RETURN:
fp->setReturnValue(js::Valueify(rval));
JS_SetFrameReturnValue(cx, fp, rval);
return JS_TRUE;
case JSTRAP_ERROR:
cx->throwing = JS_FALSE;
@ -2112,10 +2112,16 @@ nsJSContext::CallEventHandler(nsISupports* aTarget, void *aScope, void *aHandler
return NS_OK;
}
NS_TIME_FUNCTION_FMT(1.0, "%s (line %d) (function: %s)", MOZ_FUNCTION_NAME,
__LINE__, JS_GetFunctionName(static_cast<JSFunction *>(JS_GetPrivate(mContext, static_cast<JSObject *>(aHandler)))));
#ifdef NS_FUNCTION_TIMER
{
JSObject *obj = static_cast<JSObject *>(aHandler);
JSString *id = JS_GetFunctionId(static_cast<JSFunction *>(JS_GetPrivate(mContext, obj));
JSAutoByteString bytes;
const char *name = !id ? "anonymous" : bytes.encode(mContext, id) ? bytes.ptr() : "<error>";
NS_TIME_FUNCTION_FMT(1.0, "%s (line %d) (function: %s)", MOZ_FUNCTION_NAME, __LINE__, name);
}
#endif
JSAutoRequest ar(mContext);
JSObject* target = nsnull;
nsresult rv = JSObjectFromInterface(aTarget, aScope, &target);
@ -3136,7 +3142,6 @@ TraceMallocOpenLogFile(JSContext *cx, uintN argc, jsval *vp)
{
int fd;
JSString *str;
char *filename;
if (!CheckUniversalXPConnectForTraceMalloc(cx))
return JS_FALSE;
@ -3147,10 +3152,12 @@ TraceMallocOpenLogFile(JSContext *cx, uintN argc, jsval *vp)
str = JS_ValueToString(cx, JS_ARGV(cx, vp)[0]);
if (!str)
return JS_FALSE;
filename = JS_GetStringBytes(str);
fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644);
JSAutoByteString filename(cx, str);
if (!filename)
return JS_FALSE;
fd = open(filename.ptr(), O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd < 0) {
JS_ReportError(cx, "can't open %s: %s", filename, strerror(errno));
JS_ReportError(cx, "can't open %s: %s", filename.ptr(), strerror(errno));
return JS_FALSE;
}
}
@ -3201,17 +3208,16 @@ TraceMallocCloseLogFD(JSContext *cx, uintN argc, jsval *vp)
static JSBool
TraceMallocLogTimestamp(JSContext *cx, uintN argc, jsval *vp)
{
JSString *str;
const char *caption;
if (!CheckUniversalXPConnectForTraceMalloc(cx))
return JS_FALSE;
str = JS_ValueToString(cx, argc ? JS_ARGV(cx, vp)[0] : JSVAL_VOID);
JSString *str = JS_ValueToString(cx, argc ? JS_ARGV(cx, vp)[0] : JSVAL_VOID);
if (!str)
return JS_FALSE;
caption = JS_GetStringBytes(str);
NS_TraceMallocLogTimestamp(caption);
JSAutoByteString caption(cx, str);
if (!caption)
return JS_FALSE;
NS_TraceMallocLogTimestamp(caption.ptr());
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
}
@ -3219,18 +3225,17 @@ TraceMallocLogTimestamp(JSContext *cx, uintN argc, jsval *vp)
static JSBool
TraceMallocDumpAllocations(JSContext *cx, uintN argc, jsval *vp)
{
JSString *str;
const char *pathname;
if (!CheckUniversalXPConnectForTraceMalloc(cx))
return JS_FALSE;
str = JS_ValueToString(cx, argc ? JS_ARGV(cx, vp)[0] : JSVAL_VOID);
JSString *str = JS_ValueToString(cx, argc ? JS_ARGV(cx, vp)[0] : JSVAL_VOID);
if (!str)
return JS_FALSE;
pathname = JS_GetStringBytes(str);
if (NS_TraceMallocDumpAllocations(pathname) < 0) {
JS_ReportError(cx, "can't dump to %s: %s", pathname, strerror(errno));
JSAutoByteString pathname(cx, str);
if (!pathname)
return JS_FALSE;
if (NS_TraceMallocDumpAllocations(pathname.ptr()) < 0) {
JS_ReportError(cx, "can't dump to %s: %s", pathname.ptr(), strerror(errno));
return JS_FALSE;
}
JS_SET_RVAL(cx, vp, JSVAL_VOID);
@ -3999,7 +4004,7 @@ SetMemoryHighWaterMarkPrefChangedCallback(const char* aPrefName, void* aClosure)
* In the browser, we don't cap the amount of GC-owned memory.
*/
JS_SetGCParameter(nsJSRuntime::sRuntime, JSGC_MAX_MALLOC_BYTES,
64L * 1024L * 1024L);
128L * 1024L * 1024L);
JS_SetGCParameter(nsJSRuntime::sRuntime, JSGC_MAX_BYTES,
0xffffffff);
} else {

View File

@ -134,10 +134,15 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsJSScriptTimeoutHandler)
else if (tmp->mFunObj) {
JSFunction* fun = (JSFunction*)tmp->mFunObj->getPrivate();
if (fun->atom) {
JSString* name = ATOM_TO_STRING(fun->atom);
foo.AppendLiteral(" [");
foo.Append(JS_GetStringBytes(name));
foo.AppendLiteral("]");
size_t size = 1 + JS_PutEscapedString(NULL, 0, ATOM_TO_STRING(fun->atom), 0);
char *name = new char[size];
if (name) {
JS_PutEscapedString(name, size, ATOM_TO_STRING(fun->atom), 0);
foo.AppendLiteral(" [");
foo.Append(name);
delete[] name;
foo.AppendLiteral("]");
}
}
}
cb.DescribeNode(RefCounted, tmp->mRefCnt.get(),

View File

@ -144,7 +144,13 @@ interface nsIWorker : nsIAbstractWorker
void terminate();
};
[scriptable, uuid(c40dfe2c-c9d4-4c48-8e5d-adc99f207dd2)]
interface nsIChromeWorker : nsIWorker
[scriptable, uuid(cfc4bb32-ca83-4d58-9b6f-66f8054a333a)]
interface nsIWorkerFactory : nsISupports
{
nsIWorker newChromeWorker(/* in DOMString aScriptURL */);
};
%{ C++
#define NS_WORKERFACTORY_CONTRACTID \
"@mozilla.org/threads/workerfactory;1"
%}

View File

@ -1,4 +1,4 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -373,13 +373,19 @@ nsDOMWorkerFunctions::AtoB(JSContext* aCx,
return JS_FALSE;
}
// We want the bytes here, not the jschars.
const char* bytes = JS_GetStringBytesZ(aCx, str);
if (!bytes) {
return JS_FALSE;
}
size_t len = JS_GetStringEncodingLength(aCx, str);
if (len == size_t(-1))
return JS_FALSE;
nsDependentCString string(bytes, JS_GetStringLength(str));
JSUint32 alloc_len = (len + 1) * sizeof(char);
char *buffer = static_cast<char *>(nsMemory::Alloc(alloc_len));
if (!buffer)
return JS_FALSE;
JS_EncodeStringToBuffer(str, buffer, len);
buffer[len] = '\0';
nsDependentCString string(buffer, len);
nsCAutoString result;
if (NS_FAILED(nsXPConnect::Base64Decode(string, result))) {
@ -419,13 +425,19 @@ nsDOMWorkerFunctions::BtoA(JSContext* aCx,
return JS_FALSE;
}
// We want the bytes here, not the jschars.
const char* bytes = JS_GetStringBytesZ(aCx, str);
if (!bytes) {
return JS_FALSE;
}
size_t len = JS_GetStringEncodingLength(aCx, str);
if (len == size_t(-1))
return JS_FALSE;
nsDependentCString string(bytes, JS_GetStringLength(str));
JSUint32 alloc_len = (len + 1) * sizeof(char);
char *buffer = static_cast<char *>(nsMemory::Alloc(alloc_len));
if (!buffer)
return JS_FALSE;
JS_EncodeStringToBuffer(str, buffer, len);
buffer[len] = '\0';
nsDependentCString string(buffer, len);
nsCAutoString result;
if (NS_FAILED(nsXPConnect::Base64Encode(string, result))) {
@ -724,14 +736,14 @@ nsDOMWorkerScope::AddProperty(nsIXPConnectWrappedNative* aWrapper,
return NS_OK;
}
const char* name = JS_GetStringBytes(JSID_TO_STRING(aId));
JSString *str = JSID_TO_STRING(aId);
// Figure out which listener we're setting.
SetListenerFunc func;
if (!strcmp(name, "onmessage")) {
if (JS_MatchStringAndAscii(str, "onmessage")) {
func = &nsDOMWorkerScope::SetOnmessage;
}
else if (!strcmp(name, "onerror")) {
else if (JS_MatchStringAndAscii(str, "onerror")) {
func = &nsDOMWorkerScope::SetOnerror;
}
else {
@ -1166,7 +1178,7 @@ nsDOMWorker::NewWorker(nsISupports** aNewObject)
// static
nsresult
nsDOMWorker::NewChromeWorker(nsISupports** aNewObject)
nsDOMWorker::NewChromeDOMWorker(nsDOMWorker** aNewObject)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@ -1177,19 +1189,27 @@ nsDOMWorker::NewChromeWorker(nsISupports** aNewObject)
PRBool enabled;
nsresult rv = ssm->IsCapabilityEnabled("UniversalXPConnect", &enabled);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(enabled, NS_ERROR_DOM_SECURITY_ERR);
if(!enabled) {
return NS_ERROR_DOM_SECURITY_ERR;
}
nsCOMPtr<nsISupports> newWorker =
NS_ISUPPORTS_CAST(nsIWorker*, new nsDOMWorker(nsnull, nsnull, CHROME));
nsRefPtr<nsDOMWorker> newWorker = new nsDOMWorker(nsnull, nsnull, CHROME);
NS_ENSURE_TRUE(newWorker, NS_ERROR_OUT_OF_MEMORY);
newWorker.forget(aNewObject);
return NS_OK;
}
// static
nsresult
nsDOMWorker::NewChromeWorker(nsISupports** aNewObject)
{
nsDOMWorker* newWorker;
nsresult rv = NewChromeDOMWorker(&newWorker);
NS_ENSURE_SUCCESS(rv, rv);
*aNewObject = NS_ISUPPORTS_CAST(nsIWorker*, newWorker);
return NS_OK;
}
NS_IMPL_ADDREF_INHERITED(nsDOMWorker, nsDOMWorkerMessageHandler)
NS_IMPL_RELEASE_INHERITED(nsDOMWorker, nsDOMWorkerMessageHandler)
@ -1204,7 +1224,6 @@ NS_INTERFACE_MAP_BEGIN(nsDOMWorker)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEventTarget, nsDOMWorkerMessageHandler)
NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIChromeWorker, IsPrivileged())
NS_INTERFACE_MAP_END
// Use the xpc_map_end.h macros to generate the nsIXPCScriptable methods we want
@ -1233,8 +1252,11 @@ nsDOMWorker::PreCreate(nsISupports* aObject,
JSObject* /* aPlannedParent */,
JSObject** /* aParent */)
{
nsCOMPtr<nsIChromeWorker> privilegedWorker(do_QueryInterface(aObject));
return privilegedWorker ? NS_SUCCESS_CHROME_ACCESS_ONLY : NS_OK;
nsCOMPtr<nsIWorker> iworker(do_QueryInterface(aObject));
if (iworker && static_cast<nsDOMWorker *>(iworker.get())->IsPrivileged()) {
return NS_SUCCESS_CHROME_ACCESS_ONLY;
}
return NS_OK;
}
NS_IMETHODIMP
@ -1293,7 +1315,6 @@ nsDOMWorker::Finalize(nsIXPConnectWrappedNative* /* aWrapper */,
return NS_OK;
}
// Keep this list in sync with the list in nsDOMClassInfo.cpp!
NS_IMPL_CI_INTERFACE_GETTER4(nsDOMWorker, nsIWorker,
nsIAbstractWorker,
nsIDOMNSEventTarget,
@ -2300,3 +2321,52 @@ nsDOMWorker::Notify(nsITimer* aTimer)
Kill();
return NS_OK;
}
NS_IMETHODIMP
nsWorkerFactory::NewChromeWorker(nsIWorker** _retval)
{
nsresult rv;
// Get the arguments from XPConnect.
nsCOMPtr<nsIXPConnect> xpc;
xpc = do_GetService(nsIXPConnect::GetCID());
NS_ASSERTION(xpc, "Could not get XPConnect");
nsAXPCNativeCallContext* cc;
rv = xpc->GetCurrentNativeCallContext(&cc);
NS_ENSURE_SUCCESS(rv, rv);
JSContext* cx;
rv = cc->GetJSContext(&cx);
NS_ENSURE_SUCCESS(rv, rv);
PRUint32 argc;
rv = cc->GetArgc(&argc);
NS_ENSURE_SUCCESS(rv, rv);
jsval* argv;
rv = cc->GetArgvPtr(&argv);
NS_ENSURE_SUCCESS(rv, rv);
// Determine the current script global. We need it to register the worker.
// NewChromeDOMWorker will check that we are chrome, so no access check.
JSObject* globalobj = JS_GetGlobalForScopeChain(cx);
NS_ENSURE_TRUE(globalobj, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIScriptGlobalObject> global =
nsJSUtils::GetStaticScriptGlobal(cx, globalobj);
NS_ENSURE_TRUE(global, NS_ERROR_UNEXPECTED);
// Create, initialize, and return the worker.
nsRefPtr<nsDOMWorker> chromeWorker;
rv = nsDOMWorker::NewChromeDOMWorker(getter_AddRefs(chromeWorker));
NS_ENSURE_SUCCESS(rv, rv);
rv = chromeWorker->InitializeInternal(global, cx, globalobj, argc, argv);
NS_ENSURE_SUCCESS(rv, rv);
chromeWorker.forget(_retval);
return NS_OK;
}
NS_IMPL_ISUPPORTS1(nsWorkerFactory, nsIWorkerFactory)

View File

@ -1,4 +1,4 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -55,6 +55,11 @@
#include "nsDOMWorkerMessageHandler.h"
// {1295EFB5-8644-42B2-8B8E-80EEF56E4284}
#define NS_WORKERFACTORY_CID \
{0x1295efb5, 0x8644, 0x42b2, \
{0x8b, 0x8e, 0x80, 0xee, 0xf5, 0x6e, 0x42, 0x84} }
class nsDOMWorker;
class nsDOMWorkerFeature;
class nsDOMWorkerMessageHandler;
@ -133,7 +138,7 @@ private:
};
class nsDOMWorker : public nsDOMWorkerMessageHandler,
public nsIChromeWorker,
public nsIWorker,
public nsITimerCallback,
public nsIJSNativeInitializer,
public nsIXPCScriptable
@ -164,13 +169,13 @@ public:
PRUint8 optional_argc);
NS_DECL_NSIABSTRACTWORKER
NS_DECL_NSIWORKER
NS_DECL_NSICHROMEWORKER
NS_DECL_NSITIMERCALLBACK
NS_DECL_NSICLASSINFO
NS_DECL_NSIXPCSCRIPTABLE
static nsresult NewWorker(nsISupports** aNewObject);
static nsresult NewChromeWorker(nsISupports** aNewObject);
static nsresult NewChromeDOMWorker(nsDOMWorker** aNewObject);
enum WorkerPrivilegeModel { CONTENT, CHROME };
@ -435,4 +440,11 @@ private:
PRPackedBool mFreeToDie;
};
class nsWorkerFactory : public nsIWorkerFactory
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIWORKERFACTORY
};
#endif /* __NSDOMWORKER_H__ */

View File

@ -120,6 +120,7 @@ _SUBDIR_TEST_FILES = \
_CHROME_TEST_FILES = \
test_chromeWorker.xul \
test_chromeWorkerComponent.xul \
chromeWorker_worker.js \
chromeWorker_subworker.js \
$(NULL)

View File

@ -17,6 +17,16 @@
ok(true, "ChromeWorker constructor wasn't blocked!");
}
try {
var worker = Components.classes["@mozilla.org/threads/workerfactory;1"]
.createInstance(Components.interfaces.nsIWorkerFactory)
.newChromeWorker("simpleThread_worker.js");
ok(false, "nsIWorkerFactory should be blocked!");
}
catch (e) {
ok(true, "nsIWorkerFactory wasn't blocked!");
}
</script>
</pre>
</body>

View File

@ -0,0 +1,82 @@
<?xml version="1.0"?>
<!-- ***** 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 DOM Worker tests.
-
- The Initial Developer of the Original Code is
- The Mozilla Foundation.
- Portions created by the Initial Developer are Copyright (C) 2010
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
- Ben Turner <bent.mozilla@gmail.com>
-
- Alternatively, the contents of this file may be used under the terms of
- either 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 LGPL or the GPL. 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 ***** -->
<window title="DOM Worker Threads Test"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="test();">
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"/>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
<script type="application/javascript">
<![CDATA[
function test()
{
SimpleTest.waitForExplicitFinish();
const Cc = Components.classes;
const Ci = Components.interfaces;
var wf = Cc["@mozilla.org/threads/workerfactory;1"]
.createInstance(Ci.nsIWorkerFactory);
var worker = wf.newChromeWorker("chromeWorker_worker.js");
worker.onmessage = function(event) {
is(event.data, "Done!", "Wrong message!");
SimpleTest.finish();
}
worker.onerror = function(event) {
ok(false, "Worker had an error: " + event.message);
worker.terminate();
SimpleTest.finish();
}
}
]]>
</script>
<body xmlns="http://www.w3.org/1999/xhtml">
<p id="display"></p>
<div id="content" style="display:none;"></div>
<pre id="test"></pre>
</body>
<label id="test-result"/>
</window>

View File

@ -151,18 +151,20 @@ Print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
for (unsigned int i=0; i<argc; ++i) {
JSString *str = JS_ValueToString(cx, argv[i]);
if (!str) return JS_FALSE;
JSAutoByteString bytes(cx, str);
if (!bytes) return JS_FALSE;
if (shell->mOutput) {
if (shell->mEmitHeader) {
char buf[80];
sprintf(buf, "[%d]", JS_GetStringLength(str));
shell->mOutput->Write(buf, strlen(buf), &bytesWritten);
}
shell->mOutput->Write(JS_GetStringBytes(str), JS_GetStringLength(str), &bytesWritten);
shell->mOutput->Write(bytes.ptr(), strlen(bytes), &bytesWritten);
}
else
printf("%s", JS_GetStringBytes(str)); // use cout if no output stream given.
printf("%s", bytes.ptr()); // use cout if no output stream given.
#ifdef DEBUG
// printf("%s", JS_GetStringBytes(str));
// printf("%s", bytes.ptr());
#endif
}
return JS_TRUE;
@ -196,7 +198,8 @@ Load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
JSString *str = JS_ValueToString(cx, argv[i]);
if (!str) return JS_FALSE;
//argv[i] = STRING_TO_JSVAL(str);
const char *url = JS_GetStringBytes(str);
JSAutoByteString url(cx, str);
if (!url) return JS_FALSE;
if (!shell->LoadURL(url, rval))
return JS_FALSE;
}
@ -275,21 +278,20 @@ SetProtocol(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
JSAutoRequest ar(cx);
JSString *str = JS_ValueToString(cx, argv[0]);
if (!str) return JS_FALSE;
char *protocol = JS_GetStringBytes(str);
JSString *protocol = JS_ValueToString(cx, argv[0]);
if (!protocol) return JS_FALSE;
if (!strcmp(protocol, "interactive")) {
if (JS_MatchStringAndAscii(protocol, "interactive")) {
shell->mEmitHeader = PR_FALSE;
shell->mPrompt = NS_LITERAL_CSTRING("\n> ");
shell->mProtocol = protocol;
}
else if (!strcmp(protocol, "synchronous")) {
else if (JS_MatchStringAndAscii(protocol, "synchronous")) {
shell->mEmitHeader = PR_TRUE;
shell->mPrompt = NS_LITERAL_CSTRING("\n> ");
shell->mProtocol = protocol;
}
else if (!strcmp(protocol, "plain")) {
else if (JS_MatchStringAndAscii(protocol, "plain")) {
shell->mEmitHeader = PR_FALSE;
shell->mPrompt = NS_LITERAL_CSTRING("\n");
shell->mProtocol = protocol;

View File

@ -254,7 +254,10 @@ Print(JSContext *cx,
str = JS_ValueToString(cx, argv[i]);
if (!str)
return JS_FALSE;
fprintf(stdout, "%s%s", i ? " " : "", JS_GetStringBytes(str));
JSAutoByteString bytes(cx, str);
if (!bytes)
return JS_FALSE;
fprintf(stdout, "%s%s", i ? " " : "", bytes.ptr());
fflush(stdout);
}
n++;
@ -292,8 +295,7 @@ Dump(JSContext *cx,
str = JS_ValueToString(cx, JS_ARGV(cx, vp)[0]);
if (!str)
return JS_FALSE;
fputs(JS_GetStringBytes(str), stdout);
JS_FileEscapedString(stdout, str, 0);
fflush(stdout);
return JS_TRUE;
}
@ -305,7 +307,6 @@ Load(JSContext *cx,
{
uintN i;
JSString *str;
const char *filename;
JSScript *script;
JSBool ok;
jsval result;
@ -321,13 +322,15 @@ Load(JSContext *cx,
if (!str)
return JS_FALSE;
argv[i] = STRING_TO_JSVAL(str);
filename = JS_GetStringBytes(str);
file = fopen(filename, "r");
JSAutoByteString filename(cx, str);
if (!filename)
return JS_FALSE;
file = fopen(filename.ptr(), "r");
if (!file) {
JS_ReportError(cx, "cannot open file '%s' for reading", filename);
JS_ReportError(cx, "cannot open file '%s' for reading", filename.ptr());
return JS_FALSE;
}
script = JS_CompileFileHandleForPrincipals(cx, obj, filename, file,
script = JS_CompileFileHandleForPrincipals(cx, obj, filename.ptr(), file,
Environment(cx)->GetPrincipal());
fclose(file);
if (!script)
@ -431,7 +434,7 @@ DumpHeap(JSContext *cx,
uintN argc,
jsval *vp)
{
char *fileName = NULL;
JSAutoByteString fileName;
void* startThing = NULL;
uint32 startTraceKind = 0;
void *thingToFind = NULL;
@ -451,7 +454,8 @@ DumpHeap(JSContext *cx,
if (!str)
return JS_FALSE;
*vp = STRING_TO_JSVAL(str);
fileName = JS_GetStringBytes(str);
if (!fileName.encode(cx, str))
return JS_FALSE;
}
vp = argv + 1;
@ -488,10 +492,10 @@ DumpHeap(JSContext *cx,
if (!fileName) {
dumpFile = stdout;
} else {
dumpFile = fopen(fileName, "w");
dumpFile = fopen(fileName.ptr(), "w");
if (!dumpFile) {
fprintf(stderr, "dumpHeap: can't open %s: %s\n",
fileName, strerror(errno));
fileName.ptr(), strerror(errno));
return JS_FALSE;
}
}
@ -672,10 +676,13 @@ ProcessFile(JSContext *cx,
/* Suppress error reports from JS_ValueToString(). */
older = JS_SetErrorReporter(cx, NULL);
str = JS_ValueToString(cx, result);
JSAutoByteString bytes;
if (str)
bytes.encode(cx, str);
JS_SetErrorReporter(cx, older);
if (str)
fprintf(stdout, "%s\n", JS_GetStringBytes(str));
if (!!bytes)
fprintf(stdout, "%s\n", bytes.ptr());
else
ok = JS_FALSE;
}

View File

@ -127,9 +127,22 @@ _newJSDScript(JSDContext* jsdc,
jsdscript->url = jsdlw_BuildAppRelativeFilename(jsdscript->app, raw_filename);
if( function )
{
JSString* funid = JS_GetFunctionId(function);
char* funbytes;
const char* funnanme;
if( fuinid )
{
funbytes = JS_EncodeString(cx, funid);
funname = funbytes ? funbytes : "";
}
else
{
funbytes = NULL;
funname = "anonymous";
}
jsdscript->lwscript =
LWDBG_GetScriptOfFunction(jsdscript->app,
JS_GetFunctionName(function));
LWDBG_GetScriptOfFunction(jsdscript->app,funname);
JS_Free(cx, funbytes);
/* also, make sure this file is added to filelist if is .js file */
if( HasFileExtention(raw_filename,"js") ||

View File

@ -81,6 +81,8 @@ public:
//
// Describes a simple base-offset address.
struct Address {
explicit Address() {}
explicit Address(RegisterID base, int32_t offset = 0)
: base(base)
, offset(offset)

View File

@ -383,7 +383,9 @@ public:
void push_i32(int imm)
{
FIXME_INSN_PRINTING;
js::JaegerSpew(js::JSpew_Insns,
IPFX "pushl %s$0x%x\n", MAYBE_PAD,
PRETTY_PRINT_OFFSET(imm));
m_formatter.oneByteOp(OP_PUSH_Iz);
m_formatter.immediate32(imm);
}
@ -2251,6 +2253,10 @@ private:
{
intptr_t offset = reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(from);
ASSERT(offset == static_cast<int32_t>(offset));
#define JS_CRASH(x) *(int *)x = 0
if (offset != static_cast<int32_t>(offset))
JS_CRASH(0xC0DE);
#undef JS_CRASH
js::JaegerSpew(js::JSpew_Insns,
ISPFX "##setRel32 ((from=%p)) ((to=%p))\n", from, to);

File diff suppressed because it is too large Load Diff

View File

@ -513,18 +513,17 @@ JSBool
TypeError(JSContext* cx, const char* expected, jsval actual)
{
JSString* str = JS_ValueToSource(cx, actual);
js::AutoStringRooter root(cx, str);
JSAutoByteString bytes;
const char* src;
if (str) {
src = JS_GetStringBytesZ(cx, str);
src = bytes.encode(cx, str);
if (!src)
return false;
} else {
JS_ClearPendingException(cx);
src = "<<error converting value to string>>";
}
JS_ReportErrorNumber(cx, GetErrorMessage, NULL,
CTYPESMSG_TYPE_ERROR, expected, src);
return false;
@ -4331,11 +4330,11 @@ StructType::LookupField(JSContext* cx, JSObject* obj, JSString *name)
if (ptr)
return &ptr->value;
const char* bytes = JS_GetStringBytesZ(cx, name);
JSAutoByteString bytes(cx, name);
if (!bytes)
return NULL;
JS_ReportError(cx, "%s does not name a field", bytes);
JS_ReportError(cx, "%s does not name a field", bytes.ptr());
return NULL;
}

View File

@ -404,7 +404,7 @@
.end new
.igroup apply JSOP_APPLY
.igroup funapply JSOP_FUNAPPLY
.imacro apply0 # apply fun this arr
pick 3 # fun this arr apply
@ -622,6 +622,10 @@
stop #
.end #
.end funapply
.igroup funcall JSOP_FUNCALL
.imacro call0 # call fun
swap # fun call
pop # fun
@ -686,7 +690,7 @@
stop #
.end #
.end apply
.end funcall
.igroup getprop JSOP_GETPROP
.imacro scriptgetter # obj

View File

@ -0,0 +1,3 @@
// |jit-test| error: RangeError;
var vs = [1, 1, 1, 1, 3.5, 1];
for (var i = 0, sz = vs.length; i < sz; i++) new Array(vs[i]);

View File

@ -0,0 +1,13 @@
var f = 99;
function g(a) {
if (a) {
var e = 55;
function f() {
print("f");
}
assertEq(f == 99, false);
}
}
g(true);

View File

@ -0,0 +1,11 @@
function testInt8Array(L) {
var f = new Int8Array(8);
f[0] = 0; // Don't assert.
}
for (var i = 0; i < 10; i++) {
testInt8Array(0);
}

View File

@ -0,0 +1,11 @@
/* Don't trip bogus assert. */
function foo()
{
var x;
while (x = 0) {
x = 1;
}
}
foo();

View File

@ -0,0 +1,29 @@
/* Don't confuse JIT code by making slow arrays that use inline slots inconsistently. */
function foo(a)
{
assertEq(a.x, 5);
}
function bar()
{
for (var i = 0; i < 50; i++) {
var a = [];
a[i] = 0;
delete a[i];
a.x = 5;
foo(a);
}
var b = [1,,2,,3,,4,,5];
assertEq(b.toString(), "1,,2,,3,,4,,5");
b.x = 0;
assertEq(b.toString(), "1,,2,,3,,4,,5");
delete b.x;
delete b[8];
delete b[6];
delete b[4];
assertEq(b.toString(), "1,,2,,,,,,");
}
bar();

View File

@ -0,0 +1,16 @@
var magic = HOTLOOP;
var obj = {};
for (var i = 1; i <= magic; ++i)
obj[i] = "a";
function func() {
var i = 1;
while (i in obj) {
++i;
}
return i - 1;
}
assertEq(func(), magic);
assertEq(func(), magic);
assertEq(func(), magic);

View File

@ -0,0 +1,10 @@
var gen = (function () {yield})();
var t = gen.throw;
try {
new t;
} catch (e) {
actual = "" + e;
}
assertEq(actual, "TypeError: Generator.prototype.throw called on incompatible Object");

View File

@ -0,0 +1,45 @@
var so = [];
function U(unusedV)
{
for (var i = 0; i < so.length; ++i)
return false;
so.push(0);
}
function C(v)
{
if (typeof v == "object" || typeof v == "function") {
for (var i = 0; i < 10; ++i) {}
U(v);
}
}
function exploreProperties(obj)
{
var props = [];
for (var o = obj; o; o = Object.getPrototypeOf(o)) {
props = props.concat(Object.getOwnPropertyNames(o));
}
for (var i = 0; i < props.length; ++i) {
var p = props[i];
try {
var v = obj[p];
C(v);
} catch(e) { }
}
}
function boom()
{
var a = [];
var b = function(){};
var c = [{}];
exploreProperties(a);
exploreProperties(b);
exploreProperties(c);
exploreProperties(c);
}
boom();

View File

@ -0,0 +1,12 @@
function g(code) {
f = Function(code);
for (a in f()) {}
}
/* Get call ic in a state to call CompileFunction for new functions. */
g()
g("(function(){})")
g()
/* Call generator with frame created by call ic + CompileFunction. */
g("yield")

View File

@ -0,0 +1,8 @@
var g = 0;
Object.defineProperty(RegExp.prototype, 'test', { get:function() { ++g } });
function f() {
for (var i = 0; i < 100; ++i)
/a/.exec('a');
}
f();
assertEq(g, 0);

View File

@ -0,0 +1,168 @@
function script1() { return arguments.length; }
function script2(x) { return x; }
function script3(x) { var o = arguments; return o[0]; }
function genClosure() { var x = 3; eval("x = 4"); return function(y) { return x + y } };
var closed1 = genClosure();
var closed2 = genClosure();
var closed3 = genClosure();
var native1 = String.prototype.search;
var native2 = String.prototype.match;
var tricky1 = { call:function(x,y) { return y }, apply:function(x,y) { return y } };
test0();
test1();
test2();
test3();
function test0() {
assertEq(script1.call(null), 0);
assertEq(script1.call(null, 1), 1);
assertEq(script1.call(null, 1,2), 2);
assertEq(native1.call("aabc", /b/), 2);
assertEq(native1.call("abc"), -1);
assertEq(tricky1.call(null, 9), 9);
assertEq(script1.apply(null), 0);
assertEq(script1.apply(null, [1]), 1);
assertEq(script1.apply(null, [1,2]), 2);
assertEq(native1.apply("aabc", [/b/]), 2);
assertEq(native1.apply("abc"), -1);
assertEq(tricky1.apply(null, 1), 1);
}
test0();
function test1() {
function f(arr) {
for (var i = 0; i < 10; ++i) {
for (var j = 0; j < arr.length; ++j) {
arr[j].call('a');
arr[j].apply('a', []);
var arg0 = [];
arr[j].apply('a', arg0);
(function() { arr[j].apply('a', arguments); })();
arr[j].call('a', 1);
arr[j].apply('a', [1]);
var arg0 = [1];
arr[j].apply('a', arg0);
(function() { arr[j].apply('a', arguments); })(1);
arr[j].call('a', 1,'g');
arr[j].apply('a', [1,'g']);
var arg0 = [1,'g'];
arr[j].apply('a', arg0);
(function() { arr[j].apply('a', arguments); })(1,'g');
arr[j].call('a', 1,'g',3,4,5,6,7,8,9);
arr[j].apply('a', [1,'g',3,4,5,6,7,8,9]);
var arg0 = [1,'g',3,4,5,6,7,8,9];
arr[j].apply('a', arg0);
(function() { arr[j].apply('a', arguments); })(1,'g',3,4,5,6,7,8,9);
}
}
}
f([script1, script1, script1, script1, script2, script2, script1, script2]);
f([script1, script2, script3, script1, script2, script3, script3, script3]);
f([script1, script2, script2, script2, script2, script3, script1, script2]);
f([script1, script1, script1, native1, native1, native1, native1, script1]);
f([native1, native1, native1, native2, native2, native2, native2, native1]);
f([native1, native2, native1, native2, native1, native2, native1, native2]);
f([native1, native1, native1, script1, script2, script2, native1, script3]);
f([closed1, closed1, closed1, closed2, closed2, closed2, script3, script3]);
f([closed1, closed2, closed1, closed2, closed1, closed2, closed1, closed2]);
f([closed1, closed2, closed3, closed1, closed2, closed3, script1, script2]);
f([closed1, closed1, closed1, closed2, closed2, closed2, native1, native2]);
f([closed1, closed1, closed1, closed2, closed2, closed2, native1, native2]);
f([native1, native1, native1, closed1, closed2, script1, script2, native2]);
}
// test things that break our speculation
function test2() {
var threw = false;
try {
(3).call(null, 1,2);
} catch (e) {
threw = true;
}
assertEq(threw, true);
var threw = false;
try {
(3).apply(null, [1,2]);
} catch (e) {
threw = true;
}
assertEq(threw, true);
var threw = false;
try {
var arr = [1,2];
(3).apply(null, arr);
} catch (e) {
threw = true;
}
assertEq(threw, true);
function tryAndFail(o) {
var threw = false;
try {
o.call(null, 1,2);
} catch(e) {
threw = true;
}
assertEq(threw, true);
threw = false;
try {
o.apply(null, [1,2]);
} catch(e) {
threw = true;
}
assertEq(threw, true);
}
tryAndFail(1);
tryAndFail({});
tryAndFail({call:{}, apply:{}});
tryAndFail({call:function() { throw "not js_fun_call"}, apply:function(){ throw "not js_fun_apply" }});
}
// hit the stubs::CompileFunction path
function test3() {
function genFreshFunction(s) { return new Function(s, "return " + s); }
function callIt(f) {
assertEq(f.call(null, 1,2), 1);
}
callIt(script2); callIt(script2); callIt(script2); callIt(script2);
callIt(genFreshFunction("x"));
callIt(genFreshFunction("y"));
callIt(genFreshFunction("z"));
function applyIt(f) {
var arr = [1,2];
assertEq(f.apply(null, arr), 1);
}
applyIt(script2); applyIt(script2); applyIt(script2); applyIt(script2);
applyIt(genFreshFunction("x"));
applyIt(genFreshFunction("y"));
applyIt(genFreshFunction("z"));
function applyIt1(f) {
function g() {
assertEq(f.apply(null, arguments), 1);
}
g(1,2);
}
applyIt1(script2); applyIt1(script2); applyIt1(script2); applyIt1(script2);
applyIt1(genFreshFunction("x"));
applyIt1(genFreshFunction("y"));
applyIt1(genFreshFunction("z"));
function applyIt2(f) {
assertEq(f.apply(null, [1,2]), 1);
}
applyIt2(script2); applyIt2(script2); applyIt2(script2); applyIt2(script2);
applyIt2(genFreshFunction("x"));
applyIt2(genFreshFunction("y"));
applyIt2(genFreshFunction("z"));
}

View File

@ -0,0 +1,29 @@
function f(x,y,z) {
return x + y + z;
}
Array.prototype[1] = 10;
function g() {
var arr = [1, ,3,4,5,6];
for (var i = 0; i < 10; ++i) {
assertEq(f.apply(null, arr), 14);
}
}
g();
Object.prototype[1] = 20;
function h() {
delete arguments[1];
return f.apply(null, arguments);
}
assertEq(h(1,2,3), 24);
function i() {
o = arguments;
delete o[1];
return f.apply(null, o);
}
assertEq(i(1,2,3), 24);

View File

@ -1,3 +1,5 @@
// |jit-test| error: ExitCleanly
// proxies can return primitives
assertEq(new (Proxy.createFunction({}, function(){}, function(){})), undefined);
@ -7,3 +9,8 @@ new(wrap(x))
// proxies can return the callee
var x = Proxy.createFunction({}, function (q) { return q; });
new x(x);
// not an error
new (Proxy.createFunction({}, "".indexOf));
throw "ExitCleanly"

View File

@ -0,0 +1,10 @@
// Test using 'while' with 'continue' -- the most ancient, the most powerful,
// the most rare of all coding incantations.
var i = 0;
while (i < HOTLOOP+4) {
++i;
continue;
}
assertEq(i, HOTLOOP+4);

View File

@ -0,0 +1,12 @@
setDebug(true);
x = "notset";
function main() {
/* The JSOP_STOP in a. */
a = { valueOf: function () { trap(main, 38, "success()"); } };
a + "";
x = "failure";
}
function success() { x = "success"; }
main();
assertEq(x, "success");

View File

@ -0,0 +1,14 @@
setDebug(true);
x = "notset";
function main() {
/* The JSOP_STOP in a. */
a = { valueOf: function () { trap(main, 59, "success()"); } };
b = "";
eval();
a + b;
x = "failure";
}
function success() { x = "success"; }
main();
assertEq(x, "success");

View File

@ -0,0 +1,8 @@
// |jit-test| error: TypeError
eval("\
function NaN() {}\
for(w in s) {}\
")
// Don't assert.

View File

@ -0,0 +1,5 @@
// don't assert
new(function() {
#1#
})

View File

@ -0,0 +1,5 @@
// don't crash
try{a()}catch(e){}
try{for(e in((JSON.e)(x=/x/)))throw []}catch(e){}
try{(function(){c()})()}catch(e){}
try{new function(){#1#}}catch(e){}

View File

@ -0,0 +1,5 @@
function a1(a2) {
return 10 - a2;
}
a3 = a1(-2147483648);
assertEq(a3, 2147483658);

View File

@ -0,0 +1,9 @@
function testLocalNames() {
var NaN = 4;
var undefined = 5;
var Infinity = 6;
return NaN + undefined + Infinity;
}
assertEq(testLocalNames(), 15);

View File

@ -0,0 +1,20 @@
function testNaN(x) {
var x = NaN;
assertEq(isNaN(x), true);
}
testNaN();
function testInfinity(x) {
return (x === Infinity);
}
assertEq(testInfinity(Infinity), true);
assertEq(testInfinity(6), false);
assertEq(testInfinity(-Infinity), false);
function testUndefined(x) {
return (x === undefined);
}
assertEq(testUndefined(undefined), true);
assertEq(testUndefined(), true);
assertEq(testUndefined(5), false);

View File

@ -0,0 +1,9 @@
NaN = 4;
undefined = 5;
Infinity = 6;
assertEq(isNaN(NaN), true);
assertEq(Infinity > 100, true);
assertEq(undefined != 5, true);

View File

@ -0,0 +1,20 @@
// vim: ts=4 sw=4 tw=99 et:
function A() {
this.x = 12;
this.y = function () { return this.x; };
this[1] = function () { return this.x; };
}
function f(obj, key){
assertEq(obj[key](), 12);
}
a = new A();
f(a, "y");
f(a, "y");
f(a, 1);
gc();
f(a, "y");
f(a, "y");

View File

@ -0,0 +1,89 @@
// vim: set ts=4 sw=4 tw=99 et:
function fillDense(a) {
}
function testDenseUKeyUArray(a, key) {
a.push(function () { return this[3]; });
a.push(function () { return this[4]; });
a.push(function() { return this[5]; });
a.push(20);
a.push("hi");
a.push(500);
assertEq(a[key](), 20);
assertEq(a[key + 1](), "hi");
assertEq(a[key + 2](), 500);
}
function testDenseVKeyUArray(a) {
a.push(function () { return this[3]; });
a.push(function () { return this[4]; });
a.push(function() { return this[5]; });
a.push(20);
a.push("hi");
a.push(500);
var key = a.length & 1;
assertEq(a[key](), 20);
assertEq(a[(key + 1) & 3](), "hi");
assertEq(a[(key + 2) & 3](), 500);
}
function testDenseKKeyUArray(a, key) {
a.push(function () { return this[3]; });
a.push(function () { return this[4]; });
a.push(function() { return this[5]; });
a.push(20);
a.push("hi");
a.push(500);
assertEq(a[0](), 20);
assertEq(a[1](), "hi");
assertEq(a[2](), 500);
}
function testDenseUKeyVArray(key) {
var a = [function () { return this[3]; },
function () { return this[4]; },
function() { return this[5]; },
20,
"hi",
500];
assertEq(a[key](), 20);
assertEq(a[key + 1](), "hi");
assertEq(a[key + 2](), 500);
}
function testDenseVKeyVArray() {
var a = [function () { return this[3]; },
function () { return this[4]; },
function() { return this[5]; },
20,
"hi",
500];
var key = a.length & 1;
assertEq(a[key](), 20);
assertEq(a[(key + 1) & 3](), "hi");
assertEq(a[(key + 2) & 3](), 500);
}
function testDenseKKeyVArray() {
var a = [function () { return this[3]; },
function () { return this[4]; },
function() { return this[5]; },
20,
"hi",
500];
assertEq(a[0](), 20);
assertEq(a[1](), "hi");
assertEq(a[2](), 500);
}
for (var i = 0; i < 5; i++) {
testDenseUKeyUArray([], 0);
testDenseVKeyUArray([]);
testDenseKKeyUArray([]);
testDenseUKeyVArray(0);
testDenseVKeyVArray();
testDenseKKeyVArray();
}

View File

@ -0,0 +1,93 @@
// vim: set ts=4 sw=4 tw=99 et:
function testUKeyUObject(a, key1, key2, key3) {
a.a = function () { return this.d; }
a.b = function () { return this.e; }
a.c = function() { return this.f; }
a.d = 20;
a.e = "hi";
a.f = 500;
assertEq(a[key1](), 20);
assertEq(a[key2](), "hi");
assertEq(a[key3](), 500);
}
function testVKeyUObject(a, key1, key2, key3) {
a.a = function () { return this.d; }
a.b = function () { return this.e; }
a.c = function() { return this.f; }
a.d = 20;
a.e = "hi";
a.f = 500;
assertEq(a["" + key1](), 20);
assertEq(a["" + key2](), "hi");
assertEq(a["" + key3](), 500);
}
function testKKeyUObject(a) {
a.a = function () { return this.d; }
a.b = function () { return this.e; }
a.c = function() { return this.f; }
a.d = 20;
a.e = "hi";
a.f = 500;
var key1 = "a";
var key2 = "b";
var key3 = "c";
assertEq(a[key1](), 20);
assertEq(a[key2](), "hi");
assertEq(a[key3](), 500);
}
function testUKeyVObject(key1, key2, key3) {
a = { a: function () { return this.d; },
b: function () { return this.e; },
c: function () { return this.f; },
d: 20,
e: "hi",
f: 500
};
assertEq(a[key1](), 20);
assertEq(a[key2](), "hi");
assertEq(a[key3](), 500);
}
function testVKeyVObject(key1, key2, key3) {
a = { a: function () { return this.d; },
b: function () { return this.e; },
c: function () { return this.f; },
d: 20,
e: "hi",
f: 500
};
assertEq(a["" + key1](), 20);
assertEq(a["" + key2](), "hi");
assertEq(a["" + key3](), 500);
}
function testKKeyVObject(a) {
a = { a: function () { return this.d; },
b: function () { return this.e; },
c: function () { return this.f; },
d: 20,
e: "hi",
f: 500
};
var key1 = "a";
var key2 = "b";
var key3 = "c";
assertEq(a[key1](), 20);
assertEq(a[key2](), "hi");
assertEq(a[key3](), 500);
}
for (var i = 0; i < 5; i++) {
testUKeyUObject({}, "a", "b", "c");
testVKeyUObject({}, "a", "b", "c");
testKKeyUObject({});
testUKeyVObject("a", "b", "c");
testVKeyVObject("a", "b", "c");
testKKeyVObject();
}

View File

@ -0,0 +1,20 @@
// vim: set ts=4 sw=4 tw=99 et:
function testUKeyUObject(a, key1, key2, key3) {
a.a = function () { return this.d; }
a.b = function () { return this.e; }
a.c = function() { return this.f; }
a.d = 20;
a.e = "hi";
a.f = 500;
delete a["b"];
Object.defineProperty(a, "b", { get: function () { return function () { return this.e; } } });
assertEq(a[key1](), 20);
assertEq(a[key2](), "hi");
assertEq(a[key3](), 500);
}
for (var i = 0; i < 5; i++)
testUKeyUObject({}, "a", "b", "c");

View File

@ -0,0 +1,41 @@
// vim: set ts=4 sw=4 tw=99 et:
function testBadSetElems(obj, key) {
obj[key] = 5;
obj[-1] = 5;
var L = obj;
L[L] = L;
obj = [];
obj.K = 5;
obj[2] = 5;
var T = "a";
obj[T] = 12;
obj = [];
obj[Object] = key;
}
function testDenseSets(L) {
var obj = [,,,,,,,,,,];
obj[2] = 2;
assertEq(obj[2], 2);
var T = L;
assertEq(obj[T], 2);
assertEq(obj.length, 10);
obj[10] = T;
assertEq(obj[10], T);
assertEq(obj.length, 11);
var K = T + 9;
obj[K] = K;
assertEq(obj[K], K);
assertEq(obj.length, 12);
obj[K + 1] = obj;
assertEq(obj[K + 1], obj);
assertEq(obj.length, 13);
}
for (var i = 0; i < 10; i++) {
testBadSetElems([], -1);
testDenseSets(2);
}

View File

@ -0,0 +1,36 @@
// vim: set ts=4 sw=4 tw=99 et:
function f() {
return [[], [], [], []];
}
function setelem(obj, key, val) {
obj[key] = val;
}
// Generate IC
setelem([], 0, "hi");
setelem([], 0, "hi");
// Get some arrays pre-indexing.
var arrays = f();
// Do bad stuff.
Object.defineProperty(Object.prototype, "1", { set: function (v) { this.kettle = v; } });
var k = arrays[0];
setelem(k, 1, 13);
assertEq(k.kettle, 13);
assertEq(k.hasOwnProperty("1"), false);
Object.defineProperty(Array.prototype, "2", { set: function (v) { this.pot = v; } });
k = arrays[1];
setelem(k, 2, "yam");
assertEq(k.pot, "yam");
gc();
// make sure this reset okay.
setelem([], 0, "hi");
setelem([], 0, "hi");

View File

@ -0,0 +1,24 @@
// vim: set ts=4 sw=4 tw=99 et:
function f() {
return [[], [], [], []];
}
function setelem(obj, key, val) {
obj[key] = val;
}
// Generate IC
setelem([], 0, "hi");
setelem([], 0, "hi");
var arrays = f();
var evil = { };
Object.defineProperty(evil, "1", { set: function (v) { this.ham = v; } });
Array.prototype.__proto__ = evil;
var k = arrays[0];
setelem(k, 1, "yam");
assertEq(k.ham, "yam");

View File

@ -130,7 +130,7 @@ MSG_DEF(JSMSG_MIN_TOO_BIG, 47, 1, JSEXN_SYNTAXERR, "overlarge minimu
MSG_DEF(JSMSG_MAX_TOO_BIG, 48, 1, JSEXN_SYNTAXERR, "overlarge maximum {0}")
MSG_DEF(JSMSG_OUT_OF_ORDER, 49, 1, JSEXN_SYNTAXERR, "maximum {0} less than minimum")
MSG_DEF(JSMSG_BAD_DESTRUCT_DECL, 50, 0, JSEXN_SYNTAXERR, "missing = in destructuring declaration")
MSG_DEF(JSMSG_BAD_DESTRUCT_ASS, 51, 0, JSEXN_SYNTAXERR, "invalid destructuring assignment operator")
MSG_DEF(JSMSG_BAD_DESTRUCT_ASS, 51, 0, JSEXN_REFERENCEERR, "invalid destructuring assignment operator")
MSG_DEF(JSMSG_PAREN_AFTER_LET, 52, 0, JSEXN_SYNTAXERR, "missing ) after let head")
MSG_DEF(JSMSG_CURLY_AFTER_LET, 53, 0, JSEXN_SYNTAXERR, "missing } after let block")
MSG_DEF(JSMSG_MISSING_PAREN, 54, 0, JSEXN_SYNTAXERR, "unterminated parenthetical")
@ -208,7 +208,7 @@ MSG_DEF(JSMSG_BAD_LABEL, 125, 0, JSEXN_SYNTAXERR, "invalid label")
MSG_DEF(JSMSG_DUPLICATE_LABEL, 126, 0, JSEXN_SYNTAXERR, "duplicate label")
MSG_DEF(JSMSG_VAR_HIDES_ARG, 127, 1, JSEXN_TYPEERR, "variable {0} redeclares argument")
MSG_DEF(JSMSG_BAD_VAR_INIT, 128, 0, JSEXN_SYNTAXERR, "invalid variable initialization")
MSG_DEF(JSMSG_BAD_LEFTSIDE_OF_ASS, 129, 0, JSEXN_SYNTAXERR, "invalid assignment left-hand side")
MSG_DEF(JSMSG_BAD_LEFTSIDE_OF_ASS, 129, 0, JSEXN_REFERENCEERR, "invalid assignment left-hand side")
MSG_DEF(JSMSG_BAD_OPERAND, 130, 1, JSEXN_SYNTAXERR, "invalid {0} operand")
MSG_DEF(JSMSG_BAD_PROP_ID, 131, 0, JSEXN_SYNTAXERR, "invalid property id")
MSG_DEF(JSMSG_RESERVED_ID, 132, 1, JSEXN_SYNTAXERR, "{0} is a reserved identifier")
@ -299,8 +299,8 @@ MSG_DEF(JSMSG_ARRAY_COMP_LEFTSIDE, 216, 0, JSEXN_SYNTAXERR, "invalid array co
MSG_DEF(JSMSG_NON_XML_FILTER, 217, 1, JSEXN_TYPEERR, "XML filter is applied to non-XML value {0}")
MSG_DEF(JSMSG_EMPTY_ARRAY_REDUCE, 218, 0, JSEXN_TYPEERR, "reduce of empty array with no initial value")
MSG_DEF(JSMSG_NON_LIST_XML_METHOD, 219, 2, JSEXN_TYPEERR, "can't call {0} method on an XML list with {1} elements")
MSG_DEF(JSMSG_BAD_DELETE_OPERAND, 220, 0, JSEXN_SYNTAXERR, "invalid delete operand")
MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 221, 0, JSEXN_SYNTAXERR, "invalid increment/decrement operand")
MSG_DEF(JSMSG_BAD_DELETE_OPERAND, 220, 0, JSEXN_REFERENCEERR, "invalid delete operand")
MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 221, 0, JSEXN_REFERENCEERR, "invalid increment/decrement operand")
MSG_DEF(JSMSG_UNEXPECTED_TYPE, 222, 2, JSEXN_TYPEERR, "{0} is {1}")
MSG_DEF(JSMSG_LET_DECL_NOT_IN_BLOCK, 223, 0, JSEXN_SYNTAXERR, "let declaration not directly within block")
MSG_DEF(JSMSG_BAD_OBJECT_INIT, 224, 0, JSEXN_SYNTAXERR, "invalid object initializer")
@ -314,7 +314,7 @@ MSG_DEF(JSMSG_NOT_NONNULL_OBJECT, 231, 0, JSEXN_TYPEERR, "value is not a non
MSG_DEF(JSMSG_DEPRECATED_OCTAL, 232, 0, JSEXN_SYNTAXERR, "octal literals and octal escape sequences are deprecated")
MSG_DEF(JSMSG_STRICT_CODE_WITH, 233, 0, JSEXN_SYNTAXERR, "strict mode code may not contain 'with' statements")
MSG_DEF(JSMSG_DUPLICATE_PROPERTY, 234, 1, JSEXN_SYNTAXERR, "property name {0} appears more than once in object literal")
MSG_DEF(JSMSG_DEPRECATED_DELETE_OPERAND, 235, 0, JSEXN_SYNTAXERR, "Applying the 'delete' operator to an unqualified name is deprecated")
MSG_DEF(JSMSG_DEPRECATED_DELETE_OPERAND, 235, 0, JSEXN_SYNTAXERR, "applying the 'delete' operator to an unqualified name is deprecated")
MSG_DEF(JSMSG_DEPRECATED_ASSIGN, 236, 1, JSEXN_SYNTAXERR, "assignment to {0} is deprecated")
MSG_DEF(JSMSG_BAD_BINDING, 237, 1, JSEXN_SYNTAXERR, "redefining {0} is deprecated")
MSG_DEF(JSMSG_INVALID_DESCRIPTOR, 238, 0, JSEXN_TYPEERR, "property descriptors must not specify a value or be writable when a getter or setter has been specified")
@ -342,3 +342,4 @@ MSG_DEF(JSMSG_CANT_CHANGE_EXTENSIBILITY, 259, 0, JSEXN_TYPEERR, "can't change ob
MSG_DEF(JSMSG_SC_BAD_SERIALIZED_DATA, 260, 1, JSEXN_INTERNALERR, "bad serialized structured data ({0})")
MSG_DEF(JSMSG_SC_UNSUPPORTED_TYPE, 261, 0, JSEXN_TYPEERR, "unsupported type for structured data")
MSG_DEF(JSMSG_SC_RECURSION, 262, 0, JSEXN_INTERNALERR, "recursive object")
MSG_DEF(JSMSG_CANT_WRAP_XML_OBJECT, 263, 0, JSEXN_TYPEERR, "can't wrap XML objects")

View File

@ -326,6 +326,13 @@ Script::analyze(JSContext *cx, JSScript *script)
setLocal(slot, LOCAL_USE_BEFORE_DEF);
}
/*
* If the script is in debug mode, JS_SetFrameReturnValue can be called at
* any safe point.
*/
if (cx->compartment->debugMode)
usesRval = true;
/*
* If we are in the middle of one or more jumps, the offset of the highest
* target jumping over this bytecode. Includes implicit jumps from
@ -574,10 +581,14 @@ Script::analyze(JSContext *cx, JSScript *script)
case JSOP_SETLOCAL:
case JSOP_FORLOCAL: {
uint32 local = GET_SLOTNO(pc);
JS_ASSERT_IF(local < nfixed &&
locals[local] != LOCAL_CONDITIONALLY_DEFINED &&
locals[local] != LOCAL_USE_BEFORE_DEF,
locals[local] <= offset);
/*
* The local variable may already have been marked as unconditionally
* defined at a later point in the script, if that definition was in the
* condition for a loop which then jumped back here. In such cases we
* will not treat the variable as ever being defined in the loop body
* (see setLocal).
*/
if (local < nfixed && locals[local] == LOCAL_CONDITIONALLY_DEFINED) {
if (forwardJump) {
/* Add this local to the variables defined after this bytecode. */

View File

@ -74,6 +74,7 @@ CPPSRCS = \
testThreads.cpp \
testTrap.cpp \
testUTF8.cpp \
testVersion.cpp \
testXDR.cpp \
$(NULL)

View File

@ -16,9 +16,9 @@ static void
funcTransition(const JSFunction *,
const JSScript *,
const JSContext *cx,
JSBool entering)
int entering)
{
if (entering) {
if (entering > 0) {
++depth;
++enters;
if (! JS_ON_TRACE(cx))
@ -32,7 +32,7 @@ funcTransition(const JSFunction *,
static JSBool called2 = false;
static void
funcTransition2(const JSFunction *, const JSScript*, const JSContext*, JSBool)
funcTransition2(const JSFunction *, const JSScript*, const JSContext*, int)
{
called2 = true;
}
@ -43,7 +43,7 @@ static void
funcTransitionOverlay(const JSFunction *fun,
const JSScript *script,
const JSContext *cx,
JSBool entering)
int entering)
{
(*innerCallback)(fun, script, cx, entering);
overlays++;
@ -66,7 +66,7 @@ BEGIN_TEST(testFuncCallback_bug507012)
// Check whether the basic function tracking works
EXEC("f(1)");
CHECK(enters == 2 && leaves == 2 && depth == 0);
CHECK(enters == 1+1 && leaves == 1+1 && depth == 0);
// Can we switch to a different callback?
enters = 777;
@ -91,7 +91,7 @@ BEGIN_TEST(testFuncCallback_bug507012)
EXEC("function g () { ++x; }");
interpreted = enters = leaves = depth = 0;
EXEC("for (i = 0; i < 50; ++i) { g(); }");
CHECK(enters == 50+1 && leaves == 50+1 && depth == 0);
CHECK(enters == 1+50 && leaves == 1+50 && depth == 0);
// If this fails, it means that the code was interpreted rather
// than trace-JITted, and so is not testing what it's supposed to
@ -114,7 +114,7 @@ BEGIN_TEST(testFuncCallback_bug507012)
CHECK(enters == 1);
CHECK(leaves == 1);
CHECK(depth == 0);
CHECK(overlays == 2); // 1 each for enter and exit
CHECK(overlays == enters + leaves);
interpreted = enters = leaves = depth = overlays = 0;
#endif

View File

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

View File

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

View File

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

View File

@ -0,0 +1,135 @@
#include "tests.h"
#include "jsscript.h"
#include "jscntxt.h"
using namespace js;
struct VersionFixture;
static VersionFixture *callbackData = NULL;
struct VersionFixture : public JSAPITest
{
JSScript *fakeScript(const char *contents, size_t length) {
return JS_CompileScript(cx, global, contents, length, "<test>", 1);
}
bool hasXML(uintN version) {
return VersionHasXML(JSVersion(version));
}
bool hasXML(JSScript *script) {
return hasXML(script->version);
}
bool hasXML() {
return OptionsHasXML(JS_GetOptions(cx));
}
bool checkVersionHasXML() {
CHECK(hasXML(cx->findVersion()));
return true;
}
bool checkOptionsHasNoXML() {
CHECK(!OptionsHasXML(cx->options));
return true;
}
/* Check that script compilation results in a version without XML. */
bool checkNewScriptNoXML() {
JSScript *script = fakeScript("", 0);
CHECK(script);
CHECK(!hasXML(script->version));
return true;
}
bool setVersion(JSVersion version) {
CHECK(JS_GetVersion(cx) != version);
JS_SetVersion(cx, version);
return true;
}
bool toggleXML(bool shouldEnable) {
CHECK(hasXML() == !shouldEnable);
JS_ToggleOptions(cx, JSOPTION_XML);
CHECK(hasXML() == shouldEnable);
return true;
}
bool disableXML() {
return toggleXML(false);
}
bool enableXML() {
return toggleXML(true);
}
};
/* Callbacks to throw into JS-land. */
JSBool
CallSetVersion(JSContext *cx, uintN argc, jsval *vp)
{
return callbackData->setVersion(JSVERSION_1_7);
}
JSBool
CheckVersionHasXML(JSContext *cx, uintN argc, jsval *vp)
{
return callbackData->checkVersionHasXML();
}
JSBool
CheckOptionsHasNoXML(JSContext *cx, uintN argc, jsval *vp)
{
return callbackData->checkOptionsHasNoXML();
}
JSBool
CheckNewScriptNoXML(JSContext *cx, uintN argc, jsval *vp)
{
return callbackData->checkNewScriptNoXML();
}
BEGIN_FIXTURE_TEST(VersionFixture, testOptionsAreUsedForVersionFlags)
{
/*
* See bug 611462. We are checking that the XML option setting from a JSAPI
* call is propagated to newly compiled scripts, instead of inheriting the
* XML setting from a script on the stack.
*/
callbackData = this;
/* Enable XML and compile a script to activate. */
enableXML();
const char toActivateChars[] =
"checkVersionHasXML();"
"checkOptionsHasNoXML();"
"callSetVersion();"
"checkNewScriptNoXML();";
JSScript *toActivate = fakeScript(toActivateChars, sizeof(toActivateChars) - 1);
CHECK(toActivate);
JSObject *scriptObject = JS_GetScriptObject(toActivate);
CHECK(hasXML(toActivate));
disableXML();
JSFunction *f1 = JS_DefineFunction(cx, global, "checkVersionHasXML", CheckVersionHasXML, 0, 0);
CHECK(f1);
JSFunction *f2 = JS_DefineFunction(cx, global, "checkOptionsHasNoXML", CheckOptionsHasNoXML,
0, 0);
CHECK(f2);
JSFunction *f3 = JS_DefineFunction(cx, global, "callSetVersion", CallSetVersion, 0, 0);
CHECK(f3);
JSFunction *f4 = JS_DefineFunction(cx, global, "checkNewScriptNoXML", CheckNewScriptNoXML,
0, 0);
CHECK(f4);
CHECK(scriptObject);
/* Activate the script. */
jsval dummy;
CHECK(JS_ExecuteScript(cx, global, toActivate, &dummy));
return true;
}
END_FIXTURE_TEST(VersionFixture, testOptionsAreUsedForVersionFlags)

View File

@ -45,6 +45,7 @@ JSAPITest *JSAPITest::list;
int main(int argc, char *argv[])
{
int total = 0;
int failures = 0;
const char *filter = (argc == 2) ? argv[1] : NULL;
@ -52,9 +53,11 @@ int main(int argc, char *argv[])
for (JSAPITest *test = JSAPITest::list; test; test = test->next) {
const char *name = test->name();
if (filter && strcmp(filter, name) != 0)
if (filter && strstr(name, filter) == NULL)
continue;
total += 1;
printf("%s\n", name);
if (!test->init()) {
printf("TEST-UNEXPECTED-FAIL | %s | Failed to initialize.\n", name);
@ -79,6 +82,6 @@ int main(int argc, char *argv[])
printf("\n%d unexpected failure%s.\n", failures, (failures == 1 ? "" : "s"));
return 1;
}
printf("\nPassed.\n");
printf("\nPassed: ran %d tests.\n", total);
return 0;
}

View File

@ -174,8 +174,11 @@ class JSAPITest
JSAPITestString toSource(jsval v) {
JSString *str = JS_ValueToSource(cx, v);
if (str)
return JSAPITestString(JS_GetStringBytes(str));
if (str) {
JSAutoByteString bytes(cx, str);
if (!!bytes)
return JSAPITestString(bytes.ptr());
}
JS_ClearPendingException(cx);
return JSAPITestString("<<error converting value to string>>");
}
@ -207,8 +210,11 @@ class JSAPITest
JS_GetPendingException(cx, v.addr());
JS_ClearPendingException(cx);
JSString *s = JS_ValueToString(cx, v);
if (s)
msg += JS_GetStringBytes(s);
if (s) {
JSAutoByteString bytes(cx, s);
if (!!bytes)
msg += bytes.ptr();
}
}
fprintf(stderr, "%s:%d:%.*s\n", filename, lineno, (int) msg.length(), msg.begin());
msgs += msg;

View File

@ -95,6 +95,7 @@
#include "jsscopeinlines.h"
#include "jscntxtinlines.h"
#include "jsregexpinlines.h"
#include "jsstrinlines.h"
#include "assembler/wtf/Platform.h"
#if ENABLE_YARR_JIT
@ -120,13 +121,18 @@ class AutoVersionAPI
explicit AutoVersionAPI(JSContext *cx, JSVersion newVersion)
: cx(cx), oldVersion(cx->findVersion()), oldVersionWasOverride(cx->isVersionOverridden()),
oldOptions(cx->options) {
JS_ASSERT(!VersionExtractFlags(newVersion) ||
VersionExtractFlags(newVersion) == VersionFlags::HAS_XML);
/*
* Note: ANONFUNFIX in newVersion is ignored for backwards
* compatibility, must be set via JS_SetOptions. (Because of this, we
* inherit the current ANONFUNFIX setting from the options.
*/
cx->options = VersionHasXML(newVersion)
? (cx->options | JSOPTION_XML)
: (cx->options & ~JSOPTION_XML);
VersionSetAnonFunFix(&newVersion, OptionsHasAnonFunFix(cx->options));
cx->maybeOverrideVersion(newVersion);
SyncOptionsToVersion(cx);
cx->checkOptionVersionSync();
}
~AutoVersionAPI() {
@ -253,10 +259,11 @@ JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv, const char *format
if (fun) {
char numBuf[12];
JS_snprintf(numBuf, sizeof numBuf, "%u", argc);
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_MORE_ARGS_NEEDED,
JS_GetFunctionName(fun), numBuf,
(argc == 1) ? "" : "s");
JSAutoByteString funNameBytes;
if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
name, numBuf, (argc == 1) ? "" : "s");
}
}
return JS_FALSE;
}
@ -291,19 +298,13 @@ JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv, const char *format
return JS_FALSE;
*va_arg(ap, jsdouble *) = js_DoubleToInteger(d);
break;
case 's':
case 'S':
case 'W':
str = js_ValueToString(cx, Valueify(*sp));
if (!str)
return JS_FALSE;
*sp = STRING_TO_JSVAL(str);
if (c == 's') {
const char *bytes = js_GetStringBytes(cx, str);
if (!bytes)
return JS_FALSE;
*va_arg(ap, const char **) = bytes;
} else if (c == 'W') {
if (c == 'W') {
const jschar *chars = js_GetStringChars(cx, str);
if (!chars)
return JS_FALSE;
@ -809,7 +810,7 @@ StartRequest(JSContext *cx)
{
JSThread *t = cx->thread;
JS_ASSERT(CURRENT_THREAD_IS_ME(t));
if (t->data.requestDepth) {
t->data.requestDepth++;
} else {
@ -1018,17 +1019,6 @@ JS_GetVersion(JSContext *cx)
return VersionNumber(cx->findVersion());
}
static void
CheckOptionVersionSync(JSContext *cx)
{
#if DEBUG
uint32 options = cx->options;
JSVersion version = cx->findVersion();
JS_ASSERT(OptionsHasXML(options) == VersionHasXML(version));
JS_ASSERT(OptionsHasAnonFunFix(options) == VersionHasAnonFunFix(version));
#endif
}
JS_PUBLIC_API(JSVersion)
JS_SetVersion(JSContext *cx, JSVersion newVersion)
{
@ -1045,9 +1035,9 @@ JS_SetVersion(JSContext *cx, JSVersion newVersion)
if (newVersionNumber != JSVERSION_DEFAULT && newVersionNumber <= JSVERSION_1_4)
return oldVersionNumber;
VersionCloneFlags(oldVersion, &newVersion);
cx->optionFlagsToVersion(&newVersion);
cx->maybeOverrideVersion(newVersion);
CheckOptionVersionSync(cx);
cx->checkOptionVersionSync();
return oldVersionNumber;
}
@ -1109,9 +1099,9 @@ JS_SetOptions(JSContext *cx, uint32 options)
AutoLockGC lock(cx->runtime);
uint32 oldopts = cx->options;
cx->options = options;
SyncOptionsToVersion(cx);
cx->syncOptionsToVersion();
cx->updateJITEnabled();
CheckOptionVersionSync(cx);
cx->checkOptionVersionSync();
return oldopts;
}
@ -1119,12 +1109,12 @@ JS_PUBLIC_API(uint32)
JS_ToggleOptions(JSContext *cx, uint32 options)
{
AutoLockGC lock(cx->runtime);
CheckOptionVersionSync(cx);
cx->checkOptionVersionSync();
uint32 oldopts = cx->options;
cx->options ^= options;
(void) SyncOptionsToVersion(cx);
cx->syncOptionsToVersion();
cx->updateJITEnabled();
CheckOptionVersionSync(cx);
cx->checkOptionVersionSync();
return oldopts;
}
@ -1535,8 +1525,8 @@ static JSStdName standard_class_names[] = {
{js_InitObjectClass, EAGER_ATOM(eval), CLASP(Object)},
/* Global properties and functions defined by the Number class. */
{js_InitNumberClass, LAZY_ATOM(NaN), CLASP(Number)},
{js_InitNumberClass, LAZY_ATOM(Infinity), CLASP(Number)},
{js_InitNumberClass, EAGER_ATOM(NaN), CLASP(Number)},
{js_InitNumberClass, EAGER_ATOM(Infinity), CLASP(Number)},
{js_InitNumberClass, LAZY_ATOM(isNaN), CLASP(Number)},
{js_InitNumberClass, LAZY_ATOM(isFinite), CLASP(Number)},
{js_InitNumberClass, LAZY_ATOM(parseFloat), CLASP(Number)},
@ -2190,7 +2180,7 @@ JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, ui
JS_snprintf(buf, bufsize, "%p", fun);
} else {
if (fun->atom)
js_PutEscapedString(buf, bufsize, ATOM_TO_STRING(fun->atom), 0);
PutEscapedString(buf, bufsize, ATOM_TO_STRING(fun->atom), 0);
}
} else if (clasp->flags & JSCLASS_HAS_PRIVATE) {
JS_snprintf(buf, bufsize, "%p", obj->getPrivate());
@ -2201,7 +2191,7 @@ JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, ui
}
case JSTRACE_STRING:
js_PutEscapedString(buf, bufsize, (JSString *)thing, 0);
PutEscapedString(buf, bufsize, (JSString *)thing, 0);
break;
#if JS_HAS_XML_SUPPORT
@ -2681,25 +2671,26 @@ JS_FlushCaches(JSContext *cx)
JS_PUBLIC_API(intN)
JS_AddExternalStringFinalizer(JSStringFinalizeOp finalizer)
{
return js_ChangeExternalStringFinalizer(NULL, finalizer);
return JSExternalString::changeFinalizer(NULL, finalizer);
}
JS_PUBLIC_API(intN)
JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer)
{
return js_ChangeExternalStringFinalizer(finalizer, NULL);
return JSExternalString::changeFinalizer(finalizer, NULL);
}
JS_PUBLIC_API(JSString *)
JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type)
{
CHECK_REQUEST(cx);
JS_ASSERT(uintN(type) < JS_EXTERNAL_STRING_LIMIT);
JS_ASSERT(uintN(type) < JSExternalString::TYPE_LIMIT);
JSString *str = js_NewGCExternalString(cx, uintN(type));
JSExternalString *str = js_NewGCExternalString(cx, uintN(type));
if (!str)
return NULL;
str->initFlat(chars, length);
str->externalStringType = type;
cx->runtime->updateMallocCounter((length + 1) * sizeof(jschar));
return str;
}
@ -2958,6 +2949,8 @@ JS_NewGlobalObject(JSContext *cx, JSClass *clasp)
if (!obj)
return NULL;
obj->syncSpecialEquality();
/* Construct a regexp statics object for this global object. */
JSObject *res = regexp_statics_construct(cx, obj);
if (!res ||
@ -3000,6 +2993,8 @@ JS_NewObject(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
JSObject *obj = NewNonFunction<WithProto::Class>(cx, clasp, proto, parent);
if (obj)
obj->syncSpecialEquality();
JS_ASSERT_IF(obj, obj->getParent());
return obj;
@ -3019,7 +3014,10 @@ JS_NewObjectWithGivenProto(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSO
JS_ASSERT(clasp != &js_FunctionClass);
JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
return NewNonFunction<WithProto::Given>(cx, clasp, proto, parent);
JSObject *obj = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent);
if (obj)
obj->syncSpecialEquality();
return obj;
}
JS_PUBLIC_API(JSObject *)
@ -3402,6 +3400,8 @@ JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *jsclasp
if (!nobj)
return NULL;
nobj->syncSpecialEquality();
if (!DefineProperty(cx, obj, name, ObjectValue(*nobj), NULL, NULL, attrs, 0, 0))
return NULL;
@ -4137,6 +4137,18 @@ JS_NewFunction(JSContext *cx, JSNative native, uintN nargs, uintN flags,
return js_NewFunction(cx, NULL, Valueify(native), nargs, flags, parent, atom);
}
JS_PUBLIC_API(JSFunction *)
JS_NewFunctionById(JSContext *cx, JSNative native, uintN nargs, uintN flags, JSObject *parent,
jsid id)
{
JS_ASSERT(JSID_IS_STRING(id));
JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
CHECK_REQUEST(cx);
assertSameCompartment(cx, parent);
return js_NewFunction(cx, NULL, Valueify(native), nargs, flags, parent, JSID_TO_ATOM(id));
}
JS_PUBLIC_API(JSObject *)
JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
{
@ -4212,9 +4224,10 @@ JS_GetFunctionObject(JSFunction *fun)
JS_PUBLIC_API(const char *)
JS_GetFunctionName(JSFunction *fun)
{
return fun->atom
? JS_GetStringBytes(ATOM_TO_STRING(fun->atom))
: js_anonymous_str;
if (!fun->atom)
return js_anonymous_str;
const char *byte = js_GetStringBytes(fun->atom);
return byte ? byte : "";
}
JS_PUBLIC_API(JSString *)
@ -4351,7 +4364,9 @@ JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call,
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj);
JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
return atom ? js_DefineFunction(cx, obj, atom, Valueify(call), nargs, attrs) : NULL;
if (!atom)
return NULL;
return js_DefineFunction(cx, obj, ATOM_TO_JSID(atom), Valueify(call), nargs, attrs);
}
JS_PUBLIC_API(JSFunction *)
@ -4363,7 +4378,19 @@ JS_DefineUCFunction(JSContext *cx, JSObject *obj,
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj);
JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
return atom ? js_DefineFunction(cx, obj, atom, Valueify(call), nargs, attrs) : NULL;
if (!atom)
return NULL;
return js_DefineFunction(cx, obj, ATOM_TO_JSID(atom), Valueify(call), nargs, attrs);
}
extern JS_PUBLIC_API(JSFunction *)
JS_DefineFunctionById(JSContext *cx, JSObject *obj, jsid id, JSNative call,
uintN nargs, uintN attrs)
{
JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj);
return js_DefineFunction(cx, obj, id, Valueify(call), nargs, attrs);
}
inline static void
@ -4381,10 +4408,10 @@ LAST_FRAME_CHECKS(JSContext *cx, bool result)
}
}
inline static uint32
inline static uint32
JS_OPTIONS_TO_TCFLAGS(JSContext *cx)
{
return ((cx->options & JSOPTION_COMPILE_N_GO) ? TCF_COMPILE_N_GO : 0) |
return ((cx->options & JSOPTION_COMPILE_N_GO) ? TCF_COMPILE_N_GO : 0) |
((cx->options & JSOPTION_NO_SCRIPT_RVAL) ? TCF_NO_SCRIPT_RVAL : 0);
}
@ -4427,6 +4454,17 @@ JS_CompileUCScript(JSContext *cx, JSObject *obj, const jschar *chars, size_t len
return JS_CompileUCScriptForPrincipals(cx, obj, NULL, chars, length, filename, lineno);
}
JS_PUBLIC_API(JSScript *)
JS_CompileScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
JSPrincipals *principals,
const char *bytes, size_t length,
const char *filename, uintN lineno,
JSVersion version)
{
AutoVersionAPI ava(cx, version);
return JS_CompileScriptForPrincipals(cx, obj, principals, bytes, length, filename, lineno);
}
JS_PUBLIC_API(JSScript *)
JS_CompileScriptForPrincipals(JSContext *cx, JSObject *obj,
JSPrincipals *principals,
@ -4548,6 +4586,14 @@ JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj, const char *file
return script;
}
JS_PUBLIC_API(JSScript *)
JS_CompileFileHandleForPrincipalsVersion(JSContext *cx, JSObject *obj, const char *filename,
FILE *file, JSPrincipals *principals, JSVersion version)
{
AutoVersionAPI ava(cx, version);
return JS_CompileFileHandleForPrincipals(cx, obj, filename, file, principals);
}
JS_PUBLIC_API(JSScript *)
JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename, FILE *file)
{
@ -4793,6 +4839,15 @@ JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval)
return ok;
}
JS_PUBLIC_API(JSBool)
JS_ExecuteScriptVersion(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval,
JSVersion version)
{
AutoVersionAPI ava(cx, version);
return JS_ExecuteScript(cx, obj, script, rval);
}
JS_PUBLIC_API(JSBool)
JS_EvaluateUCScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
JSPrincipals *principals,
@ -4857,6 +4912,16 @@ JS_EvaluateScriptForPrincipals(JSContext *cx, JSObject *obj, JSPrincipals *princ
return ok;
}
JS_PUBLIC_API(JSBool)
JS_EvaluateScriptForPrincipalsVersion(JSContext *cx, JSObject *obj, JSPrincipals *principals,
const char *bytes, uintN nbytes,
const char *filename, uintN lineno, jsval *rval, JSVersion version)
{
AutoVersionAPI avi(cx, version);
return JS_EvaluateScriptForPrincipals(cx, obj, principals, bytes, nbytes, filename, lineno,
rval);
}
JS_PUBLIC_API(JSBool)
JS_EvaluateScript(JSContext *cx, JSObject *obj, const char *bytes, uintN nbytes,
const char *filename, uintN lineno, jsval *rval)
@ -4945,9 +5010,23 @@ JS_New(JSContext *cx, JSObject *ctor, uintN argc, jsval *argv)
memcpy(args.argv(), argv, argc * sizeof(jsval));
bool ok = InvokeConstructor(cx, args);
JSObject *obj = (ok && args.rval().isObject())
? &args.rval().toObject()
: NULL;
JSObject *obj = NULL;
if (ok) {
if (args.rval().isObject()) {
obj = &args.rval().toObject();
} else {
/*
* Although constructors may return primitives (via proxies), this
* API is asking for an object, so we report an error.
*/
JSAutoByteString bytes;
if (js_ValueToPrintable(cx, args.rval(), &bytes)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_NEW_RESULT,
bytes.ptr());
}
}
}
LAST_FRAME_CHECKS(cx, ok);
return obj;
@ -5048,14 +5127,8 @@ JS_NewString(JSContext *cx, char *bytes, size_t nbytes)
/* Free chars (but not bytes, which caller frees on error) if we fail. */
str = js_NewString(cx, chars, length);
if (!str) {
if (!str)
cx->free(chars);
return NULL;
}
/* Hand off bytes to the deflated string cache, if possible. */
if (!cx->runtime->deflatedStringCache->setBytes(cx, str, bytes))
cx->free(bytes);
return str;
}
@ -5154,15 +5227,6 @@ JS_InternUCString(JSContext *cx, const jschar *s)
return JS_InternUCStringN(cx, s, js_strlen(s));
}
JS_PUBLIC_API(char *)
JS_GetStringBytes(JSString *str)
{
const char *bytes;
bytes = js_GetStringBytes(NULL, str);
return (char *)(bytes ? bytes : "");
}
JS_PUBLIC_API(jschar *)
JS_GetStringChars(JSString *str)
{
@ -5172,9 +5236,9 @@ JS_GetStringChars(JSString *str)
str->ensureNotRope();
/*
* API botch (again, shades of JS_GetStringBytes): 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.
* 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
@ -5196,7 +5260,7 @@ JS_GetStringChars(JSString *str)
s = str->dependentChars();
}
} else {
str->flatClearMutable();
str->flatClearExtensible();
s = str->flatChars();
}
return s;
@ -5208,11 +5272,11 @@ JS_GetStringLength(JSString *str)
return str->length();
}
JS_PUBLIC_API(const char *)
JS_GetStringBytesZ(JSContext *cx, JSString *str)
JS_PUBLIC_API(const jschar *)
JS_GetStringCharsAndLength(JSString *str, size_t *lengthp)
{
assertSameCompartment(cx, str);
return js_GetStringBytes(cx, str);
*lengthp = str->length();
return str->chars();
}
JS_PUBLIC_API(const jschar *)
@ -5228,6 +5292,24 @@ JS_CompareStrings(JSString *str1, JSString *str2)
return js_CompareStrings(str1, str2);
}
JS_PUBLIC_API(JSBool)
JS_MatchStringAndAscii(JSString *str, const char *asciiBytes)
{
return MatchStringAndAscii(str, asciiBytes);
}
JS_PUBLIC_API(size_t)
JS_PutEscapedString(char *buffer, size_t size, JSString *str, char quote)
{
return PutEscapedString(buffer, size, str, quote);
}
JS_PUBLIC_API(JSBool)
JS_FileEscapedString(FILE *fp, JSString *str, char quote)
{
return FileEscapedString(fp, str, quote);
}
JS_PUBLIC_API(JSString *)
JS_NewGrowableString(JSContext *cx, jschar *chars, size_t length)
{
@ -5267,7 +5349,6 @@ JS_PUBLIC_API(JSBool)
JS_EncodeCharacters(JSContext *cx, const jschar *src, size_t srclen, char *dst, size_t *dstlenp)
{
size_t n;
if (!dst) {
n = js_GetDeflatedStringLength(cx, src, srclen);
if (n == (size_t)-1) {
@ -5293,6 +5374,37 @@ JS_EncodeString(JSContext *cx, JSString *str)
return js_DeflateString(cx, str->chars(), str->length());
}
JS_PUBLIC_API(size_t)
JS_GetStringEncodingLength(JSContext *cx, JSString *str)
{
return js_GetDeflatedStringLength(cx, str->chars(), str->length());
}
JS_PUBLIC_API(size_t)
JS_EncodeStringToBuffer(JSString *str, char *buffer, size_t length)
{
/*
* FIXME bug 612141 - fix js_DeflateStringToBuffer interface so the result
* would allow to distinguish between insufficient buffer and encoding
* error.
*/
size_t writtenLength = length;
if (js_DeflateStringToBuffer(NULL, str->chars(), str->length(), buffer, &writtenLength)) {
JS_ASSERT(writtenLength <= length);
return writtenLength;
}
JS_ASSERT(writtenLength <= length);
size_t necessaryLength = js_GetDeflatedStringLength(NULL, str->chars(), str->length());
if (necessaryLength == size_t(-1))
return size_t(-1);
if (writtenLength != length) {
/* Make sure that the buffer contains only valid UTF-8 sequences. */
JS_ASSERT(js_CStringsAreUTF8);
PodZero(buffer + writtenLength, length - writtenLength);
}
return necessaryLength;
}
JS_PUBLIC_API(JSBool)
JS_Stringify(JSContext *cx, jsval *vp, JSObject *replacer, jsval space,
JSONWriteCallback callback, void *data)
@ -5594,7 +5706,7 @@ JS_ExecuteRegExpNoStatics(JSContext *cx, JSObject *obj, jschar *chars, size_t le
size_t *indexp, JSBool test, jsval *rval)
{
CHECK_REQUEST(cx);
RegExp *re = RegExp::extractFrom(obj);
if (!re)
return false;
@ -5805,7 +5917,7 @@ JS_ClearContextThread(JSContext *cx)
js_WaitForGC(rt);
js_ClearContextThread(cx);
JS_ASSERT_IF(JS_CLIST_IS_EMPTY(&t->contextList), !t->data.requestDepth);
/*
* We can access t->id as long as the GC lock is held and we cannot race
* with the GC that may delete t.

View File

@ -326,6 +326,12 @@ JSID_TO_STRING(jsid id)
return (JSString *)(JSID_BITS(id));
}
static JS_ALWAYS_INLINE JSBool
JSID_IS_ZERO(jsid id)
{
return JSID_BITS(id) == 0;
}
JS_PUBLIC_API(JSBool)
JS_StringHasBeenInterned(JSString *str);
@ -354,6 +360,10 @@ JSID_TO_INT(jsid id)
return ((int32)JSID_BITS(id)) >> 1;
}
/*
* Note: when changing these values, verify that their use in
* js_CheckForStringIndex is still valid.
*/
#define JSID_INT_MIN (-(1 << 30))
#define JSID_INT_MAX ((1 << 30) - 1)
@ -485,16 +495,16 @@ extern JS_PUBLIC_DATA(jsid) JSID_EMPTY;
if getters/setters use a shortid */
/* Function flags, set in JSFunctionSpec and passed to JS_NewFunction etc. */
#define JSFUN_CONSTRUCTOR 0x02 /* native that can be called as a ctor
without creating a this object */
#define JSFUN_LAMBDA 0x08 /* expressed, not declared, function */
#define JSFUN_HEAVYWEIGHT 0x80 /* activation requires a Call object */
#define JSFUN_HEAVYWEIGHT_TEST(f) ((f) & JSFUN_HEAVYWEIGHT)
#define JSFUN_PRIMITIVE_THIS 0x0100 /* |this| may be a primitive value */
#define JSFUN_CONSTRUCTOR 0x0200 /* native that can be called as a ctor
without creating a this object */
#define JSFUN_FLAGS_MASK 0x07fa /* overlay JSFUN_* attributes --
#define JSFUN_FLAGS_MASK 0x07f8 /* overlay JSFUN_* attributes --
bits 12-15 are used internally to
flag interpreted functions */
@ -546,7 +556,6 @@ JS_GetEmptyStringValue(JSContext *cx);
* j int32 Rounded int32 (coordinate)
* d jsdouble IEEE double
* I jsdouble Integral IEEE double
* s char * C string
* S JSString * Unicode string, accessed by a JSString pointer
* W jschar * Unicode character vector, 0-terminated (W for wide)
* o JSObject * Object reference
@ -2319,6 +2328,14 @@ extern JS_PUBLIC_API(JSFunction *)
JS_NewFunction(JSContext *cx, JSNative call, uintN nargs, uintN flags,
JSObject *parent, const char *name);
/*
* Create the function with the name given by the id. JSID_IS_STRING(id) must
* be true.
*/
extern JS_PUBLIC_API(JSFunction *)
JS_NewFunctionById(JSContext *cx, JSNative call, uintN nargs, uintN flags,
JSObject *parent, jsid id);
extern JS_PUBLIC_API(JSObject *)
JS_GetFunctionObject(JSFunction *fun);
@ -2375,6 +2392,10 @@ JS_DefineUCFunction(JSContext *cx, JSObject *obj,
const jschar *name, size_t namelen, JSNative call,
uintN nargs, uintN attrs);
extern JS_PUBLIC_API(JSFunction *)
JS_DefineFunctionById(JSContext *cx, JSObject *obj, jsid id, JSNative call,
uintN nargs, uintN attrs);
extern JS_PUBLIC_API(JSObject *)
JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent);
@ -2407,6 +2428,13 @@ JS_CompileScriptForPrincipals(JSContext *cx, JSObject *obj,
const char *bytes, size_t length,
const char *filename, uintN lineno);
extern JS_PUBLIC_API(JSScript *)
JS_CompileScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
JSPrincipals *principals,
const char *bytes, size_t length,
const char *filename, uintN lineno,
JSVersion version);
extern JS_PUBLIC_API(JSScript *)
JS_CompileUCScript(JSContext *cx, JSObject *obj,
const jschar *chars, size_t length,
@ -2437,6 +2465,11 @@ JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj,
const char *filename, FILE *fh,
JSPrincipals *principals);
extern JS_PUBLIC_API(JSScript *)
JS_CompileFileHandleForPrincipalsVersion(JSContext *cx, JSObject *obj,
const char *filename, FILE *fh,
JSPrincipals *principals);
/*
* NB: you must use JS_NewScriptObject and root a pointer to its return value
* in order to keep a JSScript and its atoms safe from garbage collection after
@ -2554,6 +2587,10 @@ JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, uintN indent);
extern JS_PUBLIC_API(JSBool)
JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval);
extern JS_PUBLIC_API(JSBool)
JS_ExecuteScriptVersion(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval,
JSVersion version);
/*
* Execute either the function-defining prolog of a script, or the script's
* main body, but not both.
@ -2573,6 +2610,13 @@ JS_EvaluateScriptForPrincipals(JSContext *cx, JSObject *obj,
const char *filename, uintN lineno,
jsval *rval);
extern JS_PUBLIC_API(JSBool)
JS_EvaluateScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
JSPrincipals *principals,
const char *bytes, uintN length,
const char *filename, uintN lineno,
jsval *rval, JSVersion version);
extern JS_PUBLIC_API(JSBool)
JS_EvaluateUCScript(JSContext *cx, JSObject *obj,
const jschar *chars, uintN length,
@ -2633,7 +2677,7 @@ Call(JSContext *cx, jsval thisv, JSObject *funObj, uintN argc, jsval *argv, jsva
return Call(cx, thisv, OBJECT_TO_JSVAL(funObj), argc, argv, rval);
}
} /* namespace JS */
} /* namespace js */
JS_BEGIN_EXTERN_C
#endif /* __cplusplus */
@ -2727,17 +2771,21 @@ JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length);
extern JS_PUBLIC_API(JSString *)
JS_InternUCString(JSContext *cx, const jschar *s);
extern JS_PUBLIC_API(char *)
JS_GetStringBytes(JSString *str);
/*
* Deprecated. Use JS_GetStringCharsZ() instead.
*/
extern JS_PUBLIC_API(jschar *)
JS_GetStringChars(JSString *str);
extern JS_PUBLIC_API(size_t)
JS_GetStringLength(JSString *str);
extern JS_PUBLIC_API(const char *)
JS_GetStringBytesZ(JSContext *cx, JSString *str);
/*
* Return the char array and length for this string. The array is not
* null-terminated.
*/
extern JS_PUBLIC_API(const jschar *)
JS_GetStringCharsAndLength(JSString *str, size_t *lengthp);
extern JS_PUBLIC_API(const jschar *)
JS_GetStringCharsZ(JSContext *cx, JSString *str);
@ -2745,6 +2793,15 @@ JS_GetStringCharsZ(JSContext *cx, JSString *str);
extern JS_PUBLIC_API(intN)
JS_CompareStrings(JSString *str1, JSString *str2);
extern JS_PUBLIC_API(JSBool)
JS_MatchStringAndAscii(JSString *str, const char *asciiBytes);
extern JS_PUBLIC_API(size_t)
JS_PutEscapedString(char *buffer, size_t size, JSString *str, char quote);
extern JS_PUBLIC_API(JSBool)
JS_FileEscapedString(FILE *fp, JSString *str, char quote);
/*
* This function is now obsolete and behaves the same as JS_NewUCString. Use
* JS_NewUCString instead.
@ -2854,6 +2911,80 @@ JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst,
JS_PUBLIC_API(char *)
JS_EncodeString(JSContext *cx, JSString *str);
/*
* Get number of bytes in the string encoding (without accounting for a
* terminating zero bytes. The function returns (size_t) -1 if the string
* can not be encoded into bytes and reports an error using cx accordingly.
*/
JS_PUBLIC_API(size_t)
JS_GetStringEncodingLength(JSContext *cx, JSString *str);
/*
* Encode string into a buffer. The function does not stores an additional
* zero byte. The function returns (size_t) -1 if the string can not be
* encoded into bytes with no error reported. Otherwise it returns the number
* of bytes that are necessary to encode the string. If that exceeds the
* length parameter, the string will be cut and only length bytes will be
* written into the buffer.
*
* If JS_CStringsAreUTF8() is true, the string does not fit into the buffer
* and the the first length bytes ends in the middle of utf-8 encoding for
* some character, then such partial utf-8 encoding is replaced by zero bytes.
* This way the result always represents the valid UTF-8 sequence.
*/
JS_PUBLIC_API(size_t)
JS_EncodeStringToBuffer(JSString *str, char *buffer, size_t length);
#ifdef __cplusplus
class JSAutoByteString {
public:
JSAutoByteString(JSContext *cx, JSString *str JS_GUARD_OBJECT_NOTIFIER_PARAM)
: mBytes(JS_EncodeString(cx, str)) {
JS_ASSERT(cx);
JS_GUARD_OBJECT_NOTIFIER_INIT;
}
JSAutoByteString(JS_GUARD_OBJECT_NOTIFIER_PARAM0)
: mBytes(NULL) {
JS_GUARD_OBJECT_NOTIFIER_INIT;
}
~JSAutoByteString() {
js_free(mBytes);
}
char *encode(JSContext *cx, JSString *str) {
JS_ASSERT(!mBytes);
JS_ASSERT(cx);
mBytes = JS_EncodeString(cx, str);
return mBytes;
}
void clear() {
js_free(mBytes);
mBytes = NULL;
}
char *ptr() const {
return mBytes;
}
bool operator!() const {
return !mBytes;
}
private:
char *mBytes;
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
/* Copy and assignment are not supported. */
JSAutoByteString(const JSAutoByteString &another);
JSAutoByteString &operator=(const JSAutoByteString &another);
};
#endif
/************************************************************************/
/*
* JSON functions
@ -3247,8 +3378,17 @@ JS_ClearContextThread(JSContext *cx);
typedef void (*JSFunctionCallback)(const JSFunction *fun,
const JSScript *scr,
const JSContext *cx,
JSBool entering);
int entering);
/*
* The callback is expected to be quick and noninvasive. It should not
* trigger interrupts, turn on debugging, or produce uncaught JS
* exceptions. The state of the stack and registers in the context
* cannot be relied upon, since this callback may be invoked directly
* from either JIT. The 'entering' field means we are entering a
* function if it is positive, leaving a function if it is zero or
* negative.
*/
extern JS_PUBLIC_API(void)
JS_SetFunctionCallback(JSContext *cx, JSFunctionCallback fcb);

View File

@ -346,8 +346,7 @@ IndexToId(JSContext* cx, JSObject* obj, jsdouble index, JSBool* hole, jsid* idp,
* properly rooted and can be used as GC-protected storage for temporaries.
*/
static JSBool
GetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, JSBool *hole,
Value *vp)
GetElement(JSContext *cx, JSObject *obj, jsdouble index, JSBool *hole, Value *vp)
{
JS_ASSERT(index >= 0);
if (obj->isDenseArray() && index < obj->getDenseArrayCapacity() &&
@ -392,6 +391,47 @@ GetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, JSBool *hole,
return JS_TRUE;
}
namespace js {
bool
GetElements(JSContext *cx, JSObject *aobj, jsuint length, Value *vp)
{
if (aobj->isDenseArray() && length <= aobj->getDenseArrayCapacity() &&
!js_PrototypeHasIndexedProperties(cx, aobj)) {
/* The prototype does not have indexed properties so hole = undefined */
Value *srcbeg = aobj->getDenseArrayElements();
Value *srcend = srcbeg + length;
for (Value *dst = vp, *src = srcbeg; src < srcend; ++dst, ++src)
*dst = src->isMagic(JS_ARRAY_HOLE) ? UndefinedValue() : *src;
} else if (aobj->isArguments() && !aobj->isArgsLengthOverridden() &&
!js_PrototypeHasIndexedProperties(cx, aobj)) {
/*
* Two cases, two loops: note how in the case of an active stack frame
* backing aobj, even though we copy from fp->argv, we still must check
* aobj->getArgsElement(i) for a hole, to handle a delete on the
* corresponding arguments element. See args_delProperty.
*/
if (JSStackFrame *fp = (JSStackFrame *) aobj->getPrivate()) {
JS_ASSERT(fp->numActualArgs() <= JS_ARGS_LENGTH_MAX);
fp->forEachCanonicalActualArg(CopyNonHoleArgsTo(aobj, vp));
} else {
Value *srcbeg = aobj->getArgsElements();
Value *srcend = srcbeg + length;
for (Value *dst = vp, *src = srcbeg; src < srcend; ++dst, ++src)
*dst = src->isMagic(JS_ARGS_HOLE) ? UndefinedValue() : *src;
}
} else {
for (uintN i = 0; i < length; i++) {
if (!aobj->getProperty(cx, INT_TO_JSID(jsint(i)), &vp[i]))
return JS_FALSE;
}
}
return true;
}
}
/*
* Set the value of the property at the given index to v assuming v is rooted.
*/
@ -813,24 +853,6 @@ js_PrototypeHasIndexedProperties(JSContext *cx, JSObject *obj)
return JS_FALSE;
}
#ifdef JS_TRACER
JSBool FASTCALL
js_Array_dense_setelem_hole(JSContext* cx, JSObject* obj, jsint i)
{
if (js_PrototypeHasIndexedProperties(cx, obj))
return false;
jsuint u = jsuint(i);
if (u >= obj->getArrayLength())
obj->setArrayLength(u + 1);
return true;
}
/* storeAccSet == ACCSET_OBJ_PRIVATE: because it can set 'length'. */
JS_DEFINE_CALLINFO_3(extern, BOOL, js_Array_dense_setelem_hole, CONTEXT, OBJECT, INT32,
0, tjit::ACCSET_OBJ_PRIVATE)
#endif
static JSBool
array_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value,
PropertyOp getter, PropertyOp setter, uintN attrs)
@ -1021,12 +1043,10 @@ JSObject::makeDenseArraySlow(JSContext *cx)
*/
JSObjectMap *oldMap = map;
/*
* Create a native scope. All slow arrays other than Array.prototype get
* the same initial shape.
*/
/* Create a native scope. */
JSObject *arrayProto = getProto();
if (!InitScopeForObject(cx, this, &js_SlowArrayClass, arrayProto, FINALIZE_OBJECT0))
js::gc::FinalizeKind kind = js::gc::FinalizeKind(arena()->header()->thingKind);
if (!InitScopeForObject(cx, this, &js_SlowArrayClass, arrayProto, kind))
return false;
uint32 capacity = getDenseArrayCapacity();
@ -1042,7 +1062,11 @@ JSObject::makeDenseArraySlow(JSContext *cx)
return false;
}
/* Create new properties pointing to existing elements. */
/*
* Create new properties pointing to existing elements. Pack the array to
* remove holes, so that shapes use successive slots (as for other objects).
*/
uint32 next = 0;
for (uint32 i = 0; i < capacity; i++) {
jsid id;
if (!ValueToId(cx, Int32Value(i), &id)) {
@ -1050,17 +1074,28 @@ JSObject::makeDenseArraySlow(JSContext *cx)
return false;
}
if (getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) {
setDenseArrayElement(i, UndefinedValue());
if (getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE))
continue;
}
if (!addDataProperty(cx, id, i, JSPROP_ENUMERATE)) {
setDenseArrayElement(next, getDenseArrayElement(i));
if (!addDataProperty(cx, id, next, JSPROP_ENUMERATE)) {
setMap(oldMap);
return false;
}
next++;
}
/*
* Dense arrays with different numbers of slots but the same number of fixed
* slots and the same non-hole indexes must use their fixed slots consistently.
*/
if (hasSlotsArray() && next <= numFixedSlots())
revertToFixedSlots(cx);
ClearValueRange(slots + next, this->capacity - next, false);
/*
* Finally, update class. If |this| is Array.prototype, then js_InitClass
* will create an emptyShape whose class is &js_SlowArrayClass, to ensure
@ -1142,7 +1177,7 @@ array_toSource(JSContext *cx, uintN argc, Value *vp)
/* Use vp to locally root each element value. */
JSBool hole;
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, index, &hole, vp)) {
!GetElement(cx, obj, index, &hole, vp)) {
goto out;
}
@ -1246,7 +1281,7 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
/* Use rval to locally root each element value. */
JSBool hole;
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, index, &hole, rval)) {
!GetElement(cx, obj, index, &hole, rval)) {
goto out;
}
@ -1474,8 +1509,8 @@ array_reverse(JSContext *cx, uintN argc, Value *vp)
for (jsuint i = 0, half = len / 2; i < half; i++) {
JSBool hole, hole2;
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, i, &hole, tvr.addr()) ||
!GetArrayElement(cx, obj, len - i - 1, &hole2, vp) ||
!GetElement(cx, obj, i, &hole, tvr.addr()) ||
!GetElement(cx, obj, len - i - 1, &hole2, vp) ||
!SetOrDeleteArrayElement(cx, obj, len - i - 1, hole, tvr.value()) ||
!SetOrDeleteArrayElement(cx, obj, i, hole2, *vp)) {
return false;
@ -1795,7 +1830,7 @@ js::array_sort(JSContext *cx, uintN argc, Value *vp)
JSBool hole;
vec[newlen].setNull();
tvr.changeLength(newlen + 1);
if (!GetArrayElement(cx, obj, i, &hole, &vec[newlen]))
if (!GetElement(cx, obj, i, &hole, &vec[newlen]))
return false;
if (hole)
@ -2019,10 +2054,15 @@ js_ArrayCompPush(JSContext *cx, JSObject *obj, const Value &vp)
JSBool JS_FASTCALL
js_ArrayCompPush_tn(JSContext *cx, JSObject *obj, ValueArgType v)
{
return ArrayCompPushImpl(cx, obj, ValueArgToConstRef(v));
if (!ArrayCompPushImpl(cx, obj, ValueArgToConstRef(v))) {
SetBuiltinError(cx);
return JS_FALSE;
}
return cx->tracerState->builtinStatus == 0;
}
JS_DEFINE_CALLINFO_3(extern, BOOL, js_ArrayCompPush_tn, CONTEXT, OBJECT, VALUE,
0, nanojit::ACCSET_STORE_ANY)
JS_DEFINE_CALLINFO_3(extern, BOOL_FAIL, js_ArrayCompPush_tn, CONTEXT, OBJECT,
VALUE, 0, nanojit::ACCSET_STORE_ANY)
static JSBool
array_push(JSContext *cx, uintN argc, Value *vp)
@ -2051,7 +2091,7 @@ array_pop_slowly(JSContext *cx, JSObject* obj, Value *vp)
index--;
/* Get the to-be-deleted property's value into vp. */
if (!GetArrayElement(cx, obj, index, &hole, vp))
if (!GetElement(cx, obj, index, &hole, vp))
return JS_FALSE;
if (!hole && !DeleteArrayElement(cx, obj, index, true))
return JS_FALSE;
@ -2071,7 +2111,7 @@ array_pop_dense(JSContext *cx, JSObject* obj, Value *vp)
return JS_TRUE;
}
index--;
if (!GetArrayElement(cx, obj, index, &hole, vp))
if (!GetElement(cx, obj, index, &hole, vp))
return JS_FALSE;
if (!hole && !DeleteArrayElement(cx, obj, index, true))
return JS_FALSE;
@ -2118,14 +2158,14 @@ array_shift(JSContext *cx, uintN argc, Value *vp)
}
/* Get the to-be-deleted property's value into vp ASAP. */
if (!GetArrayElement(cx, obj, 0, &hole, vp))
if (!GetElement(cx, obj, 0, &hole, vp))
return JS_FALSE;
/* Slide down the array above the first element. */
AutoValueRooter tvr(cx);
for (i = 0; i != length; i++) {
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, i + 1, &hole, tvr.addr()) ||
!GetElement(cx, obj, i + 1, &hole, tvr.addr()) ||
!SetOrDeleteArrayElement(cx, obj, i, hole, tvr.value())) {
return JS_FALSE;
}
@ -2170,7 +2210,7 @@ array_unshift(JSContext *cx, uintN argc, Value *vp)
do {
--last, --upperIndex;
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, last, &hole, tvr.addr()) ||
!GetElement(cx, obj, last, &hole, tvr.addr()) ||
!SetOrDeleteArrayElement(cx, obj, upperIndex, hole, tvr.value())) {
return JS_FALSE;
}
@ -2265,7 +2305,7 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
} else {
for (last = begin; last < end; last++) {
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, last, &hole, tvr.addr())) {
!GetElement(cx, obj, last, &hole, tvr.addr())) {
return JS_FALSE;
}
@ -2301,7 +2341,7 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
/* (uint) end could be 0, so we can't use a vanilla >= test. */
while (last-- > end) {
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, last, &hole, tvr.addr()) ||
!GetElement(cx, obj, last, &hole, tvr.addr()) ||
!SetOrDeleteArrayElement(cx, obj, last + delta, hole, tvr.value())) {
return JS_FALSE;
}
@ -2322,7 +2362,7 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
} else {
for (last = end; last < length; last++) {
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, last, &hole, tvr.addr()) ||
!GetElement(cx, obj, last, &hole, tvr.addr()) ||
!SetOrDeleteArrayElement(cx, obj, last - delta, hole, tvr.value())) {
return JS_FALSE;
}
@ -2401,7 +2441,7 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
for (jsuint slot = 0; slot < alength; slot++) {
JSBool hole;
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, aobj, slot, &hole, tvr.addr())) {
!GetElement(cx, aobj, slot, &hole, tvr.addr())) {
return false;
}
@ -2493,7 +2533,7 @@ array_slice(JSContext *cx, uintN argc, Value *vp)
AutoValueRooter tvr(cx);
for (slot = begin; slot < end; slot++) {
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, slot, &hole, tvr.addr())) {
!GetElement(cx, obj, slot, &hole, tvr.addr())) {
return JS_FALSE;
}
if (!hole && !SetArrayElement(cx, nobj, slot - begin, tvr.value()))
@ -2557,7 +2597,7 @@ array_indexOfHelper(JSContext *cx, JSBool isLast, uintN argc, Value *vp)
for (;;) {
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, (jsuint)i, &hole, vp)) {
!GetElement(cx, obj, (jsuint)i, &hole, vp)) {
return JS_FALSE;
}
if (!hole && StrictlyEqual(cx, *vp, tosearch)) {
@ -2647,7 +2687,7 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp)
} else {
JSBool hole;
do {
if (!GetArrayElement(cx, obj, start, &hole, vp))
if (!GetElement(cx, obj, start, &hole, vp))
return JS_FALSE;
start += step;
} while (hole && start != end);
@ -2702,7 +2742,7 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp)
for (jsint i = start; i != end; i += step) {
JSBool hole;
ok = JS_CHECK_OPERATION_LIMIT(cx) &&
GetArrayElement(cx, obj, i, &hole, tvr.addr());
GetElement(cx, obj, i, &hole, tvr.addr());
if (!ok)
goto out;
if (hole)

View File

@ -156,6 +156,17 @@ js_HasLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp);
extern JSBool JS_FASTCALL
js_IndexToId(JSContext *cx, jsuint index, jsid *idp);
namespace js {
/*
* This function assumes 'length' is effectively the result of calling
* js_GetLengthProperty on aobj.
*/
extern bool
GetElements(JSContext *cx, JSObject *aobj, jsuint length, js::Value *vp);
}
/*
* JS-specific merge sort function.
*/

View File

@ -90,9 +90,9 @@ JS_STATIC_ASSERT((1 + 2) * sizeof(JSAtom *) ==
offsetof(JSAtomState, typeAtoms) - ATOM_OFFSET_START);
const char *
js_AtomToPrintableString(JSContext *cx, JSAtom *atom)
js_AtomToPrintableString(JSContext *cx, JSAtom *atom, JSAutoByteString *bytes)
{
return js_ValueToPrintableString(cx, StringValue(ATOM_TO_STRING(atom)));
return js_ValueToPrintable(cx, StringValue(ATOM_TO_STRING(atom)), bytes);
}
#define JS_PROTO(name,code,init) const char js_##name##_str[] = #name;
@ -181,6 +181,8 @@ const char *const js_common_atom_names[] = {
"use strict", /* useStrictAtom */
"loc", /* locAtom */
"line", /* lineAtom */
"Infinity", /* InfinityAtom */
"NaN", /* NaNAtom */
#if JS_HAS_XML_SUPPORT
js_etago_str, /* etagoAtom */
@ -498,7 +500,7 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
* compartment lock.
*/
if (!needNewString && str->isFlat()) {
str->flatClearMutable();
str->flatClearExtensible();
key = str;
atoms.add(p, StringToInitialAtomEntry(key));
} else {
@ -627,7 +629,7 @@ js_DumpAtoms(JSContext *cx, FILE *fp)
fputs("<uninitialized>", fp);
} else {
JSString *key = AtomEntryToKey(entry);
js_FileEscapedString(fp, key, '"');
FileEscapedString(fp, key, '"');
uintN flags = AtomEntryFlags(entry);
if (flags != 0) {
fputs((flags & (ATOM_PINNED | ATOM_INTERNED))

View File

@ -133,11 +133,10 @@ IdToJsval(jsid id)
/*
* Return a printable, lossless char[] representation of a string-type atom.
* The lifetime of the result extends at least until the next GC activation,
* longer if cx's string newborn root is not overwritten.
* The lifetime of the result matches the lifetime of bytes.
*/
extern const char *
js_AtomToPrintableString(JSContext *cx, JSAtom *atom);
js_AtomToPrintableString(JSContext *cx, JSAtom *atom, JSAutoByteString *bytes);
struct JSAtomListElement {
JSHashEntry entry;
@ -374,6 +373,8 @@ struct JSAtomState
JSAtom *useStrictAtom;
JSAtom *locAtom;
JSAtom *lineAtom;
JSAtom *InfinityAtom;
JSAtom *NaNAtom;
#if JS_HAS_XML_SUPPORT
JSAtom *etagoAtom;
@ -408,8 +409,6 @@ struct JSAtomState
/* Less frequently used atoms, pinned lazily by JS_ResolveStandardClass. */
struct {
JSAtom *InfinityAtom;
JSAtom *NaNAtom;
JSAtom *XMLListAtom;
JSAtom *decodeURIAtom;
JSAtom *decodeURIComponentAtom;

View File

@ -575,7 +575,6 @@ js_dmod(jsdouble a, jsdouble b);
#endif /* !JS_TRACER */
/* Defined in jsarray.cpp. */
JS_DECLARE_CALLINFO(js_Array_dense_setelem_hole)
JS_DECLARE_CALLINFO(js_NewEmptyArray)
JS_DECLARE_CALLINFO(js_NewPreallocatedArray)
JS_DECLARE_CALLINFO(js_InitializerArray)

View File

@ -397,7 +397,7 @@ StackSpace::pushGeneratorFrame(JSContext *cx, JSFrameRegs *regs, GeneratorFrameG
bool
StackSpace::bumpCommitAndLimit(JSStackFrame *base, Value *sp, uintN nvals, Value **limit) const
{
JS_ASSERT(sp == firstUnused());
JS_ASSERT(sp >= firstUnused());
JS_ASSERT(sp + nvals >= *limit);
#ifdef XP_WIN
if (commitEnd <= *limit) {
@ -737,22 +737,6 @@ js_PurgeThreads(JSContext *cx)
#endif
}
bool
js::SyncOptionsToVersion(JSContext* cx)
{
JSVersion version = cx->findVersion();
uint32 options = cx->options;
if (OptionsHasXML(options) == VersionHasXML(version) &&
OptionsHasAnonFunFix(options) == VersionHasAnonFunFix(version)) {
/* No need to override. */
return false;
}
VersionSetXML(&version, OptionsHasXML(options));
VersionSetAnonFunFix(&version, OptionsHasAnonFunFix(options));
cx->maybeOverrideVersion(version);
return true;
}
JSContext *
js_NewContext(JSRuntime *rt, size_t stackChunkSize)
{
@ -2300,7 +2284,7 @@ JSContext::updateJITEnabled()
# endif
;
#ifdef JS_TRACER
profilingEnabled = (options & JSOPTION_PROFILING) && traceJitEnabled && methodJitEnabled;
profilingEnabled = (options & JSOPTION_PROFILING) && traceJitEnabled;
#endif
#endif
}

View File

@ -701,12 +701,6 @@ class StackSpace
friend class AllFramesIter;
StackSegment *getCurrentSegment() const { return currentSegment; }
/*
* Allocate nvals on the top of the stack, report error on failure.
* N.B. the caller must ensure |from == firstUnused()|.
*/
inline bool ensureSpace(JSContext *maybecx, Value *from, ptrdiff_t nvals) const;
#ifdef XP_WIN
/* Commit more memory from the reserved stack space. */
JS_FRIEND_API(bool) bumpCommit(Value *from, ptrdiff_t nvals) const;
@ -752,9 +746,6 @@ class StackSpace
*/
inline bool ensureEnoughSpaceToEnterTrace();
/* See stubs::HitStackQuota. */
inline bool bumpCommitEnd(Value *from, uintN nslots);
/* +1 for slow native's stack frame. */
static const ptrdiff_t MAX_TRACE_SPACE_VALS =
MAX_NATIVE_STACK_SLOTS + MAX_CALL_STACK_ENTRIES * VALUES_PER_STACK_FRAME +
@ -833,6 +824,12 @@ class StackSpace
* if fully committed or if 'limit' exceeds 'base' + STACK_QUOTA.
*/
bool bumpCommitAndLimit(JSStackFrame *base, Value *from, uintN nvals, Value **limit) const;
/*
* Allocate nvals on the top of the stack, report error on failure.
* N.B. the caller must ensure |from >= firstUnused()|.
*/
inline bool ensureSpace(JSContext *maybecx, Value *from, ptrdiff_t nvals) const;
};
JS_STATIC_ASSERT(StackSpace::CAPACITY_VALS % StackSpace::COMMIT_VALS == 0);
@ -1806,10 +1803,18 @@ OptionsSameVersionFlags(uint32 self, uint32 other)
return !((self & mask) ^ (other & mask));
}
/*
* Flags accompany script version data so that a) dynamically created scripts
* can inherit their caller's compile-time properties and b) scripts can be
* appropriately compared in the eval cache across global option changes. An
* example of the latter is enabling the top-level-anonymous-function-is-error
* option: subsequent evals of the same, previously-valid script text may have
* become invalid.
*/
namespace VersionFlags {
static const uint32 MASK = 0x0FFF; /* see JSVersion in jspubtd.h */
static const uint32 HAS_XML = 0x1000; /* flag induced by XML option */
static const uint32 ANONFUNFIX = 0x2000; /* see jsapi.h comment on JSOPTION_ANONFUNFIX */
static const uint32 MASK = 0x0FFF; /* see JSVersion in jspubtd.h */
static const uint32 HAS_XML = 0x1000; /* flag induced by XML option */
static const uint32 ANONFUNFIX = 0x2000; /* see jsapi.h comment on JSOPTION_ANONFUNFIX */
}
static inline JSVersion
@ -1873,12 +1878,6 @@ VersionIsKnown(JSVersion version)
return VersionNumber(version) != JSVERSION_UNKNOWN;
}
static inline void
VersionCloneFlags(JSVersion src, JSVersion *dst)
{
*dst = JSVersion(uint32(VersionNumber(*dst)) | uint32(VersionExtractFlags(src)));
}
} /* namespace js */
struct JSContext
@ -2077,7 +2076,9 @@ struct JSContext
* The default script compilation version can be set iff there is no code running.
* This typically occurs via the JSAPI right after a context is constructed.
*/
bool canSetDefaultVersion() const { return !regs && !hasVersionOverride; }
bool canSetDefaultVersion() const {
return !regs && !hasVersionOverride;
}
/* Force a version for future script compilation. */
void overrideVersion(JSVersion newVersion) {
@ -2087,11 +2088,18 @@ struct JSContext
}
public:
void clearVersionOverride() { hasVersionOverride = false; }
bool isVersionOverridden() const { return hasVersionOverride; }
void clearVersionOverride() {
hasVersionOverride = false;
}
bool isVersionOverridden() const {
return hasVersionOverride;
}
/* Set the default script compilation version. */
void setDefaultVersion(JSVersion version) { defaultVersion = version; }
void setDefaultVersion(JSVersion version) {
defaultVersion = version;
}
/*
* Set the default version if possible; otherwise, force the version.
@ -2130,6 +2138,30 @@ struct JSContext
return defaultVersion;
}
void optionFlagsToVersion(JSVersion *version) const {
js::VersionSetXML(version, js::OptionsHasXML(options));
js::VersionSetAnonFunFix(version, js::OptionsHasAnonFunFix(options));
}
void checkOptionVersionSync() const {
#ifdef DEBUG
JSVersion version = findVersion();
JS_ASSERT(js::VersionHasXML(version) == js::OptionsHasXML(options));
JS_ASSERT(js::VersionHasAnonFunFix(version) == js::OptionsHasAnonFunFix(options));
#endif
}
/* Note: may override the version. */
void syncOptionsToVersion() {
JSVersion version = findVersion();
if (js::OptionsHasXML(options) == js::VersionHasXML(version) &&
js::OptionsHasAnonFunFix(options) == js::VersionHasAnonFunFix(version))
return;
js::VersionSetXML(&version, js::OptionsHasXML(options));
js::VersionSetAnonFunFix(&version, js::OptionsHasAnonFunFix(options));
maybeOverrideVersion(version);
}
#ifdef JS_THREADSAFE
JSThread *thread;
unsigned outstandingRequests;/* number of JS_BeginRequest calls
@ -2195,7 +2227,7 @@ struct JSContext
void doFunctionCallback(const JSFunction *fun,
const JSScript *scr,
JSBool entering) const
int entering) const
{
if (functionCallback)
functionCallback(fun, scr, this, entering);
@ -2990,14 +3022,6 @@ class ThreadDataIter
#endif /* !JS_THREADSAFE */
/*
* If necessary, push the option flags that affect script compilation to the current version.
* Note this may cause a version override -- see JSContext::overrideVersion.
* Return whether a version change occurred.
*/
extern bool
SyncOptionsToVersion(JSContext *cx);
} /* namespace js */
/*

View File

@ -172,10 +172,10 @@ STATIC_POSTCONDITION(!return || ubound(from) >= nvals)
JS_ALWAYS_INLINE bool
StackSpace::ensureSpace(JSContext *maybecx, Value *from, ptrdiff_t nvals) const
{
JS_ASSERT(from == firstUnused());
JS_ASSERT(from >= firstUnused());
#ifdef XP_WIN
JS_ASSERT(from <= commitEnd);
if (JS_LIKELY(commitEnd - from >= nvals))
if (commitEnd - from >= nvals)
goto success;
if (end - from < nvals) {
if (maybecx)
@ -189,7 +189,7 @@ StackSpace::ensureSpace(JSContext *maybecx, Value *from, ptrdiff_t nvals) const
}
goto success;
#else
if (JS_LIKELY(end - from < nvals)) {
if (end - from < nvals) {
if (maybecx)
js_ReportOutOfScriptQuota(maybecx);
return false;
@ -248,7 +248,7 @@ StackSpace::pushInvokeArgs(JSContext *cx, uintN argc, InvokeArgsGuard *ag)
Value *vp = start;
Value *vpend = vp + nvals;
MakeValueRangeGCSafe(vp, vpend);
/* Don't need to MakeValueRangeGCSafe: the VM stack is conservatively marked. */
/* Use invokeArgEnd to root [vp, vpend) until the frame is pushed. */
ag->prevInvokeArgEnd = invokeArgEnd;

View File

@ -2299,21 +2299,18 @@ date_toLocaleTimeString(JSContext *cx, uintN argc, Value *vp)
static JSBool
date_toLocaleFormat(JSContext *cx, uintN argc, Value *vp)
{
JSString *fmt;
const char *fmtbytes;
if (argc == 0)
return date_toLocaleString(cx, argc, vp);
fmt = js_ValueToString(cx, vp[2]);
JSString *fmt = js_ValueToString(cx, vp[2]);
if (!fmt)
return JS_FALSE;
vp[2].setString(fmt);
fmtbytes = js_GetStringBytes(cx, fmt);
JSAutoByteString fmtbytes(cx, fmt);
if (!fmtbytes)
return JS_FALSE;
return date_toLocaleHelper(cx, fmtbytes, vp);
return date_toLocaleHelper(cx, fmtbytes.ptr(), vp);
}
static JSBool

View File

@ -65,6 +65,7 @@
#include "jswrapper.h"
#include "jsatominlines.h"
#include "jsdbgapiinlines.h"
#include "jsinterpinlines.h"
#include "jsobjinlines.h"
#include "jsscopeinlines.h"
@ -514,7 +515,7 @@ JS_ClearInterrupt(JSRuntime *rt, JSInterruptHook *hoop, void **closurep)
/************************************************************************/
typedef struct JSWatchPoint {
struct JSWatchPoint {
JSCList links;
JSObject *object; /* weak link, see js_FinalizeObject */
const Shape *shape;
@ -522,13 +523,13 @@ typedef struct JSWatchPoint {
JSWatchPointHandler handler;
JSObject *closure;
uintN flags;
} JSWatchPoint;
};
#define JSWP_LIVE 0x1 /* live because set and not cleared */
#define JSWP_HELD 0x2 /* held while running handler/setter */
static bool
IsWatchedProperty(JSContext *cx, const Shape &shape);
IsWatchedProperty(JSContext *cx, const Shape *shape);
/*
* NB: DropWatchPointAndUnlock releases cx->runtime->debuggerLock in all cases.
@ -545,41 +546,24 @@ DropWatchPointAndUnlock(JSContext *cx, JSWatchPoint *wp, uintN flag)
return ok;
}
/*
* Remove wp from the list, then if there are no other watchpoints for
* wp->shape in any scope, restore wp->shape->setter from wp.
*/
/* Remove wp from the list, then restore wp->shape->setter from wp. */
++rt->debuggerMutations;
JS_REMOVE_LINK(&wp->links);
const Shape *shape = wp->shape;
PropertyOp setter = NULL;
for (JSWatchPoint *wp2 = (JSWatchPoint *)rt->watchPointList.next;
&wp2->links != &rt->watchPointList;
wp2 = (JSWatchPoint *)wp2->links.next) {
if (wp2->shape == shape) {
setter = wp->setter;
break;
}
}
DBG_UNLOCK(rt);
if (!setter) {
/*
* If the property wasn't found on wp->object, or it isn't still being
* watched, then someone else must have deleted or unwatched it, and we
* don't need to change the property attributes.
*/
const Shape *wprop = wp->object->nativeLookup(shape->id);
if (wprop &&
wprop->hasSetterValue() == shape->hasSetterValue() &&
IsWatchedProperty(cx, *wprop)) {
shape = wp->object->changeProperty(cx, wprop, 0, wprop->attributes(),
wprop->getter(), wp->setter);
if (!shape)
ok = false;
}
/*
* If the property isn't found on wp->object, then someone else must have deleted it,
* and we don't need to change the property attributes.
*/
const Shape *shape = wp->shape;
const Shape *wprop = wp->object->nativeLookup(shape->id);
if (wprop &&
wprop->hasSetterValue() == shape->hasSetterValue() &&
IsWatchedProperty(cx, wprop)) {
shape = wp->object->changeProperty(cx, wprop, 0, wprop->attributes(),
wprop->getter(), wp->setter);
if (!shape)
ok = false;
}
cx->free(wp);
@ -640,10 +624,10 @@ js_SweepWatchPoints(JSContext *cx)
/*
* NB: FindWatchPoint must be called with rt->debuggerLock acquired.
* NB: LockedFindWatchPoint must be called with rt->debuggerLock acquired.
*/
static JSWatchPoint *
FindWatchPoint(JSRuntime *rt, JSObject *obj, jsid id)
LockedFindWatchPoint(JSRuntime *rt, JSObject *obj, jsid id)
{
JSWatchPoint *wp;
@ -656,17 +640,15 @@ FindWatchPoint(JSRuntime *rt, JSObject *obj, jsid id)
return NULL;
}
const Shape *
js_FindWatchPoint(JSRuntime *rt, JSObject *obj, jsid id)
static JSWatchPoint *
FindWatchPoint(JSRuntime *rt, JSObject *obj, jsid id)
{
JSWatchPoint *wp;
const Shape *shape;
DBG_LOCK(rt);
wp = FindWatchPoint(rt, obj, id);
shape = wp ? wp->shape : NULL;
wp = LockedFindWatchPoint(rt, obj, id);
DBG_UNLOCK(rt);
return shape;
return wp;
}
JSBool
@ -716,7 +698,7 @@ js_watch_set(JSContext *cx, JSObject *obj, jsid id, Value *vp)
return JS_TRUE;
}
JSBool
static JSBool
js_watch_set_wrapper(JSContext *cx, uintN argc, Value *vp)
{
JSObject *obj = ComputeThisFromVp(cx, vp);
@ -732,28 +714,38 @@ js_watch_set_wrapper(JSContext *cx, uintN argc, Value *vp)
}
static bool
IsWatchedProperty(JSContext *cx, const Shape &shape)
IsWatchedProperty(JSContext *cx, const Shape *shape)
{
if (shape.hasSetterValue()) {
JSObject *funobj = shape.setterObject();
if (shape->hasSetterValue()) {
JSObject *funobj = shape->setterObject();
if (!funobj || !funobj->isFunction())
return false;
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
return fun->maybeNative() == js_watch_set_wrapper;
}
return shape.setterOp() == js_watch_set;
return shape->setterOp() == js_watch_set;
}
PropertyOp
js_WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, PropertyOp setter)
/*
* Return an appropriate setter to substitute for |setter| on a property
* with attributes |attrs|, to implement a watchpoint on the property named
* |id|.
*/
static PropertyOp
WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, PropertyOp setter)
{
JSAtom *atom;
JSFunction *wrapper;
/* Wrap a JSPropertyOp setter simply by returning our own JSPropertyOp. */
if (!(attrs & JSPROP_SETTER))
return &js_watch_set; /* & to silence schoolmarmish MSVC */
/*
* Wrap a JSObject * setter by constructing our own JSFunction * that saves the
* property id as the function name, and calls js_watch_set.
*/
if (JSID_IS_ATOM(id)) {
atom = JSID_TO_ATOM(id);
} else if (JSID_IS_INT(id)) {
@ -771,6 +763,88 @@ js_WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, PropertyOp setter)
return CastAsPropertyOp(FUN_OBJECT(wrapper));
}
static bool
UpdateWatchpointShape(JSContext *cx, JSWatchPoint *wp, const js::Shape *newShape)
{
JS_ASSERT_IF(wp->shape, wp->shape->id == newShape->id);
JS_ASSERT(!IsWatchedProperty(cx, newShape));
/* Create a watching setter we can substitute for the new shape's setter. */
js::PropertyOp watchingSetter = WrapWatchedSetter(cx, newShape->id, newShape->attributes(),
newShape->setter());
if (!watchingSetter)
return false;
/*
* Save the shape's setter; we don't know whether js_ChangeNativePropertyAttrs will
* return a new shape, or mutate this one.
*/
js::PropertyOp originalSetter = newShape->setter();
/*
* Drop the watching setter into the object, in place of newShape. Note that a single
* watchpoint-wrapped shape may correspond to more than one non-watchpoint shape: we
* wrap all (JSPropertyOp, not JSObject *) setters with js_watch_set, so shapes that
* differ only in their setter may all get wrapped to the same shape.
*/
const js::Shape *watchingShape =
js_ChangeNativePropertyAttrs(cx, wp->object, newShape, 0, newShape->attributes(),
newShape->getter(), watchingSetter);
if (!watchingShape)
return false;
/* Update the watchpoint with the new shape and its original setter. */
wp->setter = originalSetter;
wp->shape = watchingShape;
return true;
}
bool
js_SlowPathUpdateWatchpointsForShape(JSContext *cx, JSObject *obj, const js::Shape *newShape)
{
/*
* The watchpoint code uses the normal property-modification functions to install its
* own watchpoint-aware shapes. Those functions report those changes back to the
* watchpoint code, just as they do user-level changes. So if this change is
* installing a watchpoint-aware shape, it's something we asked for ourselves, and can
* proceed without interference.
*/
if (IsWatchedProperty(cx, newShape))
return true;
JSWatchPoint *wp = FindWatchPoint(cx->runtime, obj, newShape->id);
if (!wp)
return true;
return UpdateWatchpointShape(cx, wp, newShape);
}
/*
* Return the underlying setter for |shape| on |obj|, seeing through any
* watchpoint-wrapping. Note that we need |obj| to disambiguate, since a single
* watchpoint-wrapped shape may correspond to more than one non-watchpoint shape; see the
* comments in UpdateWatchpointShape.
*/
static PropertyOp
UnwrapSetter(JSContext *cx, JSObject *obj, const Shape *shape)
{
/* If it's not a watched property, its setter is not wrapped. */
if (!IsWatchedProperty(cx, shape))
return shape->setter();
/* Look up the watchpoint, from which we can retrieve the underlying setter. */
JSWatchPoint *wp = FindWatchPoint(cx->runtime, obj, shape->id);
/*
* Since we know |shape| is watched, we *must* find a watchpoint: we should never
* leave wrapped setters lying around in shapes after removing a watchpoint.
*/
JS_ASSERT(wp);
return wp->setter;
}
JS_PUBLIC_API(JSBool)
JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsid id,
JSWatchPointHandler handler, JSObject *closure)
@ -779,12 +853,6 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsid id,
Value v;
uintN attrs;
jsid propid;
JSObject *pobj;
JSProperty *prop;
const Shape *shape;
JSRuntime *rt;
JSWatchPoint *wp;
PropertyOp watcher;
origobj = obj;
OBJ_TO_INNER_OBJECT(cx, obj);
@ -814,14 +882,16 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsid id,
return JS_FALSE;
}
JSObject *pobj;
JSProperty *prop;
if (!js_LookupProperty(cx, obj, propid, &pobj, &prop))
return JS_FALSE;
shape = (Shape *) prop;
rt = cx->runtime;
const Shape *shape = (Shape *) prop;
JSRuntime *rt = cx->runtime;
if (!shape) {
/* Check for a deleted symbol watchpoint, which holds its property. */
shape = js_FindWatchPoint(rt, obj, propid);
if (!shape) {
JSWatchPoint *wp = FindWatchPoint(rt, obj, propid);
if (!wp) {
/* Make a new property in obj so we can watch for the first set. */
if (!js_DefineNativeProperty(cx, obj, propid, UndefinedValue(), NULL, NULL,
JSPROP_ENUMERATE, 0, 0, &prop)) {
@ -841,7 +911,7 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsid id,
? pobj->nativeGetSlot(shape->slot)
: UndefinedValue());
getter = shape->getter();
setter = shape->setter();
setter = UnwrapSetter(cx, pobj, shape);
attrs = shape->attributes();
flags = shape->getFlags();
shortid = shape->shortid;
@ -869,33 +939,26 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsid id,
* unlock the object before returning.
*/
DBG_LOCK(rt);
wp = FindWatchPoint(rt, obj, propid);
JSWatchPoint *wp = LockedFindWatchPoint(rt, obj, propid);
if (!wp) {
DBG_UNLOCK(rt);
watcher = js_WrapWatchedSetter(cx, propid, shape->attributes(), shape->setter());
if (!watcher)
return JS_FALSE;
wp = (JSWatchPoint *) cx->malloc(sizeof *wp);
if (!wp)
return JS_FALSE;
wp->handler = NULL;
wp->closure = NULL;
wp->object = obj;
wp->setter = shape->setter();
wp->shape = NULL;
wp->flags = JSWP_LIVE;
/* XXXbe nest in obj lock here */
shape = js_ChangeNativePropertyAttrs(cx, obj, shape, 0, shape->attributes(),
shape->getter(), watcher);
if (!shape) {
if (!UpdateWatchpointShape(cx, wp, shape)) {
/* Self-link so DropWatchPointAndUnlock can JS_REMOVE_LINK it. */
JS_INIT_CLIST(&wp->links);
DBG_LOCK(rt);
DropWatchPointAndUnlock(cx, wp, JSWP_LIVE);
return JS_FALSE;
}
wp->shape = shape;
/*
* Now that wp is fully initialized, append it to rt's wp list.
@ -903,7 +966,7 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsid id,
* a watchpoint for (obj, propid).
*/
DBG_LOCK(rt);
JS_ASSERT(!FindWatchPoint(rt, obj, propid));
JS_ASSERT(!LockedFindWatchPoint(rt, obj, propid));
JS_APPEND_LINK(&wp->links, &rt->watchPointList);
++rt->debuggerMutations;
}
@ -1289,6 +1352,9 @@ JS_GetFrameReturnValue(JSContext *cx, JSStackFrame *fp)
JS_PUBLIC_API(void)
JS_SetFrameReturnValue(JSContext *cx, JSStackFrame *fp, jsval rval)
{
#ifdef JS_METHODJIT
JS_ASSERT_IF(fp->isScriptFrame(), fp->script()->debugMode);
#endif
assertSameCompartment(cx, fp, rval);
fp->setReturnValue(Valueify(rval));
}

View File

@ -142,18 +142,9 @@ js_SweepWatchPoints(JSContext *cx);
#ifdef __cplusplus
extern const js::Shape *
js_FindWatchPoint(JSRuntime *rt, JSObject *obj, jsid id);
extern JSBool
js_watch_set(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
extern JSBool
js_watch_set_wrapper(JSContext *cx, uintN argc, js::Value *vp);
extern js::PropertyOp
js_WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, js::PropertyOp setter);
#endif
#endif /* JS_HAS_OBJ_WATCHPOINT */

68
js/src/jsdbgapiinlines.h Normal file
View File

@ -0,0 +1,68 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=4 sw=4 et tw=78:
*
* ***** 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):
* Jim Blandy <jimb@mozilla.com> (original author)
*
* 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 jsdbgapiinlines_h___
#define jsdbgapiinlines_h___
#include "jsdbgapi.h"
#include "jscntxt.h"
#if defined(JS_HAS_OBJ_WATCHPOINT) && defined(__cplusplus)
extern bool
js_SlowPathUpdateWatchpointsForShape(JSContext *cx, JSObject *obj, const js::Shape *newShape);
/*
* Update any watchpoints on |obj| on |new_shape->id| to use |new_shape|. Property-manipulating
* functions must call this any time it takes on a new shape to represent a potentially
* watched property, or when it mutates a shape's attributes/setter/getter.
*/
static inline bool
js_UpdateWatchpointsForShape(JSContext *cx, JSObject *obj, const js::Shape *newShape)
{
if (JS_CLIST_IS_EMPTY(&cx->runtime->watchPointList))
return true;
return js_SlowPathUpdateWatchpointsForShape(cx, obj, newShape);
}
#endif /* JS_HAS_OBJ_WATCHPOINT && __cplusplus */
#endif /* jsdbgapiinlines_h__ */

View File

@ -1322,10 +1322,10 @@ JSTreeContext::ensureSharpSlots()
if (!sharpArrayAtom || !sharpDepthAtom)
return false;
sharpSlotBase = fun->u.i.nvars;
if (!fun->addLocal(cx, sharpArrayAtom, JSLOCAL_VAR))
sharpSlotBase = fun()->u.i.nvars;
if (!fun()->addLocal(cx, sharpArrayAtom, JSLOCAL_VAR))
return false;
if (!fun->addLocal(cx, sharpDepthAtom, JSLOCAL_VAR))
if (!fun()->addLocal(cx, sharpDepthAtom, JSLOCAL_VAR))
return false;
} else {
/*
@ -1529,8 +1529,7 @@ EmitKnownBlockChain(JSContext *cx, JSCodeGenerator *cg, JSObjectBox *box)
{
if (box)
return EmitIndexOp(cx, JSOP_BLOCKCHAIN, box->index, cg);
else
return js_Emit1(cx, cg, JSOP_NULLBLOCKCHAIN) >= 0;
return js_Emit1(cx, cg, JSOP_NULLBLOCKCHAIN) >= 0;
}
static JSBool
@ -1707,11 +1706,11 @@ LookupCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom,
* nor can prop be deleted.
*/
if (cg->inFunction()) {
if (cg->fun->lookupLocal(cx, atom, NULL) != JSLOCAL_NONE)
if (cg->fun()->lookupLocal(cx, atom, NULL) != JSLOCAL_NONE)
break;
} else {
JS_ASSERT(cg->compileAndGo());
obj = cg->scopeChain;
obj = cg->scopeChain();
const Shape *shape = obj->nativeLookup(ATOM_TO_JSID(atom));
if (shape) {
@ -1884,7 +1883,7 @@ AdjustBlockSlot(JSContext *cx, JSCodeGenerator *cg, jsint slot)
{
JS_ASSERT((jsuint) slot < cg->maxStackDepth);
if (cg->inFunction()) {
slot += cg->fun->u.i.nvars;
slot += cg->fun()->u.i.nvars;
if ((uintN) slot >= SLOTNO_LIMIT) {
ReportCompileErrorNumber(cx, CG_TS(cg), NULL, JSREPORT_ERROR, JSMSG_TOO_MANY_LOCALS);
slot = -1;
@ -2012,7 +2011,7 @@ MakeUpvarForEval(JSParseNode *pn, JSCodeGenerator *cg)
JSAtomListElement *ale = cg->upvarList.lookup(atom);
if (!ale) {
if (cg->inFunction() && !cg->fun->addLocal(cx, atom, JSLOCAL_UPVAR))
if (cg->inFunction() && !cg->fun()->addLocal(cx, atom, JSLOCAL_UPVAR))
return false;
ale = cg->upvarList.add(cg->parser, atom);
@ -2214,8 +2213,8 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
* as their parent by Parser::newFunction.
*/
JSObject *scopeobj = cg->inFunction()
? FUN_OBJECT(cg->fun)->getParent()
: cg->scopeChain;
? FUN_OBJECT(cg->fun())->getParent()
: cg->scopeChain();
if (scopeobj != cg->parser->callerVarObj)
return JS_TRUE;
@ -2257,6 +2256,13 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
}
if (dn->pn_dflags & PND_GVAR) {
/*
* JSOP_DEFFUN could introduce a shadowing definition, so if it
* is present, we can't optimize to JSOP_GETGLOBAL.
*/
if (cg->hasDefFun())
return JS_TRUE;
switch (op) {
case JSOP_NAME: op = JSOP_GETGLOBAL; break;
case JSOP_SETNAME: op = JSOP_SETGLOBAL; break;
@ -2317,7 +2323,8 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
JSCodeGenerator *evalcg = (JSCodeGenerator *) tc;
JS_ASSERT(evalcg->compileAndGo());
JS_ASSERT(caller->isFunctionFrame() && cg->parser->callerVarObj == evalcg->scopeChain);
JS_ASSERT(caller->isFunctionFrame());
JS_ASSERT(cg->parser->callerVarObj == evalcg->scopeChain());
/*
* Don't generate upvars on the left side of a for loop. See
@ -2341,7 +2348,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
JS_ASSERT(cg->inFunction());
JS_ASSERT_IF(cookie.slot() != UpvarCookie::CALLEE_SLOT, cg->lexdeps.lookup(atom));
JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
JS_ASSERT(cg->fun->u.i.skipmin <= skip);
JS_ASSERT(cg->fun()->u.i.skipmin <= skip);
/*
* If op is a mutating opcode, this upvar's lookup skips too many levels,
@ -2354,7 +2361,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
if (cg->flags & TCF_FUN_HEAVYWEIGHT)
return JS_TRUE;
if (FUN_FLAT_CLOSURE(cg->fun)) {
if (cg->fun()->isFlatClosure()) {
op = JSOP_GETFCSLOT;
} else {
/*
@ -2382,7 +2389,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
if (ale) {
index = ALE_INDEX(ale);
} else {
if (!cg->fun->addLocal(cx, atom, JSLOCAL_UPVAR))
if (!cg->fun()->addLocal(cx, atom, JSLOCAL_UPVAR))
return JS_FALSE;
ale = cg->upvarList.add(cg->parser, atom);
@ -2411,7 +2418,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
tc = tc->parent;
} while (tc->staticLevel != level);
if (tc->inFunction())
slot += tc->fun->nargs;
slot += tc->fun()->nargs;
}
vector[index].set(skip, slot);
@ -2463,11 +2470,11 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
case JSDefinition::VAR:
if (PN_OP(dn) == JSOP_CALLEE) {
JS_ASSERT(op != JSOP_CALLEE);
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
* cannot be sure cg->fun is not something of the form:
* Leave pn->pn_op == JSOP_NAME if cg->fun() is heavyweight, as we
* cannot be sure cg->fun() is not something of the form:
*
* var ff = (function f(s) { eval(s); return f; });
*
@ -2798,7 +2805,7 @@ EmitNameOp(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
if (op == JSOP_ARGUMENTS || op == JSOP_CALLEE) {
if (js_Emit1(cx, cg, op) < 0)
return JS_FALSE;
if (callContext && js_Emit1(cx, cg, JSOP_NULL) < 0)
if (callContext && js_Emit1(cx, cg, JSOP_PUSH) < 0)
return JS_FALSE;
} else {
if (!pn->pn_cookie.isFree()) {
@ -3812,8 +3819,9 @@ MaybeEmitVarDecl(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp,
CG_SWITCH_TO_MAIN(cg);
}
if (JOF_OPTYPE(pn->pn_op) == JOF_LOCAL &&
pn->pn_cookie.slot() < cg->fun->u.i.nvars &&
if (cg->inFunction() &&
JOF_OPTYPE(pn->pn_op) == JOF_LOCAL &&
pn->pn_cookie.slot() < cg->fun()->u.i.nvars &&
cg->shouldNoteClosedName(pn))
{
if (!cg->closedVars.append(pn->pn_cookie.slot()))
@ -4598,7 +4606,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
return JS_FALSE;
}
#endif
cg2->fun = fun;
cg2->setFunction(fun);
cg2->funbox = pn->pn_funbox;
cg2->parent = cg;
@ -4668,7 +4676,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
#ifdef DEBUG
JSLocalKind localKind =
#endif
cg->fun->lookupLocal(cx, fun->atom, &slot);
cg->fun()->lookupLocal(cx, fun->atom, &slot);
JS_ASSERT(localKind == JSLOCAL_VAR || localKind == JSLOCAL_CONST);
JS_ASSERT(index < JS_BIT(20));
pn->pn_index = index;
@ -5097,7 +5105,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
} else
#endif
if (pn3->pn_type == TOK_LP) {
JS_ASSERT(pn3->pn_op == JSOP_SETCALL);
JS_ASSERT(pn3->pn_xflags & PNX_SETCALL);
if (!js_EmitTree(cx, cg, pn3))
return JS_FALSE;
if (js_Emit1(cx, cg, JSOP_ENUMELEM) < 0)
@ -6497,8 +6505,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
if (!useful) {
off = noteIndex = -1;
} else {
if (pn2->pn_op == JSOP_SETCALL)
pn2->pn_op = JSOP_CALL;
JS_ASSERT_IF(pn2->pn_type == TOK_LP, !(pn2->pn_xflags & PNX_SETCALL));
if (!js_EmitTree(cx, cg, pn2))
return JS_FALSE;
off = CG_OFFSET(cg);
@ -6640,6 +6647,10 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
if (EmitBlockChain(cx, cg) < 0)
return JS_FALSE;
}
if (pn->pn_xflags & PNX_SETCALL) {
if (js_Emit1(cx, cg, JSOP_SETCALL) < 0)
return JS_FALSE;
}
break;
}
@ -6991,7 +7002,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
* and lastIndex sharing, select JSOP_REGEXP.
*/
JS_ASSERT(pn->pn_op == JSOP_REGEXP);
bool singleton = !cg->fun && cg->compileAndGo();
bool singleton = !(cg->inFunction() ? cg->fun() : cg->scopeChain()) && cg->compileAndGo();
if (singleton) {
for (JSStmtInfo *stmt = cg->topStmt; stmt; stmt = stmt->down) {
if (STMT_IS_LOOP(stmt)) {

View File

@ -251,6 +251,11 @@ struct JSStmtInfo {
*/
#define TCF_COMPILE_FOR_EVAL 0x2000000
/*
* The function contains a JSOP_DEFFUN bytecode.
*/
#define TCF_FUN_HAS_DEFFUN 0x4000000
/*
* Flags to check for return; vs. return expr; in a function.
*/
@ -267,6 +272,7 @@ struct JSStmtInfo {
TCF_FUN_USES_OWN_NAME | \
TCF_HAS_SHARPS | \
TCF_FUN_CALLS_EVAL | \
TCF_FUN_HAS_DEFFUN | \
TCF_FUN_MUTATES_PARAMETER | \
TCF_STRICT_MODE_CODE)
@ -284,12 +290,31 @@ struct JSTreeContext { /* tree context for semantic checks */
JSAtomList decls; /* function, const, and var declarations */
js::Parser *parser; /* ptr to common parsing and lexing data */
private:
union {
JSFunction *fun; /* function to store argument and variable
JSFunction *fun_; /* function to store argument and variable
names when flags & TCF_IN_FUNCTION */
JSObject *scopeChain; /* scope chain object for the script */
JSObject *scopeChain_; /* scope chain object for the script */
};
public:
JSFunction *fun() const {
JS_ASSERT(inFunction());
return fun_;
}
void setFunction(JSFunction *fun) {
JS_ASSERT(inFunction());
fun_ = fun;
}
JSObject *scopeChain() const {
JS_ASSERT(!inFunction());
return scopeChain_;
}
void setScopeChain(JSObject *scopeChain) {
JS_ASSERT(!inFunction());
scopeChain_ = scopeChain;
}
JSAtomList lexdeps; /* unresolved lexical name dependencies */
JSTreeContext *parent; /* enclosing function or global context */
uintN staticLevel; /* static compilation unit nesting level */
@ -309,7 +334,7 @@ struct JSTreeContext { /* tree context for semantic checks */
JSTreeContext(js::Parser *prs)
: flags(0), bodyid(0), blockidGen(0),
topStmt(NULL), topScopeStmt(NULL), blockChainBox(NULL), blockNode(NULL),
parser(prs), scopeChain(NULL), parent(prs->tc), staticLevel(0),
parser(prs), scopeChain_(NULL), parent(prs->tc), staticLevel(0),
funbox(NULL), functionList(NULL), innermostWith(NULL), sharpSlotBase(-1)
{
prs->tc = this;
@ -378,6 +403,14 @@ struct JSTreeContext { /* tree context for semantic checks */
return flags & TCF_FUN_CALLS_EVAL;
}
void noteHasDefFun() {
flags |= TCF_FUN_HAS_DEFFUN;
}
bool hasDefFun() const {
return flags & TCF_FUN_HAS_DEFFUN;
}
void noteParameterMutation() {
JS_ASSERT(inFunction());
flags |= TCF_FUN_MUTATES_PARAMETER;

View File

@ -61,6 +61,7 @@
#include "jsscope.h"
#include "jsscript.h"
#include "jsstaticcheck.h"
#include "jswrapper.h"
#include "jscntxtinlines.h"
#include "jsinterpinlines.h"
@ -259,15 +260,6 @@ GetStackTraceValueBuffer(JSExnPrivate *priv)
return (jsval *)(priv->stackElems + priv->stackDepth);
}
struct CopyTo
{
Value *dst;
CopyTo(jsval *dst) : dst(Valueify(dst)) {}
void operator()(uintN, Value *src) {
*dst++ = *src;
}
};
static JSBool
InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
JSString *filename, uintN lineno, JSErrorReport *report)
@ -353,7 +345,7 @@ InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
? ATOM_TO_STRING(fp->fun()->atom)
: cx->runtime->emptyString;
elem->argc = fp->numActualArgs();
fp->forEachCanonicalActualArg(CopyTo(values));
fp->forEachCanonicalActualArg(CopyTo(Valueify(values)));
values += elem->argc;
}
elem->ulineno = 0;
@ -545,9 +537,14 @@ ValueToShortSource(JSContext *cx, jsval v)
JSString *str;
/* Avoid toSource bloat and fallibility for object types. */
if (JSVAL_IS_PRIMITIVE(v)) {
str = js_ValueToSource(cx, Valueify(v));
} else if (VALUE_IS_FUNCTION(cx, v)) {
if (JSVAL_IS_PRIMITIVE(v))
return js_ValueToSource(cx, Valueify(v));
AutoCompartment ac(cx, JSVAL_TO_OBJECT(v));
if (!ac.enter())
return NULL;
if (VALUE_IS_FUNCTION(cx, v)) {
/*
* XXX Avoid function decompilation bloat for now.
*/
@ -570,6 +567,11 @@ ValueToShortSource(JSContext *cx, jsval v)
JSVAL_TO_OBJECT(v)->getClass()->name);
str = JS_NewStringCopyZ(cx, buf);
}
ac.leave();
if (!str || !cx->compartment->wrap(cx, &str))
return NULL;
return str;
}
@ -696,12 +698,6 @@ FilenameToString(JSContext *cx, const char *filename)
return JS_NewStringCopyZ(cx, filename);
}
static const char *
StringToFilename(JSContext *cx, JSString *str)
{
return js_GetStringBytes(cx, str);
}
static JSBool
Exception(JSContext *cx, uintN argc, Value *vp)
{
@ -1038,8 +1034,9 @@ js_InitExceptionClasses(JSContext *cx, JSObject *obj)
/* Make a constructor function for the current name. */
JSProtoKey protoKey = GetExceptionProtoKey(i);
JSAtom *atom = cx->runtime->atomState.classAtoms[protoKey];
JSFunction *fun = js_DefineFunction(cx, obj, atom, Exception, 3, JSFUN_CONSTRUCTOR);
jsid id = ATOM_TO_JSID(cx->runtime->atomState.classAtoms[protoKey]);
JSFunction *fun = js_DefineFunction(cx, obj, id, Exception, 3, JSFUN_CONSTRUCTOR);
if (!fun)
return NULL;
roots[2] = OBJECT_TO_JSVAL(FUN_OBJECT(fun));
@ -1054,8 +1051,7 @@ js_InitExceptionClasses(JSContext *cx, JSObject *obj)
}
/* Add the name property to the prototype. */
if (!JS_DefineProperty(cx, proto, js_name_str,
STRING_TO_JSVAL(ATOM_TO_STRING(atom)),
if (!JS_DefineProperty(cx, proto, js_name_str, STRING_TO_JSVAL(JSID_TO_STRING(id)),
NULL, NULL, JSPROP_ENUMERATE)) {
return NULL;
}
@ -1245,44 +1241,42 @@ js_ReportUncaughtException(JSContext *cx)
/* XXX L10N angels cry once again (see also jsemit.c, /L10N gaffes/) */
str = js_ValueToString(cx, Valueify(exn));
JSAutoByteString bytesStorage;
if (!str) {
bytes = "unknown (can't convert to string)";
} else {
roots[1] = STRING_TO_JSVAL(str);
bytes = js_GetStringBytes(cx, str);
if (!bytes)
if (!bytesStorage.encode(cx, str))
return false;
bytes = bytesStorage.ptr();
}
JSAutoByteString filename;
if (!reportp && exnObject && exnObject->getClass() == &js_ErrorClass) {
const char *filename;
if (!JS_GetProperty(cx, exnObject, js_message_str, &roots[2]))
return false;
if (JSVAL_IS_STRING(roots[2])) {
bytes = js_GetStringBytes(cx, JSVAL_TO_STRING(roots[2]));
if (!bytes)
bytesStorage.clear();
if (!bytesStorage.encode(cx, str))
return false;
bytes = bytesStorage.ptr();
}
if (!JS_GetProperty(cx, exnObject, js_fileName_str, &roots[3]))
return false;
str = js_ValueToString(cx, Valueify(roots[3]));
if (!str)
return false;
filename = StringToFilename(cx, str);
if (!filename)
if (!str || !filename.encode(cx, str))
return false;
if (!JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[4]))
return false;
uint32_t lineno;
if (!ValueToECMAUint32 (cx, Valueify(roots[4]), &lineno))
if (!ValueToECMAUint32(cx, Valueify(roots[4]), &lineno))
return false;
reportp = &report;
PodZero(&report);
report.filename = filename;
report.filename = filename.ptr();
report.lineno = (uintN) lineno;
if (JSVAL_IS_STRING(roots[2])) {
report.ucmessage = js_GetStringChars(cx, JSVAL_TO_STRING(roots[2]));

View File

@ -1808,15 +1808,17 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
if (xdr->mode == JSXDR_ENCODE) {
fun = GET_FUNCTION_PRIVATE(cx, *objp);
if (!FUN_INTERPRETED(fun)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_NOT_SCRIPTED_FUNCTION,
JS_GetFunctionName(fun));
JSAutoByteString funNameBytes;
if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_SCRIPTED_FUNCTION,
name);
}
return false;
}
if (fun->u.i.wrapper) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_XDR_CLOSURE_WRAPPER,
JS_GetFunctionName(fun));
JSAutoByteString funNameBytes;
if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes))
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_XDR_CLOSURE_WRAPPER, name);
return false;
}
JS_ASSERT((fun->u.i.wrapper & ~1U) == 0);
@ -2190,13 +2192,12 @@ js_fun_call(JSContext *cx, uintN argc, Value *vp)
if (!js_IsCallable(fval)) {
JSString *str = js_ValueToString(cx, fval);
if (str) {
const char *bytes = js_GetStringBytes(cx, str);
if (bytes) {
JSAutoByteString bytes(cx, str);
if (!!bytes) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_PROTO,
js_Function_str, js_call_str,
bytes);
bytes.ptr());
}
}
return JS_FALSE;
@ -2228,20 +2229,6 @@ js_fun_call(JSContext *cx, uintN argc, Value *vp)
return ok;
}
struct STATIC_SKIP_INFERENCE CopyNonHoleArgs
{
CopyNonHoleArgs(JSObject *aobj, Value *dst) : aobj(aobj), dst(dst) {}
JSObject *aobj;
Value *dst;
void operator()(uintN argi, Value *src) {
if (aobj->getArgsElement(argi).isMagic(JS_ARGS_HOLE))
dst->setUndefined();
else
*dst = *src;
++dst;
}
};
/* ES5 15.3.4.3 */
JSBool
js_fun_apply(JSContext *cx, uintN argc, Value *vp)
@ -2254,11 +2241,12 @@ js_fun_apply(JSContext *cx, uintN argc, Value *vp)
Value fval = vp[1];
if (!js_IsCallable(fval)) {
if (JSString *str = js_ValueToString(cx, fval)) {
if (const char *bytes = js_GetStringBytes(cx, str)) {
JSAutoByteString bytes(cx, str);
if (!!bytes) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_PROTO,
js_Function_str, js_apply_str,
bytes);
bytes.ptr());
}
}
return false;
@ -2268,6 +2256,8 @@ js_fun_apply(JSContext *cx, uintN argc, Value *vp)
if (argc < 2 || vp[3].isNullOrUndefined())
return js_fun_call(cx, (argc > 0) ? 1 : 0, vp);
/* N.B. Changes need to be propagated to stubs::SplatApplyArgs. */
/* Step 3. */
if (!vp[3].isObject()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_APPLY_ARGS, js_apply_str);
@ -2280,23 +2270,8 @@ js_fun_apply(JSContext *cx, uintN argc, Value *vp)
*/
JSObject *aobj = &vp[3].toObject();
jsuint length;
if (aobj->isArray()) {
length = aobj->getArrayLength();
} else if (aobj->isArguments() && !aobj->isArgsLengthOverridden()) {
length = aobj->getArgsInitialLength();
} else {
Value &lenval = vp[0];
if (!aobj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), &lenval))
return false;
if (lenval.isInt32()) {
length = jsuint(lenval.toInt32()); /* jsuint cast does ToUint32 */
} else {
JS_STATIC_ASSERT(sizeof(jsuint) == sizeof(uint32_t));
if (!ValueToECMAUint32(cx, lenval, (uint32_t *)&length))
return false;
}
}
if (!js_GetLengthProperty(cx, aobj, &length))
return false;
LeaveTrace(cx);
@ -2312,32 +2287,8 @@ js_fun_apply(JSContext *cx, uintN argc, Value *vp)
args.thisv() = vp[2];
/* Steps 7-8. */
if (aobj && aobj->isArguments() && !aobj->isArgsLengthOverridden()) {
/*
* Two cases, two loops: note how in the case of an active stack frame
* backing aobj, even though we copy from fp->argv, we still must check
* aobj->getArgsElement(i) for a hole, to handle a delete on the
* corresponding arguments element. See args_delProperty.
*/
JSStackFrame *fp = (JSStackFrame *) aobj->getPrivate();
Value *argv = args.argv();
if (fp) {
JS_ASSERT(fp->numActualArgs() <= JS_ARGS_LENGTH_MAX);
fp->forEachCanonicalActualArg(CopyNonHoleArgs(aobj, argv));
} else {
for (uintN i = 0; i < n; i++) {
argv[i] = aobj->getArgsElement(i);
if (argv[i].isMagic(JS_ARGS_HOLE))
argv[i].setUndefined();
}
}
} else {
Value *argv = args.argv();
for (uintN i = 0; i < n; i++) {
if (!aobj->getProperty(cx, INT_TO_JSID(jsint(i)), &argv[i]))
return JS_FALSE;
}
}
if (!GetElements(cx, aobj, n, args.argv()))
return false;
/* Step 9. */
if (!Invoke(cx, args, 0))
@ -2467,10 +2418,11 @@ fun_bind(JSContext *cx, uintN argc, Value *vp)
/* Step 2. */
if (!target->isCallable()) {
if (JSString *str = js_ValueToString(cx, vp[1])) {
if (const char *bytes = js_GetStringBytes(cx, str)) {
JSAutoByteString bytes(cx, str);
if (!!bytes) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_PROTO,
js_Function_str, "bind", bytes);
js_Function_str, "bind", bytes.ptr());
}
}
return false;
@ -2689,12 +2641,14 @@ Function(JSContext *cx, uintN argc, Value *vp)
/* Check for a duplicate parameter name. */
if (fun->lookupLocal(cx, atom, NULL) != JSLOCAL_NONE) {
const char *name;
name = js_AtomToPrintableString(cx, atom);
if (!name && ReportCompileErrorNumber(cx, &ts, NULL,
JSREPORT_WARNING | JSREPORT_STRICT,
JSMSG_DUPLICATE_FORMAL, name)) {
JSAutoByteString name;
if (!js_AtomToPrintableString(cx, atom, &name)) {
state = BAD;
goto after_args;
}
if (!ReportCompileErrorNumber(cx, &ts, NULL,
JSREPORT_WARNING | JSREPORT_STRICT,
JSMSG_DUPLICATE_FORMAL, name.ptr())) {
goto after_args;
}
}
@ -2959,7 +2913,7 @@ js_NewDebuggableFlatClosure(JSContext *cx, JSFunction *fun)
}
JSFunction *
js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, Native native,
js_DefineFunction(JSContext *cx, JSObject *obj, jsid id, Native native,
uintN nargs, uintN attrs)
{
PropertyOp gsop;
@ -2977,15 +2931,61 @@ js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, Native native,
} else {
gsop = NULL;
}
/*
* Historically, all objects have had a parent member as intrinsic scope
* chain link. We want to move away from this universal parent, but JS
* requires that function objects have something like parent (ES3 and ES5
* call it the [[Scope]] internal property), to bake a particular static
* scope environment into each function object.
*
* All function objects thus have parent, including all native functions.
* All native functions defined by the JS_DefineFunction* APIs are created
* via the call below to js_NewFunction, which passes obj as the parent
* parameter, and so binds fun's parent to obj using JSObject::setParent,
* under js_NewFunction (in JSObject::init, called from NewObject -- see
* jsobjinlines.h).
*
* But JSObject::setParent sets the DELEGATE object flag on its receiver,
* to mark the object as a proto or parent of another object. Such objects
* may intervene in property lookups and scope chain searches, so require
* special handling when caching lookup and search results (since such
* intervening objects can in general grow shadowing properties later).
*
* Thus using setParent prematurely flags certain objects, notably class
* prototypes, so that defining native methods on them, where the method's
* name (e.g., toString) is already bound on Object.prototype, triggers
* shadowingShapeChange events and gratuitous shape regeneration.
*
* To fix this longstanding bug, we set check whether obj is already a
* delegate, and if not, then if js_NewFunction flagged obj as a delegate,
* we clear the flag.
*
* We thus rely on the fact that native functions (including indirect eval)
* do not use the property cache or equivalent JIT techniques that require
* this bit to be set on their parent-linked scope chain objects.
*
* Note: we keep API compatibility by setting parent to obj for all native
* function objects, even if obj->getGlobal() would suffice. This should be
* revisited when parent is narrowed to exist only for function objects and
* possibly a few prehistoric scope objects (e.g. event targets).
*
* FIXME: bug 611190.
*/
bool wasDelegate = obj->isDelegate();
fun = js_NewFunction(cx, NULL, native, nargs,
attrs & (JSFUN_FLAGS_MASK | JSFUN_TRCINFO),
obj, atom);
obj,
JSID_IS_ATOM(id) ? JSID_TO_ATOM(id) : NULL);
if (!fun)
return NULL;
if (!obj->defineProperty(cx, ATOM_TO_JSID(atom), ObjectValue(*fun),
gsop, gsop, attrs & ~JSFUN_FLAGS_MASK)) {
if (!wasDelegate && obj->isDelegate())
obj->clearDelegate();
if (!obj->defineProperty(cx, id, ObjectValue(*fun), gsop, gsop, attrs & ~JSFUN_FLAGS_MASK))
return NULL;
}
return fun;
}

View File

@ -151,6 +151,7 @@ struct JSFunction : public JSObject_Slots2
JSNativeTraceInfo *trcinfo;
} n;
struct Scripted {
JSScript *script; /* interpreted bytecode descriptor or null */
uint16 nvars; /* number of local variables */
uint16 nupvars; /* number of upvars (computable from script
but here for faster access) */
@ -163,9 +164,9 @@ struct JSFunction : public JSObject_Slots2
then escaped via the debugger or a rogue
indirect eval; if true, then this function
object's proto is the wrapped object */
JSScript *script; /* interpreted bytecode descriptor or null */
js::Shape *names; /* argument and variable names */
} i;
void *nativeOrScript;
} u;
JSAtom *atom; /* name for diagnostics and decompiling */
@ -175,6 +176,7 @@ struct JSFunction : public JSObject_Slots2
bool isNative() const { return !FUN_INTERPRETED(this); }
bool isConstructor() const { return flags & JSFUN_CONSTRUCTOR; }
bool isHeavyweight() const { return JSFUN_HEAVYWEIGHT_TEST(flags); }
bool isFlatClosure() const { return FUN_KIND(this) == JSFUN_FLAT_CLOSURE; }
bool isFunctionPrototype() const { return flags & JSFUN_PROTOTYPE; }
@ -308,6 +310,12 @@ struct JSFunction : public JSObject_Slots2
return u.i.script;
}
static uintN offsetOfNativeOrScript() {
JS_STATIC_ASSERT(offsetof(U, n.native) == offsetof(U, i.script));
JS_STATIC_ASSERT(offsetof(U, n.native) == offsetof(U, nativeOrScript));
return offsetof(JSFunction, u.nativeOrScript);
}
/* Number of extra fixed function object slots. */
static const uint32 CLASS_RESERVED_SLOTS = JSObject::FUN_CLASS_RESERVED_SLOTS;
};
@ -482,6 +490,14 @@ IsConstructing_PossiblyWithGivenThisObject(const Value *vp, JSObject **ctorThis)
return isCtor;
}
inline const char *
GetFunctionNameBytes(JSContext *cx, JSFunction *fun, JSAutoByteString *bytes)
{
if (fun->atom)
return bytes->encode(cx, ATOM_TO_STRING(fun->atom));
return js_anonymous_str;
}
} /* namespace js */
extern JSString *
@ -527,7 +543,7 @@ extern JS_REQUIRES_STACK JSObject *
js_NewDebuggableFlatClosure(JSContext *cx, JSFunction *fun);
extern JSFunction *
js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, js::Native native,
js_DefineFunction(JSContext *cx, JSObject *obj, jsid id, js::Native native,
uintN nargs, uintN flags);
/*

View File

@ -117,31 +117,26 @@ JS_STATIC_ASSERT(JSTRACE_XML == 2);
*/
JS_STATIC_ASSERT(JSTRACE_STRING + 1 == JSTRACE_XML);
/*
* Check consistency of external string constants from JSFinalizeGCThingKind.
*/
JS_STATIC_ASSERT(FINALIZE_EXTERNAL_STRING_LAST - FINALIZE_EXTERNAL_STRING0 ==
JS_EXTERNAL_STRING_LIMIT - 1);
/*
* Everything we store in the heap must be a multiple of the cell size.
*/
JS_STATIC_ASSERT(sizeof(JSString) % sizeof(FreeCell) == 0);
JS_STATIC_ASSERT(sizeof(JSShortString) % sizeof(FreeCell) == 0);
JS_STATIC_ASSERT(sizeof(JSObject) % sizeof(FreeCell) == 0);
JS_STATIC_ASSERT(sizeof(JSFunction) % sizeof(FreeCell) == 0);
JS_STATIC_ASSERT(sizeof(JSString) % sizeof(FreeCell) == 0);
JS_STATIC_ASSERT(sizeof(JSShortString) % sizeof(FreeCell) == 0);
JS_STATIC_ASSERT(sizeof(JSObject) % sizeof(FreeCell) == 0);
JS_STATIC_ASSERT(sizeof(JSFunction) % sizeof(FreeCell) == 0);
#ifdef JSXML
JS_STATIC_ASSERT(sizeof(JSXML) % sizeof(FreeCell) == 0);
JS_STATIC_ASSERT(sizeof(JSXML) % sizeof(FreeCell) == 0);
#endif
/*
* All arenas must be exactly 4k.
*/
JS_STATIC_ASSERT(sizeof(Arena<JSString>) == 4096);
JS_STATIC_ASSERT(sizeof(Arena<JSShortString>) == 4096);
JS_STATIC_ASSERT(sizeof(Arena<JSObject>) == 4096);
JS_STATIC_ASSERT(sizeof(Arena<JSFunction>) == 4096);
JS_STATIC_ASSERT(sizeof(Arena<JSXML>) == 4096);
JS_STATIC_ASSERT(sizeof(Arena<JSString>) == 4096);
JS_STATIC_ASSERT(sizeof(Arena<JSExternalString>) == 4096);
JS_STATIC_ASSERT(sizeof(Arena<JSShortString>) == 4096);
JS_STATIC_ASSERT(sizeof(Arena<JSObject>) == 4096);
JS_STATIC_ASSERT(sizeof(Arena<JSFunction>) == 4096);
JS_STATIC_ASSERT(sizeof(Arena<JSXML>) == 4096);
#ifdef JS_GCMETER
# define METER(x) ((void) (x))
@ -219,19 +214,21 @@ Arena<T>::mark(T *thing, JSTracer *trc)
{
JS_ASSERT(sizeof(T) == aheader.thingSize);
thing = getAlignedThing(thing);
T *alignedThing = getAlignedThing(thing);
if (thing > &t.things[ThingsPerArena-1].t || thing < &t.things[0].t)
if (alignedThing > &t.things[ThingsPerArena-1].t || alignedThing < &t.things[0].t)
return CGCT_NOTARENA;
if (!aheader.isUsed || inFreeList(thing))
if (!aheader.isUsed || inFreeList(alignedThing))
return CGCT_NOTLIVE;
JS_ASSERT(assureThingIsAligned(thing));
JS_SET_TRACING_NAME(trc, "machine stack");
Mark(trc, thing);
Mark(trc, alignedThing);
#ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS
if (alignedThing != thing)
return CGCT_VALIDWITHOFFSET;
#endif
return CGCT_VALID;
}
@ -248,13 +245,12 @@ checkArenaListsForThing(JSCompartment *comp, void *thing) {
#if JS_HAS_XML_SUPPORT
comp->arenas[FINALIZE_XML].arenasContainThing<JSXML>(thing) ||
#endif
comp->arenas[FINALIZE_STRING].arenasContainThing<JSString>(thing) ||
comp->arenas[FINALIZE_EXTERNAL_STRING].arenasContainThing<JSExternalString>(thing) ||
comp->arenas[FINALIZE_SHORT_STRING].arenasContainThing<JSShortString>(thing)) {
return true;
}
for (unsigned i = FINALIZE_STRING; i <= FINALIZE_EXTERNAL_STRING_LAST; i++) {
if (comp->arenas[i].arenasContainThing<JSString>(thing))
return true;
}
return false;
}
#endif
@ -557,11 +553,12 @@ MarkCell(Cell *cell, JSTracer *trc)
}
/*
* Returns CGCT_VALID and mark it if the w can be a live GC thing and sets traceKind
* accordingly. Otherwise returns the reason for rejection.
* Returns CGCT_VALID or CGCT_VALIDWITHOFFSET and mark it if the w can be a
* live GC thing and sets thingKind accordingly. Otherwise returns the
* reason for rejection.
*/
inline ConservativeGCTest
MarkIfGCThingWord(JSTracer *trc, jsuword w, uint32 &traceKind)
MarkIfGCThingWord(JSTracer *trc, jsuword w, uint32 &thingKind)
{
JSRuntime *rt = trc->context->runtime;
/*
@ -611,9 +608,9 @@ MarkIfGCThingWord(JSTracer *trc, jsuword w, uint32 &traceKind)
return CGCT_FREEARENA;
ConservativeGCTest test;
traceKind = aheader->thingKind;
thingKind = aheader->thingKind;
switch (traceKind) {
switch (thingKind) {
case FINALIZE_OBJECT0:
test = MarkCell<JSObject>(cell, trc);
break;
@ -633,16 +630,11 @@ MarkIfGCThingWord(JSTracer *trc, jsuword w, uint32 &traceKind)
test = MarkCell<JSObject_Slots16>(cell, trc);
break;
case FINALIZE_STRING:
case FINALIZE_EXTERNAL_STRING0:
case FINALIZE_EXTERNAL_STRING1:
case FINALIZE_EXTERNAL_STRING2:
case FINALIZE_EXTERNAL_STRING3:
case FINALIZE_EXTERNAL_STRING4:
case FINALIZE_EXTERNAL_STRING5:
case FINALIZE_EXTERNAL_STRING6:
case FINALIZE_EXTERNAL_STRING7:
test = MarkCell<JSString>(cell, trc);
break;
case FINALIZE_EXTERNAL_STRING:
test = MarkCell<JSExternalString>(cell, trc);
break;
case FINALIZE_SHORT_STRING:
test = MarkCell<JSShortString>(cell, trc);
break;
@ -665,8 +657,8 @@ MarkIfGCThingWord(JSTracer *trc, jsuword w, uint32 &traceKind)
inline ConservativeGCTest
MarkIfGCThingWord(JSTracer *trc, jsuword w)
{
uint32 traceKind;
return MarkIfGCThingWord(trc, w, traceKind);
uint32 thingKind;
return MarkIfGCThingWord(trc, w, thingKind);
}
static void
@ -682,16 +674,25 @@ MarkWordConservatively(JSTracer *trc, jsuword w)
VALGRIND_MAKE_MEM_DEFINED(&w, sizeof(w));
#endif
uint32 traceKind;
uint32 thingKind;
#if defined JS_DUMP_CONSERVATIVE_GC_ROOTS || defined JS_GCMETER
ConservativeGCTest test =
#endif
MarkIfGCThingWord(trc, w, traceKind);
MarkIfGCThingWord(trc, w, thingKind);
#ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS
if (test == CGCT_VALID) {
if (test == CGCT_VALID || test == CGCT_VALIDWITHOFFSET) {
if (IS_GC_MARKING_TRACER(trc) && static_cast<GCMarker *>(trc)->conservativeDumpFileName) {
GCMarker::ConservativeRoot root = {(void *)w, traceKind};
const jsuword JSID_PAYLOAD_MASK = ~jsuword(JSID_TYPE_MASK);
#if JS_BITS_PER_WORD == 32
jsuword payload = w & JSID_PAYLOAD_MASK;
#elif JS_BITS_PER_WORD == 64
jsuword payload = w & JSID_PAYLOAD_MASK & JSVAL_PAYLOAD_MASK;
#endif
void *thing = (test == CGCT_VALIDWITHOFFSET)
? GetAlignedThing((void *)payload, thingKind)
: (void *)payload;
GCMarker::ConservativeRoot root = {thing, thingKind};
static_cast<GCMarker *>(trc)->conservativeRoots.append(root);
}
}
@ -704,10 +705,10 @@ MarkWordConservatively(JSTracer *trc, jsuword w)
}
static void
MarkRangeConservatively(JSTracer *trc, jsuword *begin, jsuword *end)
MarkRangeConservatively(JSTracer *trc, const jsuword *begin, const jsuword *end)
{
JS_ASSERT(begin <= end);
for (jsuword *i = begin; i != end; ++i)
for (const jsuword *i = begin; i != end; ++i)
MarkWordConservatively(trc, *i);
}
@ -734,15 +735,15 @@ MarkThreadDataConservatively(JSTracer *trc, JSThreadData *td)
void
MarkStackRangeConservatively(JSTracer *trc, Value *beginv, Value *endv)
{
jsuword *begin = (jsuword *) beginv;
jsuword *end = (jsuword *) endv;
const jsuword *begin = beginv->payloadWord();
const jsuword *end = endv->payloadWord();;
#ifdef JS_NUNBOX32
/*
* With 64-bit jsvals on 32-bit systems, we can optimize a bit by
* scanning only the payloads.
*/
JS_ASSERT(begin <= end);
for (jsuword *i = begin; i != end; i += 2)
for (const jsuword *i = begin; i != end; i += sizeof(Value)/sizeof(jsuword))
MarkWordConservatively(trc, *i);
#else
MarkRangeConservatively(trc, begin, end);
@ -1139,15 +1140,9 @@ RefillFinalizableFreeList(JSContext *cx, unsigned thingKind)
case FINALIZE_OBJECT16:
return RefillTypedFreeList<JSObject_Slots16>(cx, thingKind);
case FINALIZE_STRING:
case FINALIZE_EXTERNAL_STRING0:
case FINALIZE_EXTERNAL_STRING1:
case FINALIZE_EXTERNAL_STRING2:
case FINALIZE_EXTERNAL_STRING3:
case FINALIZE_EXTERNAL_STRING4:
case FINALIZE_EXTERNAL_STRING5:
case FINALIZE_EXTERNAL_STRING6:
case FINALIZE_EXTERNAL_STRING7:
return RefillTypedFreeList<JSString>(cx, thingKind);
case FINALIZE_EXTERNAL_STRING:
return RefillTypedFreeList<JSExternalString>(cx, thingKind);
case FINALIZE_SHORT_STRING:
return RefillTypedFreeList<JSShortString>(cx, thingKind);
case FINALIZE_FUNCTION:
@ -1164,7 +1159,7 @@ RefillFinalizableFreeList(JSContext *cx, unsigned thingKind)
intN
js_GetExternalStringGCType(JSString *str) {
return GetExternalStringGCType(str);
return GetExternalStringGCType((JSExternalString *)str);
}
uint32
@ -1355,16 +1350,11 @@ GCMarker::markDelayedChildren()
reinterpret_cast<Arena<JSObject_Slots16> *>(a)->markDelayedChildren(this);
break;
case FINALIZE_STRING:
case FINALIZE_EXTERNAL_STRING0:
case FINALIZE_EXTERNAL_STRING1:
case FINALIZE_EXTERNAL_STRING2:
case FINALIZE_EXTERNAL_STRING3:
case FINALIZE_EXTERNAL_STRING4:
case FINALIZE_EXTERNAL_STRING5:
case FINALIZE_EXTERNAL_STRING6:
case FINALIZE_EXTERNAL_STRING7:
reinterpret_cast<Arena<JSString> *>(a)->markDelayedChildren(this);
break;
case FINALIZE_EXTERNAL_STRING:
reinterpret_cast<Arena<JSExternalString> *>(a)->markDelayedChildren(this);
break;
case FINALIZE_SHORT_STRING:
JS_ASSERT(false);
break;
@ -1766,19 +1756,6 @@ js_DestroyScriptsToGC(JSContext *cx, JSThreadData *data)
}
}
intN
js_ChangeExternalStringFinalizer(JSStringFinalizeOp oldop,
JSStringFinalizeOp newop)
{
for (uintN i = 0; i != JS_ARRAY_LENGTH(str_finalizers); i++) {
if (str_finalizers[i] == oldop) {
str_finalizers[i] = newop;
return intN(i);
}
}
return -1;
}
/*
* This function is called from js_FinishAtomState to force the finalization
* of the permanently interned strings when cx is not available.
@ -1805,17 +1782,8 @@ js_FinalizeStringRT(JSRuntime *rt, JSString *str)
return;
if (thingKind == FINALIZE_STRING) {
rt->free(chars);
} else if (thingKind != FINALIZE_SHORT_STRING) {
unsigned type = thingKind - FINALIZE_EXTERNAL_STRING0;
JS_ASSERT(type < JS_ARRAY_LENGTH(str_finalizers));
JSStringFinalizeOp finalizer = str_finalizers[type];
if (finalizer) {
/*
* Assume that the finalizer for the permanently interned
* string knows how to deal with null context.
*/
finalizer(NULL, str);
}
} else if (thingKind == FINALIZE_EXTERNAL_STRING) {
((JSExternalString *)str)->finalize();
}
}
}
@ -1875,7 +1843,7 @@ FinalizeArenaList(JSCompartment *comp, JSContext *cx, unsigned thingKind)
METER(nthings++);
continue;
} else {
thing->finalize(cx, thingKind);
thing->finalize(cx);
#ifdef DEBUG
memset(thing, JS_FREE_PATTERN, sizeof(T));
#endif
@ -2254,8 +2222,7 @@ MarkAndSweep(JSContext *cx, JSGCInvocationKind gckind GCTIMER_PARAM)
for (JSCompartment **comp = rt->compartments.begin(); comp != rt->compartments.end(); comp++) {
FinalizeArenaList<JSShortString>(*comp, cx, FINALIZE_SHORT_STRING);
FinalizeArenaList<JSString>(*comp, cx, FINALIZE_STRING);
for (unsigned i = FINALIZE_EXTERNAL_STRING0; i <= FINALIZE_EXTERNAL_STRING_LAST; ++i)
FinalizeArenaList<JSString>(*comp, cx, i);
FinalizeArenaList<JSExternalString>(*comp, cx, FINALIZE_EXTERNAL_STRING);
}
TIMESTAMP(sweepStringEnd);

View File

@ -90,20 +90,11 @@ enum FinalizeKind {
#endif
FINALIZE_SHORT_STRING,
FINALIZE_STRING,
FINALIZE_EXTERNAL_STRING0,
FINALIZE_EXTERNAL_STRING1,
FINALIZE_EXTERNAL_STRING2,
FINALIZE_EXTERNAL_STRING3,
FINALIZE_EXTERNAL_STRING4,
FINALIZE_EXTERNAL_STRING5,
FINALIZE_EXTERNAL_STRING6,
FINALIZE_EXTERNAL_STRING7,
FINALIZE_EXTERNAL_STRING_LAST = FINALIZE_EXTERNAL_STRING7,
FINALIZE_EXTERNAL_STRING,
FINALIZE_LIMIT
};
const uintN JS_FINALIZE_OBJECT_LIMIT = 6;
const uintN JS_EXTERNAL_STRING_LIMIT = 8;
/* Every arena has a header. */
struct ArenaHeader {
@ -270,8 +261,6 @@ template <typename T>
inline Arena<T> *
EmptyArenaLists::getTypedFreeList(unsigned thingKind) {
JS_ASSERT(thingKind < FINALIZE_LIMIT);
if (thingKind >= FINALIZE_EXTERNAL_STRING0)
thingKind = FINALIZE_STRING;
Arena<T> *arena = (Arena<T>*) freeLists[thingKind];
if (arena) {
freeLists[thingKind] = freeLists[thingKind]->header()->next;
@ -303,8 +292,6 @@ inline void
EmptyArenaLists::insert(Arena<T> *arena) {
unsigned thingKind = arena->header()->thingKind;
JS_ASSERT(thingKind < FINALIZE_LIMIT);
if (thingKind >= FINALIZE_EXTERNAL_STRING0)
thingKind = FINALIZE_STRING;
arena->header()->next = freeLists[thingKind];
freeLists[thingKind] = (Arena<FreeCell> *) arena;
}
@ -490,7 +477,7 @@ const float GC_HEAP_GROWTH_FACTOR = 3.0f;
static inline size_t
GetFinalizableTraceKind(size_t thingKind)
{
JS_STATIC_ASSERT(JS_EXTERNAL_STRING_LIMIT == 8);
JS_STATIC_ASSERT(JSExternalString::TYPE_LIMIT == 8);
static const uint8 map[FINALIZE_LIMIT] = {
JSTRACE_OBJECT, /* FINALIZE_OBJECT0 */
@ -505,14 +492,7 @@ GetFinalizableTraceKind(size_t thingKind)
#endif
JSTRACE_STRING, /* FINALIZE_SHORT_STRING */
JSTRACE_STRING, /* FINALIZE_STRING */
JSTRACE_STRING, /* FINALIZE_EXTERNAL_STRING0 */
JSTRACE_STRING, /* FINALIZE_EXTERNAL_STRING1 */
JSTRACE_STRING, /* FINALIZE_EXTERNAL_STRING2 */
JSTRACE_STRING, /* FINALIZE_EXTERNAL_STRING3 */
JSTRACE_STRING, /* FINALIZE_EXTERNAL_STRING4 */
JSTRACE_STRING, /* FINALIZE_EXTERNAL_STRING5 */
JSTRACE_STRING, /* FINALIZE_EXTERNAL_STRING6 */
JSTRACE_STRING, /* FINALIZE_EXTERNAL_STRING7 */
JSTRACE_STRING, /* FINALIZE_EXTERNAL_STRING */
};
JS_ASSERT(thingKind < FINALIZE_LIMIT);
@ -523,7 +503,7 @@ static inline bool
IsFinalizableStringKind(unsigned thingKind)
{
return unsigned(FINALIZE_SHORT_STRING) <= thingKind &&
thingKind <= unsigned(FINALIZE_EXTERNAL_STRING_LAST);
thingKind <= unsigned(FINALIZE_EXTERNAL_STRING);
}
/*
@ -531,14 +511,14 @@ IsFinalizableStringKind(unsigned thingKind)
* with JS_NewExternalString.
*/
static inline intN
GetExternalStringGCType(JSString *str)
GetExternalStringGCType(JSExternalString *str)
{
JS_STATIC_ASSERT(FINALIZE_STRING + 1 == FINALIZE_EXTERNAL_STRING0);
JS_STATIC_ASSERT(FINALIZE_STRING + 1 == FINALIZE_EXTERNAL_STRING);
JS_ASSERT(!JSString::isStatic(str));
unsigned thingKind = GetArena<JSString>((Cell *)str)->header()->thingKind;
unsigned thingKind = str->externalStringType;
JS_ASSERT(IsFinalizableStringKind(thingKind));
return intN(thingKind) - intN(FINALIZE_EXTERNAL_STRING0);
return intN(thingKind);
}
static inline uint32
@ -751,10 +731,6 @@ js_InitGC(JSRuntime *rt, uint32 maxbytes);
extern void
js_FinishGC(JSRuntime *rt);
extern intN
js_ChangeExternalStringFinalizer(JSStringFinalizeOp oldop,
JSStringFinalizeOp newop);
extern JSBool
js_AddRoot(JSContext *cx, js::Value *vp, const char *name);
@ -1000,7 +976,7 @@ struct GCMarker : public JSTracer {
#endif
#ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS
struct ConservativeRoot { void *thing; uint32 traceKind; };
struct ConservativeRoot { void *thing; uint32 thingKind; };
Vector<ConservativeRoot, 0, SystemAllocPolicy> conservativeRoots;
const char *conservativeDumpFileName;

View File

@ -154,12 +154,12 @@ js_NewGCShortString(JSContext *cx)
return NewFinalizableGCThing<JSShortString>(cx, js::gc::FINALIZE_SHORT_STRING);
}
inline JSString *
inline JSExternalString *
js_NewGCExternalString(JSContext *cx, uintN type)
{
JS_ASSERT(type < js::gc::JS_EXTERNAL_STRING_LIMIT);
type += js::gc::FINALIZE_EXTERNAL_STRING0;
return NewFinalizableGCThing<JSString>(cx, type);
JS_ASSERT(type < JSExternalString::TYPE_LIMIT);
JSExternalString *str = NewFinalizableGCThing<JSExternalString>(cx, js::gc::FINALIZE_EXTERNAL_STRING);
return str;
}
inline JSFunction*
@ -437,9 +437,7 @@ MarkKind(JSTracer *trc, void *thing, uint32 kind)
Mark(trc, reinterpret_cast<JSObject *>(thing));
break;
case JSTRACE_STRING:
if (JSString::isStatic((JSString *)thing))
return;
Mark(trc, reinterpret_cast<JSString *>(thing));
MarkString(trc, reinterpret_cast<JSString *>(thing));
break;
#if JS_HAS_XML_SUPPORT
case JSTRACE_XML:

View File

@ -72,6 +72,7 @@ ConservativeGCStats::dump(FILE *fp)
fprintf(fp, " excluded, wrong tag: %lu\n", ULSTAT(counter[CGCT_WRONGTAG]));
fprintf(fp, " excluded, not live: %lu\n", ULSTAT(counter[CGCT_NOTLIVE]));
fprintf(fp, " valid GC things: %lu\n", ULSTAT(counter[CGCT_VALID]));
fprintf(fp, " valid but not aligned: %lu\n", ULSTAT(counter[CGCT_VALIDWITHOFFSET]));
#undef ULSTAT
}
#endif
@ -123,14 +124,7 @@ static const char *const GC_ARENA_NAMES[] = {
#endif
"short string",
"string",
"external_string_0",
"external_string_1",
"external_string_2",
"external_string_3",
"external_string_4",
"external_string_5",
"external_string_6",
"external_string_7",
"external_string",
};
JS_STATIC_ASSERT(JS_ARRAY_LENGTH(GC_ARENA_NAMES) == FINALIZE_LIMIT);
@ -142,6 +136,43 @@ GetSizeAndThings(size_t &thingSize, size_t &thingsPerArena)
thingsPerArena = Arena<T>::ThingsPerArena;
}
#if defined JS_DUMP_CONSERVATIVE_GC_ROOTS
void *
GetAlignedThing(void *thing, int thingKind)
{
Cell *cell = (Cell *)thing;
switch (thingKind) {
case FINALIZE_OBJECT0:
return (void *)GetArena<JSObject>(cell)->getAlignedThing(thing);
case FINALIZE_OBJECT2:
return (void *)GetArena<JSObject_Slots2>(cell)->getAlignedThing(thing);
case FINALIZE_OBJECT4:
return (void *)GetArena<JSObject_Slots4>(cell)->getAlignedThing(thing);
case FINALIZE_OBJECT8:
return (void *)GetArena<JSObject_Slots8>(cell)->getAlignedThing(thing);
case FINALIZE_OBJECT12:
return (void *)GetArena<JSObject_Slots12>(cell)->getAlignedThing(thing);
case FINALIZE_OBJECT16:
return (void *)GetArena<JSObject_Slots16>(cell)->getAlignedThing(thing);
case FINALIZE_STRING:
return (void *)GetArena<JSString>(cell)->getAlignedThing(thing);
case FINALIZE_EXTERNAL_STRING:
return (void *)GetArena<JSExternalString>(cell)->getAlignedThing(thing);
case FINALIZE_SHORT_STRING:
return (void *)GetArena<JSShortString>(cell)->getAlignedThing(thing);
case FINALIZE_FUNCTION:
return (void *)GetArena<JSFunction>(cell)->getAlignedThing(thing);
#if JS_HAS_XML_SUPPORT
case FINALIZE_XML:
return (void *)GetArena<JSXML>(cell)->getAlignedThing(thing);
#endif
default:
JS_ASSERT(false);
return NULL;
}
}
#endif
void GetSizeAndThingsPerArena(int thingKind, size_t &thingSize, size_t &thingsPerArena)
{
switch (thingKind) {
@ -163,15 +194,8 @@ void GetSizeAndThingsPerArena(int thingKind, size_t &thingSize, size_t &thingsPe
case FINALIZE_OBJECT16:
GetSizeAndThings<JSObject_Slots16>(thingSize, thingsPerArena);
break;
case FINALIZE_EXTERNAL_STRING:
case FINALIZE_STRING:
case FINALIZE_EXTERNAL_STRING0:
case FINALIZE_EXTERNAL_STRING1:
case FINALIZE_EXTERNAL_STRING2:
case FINALIZE_EXTERNAL_STRING3:
case FINALIZE_EXTERNAL_STRING4:
case FINALIZE_EXTERNAL_STRING5:
case FINALIZE_EXTERNAL_STRING6:
case FINALIZE_EXTERNAL_STRING7:
GetSizeAndThings<JSString>(thingSize, thingsPerArena);
break;
case FINALIZE_SHORT_STRING:
@ -327,7 +351,7 @@ GCMarker::dumpConservativeRoots()
i != conservativeRoots.end();
++i) {
fprintf(fp, " %p: ", i->thing);
switch (i->traceKind) {
switch (GetFinalizableTraceKind(i->thingKind)) {
default:
JS_NOT_REACHED("Unknown trace kind");
@ -339,7 +363,7 @@ GCMarker::dumpConservativeRoots()
case JSTRACE_STRING: {
JSString *str = (JSString *) i->thing;
char buf[50];
js_PutEscapedString(buf, sizeof buf, str, '"');
PutEscapedString(buf, sizeof buf, str, '"');
fprintf(fp, "string %s", buf);
break;
}

View File

@ -63,6 +63,7 @@ namespace gc {
*/
enum ConservativeGCTest {
CGCT_VALID,
CGCT_VALIDWITHOFFSET, /* points within an object */
CGCT_LOWBITSET, /* excluded because one of the low bits was set */
CGCT_NOTARENA, /* not within arena range in a chunk */
CGCT_NOTCHUNK, /* not within a valid chunk */
@ -128,6 +129,10 @@ UpdateCompartmentStats(JSCompartment *comp, unsigned thingKind, uint32 nlivearen
uint32 nkilledArenas, uint32 nthings);
#endif /* JS_GCMETER */
#if defined JS_DUMP_CONSERVATIVE_GC_ROOTS
void *GetAlignedThing(void *thing, int thingKind);
#endif
} //gc
#ifdef MOZ_GCTIMER

View File

@ -202,36 +202,37 @@ js::GetBlockChain(JSContext *cx, JSStackFrame *fp)
if (!fp->isScriptFrame())
return NULL;
/* Assume that imacros don't affect blockChain */
jsbytecode *target = fp->hasImacropc() ? fp->imacropc() : fp->pc(cx);
JSScript *script = fp->script();
jsbytecode *start = script->code;
/* Assume that imacros don't affect blockChain */
jsbytecode *pc = fp->hasImacropc() ? fp->imacropc() : fp->pc(cx);
JS_ASSERT(pc >= start && pc < script->code + script->length);
JS_ASSERT(target >= start && target < start + script->length);
JSObject *blockChain = NULL;
if (*pc == JSOP_BLOCKCHAIN) {
blockChain = script->getObject(GET_INDEX(pc));
} else if (*pc == JSOP_NULLBLOCKCHAIN) {
blockChain = NULL;
} else {
ptrdiff_t oplen;
for (jsbytecode *p = start; p < pc; p += oplen) {
JSOp op = js_GetOpcode(cx, script, p);
const JSCodeSpec *cs = &js_CodeSpec[op];
oplen = cs->length;
if (oplen < 0)
oplen = js_GetVariableBytecodeLength(p);
uintN indexBase = 0;
ptrdiff_t oplen;
for (jsbytecode *pc = start; pc < target; pc += oplen) {
JSOp op = js_GetOpcode(cx, script, pc);
const JSCodeSpec *cs = &js_CodeSpec[op];
oplen = cs->length;
if (oplen < 0)
oplen = js_GetVariableBytecodeLength(pc);
if (op == JSOP_ENTERBLOCK)
blockChain = script->getObject(GET_INDEX(p));
else if (op == JSOP_LEAVEBLOCK || op == JSOP_LEAVEBLOCKEXPR)
blockChain = blockChain->getParent();
else if (op == JSOP_BLOCKCHAIN)
blockChain = script->getObject(GET_INDEX(p));
else if (op == JSOP_NULLBLOCKCHAIN)
blockChain = NULL;
}
if (op == JSOP_INDEXBASE)
indexBase = GET_INDEXBASE(pc);
else if (op == JSOP_INDEXBASE1 || op == JSOP_INDEXBASE2 || op == JSOP_INDEXBASE3)
indexBase = (op - JSOP_INDEXBASE1 + 1) << 16;
else if (op == JSOP_RESETBASE || op == JSOP_RESETBASE0)
indexBase = 0;
else if (op == JSOP_ENTERBLOCK)
blockChain = script->getObject(indexBase + GET_INDEX(pc));
else if (op == JSOP_LEAVEBLOCK || op == JSOP_LEAVEBLOCKEXPR)
blockChain = blockChain->getParent();
else if (op == JSOP_BLOCKCHAIN)
blockChain = script->getObject(indexBase + GET_INDEX(pc));
else if (op == JSOP_NULLBLOCKCHAIN)
blockChain = NULL;
}
return blockChain;
@ -249,29 +250,19 @@ js::GetBlockChainFast(JSContext *cx, JSStackFrame *fp, JSOp op, size_t oplen)
{
/* Assume that we're in a script frame. */
jsbytecode *pc = fp->pc(cx);
JS_ASSERT(js_GetOpcode(cx, fp->script(), pc) == op);
/* The fast path. */
if (pc[oplen] == JSOP_NULLBLOCKCHAIN) {
JS_ASSERT(js_GetOpcode(cx, fp->script(), pc) == op);
pc += oplen;
op = JSOp(*pc);
JS_ASSERT(js_GetOpcode(cx, fp->script(), pc) == op);
/* The fast paths assume no JSOP_RESETBASE/INDEXBASE noise. */
if (op == JSOP_NULLBLOCKCHAIN)
return NULL;
}
if (op == JSOP_BLOCKCHAIN)
return fp->script()->getObject(GET_INDEX(pc));
JSScript *script = fp->script();
JS_ASSERT(js_GetOpcode(cx, script, pc) == op);
JSObject *blockChain;
JSOp opNext = js_GetOpcode(cx, script, pc + oplen);
if (opNext == JSOP_BLOCKCHAIN) {
blockChain = script->getObject(GET_INDEX(pc + oplen));
} else if (opNext == JSOP_NULLBLOCKCHAIN) {
blockChain = NULL;
} else {
blockChain = NULL; /* appease gcc */
JS_NOT_REACHED("invalid opcode for fast block chain access");
}
return blockChain;
return GetBlockChain(cx, fp);
}
/*
@ -508,10 +499,11 @@ ReportIncompatibleMethod(JSContext *cx, Value *vp, Class *clasp)
: thisv.isUndefined()
? js_undefined_str
: "value";
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_PROTO,
clasp->name, JS_GetFunctionName(fun),
name);
JSAutoByteString funNameBytes;
if (const char *funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
clasp->name, funName, name);
}
}
}
@ -738,29 +730,6 @@ Invoke(JSContext *cx, const CallArgs &argsRef, uint32 flags)
if (fun->isHeavyweight() && !js_GetCallObject(cx, fp))
return false;
/*
* FIXME bug 592992: hoist to ExternalInvoke
*
* Compute |this|. Currently, this must happen after the frame is pushed
* and fp->scopeChain is correct because the thisObject hook may call
* GetScopeChain.
*/
if (!(flags & JSINVOKE_CONSTRUCT)) {
Value &thisv = fp->functionThis();
if (thisv.isObject()) {
/*
* We must call the thisObject hook in case we are not called from the
* interpreter, where a prior bytecode has computed an appropriate
* |this| already.
*/
JSObject *thisp = thisv.toObject().thisObject(cx);
if (!thisp)
return false;
JS_ASSERT(IsSaneThisObject(*thisp));
thisv.setObject(*thisp);
}
}
/* Run function until JSOP_STOP, JSOP_RETURN or error. */
JSBool ok;
{
@ -780,6 +749,10 @@ InvokeSessionGuard::start(JSContext *cx, const Value &calleev, const Value &this
#ifdef JS_TRACER
if (TRACE_RECORDER(cx))
AbortRecording(cx, "attempt to reenter VM while recording");
#ifdef JS_METHODJIT
if (TRACE_PROFILER(cx))
AbortProfiling(cx);
#endif
LeaveTrace(cx);
#endif
@ -793,6 +766,10 @@ InvokeSessionGuard::start(JSContext *cx, const Value &calleev, const Value &this
savedThis_ = args_.thisv() = thisv;
do {
/* In debug mode, script->getJIT(fp->isConstructing()) can change. */
if (cx->compartment->debugMode)
break;
/* Hoist dynamic checks from scripted Invoke. */
if (!calleev.isObject())
break;
@ -814,15 +791,6 @@ InvokeSessionGuard::start(JSContext *cx, const Value &calleev, const Value &this
fp->initCallFrame(cx, calleev.toObject(), fun, argc, flags);
stack.pushInvokeFrame(cx, args_, &frame_);
// FIXME bug 592992: hoist thisObject hook to ExternalInvoke
if (thisv.isObject()) {
JSObject *thisp = thisv.toObject().thisObject(cx);
if (!thisp)
return false;
JS_ASSERT(IsSaneThisObject(*thisp));
savedThis_.setObject(*thisp);
}
#ifdef JS_METHODJIT
/* Hoist dynamic checks from RunScript. */
mjit::CompileStatus status = mjit::CanMethodJIT(cx, script_, fp);
@ -872,18 +840,51 @@ ExternalInvoke(JSContext *cx, const Value &thisv, const Value &fval,
InvokeArgsGuard args;
if (!cx->stack().pushInvokeArgs(cx, argc, &args))
return JS_FALSE;
return false;
args.callee() = fval;
args.thisv() = thisv;
memcpy(args.argv(), argv, argc * sizeof(Value));
if (args.thisv().isObject()) {
/*
* We must call the thisObject hook in case we are not called from the
* interpreter, where a prior bytecode has computed an appropriate
* |this| already.
*/
JSObject *thisp = args.thisv().toObject().thisObject(cx);
if (!thisp)
return false;
JS_ASSERT(IsSaneThisObject(*thisp));
args.thisv().setObject(*thisp);
}
if (!Invoke(cx, args, 0))
return JS_FALSE;
return false;
*rval = args.rval();
return true;
}
return JS_TRUE;
bool
ExternalInvokeConstructor(JSContext *cx, const Value &fval, uintN argc, Value *argv,
Value *rval)
{
LeaveTrace(cx);
InvokeArgsGuard args;
if (!cx->stack().pushInvokeArgs(cx, argc, &args))
return false;
args.callee() = fval;
args.thisv().setMagic(JS_THIS_POISON);
memcpy(args.argv(), argv, argc * sizeof(Value));
if (!InvokeConstructor(cx, args))
return false;
*rval = args.rval();
return true;
}
bool
@ -1121,7 +1122,8 @@ CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs,
: isFunction
? js_function_str
: js_var_str;
name = js_ValueToPrintableString(cx, IdToValue(id));
JSAutoByteString bytes;
name = js_ValueToPrintable(cx, IdToValue(id), &bytes);
if (!name)
return JS_FALSE;
return !!JS_ReportErrorFlagsAndNumber(cx, report,
@ -1226,12 +1228,12 @@ InstanceOfSlow(JSContext *cx, JSObject *obj, Class *clasp, Value *argv)
if (argv) {
JSFunction *fun = js_ValueToFunction(cx, &argv[-2], 0);
if (fun) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_PROTO,
clasp->name, JS_GetFunctionName(fun),
obj
? obj->getClass()->name
: js_null_str);
JSAutoByteString funNameBytes;
if (const char *funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
clasp->name, funName,
obj ? obj->getClass()->name : js_null_str);
}
}
}
return false;
@ -1277,10 +1279,12 @@ InvokeConstructor(JSContext *cx, const CallArgs &argsRef)
if (args.rval().isPrimitive()) {
if (clasp != &js_FunctionClass) {
/* native [[Construct]] returning primitive is error */
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_BAD_NEW_RESULT,
js_ValueToPrintableString(cx, args.rval()));
return false;
JSAutoByteString bytes;
if (js_ValueToPrintable(cx, args.rval(), &bytes)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_BAD_NEW_RESULT, bytes.ptr());
return false;
}
}
/* The interpreter fixes rval for us. */
@ -1336,10 +1340,10 @@ DirectEval(JSContext *cx, JSFunction *evalfun, uint32 argc, Value *vp)
JS_ASSERT(vp[0].toObject().getFunctionPrivate() == evalfun);
JS_ASSERT(IsBuiltinEvalFunction(evalfun));
AutoFunctionCallProbe callProbe(cx, evalfun);
JSStackFrame *caller = cx->fp();
JS_ASSERT(caller->isScriptFrame());
AutoFunctionCallProbe callProbe(cx, evalfun, caller->script());
JSObject *scopeChain =
GetScopeChainFast(cx, caller, JSOP_EVAL, JSOP_EVAL_LENGTH + JSOP_LINENO_LENGTH);
if (!scopeChain || !EvalKernel(cx, argc, vp, DIRECT_EVAL, caller, scopeChain))
@ -1576,7 +1580,7 @@ js_LogOpcode(JSContext *cx)
fputs("<null>", logfp);
} else {
JS_ClearPendingException(cx);
js_FileEscapedString(logfp, str, 0);
FileEscapedString(logfp, str, 0);
}
}
fputc(' ', logfp);
@ -2203,7 +2207,8 @@ ScriptPrologue(JSContext *cx, JSStackFrame *fp)
if (JS_UNLIKELY(hook != NULL) && !fp->isExecuteFrame())
fp->setHookData(hook(cx, fp, JS_TRUE, 0, cx->debugHooks->callHookData));
Probes::enterJSFun(cx, fp->maybeFun());
if (!fp->isExecuteFrame())
Probes::enterJSFun(cx, fp->maybeFun(), fp->maybeScript());
return true;
}
@ -2336,11 +2341,21 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
/* Check for too deep of a native thread stack. */
#ifdef JS_TRACER
#ifdef JS_METHODJIT
JS_CHECK_RECURSION(cx, do {
if (TRACE_RECORDER(cx))
AbortRecording(cx, "too much recursion");
if (TRACE_PROFILER(cx))
AbortProfiling(cx);
return JS_FALSE;
} while (0););
#else
JS_CHECK_RECURSION(cx, do {
if (TRACE_RECORDER(cx))
AbortRecording(cx, "too much recursion");
return JS_FALSE;
} while (0););
#endif
#else
JS_CHECK_RECURSION(cx, return JS_FALSE);
#endif
@ -2403,9 +2418,15 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
MonitorResult r = MonitorLoopEdge(cx, inlineCallCount); \
if (r == MONITOR_RECORDING) { \
JS_ASSERT(TRACE_RECORDER(cx)); \
JS_ASSERT(!TRACE_PROFILER(cx)); \
MONITOR_BRANCH_TRACEVIS; \
ENABLE_INTERRUPTS(); \
CLEAR_LEAVE_ON_TRACE_POINT(); \
} else if (r == MONITOR_PROFILING) { \
JS_ASSERT(TRACE_PROFILER(cx)); \
JS_ASSERT(!TRACE_RECORDER(cx)); \
ENABLE_INTERRUPTS(); \
CLEAR_LEAVE_ON_TRACE_POINT(); \
} \
RESTORE_INTERP_VARS(); \
JS_ASSERT_IF(cx->throwing, r == MONITOR_ERROR); \
@ -2439,6 +2460,7 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
# define LEAVE_ON_SAFE_POINT() \
do { \
JS_ASSERT_IF(leaveOnSafePoint, !TRACE_RECORDER(cx)); \
JS_ASSERT_IF(leaveOnSafePoint, !TRACE_PROFILER(cx)); \
if (leaveOnSafePoint && !regs.fp->hasImacropc() && \
script->maybeNativeCodeForPC(regs.fp->isConstructing(), regs.pc)) { \
JS_ASSERT(!TRACE_RECORDER(cx)); \
@ -2550,11 +2572,20 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
*/
if (interpMode == JSINTERP_RECORD) {
JS_ASSERT(TRACE_RECORDER(cx));
JS_ASSERT(!TRACE_PROFILER(cx));
ENABLE_INTERRUPTS();
#ifdef JS_METHODJIT
} else if (interpMode == JSINTERP_PROFILE) {
JS_ASSERT(TRACE_PROFILER(cx));
JS_ASSERT(!TRACE_RECORDER(cx));
ENABLE_INTERRUPTS();
#endif
} else if (TRACE_RECORDER(cx)) {
AbortRecording(cx, "attempt to reenter interpreter while recording");
#ifdef JS_METHODJIT
} else if (TRACE_PROFILER(cx)) {
AbortProfiling(cx);
#endif
}
if (regs.fp->hasImacropc())
@ -2629,6 +2660,10 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
#ifdef JS_TRACER
if (TRACE_RECORDER(cx))
AbortRecording(cx, "interrupt hook");
#ifdef JS_METHODJIT
if (TRACE_PROFILER(cx))
AbortProfiling(cx);
#endif
#endif
Value rval;
switch (hook(cx, script, regs.pc, Jsvalify(&rval),
@ -2653,6 +2688,7 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
#ifdef JS_TRACER
#ifdef JS_METHODJIT
if (LoopProfile *prof = TRACE_PROFILER(cx)) {
JS_ASSERT(!TRACE_RECORDER(cx));
LoopProfile::ProfileAction act = prof->profileOperation(cx, op);
switch (act) {
case LoopProfile::ProfComplete:
@ -2666,6 +2702,7 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
}
#endif
if (TraceRecorder* tr = TRACE_RECORDER(cx)) {
JS_ASSERT(!TRACE_PROFILER(cx));
AbortableRecordingStatus status = tr->monitorRecording(op);
JS_ASSERT_IF(cx->throwing, status == ARECORD_ERROR);
@ -3387,16 +3424,8 @@ END_CASE(JSOP_BITAND)
goto error; \
cond = cond OP JS_TRUE; \
} else
#define EXTENDED_EQUALITY_OP(OP) \
if (EqualityOp eq = l->getClass()->ext.equality) { \
if (!eq(cx, l, &rval, &cond)) \
goto error; \
cond = cond OP JS_TRUE; \
} else
#else
#define XML_EQUALITY_OP(OP) /* nothing */
#define EXTENDED_EQUALITY_OP(OP) /* nothing */
#endif
#define EQUALITY_OP(OP, IFNAN) \
@ -3414,8 +3443,14 @@ END_CASE(JSOP_BITAND)
cond = JSDOUBLE_COMPARE(l, OP, r, IFNAN); \
} else if (lval.isObject()) { \
JSObject *l = &lval.toObject(), *r = &rval.toObject(); \
EXTENDED_EQUALITY_OP(OP) \
cond = l OP r; \
l->assertSpecialEqualitySynced(); \
if (EqualityOp eq = l->getClass()->ext.equality) { \
if (!eq(cx, l, &rval, &cond)) \
goto error; \
cond = cond OP JS_TRUE; \
} else { \
cond = l OP r; \
} \
} else { \
cond = lval.payloadAsRawUint32() OP rval.payloadAsRawUint32();\
} \
@ -4651,7 +4686,7 @@ BEGIN_CASE(JSOP_EVAL)
newfun = callee->getFunctionPrivate();
if (!IsBuiltinEvalFunction(newfun))
goto not_direct_eval;
goto call_using_invoke;
if (!DirectEval(cx, newfun, argc, vp))
goto error;
@ -4659,7 +4694,8 @@ BEGIN_CASE(JSOP_EVAL)
END_CASE(JSOP_EVAL)
BEGIN_CASE(JSOP_CALL)
BEGIN_CASE(JSOP_APPLY)
BEGIN_CASE(JSOP_FUNAPPLY)
BEGIN_CASE(JSOP_FUNCALL)
{
argc = GET_ARGC(regs.pc);
vp = regs.sp - (argc + 2);
@ -4667,7 +4703,6 @@ BEGIN_CASE(JSOP_APPLY)
if (IsFunctionObject(*vp, &callee)) {
newfun = callee->getFunctionPrivate();
not_direct_eval:
/* Clear frame flags since this is not a constructor call. */
flags = 0;
if (newfun->isInterpreted())
@ -4740,9 +4775,9 @@ BEGIN_CASE(JSOP_APPLY)
DO_OP();
}
Probes::enterJSFun(cx, newfun);
Probes::enterJSFun(cx, newfun, script);
JSBool ok = CallJSNative(cx, newfun->u.n.native, argc, vp);
Probes::exitJSFun(cx, newfun);
Probes::exitJSFun(cx, newfun, script);
regs.sp = vp + 1;
if (!ok)
goto error;
@ -4768,11 +4803,7 @@ END_CASE(JSOP_CALL)
BEGIN_CASE(JSOP_SETCALL)
{
uintN argc = GET_ARGC(regs.pc);
Value *vp = regs.sp - argc - 2;
JSBool ok = Invoke(cx, InvokeArgsAlreadyOnTheStack(vp, argc), 0);
if (ok)
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_LEFTSIDE_OF_ASS);
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_LEFTSIDE_OF_ASS);
goto error;
}
END_CASE(JSOP_SETCALL)
@ -4919,7 +4950,6 @@ END_CASE(JSOP_RESETBASE)
BEGIN_CASE(JSOP_DOUBLE)
{
JS_ASSERT(!regs.fp->hasImacropc());
JS_ASSERT(size_t(atoms - script->atomMap.vector) <= script->atomMap.length);
double dbl;
LOAD_DOUBLE(0, dbl);
PUSH_DOUBLE(dbl);
@ -5624,7 +5654,7 @@ BEGIN_CASE(JSOP_LAMBDA)
parent = &regs.fp->scopeChain();
if (obj->getParent() == parent) {
jsbytecode *pc2 = js_AdvanceOverBlockchain(regs.pc + JSOP_LAMBDA_LENGTH);
jsbytecode *pc2 = AdvanceOverBlockchainOp(regs.pc + JSOP_LAMBDA_LENGTH);
JSOp op2 = JSOp(*pc2);
/*
@ -6981,13 +7011,11 @@ END_CASE(JSOP_ARRAYPUSH)
atom_not_defined:
{
const char *printable;
printable = js_AtomToPrintableString(cx, atomNotDefined);
if (printable)
js_ReportIsNotDefined(cx, printable);
goto error;
JSAutoByteString printable;
if (js_AtomToPrintableString(cx, atomNotDefined, &printable))
js_ReportIsNotDefined(cx, printable.ptr());
}
goto error;
/*
* This path is used when it's guaranteed the method can be finished

View File

@ -197,8 +197,8 @@ struct JSStackFrame
inline void resetInvokeCallFrame();
/* Called by method-jit stubs and serve as a specification for jit-code. */
inline void initCallFrameCallerHalf(JSContext *cx, uint32 nactual, uint32 flags);
inline void initCallFrameEarlyPrologue(JSFunction *fun, void *ncode);
inline void initCallFrameCallerHalf(JSContext *cx, uint32 flags, void *ncode);
inline void initCallFrameEarlyPrologue(JSFunction *fun, uint32 nactual);
inline void initCallFrameLatePrologue();
/* Used for eval. */
@ -973,6 +973,20 @@ extern JS_REQUIRES_STACK bool
InvokeConstructorWithGivenThis(JSContext *cx, JSObject *thisobj, const Value &fval,
uintN argc, Value *argv, Value *rval);
extern bool
ExternalInvokeConstructor(JSContext *cx, const Value &fval, uintN argc, Value *argv,
Value *rval);
/*
* Performs a direct eval for the given arguments, which must correspond to the
* currently-executing stack frame, which must be a script frame. evalfun must
* be the built-in eval function and must correspond to the callee in vp[0].
* When this function succeeds it returns the result in *vp, adjusts the JS
* stack pointer, and returns true.
*/
extern JS_REQUIRES_STACK bool
DirectEval(JSContext *cx, JSFunction *evalfun, uint32 argc, Value *vp);
/*
* Performs a direct eval for the given arguments, which must correspond to the
* currently-executing stack frame, which must be a script frame. evalfun must

View File

@ -69,6 +69,7 @@ JSStackFrame::initPrev(JSContext *cx)
inline void
JSStackFrame::resetGeneratorPrev(JSContext *cx)
{
flags_ |= JSFRAME_HAS_PREVPC;
initPrev(cx);
}
@ -131,23 +132,17 @@ JSStackFrame::resetInvokeCallFrame()
}
inline void
JSStackFrame::initCallFrameCallerHalf(JSContext *cx, uint32 nactual, uint32 flagsArg)
JSStackFrame::initCallFrameCallerHalf(JSContext *cx, uint32 flagsArg,
void *ncode)
{
JS_ASSERT((flagsArg & ~(JSFRAME_CONSTRUCTING |
JSFRAME_FUNCTION |
JSFRAME_OVERFLOW_ARGS |
JSFRAME_UNDERFLOW_ARGS)) == 0);
JSFrameRegs *regs = cx->regs;
/* Initialize the caller half of the stack frame members. */
flags_ = JSFRAME_FUNCTION | flagsArg;
args.nactual = nactual; /* only need to write if over/under-flow */
prev_ = regs->fp;
JS_ASSERT(!hasImacropc());
JS_ASSERT(!hasHookData());
JS_ASSERT(annotation() == NULL);
JS_ASSERT(!hasCallObj());
prev_ = cx->regs->fp;
ncode_ = ncode;
}
/*
@ -155,10 +150,11 @@ JSStackFrame::initCallFrameCallerHalf(JSContext *cx, uint32 nactual, uint32 flag
* of slow paths before initializing the rest of the members.
*/
inline void
JSStackFrame::initCallFrameEarlyPrologue(JSFunction *fun, void *ncode)
JSStackFrame::initCallFrameEarlyPrologue(JSFunction *fun, uint32 nactual)
{
exec.fun = fun;
ncode_ = ncode;
if (flags_ & (JSFRAME_OVERFLOW_ARGS | JSFRAME_UNDERFLOW_ARGS))
args.nactual = nactual;
}
/*
@ -319,6 +315,33 @@ JSStackFrame::forEachFormalArg(Op op)
op(i, p);
}
namespace js {
struct STATIC_SKIP_INFERENCE CopyNonHoleArgsTo
{
CopyNonHoleArgsTo(JSObject *aobj, Value *dst) : aobj(aobj), dst(dst) {}
JSObject *aobj;
Value *dst;
void operator()(uintN argi, Value *src) {
if (aobj->getArgsElement(argi).isMagic(JS_ARGS_HOLE))
dst->setUndefined();
else
*dst = *src;
++dst;
}
};
struct CopyTo
{
Value *dst;
CopyTo(Value *dst) : dst(dst) {}
void operator()(uintN, Value *src) {
*dst++ = *src;
}
};
}
JS_ALWAYS_INLINE void
JSStackFrame::clearMissingArgs()
{
@ -570,8 +593,11 @@ InvokeSessionGuard::invoke(JSContext *cx) const
JSBool ok;
{
AutoPreserveEnumerators preserve(cx);
Probes::enterJSFun(cx, fp->fun());
Probes::enterJSFun(cx, fp->fun(), script_);
#ifdef JS_METHODJIT
if (code_ != script_->getJIT(fp->isConstructing())->invokeEntry)
*(volatile int *)0x101 = 0;
AutoInterpPreparer prepareInterp(cx, script_);
ok = mjit::EnterMethodJIT(cx, fp, code_, stackLimit_);
cx->regs->pc = stop_;
@ -579,7 +605,7 @@ InvokeSessionGuard::invoke(JSContext *cx) const
cx->regs->pc = script_->code;
ok = Interpret(cx, cx->fp());
#endif
Probes::exitJSFun(cx, fp->fun());
Probes::exitJSFun(cx, fp->fun(), script_);
}
PutActivationObjects(cx, fp);
@ -684,10 +710,14 @@ ValuePropertyBearer(JSContext *cx, const Value &v, int spindex)
static inline bool
ScriptEpilogue(JSContext *cx, JSStackFrame *fp, JSBool ok)
{
Probes::exitJSFun(cx, fp->maybeFun());
if (!fp->isExecuteFrame())
Probes::exitJSFun(cx, fp->maybeFun(), fp->maybeScript());
JSInterpreterHook hook = cx->debugHooks->callHook;
if (hook && fp->hasHookData() && !fp->isExecuteFrame())
hook(cx, fp, JS_FALSE, &ok, fp->hookData());
void* hookData;
if (hook && (hookData = fp->maybeHookData()) && !fp->isExecuteFrame())
hook(cx, fp, JS_FALSE, &ok, hookData);
/*
* An eval frame's parent owns its activation objects. A yielding frame's

View File

@ -417,9 +417,11 @@ GetCustomIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp)
* We are always coming from js_ValueToIterator, and we are no longer on
* trace, so the object we are iterating over is on top of the stack (-1).
*/
JSAutoByteString bytes;
if (!js_AtomToPrintableString(cx, atom, &bytes))
return false;
js_ReportValueError2(cx, JSMSG_BAD_TRAP_RETURN_VALUE,
-1, ObjectValue(*obj), NULL,
js_AtomToPrintableString(cx, atom));
-1, ObjectValue(*obj), NULL, bytes.ptr());
return false;
}
return true;

View File

@ -584,6 +584,54 @@ ToCStringBuf::~ToCStringBuf()
js_free(dbuf);
}
JSString * JS_FASTCALL
js_IntToString(JSContext *cx, int32 si)
{
uint32 ui;
if (si >= 0) {
if (si < INT_STRING_LIMIT)
return JSString::intString(si);
if (si < 100)
return JSString::length2String(si);
ui = si;
} else {
ui = uint32(-si);
JS_ASSERT_IF(si == INT32_MIN, ui == uint32(INT32_MAX) + 1);
}
JSThreadData *data = JS_THREAD_DATA(cx);
if (data->dtoaCache.s && data->dtoaCache.base == 10 && data->dtoaCache.d == si)
return data->dtoaCache.s;
JSShortString *str = js_NewGCShortString(cx);
if (!str)
return NULL;
/* +1, since MAX_SHORT_STRING_LENGTH does not count the null char. */
JS_STATIC_ASSERT(JSShortString::MAX_SHORT_STRING_LENGTH + 1 >= sizeof("-2147483648"));
jschar *end = str->getInlineStorageBeforeInit() + JSShortString::MAX_SHORT_STRING_LENGTH;
jschar *cp = end;
*cp = 0;
do {
jsuint newui = ui / 10, digit = ui % 10; /* optimizers are our friends */
*--cp = '0' + digit;
ui = newui;
} while (ui != 0);
if (si < 0)
*--cp = '-';
str->initAtOffsetInBuffer(cp, end - cp);
JSString *ret = str->header();
data->dtoaCache.base = 10;
data->dtoaCache.d = si;
data->dtoaCache.s = ret;
return ret;
}
/* Returns a non-NULL pointer to inside cbuf. */
static char *
IntToCString(ToCStringBuf *cbuf, jsint i, jsint base = 10)
@ -683,7 +731,10 @@ num_toLocaleString(JSContext *cx, uintN argc, Value *vp)
if (!num_toString(cx, 0, vp))
return JS_FALSE;
JS_ASSERT(vp->isString());
num = js_GetStringBytes(cx, vp->toString());
JSAutoByteString numBytes(cx, vp->toString());
if (!numBytes)
return JS_FALSE;
num = numBytes.ptr();
if (!num)
return JS_FALSE;
@ -1071,16 +1122,6 @@ NumberToCString(JSContext *cx, ToCStringBuf *cbuf, jsdouble d, jsint base/* = 10
}
JSString * JS_FASTCALL
js_IntToString(JSContext *cx, jsint i)
{
if (jsuint(i) < INT_STRING_LIMIT)
return JSString::intString(i);
ToCStringBuf cbuf;
return js_NewStringCopyZ(cx, IntToCString(&cbuf, i));
}
static JSString * JS_FASTCALL
js_NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base)
{

View File

@ -913,18 +913,17 @@ js_CheckPrincipalsAccess(JSContext *cx, JSObject *scopeobj,
{
JSSecurityCallbacks *callbacks;
JSPrincipals *scopePrincipals;
const char *callerstr;
callbacks = JS_GetSecurityCallbacks(cx);
if (callbacks && callbacks->findObjectPrincipals) {
scopePrincipals = callbacks->findObjectPrincipals(cx, scopeobj);
if (!principals || !scopePrincipals ||
!principals->subsume(principals, scopePrincipals)) {
callerstr = js_AtomToPrintableString(cx, caller);
if (!callerstr)
JSAutoByteString callerstr;
if (!js_AtomToPrintableString(cx, caller, &callerstr))
return JS_FALSE;
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_BAD_INDIRECT_CALL, callerstr);
JSMSG_BAD_INDIRECT_CALL, callerstr.ptr());
return JS_FALSE;
}
}
@ -1198,7 +1197,7 @@ EvalKernel(JSContext *cx, uintN argc, Value *vp, EvalType evalType, JSStackFrame
JSONParser *jp = js_BeginJSONParse(cx, vp, /* suppressErrors = */true);
if (jp != NULL) {
/* Run JSON-parser on string inside ( and ). */
JSBool ok = js_ConsumeJSONText(cx, jp, chars + 1, length - 2);
bool ok = js_ConsumeJSONText(cx, jp, chars + 1, length - 2);
ok &= js_FinishJSONParse(cx, jp, NullValue());
if (ok)
return true;
@ -1782,34 +1781,36 @@ obj_keys(JSContext *cx, uintN argc, Value *vp)
{
JSObject *obj;
if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.keys", &obj))
return JS_FALSE;
return false;
AutoIdVector props(cx);
if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &props))
return JS_FALSE;
return false;
AutoValueVector vals(cx);
vals.resize(props.length());
if (!vals.reserve(props.length()))
return false;
for (size_t i = 0, len = props.length(); i < len; i++) {
jsid id = props[i];
if (JSID_IS_STRING(id)) {
vals[i].setString(JSID_TO_STRING(id));
} else {
JS_ASSERT(JSID_IS_INT(id));
JS_ALWAYS_TRUE(vals.append(StringValue(JSID_TO_STRING(id))));
} else if (JSID_IS_INT(id)) {
JSString *str = js_IntToString(cx, JSID_TO_INT(id));
if (!str)
return JS_FALSE;
vals[i].setString(str);
return false;
JS_ALWAYS_TRUE(vals.append(StringValue(str)));
} else {
JS_ASSERT(JSID_IS_OBJECT(id));
}
}
JS_ASSERT(props.length() <= UINT32_MAX);
JSObject *aobj = js_NewArrayObject(cx, jsuint(vals.length()), vals.begin());
if (!aobj)
return JS_FALSE;
return false;
vp->setObject(*aobj);
return JS_TRUE;
return true;
}
static bool
@ -1947,8 +1948,10 @@ Reject(JSContext *cx, uintN errorNumber, bool throwError, jsid id, bool *rval)
jsid idstr;
if (!js_ValueToStringId(cx, IdToValue(id), &idstr))
return JS_FALSE;
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, errorNumber,
JS_GetStringBytes(JSID_TO_STRING(idstr)));
JSAutoByteString bytes(cx, JSID_TO_STRING(idstr));
if (!bytes)
return JS_FALSE;
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, errorNumber, bytes.ptr());
return JS_FALSE;
}
@ -2539,15 +2542,18 @@ obj_preventExtensions(JSContext *cx, uintN argc, Value *vp)
return false;
vp->setObject(*obj);
if (!obj->isExtensible())
return true;
AutoIdVector props(cx);
return obj->preventExtensions(cx, &props);
}
bool
JSObject::sealOrFreeze(JSContext *cx, bool freeze)
JSObject::sealOrFreeze(JSContext *cx, ImmutabilityType it)
{
assertSameCompartment(cx, this);
JS_ASSERT(it == SEAL || it == FREEZE);
AutoIdVector props(cx);
if (isExtensible()) {
@ -2570,7 +2576,7 @@ JSObject::sealOrFreeze(JSContext *cx, bool freeze)
/* Make all attributes permanent; if freezing, make data attributes read-only. */
uintN new_attrs;
if (freeze && !(attrs & (JSPROP_GETTER | JSPROP_SETTER)))
if (it == FREEZE && !(attrs & (JSPROP_GETTER | JSPROP_SETTER)))
new_attrs = JSPROP_PERMANENT | JSPROP_READONLY;
else
new_attrs = JSPROP_PERMANENT;
@ -2769,7 +2775,10 @@ js_CreateThis(JSContext *cx, JSObject *callee)
JSObject *proto = protov.isObjectOrNull() ? protov.toObjectOrNull() : NULL;
JSObject *parent = callee->getParent();
gc::FinalizeKind kind = NewObjectGCKind(cx, newclasp);
return NewObject<WithProto::Class>(cx, newclasp, proto, parent, kind);
JSObject *obj = NewObject<WithProto::Class>(cx, newclasp, proto, parent, kind);
if (obj)
obj->syncSpecialEquality();
return obj;
}
JSObject *
@ -3487,7 +3496,8 @@ js_InitObjectClass(JSContext *cx, JSObject *obj)
return NULL;
/* ECMA (15.1.2.1) says 'eval' is a property of the global object. */
if (!js_DefineFunction(cx, obj, cx->runtime->atomState.evalAtom, eval, 1, JSFUN_STUB_GSOPS))
jsid id = ATOM_TO_JSID(cx->runtime->atomState.evalAtom);
if (!js_DefineFunction(cx, obj, id, eval, 1, JSFUN_STUB_GSOPS))
return NULL;
return proto;
@ -3589,6 +3599,8 @@ js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
if (!proto)
return NULL;
proto->syncSpecialEquality();
/* After this point, control must exit via label bad or out. */
AutoObjectRooter tvr(cx, proto);
@ -3664,6 +3676,15 @@ js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
goto bad;
}
/*
* Pre-brand the prototype and constructor if they have built-in methods.
* This avoids extra shape guard branch exits in the tracejitted code.
*/
if (fs && !proto->brand(cx))
goto bad;
if (ctor != proto && static_fs && !ctor->brand(cx))
goto bad;
/*
* Make sure proto's emptyShape is available to be shared by objects of
* this class. JSObject::emptyShape is a one-slot cache. If we omit this,
@ -4041,6 +4062,8 @@ js_ConstructObject(JSContext *cx, Class *clasp, JSObject *proto, JSObject *paren
if (!obj)
return NULL;
obj->syncSpecialEquality();
Value rval;
if (!InvokeConstructorWithGivenThis(cx, obj, cval, argc, argv, &rval))
return NULL;
@ -4191,7 +4214,7 @@ js_CheckForStringIndex(jsid id)
if (oldIndex < -(JSID_INT_MIN / 10) ||
(oldIndex == -(JSID_INT_MIN / 10) && c <= (-JSID_INT_MIN % 10)))
{
id = INT_TO_JSID(jsint(-index));
id = INT_TO_JSID(-jsint(index));
}
} else {
if (oldIndex < JSID_INT_MAX / 10 ||
@ -4835,8 +4858,8 @@ js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id)
}
static JS_ALWAYS_INLINE JSBool
js_NativeGetInline(JSContext *cx, JSObject *obj, JSObject *pobj, const Shape *shape, uintN getHow,
Value *vp)
js_NativeGetInline(JSContext *cx, JSObject *receiver, JSObject *obj, JSObject *pobj,
const Shape *shape, uintN getHow, Value *vp)
{
LeaveTraceIfGlobalObject(cx, pobj);
@ -4864,7 +4887,7 @@ js_NativeGetInline(JSContext *cx, JSObject *obj, JSObject *pobj, const Shape *sh
{
AutoShapeRooter tvr(cx, shape);
AutoObjectRooter tvr2(cx, pobj);
if (!shape->get(cx, obj, pobj, vp))
if (!shape->get(cx, receiver, obj, pobj, vp))
return false;
}
@ -4883,7 +4906,7 @@ JSBool
js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, const Shape *shape, uintN getHow,
Value *vp)
{
return js_NativeGetInline(cx, obj, pobj, shape, getHow, vp);
return js_NativeGetInline(cx, obj, obj, pobj, shape, getHow, vp);
}
JSBool
@ -5038,7 +5061,7 @@ js_GetPropertyHelperWithShapeInline(JSContext *cx, JSObject *obj, JSObject *rece
}
/* This call site is hot -- use the always-inlined variant of js_NativeGet(). */
if (!js_NativeGetInline(cx, receiver, obj2, shape, getHow, vp))
if (!js_NativeGetInline(cx, receiver, obj, obj2, shape, getHow, vp))
return JS_FALSE;
return JS_TRUE;
@ -5076,7 +5099,7 @@ js_GetProperty(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value
}
JSBool
js::GetPropertyDefault(JSContext *cx, JSObject *obj, jsid id, Value def, Value *vp)
js::GetPropertyDefault(JSContext *cx, JSObject *obj, jsid id, const Value &def, Value *vp)
{
JSProperty *prop;
JSObject *obj2;
@ -5124,13 +5147,13 @@ js_CheckUndeclaredVarAssignment(JSContext *cx, JSString *propname)
return true;
}
const char *bytes = js_GetStringBytes(cx, propname);
return bytes &&
JSAutoByteString bytes(cx, propname);
return !!bytes &&
JS_ReportErrorFlagsAndNumber(cx,
(JSREPORT_WARNING | JSREPORT_STRICT
| JSREPORT_STRICT_MODE_ERROR),
js_GetErrorMessage, NULL,
JSMSG_UNDECLARED_VAR, bytes);
JSMSG_UNDECLARED_VAR, bytes.ptr());
}
bool
@ -5540,6 +5563,21 @@ js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool str
namespace js {
JSObject *
HasNativeMethod(JSObject *obj, jsid methodid, Native native)
{
const Shape *shape = obj->nativeLookup(methodid);
if (!shape || !shape->hasDefaultGetter() || !obj->containsSlot(shape->slot))
return NULL;
const Value &fval = obj->nativeGetSlot(shape->slot);
JSObject *funobj;
if (!IsFunctionObject(fval, &funobj) || funobj->getFunctionPrivate()->maybeNative() != native)
return NULL;
return funobj;
}
/*
* When we have an object of a builtin class, we don't quite know what its
* valueOf/toString methods are, since these methods may have been overwritten
@ -5549,35 +5587,20 @@ namespace js {
* TODO: a per-thread shape-based cache would be faster and simpler.
*/
static JS_ALWAYS_INLINE bool
ClassMethodIsNative(JSContext *cx, JSObject *obj, Class *classp, jsid methodid,
ClassMethodIsNative(JSContext *cx, JSObject *obj, Class *clasp, jsid methodid,
Native native)
{
JS_ASSERT(obj->getClass() == classp);
JS_ASSERT(obj->getClass() == clasp);
const Shape *shape = obj->nativeLookup(methodid);
JSObject *pobj = obj;
if (HasNativeMethod(obj, methodid, native))
return true;
if (!shape) {
pobj = obj->getProto();
if (pobj && pobj->getClass() == classp)
shape = pobj->nativeLookup(methodid);
}
if (shape && shape->hasDefaultGetter() && pobj->containsSlot(shape->slot)) {
const Value &fval = pobj->nativeGetSlot(shape->slot);
JSObject *funobj;
if (IsFunctionObject(fval, &funobj)) {
JSFunction *fun = funobj->getFunctionPrivate();
if (fun->maybeNative() == native)
return true;
}
}
return false;
JSObject *pobj = obj->getProto();
return pobj && pobj->getClass() == clasp &&
HasNativeMethod(pobj, methodid, native);
}
JSBool
bool
DefaultValue(JSContext *cx, JSObject *obj, JSType hint, Value *vp)
{
JS_ASSERT(hint != JSTYPE_OBJECT && hint != JSTYPE_FUNCTION);
@ -5837,39 +5860,6 @@ js_GetClassPrototype(JSContext *cx, JSObject *scopeobj, JSProtoKey protoKey,
return FindClassPrototype(cx, scopeobj, protoKey, protop, clasp);
}
/*
* For shared precompilation of function objects, we support cloning on entry
* to an execution context in which the function declaration or expression
* should be processed as if it were not precompiled, where the precompiled
* function's scope chain does not match the execution context's. The cloned
* function object carries its execution-context scope in its parent slot; it
* links to the precompiled function (the "clone-parent") via its proto slot.
*
* Note that this prototype-based delegation leaves an unchecked access path
* from the clone to the clone-parent's 'constructor' property. If the clone
* lives in a less privileged or shared scope than the clone-parent, this is
* a security hole, a sharing hazard, or both. Therefore we check all such
* accesses with the following getter/setter pair, which we use when defining
* 'constructor' in f.prototype for all function objects f.
*/
static JSBool
CheckCtorGetAccess(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{
JSAtom *atom = cx->runtime->atomState.constructorAtom;
JS_ASSERT(id == ATOM_TO_JSID(atom));
uintN attrs;
return CheckAccess(cx, obj, ATOM_TO_JSID(atom), JSACC_READ, vp, &attrs);
}
static JSBool
CheckCtorSetAccess(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{
JSAtom *atom = cx->runtime->atomState.constructorAtom;
JS_ASSERT(id == ATOM_TO_JSID(atom));
uintN attrs;
return CheckAccess(cx, obj, ATOM_TO_JSID(atom), JSACC_WRITE, vp, &attrs);
}
JSBool
js_SetClassPrototype(JSContext *cx, JSObject *ctor, JSObject *proto, uintN attrs)
{
@ -5889,7 +5879,7 @@ js_SetClassPrototype(JSContext *cx, JSObject *ctor, JSObject *proto, uintN attrs
* for a user-defined function f, is DontEnum.
*/
return proto->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.constructorAtom),
ObjectOrNullValue(ctor), CheckCtorGetAccess, CheckCtorSetAccess, 0);
ObjectOrNullValue(ctor), PropertyStub, PropertyStub, 0);
}
JSBool
@ -6138,7 +6128,7 @@ js_PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize)
if (JSID_IS_INT(id)) {
JS_snprintf(buf, bufsize, "%ld", (long)JSID_TO_INT(id));
} else if (JSID_IS_ATOM(id)) {
js_PutEscapedString(buf, bufsize, JSID_TO_STRING(id), 0);
PutEscapedString(buf, bufsize, JSID_TO_STRING(id), 0);
} else {
JS_snprintf(buf, bufsize, "**FINALIZED ATOM KEY**");
}
@ -6366,11 +6356,13 @@ dumpValue(const Value &v)
else if (v.isObject() && v.toObject().isFunction()) {
JSObject *funobj = &v.toObject();
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
fprintf(stderr, "<%s %s at %p (JSFunction at %p)>",
fun->atom ? "function" : "unnamed",
fun->atom ? JS_GetStringBytes(ATOM_TO_STRING(fun->atom)) : "function",
(void *) funobj,
(void *) fun);
if (fun->atom) {
fputs("<function ", stderr);
FileEscapedString(stderr, ATOM_TO_STRING(fun->atom), 0);
} else {
fputs("<unnamed function", stderr);
}
fprintf(stderr, " at %p (JSFunction at %p)>", (void *) funobj, (void *) fun);
} else if (v.isObject()) {
JSObject *obj = &v.toObject();
Class *clasp = obj->getClass();

View File

@ -176,11 +176,11 @@ typedef Vector<PropDesc, 1> PropDescArray;
} /* namespace js */
struct JSObjectMap {
static JS_FRIEND_DATA(const JSObjectMap) sharedNonNative;
uint32 shape; /* shape identifier */
uint32 slotSpan; /* one more than maximum live slot number */
static JS_FRIEND_DATA(const JSObjectMap) sharedNonNative;
explicit JSObjectMap(uint32 shape) : shape(shape), slotSpan(0) {}
JSObjectMap(uint32 shape, uint32 slotSpan) : shape(shape), slotSpan(slotSpan) {}
@ -220,7 +220,7 @@ js_GetProperty(JSContext *cx, JSObject *obj, jsid id, js::Value *vp)
namespace js {
extern JSBool
GetPropertyDefault(JSContext *cx, JSObject *obj, jsid id, Value def, Value *vp);
GetPropertyDefault(JSContext *cx, JSObject *obj, jsid id, const Value &def, Value *vp);
} /* namespace js */
@ -404,6 +404,7 @@ struct JSObject : js::gc::Cell {
bool isDelegate() const { return !!(flags & DELEGATE); }
void setDelegate() { flags |= DELEGATE; }
void clearDelegate() { flags &= ~DELEGATE; }
bool isBoundFunction() const { return !!(flags & BOUND_FUNCTION); }
@ -422,14 +423,20 @@ struct JSObject : js::gc::Cell {
*/
bool branded() { return !!(flags & BRANDED); }
bool brand(JSContext *cx, uint32 slot, js::Value v);
bool brand(JSContext *cx);
bool unbrand(JSContext *cx);
bool generic() { return !!(flags & GENERIC); }
void setGeneric() { flags |= GENERIC; }
bool hasSpecialEquality() { return !!(flags & HAS_EQUALITY); }
bool hasSpecialEquality() const { return !!(flags & HAS_EQUALITY); }
void assertSpecialEqualitySynced() const {
JS_ASSERT(!!clasp->ext.equality == hasSpecialEquality());
}
/* Sets an object's HAS_EQUALITY flag based on its clasp. */
inline void syncSpecialEquality();
private:
void generateOwnShape(JSContext *cx);
@ -701,22 +708,24 @@ struct JSObject : js::gc::Cell {
*/
private:
enum ImmutabilityType { SEAL, FREEZE };
/*
* The guts of Object.seal (ES5 15.2.3.8) and Object.freeze (ES5 15.2.3.9): mark the
* object as non-extensible, and adjust each property's attributes appropriately: each
* property becomes non-configurable, and if |freeze|, data properties become
* read-only as well.
*/
bool sealOrFreeze(JSContext *cx, bool freeze = false);
bool sealOrFreeze(JSContext *cx, ImmutabilityType it);
public:
bool isExtensible() const { return !(flags & NOT_EXTENSIBLE); }
bool preventExtensions(JSContext *cx, js::AutoIdVector *props);
/* ES5 15.2.3.8: non-extensible, all props non-configurable */
inline bool seal(JSContext *cx) { return sealOrFreeze(cx); }
inline bool seal(JSContext *cx) { return sealOrFreeze(cx, SEAL); }
/* ES5 15.2.3.9: non-extensible, all properties non-configurable, all data props read-only */
bool freeze(JSContext *cx) { return sealOrFreeze(cx, true); }
bool freeze(JSContext *cx) { return sealOrFreeze(cx, FREEZE); }
/*
* Primitive-specific getters and setters.
@ -805,6 +814,7 @@ struct JSObject : js::gc::Cell {
inline void setArgsCallee(const js::Value &callee);
inline const js::Value &getArgsElement(uint32 i) const;
inline js::Value *getArgsElements() const;
inline js::Value *addressOfArgsElement(uint32 i);
inline void setArgsElement(uint32 i, const js::Value &v);
@ -980,7 +990,7 @@ struct JSObject : js::gc::Cell {
void *priv, bool useHoles);
inline void finish(JSContext *cx);
JS_ALWAYS_INLINE void finalize(JSContext *cx, unsigned thindKind);
JS_ALWAYS_INLINE void finalize(JSContext *cx);
/*
* Like init, but also initializes map. The catch: proto must be the result
@ -1612,7 +1622,14 @@ js_SetNativeAttributes(JSContext *cx, JSObject *obj, js::Shape *shape,
namespace js {
extern JSBool
/*
* If obj has a data property methodid which is a function object for the given
* native, return that function object. Otherwise, return NULL.
*/
extern JSObject *
HasNativeMethod(JSObject *obj, jsid methodid, Native native);
extern bool
DefaultValue(JSContext *cx, JSObject *obj, JSType hint, Value *vp);
extern JSBool

View File

@ -89,7 +89,7 @@ JSObject::preventExtensions(JSContext *cx, js::AutoIdVector *props)
}
inline bool
JSObject::brand(JSContext *cx, uint32 slot, js::Value v)
JSObject::brand(JSContext *cx)
{
JS_ASSERT(!generic());
JS_ASSERT(!branded());
@ -111,11 +111,15 @@ JSObject::unbrand(JSContext *cx)
}
inline void
JSObject::finalize(JSContext *cx, unsigned thingKind)
JSObject::syncSpecialEquality()
{
JS_ASSERT(thingKind >= js::gc::FINALIZE_OBJECT0 &&
thingKind <= js::gc::FINALIZE_FUNCTION);
if (clasp->ext.equality)
flags |= JSObject::HAS_EQUALITY;
}
inline void
JSObject::finalize(JSContext *cx)
{
/* Cope with stillborn objects that have no map. */
if (!map)
return;
@ -402,6 +406,13 @@ JSObject::getArgsElement(uint32 i) const
return getArgsData()->slots[i];
}
inline js::Value *
JSObject::getArgsElements() const
{
JS_ASSERT(isArguments());
return getArgsData()->slots;
}
inline js::Value *
JSObject::addressOfArgsElement(uint32 i)
{

View File

@ -225,9 +225,8 @@ js_GetVariableStackUses(JSOp op, jsbytecode *pc)
return GET_UINT16(pc);
default:
/* stack: fun, this, [argc arguments] */
JS_ASSERT(op == JSOP_NEW || op == JSOP_CALL ||
op == JSOP_EVAL || op == JSOP_SETCALL ||
op == JSOP_APPLY);
JS_ASSERT(op == JSOP_NEW || op == JSOP_CALL || op == JSOP_EVAL ||
op == JSOP_FUNCALL || op == JSOP_FUNAPPLY);
return 2 + GET_ARGC(pc);
}
}
@ -290,8 +289,8 @@ js_DumpScript(JSContext *cx, JSScript *script)
return js_Disassemble(cx, script, true, stdout);
}
const char *
ToDisassemblySource(JSContext *cx, jsval v)
static bool
ToDisassemblySource(JSContext *cx, jsval v, JSAutoByteString *bytes)
{
if (!JSVAL_IS_PRIMITIVE(v)) {
JSObject *obj = JSVAL_TO_OBJECT(v);
@ -303,13 +302,13 @@ ToDisassemblySource(JSContext *cx, jsval v)
Shape::Range r = obj->lastProperty()->all();
while (!r.empty()) {
const Shape &shape = r.front();
const char *bytes = js_AtomToPrintableString(cx, JSID_TO_ATOM(shape.id));
if (!bytes)
JSAutoByteString bytes;
if (!js_AtomToPrintableString(cx, JSID_TO_ATOM(shape.id), &bytes))
return NULL;
r.popFront();
source = JS_sprintf_append(source, "%s: %d%s",
bytes, shape.shortid,
bytes.ptr(), shape.shortid,
!r.empty() ? ", " : "");
}
@ -320,7 +319,7 @@ ToDisassemblySource(JSContext *cx, jsval v)
JSString *str = JS_NewString(cx, source, strlen(source));
if (!str)
return NULL;
return js_GetStringBytes(cx, str);
return bytes->encode(cx, str);
}
if (clasp == &js_FunctionClass) {
@ -328,18 +327,18 @@ ToDisassemblySource(JSContext *cx, jsval v)
JSString *str = JS_DecompileFunction(cx, fun, JS_DONT_PRETTY_PRINT);
if (!str)
return NULL;
return js_GetStringBytes(cx, str);
return bytes->encode(cx, str);
}
if (clasp == &js_RegExpClass) {
AutoValueRooter tvr(cx);
if (!js_regexp_toString(cx, obj, tvr.addr()))
return NULL;
return js_GetStringBytes(cx, JSVAL_TO_STRING(Jsvalify(tvr.value())));
return bytes->encode(cx, JSVAL_TO_STRING(Jsvalify(tvr.value())));
}
}
return js_ValueToPrintableSource(cx, Valueify(v));
return !!js_ValueToPrintable(cx, Valueify(v), bytes, true);
}
JS_FRIEND_API(uintN)
@ -354,7 +353,6 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc,
uintN index;
JSObject *obj;
jsval v;
const char *bytes;
jsint i;
op = (JSOp)*pc;
@ -405,19 +403,23 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc,
obj = script->getRegExp(index);
v = OBJECT_TO_JSVAL(obj);
}
bytes = ToDisassemblySource(cx, v);
if (!bytes)
return 0;
fprintf(fp, " %s", bytes);
{
JSAutoByteString bytes;
if (!ToDisassemblySource(cx, v, &bytes))
return 0;
fprintf(fp, " %s", bytes.ptr());
}
break;
case JOF_GLOBAL:
atom = script->getGlobalAtom(GET_SLOTNO(pc));
v = ATOM_TO_JSVAL(atom);
bytes = ToDisassemblySource(cx, v);
if (!bytes)
return 0;
fprintf(fp, " %s", bytes);
{
JSAutoByteString bytes;
if (!ToDisassemblySource(cx, v, &bytes))
return 0;
fprintf(fp, " %s", bytes.ptr());
}
break;
case JOF_UINT16PAIR:
@ -475,10 +477,10 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc,
off = GetJumpOffset(pc, pc2);
pc2 += jmplen;
bytes = ToDisassemblySource(cx, Jsvalify(script->getConst(constIndex)));
if (!bytes)
JSAutoByteString bytes;
if (!ToDisassemblySource(cx, Jsvalify(script->getConst(constIndex)), &bytes))
return 0;
fprintf(fp, "\n\t%s: %d", bytes, (intN) off);
fprintf(fp, "\n\t%s: %d", bytes.ptr(), (intN) off);
npairs--;
}
len = 1 + pc2 - pc;
@ -494,7 +496,7 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc,
break;
case JOF_SLOTATOM:
case JOF_SLOTOBJECT:
case JOF_SLOTOBJECT: {
fprintf(fp, " %u", GET_SLOTNO(pc));
index = js_GetIndexFromBytecode(cx, script, pc, SLOTNO_LEN);
if (type == JOF_SLOTATOM) {
@ -504,11 +506,13 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc,
obj = script->getObject(index);
v = OBJECT_TO_JSVAL(obj);
}
bytes = ToDisassemblySource(cx, v);
if (!bytes)
JSAutoByteString bytes;
if (!ToDisassemblySource(cx, v, &bytes))
return 0;
fprintf(fp, " %s", bytes);
fprintf(fp, " %s", bytes.ptr());
break;
}
case JOF_UINT24:
JS_ASSERT(op == JSOP_UINT24 || op == JSOP_NEWARRAY);
@ -1462,10 +1466,13 @@ DecompileDestructuringLHS(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc,
} else {
lval = GetLocal(ss, i);
}
if (atom)
lval = js_AtomToPrintableString(cx, atom);
LOCAL_ASSERT(lval);
todo = SprintCString(&ss->sprinter, lval);
{
JSAutoByteString bytes;
if (atom)
lval = js_AtomToPrintableString(cx, atom, &bytes);
LOCAL_ASSERT(lval);
todo = SprintCString(&ss->sprinter, lval);
}
if (op != JSOP_SETLOCALPOP) {
pc += oplen;
if (pc == endpc)
@ -1948,7 +1955,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
JS_BEGIN_MACRO \
if (ss->opcodes[ss->top - 1] == JSOP_CALL || \
ss->opcodes[ss->top - 1] == JSOP_EVAL || \
ss->opcodes[ss->top - 1] == JSOP_APPLY) { \
ss->opcodes[ss->top - 1] == JSOP_FUNCALL || \
ss->opcodes[ss->top - 1] == JSOP_FUNAPPLY) { \
saveop = JSOP_CALL; \
} \
JS_END_MACRO
@ -2075,9 +2083,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case JSOP_ENUMCONSTELEM:
op = JSOP_GETELEM;
break;
case JSOP_SETCALL:
op = JSOP_CALL;
break;
case JSOP_GETTHISPROP:
/*
* NB: JSOP_GETTHISPROP can't fail due to |this|
@ -3586,8 +3591,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case JSOP_NEW:
case JSOP_CALL:
case JSOP_EVAL:
case JSOP_APPLY:
case JSOP_SETCALL:
case JSOP_FUNCALL:
case JSOP_FUNAPPLY:
argc = GET_ARGC(pc);
argv = (char **)
cx->malloc((size_t)(argc + 1) * sizeof *argv);
@ -3613,7 +3618,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
(saveop == JSOP_NEW &&
(op == JSOP_CALL ||
op == JSOP_EVAL ||
op == JSOP_APPLY ||
op == JSOP_FUNCALL ||
op == JSOP_FUNAPPLY ||
(js_CodeSpec[op].format & JOF_CALLOP)))
? JSOP_NAME
: saveop);
@ -3652,11 +3658,10 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
cx->free(argv);
if (!ok)
return NULL;
if (op == JSOP_SETCALL) {
if (!PushOff(ss, todo, op))
return NULL;
todo = Sprint(&ss->sprinter, "");
}
break;
case JSOP_SETCALL:
todo = Sprint(&ss->sprinter, "");
break;
case JSOP_DELNAME:
@ -4112,10 +4117,9 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
pc += len;
if (*pc == JSOP_BLOCKCHAIN) {
pc += JSOP_BLOCKCHAIN_LENGTH;
} else if (*pc == JSOP_NULLBLOCKCHAIN) {
pc += JSOP_NULLBLOCKCHAIN_LENGTH;
} else {
JS_NOT_REACHED("should see block chain operation");
LOCAL_ASSERT(*pc == JSOP_NULLBLOCKCHAIN);
pc += JSOP_NULLBLOCKCHAIN_LENGTH;
}
LOCAL_ASSERT(*pc == JSOP_PUSH);
pc += JSOP_PUSH_LENGTH;

View File

@ -201,9 +201,9 @@ OPDEF(JSOP_STRICTNE, 73, "strictne", "!==", 1, 2, 1, 10, JOF_BYTE|J
/*
* Host object extension: given 'o.item(i) = j', the left-hand side compiles
* JSOP_SETCALL, rather than JSOP_CALL.
* JSOP_SETCALL after JSOP_CALL, JSOP_EVAL, JSOP_FUNAPPLY, or JSOP_FUNCALL.
*/
OPDEF(JSOP_SETCALL, 74, "setcall", NULL, 3, -1, 2, 18, JOF_UINT16|JOF_SET)
OPDEF(JSOP_SETCALL, 74, "setcall", NULL, 1, 1, 2, 18, JOF_BYTE)
/*
* JSOP_ITER sets up a for-in or for-each-in loop using the JSITER_* flag bits
@ -221,7 +221,7 @@ OPDEF(JSOP_ITER, 75, "iter", NULL, 2, 1, 1, 0, JOF_UINT8)
OPDEF(JSOP_MOREITER, 76, "moreiter", NULL, 1, 1, 2, 0, JOF_BYTE)
OPDEF(JSOP_ENDITER, 77, "enditer", NULL, 1, 1, 0, 0, JOF_BYTE)
OPDEF(JSOP_APPLY, 78, "apply", NULL, 3, -1, 1, 18, JOF_UINT16|JOF_INVOKE)
OPDEF(JSOP_FUNAPPLY, 78, "funapply", NULL, 3, -1, 1, 18, JOF_UINT16|JOF_INVOKE)
OPDEF(JSOP_SWAP, 79, "swap", NULL, 1, 2, 2, 0, JOF_BYTE)
/* Push object literal. */
@ -254,10 +254,10 @@ OPDEF(JSOP_DEFSHARP, 93, "defsharp", NULL, 5, 0, 0, 0, JOF_UINT16
OPDEF(JSOP_USESHARP, 94, "usesharp", NULL, 5, 0, 1, 0, JOF_UINT16PAIR|JOF_SHARPSLOT)
/* Fast inc/dec ops for args and locals. */
OPDEF(JSOP_INCARG, 95, "incarg", NULL, 3, 0, 1, 15, JOF_QARG |JOF_NAME|JOF_INC|JOF_TMPSLOT2)
OPDEF(JSOP_DECARG, 96, "decarg", NULL, 3, 0, 1, 15, JOF_QARG |JOF_NAME|JOF_DEC|JOF_TMPSLOT2)
OPDEF(JSOP_ARGINC, 97, "arginc", NULL, 3, 0, 1, 15, JOF_QARG |JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT2)
OPDEF(JSOP_ARGDEC, 98, "argdec", NULL, 3, 0, 1, 15, JOF_QARG |JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT2)
OPDEF(JSOP_INCARG, 95, "incarg", NULL, 3, 0, 1, 15, JOF_QARG |JOF_NAME|JOF_INC|JOF_TMPSLOT3)
OPDEF(JSOP_DECARG, 96, "decarg", NULL, 3, 0, 1, 15, JOF_QARG |JOF_NAME|JOF_DEC|JOF_TMPSLOT3)
OPDEF(JSOP_ARGINC, 97, "arginc", NULL, 3, 0, 1, 15, JOF_QARG |JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT3)
OPDEF(JSOP_ARGDEC, 98, "argdec", NULL, 3, 0, 1, 15, JOF_QARG |JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT3)
OPDEF(JSOP_INCLOCAL, 99, "inclocal", NULL, 3, 0, 1, 15, JOF_LOCAL|JOF_NAME|JOF_INC|JOF_TMPSLOT3)
OPDEF(JSOP_DECLOCAL, 100,"declocal", NULL, 3, 0, 1, 15, JOF_LOCAL|JOF_NAME|JOF_DEC|JOF_TMPSLOT3)
@ -455,7 +455,7 @@ OPDEF(JSOP_UINT24, 188,"uint24", NULL, 4, 0, 1, 16, JOF_UINT24
* JSOP_INDEXBASE and JSOP_RESETBASE to provide the upper bits of the index.
* See jsemit.c, EmitIndexOp.
*/
OPDEF(JSOP_INDEXBASE, 189,"atombase", NULL, 2, 0, 0, 0, JOF_UINT8|JOF_INDEXBASE)
OPDEF(JSOP_INDEXBASE, 189,"indexbase", NULL, 2, 0, 0, 0, JOF_UINT8|JOF_INDEXBASE)
OPDEF(JSOP_RESETBASE, 190,"resetbase", NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_RESETBASE0, 191,"resetbase0", NULL, 1, 0, 0, 0, JOF_BYTE)
@ -532,9 +532,9 @@ OPDEF(JSOP_GETLOCALPROP, 211,"getlocalprop", NULL, 5, 0, 1, 18, JOF_SLOTAT
* Optimize atom segments 1-3. These must be followed by JSOP_RESETBASE0 after
* the opcode that they prefix.
*/
OPDEF(JSOP_INDEXBASE1, 212,"atombase1", NULL, 1, 0, 0, 0, JOF_BYTE |JOF_INDEXBASE)
OPDEF(JSOP_INDEXBASE2, 213,"atombase2", NULL, 1, 0, 0, 0, JOF_BYTE |JOF_INDEXBASE)
OPDEF(JSOP_INDEXBASE3, 214,"atombase3", NULL, 1, 0, 0, 0, JOF_BYTE |JOF_INDEXBASE)
OPDEF(JSOP_INDEXBASE1, 212,"indexbase1", NULL, 1, 0, 0, 0, JOF_BYTE |JOF_INDEXBASE)
OPDEF(JSOP_INDEXBASE2, 213,"indexbase2", NULL, 1, 0, 0, 0, JOF_BYTE |JOF_INDEXBASE)
OPDEF(JSOP_INDEXBASE3, 214,"indexbase3", NULL, 1, 0, 0, 0, JOF_BYTE |JOF_INDEXBASE)
OPDEF(JSOP_CALLGNAME, 215, "callgname", NULL, 3, 0, 2, 19, JOF_ATOM|JOF_NAME|JOF_CALLOP|JOF_GNAME)
OPDEF(JSOP_CALLLOCAL, 216, "calllocal", NULL, 3, 0, 2, 19, JOF_LOCAL|JOF_NAME|JOF_CALLOP)
@ -624,4 +624,7 @@ OPDEF(JSOP_FORGLOBAL, 246,"forglobal", NULL, 3, 1, 1, 19, JOF_GLOBAL
OPDEF(JSOP_BLOCKCHAIN, 247,"blockchain", NULL, 3, 0, 0, 0, JOF_OBJECT)
OPDEF(JSOP_NULLBLOCKCHAIN,248,"nullblockchain",NULL, 1, 0, 0, 0, JOF_BYTE)
/* Like JSOP_FUNAPPLY but for f.call instead of f.apply. */
OPDEF(JSOP_FUNCALL, 249,"funcall", NULL, 3, -1, 1, 18, JOF_UINT16|JOF_INVOKE)
/* When changing bytecodes, don't forget to update JSXDR_BYTECODE_VERSION. */

View File

@ -13,12 +13,11 @@
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
* The Original Code is the Mozilla SpiderMonkey JaegerMonkey implementation
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2002-2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
@ -39,13 +38,20 @@
#include "jsautooplen.h"
namespace js {
/*
* Warning: this does not skip JSOP_RESETBASE* or JSOP_INDEXBASE* ops, so it is
* useful only when checking for optimization opportunities.
*/
JS_ALWAYS_INLINE jsbytecode *
js_AdvanceOverBlockchain(jsbytecode *pc)
AdvanceOverBlockchainOp(jsbytecode *pc)
{
if (*pc == JSOP_NULLBLOCKCHAIN)
return pc + JSOP_NULLBLOCKCHAIN_LENGTH;
else if (*pc == JSOP_BLOCKCHAIN)
if (*pc == JSOP_BLOCKCHAIN)
return pc + JSOP_BLOCKCHAIN_LENGTH;
else
return pc;
return pc;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -504,8 +504,8 @@ public:
#define PNX_XMLROOT 0x20 /* top-most node in XML literal tree */
#define PNX_GROUPINIT 0x40 /* var [a, b] = [c, d]; unit list */
#define PNX_NEEDBRACES 0x80 /* braces necessary due to closure */
#define PNX_FUNCDEFS 0x100 /* contains top-level function
statements */
#define PNX_FUNCDEFS 0x100 /* contains top-level function statements */
#define PNX_SETCALL 0x100 /* call expression in lvalue context */
#define PNX_DESTRUCT 0x200 /* destructuring special cases:
1. shorthand syntax used, at present
object destructuring ({x,y}) only;
@ -1088,6 +1088,14 @@ private:
JSParseNode *functionExpr();
JSParseNode *statements();
JSParseNode *statement();
JSParseNode *switchStatement();
JSParseNode *forStatement();
JSParseNode *tryStatement();
JSParseNode *withStatement();
#if JS_HAS_BLOCK_SCOPE
JSParseNode *letStatement();
#endif
JSParseNode *expressionStatement();
JSParseNode *variables(bool inLetHead);
JSParseNode *expr();
JSParseNode *assignExpr();

View File

@ -124,7 +124,7 @@ jsprobes_jsvaltovoid(JSContext *cx, const js::Value &argval)
#endif
const char *
Probes::FunctionName(JSContext *cx, const JSFunction *fun)
Probes::FunctionName(JSContext *cx, const JSFunction *fun, JSAutoByteString *bytes)
{
if (!fun)
return nullName;
@ -139,8 +139,7 @@ Probes::FunctionName(JSContext *cx, const JSFunction *fun)
return nullName;
}
char *name = (char *)js_GetStringBytes(cx, ATOM_TO_STRING(atom));
return name ? name : nullName;
return bytes->encode(cx, ATOM_TO_STRING(atom)) ? bytes->ptr() : nullName;
}
#ifdef INCLUDE_MOZILLA_DTRACE
@ -152,16 +151,16 @@ Probes::FunctionName(JSContext *cx, const JSFunction *fun)
* a number of usually unused lines of code would cause.
*/
void
Probes::enterJSFunImpl(JSContext *cx, const JSFunction *fun)
Probes::enterJSFunImpl(JSContext *cx, JSFunction *fun, JSScript *script)
{
JAVASCRIPT_FUNCTION_ENTRY(ScriptFilename(FUN_SCRIPT(fun)), FunctionClassname(fun),
JAVASCRIPT_FUNCTION_ENTRY(ScriptFilename(script), FunctionClassname(fun),
FunctionName(cx, fun));
}
void
Probes::handleFunctionReturn(JSContext *cx, JSFunction *fun)
Probes::handleFunctionReturn(JSContext *cx, JSFunction *fun, JSScript *script)
{
JAVASCRIPT_FUNCTION_RETURN(ScriptFilename(FUN_SCRIPT(fun)), FunctionClassname(fun),
JAVASCRIPT_FUNCTION_RETURN(ScriptFilename(script), FunctionClassname(fun),
FunctionName(cx, fun));
}

View File

@ -50,18 +50,16 @@ class Probes {
static const char *FunctionClassname(const JSFunction *fun);
static const char *ScriptFilename(JSScript *script);
static int FunctionLineNumber(JSContext *cx, const JSFunction *fun);
static const char *FunctionName(JSContext *cx, const JSFunction *fun);
static const char *FunctionName(JSContext *cx, const JSFunction *fun, JSAutoByteString *bytes);
static void enterJSFunImpl(JSContext *cx, const JSFunction *fun);
static void handleFunctionReturn(JSContext *cx, JSFunction *fun);
static void enterJSFunImpl(JSContext *cx, JSFunction *fun, JSScript *script);
static void handleFunctionReturn(JSContext *cx, JSFunction *fun, JSScript *script);
static void finalizeObjectImpl(JSObject *obj);
public:
/*
* If |lval| is provided to the enter/exit methods, it is tested to see if
* it is a function as a predicate to the dtrace event emission.
*/
static void enterJSFun(JSContext *cx, JSFunction *fun, js::Value *lval = NULL);
static void exitJSFun(JSContext *cx, JSFunction *fun, js::Value *lval = NULL);
static bool callTrackingActive(JSContext *);
static void enterJSFun(JSContext *, JSFunction *, JSScript *, int counter = 1);
static void exitJSFun(JSContext *, JSFunction *, JSScript *, int counter = 0);
static void startExecution(JSContext *cx, JSScript *script);
static void stopExecution(JSContext *cx, JSScript *script);
@ -113,31 +111,47 @@ class Probes {
static JSBool CustomMark(int marker);
};
inline void
Probes::enterJSFun(JSContext *cx, JSFunction *fun, js::Value *lval)
inline bool
Probes::callTrackingActive(JSContext *cx)
{
#ifdef INCLUDE_MOZILLA_DTRACE
if (!lval || IsFunctionObject(*lval)) {
if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED())
enterJSFunImpl(cx, fun);
}
if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED() || JAVASCRIPT_FUNCTION_RETURN_ENABLED())
return true;
#endif
#ifdef MOZ_TRACE_JSCALLS
cx->doFunctionCallback(fun, fun ? FUN_SCRIPT(fun) : NULL, true);
if (cx->functionCallback)
return true;
#endif
#ifdef MOZ_ETW
if (ProfilingActive && MCGEN_ENABLE_CHECK(MozillaSpiderMonkey_Context, EvtFunctionEntry))
return true;
#endif
return false;
}
inline void
Probes::enterJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter)
{
#ifdef INCLUDE_MOZILLA_DTRACE
if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED())
enterJSFunImpl(cx, fun, script);
#endif
#ifdef MOZ_TRACE_JSCALLS
cx->doFunctionCallback(fun, script, counter);
#endif
}
inline void
Probes::exitJSFun(JSContext *cx, JSFunction *fun, js::Value *lval)
Probes::exitJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter)
{
#ifdef INCLUDE_MOZILLA_DTRACE
if (!lval || IsFunctionObject(*lval)) {
if (JAVASCRIPT_FUNCTION_RETURN_ENABLED())
handleFunctionReturn(cx, fun);
}
if (JAVASCRIPT_FUNCTION_RETURN_ENABLED())
handleFunctionReturn(cx, fun, script);
#endif
#ifdef MOZ_TRACE_JSCALLS
cx->doFunctionCallback(fun, fun ? FUN_SCRIPT(fun) : NULL, false);
if (counter > 0)
counter = -counter;
cx->doFunctionCallback(fun, script, counter);
#endif
}
@ -170,11 +184,11 @@ Probes::startExecution(JSContext *cx, JSScript *script)
{
#ifdef INCLUDE_MOZILLA_DTRACE
if (JAVASCRIPT_EXECUTE_START_ENABLED())
JAVASCRIPT_EXECUTE_START(script->filename ? (char *)script->filename : nullName,
JAVASCRIPT_EXECUTE_START((script->filename ? (char *)script->filename : nullName),
script->lineno);
#endif
#ifdef MOZ_TRACE_JSCALLS
cx->doFunctionCallback(NULL, script, true);
cx->doFunctionCallback(NULL, script, 1);
#endif
}
@ -183,11 +197,11 @@ Probes::stopExecution(JSContext *cx, JSScript *script)
{
#ifdef INCLUDE_MOZILLA_DTRACE
if (JAVASCRIPT_EXECUTE_DONE_ENABLED())
JAVASCRIPT_EXECUTE_DONE(script->filename ? (char *)script->filename : nullName,
JAVASCRIPT_EXECUTE_DONE((script->filename ? (char *)script->filename : nullName),
script->lineno);
#endif
#ifdef MOZ_TRACE_JSCALLS
cx->doFunctionCallback(NULL, script, false);
cx->doFunctionCallback(NULL, script, 0);
#endif
}
@ -219,19 +233,19 @@ inline JSBool Probes::CustomMark(int marker) { return JS_TRUE; }
struct AutoFunctionCallProbe {
JSContext * const cx;
JSFunction *fun;
js::Value *lval;
JSScript *script;
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
AutoFunctionCallProbe(JSContext *cx, JSFunction *fun, js::Value *lval = NULL
AutoFunctionCallProbe(JSContext *cx, JSFunction *fun, JSScript *script
JS_GUARD_OBJECT_NOTIFIER_PARAM)
: cx(cx), fun(fun), lval(lval)
: cx(cx), fun(fun), script(script)
{
JS_GUARD_OBJECT_NOTIFIER_INIT;
Probes::enterJSFun(cx, fun, lval);
Probes::enterJSFun(cx, fun, script);
}
~AutoFunctionCallProbe() {
Probes::exitJSFun(cx, fun, lval);
Probes::exitJSFun(cx, fun, script);
}
};

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