mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
Merge tracemonkey to mozilla-centra. a=blockers.
This commit is contained in:
commit
4945f654ff
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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(),
|
||||
|
@ -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"
|
||||
%}
|
||||
|
@ -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)
|
||||
|
@ -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__ */
|
||||
|
@ -120,6 +120,7 @@ _SUBDIR_TEST_FILES = \
|
||||
|
||||
_CHROME_TEST_FILES = \
|
||||
test_chromeWorker.xul \
|
||||
test_chromeWorkerComponent.xul \
|
||||
chromeWorker_worker.js \
|
||||
chromeWorker_subworker.js \
|
||||
$(NULL)
|
||||
|
@ -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>
|
||||
|
82
dom/src/threads/test/test_chromeWorkerComponent.xul
Normal file
82
dom/src/threads/test/test_chromeWorkerComponent.xul
Normal 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>
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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") ||
|
||||
|
@ -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)
|
||||
|
@ -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
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
3
js/src/jit-test/tests/basic/bug582161.js
Normal file
3
js/src/jit-test/tests/basic/bug582161.js
Normal 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]);
|
13
js/src/jit-test/tests/basic/bug584603.js
Normal file
13
js/src/jit-test/tests/basic/bug584603.js
Normal 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);
|
11
js/src/jit-test/tests/basic/bug608313.js
Normal file
11
js/src/jit-test/tests/basic/bug608313.js
Normal 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);
|
||||
}
|
||||
|
||||
|
11
js/src/jit-test/tests/basic/bug608980.js
Normal file
11
js/src/jit-test/tests/basic/bug608980.js
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
/* Don't trip bogus assert. */
|
||||
|
||||
function foo()
|
||||
{
|
||||
var x;
|
||||
while (x = 0) {
|
||||
x = 1;
|
||||
}
|
||||
}
|
||||
foo();
|
29
js/src/jit-test/tests/basic/bug610592.js
Normal file
29
js/src/jit-test/tests/basic/bug610592.js
Normal 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();
|
16
js/src/jit-test/tests/basic/testBug586866.js
Normal file
16
js/src/jit-test/tests/basic/testBug586866.js
Normal 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);
|
10
js/src/jit-test/tests/basic/testBug593559.js
Normal file
10
js/src/jit-test/tests/basic/testBug593559.js
Normal 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");
|
||||
|
45
js/src/jit-test/tests/basic/testBug602413.js
Normal file
45
js/src/jit-test/tests/basic/testBug602413.js
Normal 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();
|
||||
|
12
js/src/jit-test/tests/basic/testBug603193.js
Normal file
12
js/src/jit-test/tests/basic/testBug603193.js
Normal 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")
|
8
js/src/jit-test/tests/basic/testBug607659.js
Normal file
8
js/src/jit-test/tests/basic/testBug607659.js
Normal 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);
|
168
js/src/jit-test/tests/basic/testCallApply.js
Normal file
168
js/src/jit-test/tests/basic/testCallApply.js
Normal 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"));
|
||||
}
|
@ -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);
|
@ -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"
|
||||
|
10
js/src/jit-test/tests/basic/testWhileWithContinue.js
Normal file
10
js/src/jit-test/tests/basic/testWhileWithContinue.js
Normal 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);
|
||||
|
@ -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");
|
14
js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js
Normal file
14
js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js
Normal 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");
|
8
js/src/jit-test/tests/jaeger/bug601400.js
Normal file
8
js/src/jit-test/tests/jaeger/bug601400.js
Normal file
@ -0,0 +1,8 @@
|
||||
// |jit-test| error: TypeError
|
||||
|
||||
eval("\
|
||||
function NaN() {}\
|
||||
for(w in s) {}\
|
||||
")
|
||||
|
||||
// Don't assert.
|
5
js/src/jit-test/tests/jaeger/bug606662-1.js
Normal file
5
js/src/jit-test/tests/jaeger/bug606662-1.js
Normal file
@ -0,0 +1,5 @@
|
||||
// don't assert
|
||||
new(function() {
|
||||
#1#
|
||||
})
|
||||
|
5
js/src/jit-test/tests/jaeger/bug606662-2.js
Normal file
5
js/src/jit-test/tests/jaeger/bug606662-2.js
Normal 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){}
|
5
js/src/jit-test/tests/jaeger/bug610652.js
Normal file
5
js/src/jit-test/tests/jaeger/bug610652.js
Normal file
@ -0,0 +1,5 @@
|
||||
function a1(a2) {
|
||||
return 10 - a2;
|
||||
}
|
||||
a3 = a1(-2147483648);
|
||||
assertEq(a3, 2147483658);
|
9
js/src/jit-test/tests/jaeger/optimize-globals-1.js
Normal file
9
js/src/jit-test/tests/jaeger/optimize-globals-1.js
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
function testLocalNames() {
|
||||
var NaN = 4;
|
||||
var undefined = 5;
|
||||
var Infinity = 6;
|
||||
return NaN + undefined + Infinity;
|
||||
}
|
||||
assertEq(testLocalNames(), 15);
|
||||
|
20
js/src/jit-test/tests/jaeger/optimize-globals-2.js
Normal file
20
js/src/jit-test/tests/jaeger/optimize-globals-2.js
Normal 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);
|
9
js/src/jit-test/tests/jaeger/optimize-globals-3.js
Normal file
9
js/src/jit-test/tests/jaeger/optimize-globals-3.js
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
NaN = 4;
|
||||
undefined = 5;
|
||||
Infinity = 6;
|
||||
|
||||
assertEq(isNaN(NaN), true);
|
||||
assertEq(Infinity > 100, true);
|
||||
assertEq(undefined != 5, true);
|
||||
|
20
js/src/jit-test/tests/jaeger/testCallElemAfterGC.js
Normal file
20
js/src/jit-test/tests/jaeger/testCallElemAfterGC.js
Normal 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");
|
||||
|
89
js/src/jit-test/tests/jaeger/testDenseCallElem.js
Normal file
89
js/src/jit-test/tests/jaeger/testDenseCallElem.js
Normal 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();
|
||||
}
|
||||
|
||||
|
93
js/src/jit-test/tests/jaeger/testPropCallElem.js
Normal file
93
js/src/jit-test/tests/jaeger/testPropCallElem.js
Normal 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();
|
||||
}
|
||||
|
||||
|
20
js/src/jit-test/tests/jaeger/testPropCallElem2.js
Normal file
20
js/src/jit-test/tests/jaeger/testPropCallElem2.js
Normal 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");
|
||||
|
||||
|
41
js/src/jit-test/tests/jaeger/testSetElem-Easy.js
Normal file
41
js/src/jit-test/tests/jaeger/testSetElem-Easy.js
Normal 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);
|
||||
}
|
||||
|
||||
|
36
js/src/jit-test/tests/jaeger/testSetElem-Indexed.js
Normal file
36
js/src/jit-test/tests/jaeger/testSetElem-Indexed.js
Normal 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");
|
||||
|
24
js/src/jit-test/tests/jaeger/testSetElem-NewProto.js
Normal file
24
js/src/jit-test/tests/jaeger/testSetElem-NewProto.js
Normal 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");
|
||||
|
@ -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")
|
||||
|
@ -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. */
|
||||
|
@ -74,6 +74,7 @@ CPPSRCS = \
|
||||
testThreads.cpp \
|
||||
testTrap.cpp \
|
||||
testUTF8.cpp \
|
||||
testVersion.cpp \
|
||||
testXDR.cpp \
|
||||
$(NULL)
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
135
js/src/jsapi-tests/testVersion.cpp
Normal file
135
js/src/jsapi-tests/testVersion.cpp
Normal 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)
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
270
js/src/jsapi.cpp
270
js/src/jsapi.cpp
@ -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.
|
||||
|
162
js/src/jsapi.h
162
js/src/jsapi.h
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 */
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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
68
js/src/jsdbgapiinlines.h
Normal 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__ */
|
@ -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)) {
|
||||
|
@ -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;
|
||||
|
@ -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]));
|
||||
|
164
js/src/jsfun.cpp
164
js/src/jsfun.cpp
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
/*
|
||||
|
155
js/src/jsgc.cpp
155
js/src/jsgc.cpp
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 = ®s.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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
180
js/src/jsobj.cpp
180
js/src/jsobj.cpp
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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. */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
2162
js/src/jsparse.cpp
2162
js/src/jsparse.cpp
File diff suppressed because it is too large
Load Diff
@ -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();
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user