author | Luke Wagner <lw@mozilla.com> |
Mon, 16 Aug 2010 12:35:04 -0700 | |
changeset 53557 | 66c8ad02543b3dc3a10ab329258dceac96095cb2 |
parent 53556 | d008c236ac465199be2678624298f507dda44d38 |
child 53558 | 24749e6ae6e941c01a5739d54ae6230892ee2893 |
push id | 15660 |
push user | rsayre@mozilla.com |
push date | Sat, 11 Sep 2010 19:16:24 +0000 |
treeherder | mozilla-central@f1bd314e64ac [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | waldo, mrbkap |
bugs | 581263 |
milestone | 2.0b5pre |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/caps/src/nsSecurityManagerFactory.cpp +++ b/caps/src/nsSecurityManagerFactory.cpp @@ -106,165 +106,188 @@ getUTF8StringArgument(JSContext *cx, JSO return; } PRUnichar *data = (PRUnichar*)JS_GetStringChars(str); CopyUTF16toUTF8(data, aRetval); } static JSBool -netscape_security_isPrivilegeEnabled(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +netscape_security_isPrivilegeEnabled(JSContext *cx, uintN argc, jsval *vp) { + JSObject *obj = JS_THIS_OBJECT(cx, vp); + if (!obj) + return JS_FALSE; + JSBool result = JS_FALSE; - char *cap = getStringArgument(cx, obj, 0, argc, argv); + char *cap = getStringArgument(cx, obj, 0, argc, JS_ARGV(cx, vp)); if (cap) { 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); if (NS_FAILED(rv)) result = JS_FALSE; } } - *rval = BOOLEAN_TO_JSVAL(result); + JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(result)); return JS_TRUE; } static JSBool -netscape_security_enablePrivilege(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +netscape_security_enablePrivilege(JSContext *cx, uintN argc, jsval *vp) { - char *cap = getStringArgument(cx, obj, 0, argc, argv); + JSObject *obj = JS_THIS_OBJECT(cx, vp); + if (!obj) + return JS_FALSE; + + char *cap = getStringArgument(cx, obj, 0, argc, JS_ARGV(cx, vp)); if (!cap) return JS_FALSE; nsresult rv; nsCOMPtr<nsIScriptSecurityManager> securityManager = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); if (NS_FAILED(rv)) return JS_FALSE; // NS_ASSERTION(cx == GetCurrentContext(), "unexpected context"); rv = securityManager->EnableCapability(cap); if (NS_FAILED(rv)) return JS_FALSE; + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } static JSBool -netscape_security_disablePrivilege(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +netscape_security_disablePrivilege(JSContext *cx, uintN argc, jsval *vp) { - char *cap = getStringArgument(cx, obj, 0, argc, argv); + JSObject *obj = JS_THIS_OBJECT(cx, vp); + if (!obj) + return JS_FALSE; + + char *cap = getStringArgument(cx, obj, 0, argc, JS_ARGV(cx, vp)); if (!cap) return JS_FALSE; nsresult rv; nsCOMPtr<nsIScriptSecurityManager> securityManager = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); if (NS_FAILED(rv)) return JS_FALSE; // NS_ASSERTION(cx == GetCurrentContext(), "unexpected context"); rv = securityManager->DisableCapability(cap); if (NS_FAILED(rv)) return JS_FALSE; + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } static JSBool -netscape_security_revertPrivilege(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +netscape_security_revertPrivilege(JSContext *cx, uintN argc, jsval *vp) { - char *cap = getStringArgument(cx, obj, 0, argc, argv); + JSObject *obj = JS_THIS_OBJECT(cx, vp); + if (!obj) + return JS_FALSE; + + char *cap = getStringArgument(cx, obj, 0, argc, JS_ARGV(cx, vp)); if (!cap) return JS_FALSE; nsresult rv; nsCOMPtr<nsIScriptSecurityManager> securityManager = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); if (NS_FAILED(rv)) return JS_FALSE; // NS_ASSERTION(cx == GetCurrentContext(), "unexpected context"); rv = securityManager->RevertCapability(cap); if (NS_FAILED(rv)) return JS_FALSE; + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } static JSBool -netscape_security_setCanEnablePrivilege(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +netscape_security_setCanEnablePrivilege(JSContext *cx, uintN argc, jsval *vp) { + JSObject *obj = JS_THIS_OBJECT(cx, vp); + if (!obj) + return JS_FALSE; + if (argc < 2) return JS_FALSE; nsCAutoString principalFingerprint; - getUTF8StringArgument(cx, obj, 0, argc, argv, principalFingerprint); - char *cap = getStringArgument(cx, obj, 1, argc, argv); + getUTF8StringArgument(cx, obj, 0, argc, JS_ARGV(cx, vp), principalFingerprint); + char *cap = getStringArgument(cx, obj, 1, argc, JS_ARGV(cx, vp)); if (principalFingerprint.IsEmpty() || !cap) return JS_FALSE; nsresult rv; nsCOMPtr<nsIScriptSecurityManager> securityManager = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); if (NS_FAILED(rv)) return JS_FALSE; // NS_ASSERTION(cx == GetCurrentContext(), "unexpected context"); rv = securityManager->SetCanEnableCapability(principalFingerprint, cap, nsIPrincipal::ENABLE_GRANTED); if (NS_FAILED(rv)) return JS_FALSE; + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } static JSBool -netscape_security_invalidate(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +netscape_security_invalidate(JSContext *cx, uintN argc, jsval *vp) { + JSObject *obj = JS_THIS_OBJECT(cx, vp); + if (!obj) + return JS_FALSE; + nsCAutoString principalFingerprint; - getUTF8StringArgument(cx, obj, 0, argc, argv, principalFingerprint); + getUTF8StringArgument(cx, obj, 0, argc, JS_ARGV(cx, vp), principalFingerprint); if (principalFingerprint.IsEmpty()) return JS_FALSE; nsresult rv; nsCOMPtr<nsIScriptSecurityManager> securityManager = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); if (NS_FAILED(rv)) return JS_FALSE; // NS_ASSERTION(cx == GetCurrentContext(), "unexpected context"); rv = securityManager->SetCanEnableCapability(principalFingerprint, nsPrincipal::sInvalid, nsIPrincipal::ENABLE_GRANTED); if (NS_FAILED(rv)) return JS_FALSE; + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } static JSFunctionSpec PrivilegeManager_static_methods[] = { - { "isPrivilegeEnabled", netscape_security_isPrivilegeEnabled, 1,0,0}, - { "enablePrivilege", netscape_security_enablePrivilege, 1,0,0}, - { "disablePrivilege", netscape_security_disablePrivilege, 1,0,0}, - { "revertPrivilege", netscape_security_revertPrivilege, 1,0,0}, + { "isPrivilegeEnabled", netscape_security_isPrivilegeEnabled, 1,0}, + { "enablePrivilege", netscape_security_enablePrivilege, 1,0}, + { "disablePrivilege", netscape_security_disablePrivilege, 1,0}, + { "revertPrivilege", netscape_security_revertPrivilege, 1,0}, //-- System Cert Functions { "setCanEnablePrivilege", netscape_security_setCanEnablePrivilege, - 2,0,0}, - { "invalidate", netscape_security_invalidate, 1,0,0}, - {nsnull,nsnull,0,0,0} + 2,0}, + { "invalidate", netscape_security_invalidate, 1,0}, + {nsnull,nsnull,0,0} }; /* * "Steal" calls to netscape.security.PrivilegeManager.enablePrivilege, * et. al. so that code that worked with 4.0 can still work. */ NS_IMETHODIMP nsSecurityNameSet::InitializeNameSet(nsIScriptContext* aScriptContext)
--- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -6522,20 +6522,23 @@ nsCommonWindowSH::GlobalResolve(nsGlobal } return rv; } // Native code for window._content getter, this simply maps // window._content to window.content for backwards compatibility only. static JSBool -ContentWindowGetter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - return ::JS_GetProperty(cx, obj, "content", rval); +ContentWindowGetter(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj = JS_THIS_OBJECT(cx, vp); + if (!obj) + return JS_FALSE; + + return ::JS_GetProperty(cx, obj, "content", vp); } PRBool nsOuterWindowSH::sResolving = PR_FALSE; NS_IMETHODIMP nsOuterWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, jsid id, PRUint32 flags, @@ -8718,26 +8721,30 @@ ResolveImpl(JSContext *cx, nsIXPConnectW JSString *str = IdToString(cx, id); NS_ENSURE_TRUE(str, NS_ERROR_UNEXPECTED); return doc->ResolveName(nsDependentJSString(str), nsnull, result, aCache); } // static JSBool -nsHTMLDocumentSH::DocumentOpen(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ +nsHTMLDocumentSH::DocumentOpen(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj = JS_THIS_OBJECT(cx, vp); + if (!obj) + return JS_FALSE; + + jsval *argv = JS_ARGV(cx, vp); if (argc > 2) { JSObject *global = ::JS_GetGlobalForObject(cx, obj); // DOM0 quirk that makes document.open() call window.open() if // called with 3 or more arguments. - return ::JS_CallFunctionName(cx, global, "open", argc, argv, rval); + return ::JS_CallFunctionName(cx, global, "open", argc, JS_ARGV(cx, vp), vp); } nsCOMPtr<nsISupports> native = do_QueryWrapper(cx, obj); if (!native) { nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_FAILURE); return JS_FALSE; } @@ -8780,17 +8787,17 @@ nsHTMLDocumentSH::DocumentOpen(JSContext nsresult rv = doc->Open(contentType, replace, getter_AddRefs(retval)); if (NS_FAILED(rv)) { nsDOMClassInfo::ThrowJSException(cx, rv); return JS_FALSE; } nsCOMPtr<nsIXPConnectJSObjectHolder> holder; - rv = WrapNative(cx, obj, retval, PR_FALSE, rval, + rv = WrapNative(cx, obj, retval, PR_FALSE, vp, getter_AddRefs(holder)); NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to wrap native!"); return NS_SUCCEEDED(rv); } static JSClass sHTMLDocumentAllClass = { @@ -9056,53 +9063,54 @@ void nsHTMLDocumentSH::ReleaseDocument(JSContext *cx, JSObject *obj) { nsIHTMLDocument *doc = (nsIHTMLDocument *)::JS_GetPrivate(cx, obj); NS_IF_RELEASE(doc); } JSBool -nsHTMLDocumentSH::CallToGetPropMapper(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +nsHTMLDocumentSH::CallToGetPropMapper(JSContext *cx, uintN argc, jsval *vp) { // Handle document.all("foo") style access to document.all. if (argc != 1) { // XXX: Should throw NS_ERROR_XPC_NOT_ENOUGH_ARGS for argc < 1, // and create a new NS_ERROR_XPC_TOO_MANY_ARGS for argc > 1? IE // accepts nothing other than one arg. nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_INVALID_ARG); return JS_FALSE; } // Convert all types to string. - JSString *str = ::JS_ValueToString(cx, argv[0]); + JSString *str = ::JS_ValueToString(cx, JS_ARGV(cx, vp)[0]); if (!str) { return JS_FALSE; } JSObject *self; - if (::JS_TypeOfValue(cx, argv[-2]) == JSTYPE_FUNCTION) { - // If argv[-2] is a function, we're called through + if (::JS_TypeOfValue(cx, JS_CALLEE(cx, vp)) == JSTYPE_FUNCTION) { + // If the callee is a function, we're called through // document.all.item() or something similar. In such a case, self // is passed as obj. - self = obj; + self = JS_THIS_OBJECT(cx, vp); + if (!self) + return JS_FALSE; } else { // In other cases (i.e. document.all("foo")), self is passed as - // argv[-2]. - - self = JSVAL_TO_OBJECT(argv[-2]); + // the callee + + self = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)); } return ::JS_GetUCProperty(cx, self, ::JS_GetStringChars(str), - ::JS_GetStringLength(str), rval); + ::JS_GetStringLength(str), vp); } static inline JSObject * GetDocumentAllHelper(JSContext *cx, JSObject *obj) { while (obj && JS_GET_CLASS(cx, obj) != &sHTMLDocumentAllHelperClass) { obj = ::JS_GetPrototype(cx, obj);
--- a/dom/base/nsDOMClassInfo.h +++ b/dom/base/nsDOMClassInfo.h @@ -994,30 +994,28 @@ protected: nsHTMLDocumentSH(nsDOMClassInfoData* aData) : nsDocumentSH(aData) { } virtual ~nsHTMLDocumentSH() { } - static JSBool DocumentOpen(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval); + static JSBool DocumentOpen(JSContext *cx, uintN argc, jsval *vp); static JSBool GetDocumentAllNodeList(JSContext *cx, JSObject *obj, nsDocument *doc, nsContentList **nodeList); public: static JSBool DocumentAllGetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool DocumentAllNewResolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp); static void ReleaseDocument(JSContext *cx, JSObject *obj); - static JSBool CallToGetPropMapper(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval); + static JSBool CallToGetPropMapper(JSContext *cx, uintN argc, jsval *vp); static JSBool DocumentAllHelperGetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool DocumentAllHelperNewResolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp); static JSBool DocumentAllTagsNewResolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp);
--- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -554,17 +554,17 @@ NS_ScriptErrorReporter(JSContext *cx, const char *message, JSErrorReport *report) { // We don't want to report exceptions too eagerly, but warnings in the // absence of werror are swallowed whole, so report those now. if (!JSREPORT_IS_WARNING(report->flags)) { JSStackFrame * fp = nsnull; while ((fp = JS_FrameIterator(cx, &fp))) { - if (!JS_IsNativeFrame(cx, fp)) { + if (JS_IsScriptFrame(cx, fp)) { return; } } nsIXPConnect* xpc = nsContentUtils::XPConnect(); if (xpc) { nsAXPCNativeCallContext *cc = nsnull; xpc->GetCurrentNativeCallContext(&cc); @@ -3156,126 +3156,131 @@ static JSClass OptionsClass = { #include <unistd.h> #endif #ifdef XP_WIN32 #include <io.h> #endif #include "nsTraceMalloc.h" static JSBool -TraceMallocDisable(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +TraceMallocDisable(JSContext *cx, uintN argc, jsval *vp) { NS_TraceMallocDisable(); + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } static JSBool -TraceMallocEnable(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +TraceMallocEnable(JSContext *cx, uintN argc, jsval *vp) { NS_TraceMallocEnable(); + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } static JSBool -TraceMallocOpenLogFile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +TraceMallocOpenLogFile(JSContext *cx, uintN argc, jsval *vp) { int fd; JSString *str; char *filename; if (argc == 0) { fd = -1; } else { - str = JS_ValueToString(cx, argv[0]); + 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); if (fd < 0) { JS_ReportError(cx, "can't open %s: %s", filename, strerror(errno)); return JS_FALSE; } } - *rval = INT_TO_JSVAL(fd); + JS_SET_RVAL(cx, vp, INT_TO_JSVAL(fd)); return JS_TRUE; } static JSBool -TraceMallocChangeLogFD(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +TraceMallocChangeLogFD(JSContext *cx, uintN argc, jsval *vp) { int32 fd, oldfd; if (argc == 0) { oldfd = -1; } else { - if (!JS_ValueToECMAInt32(cx, argv[0], &fd)) + if (!JS_ValueToECMAInt32(cx, JS_ARGV(cx, vp)[0], &fd)) return JS_FALSE; oldfd = NS_TraceMallocChangeLogFD(fd); if (oldfd == -2) { JS_ReportOutOfMemory(cx); return JS_FALSE; } } - *rval = INT_TO_JSVAL(oldfd); + JS_SET_RVAL(cx, vp, INT_TO_JSVAL(oldfd)); return JS_TRUE; } static JSBool -TraceMallocCloseLogFD(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +TraceMallocCloseLogFD(JSContext *cx, uintN argc, jsval *vp) { int32 fd; + JS_SET_RVAL(cx, vp, JSVAL_VOID); if (argc == 0) return JS_TRUE; - if (!JS_ValueToECMAInt32(cx, argv[0], &fd)) + if (!JS_ValueToECMAInt32(cx, JS_ARGV(cx, vp)[0], &fd)) return JS_FALSE; NS_TraceMallocCloseLogFD((int) fd); return JS_TRUE; } static JSBool -TraceMallocLogTimestamp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +TraceMallocLogTimestamp(JSContext *cx, uintN argc, jsval *vp) { JSString *str; const char *caption; - str = JS_ValueToString(cx, argv[0]); + str = JS_ValueToString(cx, argc ? JS_ARGV(cx, vp)[0] : JSVAL_VOID); if (!str) return JS_FALSE; caption = JS_GetStringBytes(str); NS_TraceMallocLogTimestamp(caption); + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } static JSBool -TraceMallocDumpAllocations(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +TraceMallocDumpAllocations(JSContext *cx, uintN argc, jsval *vp) { JSString *str; const char *pathname; - str = JS_ValueToString(cx, argv[0]); + 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)); return JS_FALSE; } + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } static JSFunctionSpec TraceMallocFunctions[] = { - {"TraceMallocDisable", TraceMallocDisable, 0, 0, 0}, - {"TraceMallocEnable", TraceMallocEnable, 0, 0, 0}, - {"TraceMallocOpenLogFile", TraceMallocOpenLogFile, 1, 0, 0}, - {"TraceMallocChangeLogFD", TraceMallocChangeLogFD, 1, 0, 0}, - {"TraceMallocCloseLogFD", TraceMallocCloseLogFD, 1, 0, 0}, - {"TraceMallocLogTimestamp", TraceMallocLogTimestamp, 1, 0, 0}, - {"TraceMallocDumpAllocations", TraceMallocDumpAllocations, 1, 0, 0}, - {nsnull, nsnull, 0, 0, 0} + {"TraceMallocDisable", TraceMallocDisable, 0, 0}, + {"TraceMallocEnable", TraceMallocEnable, 0, 0}, + {"TraceMallocOpenLogFile", TraceMallocOpenLogFile, 1, 0}, + {"TraceMallocChangeLogFD", TraceMallocChangeLogFD, 1, 0}, + {"TraceMallocCloseLogFD", TraceMallocCloseLogFD, 1, 0}, + {"TraceMallocLogTimestamp", TraceMallocLogTimestamp, 1, 0}, + {"TraceMallocDumpAllocations", TraceMallocDumpAllocations, 1, 0}, + {nsnull, nsnull, 0, 0} }; #endif /* NS_TRACE_MALLOC */ #ifdef MOZ_JPROF #include <signal.h> @@ -3348,21 +3353,21 @@ static JSFunctionSpec JProfFunctions[] = {"JProfStopProfiling", JProfStopProfilingJS, 0, 0, 0}, {nsnull, nsnull, 0, 0, 0} }; #endif /* defined(MOZ_JPROF) */ #ifdef MOZ_SHARK static JSFunctionSpec SharkFunctions[] = { - {"startShark", js_StartShark, 0, 0, 0}, - {"stopShark", js_StopShark, 0, 0, 0}, - {"connectShark", js_ConnectShark, 0, 0, 0}, - {"disconnectShark", js_DisconnectShark, 0, 0, 0}, - {nsnull, nsnull, 0, 0, 0} + {"startShark", js_StartShark, 0, 0}, + {"stopShark", js_StopShark, 0, 0}, + {"connectShark", js_ConnectShark, 0, 0}, + {"disconnectShark", js_DisconnectShark, 0, 0}, + {nsnull, nsnull, 0, 0} }; #endif #ifdef MOZ_CALLGRIND static JSFunctionSpec CallgrindFunctions[] = { {"startCallgrind", js_StartCallgrind, 0, 0, 0}, {"stopCallgrind", js_StopCallgrind, 0, 0, 0}, {"dumpCallgrind", js_DumpCallgrind, 1, 0, 0},
--- a/dom/src/threads/nsDOMWorker.cpp +++ b/dom/src/threads/nsDOMWorker.cpp @@ -69,122 +69,111 @@ class nsDOMWorkerFunctions { public: typedef nsDOMWorker::WorkerPrivilegeModel WorkerPrivilegeModel; // Same as window.dump(). static JSBool - Dump(JSContext* aCx, JSObject* aObj, uintN aArgc, jsval* aArgv, jsval* aRval); + Dump(JSContext* aCx, uintN aArgc, jsval* aVp); // Same as window.setTimeout(). static JSBool - SetTimeout(JSContext* aCx, JSObject* aObj, uintN aArgc, jsval* aArgv, - jsval* aRval) { - return MakeTimeout(aCx, aObj, aArgc, aArgv, aRval, PR_FALSE); + SetTimeout(JSContext* aCx, uintN aArgc, jsval* aVp) { + return MakeTimeout(aCx, aArgc, aVp, PR_FALSE); } // Same as window.setInterval(). static JSBool - SetInterval(JSContext* aCx, JSObject* aObj, uintN aArgc, jsval* aArgv, - jsval* aRval) { - return MakeTimeout(aCx, aObj, aArgc, aArgv, aRval, PR_TRUE); + SetInterval(JSContext* aCx, uintN aArgc, jsval* aVp) { + return MakeTimeout(aCx, aArgc, aVp, PR_TRUE); } // Used for both clearTimeout() and clearInterval(). static JSBool - KillTimeout(JSContext* aCx, JSObject* aObj, uintN aArgc, jsval* aArgv, - jsval* aRval); + KillTimeout(JSContext* aCx, uintN aArgc, jsval* aVp); static JSBool - LoadScripts(JSContext* aCx, JSObject* aObj, uintN aArgc, jsval* aArgv, - jsval* aRval); + LoadScripts(JSContext* aCx, uintN aArgc, jsval* aVp); static JSBool - NewXMLHttpRequest(JSContext* aCx, JSObject* aObj, uintN aArgc, jsval* aArgv, - jsval* aRval); + NewXMLHttpRequest(JSContext* aCx, uintN aArgc, jsval* aVp); static JSBool - NewWorker(JSContext* aCx, JSObject* aObj, uintN aArgc, jsval* aArgv, - jsval* aRval) { - return MakeNewWorker(aCx, aObj, aArgc, aArgv, aRval, nsDOMWorker::CONTENT); + NewWorker(JSContext* aCx, uintN aArgc, jsval* aVp) { + return MakeNewWorker(aCx, aArgc, aVp, nsDOMWorker::CONTENT); } // Chrome-only functions static JSBool - NewChromeWorker(JSContext* aCx, JSObject* aObj, uintN aArgc, jsval* aArgv, - jsval* aRval); + NewChromeWorker(JSContext* aCx, uintN aArgc, jsval* aVp); #ifdef BUILD_CTYPES static JSBool CTypesLazyGetter(JSContext* aCx, JSObject* aObj, jsid aId, jsval* aVp); #endif private: // Internal helper for SetTimeout and SetInterval. static JSBool - MakeTimeout(JSContext* aCx, JSObject* aObj, uintN aArgc, jsval* aArgv, - jsval* aRval, PRBool aIsInterval); + MakeTimeout(JSContext* aCx, uintN aArgc, jsval* aVp, PRBool aIsInterval); static JSBool - MakeNewWorker(JSContext* aCx, JSObject* aObj, uintN aArgc, jsval* aArgv, - jsval* aRval, WorkerPrivilegeModel aPrivilegeModel); + MakeNewWorker(JSContext* aCx, uintN aArgc, jsval* aVp, + WorkerPrivilegeModel aPrivilegeModel); }; JSBool nsDOMWorkerFunctions::Dump(JSContext* aCx, - JSObject* /* aObj */, uintN aArgc, - jsval* aArgv, - jsval* /* aRval */) + jsval* aVp) { + JS_SET_RVAL(cx, aVp, JSVAL_VOID); if (!nsGlobalWindow::DOMWindowDumpEnabled()) { return JS_TRUE; } JSString* str; - if (aArgc && (str = JS_ValueToString(aCx, aArgv[0])) && str) { + if (aArgc && (str = JS_ValueToString(aCx, JS_ARGV(aCx, aVp)[0])) && str) { nsDependentJSString string(str); fputs(NS_ConvertUTF16toUTF8(nsDependentJSString(str)).get(), stderr); fflush(stderr); } return JS_TRUE; } JSBool nsDOMWorkerFunctions::MakeTimeout(JSContext* aCx, - JSObject* /* aObj */, uintN aArgc, - jsval* aArgv, - jsval* aRval, + jsval* aVp, PRBool aIsInterval) { nsDOMWorker* worker = static_cast<nsDOMWorker*>(JS_GetContextPrivate(aCx)); NS_ASSERTION(worker, "This should be set by the DOM thread service!"); if (worker->IsCanceled()) { return JS_FALSE; } PRUint32 id = worker->NextTimeoutId(); if (worker->IsClosing()) { // Timeouts won't run in the close handler, fake success and bail. - *aRval = INT_TO_JSVAL(id); + JS_SET_RVAL(aCx, aVp, INT_TO_JSVAL(id)); return JS_TRUE; } nsRefPtr<nsDOMWorkerTimeout> timeout = new nsDOMWorkerTimeout(worker, id); if (!timeout) { JS_ReportOutOfMemory(aCx); return JS_FALSE; } - nsresult rv = timeout->Init(aCx, aArgc, aArgv, aIsInterval); + nsresult rv = timeout->Init(aCx, aArgc, JS_ARGV(aCx, aVp), aIsInterval); if (NS_FAILED(rv)) { JS_ReportError(aCx, "Failed to initialize timeout!"); return JS_FALSE; } rv = worker->AddFeature(timeout, aCx); if (NS_FAILED(rv)) { JS_ReportOutOfMemory(aCx); @@ -192,55 +181,52 @@ nsDOMWorkerFunctions::MakeTimeout(JSCont } rv = timeout->Start(); if (NS_FAILED(rv)) { JS_ReportError(aCx, "Failed to start timeout!"); return JS_FALSE; } - *aRval = INT_TO_JSVAL(id); + JS_SET_RVAL(aCx, aVp, INT_TO_JSVAL(id)); return JS_TRUE; } JSBool nsDOMWorkerFunctions::KillTimeout(JSContext* aCx, - JSObject* /* aObj */, uintN aArgc, - jsval* aArgv, - jsval* /* aRval */) + jsval* aVp) { nsDOMWorker* worker = static_cast<nsDOMWorker*>(JS_GetContextPrivate(aCx)); NS_ASSERTION(worker, "This should be set by the DOM thread service!"); if (worker->IsCanceled()) { return JS_FALSE; } if (!aArgc) { JS_ReportError(aCx, "Function requires at least 1 parameter"); return JS_FALSE; } uint32 id; - if (!JS_ValueToECMAUint32(aCx, aArgv[0], &id)) { + if (!JS_ValueToECMAUint32(aCx, JS_ARGV(aCx, aVp)[0], &id)) { JS_ReportError(aCx, "First argument must be a timeout id"); return JS_FALSE; } worker->CancelTimeoutWithId(PRUint32(id)); + JS_SET_RVAL(aCx, aVp, JSVAL_VOID); return JS_TRUE; } JSBool nsDOMWorkerFunctions::LoadScripts(JSContext* aCx, - JSObject* /* aObj */, uintN aArgc, - jsval* aArgv, - jsval* /* aRval */) + jsval* aVp) { nsDOMWorker* worker = static_cast<nsDOMWorker*>(JS_GetContextPrivate(aCx)); NS_ASSERTION(worker, "This should be set by the DOM thread service!"); if (worker->IsCanceled()) { return JS_FALSE; } @@ -251,18 +237,19 @@ nsDOMWorkerFunctions::LoadScripts(JSCont nsAutoTArray<nsString, 10> urls; if (!urls.SetCapacity((PRUint32)aArgc)) { JS_ReportOutOfMemory(aCx); return JS_FALSE; } + jsval* argv = JS_ARGV(aCx, aVp); for (uintN index = 0; index < aArgc; index++) { - jsval val = aArgv[index]; + jsval val = argv[index]; if (!JSVAL_IS_STRING(val)) { JS_ReportError(aCx, "Argument %d must be a string", index); return JS_FALSE; } JSString* str = JS_ValueToString(aCx, val); if (!str) { @@ -292,26 +279,30 @@ nsDOMWorkerFunctions::LoadScripts(JSCont rv = loader->LoadScripts(aCx, urls, PR_FALSE); if (NS_FAILED(rv)) { if (!JS_IsExceptionPending(aCx)) { JS_ReportError(aCx, "Failed to load scripts"); } return JS_FALSE; } + JS_SET_RVAL(aCx, aVp, JSVAL_VOID); return JS_TRUE; } JSBool nsDOMWorkerFunctions::NewXMLHttpRequest(JSContext* aCx, - JSObject* aObj, uintN aArgc, - jsval* /* aArgv */, - jsval* aRval) + jsval* aVp) { + JSObject *obj = JS_THIS_OBJECT(aCx, aVp); + if (!obj) { + return JS_FALSE; + } + nsDOMWorker* worker = static_cast<nsDOMWorker*>(JS_GetContextPrivate(aCx)); NS_ASSERTION(worker, "This should be set by the DOM thread service!"); if (worker->IsCanceled()) { return JS_FALSE; } if (aArgc) { @@ -334,54 +325,55 @@ nsDOMWorkerFunctions::NewXMLHttpRequest( rv = worker->AddFeature(xhr, aCx); if (NS_FAILED(rv)) { JS_ReportOutOfMemory(aCx); return JS_FALSE; } nsCOMPtr<nsIXPConnectJSObjectHolder> xhrWrapped; jsval v; - rv = nsContentUtils::WrapNative(aCx, aObj, + rv = nsContentUtils::WrapNative(aCx, obj, static_cast<nsIXMLHttpRequest*>(xhr), &v, getter_AddRefs(xhrWrapped)); if (NS_FAILED(rv)) { JS_ReportError(aCx, "Failed to wrap XMLHttpRequest!"); return JS_FALSE; } - *aRval = v; + JS_SET_RVAL(aCs, aVp, v); return JS_TRUE; } JSBool nsDOMWorkerFunctions::NewChromeWorker(JSContext* aCx, - JSObject* aObj, uintN aArgc, - jsval* aArgv, - jsval* aRval) + jsval* aVp) { nsDOMWorker* worker = static_cast<nsDOMWorker*>(JS_GetContextPrivate(aCx)); NS_ASSERTION(worker, "This should be set by the DOM thread service!"); if (!worker->IsPrivileged()) { JS_ReportError(aCx, "Cannot create a priviliged worker!"); return JS_FALSE; } - return MakeNewWorker(aCx, aObj, aArgc, aArgv, aRval, nsDOMWorker::CHROME); + return MakeNewWorker(aCx, aArgc, aVp, nsDOMWorker::CHROME); } JSBool nsDOMWorkerFunctions::MakeNewWorker(JSContext* aCx, - JSObject* aObj, uintN aArgc, - jsval* aArgv, - jsval* aRval, + jsval* aVp, WorkerPrivilegeModel aPrivilegeModel) { + JSObject *obj = JS_THIS_OBJECT(aCx, aVp); + if (!obj) { + return JS_FALSE; + } + nsDOMWorker* worker = static_cast<nsDOMWorker*>(JS_GetContextPrivate(aCx)); NS_ASSERTION(worker, "This should be set by the DOM thread service!"); if (worker->IsCanceled()) { return JS_FALSE; } if (!aArgc) { @@ -406,32 +398,33 @@ nsDOMWorkerFunctions::MakeNewWorker(JSCo nsRefPtr<nsDOMWorker> newWorker = new nsDOMWorker(worker, wrappedWorker, aPrivilegeModel); if (!newWorker) { JS_ReportOutOfMemory(aCx); return JS_FALSE; } - nsresult rv = newWorker->InitializeInternal(owner, aCx, aObj, aArgc, aArgv); + nsresult rv = newWorker->InitializeInternal(owner, aCx, obj, aArgc, + JS_ARGV(aCx, aVp)); if (NS_FAILED(rv)) { JS_ReportError(aCx, "Couldn't initialize new worker!"); return JS_FALSE; } nsCOMPtr<nsIXPConnectJSObjectHolder> workerWrapped; jsval v; - rv = nsContentUtils::WrapNative(aCx, aObj, static_cast<nsIWorker*>(newWorker), + rv = nsContentUtils::WrapNative(aCx, obj, static_cast<nsIWorker*>(newWorker), &v, getter_AddRefs(workerWrapped)); if (NS_FAILED(rv)) { JS_ReportError(aCx, "Failed to wrap new worker!"); return JS_FALSE; } - *aRval = v; + JS_SET_RVAL(aCx, aVp, v); return JS_TRUE; } #ifdef BUILD_CTYPES JSBool nsDOMWorkerFunctions::CTypesLazyGetter(JSContext* aCx, JSObject* aObj, jsid aId, @@ -455,36 +448,36 @@ nsDOMWorkerFunctions::CTypesLazyGetter(J return JS_DeletePropertyById(aCx, aObj, aId) && JS_InitCTypesClass(aCx, aObj) && JS_GetPropertyById(aCx, aObj, aId, aVp); } #endif JSFunctionSpec gDOMWorkerFunctions[] = { - { "dump", nsDOMWorkerFunctions::Dump, 1, 0, 0 }, - { "setTimeout", nsDOMWorkerFunctions::SetTimeout, 1, 0, 0 }, - { "clearTimeout", nsDOMWorkerFunctions::KillTimeout, 1, 0, 0 }, - { "setInterval", nsDOMWorkerFunctions::SetInterval, 1, 0, 0 }, - { "clearInterval", nsDOMWorkerFunctions::KillTimeout, 1, 0, 0 }, - { "importScripts", nsDOMWorkerFunctions::LoadScripts, 1, 0, 0 }, - { "XMLHttpRequest", nsDOMWorkerFunctions::NewXMLHttpRequest, 0, 0, 0 }, - { "Worker", nsDOMWorkerFunctions::NewWorker, 1, 0, 0 }, + { "dump", nsDOMWorkerFunctions::Dump, 1, 0 }, + { "setTimeout", nsDOMWorkerFunctions::SetTimeout, 1, 0 }, + { "clearTimeout", nsDOMWorkerFunctions::KillTimeout, 1, 0 }, + { "setInterval", nsDOMWorkerFunctions::SetInterval, 1, 0 }, + { "clearInterval", nsDOMWorkerFunctions::KillTimeout, 1, 0 }, + { "importScripts", nsDOMWorkerFunctions::LoadScripts, 1, 0 }, + { "XMLHttpRequest", nsDOMWorkerFunctions::NewXMLHttpRequest, 0, 0 }, + { "Worker", nsDOMWorkerFunctions::NewWorker, 1, 0 }, #ifdef MOZ_SHARK - { "startShark", js_StartShark, 0, 0, 0 }, - { "stopShark", js_StopShark, 0, 0, 0 }, - { "connectShark", js_ConnectShark, 0, 0, 0 }, - { "disconnectShark", js_DisconnectShark, 0, 0, 0 }, + { "startShark", js_StartShark, 0, 0 }, + { "stopShark", js_StopShark, 0, 0 }, + { "connectShark", js_ConnectShark, 0, 0 }, + { "disconnectShark", js_DisconnectShark, 0, 0 }, #endif - { nsnull, nsnull, 0, 0, 0 } + { nsnull, nsnull, 0, 0 } }; JSFunctionSpec gDOMWorkerChromeFunctions[] = { - { "ChromeWorker", nsDOMWorkerFunctions::NewChromeWorker, 1, 0, 0 }, - { nsnull, nsnull, 0, 0, 0 } + { "ChromeWorker", nsDOMWorkerFunctions::NewChromeWorker, 1, 0 }, + { nsnull, nsnull, 0, 0 } }; nsDOMWorkerScope::nsDOMWorkerScope(nsDOMWorker* aWorker) : mWorker(aWorker), mWrappedNative(nsnull), mHasOnerror(PR_FALSE) { NS_ASSERTION(aWorker, "Null pointer!");
--- a/ipc/testshell/XPCShellEnvironment.cpp +++ b/ipc/testshell/XPCShellEnvironment.cpp @@ -135,17 +135,17 @@ ScriptErrorReporter(JSContext *cx, char *prefix = NULL, *tmp; const char *ctmp; JSStackFrame * fp = nsnull; nsCOMPtr<nsIXPConnect> xpc; // Don't report an exception from inner JS frames as the callers may intend // to handle it. while ((fp = JS_FrameIterator(cx, &fp))) { - if (!JS_IsNativeFrame(cx, fp)) { + if (JS_IsScriptFrame(cx, fp)) { return; } } // In some cases cx->fp is null here so use XPConnect to tell us about inner // frames. if ((xpc = do_GetService(nsIXPConnect::GetCID()))) { nsAXPCNativeCallContext *cc = nsnull; @@ -238,34 +238,34 @@ ContextCallback(JSContext *cx, JS_SetErrorReporter(cx, ScriptErrorReporter); JS_SetVersion(cx, JSVERSION_LATEST); } return JS_TRUE; } static JSBool Print(JSContext *cx, - JSObject *obj, uintN argc, - jsval *argv, - jsval *rval) + jsval *vp) { uintN i, n; JSString *str; + jsval *argv = JS_ARGV(cx, vp); for (i = n = 0; i < argc; i++) { str = JS_ValueToString(cx, argv[i]); if (!str) return JS_FALSE; fprintf(stdout, "%s%s", i ? " " : "", JS_GetStringBytes(str)); fflush(stdout); } n++; if (n) fputc('\n', stdout); + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } static JSBool GetLine(char *bufp, FILE *file, const char *prompt) { @@ -275,49 +275,52 @@ GetLine(char *bufp, if (!fgets(line, sizeof line, file)) return JS_FALSE; strcpy(bufp, line); return JS_TRUE; } static JSBool Dump(JSContext *cx, - JSObject *obj, uintN argc, - jsval *argv, - jsval *rval) + jsval *vp) { + JS_SET_RVAL(cx, vp, JSVAL_VOID); + JSString *str; if (!argc) return JS_TRUE; - str = JS_ValueToString(cx, argv[0]); + str = JS_ValueToString(cx, JS_ARGV(cx, vp)[0]); if (!str) return JS_FALSE; fputs(JS_GetStringBytes(str), stdout); fflush(stdout); return JS_TRUE; } static JSBool Load(JSContext *cx, - JSObject *obj, uintN argc, - jsval *argv, - jsval *rval) + jsval *vp) { uintN i; JSString *str; const char *filename; JSScript *script; JSBool ok; jsval result; FILE *file; + JSObject *obj = JS_THIS_OBJECT(cx, vp); + if (!obj) + return JS_FALSE; + + jsval *argv = JS_ARGV(cx, vp); for (i = 0; i < argc; i++) { str = JS_ValueToString(cx, argv[i]); if (!str) return JS_FALSE; argv[i] = STRING_TO_JSVAL(str); filename = JS_GetStringBytes(str); file = fopen(filename, "r"); if (!file) { @@ -332,83 +335,78 @@ Load(JSContext *cx, ok = !Environment(cx)->ShouldCompileOnly() ? JS_ExecuteScript(cx, obj, script, &result) : JS_TRUE; JS_DestroyScript(cx, script); if (!ok) return JS_FALSE; } + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } static JSBool Version(JSContext *cx, - JSObject *obj, uintN argc, - jsval *argv, - jsval *rval) + jsval *vp) { + jsval *argv = JS_ARGV(cx, vp); if (argc > 0 && JSVAL_IS_INT(argv[0])) - *rval = INT_TO_JSVAL(JS_SetVersion(cx, JSVersion(JSVAL_TO_INT(argv[0])))); + JS_SET_RVAL(cx, vp, INT_TO_JSVAL(JS_SetVersion(cx, JSVersion(JSVAL_TO_INT(argv[0]))))); else - *rval = INT_TO_JSVAL(JS_GetVersion(cx)); + JS_SET_RVAL(cx, vp, INT_TO_JSVAL(JS_GetVersion(cx))); return JS_TRUE; } static JSBool -BuildDate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +BuildDate(JSContext *cx, uintN argc, jsval *vp) { fprintf(stdout, "built on %s at %s\n", __DATE__, __TIME__); return JS_TRUE; } static JSBool Quit(JSContext *cx, - JSObject *obj, uintN argc, - jsval *argv, - jsval *rval) + jsval *vp) { int exitCode = 0; - JS_ConvertArguments(cx, argc, argv, "/ i", &exitCode); + JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "/ i", &exitCode); XPCShellEnvironment* env = Environment(cx); env->SetExitCode(exitCode); env->SetIsQuitting(); return JS_FALSE; } static JSBool DumpXPC(JSContext *cx, - JSObject *obj, uintN argc, - jsval *argv, - jsval *rval) + jsval *vp) { int32 depth = 2; if (argc > 0) { - if (!JS_ValueToInt32(cx, argv[0], &depth)) + if (!JS_ValueToInt32(cx, JS_ARGV(cx, vp)[0], &depth)) return JS_FALSE; } nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID()); if(xpc) xpc->DebugDump((int16)depth); + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } static JSBool GC(JSContext *cx, - JSObject *obj, uintN argc, - jsval *argv, - jsval *rval) + jsval *vp) { JSRuntime *rt; uint32 preBytes; rt = cx->runtime; preBytes = rt->gcBytes; JS_GC(cx); fprintf(stdout, "before %lu, after %lu, break %08lx\n", @@ -417,75 +415,76 @@ GC(JSContext *cx, (unsigned long)sbrk(0) #else 0 #endif ); #ifdef JS_GCMETER js_DumpGCStats(rt, stdout); #endif + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } #ifdef DEBUG static JSBool DumpHeap(JSContext *cx, - JSObject *obj, uintN argc, - jsval *argv, - jsval *rval) + jsval *vp) { char *fileName = NULL; void* startThing = NULL; uint32 startTraceKind = 0; void *thingToFind = NULL; size_t maxDepth = (size_t)-1; void *thingToIgnore = NULL; - jsval *vp; FILE *dumpFile; JSBool ok; - vp = &argv[0]; - if (*vp != JSVAL_NULL && *vp != JSVAL_VOID) { + jsval *argv = JS_ARGV(cx, vp); + JS_SET_RVAL(cx, vp, JSVAL_VOID); + + vp = argv + 0; + if (argc > 0 && *vp != JSVAL_NULL && *vp != JSVAL_VOID) { JSString *str; str = JS_ValueToString(cx, *vp); if (!str) return JS_FALSE; *vp = STRING_TO_JSVAL(str); fileName = JS_GetStringBytes(str); } - vp = &argv[1]; - if (*vp != JSVAL_NULL && *vp != JSVAL_VOID) { + vp = argv + 1; + if (argc > 1 && *vp != JSVAL_NULL && *vp != JSVAL_VOID) { if (!JSVAL_IS_TRACEABLE(*vp)) goto not_traceable_arg; startThing = JSVAL_TO_TRACEABLE(*vp); startTraceKind = JSVAL_TRACE_KIND(*vp); } - vp = &argv[2]; - if (*vp != JSVAL_NULL && *vp != JSVAL_VOID) { + vp = argv + 2; + if (argc > 2 && *vp != JSVAL_NULL && *vp != JSVAL_VOID) { if (!JSVAL_IS_TRACEABLE(*vp)) goto not_traceable_arg; thingToFind = JSVAL_TO_TRACEABLE(*vp); } - vp = &argv[3]; - if (*vp != JSVAL_NULL && *vp != JSVAL_VOID) { + vp = argv + 3; + if (argc > 3 && *vp != JSVAL_NULL && *vp != JSVAL_VOID) { uint32 depth; if (!JS_ValueToECMAUint32(cx, *vp, &depth)) return JS_FALSE; maxDepth = depth; } - vp = &argv[4]; - if (*vp != JSVAL_NULL && *vp != JSVAL_VOID) { + vp = argv + 4; + if (argc > 4 && *vp != JSVAL_NULL && *vp != JSVAL_VOID) { if (!JSVAL_IS_TRACEABLE(*vp)) goto not_traceable_arg; thingToIgnore = JSVAL_TO_TRACEABLE(*vp); } if (!fileName) { dumpFile = stdout; } else { @@ -509,87 +508,68 @@ DumpHeap(JSContext *cx, (unsigned)(vp - argv)); return JS_FALSE; } #endif /* DEBUG */ static JSBool Clear(JSContext *cx, - JSObject *obj, uintN argc, - jsval *argv, - jsval *rval) + jsval *vp) { + jsval *argv = JS_ARGV(cx, vp); if (argc > 0 && !JSVAL_IS_PRIMITIVE(argv[0])) { JS_ClearScope(cx, JSVAL_TO_OBJECT(argv[0])); } else { JS_ReportError(cx, "'clear' requires an object"); return JS_FALSE; } + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } JSFunctionSpec gGlobalFunctions[] = { - {"print", Print, 0,0,0}, - {"load", Load, 1,0,0}, - {"quit", Quit, 0,0,0}, - {"version", Version, 1,0,0}, - {"build", BuildDate, 0,0,0}, - {"dumpXPC", DumpXPC, 1,0,0}, - {"dump", Dump, 1,0,0}, - {"gc", GC, 0,0,0}, - {"clear", Clear, 1,0,0}, + {"print", Print, 0,0}, + {"load", Load, 1,0}, + {"quit", Quit, 0,0}, + {"version", Version, 1,0}, + {"build", BuildDate, 0,0}, + {"dumpXPC", DumpXPC, 1,0}, + {"dump", Dump, 1,0}, + {"gc", GC, 0,0}, + {"clear", Clear, 1,0}, #ifdef DEBUG - {"dumpHeap", DumpHeap, 5,0,0}, + {"dumpHeap", DumpHeap, 5,0}, #endif #ifdef MOZ_SHARK - {"startShark", js_StartShark, 0,0,0}, - {"stopShark", js_StopShark, 0,0,0}, - {"connectShark", js_ConnectShark, 0,0,0}, - {"disconnectShark", js_DisconnectShark, 0,0,0}, + {"startShark", js_StartShark, 0,0}, + {"stopShark", js_StopShark, 0,0}, + {"connectShark", js_ConnectShark, 0,0}, + {"disconnectShark", js_DisconnectShark, 0,0}, #endif #ifdef MOZ_CALLGRIND - {"startCallgrind", js_StartCallgrind, 0,0,0}, - {"stopCallgrind", js_StopCallgrind, 0,0,0}, - {"dumpCallgrind", js_DumpCallgrind, 1,0,0}, + {"startCallgrind", js_StartCallgrind, 0,0}, + {"stopCallgrind", js_StopCallgrind, 0,0}, + {"dumpCallgrind", js_DumpCallgrind, 1,0}, #endif - {nsnull,nsnull,0,0,0} + {nsnull,nsnull,0,0} }; typedef enum JSShellErrNum { #define MSG_DEF(name, number, count, exception, format) \ name = number, #include "jsshell.msg" #undef MSG_DEF JSShellErr_Limit #undef MSGDEF } JSShellErrNum; -JSErrorFormatString gErrorFormatString[JSErr_Limit] = -{ -#define MSG_DEF(name, number, count, exception, format) \ - { format, count } , -#include "jsshell.msg" -#undef MSG_DEF -}; - -static const JSErrorFormatString * -GetErrorMessage(void *userRef, - const char *locale, - const uintN errorNumber) -{ - if ((errorNumber > 0) && (errorNumber < JSShellErr_Limit)) - return &gErrorFormatString[errorNumber]; - - return NULL; -} - static void ProcessFile(JSContext *cx, JSObject *obj, const char *filename, FILE *file, JSBool forceTTY) { XPCShellEnvironment* env = Environment(cx);
--- a/js/ipc/ObjectWrapperParent.cpp +++ b/js/ipc/ObjectWrapperParent.cpp @@ -637,76 +637,78 @@ ObjectWrapperParent::CPOW_Finalize(JSCon ObjectWrapperParent* self = Unwrap(cx, obj); if (self) { self->mObj = NULL; unused << ObjectWrapperParent::Send__delete__(self); } } /*static*/ JSBool -ObjectWrapperParent::CPOW_Call(JSContext* cx, JSObject* obj, uintN argc, - jsval* argv, jsval* rval) +ObjectWrapperParent::CPOW_Call(JSContext* cx, uintN argc, jsval* vp) { CPOW_LOG(("Calling CPOW_Call...")); + JSObject* thisobj = JS_THIS_OBJECT(cx, vp); + if (!thisobj) + return JS_FALSE; + ObjectWrapperParent* function = - Unwrap(cx, JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv))); + Unwrap(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp))); if (!function) return with_error(cx, JS_FALSE, "Could not unwrap CPOW function"); AutoCheckOperation aco(cx, function); - ObjectWrapperParent* receiver = Unwrap(cx, obj); + ObjectWrapperParent* receiver = Unwrap(cx, thisobj); if (!receiver) { // Substitute child global for parent global object. // TODO First make sure we're really replacing the global object? ContextWrapperParent* manager = static_cast<ContextWrapperParent*>(function->Manager()); receiver = manager->GetGlobalObjectWrapper(); } nsTArray<JSVariant> in_argv(argc); + jsval* argv = JS_ARGV(cx, vp); for (uintN i = 0; i < argc; i++) if (!jsval_to_JSVariant(cx, argv[i], in_argv.AppendElement())) return JS_FALSE; JSVariant out_rval; return (function->Manager()->RequestRunToCompletion() && function->CallCall(receiver, in_argv, aco.StatusPtr(), &out_rval) && aco.Ok() && - jsval_from_JSVariant(cx, out_rval, rval)); + jsval_from_JSVariant(cx, out_rval, vp)); } /*static*/ JSBool -ObjectWrapperParent::CPOW_Construct(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +ObjectWrapperParent::CPOW_Construct(JSContext* cx, uintN argc, jsval* vp) { CPOW_LOG(("Calling CPOW_Construct...")); - ObjectWrapperParent* constructor = - Unwrap(cx, JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv))); + ObjectWrapperParent* constructor = Unwrap(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp))); if (!constructor) return with_error(cx, JS_FALSE, "Could not unwrap CPOW constructor function"); AutoCheckOperation aco(cx, constructor); nsTArray<JSVariant> in_argv(argc); + jsval* argv = JS_ARGV(cx, vp); for (uintN i = 0; i < argc; i++) if (!jsval_to_JSVariant(cx, argv[i], in_argv.AppendElement())) return JS_FALSE; PObjectWrapperParent* out_powp; return (constructor->Manager()->RequestRunToCompletion() && - constructor->CallConstruct(in_argv, - aco.StatusPtr(), &out_powp) && + constructor->CallConstruct(in_argv, aco.StatusPtr(), &out_powp) && aco.Ok() && - jsval_from_PObjectWrapperParent(cx, out_powp, rval)); + jsval_from_PObjectWrapperParent(cx, out_powp, vp)); } /*static*/ JSBool ObjectWrapperParent::CPOW_HasInstance(JSContext *cx, JSObject *obj, const jsval *v, JSBool *bp) { CPOW_LOG(("Calling CPOW_HasInstance..."));
--- a/js/ipc/ObjectWrapperParent.h +++ b/js/ipc/ObjectWrapperParent.h @@ -113,22 +113,20 @@ private: static JSBool CPOW_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp); static void CPOW_Finalize(JSContext* cx, JSObject* obj); static JSBool - CPOW_Call(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, - jsval* rval); + CPOW_Call(JSContext* cx, uintN argc, jsval* vp); static JSBool - CPOW_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval); + CPOW_Construct(JSContext *cx, uintN argc, jsval *vp); static JSBool CPOW_HasInstance(JSContext *cx, JSObject *obj, const jsval *v, JSBool *bp); static JSBool CPOW_Equality(JSContext *cx, JSObject *obj, const jsval *v, JSBool *bp); static bool jsval_to_JSVariant(JSContext* cx, jsval from, JSVariant* to);
--- a/js/jetpack/Handle.h +++ b/js/jetpack/Handle.h @@ -342,18 +342,17 @@ Handle<BaseType>::sHandle_Properties[] = { "parent", 0, HANDLE_PROP_FLAGS | JSPROP_READONLY, GetParent, NULL }, { "isValid", 0, HANDLE_PROP_FLAGS | JSPROP_READONLY, GetIsValid, NULL }, { "isRooted", 0, HANDLE_PROP_FLAGS, GetIsRooted, SetIsRooted }, { 0, 0, 0, NULL, NULL } }; #undef HANDLE_PROP_FLAGS -#define HANDLE_FUN_FLAGS (JSFUN_FAST_NATIVE | \ - JSPROP_READONLY | \ +#define HANDLE_FUN_FLAGS (JSPROP_READONLY | \ JSPROP_PERMANENT) template <class BaseType> const JSFunctionSpec Handle<BaseType>::sHandle_Functions[] = { JS_FN("invalidate", Invalidate, 0, HANDLE_FUN_FLAGS), JS_FN("createHandle", CreateHandle, 0, HANDLE_FUN_FLAGS), JS_FS_END
--- a/js/jetpack/JetpackChild.cpp +++ b/js/jetpack/JetpackChild.cpp @@ -52,18 +52,17 @@ namespace jetpack { JetpackChild::JetpackChild() { } JetpackChild::~JetpackChild() { } -#define IMPL_METHOD_FLAGS (JSFUN_FAST_NATIVE | \ - JSPROP_ENUMERATE | \ +#define IMPL_METHOD_FLAGS (JSPROP_ENUMERATE | \ JSPROP_READONLY | \ JSPROP_PERMANENT) const JSFunctionSpec JetpackChild::sImplMethods[] = { JS_FN("sendMessage", SendMessage, 3, IMPL_METHOD_FLAGS), JS_FN("callMessage", CallMessage, 2, IMPL_METHOD_FLAGS), JS_FN("registerReceiver", RegisterReceiver, 2, IMPL_METHOD_FLAGS), JS_FN("unregisterReceiver", UnregisterReceiver, 2, IMPL_METHOD_FLAGS),
--- a/js/jsd/idl/jsdIDebuggerService.idl +++ b/js/jsd/idl/jsdIDebuggerService.idl @@ -788,20 +788,16 @@ interface jsdIStackFrame : jsdIEphemeral /** Internal use only. */ [noscript] readonly attribute JSDContext JSDContext; /** Internal use only. */ [noscript] readonly attribute JSDThreadState JSDThreadState; /** Internal use only. */ [noscript] readonly attribute JSDStackFrameInfo JSDStackFrameInfo; /** - * True if stack frame represents a native frame. - */ - readonly attribute boolean isNative; - /** * True if stack frame represents a frame created as a result of a debugger * evaluation. */ readonly attribute boolean isDebugger; /** * True if stack frame is constructing a new object. */ readonly attribute boolean isConstructing;
--- a/js/jsd/jsd.h +++ b/js/jsd/jsd.h @@ -703,21 +703,16 @@ jsd_GetCallObjectForStackFrame(JSDContex JSDStackFrameInfo* jsdframe); extern JSDValue* jsd_GetScopeChainForStackFrame(JSDContext* jsdc, JSDThreadState* jsdthreadstate, JSDStackFrameInfo* jsdframe); extern JSBool -jsd_IsStackFrameNative(JSDContext* jsdc, - JSDThreadState* jsdthreadstate, - JSDStackFrameInfo* jsdframe); - -extern JSBool jsd_IsStackFrameDebugger(JSDContext* jsdc, JSDThreadState* jsdthreadstate, JSDStackFrameInfo* jsdframe); extern JSBool jsd_IsStackFrameConstructing(JSDContext* jsdc, JSDThreadState* jsdthreadstate, JSDStackFrameInfo* jsdframe);
--- a/js/jsd/jsd_obj.c +++ b/js/jsd/jsd_obj.c @@ -139,17 +139,17 @@ jsd_Constructing(JSDContext* jsdc, JSCon JSDObject* jsdobj; JSScript* script; JSDScript* jsdscript; const char* ctorURL; const char* ctorName; JSD_LOCK_OBJECTS(jsdc); jsdobj = jsd_GetJSDObjectForJSObject(jsdc, obj); - if( jsdobj && !jsdobj->ctorURL && !JS_IsNativeFrame(cx, fp) ) + if( jsdobj && !jsdobj->ctorURL && JS_IsScriptFrame(cx, fp) ) { script = JS_GetFrameScript(cx, fp); if( script ) { ctorURL = JS_GetScriptFilename(cx, script); if( ctorURL ) jsdobj->ctorURL = jsd_AddAtom(jsdc, ctorURL);
--- a/js/jsd/jsd_stak.c +++ b/js/jsd/jsd_stak.c @@ -60,17 +60,17 @@ static JSDStackFrameInfo* JSDThreadState* jsdthreadstate, JSScript* script, jsuword pc, JSStackFrame* fp) { JSDStackFrameInfo* jsdframe; JSDScript* jsdscript = NULL; - if (!JS_IsNativeFrame(jsdthreadstate->context, fp)) + if (JS_IsScriptFrame(jsdthreadstate->context, fp)) { JSD_LOCK_SCRIPTS(jsdc); jsdscript = jsd_FindJSDScript(jsdc, script); JSD_UNLOCK_SCRIPTS(jsdc); if (!jsdscript || (jsdc->flags & JSD_HIDE_DISABLED_FRAMES && !JSD_IS_DEBUG_ENABLED(jsdc, jsdscript))) { return NULL; @@ -128,17 +128,17 @@ jsd_NewThreadState(JSDContext* jsdc, JSC /* * don't construct a JSDStackFrame for dummy frames (those without a * |this| object, or native frames, if JSD_INCLUDE_NATIVE_FRAMES * isn't set. */ if (JS_GetFrameThis(cx, fp) && ((jsdc->flags & JSD_INCLUDE_NATIVE_FRAMES) || - !JS_IsNativeFrame(cx, fp))) + JS_IsScriptFrame(cx, fp))) { JSDStackFrameInfo *frame; frame = _addNewFrame( jsdc, jsdthreadstate, script, pc, fp ); if ((jsdthreadstate->stackDepth == 0 && !frame) || (jsdthreadstate->stackDepth == 1 && frame && frame->jsdscript && !JSD_IS_DEBUG_ENABLED(jsdc, frame->jsdscript))) @@ -370,38 +370,16 @@ jsd_GetNameForStackFrame(JSDContext* jsd rv = JS_GetFunctionName (fun); } JSD_UNLOCK_THREADSTATES(jsdc); return rv; } JSBool -jsd_IsStackFrameNative(JSDContext* jsdc, - JSDThreadState* jsdthreadstate, - JSDStackFrameInfo* jsdframe) -{ - JSBool rv; - - JSD_LOCK_THREADSTATES(jsdc); - - if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) ) - { - rv = JS_IsNativeFrame(jsdthreadstate->context, jsdframe->fp); - } - else - { - rv = JS_FALSE; - } - - JSD_UNLOCK_THREADSTATES(jsdc); - return rv; -} - -JSBool jsd_IsStackFrameDebugger(JSDContext* jsdc, JSDThreadState* jsdthreadstate, JSDStackFrameInfo* jsdframe) { JSBool rv = JS_TRUE; JSD_LOCK_THREADSTATES(jsdc); if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
--- a/js/jsd/jsd_xpc.cpp +++ b/js/jsd/jsd_xpc.cpp @@ -1836,24 +1836,16 @@ NS_IMETHODIMP jsdStackFrame::GetFunctionName(nsACString &_rval) { ASSERT_VALID_EPHEMERAL; _rval.Assign(JSD_GetNameForStackFrame(mCx, mThreadState, mStackFrameInfo)); return NS_OK; } NS_IMETHODIMP -jsdStackFrame::GetIsNative(PRBool *_rval) -{ - ASSERT_VALID_EPHEMERAL; - *_rval = JSD_IsStackFrameNative (mCx, mThreadState, mStackFrameInfo); - return NS_OK; -} - -NS_IMETHODIMP jsdStackFrame::GetIsDebugger(PRBool *_rval) { ASSERT_VALID_EPHEMERAL; *_rval = JSD_IsStackFrameDebugger (mCx, mThreadState, mStackFrameInfo); return NS_OK; } NS_IMETHODIMP @@ -1897,19 +1889,17 @@ jsdStackFrame::GetLine(PRUint32 *_rval) { ASSERT_VALID_EPHEMERAL; JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState, mStackFrameInfo); if (script) { jsuword pc = JSD_GetPCForStackFrame (mCx, mThreadState, mStackFrameInfo); *_rval = JSD_GetClosestLine (mCx, script, pc); } else { - if (!JSD_IsStackFrameNative(mCx, mThreadState, mStackFrameInfo)) - return NS_ERROR_FAILURE; - *_rval = 1; + return NS_ERROR_FAILURE; } return NS_OK; } NS_IMETHODIMP jsdStackFrame::GetCallee(jsdIValue **_rval) { ASSERT_VALID_EPHEMERAL;
--- a/js/jsd/jsdebug.c +++ b/js/jsd/jsdebug.c @@ -746,25 +746,16 @@ JSD_GetNameForStackFrame(JSDContext* jsd JSDThreadState* jsdthreadstate, JSDStackFrameInfo* jsdframe) { JSD_ASSERT_VALID_CONTEXT(jsdc); return jsd_GetNameForStackFrame(jsdc, jsdthreadstate, jsdframe); } JSD_PUBLIC_API(JSBool) -JSD_IsStackFrameNative(JSDContext* jsdc, - JSDThreadState* jsdthreadstate, - JSDStackFrameInfo* jsdframe) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - return jsd_IsStackFrameNative(jsdc, jsdthreadstate, jsdframe); -} - -JSD_PUBLIC_API(JSBool) JSD_IsStackFrameDebugger(JSDContext* jsdc, JSDThreadState* jsdthreadstate, JSDStackFrameInfo* jsdframe) { JSD_ASSERT_VALID_CONTEXT(jsdc); return jsd_IsStackFrameDebugger(jsdc, jsdthreadstate, jsdframe); }
--- a/js/jsd/jsdebug.h +++ b/js/jsd/jsdebug.h @@ -946,24 +946,16 @@ JSD_GetThisForStackFrame(JSDContext* jsd * for native frames (without script objects.) */ extern JSD_PUBLIC_API(const char*) JSD_GetNameForStackFrame(JSDContext* jsdc, JSDThreadState* jsdthreadstate, JSDStackFrameInfo* jsdframe); /* -* True if stack frame represents a native frame. -*/ -extern JSD_PUBLIC_API(JSBool) -JSD_IsStackFrameNative(JSDContext* jsdc, - JSDThreadState* jsdthreadstate, - JSDStackFrameInfo* jsdframe); - -/* * True if stack frame represents a frame created as a result of a debugger * evaluation. */ extern JSD_PUBLIC_API(JSBool) JSD_IsStackFrameDebugger(JSDContext* jsdc, JSDThreadState* jsdthreadstate, JSDStackFrameInfo* jsdframe);
--- a/js/src/ctypes/CTypes.cpp +++ b/js/src/ctypes/CTypes.cpp @@ -71,92 +71,85 @@ public: private: JSContext* mCx; }; /******************************************************************************* ** JSAPI function prototypes *******************************************************************************/ -static JSBool ConstructAbstract(JSContext* cx, JSObject* obj, uintN argc, - jsval* argv, jsval* rval); +static JSBool ConstructAbstract(JSContext* cx, uintN argc, jsval* vp); namespace CType { - static JSBool ConstructData(JSContext* cx, JSObject* obj, uintN argc, - jsval* argv, jsval* rval); - static JSBool ConstructBasic(JSContext* cx, JSObject* obj, uintN argc, - jsval* argv, jsval* rval); + static JSBool ConstructData(JSContext* cx, uintN argc, jsval* vp); + static JSBool ConstructBasic(JSContext* cx, JSObject* obj, uintN argc, jsval* vp); static void Trace(JSTracer* trc, JSObject* obj); static void Finalize(JSContext* cx, JSObject* obj); static void FinalizeProtoClass(JSContext* cx, JSObject* obj); static JSBool PrototypeGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); static JSBool NameGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); static JSBool SizeGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); static JSBool PtrGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); static JSBool CreateArray(JSContext* cx, uintN argc, jsval* vp); static JSBool ToString(JSContext* cx, uintN argc, jsval* vp); static JSBool ToSource(JSContext* cx, uintN argc, jsval* vp); - static JSBool HasInstance(JSContext* cx, JSObject* obj, const jsval *v, JSBool* bp); + static JSBool HasInstance(JSContext* cx, JSObject* obj, const jsval* v, JSBool* bp); } namespace PointerType { static JSBool Create(JSContext* cx, uintN argc, jsval* vp); - static JSBool ConstructData(JSContext* cx, JSObject* obj, uintN argc, - jsval* argv, jsval* rval); + static JSBool ConstructData(JSContext* cx, JSObject* obj, uintN argc, jsval* vp); static JSBool TargetTypeGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); static JSBool ContentsGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); static JSBool ContentsSetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); static JSBool IsNull(JSContext* cx, uintN argc, jsval* vp); } namespace ArrayType { static JSBool Create(JSContext* cx, uintN argc, jsval* vp); - static JSBool ConstructData(JSContext* cx, JSObject* obj, uintN argc, - jsval* argv, jsval* rval); + static JSBool ConstructData(JSContext* cx, JSObject* obj, uintN argc, jsval* vp); static JSBool ElementTypeGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); static JSBool LengthGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); static JSBool Getter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); static JSBool Setter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); static JSBool AddressOfElement(JSContext* cx, uintN argc, jsval* vp); } namespace StructType { static JSBool Create(JSContext* cx, uintN argc, jsval* vp); - static JSBool ConstructData(JSContext* cx, JSObject* obj, uintN argc, - jsval* argv, jsval* rval); + static JSBool ConstructData(JSContext* cx, JSObject* obj, uintN argc, jsval* vp); static JSBool FieldsArrayGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); static JSBool FieldGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); static JSBool FieldSetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); static JSBool AddressOfField(JSContext* cx, uintN argc, jsval* vp); static JSBool Define(JSContext* cx, uintN argc, jsval* vp); } namespace FunctionType { static JSBool Create(JSContext* cx, uintN argc, jsval* vp); static JSBool ConstructData(JSContext* cx, JSObject* typeObj, JSObject* dataObj, JSObject* fnObj, JSObject* thisObj); - static JSBool Call(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, - jsval* rval); + static JSBool Call(JSContext* cx, uintN argc, jsval* vp); static JSBool ArgTypesGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); static JSBool ReturnTypeGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); static JSBool ABIGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); static JSBool IsVariadicGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); @@ -195,31 +188,29 @@ namespace Int64Base { JSBool ToSource(JSContext* cx, JSObject* obj, uintN argc, jsval* vp, bool isUnsigned); static void Finalize(JSContext* cx, JSObject* obj); } namespace Int64 { - static JSBool Construct(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, - jsval* rval); + static JSBool Construct(JSContext* cx, uintN argc, jsval* vp); static JSBool ToString(JSContext* cx, uintN argc, jsval* vp); static JSBool ToSource(JSContext* cx, uintN argc, jsval* vp); static JSBool Compare(JSContext* cx, uintN argc, jsval* vp); static JSBool Lo(JSContext* cx, uintN argc, jsval* vp); static JSBool Hi(JSContext* cx, uintN argc, jsval* vp); static JSBool Join(JSContext* cx, uintN argc, jsval* vp); } namespace UInt64 { - static JSBool Construct(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, - jsval* rval); + static JSBool Construct(JSContext* cx, uintN argc, jsval* vp); static JSBool ToString(JSContext* cx, uintN argc, jsval* vp); static JSBool ToSource(JSContext* cx, uintN argc, jsval* vp); static JSBool Compare(JSContext* cx, uintN argc, jsval* vp); static JSBool Lo(JSContext* cx, uintN argc, jsval* vp); static JSBool Hi(JSContext* cx, uintN argc, jsval* vp); static JSBool Join(JSContext* cx, uintN argc, jsval* vp); @@ -279,23 +270,26 @@ static JSClass sCClosureClass = { "CClosure", JSCLASS_HAS_RESERVED_SLOTS(CCLOSURE_SLOTS) | JSCLASS_MARK_IS_TRACE, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, CClosure::Finalize, NULL, NULL, NULL, NULL, NULL, NULL, JS_CLASS_TRACE(CClosure::Trace), NULL }; #define CTYPESFN_FLAGS \ - (JSFUN_FAST_NATIVE | JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT) + (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT) + +#define CTYPESCTOR_FLAGS \ + (CTYPESFN_FLAGS | JSFUN_CONSTRUCTOR) #define CTYPESPROP_FLAGS \ (JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT) #define CDATAFN_FLAGS \ - (JSFUN_FAST_NATIVE | JSPROP_READONLY | JSPROP_PERMANENT) + (JSPROP_READONLY | JSPROP_PERMANENT) static JSPropertySpec sCTypeProps[] = { { "name", 0, CTYPESPROP_FLAGS, CType::NameGetter, NULL }, { "size", 0, CTYPESPROP_FLAGS, CType::SizeGetter, NULL }, { "ptr", 0, CTYPESPROP_FLAGS, CType::PtrGetter, NULL }, { "prototype", 0, CTYPESPROP_FLAGS, CType::PrototypeGetter, NULL }, { 0, 0, 0, NULL, NULL } }; @@ -317,17 +311,17 @@ static JSFunctionSpec sCDataFunctions[] JS_FN("address", CData::Address, 0, CDATAFN_FLAGS), JS_FN("readString", CData::ReadString, 0, CDATAFN_FLAGS), JS_FN("toSource", CData::ToSource, 0, CDATAFN_FLAGS), JS_FN("toString", CData::ToSource, 0, CDATAFN_FLAGS), JS_FS_END }; static JSFunctionSpec sPointerFunction = - JS_FN("PointerType", PointerType::Create, 1, CTYPESFN_FLAGS); + JS_FN("PointerType", PointerType::Create, 1, CTYPESCTOR_FLAGS); static JSPropertySpec sPointerProps[] = { { "targetType", 0, CTYPESPROP_FLAGS, PointerType::TargetTypeGetter, NULL }, { 0, 0, 0, NULL, NULL } }; static JSFunctionSpec sPointerInstanceFunctions[] = { JS_FN("isNull", PointerType::IsNull, 0, CTYPESFN_FLAGS), @@ -336,17 +330,17 @@ static JSFunctionSpec sPointerInstanceFu static JSPropertySpec sPointerInstanceProps[] = { { "contents", 0, JSPROP_SHARED | JSPROP_PERMANENT, PointerType::ContentsGetter, PointerType::ContentsSetter }, { 0, 0, 0, NULL, NULL } }; static JSFunctionSpec sArrayFunction = - JS_FN("ArrayType", ArrayType::Create, 1, CTYPESFN_FLAGS); + JS_FN("ArrayType", ArrayType::Create, 1, CTYPESCTOR_FLAGS); static JSPropertySpec sArrayProps[] = { { "elementType", 0, CTYPESPROP_FLAGS, ArrayType::ElementTypeGetter, NULL }, { "length", 0, CTYPESPROP_FLAGS, ArrayType::LengthGetter, NULL }, { 0, 0, 0, NULL, NULL } }; static JSFunctionSpec sArrayInstanceFunctions[] = { @@ -356,17 +350,17 @@ static JSFunctionSpec sArrayInstanceFunc static JSPropertySpec sArrayInstanceProps[] = { { "length", 0, JSPROP_SHARED | JSPROP_READONLY | JSPROP_PERMANENT, ArrayType::LengthGetter, NULL }, { 0, 0, 0, NULL, NULL } }; static JSFunctionSpec sStructFunction = - JS_FN("StructType", StructType::Create, 2, CTYPESFN_FLAGS); + JS_FN("StructType", StructType::Create, 2, CTYPESCTOR_FLAGS); static JSPropertySpec sStructProps[] = { { "fields", 0, CTYPESPROP_FLAGS, StructType::FieldsArrayGetter, NULL }, { 0, 0, 0, NULL, NULL } }; static JSFunctionSpec sStructFunctions[] = { JS_FN("define", StructType::Define, 1, CDATAFN_FLAGS), @@ -374,17 +368,17 @@ static JSFunctionSpec sStructFunctions[] }; static JSFunctionSpec sStructInstanceFunctions[] = { JS_FN("addressOfField", StructType::AddressOfField, 1, CDATAFN_FLAGS), JS_FS_END }; static JSFunctionSpec sFunctionFunction = - JS_FN("FunctionType", FunctionType::Create, 2, CTYPESFN_FLAGS); + JS_FN("FunctionType", FunctionType::Create, 2, CTYPESCTOR_FLAGS); static JSPropertySpec sFunctionProps[] = { { "argTypes", 0, CTYPESPROP_FLAGS, FunctionType::ArgTypesGetter, NULL }, { "returnType", 0, CTYPESPROP_FLAGS, FunctionType::ReturnTypeGetter, NULL }, { "abi", 0, CTYPESPROP_FLAGS, FunctionType::ABIGetter, NULL }, { "isVariadic", 0, CTYPESPROP_FLAGS, FunctionType::IsVariadicGetter, NULL }, { 0, 0, 0, NULL, NULL } }; @@ -531,17 +525,17 @@ TypeError(JSContext* cx, const char* exp CTYPESMSG_TYPE_ERROR, expected, src); return false; } static JSObject* InitCTypeClass(JSContext* cx, JSObject* parent) { JSFunction* fun = JS_DefineFunction(cx, parent, "CType", ConstructAbstract, 0, - CTYPESFN_FLAGS); + CTYPESCTOR_FLAGS); if (!fun) return NULL; JSObject* ctor = JS_GetFunctionObject(fun); JSObject* fnproto = JS_GetPrototype(cx, ctor); JS_ASSERT(ctor); JS_ASSERT(fnproto); @@ -569,17 +563,17 @@ InitCTypeClass(JSContext* cx, JSObject* return prototype; } static JSObject* InitCDataClass(JSContext* cx, JSObject* parent, JSObject* CTypeProto) { JSFunction* fun = JS_DefineFunction(cx, parent, "CData", ConstructAbstract, 0, - CTYPESFN_FLAGS); + CTYPESCTOR_FLAGS); if (!fun) return NULL; JSObject* ctor = JS_GetFunctionObject(fun); JS_ASSERT(ctor); // Set up ctypes.CData.__proto__ === ctypes.CType.prototype. // (Note that 'ctypes.CData instanceof Function' is still true, thanks to the @@ -2478,39 +2472,35 @@ BuildDataSource(JSContext* cx, } /******************************************************************************* ** JSAPI callback function implementations *******************************************************************************/ JSBool ConstructAbstract(JSContext* cx, - JSObject* obj, uintN argc, - jsval* argv, - jsval* rval) + jsval* vp) { // Calling an abstract base class constructor is disallowed. JS_ReportError(cx, "cannot construct from abstract type"); return JS_FALSE; } /******************************************************************************* ** CType implementation *******************************************************************************/ JSBool CType::ConstructData(JSContext* cx, - JSObject* obj, uintN argc, - jsval* argv, - jsval* rval) + jsval* vp) { // get the callee object... - obj = JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)); + JSObject* obj = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)); if (!CType::IsCType(cx, obj)) { JS_ReportError(cx, "not a CType"); return JS_FALSE; } // How we construct the CData object depends on what type we represent. // An instance 'd' of a CData object of type 't' has: // * [[Class]] "CData" @@ -2518,50 +2508,48 @@ CType::ConstructData(JSContext* cx, switch (GetTypeCode(cx, obj)) { case TYPE_void_t: JS_ReportError(cx, "cannot construct from void_t"); return JS_FALSE; case TYPE_function: JS_ReportError(cx, "cannot construct from FunctionType; use FunctionType.ptr instead"); return JS_FALSE; case TYPE_pointer: - return PointerType::ConstructData(cx, obj, argc, argv, rval); + return PointerType::ConstructData(cx, obj, argc, vp); case TYPE_array: - return ArrayType::ConstructData(cx, obj, argc, argv, rval); + return ArrayType::ConstructData(cx, obj, argc, vp); case TYPE_struct: - return StructType::ConstructData(cx, obj, argc, argv, rval); + return StructType::ConstructData(cx, obj, argc, vp); default: - return ConstructBasic(cx, obj, argc, argv, rval); + return ConstructBasic(cx, obj, argc, vp); } } JSBool CType::ConstructBasic(JSContext* cx, JSObject* obj, uintN argc, - jsval* argv, - jsval* rval) + jsval* vp) { if (argc > 1) { JS_ReportError(cx, "CType constructor takes zero or one argument"); return JS_FALSE; } // construct a CData object JSObject* result = CData::Create(cx, obj, NULL, NULL, true); if (!result) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(result); - if (argc == 1) { - if (!ExplicitConvert(cx, argv[0], obj, CData::GetData(cx, result))) + if (!ExplicitConvert(cx, JS_ARGV(cx, vp)[0], obj, CData::GetData(cx, result))) return JS_FALSE; } + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result)); return JS_TRUE; } JSObject* CType::Create(JSContext* cx, JSObject* typeProto, JSObject* dataProto, TypeCode type, @@ -3060,17 +3048,17 @@ CType::PtrGetter(JSContext* cx, JSObject if (!pointerType) return JS_FALSE; *vp = OBJECT_TO_JSVAL(pointerType); return JS_TRUE; } JSBool -CType::CreateArray(JSContext* cx, uintN argc, jsval *vp) +CType::CreateArray(JSContext* cx, uintN argc, jsval* vp) { JSObject* baseType = JS_THIS_OBJECT(cx, vp); JS_ASSERT(baseType); if (!CType::IsCType(cx, baseType)) { JS_ReportError(cx, "not a CType"); return JS_FALSE; } @@ -3093,17 +3081,17 @@ CType::CreateArray(JSContext* cx, uintN if (!result) return JS_FALSE; JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result)); return JS_TRUE; } JSBool -CType::ToString(JSContext* cx, uintN argc, jsval *vp) +CType::ToString(JSContext* cx, uintN argc, jsval* vp) { JSObject* obj = JS_THIS_OBJECT(cx, vp); JS_ASSERT(obj); if (!CType::IsCType(cx, obj)) { JS_ReportError(cx, "not a CType"); return JS_FALSE; } @@ -3116,17 +3104,17 @@ CType::ToString(JSContext* cx, uintN arg if (!result) return JS_FALSE; JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(result)); return JS_TRUE; } JSBool -CType::ToSource(JSContext* cx, uintN argc, jsval *vp) +CType::ToSource(JSContext* cx, uintN argc, jsval* vp) { JSObject* obj = JS_THIS_OBJECT(cx, vp); JS_ASSERT(obj); if (!CType::IsCType(cx, obj)) { JS_ReportError(cx, "not a CType"); return JS_FALSE; } @@ -3137,17 +3125,17 @@ CType::ToSource(JSContext* cx, uintN arg if (!result) return JS_FALSE; JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(result)); return JS_TRUE; } JSBool -CType::HasInstance(JSContext* cx, JSObject* obj, const jsval *v, JSBool* bp) +CType::HasInstance(JSContext* cx, JSObject* obj, const jsval* v, JSBool* bp) { JS_ASSERT(CType::IsCType(cx, obj)); jsval slot; ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_PROTO, &slot)); JSObject* prototype = JSVAL_TO_OBJECT(slot); JS_ASSERT(prototype); JS_ASSERT(JS_GET_CLASS(cx, prototype) == &sCDataProtoClass); @@ -3228,40 +3216,41 @@ PointerType::CreateInternal(JSContext* c return typeObj; } JSBool PointerType::ConstructData(JSContext* cx, JSObject* obj, uintN argc, - jsval* argv, - jsval* rval) + jsval* vp) { if (!CType::IsCType(cx, obj) || CType::GetTypeCode(cx, obj) != TYPE_pointer) { JS_ReportError(cx, "not a PointerType"); return JS_FALSE; } if (argc > 2) { JS_ReportError(cx, "constructor takes 0, 1, or 2 arguments"); return JS_FALSE; } JSObject* result = CData::Create(cx, obj, NULL, NULL, true); if (!result) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(result); + // Set return value early, must not observe *vp after + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result)); if (argc == 0) { // Construct a null pointer. return JS_TRUE; } + jsval* argv = JS_ARGV(cx, vp); if (argc >= 1) { JSObject* baseObj = PointerType::GetBaseType(cx, obj); if (CType::GetTypeCode(cx, baseObj) == TYPE_function && JSVAL_IS_OBJECT(argv[0]) && JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(argv[0]))) { // Construct a FunctionType.ptr from a JS function, and allow an // optional 'this' argument. JSObject* thisObj = NULL; @@ -3498,18 +3487,17 @@ ArrayType::CreateInternal(JSContext* cx, return typeObj; } JSBool ArrayType::ConstructData(JSContext* cx, JSObject* obj, uintN argc, - jsval* argv, - jsval* rval) + jsval* vp) { if (!CType::IsCType(cx, obj) || CType::GetTypeCode(cx, obj) != TYPE_array) { JS_ReportError(cx, "not an ArrayType"); return JS_FALSE; } // Decide whether we have an object to initialize from. We'll override this // if we get a length argument instead. @@ -3526,16 +3514,17 @@ ArrayType::ConstructData(JSContext* cx, } else { if (argc != 1) { JS_ReportError(cx, "constructor takes one argument"); return JS_FALSE; } JSObject* baseType = GetBaseType(cx, obj); + jsval* argv = JS_ARGV(cx, vp); size_t length; if (jsvalToSize(cx, argv[0], false, &length)) { // Have a length, rather than an object to initialize from. convertObject = false; } else if (!JSVAL_IS_PRIMITIVE(argv[0])) { // We were given an object with a .length property. // This could be a JS array, or a CData array. @@ -3586,20 +3575,20 @@ ArrayType::ConstructData(JSContext* cx, // Root the CType object, in case we created one above. js::AutoObjectRooter root(cx, obj); JSObject* result = CData::Create(cx, obj, NULL, NULL, true); if (!result) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(result); + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result)); if (convertObject) { - if (!ExplicitConvert(cx, argv[0], obj, CData::GetData(cx, result))) + if (!ExplicitConvert(cx, JS_ARGV(cx, vp)[0], obj, CData::GetData(cx, result))) return JS_FALSE; } return JS_TRUE; } JSObject* ArrayType::GetBaseType(JSContext* cx, JSObject* obj) @@ -3796,17 +3785,17 @@ ArrayType::Setter(JSContext* cx, JSObjec JSObject* baseType = GetBaseType(cx, typeObj); size_t elementSize = CType::GetSize(cx, baseType); char* data = static_cast<char*>(CData::GetData(cx, obj)) + elementSize * index; return ImplicitConvert(cx, *vp, baseType, data, false, NULL); } JSBool -ArrayType::AddressOfElement(JSContext* cx, uintN argc, jsval *vp) +ArrayType::AddressOfElement(JSContext* cx, uintN argc, jsval* vp) { JSObject* obj = JS_THIS_OBJECT(cx, vp); JS_ASSERT(obj); if (!CData::IsCData(cx, obj)) { JS_ReportError(cx, "not a CData"); return JS_FALSE; } @@ -4212,41 +4201,41 @@ StructType::Define(JSContext* cx, uintN return DefineInternal(cx, obj, JSVAL_TO_OBJECT(arg)); } JSBool StructType::ConstructData(JSContext* cx, JSObject* obj, uintN argc, - jsval* argv, - jsval* rval) + jsval* vp) { if (!CType::IsCType(cx, obj) || CType::GetTypeCode(cx, obj) != TYPE_struct) { JS_ReportError(cx, "not a StructType"); return JS_FALSE; } if (!CType::IsSizeDefined(cx, obj)) { JS_ReportError(cx, "cannot construct an opaque StructType"); return JS_FALSE; } JSObject* result = CData::Create(cx, obj, NULL, NULL, true); if (!result) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(result); + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result)); if (argc == 0) return JS_TRUE; char* buffer = static_cast<char*>(CData::GetData(cx, result)); const FieldInfoHash* fields = GetFieldInfo(cx, obj); + jsval* argv = JS_ARGV(cx, vp); if (argc == 1) { // There are two possible interpretations of the argument: // 1) It may be an object '{ ... }' with properties representing the // struct fields intended to ExplicitConvert wholesale to our StructType. // 2) If the struct contains one field, the arg may be intended to // ImplicitConvert directly to that arg's CType. // Thankfully, the conditions for these two possibilities to succeed // are mutually exclusive, so we can pick the right one. @@ -4424,17 +4413,17 @@ StructType::FieldSetter(JSContext* cx, J if (!field) return JS_FALSE; char* data = static_cast<char*>(CData::GetData(cx, obj)) + field->mOffset; return ImplicitConvert(cx, *vp, field->mType, data, false, NULL); } JSBool -StructType::AddressOfField(JSContext* cx, uintN argc, jsval *vp) +StructType::AddressOfField(JSContext* cx, uintN argc, jsval* vp) { JSObject* obj = JS_THIS_OBJECT(cx, vp); JS_ASSERT(obj); if (!CData::IsCData(cx, obj)) { JS_ReportError(cx, "not a CData"); return JS_FALSE; } @@ -4920,23 +4909,21 @@ ConvertArgument(JSContext* cx, strings->back().mData = *static_cast<char**>(value->mData); } return true; } JSBool FunctionType::Call(JSContext* cx, - JSObject* obj, uintN argc, - jsval* argv, - jsval* rval) + jsval* vp) { // get the callee object... - obj = JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)); + JSObject* obj = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)); if (!CData::IsCData(cx, obj)) { JS_ReportError(cx, "not a CData"); return false; } JSObject* typeObj = CData::GetCType(cx, obj); if (CType::GetTypeCode(cx, typeObj) != TYPE_pointer) { JS_ReportError(cx, "not a FunctionType.ptr"); @@ -4972,16 +4959,17 @@ FunctionType::Call(JSContext* cx, // prepare the values for each argument AutoValueAutoArray values; AutoValueAutoArray strings; if (!values.resize(argc)) { JS_ReportOutOfMemory(cx); return false; } + jsval* argv = JS_ARGV(cx, vp); for (jsuint i = 0; i < argcFixed; ++i) if (!ConvertArgument(cx, argv[i], fninfo->mArgTypes[i], &values[i], &strings)) return false; if (fninfo->mIsVariadic) { if (!fninfo->mFFITypes.resize(argc)) { JS_ReportOutOfMemory(cx); return false; @@ -5048,17 +5036,17 @@ FunctionType::Call(JSContext* cx, #define DEFINE_JSCHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z) #include "typedefs.h" default: break; } // prepare a JS object from the result return ConvertToJS(cx, fninfo->mReturnType, NULL, returnValue.mData, - false, true, rval); + false, true, vp); } FunctionInfo* FunctionType::GetFunctionInfo(JSContext* cx, JSObject* obj) { JS_ASSERT(CType::IsCType(cx, obj)); JS_ASSERT(CType::GetTypeCode(cx, obj) == TYPE_function); @@ -5568,17 +5556,17 @@ CData::ValueSetter(JSContext* cx, JSObje JS_ReportError(cx, "not a CData"); return JS_FALSE; } return ImplicitConvert(cx, *vp, GetCType(cx, obj), GetData(cx, obj), false, NULL); } JSBool -CData::Address(JSContext* cx, uintN argc, jsval *vp) +CData::Address(JSContext* cx, uintN argc, jsval* vp) { if (argc != 0) { JS_ReportError(cx, "address takes zero arguments"); return JS_FALSE; } JSObject* obj = JS_THIS_OBJECT(cx, vp); JS_ASSERT(obj); @@ -5603,17 +5591,17 @@ CData::Address(JSContext* cx, uintN argc // Manually set the pointer inside the object, so we skip the conversion step. void** data = static_cast<void**>(GetData(cx, result)); *data = GetData(cx, obj); return JS_TRUE; } JSBool -CData::Cast(JSContext* cx, uintN argc, jsval *vp) +CData::Cast(JSContext* cx, uintN argc, jsval* vp) { if (argc != 2) { JS_ReportError(cx, "cast takes two arguments"); return JS_FALSE; } jsval* argv = JS_ARGV(cx, vp); if (JSVAL_IS_PRIMITIVE(argv[0]) || @@ -5646,17 +5634,17 @@ CData::Cast(JSContext* cx, uintN argc, j if (!result) return JS_FALSE; JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result)); return JS_TRUE; } JSBool -CData::ReadString(JSContext* cx, uintN argc, jsval *vp) +CData::ReadString(JSContext* cx, uintN argc, jsval* vp) { if (argc != 0) { JS_ReportError(cx, "readString takes zero arguments"); return JS_FALSE; } JSObject* obj = JS_THIS_OBJECT(cx, vp); JS_ASSERT(obj); @@ -5739,17 +5727,17 @@ CData::ReadString(JSContext* cx, uintN a if (!result) return JS_FALSE; JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(result)); return JS_TRUE; } JSBool -CData::ToSource(JSContext* cx, uintN argc, jsval *vp) +CData::ToSource(JSContext* cx, uintN argc, jsval* vp) { if (argc != 0) { JS_ReportError(cx, "toSource takes zero arguments"); return JS_FALSE; } JSObject* obj = JS_THIS_OBJECT(cx, vp); if (!CData::IsCData(cx, obj)) { @@ -5834,17 +5822,17 @@ Int64Base::GetInt(JSContext* cx, JSObjec ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_INT64, &slot)); return *static_cast<JSUint64*>(JSVAL_TO_PRIVATE(slot)); } JSBool Int64Base::ToString(JSContext* cx, JSObject* obj, uintN argc, - jsval *vp, + jsval* vp, bool isUnsigned) { if (argc > 1) { JS_ReportError(cx, "toString takes zero or one argument"); return JS_FALSE; } jsuint radix = 10; @@ -5872,17 +5860,17 @@ Int64Base::ToString(JSContext* cx, JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(result)); return JS_TRUE; } JSBool Int64Base::ToSource(JSContext* cx, JSObject* obj, uintN argc, - jsval *vp, + jsval* vp, bool isUnsigned) { if (argc != 0) { JS_ReportError(cx, "toSource takes zero arguments"); return JS_FALSE; } // Return a decimal string suitable for constructing the number. @@ -5901,66 +5889,65 @@ Int64Base::ToSource(JSContext* cx, return JS_FALSE; JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(result)); return JS_TRUE; } JSBool Int64::Construct(JSContext* cx, - JSObject* obj, uintN argc, - jsval* argv, - jsval* rval) + jsval* vp) { // Construct and return a new Int64 object. if (argc != 1) { JS_ReportError(cx, "Int64 takes one argument"); return JS_FALSE; } + jsval* argv = JS_ARGV(cx, vp); JSInt64 i = 0; if (!jsvalToBigInteger(cx, argv[0], true, &i)) return TypeError(cx, "int64", argv[0]); // Get ctypes.Int64.prototype from the 'prototype' property of the ctor. jsval slot; - ASSERT_OK(JS_GetProperty(cx, JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)), + ASSERT_OK(JS_GetProperty(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)), "prototype", &slot)); JSObject* proto = JSVAL_TO_OBJECT(slot); JS_ASSERT(JS_GET_CLASS(cx, proto) == &sInt64ProtoClass); JSObject* result = Int64Base::Construct(cx, proto, i, false); if (!result) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(result); + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result)); return JS_TRUE; } bool Int64::IsInt64(JSContext* cx, JSObject* obj) { return JS_GET_CLASS(cx, obj) == &sInt64Class; } JSBool -Int64::ToString(JSContext* cx, uintN argc, jsval *vp) +Int64::ToString(JSContext* cx, uintN argc, jsval* vp) { JSObject* obj = JS_THIS_OBJECT(cx, vp); if (!Int64::IsInt64(cx, obj)) { JS_ReportError(cx, "not an Int64"); return JS_FALSE; } return Int64Base::ToString(cx, obj, argc, vp, false); } JSBool -Int64::ToSource(JSContext* cx, uintN argc, jsval *vp) +Int64::ToSource(JSContext* cx, uintN argc, jsval* vp) { JSObject* obj = JS_THIS_OBJECT(cx, vp); if (!Int64::IsInt64(cx, obj)) { JS_ReportError(cx, "not an Int64"); return JS_FALSE; } return Int64Base::ToSource(cx, obj, argc, vp, false); @@ -6057,83 +6044,82 @@ Int64::Join(JSContext* cx, uintN argc, j if (!jsvalToInteger(cx, argv[0], &hi)) return TypeError(cx, "int32", argv[0]); if (!jsvalToInteger(cx, argv[1], &lo)) return TypeError(cx, "uint32", argv[1]); JSInt64 i = (JSInt64(hi) << 32) + JSInt64(lo); // Get Int64.prototype from the function's reserved slot. - JSObject* callee = JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)); + JSObject* callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)); jsval slot; ASSERT_OK(JS_GetReservedSlot(cx, callee, SLOT_FN_INT64PROTO, &slot)); JSObject* proto = JSVAL_TO_OBJECT(slot); JS_ASSERT(JS_GET_CLASS(cx, proto) == &sInt64ProtoClass); JSObject* result = Int64Base::Construct(cx, proto, i, false); if (!result) return JS_FALSE; JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result)); return JS_TRUE; } JSBool UInt64::Construct(JSContext* cx, - JSObject* obj, uintN argc, - jsval* argv, - jsval* rval) + jsval* vp) { // Construct and return a new UInt64 object. if (argc != 1) { JS_ReportError(cx, "UInt64 takes one argument"); return JS_FALSE; } + jsval* argv = JS_ARGV(cx, vp); JSUint64 u = 0; if (!jsvalToBigInteger(cx, argv[0], true, &u)) return TypeError(cx, "uint64", argv[0]); // Get ctypes.UInt64.prototype from the 'prototype' property of the ctor. jsval slot; - ASSERT_OK(JS_GetProperty(cx, JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)), + ASSERT_OK(JS_GetProperty(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)), "prototype", &slot)); JSObject* proto = JSVAL_TO_OBJECT(slot); JS_ASSERT(JS_GET_CLASS(cx, proto) == &sUInt64ProtoClass); JSObject* result = Int64Base::Construct(cx, proto, u, true); if (!result) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(result); + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result)); return JS_TRUE; } bool UInt64::IsUInt64(JSContext* cx, JSObject* obj) { return JS_GET_CLASS(cx, obj) == &sUInt64Class; } JSBool -UInt64::ToString(JSContext* cx, uintN argc, jsval *vp) +UInt64::ToString(JSContext* cx, uintN argc, jsval* vp) { JSObject* obj = JS_THIS_OBJECT(cx, vp); if (!UInt64::IsUInt64(cx, obj)) { JS_ReportError(cx, "not a UInt64"); return JS_FALSE; } return Int64Base::ToString(cx, obj, argc, vp, true); } JSBool -UInt64::ToSource(JSContext* cx, uintN argc, jsval *vp) +UInt64::ToSource(JSContext* cx, uintN argc, jsval* vp) { JSObject* obj = JS_THIS_OBJECT(cx, vp); if (!UInt64::IsUInt64(cx, obj)) { JS_ReportError(cx, "not a UInt64"); return JS_FALSE; } return Int64Base::ToSource(cx, obj, argc, vp, true); @@ -6226,17 +6212,17 @@ UInt64::Join(JSContext* cx, uintN argc, if (!jsvalToInteger(cx, argv[0], &hi)) return TypeError(cx, "uint32_t", argv[0]); if (!jsvalToInteger(cx, argv[1], &lo)) return TypeError(cx, "uint32_t", argv[1]); JSUint64 u = (JSUint64(hi) << 32) + JSUint64(lo); // Get UInt64.prototype from the function's reserved slot. - JSObject* callee = JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)); + JSObject* callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)); jsval slot; ASSERT_OK(JS_GetReservedSlot(cx, callee, SLOT_FN_INT64PROTO, &slot)); JSObject* proto = JSVAL_TO_OBJECT(slot); JS_ASSERT(JS_GET_CLASS(cx, proto) == &sUInt64ProtoClass); JSObject* result = Int64Base::Construct(cx, proto, u, true); if (!result)
--- a/js/src/ctypes/Library.cpp +++ b/js/src/ctypes/Library.cpp @@ -66,17 +66,17 @@ static JSClass sLibraryClass = { "Library", JSCLASS_HAS_RESERVED_SLOTS(LIBRARY_SLOTS) | JSCLASS_MARK_IS_TRACE, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub,JS_ResolveStub, JS_ConvertStub, Library::Finalize, JSCLASS_NO_OPTIONAL_MEMBERS }; #define CTYPESFN_FLAGS \ - (JSFUN_FAST_NATIVE | JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT) + (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT) static JSFunctionSpec sLibraryFunctions[] = { JS_FN("close", Library::Close, 0, CTYPESFN_FLAGS), JS_FN("declare", Library::Declare, 0, CTYPESFN_FLAGS), JS_FS_END }; JSBool
--- a/js/src/jsapi-tests/testClassGetter.cpp +++ b/js/src/jsapi-tests/testClassGetter.cpp @@ -11,18 +11,22 @@ int called_test_prop_get; static JSBool test_prop_get( JSContext *cx, JSObject *obj, jsid id, jsval *vp ) { called_test_prop_get++; return JS_TRUE; } static JSBool -PTest(JSContext* cx, JSObject* obj, uintN argc, jsval *argv, jsval* rval) +PTest(JSContext* cx, uintN argc, jsval *vp) { + JSObject *obj = JS_NewObjectForConstructor(cx, vp); + if (!obj) + return JS_FALSE; + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj)); return JS_TRUE; } static JSClass ptestClass = { "PTest", JSCLASS_HAS_PRIVATE, JS_PropertyStub, // add @@ -31,24 +35,24 @@ static JSClass ptestClass = { JS_PropertyStub, // set JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, JSCLASS_NO_OPTIONAL_MEMBERS }; -static JSBool test_fn(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +static JSBool test_fn(JSContext *cx, uintN argc, jsval *vp) { called_test_fn++; return JS_TRUE; } static JSFunctionSpec ptestFunctions[] = { - JS_FS( "test_fn", test_fn, 0, 0, 0 ), + JS_FS( "test_fn", test_fn, 0, 0 ), JS_FS_END }; BEGIN_TEST(testClassGetter_isCalled) { JSObject *my_proto; my_proto = JS_InitClass(cx, JS_GetGlobalObject(cx), NULL, &ptestClass, PTest, 0,
--- a/js/src/jsapi-tests/testContexts.cpp +++ b/js/src/jsapi-tests/testContexts.cpp @@ -6,17 +6,17 @@ BEGIN_TEST(testContexts_IsRunning) { CHECK(JS_DefineFunction(cx, global, "chk", chk, 0, 0)); EXEC("for (var i = 0; i < 9; i++) chk();"); return true; } - static JSBool chk(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) + static JSBool chk(JSContext *cx, uintN argc, jsval *vp) { JSRuntime *rt = JS_GetRuntime(cx); JSContext *acx = JS_NewContext(rt, 8192); if (!acx) { JS_ReportOutOfMemory(cx); return JS_FALSE; }
--- a/js/src/jsapi-tests/testDefineGetterSetterNonEnumerable.cpp +++ b/js/src/jsapi-tests/testDefineGetterSetterNonEnumerable.cpp @@ -1,17 +1,17 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sw=4 et tw=99: */ #include "tests.h" #include "jsxdrapi.h" static JSBool -native(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +native(JSContext *cx, uintN argc, jsval *vp) { return JS_TRUE; } static const char PROPERTY_NAME[] = "foo"; BEGIN_TEST(testDefineGetterSetterNonEnumerable) {
--- a/js/src/jsapi-tests/testNewObject.cpp +++ b/js/src/jsapi-tests/testNewObject.cpp @@ -3,46 +3,48 @@ */ #include "tests.h" const size_t N = 1000; static jsval argv[N]; static JSBool -constructHook(JSContext *cx, JSObject *thisobj, uintN argc, jsval *argv, jsval *rval) +constructHook(JSContext *cx, uintN argc, jsval *vp) { // Check that arguments were passed properly from JS_New. - JSObject *callee = JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)); - if (!thisobj) { - JS_ReportError(cx, "test failed, null 'this'"); + JSObject *callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)); + + JSObject *obj = JS_NewObjectForConstructor(cx, vp); + if (!obj) { + JS_ReportError(cx, "test failed, could not construct object"); return false; } - if (strcmp(JS_GET_CLASS(cx, thisobj)->name, "Object") != 0) { + if (strcmp(JS_GET_CLASS(cx, obj)->name, "Object") != 0) { JS_ReportError(cx, "test failed, wrong class for 'this'"); return false; } if (argc != 3) { JS_ReportError(cx, "test failed, argc == %d", argc); return false; } if (!JSVAL_IS_INT(argv[2]) || JSVAL_TO_INT(argv[2]) != 2) { JS_ReportError(cx, "test failed, wrong value in argv[2]"); return false; } - if (!JS_IsConstructing(cx)) { + if (!JS_IsConstructing(cx, vp)) { JS_ReportError(cx, "test failed, not constructing"); return false; } // Perform a side-effect to indicate that this hook was actually called. if (!JS_SetElement(cx, callee, 0, &argv[0])) return false; - *rval = OBJECT_TO_JSVAL(callee); // return the callee, perversely + *vp = OBJECT_TO_JSVAL(obj); argv[0] = argv[1] = argv[2] = JSVAL_VOID; // trash the argv, perversely return true; } BEGIN_TEST(testNewObject_1) { jsval v; EVAL("Array", &v); @@ -86,16 +88,13 @@ BEGIN_TEST(testNewObject_1) JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, NULL, NULL, NULL, constructHook, NULL, NULL, NULL, NULL }; JSObject *ctor = JS_NewObject(cx, &cls, NULL, NULL); CHECK(ctor); jsvalRoot rt2(cx, OBJECT_TO_JSVAL(ctor)); obj = JS_New(cx, ctor, 3, argv); CHECK(obj); - CHECK(obj == ctor); // constructHook returns ctor, perversely CHECK(JS_GetElement(cx, ctor, 0, &v)); CHECK_SAME(v, JSVAL_ZERO); - CHECK_SAME(argv[0], JSVAL_ZERO); // original argv should not have been trashed - CHECK_SAME(argv[1], JSVAL_ONE); return true; } END_TEST(testNewObject_1)
--- a/js/src/jsapi-tests/testOps.cpp +++ b/js/src/jsapi-tests/testOps.cpp @@ -18,34 +18,34 @@ static JSClass myClass = { "MyClass", 0, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, my_convert, JS_FinalizeStub, JSCLASS_NO_OPTIONAL_MEMBERS }; static JSBool -createMyObject(JSContext* context, JSObject* obj, uintN argc, jsval *argv, jsval* rval) +createMyObject(JSContext* context, uintN argc, jsval *vp) { JS_BeginRequest(context); //JS_GC(context); //<- if we make GC here, all is ok JSObject* myObject = JS_NewObject(context, &myClass, NULL, NULL); - *rval = OBJECT_TO_JSVAL(myObject); + *vp = OBJECT_TO_JSVAL(myObject); JS_EndRequest(context); return JS_TRUE; } static JSFunctionSpec s_functions[] = { { "createMyObject", createMyObject, 0 }, - { 0,0,0,0,0 } + { 0,0,0,0 } }; BEGIN_TEST(testOps_bug559006) { CHECK(JS_DefineFunctions(cx, global, s_functions)); EXEC("function main() { while(1) return 0 + createMyObject(); }");
--- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -2924,16 +2924,25 @@ JS_NewObjectWithGivenProto(JSContext *cx clasp = &js_ObjectClass; /* default class is Object */ JS_ASSERT(clasp != &js_FunctionClass); JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL)); return NewNonFunction<WithProto::Given>(cx, clasp, proto, parent); } +JS_PUBLIC_API(JSObject *) +JS_NewObjectForConstructor(JSContext *cx, const jsval *vp) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, *vp); + + return js_NewInstance(cx, JSVAL_TO_OBJECT(*vp)); +} + JS_PUBLIC_API(JSBool) JS_SealObject(JSContext *cx, JSObject *obj, JSBool deep) { CHECK_REQUEST(cx); assertSameCompartment(cx, obj); /* Nothing to do if obj is already sealed. */ if (obj->sealed()) @@ -4143,24 +4152,24 @@ JS_GetFunctionArity(JSFunction *fun) JS_PUBLIC_API(JSBool) JS_ObjectIsFunction(JSContext *cx, JSObject *obj) { return obj->getClass() == &js_FunctionClass; } static JSBool -js_generic_fast_native_method_dispatcher(JSContext *cx, uintN argc, Value *vp) +js_generic_native_method_dispatcher(JSContext *cx, uintN argc, Value *vp) { JSFunctionSpec *fs; JSObject *tmp; - FastNative native; + Native native; fs = (JSFunctionSpec *) vp->toObject().getReservedSlot(0).toPrivate(); - JS_ASSERT((~fs->flags & (JSFUN_FAST_NATIVE | JSFUN_GENERIC_NATIVE)) == 0); + JS_ASSERT((fs->flags & JSFUN_GENERIC_NATIVE) != 0); if (argc < 1) { js_ReportMissingArg(cx, *vp, 0); return JS_FALSE; } if (vp[2].isPrimitive()) { /* @@ -4188,72 +4197,23 @@ js_generic_fast_native_method_dispatcher return JS_FALSE; /* Clear the last parameter in case too few arguments were passed. */ vp[2 + --argc].setUndefined(); native = #ifdef JS_TRACER (fs->flags & JSFUN_TRCINFO) - ? (FastNative) JS_FUNC_TO_DATA_PTR(JSNativeTraceInfo *, fs->call)->native + ? JS_FUNC_TO_DATA_PTR(JSNativeTraceInfo *, fs->call)->native : #endif - (FastNative) fs->call; + Valueify(fs->call); return native(cx, argc, vp); } -static JSBool -js_generic_native_method_dispatcher(JSContext *cx, JSObject *obj, - uintN argc, Value *argv, Value *rval) -{ - JSFunctionSpec *fs; - JSObject *tmp; - - fs = (JSFunctionSpec *) argv[-2].toObject().getReservedSlot(0).toPrivate(); - JS_ASSERT((fs->flags & (JSFUN_FAST_NATIVE | JSFUN_GENERIC_NATIVE)) == - JSFUN_GENERIC_NATIVE); - - if (argc < 1) { - js_ReportMissingArg(cx, *(argv - 2), 0); - return JS_FALSE; - } - - if (argv[0].isPrimitive()) { - /* - * Make sure that this is an object or null, as required by the generic - * functions. - */ - if (!js_ValueToObjectOrNull(cx, argv[0], &tmp)) - return JS_FALSE; - argv[0].setObjectOrNull(tmp); - } - - /* - * Copy all actual (argc) arguments down over our |this| parameter, - * argv[-1], which is almost always the class constructor object, e.g. - * Array. Then call the corresponding prototype native method with our - * first argument passed as |this|. - */ - memmove(argv - 1, argv, argc * sizeof(jsval)); - - /* - * Follow Function.prototype.apply and .call by using the global object as - * the 'this' param if no args. - */ - if (!ComputeThisFromArgv(cx, argv)) - return JS_FALSE; - js_GetTopStackFrame(cx)->setThisValue(argv[-1]); - JS_ASSERT(cx->fp()->argv == argv); - - /* Clear the last parameter in case too few arguments were passed. */ - argv[--argc].setUndefined(); - - return fs->call(cx, &argv[-1].toObject(), argc, Jsvalify(argv), Jsvalify(rval)); -} - JS_PUBLIC_API(JSBool) JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs) { uintN flags; JSObject *ctor; JSFunction *fun; CHECK_REQUEST(cx); @@ -4270,40 +4230,34 @@ JS_DefineFunctions(JSContext *cx, JSObje if (!ctor) { ctor = JS_GetConstructor(cx, obj); if (!ctor) return JS_FALSE; } flags &= ~JSFUN_GENERIC_NATIVE; fun = JS_DefineFunction(cx, ctor, fs->name, - (flags & JSFUN_FAST_NATIVE) - ? (JSNative) js_generic_fast_native_method_dispatcher - : Jsvalify(js_generic_native_method_dispatcher), + Jsvalify(js_generic_native_method_dispatcher), fs->nargs + 1, flags & ~JSFUN_TRCINFO); if (!fun) return JS_FALSE; - fun->u.n.extra = (uint16)fs->extra; /* * As jsapi.h notes, fs must point to storage that lives as long * as fun->object lives. */ Value priv = PrivateValue(fs); if (!js_SetReservedSlot(cx, FUN_OBJECT(fun), 0, priv)) return JS_FALSE; } - JS_ASSERT(!(flags & JSFUN_FAST_NATIVE) || - (uint16)(fs->extra >> 16) <= fs->nargs); fun = JS_DefineFunction(cx, obj, fs->name, fs->call, fs->nargs, flags); if (!fun) return JS_FALSE; - fun->u.n.extra = (uint16)fs->extra; } return JS_TRUE; } JS_PUBLIC_API(JSFunction *) JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call, uintN nargs, uintN attrs) { @@ -4766,46 +4720,46 @@ JS_EvaluateScript(JSContext *cx, JSObjec JS_PUBLIC_API(JSBool) JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc, jsval *argv, jsval *rval) { JSBool ok; CHECK_REQUEST(cx); assertSameCompartment(cx, obj, fun, JSValueArray(argv, argc)); - ok = InternalCall(cx, obj, ObjectValue(*fun), argc, Valueify(argv), Valueify(rval)); + ok = ExternalInvoke(cx, obj, ObjectValue(*fun), argc, Valueify(argv), Valueify(rval)); LAST_FRAME_CHECKS(cx, ok); return ok; } JS_PUBLIC_API(JSBool) JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc, jsval *argv, jsval *rval) { CHECK_REQUEST(cx); assertSameCompartment(cx, obj, JSValueArray(argv, argc)); AutoValueRooter tvr(cx); JSAtom *atom = js_Atomize(cx, name, strlen(name), 0); JSBool ok = atom && js_GetMethod(cx, obj, ATOM_TO_JSID(atom), JSGET_NO_METHOD_BARRIER, tvr.addr()) && - InternalCall(cx, obj, tvr.value(), argc, Valueify(argv), Valueify(rval)); + ExternalInvoke(cx, obj, tvr.value(), argc, Valueify(argv), Valueify(rval)); LAST_FRAME_CHECKS(cx, ok); return ok; } JS_PUBLIC_API(JSBool) JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc, jsval *argv, jsval *rval) { JSBool ok; CHECK_REQUEST(cx); assertSameCompartment(cx, obj, fval, JSValueArray(argv, argc)); - ok = InternalCall(cx, obj, Valueify(fval), argc, Valueify(argv), Valueify(rval)); + ok = ExternalInvoke(cx, obj, Valueify(fval), argc, Valueify(argv), Valueify(rval)); LAST_FRAME_CHECKS(cx, ok); return ok; } JS_PUBLIC_API(JSObject *) JS_New(JSContext *cx, JSObject *ctor, uintN argc, jsval *argv) { CHECK_REQUEST(cx); @@ -4888,22 +4842,16 @@ JS_IsRunning(JSContext *cx) JS_ASSERT_IF(JS_TRACE_MONITOR(cx).tracecx == cx, cx->hasfp()); #endif JSStackFrame *fp = cx->maybefp(); while (fp && fp->isDummyFrame()) fp = fp->down; return fp != NULL; } -JS_PUBLIC_API(JSBool) -JS_IsConstructing(JSContext *cx) -{ - return cx->isConstructing(); -} - JS_PUBLIC_API(JSStackFrame *) JS_SaveFrameChain(JSContext *cx) { CHECK_REQUEST(cx); JSStackFrame *fp = js_GetTopStackFrame(cx); if (!fp) return NULL; cx->saveActiveSegment();
--- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -479,32 +479,32 @@ extern JS_PUBLIC_DATA(jsid) JSID_EMPTY; set of the same-named property in an object that delegates to a prototype containing this property */ #define JSPROP_INDEX 0x80 /* name is actually (jsint) index */ #define JSPROP_SHORTID 0x100 /* set in JSPropertyDescriptor.attrs 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_THISP_FLAGS(f) (f) #define JSFUN_THISP_TEST(f,t) ((f) & t) #define JSFUN_THISP_STRING 0x0100 /* |this| may be a primitive string */ #define JSFUN_THISP_NUMBER 0x0200 /* |this| may be a primitive number */ #define JSFUN_THISP_BOOLEAN 0x0400 /* |this| may be a primitive boolean */ #define JSFUN_THISP_PRIMITIVE 0x0700 /* |this| may be any primitive value */ -#define JSFUN_FAST_NATIVE 0x0800 /* JSFastNative needs no JSStackFrame */ - -#define JSFUN_FLAGS_MASK 0x0ff8 /* overlay JSFUN_* attributes -- +#define JSFUN_FLAGS_MASK 0x07fa /* overlay JSFUN_* attributes -- bits 12-15 are used internally to flag interpreted functions */ #define JSFUN_STUB_GSOPS 0x1000 /* use JS_PropertyStub getter/setter instead of defaulting to class gsops for property holding function */ /* @@ -1073,19 +1073,21 @@ JS_InitCTypesClass(JSContext *cx, JSObje * NB: there is an anti-dependency between JS_CALLEE and JS_SET_RVAL: native * methods that may inspect their callee must defer setting their return value * until after any such possible inspection. Otherwise the return value will be * inspected instead of the callee function object. * * WARNING: These are not (yet) mandatory macros, but new code outside of the * engine should use them. In the Mozilla 2.0 milestone their definitions may * change incompatibly. + * + * N.B. constructors must not use JS_THIS, as no 'this' object has been created. */ + #define JS_CALLEE(cx,vp) ((vp)[0]) -#define JS_ARGV_CALLEE(argv) ((argv)[-2]) #define JS_THIS(cx,vp) JS_ComputeThis(cx, vp) #define JS_THIS_OBJECT(cx,vp) (JSVAL_TO_OBJECT(JS_THIS(cx,vp))) #define JS_ARGV(cx,vp) ((vp) + 2) #define JS_RVAL(cx,vp) (*(vp)) #define JS_SET_RVAL(cx,vp,v) (*(vp) = (v)) extern JS_PUBLIC_API(jsval) JS_ComputeThis(JSContext *cx, jsval *vp); @@ -1660,17 +1662,16 @@ struct JSClass { JSClassInternal reserved1; void *reserved[19]; }; #define JSCLASS_HAS_PRIVATE (1<<0) /* objects have private slot */ #define JSCLASS_NEW_ENUMERATE (1<<1) /* has JSNewEnumerateOp hook */ #define JSCLASS_NEW_RESOLVE (1<<2) /* has JSNewResolveOp hook */ #define JSCLASS_PRIVATE_IS_NSISUPPORTS (1<<3) /* private is (nsISupports *) */ -/* (1<<4) was JSCLASS_SHARE_ALL_PROPERTIES, now obsolete. See bug 527805. */ #define JSCLASS_NEW_RESOLVE_GETS_START (1<<5) /* JSNewResolveOp gets starting object in prototype chain passed in via *objp in/out parameter */ #define JSCLASS_CONSTRUCT_PROTOTYPE (1<<6) /* call constructor on class prototype */ #define JSCLASS_DOCUMENT_OBSERVER (1<<7) /* DOM document observer */ @@ -1793,48 +1794,33 @@ struct JSPropertySpec { JSPropertyOp setter; }; struct JSFunctionSpec { const char *name; JSNative call; uint16 nargs; uint16 flags; - - /* - * extra & 0xFFFF: Number of extra argument slots for local GC roots. - * If fast native, must be zero. - * extra >> 16: Reserved for future use (must be 0). - */ - uint32 extra; }; /* * Terminating sentinel initializer to put at the end of a JSFunctionSpec array * that's passed to JS_DefineFunctions or JS_InitClass. */ -#define JS_FS_END JS_FS(NULL,NULL,0,0,0) +#define JS_FS_END JS_FS(NULL,NULL,0,0) /* - * Initializer macro for a JSFunctionSpec array element. This is the original - * kind of native function specifier initializer. Use JS_FN ("fast native", see - * JSFastNative in jspubtd.h) for all functions that do not need a stack frame - * when activated. + * Initializer macros for a JSFunctionSpec array element. JS_FN (whose name + * pays homage to the old JSNative/JSFastNative split) simply adds the flag + * JSFUN_STUB_GSOPS. */ -#define JS_FS(name,call,nargs,flags,extra) \ - {name, call, nargs, flags, extra} - -/* - * "Fast native" initializer macro for a JSFunctionSpec array element. Use this - * in preference to JS_FS if the native in question does not need its own stack - * frame when activated. - */ -#define JS_FN(name,fastcall,nargs,flags) \ - JS_FS(name, (JSNative)(fastcall), nargs, \ - (flags) | JSFUN_FAST_NATIVE | JSFUN_STUB_GSOPS, 0) +#define JS_FS(name,call,nargs,flags) \ + {name, call, nargs, flags} +#define JS_FN(name,call,nargs,flags) \ + {name, call, nargs, (flags) | JSFUN_STUB_GSOPS} extern JS_PUBLIC_API(JSObject *) JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, JSClass *clasp, JSNative constructor, uintN nargs, JSPropertySpec *ps, JSFunctionSpec *fs, JSPropertySpec *static_ps, JSFunctionSpec *static_fs); #ifdef JS_THREADSAFE @@ -2581,19 +2567,16 @@ extern JS_PUBLIC_API(void) JS_TriggerOperationCallback(JSContext *cx); extern JS_PUBLIC_API(void) JS_TriggerAllOperationCallbacks(JSRuntime *rt); extern JS_PUBLIC_API(JSBool) JS_IsRunning(JSContext *cx); -extern JS_PUBLIC_API(JSBool) -JS_IsConstructing(JSContext *cx); - /* * Saving and restoring frame chains. * * These two functions are used to set aside cx's call stack while that stack * is inactive. After a call to JS_SaveFrameChain, it looks as if there is no * code running on cx. Before calling JS_RestoreFrameChain, cx's call stack * must be balanced and all nested calls to JS_SaveFrameChain must have had * matching JS_RestoreFrameChain calls. @@ -3059,16 +3042,97 @@ extern JS_PUBLIC_API(void) JS_SetFunctionCallback(JSContext *cx, JSFunctionCallback fcb); extern JS_PUBLIC_API(JSFunctionCallback) JS_GetFunctionCallback(JSContext *cx); #endif /************************************************************************/ +/* + * JS_IsConstructing must be called from within a native given the + * native's original cx and vp arguments. If JS_IsConstructing is true, + * JS_THIS must not be used; the constructor should construct and return a + * new object. Otherwise, the native is called as an ordinary function and + * JS_THIS may be used. + */ +static JS_ALWAYS_INLINE JSBool +JS_IsConstructing(JSContext *cx, const jsval *vp) +{ + jsval_layout l; + +#ifdef DEBUG + JSObject *callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)); + if (JS_ObjectIsFunction(cx, callee)) { + JSFunction *fun = JS_ValueToFunction(cx, JS_CALLEE(cx, vp)); + JS_ASSERT((JS_GetFunctionFlags(fun) & JSFUN_CONSTRUCTOR) != 0); + } else { + JS_ASSERT(JS_GET_CLASS(cx, callee)->construct != NULL); + } +#endif + + l.asBits = JSVAL_BITS(vp[1]); + return JSVAL_IS_MAGIC_IMPL(l); +} + +/* + * In the case of a constructor called from JS_ConstructObject and + * JS_InitClass where the class has the JSCLASS_CONSTRUCT_PROTOTYPE flag set, + * the JS engine passes the constructor a non-standard 'this' object. In such + * cases, the following query provides the additional information of whether a + * special 'this' was supplied. E.g.: + * + * JSBool foo_native(JSContext *cx, uintN argc, jsval *vp) { + * JSObject *maybeThis; + * if (JS_IsConstructing_PossiblyWithGivenThisObject(cx, vp, &maybeThis)) { + * // native called as a constructor + * if (maybeThis) + * // native called as a constructor with maybeThis as 'this' + * } else { + * // native called as function, maybeThis is still uninitialized + * } + * } + * + * Note that embeddings do not need to use this query unless they use the + * aforementioned API/flags. + */ +static JS_ALWAYS_INLINE JSBool +JS_IsConstructing_PossiblyWithGivenThisObject(JSContext *cx, const jsval *vp, + JSObject **maybeThis) +{ + jsval_layout l; + JSBool isCtor; + +#ifdef DEBUG + JSObject *callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)); + if (JS_ObjectIsFunction(cx, callee)) { + JSFunction *fun = JS_ValueToFunction(cx, JS_CALLEE(cx, vp)); + JS_ASSERT((JS_GetFunctionFlags(fun) & JSFUN_CONSTRUCTOR) != 0); + } else { + JS_ASSERT(JS_GET_CLASS(cx, callee)->construct != NULL); + } +#endif + + l.asBits = JSVAL_BITS(vp[1]); + isCtor = JSVAL_IS_MAGIC_IMPL(l); + if (isCtor) + *maybeThis = MAGIC_JSVAL_TO_OBJECT_OR_NULL_IMPL(l); + return isCtor; +} + +/* + * If a constructor does not have any static knowledge about the type of + * object to create, it can request that the JS engine create a default new + * 'this' object, as is done for non-constructor natives when called with new. + */ +extern JS_PUBLIC_API(JSObject *) +JS_NewObjectForConstructor(JSContext *cx, const jsval *vp); + +/************************************************************************/ + #ifdef DEBUG #define JS_GC_ZEAL 1 #endif #ifdef JS_GC_ZEAL extern JS_PUBLIC_API(void) JS_SetGCZeal(JSContext *cx, uint8 zeal); #endif
--- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -1003,18 +1003,17 @@ array_trace(JSTracer *trc, JSObject *obj static_cast<GCMarker *>(trc)->arraysToSlowify.append(obj); } } Class js_ArrayClass = { "Array", Class::NON_NATIVE | JSCLASS_HAS_RESERVED_SLOTS(JSObject::DENSE_ARRAY_CLASS_RESERVED_SLOTS) | - JSCLASS_HAS_CACHED_PROTO(JSProto_Array) | - JSCLASS_FAST_CONSTRUCTOR, + JSCLASS_HAS_CACHED_PROTO(JSProto_Array), PropertyStub, /* addProperty */ PropertyStub, /* delProperty */ PropertyStub, /* getProperty */ PropertyStub, /* setProperty */ EnumerateStub, ResolveStub, js_TryValueOf, array_finalize, @@ -1040,18 +1039,17 @@ Class js_ArrayClass = { NULL, /* thisObject */ NULL, /* clear */ } }; Class js_SlowArrayClass = { "Array", JSCLASS_HAS_PRIVATE | - JSCLASS_HAS_CACHED_PROTO(JSProto_Array) | - JSCLASS_FAST_CONSTRUCTOR, + JSCLASS_HAS_CACHED_PROTO(JSProto_Array), slowarray_addProperty, PropertyStub, /* delProperty */ PropertyStub, /* getProperty */ PropertyStub, /* setProperty */ EnumerateStub, ResolveStub, js_TryValueOf }; @@ -2905,21 +2903,21 @@ array_some(JSContext *cx, uintN argc, Va static JSBool array_every(JSContext *cx, uintN argc, Value *vp) { return array_extra(cx, EVERY, argc, vp); } #endif static JSBool -array_isArray(JSContext *cx, uintN argc, jsval *vp) +array_isArray(JSContext *cx, uintN argc, Value *vp) { - *vp = BOOLEAN_TO_JSVAL(argc > 0 && - !JSVAL_IS_PRIMITIVE(vp[2]) && - JSVAL_TO_OBJECT(vp[2])->wrappedObject(cx)->isArray()); + vp->setBoolean(argc > 0 && + vp[2].isObject() && + vp[2].toObject().wrappedObject(cx)->isArray()); return JS_TRUE; } static JSFunctionSpec array_methods[] = { #if JS_HAS_TOSOURCE JS_FN(js_toSource_str, array_toSource, 0,0), #endif JS_FN(js_toString_str, array_toString, 0,0), @@ -3033,17 +3031,17 @@ js_NewPreallocatedArray(JSContext* cx, J #ifdef JS_TRACER JS_DEFINE_CALLINFO_3(extern, OBJECT, js_NewPreallocatedArray, CONTEXT, OBJECT, INT32, 0, nanojit::ACCSET_STORE_ANY) #endif JSObject * js_InitArrayClass(JSContext *cx, JSObject *obj) { - JSObject *proto = js_InitClass(cx, obj, NULL, &js_ArrayClass, (Native) js_Array, 1, + JSObject *proto = js_InitClass(cx, obj, NULL, &js_ArrayClass, js_Array, 1, NULL, array_methods, NULL, array_static_methods); if (!proto) return NULL; /* * Assert that js_InitClass used the correct (slow array, not dense array) * class for proto's emptyShape class. */
--- a/js/src/jsbool.cpp +++ b/js/src/jsbool.cpp @@ -55,17 +55,18 @@ #include "jsvector.h" #include "jsobjinlines.h" using namespace js; Class js_BooleanClass = { "Boolean", - JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Boolean), + JSCLASS_HAS_RESERVED_SLOTS(1) | + JSCLASS_HAS_CACHED_PROTO(JSProto_Boolean), PropertyStub, /* addProperty */ PropertyStub, /* delProperty */ PropertyStub, /* getProperty */ PropertyStub, /* setProperty */ EnumerateStub, ResolveStub, ConvertStub }; @@ -121,28 +122,30 @@ static JSFunctionSpec boolean_methods[] #endif JS_FN(js_toString_str, bool_toString, 0, JSFUN_THISP_BOOLEAN), JS_FN(js_valueOf_str, bool_valueOf, 0, JSFUN_THISP_BOOLEAN), JS_FN(js_toJSON_str, bool_valueOf, 0, JSFUN_THISP_BOOLEAN), JS_FS_END }; static JSBool -Boolean(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) +Boolean(JSContext *cx, uintN argc, Value *vp) { - Value bval; + Value *argv = vp + 2; + bool b = argc != 0 ? js_ValueToBoolean(argv[0]) : false; - if (argc != 0) - bval.setBoolean(!!js_ValueToBoolean(argv[0])); - else - bval.setBoolean(false); - if (!JS_IsConstructing(cx)) - *rval = bval; - else - obj->setPrimitiveThis(bval); + if (IsConstructing(vp)) { + JSObject *obj = NewBuiltinClassInstance(cx, &js_BooleanClass); + if (!obj) + return false; + obj->setPrimitiveThis(BooleanValue(b)); + vp->setObject(*obj); + } else { + vp->setBoolean(b); + } return true; } JSObject * js_InitBooleanClass(JSContext *cx, JSObject *obj) { JSObject *proto;
--- a/js/src/jsbuiltins.h +++ b/js/src/jsbuiltins.h @@ -38,16 +38,17 @@ * ***** END LICENSE BLOCK ***** */ #ifndef jsbuiltins_h___ #define jsbuiltins_h___ #ifdef JS_TRACER #include "nanojit/nanojit.h" +#include "jsvalue.h" #ifdef THIS #undef THIS #endif enum JSTNErrType { INFALLIBLE, FAIL_STATUS, FAIL_NULL, FAIL_NEG, FAIL_NEITHER }; enum { JSTN_ERRTYPE_MASK = 0x07, @@ -56,17 +57,17 @@ enum { JSTN_CONSTRUCTOR = 0x20, JSTN_RETURN_NULLABLE_STR = 0x40, JSTN_RETURN_NULLABLE_OBJ = 0x80 }; #define JSTN_ERRTYPE(jstn) ((jstn)->flags & JSTN_ERRTYPE_MASK) /* - * Type describing a type specialization of a JSFastNative. + * Type describing a type specialization of a js::Native. * * |prefix| and |argtypes| declare what arguments should be passed to the * native function. |prefix| can contain the following characters: * * 'C': a JSContext* argument * 'T': |this| as a JSObject* argument (bails if |this| is not an object) * 'S': |this| as a JSString* argument (bails if |this| is not a string) * 'R': a JSRuntime* argument @@ -98,17 +99,17 @@ struct JSSpecializedNative { /* * Type holding extra trace-specific information about a fast native. * * 'specializations' points to a static array of available specializations * terminated by the lack of having the JSTN_MORE flag set. */ struct JSNativeTraceInfo { - JSFastNative native; + js::Native native; JSSpecializedNative *specializations; }; /* Macros used by JS_DEFINE_CALLINFOn. */ #ifdef DEBUG #define _JS_CI_NAME(op) ,#op #else #define _JS_CI_NAME(op) @@ -501,50 +502,50 @@ struct ClosureVarInfo; _JS_CTYPE_ACH(at3) _JS_CTYPE_ACH(at2) _JS_CTYPE_ACH(at1) _JS_CTYPE_ACH(at0), \ _JS_CTYPE_FLAGS(rt) #define JS_DEFINE_TRCINFO_1(name, tn0) \ _JS_DEFINE_CALLINFO_n tn0 \ JSSpecializedNative name##_sns[] = { \ { _JS_TN_INIT_HELPER_n tn0 } \ }; \ - JSNativeTraceInfo name##_trcinfo = { (JSFastNative)name, name##_sns }; + JSNativeTraceInfo name##_trcinfo = { JS_VALUEIFY_NATIVE(name), name##_sns }; #define JS_DEFINE_TRCINFO_2(name, tn0, tn1) \ _JS_DEFINE_CALLINFO_n tn0 \ _JS_DEFINE_CALLINFO_n tn1 \ JSSpecializedNative name##_sns[] = { \ { _JS_TN_INIT_HELPER_n tn0 | JSTN_MORE }, \ { _JS_TN_INIT_HELPER_n tn1 } \ }; \ - JSNativeTraceInfo name##_trcinfo = { (JSFastNative)name, name##_sns }; + JSNativeTraceInfo name##_trcinfo = { JS_VALUEIFY_NATIVE(name), name##_sns }; #define JS_DEFINE_TRCINFO_3(name, tn0, tn1, tn2) \ _JS_DEFINE_CALLINFO_n tn0 \ _JS_DEFINE_CALLINFO_n tn1 \ _JS_DEFINE_CALLINFO_n tn2 \ JSSpecializedNative name##_sns[] = { \ { _JS_TN_INIT_HELPER_n tn0 | JSTN_MORE }, \ { _JS_TN_INIT_HELPER_n tn1 | JSTN_MORE }, \ { _JS_TN_INIT_HELPER_n tn2 } \ }; \ - JSNativeTraceInfo name##_trcinfo = { (JSFastNative)name, name##_sns }; + JSNativeTraceInfo name##_trcinfo = { JS_VALUEIFY_NATIVE(name), name##_sns }; #define JS_DEFINE_TRCINFO_4(name, tn0, tn1, tn2, tn3) \ _JS_DEFINE_CALLINFO_n tn0 \ _JS_DEFINE_CALLINFO_n tn1 \ _JS_DEFINE_CALLINFO_n tn2 \ _JS_DEFINE_CALLINFO_n tn3 \ JSSpecializedNative name##_sns[] = { \ { _JS_TN_INIT_HELPER_n tn0 | JSTN_MORE }, \ { _JS_TN_INIT_HELPER_n tn1 | JSTN_MORE }, \ { _JS_TN_INIT_HELPER_n tn2 | JSTN_MORE }, \ { _JS_TN_INIT_HELPER_n tn3 } \ }; \ - JSNativeTraceInfo name##_trcinfo = { (JSFastNative)name, name##_sns }; + JSNativeTraceInfo name##_trcinfo = { JS_VALUEIFY_NATIVE(name), name##_sns }; #define _JS_DEFINE_CALLINFO_n(n, args) JS_DEFINE_CALLINFO_##n args jsdouble FASTCALL js_StringToNumber(JSContext* cx, JSString* str); /* Extern version of SetBuiltinError. */ extern JS_FRIEND_API(void) @@ -606,17 +607,17 @@ JS_DECLARE_CALLINFO(js_CloneFunctionObje JS_DECLARE_CALLINFO(js_CreateCallObjectOnTrace) JS_DECLARE_CALLINFO(js_Arguments) /* Defined in jsnum.cpp. */ JS_DECLARE_CALLINFO(js_NumberToString) /* Defined in jsobj.cpp. */ JS_DECLARE_CALLINFO(js_Object_tn) -JS_DECLARE_CALLINFO(js_NewInstance) +JS_DECLARE_CALLINFO(js_NewInstanceFromTrace) JS_DECLARE_CALLINFO(js_NonEmptyObject) /* Defined in jsregexp.cpp. */ JS_DECLARE_CALLINFO(js_CloneRegExpObject) /* Defined in jsstr.cpp. */ JS_DECLARE_CALLINFO(js_String_tn) JS_DECLARE_CALLINFO(js_CompareStrings)
--- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -336,47 +336,16 @@ FrameGuard::~FrameGuard() { if (!pushed()) return; JS_ASSERT(cx->activeSegment() == seg); JS_ASSERT(cx->maybefp() == fp); cx->stack().popFrame(cx); } -JS_REQUIRES_STACK void -StackSpace::getSynthesizedSlowNativeFrame(JSContext *cx, StackSegment *&seg, JSStackFrame *&fp) -{ - Value *start = firstUnused(); - JS_ASSERT(size_t(end - start) >= VALUES_PER_STACK_SEGMENT + VALUES_PER_STACK_FRAME); - seg = new(start) StackSegment; - fp = reinterpret_cast<JSStackFrame *>(seg + 1); -} - -JS_REQUIRES_STACK void -StackSpace::pushSynthesizedSlowNativeFrame(JSContext *cx, StackSegment *seg, JSFrameRegs ®s) -{ - JS_ASSERT(!regs.fp->hasScript() && FUN_SLOW_NATIVE(regs.fp->getFunction())); - regs.fp->down = cx->maybefp(); - seg->setPreviousInMemory(currentSegment); - currentSegment = seg; - cx->pushSegmentAndFrame(seg, regs); - seg->setInitialVarObj(NULL); -} - -JS_REQUIRES_STACK void -StackSpace::popSynthesizedSlowNativeFrame(JSContext *cx) -{ - JS_ASSERT(isCurrentAndActive(cx)); - JS_ASSERT(cx->hasActiveSegment()); - JS_ASSERT(currentSegment->getInitialFrame() == cx->fp()); - JS_ASSERT(!cx->fp()->hasScript() && FUN_SLOW_NATIVE(cx->fp()->getFunction())); - cx->popSegmentAndFrame(); - currentSegment = currentSegment->getPreviousInMemory(); -} - JS_REQUIRES_STACK bool StackSpace::pushDummyFrame(JSContext *cx, FrameGuard &fg, JSFrameRegs ®s, JSObject *scopeChain) { if (!getExecuteFrame(cx, cx->maybefp(), 0, 0, fg)) return false; JSStackFrame *fp = fg.getFrame(); PodZero(fp); @@ -1942,22 +1911,20 @@ js_TriggerAllOperationCallbacks(JSRuntim i.threadData()->triggerOperationCallback(); } JSStackFrame * js_GetScriptedCaller(JSContext *cx, JSStackFrame *fp) { if (!fp) fp = js_GetTopStackFrame(cx); - while (fp) { - if (fp->hasScript()) - return fp; + while (fp && fp->isDummyFrame()) fp = fp->down; - } - return NULL; + JS_ASSERT_IF(fp, fp->hasScript()); + return fp; } jsbytecode* js_GetCurrentBytecodePC(JSContext* cx) { jsbytecode *pc, *imacpc; #ifdef JS_TRACER @@ -2190,30 +2157,16 @@ JSContext::checkMallocGCPressure(void *p * their manipulation is not thread-safe. */ JS_THREAD_DATA(this)->gcFreeLists.purge(); js_TriggerGC(this, true); } } } -bool -JSContext::isConstructing() -{ -#ifdef JS_TRACER - if (JS_ON_TRACE(this)) { - JS_ASSERT(bailExit); - return *bailExit->pc == JSOP_NEW; - } -#endif - JSStackFrame *fp = js_GetTopStackFrame(this); - return fp && (fp->flags & JSFRAME_CONSTRUCTING); -} - - /* * Release pool's arenas if the stackPool has existed for longer than the * limit specified by gcEmptyArenaPoolLifespan. */ inline void FreeOldArenas(JSRuntime *rt, JSArenaPool *pool) { JSArena *a = pool->current;
--- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -805,29 +805,16 @@ class StackSpace JS_REQUIRES_STACK inline void pushInlineFrame(JSContext *cx, JSStackFrame *fp, jsbytecode *pc, JSStackFrame *newfp); JS_REQUIRES_STACK inline void popInlineFrame(JSContext *cx, JSStackFrame *up, JSStackFrame *down); /* - * For the special case of the slow native stack frame pushed and popped by - * tracing deep bail logic. - */ - JS_REQUIRES_STACK - void getSynthesizedSlowNativeFrame(JSContext *cx, StackSegment *&seg, JSStackFrame *&fp); - - JS_REQUIRES_STACK - void pushSynthesizedSlowNativeFrame(JSContext *cx, StackSegment *seg, JSFrameRegs ®s); - - JS_REQUIRES_STACK - void popSynthesizedSlowNativeFrame(JSContext *cx); - - /* * For pushing a bookkeeping frame. */ JS_REQUIRES_STACK bool pushDummyFrame(JSContext *cx, FrameGuard &fg, JSFrameRegs ®s, JSObject *scopeChain); /* * Ensure space based on an over-recursion limit. */ @@ -2356,18 +2343,16 @@ struct JSContext #undef CREATE_BODY template <class T> JS_ALWAYS_INLINE void destroy(T *p) { p->~T(); this->free(p); } - bool isConstructing(); - void purge(); js::StackSpace &stack() const { return JS_THREAD_DATA(this)->stackSpace; } #ifdef DEBUG void assertValidStackDepth(uintN depth) {
--- a/js/src/jscntxtinlines.h +++ b/js/src/jscntxtinlines.h @@ -599,47 +599,63 @@ assertSameCompartment(JSContext *cx, T1 c.check(t3); c.check(t4); c.check(t5); #endif } #undef START_ASSERT_SAME_COMPARTMENT -inline JSBool -CallJSNative(JSContext *cx, js::Native native, JSObject *thisobj, uintN argc, js::Value *argv, js::Value *rval) +JS_ALWAYS_INLINE bool +CallJSNative(JSContext *cx, js::Native native, uintN argc, js::Value *vp) { - assertSameCompartment(cx, thisobj, ValueArray(argv, argc)); - JSBool ok = native(cx, thisobj, argc, argv, rval); - if (ok) - assertSameCompartment(cx, *rval); +#ifdef DEBUG + JSBool alreadyThrowing = cx->throwing; +#endif + assertSameCompartment(cx, ValueArray(vp, argc + 2)); + JSBool ok = native(cx, argc, vp); + if (ok) { + assertSameCompartment(cx, vp[0]); + JS_ASSERT_IF(!alreadyThrowing, !cx->throwing); + } return ok; } -inline JSBool -CallJSFastNative(JSContext *cx, js::FastNative native, uintN argc, js::Value *vp) +JS_ALWAYS_INLINE bool +CallJSNativeConstructor(JSContext *cx, js::Native native, uintN argc, js::Value *vp) { - assertSameCompartment(cx, ValueArray(vp, argc + 2)); - JSBool ok = native(cx, argc, vp); - if (ok) - assertSameCompartment(cx, vp[0]); - return ok; +#ifdef DEBUG + JSObject *callee = &vp[0].toObject(); +#endif + + JS_ASSERT(vp[1].isMagic()); + if (!CallJSNative(cx, native, argc, vp)) + return false; + JS_ASSERT(!vp->isPrimitive()); + + /* + * Even though its technically legal, if a native constructor returns the + * callee, there is a 99.9999% chance it is a bug. If any valid code + * actually wants the constructor to return the callee, this can be removed. + */ + JS_ASSERT(callee != &vp[0].toObject()); + return true; } -inline JSBool +JS_ALWAYS_INLINE bool CallJSPropertyOp(JSContext *cx, js::PropertyOp op, JSObject *obj, jsid id, js::Value *vp) { assertSameCompartment(cx, obj, id, *vp); JSBool ok = op(cx, obj, id, vp); if (ok) assertSameCompartment(cx, obj, *vp); return ok; } -inline JSBool +JS_ALWAYS_INLINE bool CallJSPropertyOpSetter(JSContext *cx, js::PropertyOp op, JSObject *obj, jsid id, js::Value *vp) { assertSameCompartment(cx, obj, id, *vp); return op(cx, obj, id, vp); } } /* namespace js */
--- a/js/src/jsdate.cpp +++ b/js/src/jsdate.cpp @@ -492,18 +492,17 @@ msFromTime(jsdouble t) /* * Other Support routines and definitions */ Class js_DateClass = { js_Date_str, JSCLASS_HAS_RESERVED_SLOTS(JSObject::DATE_CLASS_RESERVED_SLOTS) | - JSCLASS_HAS_CACHED_PROTO(JSProto_Date) | - JSCLASS_FAST_CONSTRUCTOR, + JSCLASS_HAS_CACHED_PROTO(JSProto_Date), PropertyStub, /* addProperty */ PropertyStub, /* delProperty */ PropertyStub, /* getProperty */ PropertyStub, /* setProperty */ EnumerateStub, ResolveStub, ConvertStub }; @@ -2474,67 +2473,69 @@ static JSFunctionSpec date_methods[] = { JS_FN(js_valueOf_str, date_valueOf, 0,0), JS_FS_END }; JSBool js_Date(JSContext *cx, uintN argc, Value *vp) { /* Date called as function. */ - if (!vp[1].isMagic(JS_FAST_CONSTRUCTOR)) + if (!IsConstructing(vp)) return date_format(cx, NowAsMillis(), FORMATSPEC_FULL, vp); + Value *argv = vp + 2; + /* Date called as constructor. */ jsdouble d; if (argc == 0) { d = NowAsMillis(); } else if (argc == 1) { - if (!vp[2].isString()) { + if (!argv[0].isString()) { /* the argument is a millisecond number */ - if (!ValueToNumber(cx, vp[2], &d)) - return JS_FALSE; + if (!ValueToNumber(cx, argv[0], &d)) + return false; d = TIMECLIP(d); } else { /* the argument is a string; parse it. */ - JSString *str = js_ValueToString(cx, vp[2]); + JSString *str = js_ValueToString(cx, argv[0]); if (!str) - return JS_FALSE; - vp[2].setString(str); + return false; + argv[0].setString(str); if (!date_parseString(str, &d, cx)) d = js_NaN; else d = TIMECLIP(d); } } else { jsdouble msec_time; - if (!date_msecFromArgs(cx, argc, vp + 2, &msec_time)) - return JS_FALSE; + if (!date_msecFromArgs(cx, argc, argv, &msec_time)) + return false; if (JSDOUBLE_IS_FINITE(msec_time)) { msec_time = UTC(msec_time, cx); msec_time = TIMECLIP(msec_time); } d = msec_time; } JSObject *obj = js_NewDateObjectMsec(cx, d); if (!obj) - return JS_FALSE; + return false; vp->setObject(*obj); - return JS_TRUE; + return true; } JSObject * js_InitDateClass(JSContext *cx, JSObject *obj) { /* set static LocalTZA */ LocalTZA = -(PRMJ_LocalGMTDifference() * msPerSecond); - JSObject *proto = js_InitClass(cx, obj, NULL, &js_DateClass, (Native) js_Date, MAXARGS, + JSObject *proto = js_InitClass(cx, obj, NULL, &js_DateClass, js_Date, MAXARGS, NULL, date_methods, NULL, date_static_methods); if (!proto) return NULL; AutoObjectRooter tvr(cx, proto); SetDateToNaN(cx, proto);
--- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -88,25 +88,27 @@ typedef struct JSTrap { #define DBG_LOCK_EVAL(rt,expr) (DBG_LOCK(rt), (expr), DBG_UNLOCK(rt)) JS_PUBLIC_API(JSBool) JS_GetDebugMode(JSContext *cx) { return cx->compartment->debugMode; } +#ifdef JS_METHODJIT static bool IsScriptLive(JSContext *cx, JSScript *script) { for (AllFramesIter i(cx); !i.done(); ++i) { if (i.fp()->maybeScript() == script) return true; } return false; } +#endif JS_FRIEND_API(JSBool) js_SetDebugMode(JSContext *cx, JSBool debug) { cx->compartment->debugMode = debug; #ifdef JS_METHODJIT for (JSScript *script = (JSScript *)cx->compartment->scripts.next; &script->links != &cx->compartment->scripts; @@ -132,17 +134,17 @@ js_SetDebugMode(JSContext *cx, JSBool de return JS_TRUE; } JS_PUBLIC_API(JSBool) JS_SetDebugMode(JSContext *cx, JSBool debug) { #ifdef DEBUG for (AllFramesIter i(cx); !i.done(); ++i) - JS_ASSERT(JS_IsNativeFrame(cx, i.fp())); + JS_ASSERT(!JS_IsScriptFrame(cx, i.fp())); #endif return js_SetDebugMode(cx, debug); } static JSBool CheckDebugMode(JSContext *cx) { @@ -693,54 +695,54 @@ js_watch_set(JSContext *cx, JSObject *ob } /* * Pass the output of the handler to the setter. Security wrappers * prevent any funny business between watchpoints and setters. */ JSBool ok = !wp->setter || (shape->hasSetterValue() - ? InternalCall(cx, obj, - ObjectValue(*CastAsObject(wp->setter)), - 1, vp, vp) + ? ExternalInvoke(cx, obj, + ObjectValue(*CastAsObject(wp->setter)), + 1, vp, vp) : CallJSPropertyOpSetter(cx, wp->setter, obj, userid, vp)); DBG_LOCK(rt); return DropWatchPointAndUnlock(cx, wp, JSWP_HELD) && ok; } } DBG_UNLOCK(rt); return JS_TRUE; } JSBool -js_watch_set_wrapper(JSContext *cx, JSObject *obj, uintN argc, Value *argv, - Value *rval) +js_watch_set_wrapper(JSContext *cx, uintN argc, Value *vp) { - JSObject *funobj; - JSFunction *wrapper; - jsid userid; + JSObject *obj = ComputeThisFromVp(cx, vp); + if (!obj) + return false; - funobj = &argv[-2].toObject(); - wrapper = GET_FUNCTION_PRIVATE(cx, funobj); - userid = ATOM_TO_JSID(wrapper->atom); - *rval = argv[0]; - return js_watch_set(cx, obj, userid, rval); + JSObject &funobj = JS_CALLEE(cx, vp).toObject(); + JSFunction *wrapper = funobj.getFunctionPrivate(); + jsid userid = ATOM_TO_JSID(wrapper->atom); + + JS_SET_RVAL(cx, vp, argc ? JS_ARGV(cx, vp)[0] : UndefinedValue()); + return js_watch_set(cx, obj, userid, vp); } static bool IsWatchedProperty(JSContext *cx, const Shape &shape) { if (shape.hasSetterValue()) { JSObject *funobj = shape.setterObject(); if (!funobj || !funobj->isFunction()) return false; JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj); - return FUN_NATIVE(fun) == js_watch_set_wrapper; + return fun->maybeNative() == js_watch_set_wrapper; } return shape.setterOp() == js_watch_set; } PropertyOp js_WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, PropertyOp setter) { JSAtom *atom; @@ -1053,23 +1055,17 @@ JS_PUBLIC_API(JSScript *) JS_GetFunctionScript(JSContext *cx, JSFunction *fun) { return FUN_SCRIPT(fun); } JS_PUBLIC_API(JSNative) JS_GetFunctionNative(JSContext *cx, JSFunction *fun) { - return Jsvalify(FUN_NATIVE(fun)); -} - -JS_PUBLIC_API(JSFastNative) -JS_GetFunctionFastNative(JSContext *cx, JSFunction *fun) -{ - return Jsvalify(FUN_FAST_NATIVE(fun)); + return Jsvalify(fun->maybeNative()); } JS_PUBLIC_API(JSPrincipals *) JS_GetScriptPrincipals(JSContext *cx, JSScript *script) { return script->principals; } @@ -1098,18 +1094,18 @@ JS_GetFramePC(JSContext *cx, JSStackFram } JS_PUBLIC_API(JSStackFrame *) JS_GetScriptedCaller(JSContext *cx, JSStackFrame *fp) { return js_GetScriptedCaller(cx, fp); } -JS_PUBLIC_API(JSPrincipals *) -JS_StackFramePrincipals(JSContext *cx, JSStackFrame *fp) +JSPrincipals * +js_StackFramePrincipals(JSContext *cx, JSStackFrame *fp) { JSSecurityCallbacks *callbacks; if (fp->hasFunction()) { callbacks = JS_GetSecurityCallbacks(cx); if (callbacks && callbacks->findObjectPrincipals) { if (FUN_OBJECT(fp->getFunction()) != fp->callee()) return callbacks->findObjectPrincipals(cx, fp->callee()); @@ -1129,34 +1125,28 @@ js_EvalFramePrincipals(JSContext *cx, JS callbacks = JS_GetSecurityCallbacks(cx); if (callbacks && callbacks->findObjectPrincipals) principals = callbacks->findObjectPrincipals(cx, callee); else principals = NULL; if (!caller) return principals; - callerPrincipals = JS_StackFramePrincipals(cx, caller); + callerPrincipals = js_StackFramePrincipals(cx, caller); return (callerPrincipals && principals && callerPrincipals->subsume(callerPrincipals, principals)) ? principals : callerPrincipals; } -JS_PUBLIC_API(JSPrincipals *) -JS_EvalFramePrincipals(JSContext *cx, JSStackFrame *fp, JSStackFrame *caller) -{ - return js_EvalFramePrincipals(cx, fp->callee(), caller); -} - JS_PUBLIC_API(void *) JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp) { if (fp->hasAnnotation() && fp->hasScript()) { - JSPrincipals *principals = JS_StackFramePrincipals(cx, fp); + JSPrincipals *principals = js_StackFramePrincipals(cx, fp); if (principals && principals->globalPrivilegesEnabled(cx, principals)) { /* * Give out an annotation only if privileges have not been revoked * or disabled globally. */ return fp->getAnnotation(); } @@ -1171,26 +1161,26 @@ JS_SetFrameAnnotation(JSContext *cx, JSS fp->setAnnotation(annotation); } JS_PUBLIC_API(void *) JS_GetFramePrincipalArray(JSContext *cx, JSStackFrame *fp) { JSPrincipals *principals; - principals = JS_StackFramePrincipals(cx, fp); + principals = js_StackFramePrincipals(cx, fp); if (!principals) return NULL; return principals->getPrincipalArray(cx, principals); } JS_PUBLIC_API(JSBool) -JS_IsNativeFrame(JSContext *cx, JSStackFrame *fp) +JS_IsScriptFrame(JSContext *cx, JSStackFrame *fp) { - return !fp->hasScript(); + return !fp->isDummyFrame(); } /* this is deprecated, use JS_GetFrameScopeChain instead */ JS_PUBLIC_API(JSObject *) JS_GetFrameObject(JSContext *cx, JSStackFrame *fp) { return fp->maybeScopeChain(); } @@ -1351,17 +1341,17 @@ JS_EvaluateUCInStackFrame(JSContext *cx, return false; /* * NB: This function breaks the assumption that the compiler can see all * calls and properly compute a static level. In order to get around this, * we use a static level that will cause us not to attempt to optimize * variable references made by this frame. */ - JSScript *script = Compiler::compileScript(cx, scobj, fp, JS_StackFramePrincipals(cx, fp), + JSScript *script = Compiler::compileScript(cx, scobj, fp, js_StackFramePrincipals(cx, fp), TCF_COMPILE_N_GO, chars, length, NULL, filename, lineno, NULL, UpvarCookie::UPVAR_LEVEL_LIMIT); if (!script) return false; bool ok = !!Execute(cx, scobj, script, fp, JSFRAME_DEBUGGER | JSFRAME_EVAL, Valueify(rval)); @@ -1871,104 +1861,105 @@ JS_DisconnectShark() { if (chudIsRemoteAccessAcquired() && (chudReleaseRemoteAccess() != chudSuccess)) return JS_FALSE; return JS_TRUE; } JS_FRIEND_API(JSBool) -js_StartShark(JSContext *cx, JSObject *obj, - uintN argc, jsval *argv, jsval *rval) +js_StartShark(JSContext *cx, uintN argc, jsval *vp) { if (!JS_StartChudRemote()) { JS_ReportError(cx, "Error starting CHUD."); return JS_FALSE; } + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } JS_FRIEND_API(JSBool) -js_StopShark(JSContext *cx, JSObject *obj, - uintN argc, jsval *argv, jsval *rval) +js_StopShark(JSContext *cx, uintN argc, jsval *vp) { if (!JS_StopChudRemote()) { JS_ReportError(cx, "Error stopping CHUD."); return JS_FALSE; } + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } JS_FRIEND_API(JSBool) -js_ConnectShark(JSContext *cx, JSObject *obj, - uintN argc, jsval *argv, jsval *rval) +js_ConnectShark(JSContext *cx, uintN argc, jsval *vp) { if (!JS_ConnectShark()) { JS_ReportError(cx, "Error connecting to Shark."); return JS_FALSE; } + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } JS_FRIEND_API(JSBool) -js_DisconnectShark(JSContext *cx, JSObject *obj, - uintN argc, jsval *argv, jsval *rval) +js_DisconnectShark(JSContext *cx, uintN argc, jsval *vp) { if (!JS_DisconnectShark()) { JS_ReportError(cx, "Error disconnecting from Shark."); return JS_FALSE; } + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } #endif /* MOZ_SHARK */ #ifdef MOZ_CALLGRIND #include <valgrind/callgrind.h> JS_FRIEND_API(JSBool) -js_StartCallgrind(JSContext *cx, JSObject *obj, - uintN argc, jsval *argv, jsval *rval) +js_StartCallgrind(JSContext *cx, uintN argc, jsval *vp) { CALLGRIND_START_INSTRUMENTATION; CALLGRIND_ZERO_STATS; + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } JS_FRIEND_API(JSBool) -js_StopCallgrind(JSContext *cx, JSObject *obj, - uintN argc, jsval *argv, jsval *rval) +js_StopCallgrind(JSContext *cx, uintN argc, jsval *vp) { CALLGRIND_STOP_INSTRUMENTATION; + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } JS_FRIEND_API(JSBool) -js_DumpCallgrind(JSContext *cx, JSObject *obj, - uintN argc, jsval *argv, jsval *rval) +js_DumpCallgrind(JSContext *cx, uintN argc, jsval *vp) { JSString *str; char *cstr; + jsval *argv = JS_ARGV(cx, vp); if (argc > 0 && JSVAL_IS_STRING(argv[0])) { str = JSVAL_TO_STRING(argv[0]); cstr = js_DeflateString(cx, str->chars(), str->length()); if (cstr) { CALLGRIND_DUMP_STATS_AT(cstr); cx->free(cstr); return JS_TRUE; } } CALLGRIND_DUMP_STATS; + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } #endif /* MOZ_CALLGRIND */ #ifdef MOZ_VTUNE #include <VTuneApi.h>
--- a/js/src/jsdbgapi.h +++ b/js/src/jsdbgapi.h @@ -137,18 +137,17 @@ js_SweepWatchPoints(JSContext *cx); 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, JSObject *obj, uintN argc, js::Value *argv, - js::Value *rval); +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 */ @@ -184,19 +183,16 @@ extern JS_PUBLIC_API(void) JS_ReleaseFunctionLocalNameArray(JSContext *cx, void *mark); extern JS_PUBLIC_API(JSScript *) JS_GetFunctionScript(JSContext *cx, JSFunction *fun); extern JS_PUBLIC_API(JSNative) JS_GetFunctionNative(JSContext *cx, JSFunction *fun); -extern JS_PUBLIC_API(JSFastNative) -JS_GetFunctionFastNative(JSContext *cx, JSFunction *fun); - extern JS_PUBLIC_API(JSPrincipals *) JS_GetScriptPrincipals(JSContext *cx, JSScript *script); /* * Stack Frame Iterator * * Used to iterate through the JS stack frames to extract * information from the frames. @@ -216,47 +212,33 @@ JS_GetFramePC(JSContext *cx, JSStackFram */ extern JS_PUBLIC_API(JSStackFrame *) JS_GetScriptedCaller(JSContext *cx, JSStackFrame *fp); /* * Return a weak reference to fp's principals. A null return does not denote * an error, it means there are no principals. */ -extern JS_PUBLIC_API(JSPrincipals *) -JS_StackFramePrincipals(JSContext *cx, JSStackFrame *fp); - -/* - * This API is like JS_StackFramePrincipals(cx, caller), except that if - * cx->runtime->findObjectPrincipals is non-null, it returns the weaker of - * the caller's principals and the object principals of fp's callee function - * object (fp->argv[-2]), which is eval, Function, or a similar eval-like - * method. The caller parameter should be JS_GetScriptedCaller(cx, fp). - * - * All eval-like methods must use JS_EvalFramePrincipals to acquire a weak - * reference to the correct principals for the eval call to be secure, given - * an embedding that calls JS_SetObjectPrincipalsFinder (see jsapi.h). - */ -extern JS_PUBLIC_API(JSPrincipals *) -JS_EvalFramePrincipals(JSContext *cx, JSStackFrame *fp, JSStackFrame *caller); +extern JSPrincipals * +js_StackFramePrincipals(JSContext *cx, JSStackFrame *fp); JSPrincipals * js_EvalFramePrincipals(JSContext *cx, JSObject *callee, JSStackFrame *caller); extern JS_PUBLIC_API(void *) JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp); extern JS_PUBLIC_API(void) JS_SetFrameAnnotation(JSContext *cx, JSStackFrame *fp, void *annotation); extern JS_PUBLIC_API(void *) JS_GetFramePrincipalArray(JSContext *cx, JSStackFrame *fp); extern JS_PUBLIC_API(JSBool) -JS_IsNativeFrame(JSContext *cx, JSStackFrame *fp); +JS_IsScriptFrame(JSContext *cx, JSStackFrame *fp); /* this is deprecated, use JS_GetFrameScopeChain instead */ extern JS_PUBLIC_API(JSObject *) JS_GetFrameObject(JSContext *cx, JSStackFrame *fp); extern JS_PUBLIC_API(JSObject *) JS_GetFrameScopeChain(JSContext *cx, JSStackFrame *fp); @@ -530,46 +512,39 @@ JS_StopChudRemote(); extern JS_PUBLIC_API(JSBool) JS_ConnectShark(); extern JS_PUBLIC_API(JSBool) JS_DisconnectShark(); extern JS_FRIEND_API(JSBool) -js_StopShark(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval); +js_StopShark(JSContext *cx, uintN argc, jsval *vp); extern JS_FRIEND_API(JSBool) -js_StartShark(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval); +js_StartShark(JSContext *cx, uintN argc, jsval *vp); extern JS_FRIEND_API(JSBool) -js_ConnectShark(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval); +js_ConnectShark(JSContext *cx, uintN argc, jsval *vp); extern JS_FRIEND_API(JSBool) -js_DisconnectShark(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval); +js_DisconnectShark(JSContext *cx, uintN argc, jsval *vp); #endif /* MOZ_SHARK */ #ifdef MOZ_CALLGRIND extern JS_FRIEND_API(JSBool) -js_StopCallgrind(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval); +js_StopCallgrind(JSContext *cx, uintN argc, jsval *vp); extern JS_FRIEND_API(JSBool) -js_StartCallgrind(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval); +js_StartCallgrind(JSContext *cx, uintN argc, jsval *vp); extern JS_FRIEND_API(JSBool) -js_DumpCallgrind(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval); +js_DumpCallgrind(JSContext *cx, uintN argc, jsval *vp); #endif /* MOZ_CALLGRIND */ #ifdef MOZ_VTUNE extern JS_FRIEND_API(JSBool) js_StartVtune(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
--- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -64,17 +64,17 @@ #include "jscntxtinlines.h" #include "jsobjinlines.h" using namespace js; /* Forward declarations for js_ErrorClass's initializer. */ static JSBool -Exception(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval); +Exception(JSContext *cx, uintN argc, Value *vp); static void exn_trace(JSTracer *trc, JSObject *obj); static void exn_finalize(JSContext *cx, JSObject *obj); static JSBool @@ -691,50 +691,47 @@ FilenameToString(JSContext *cx, const ch static const char * StringToFilename(JSContext *cx, JSString *str) { return js_GetStringBytes(cx, str); } static JSBool -Exception(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) +Exception(JSContext *cx, uintN argc, Value *vp) { JSString *message, *filename; JSStackFrame *fp; - if (!JS_IsConstructing(cx)) { - /* - * ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when - * called as functions, without operator new. But as we do not give - * each constructor a distinct JSClass, whose .name member is used by - * NewNativeClassInstance to find the class prototype, we must get the - * class prototype ourselves. - */ - if (!argv[-2].toObject().getProperty(cx, - ATOM_TO_JSID(cx->runtime->atomState - .classPrototypeAtom), - rval)) { - return JS_FALSE; - } - JSObject *errProto = &rval->toObject(); - obj = NewNativeClassInstance(cx, &js_ErrorClass, errProto, errProto->getParent()); - if (!obj) - return JS_FALSE; - rval->setObject(*obj); - } + /* + * ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when + * called as functions, without operator new. But as we do not give + * each constructor a distinct JSClass, whose .name member is used by + * NewNativeClassInstance to find the class prototype, we must get the + * class prototype ourselves. + */ + JSObject &callee = vp[0].toObject(); + Value protov; + if (!callee.getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), &protov)) + return JS_FALSE; + + JSObject *errProto = &protov.toObject(); + JSObject *obj = NewNativeClassInstance(cx, &js_ErrorClass, errProto, errProto->getParent()); + if (!obj) + return JS_FALSE; /* * If it's a new object of class Exception, then null out the private * data so that the finalizer doesn't attempt to free it. */ if (obj->getClass() == &js_ErrorClass) obj->setPrivate(NULL); /* Set the 'message' property. */ + Value *argv = vp + 2; if (argc != 0) { message = js_ValueToString(cx, argv[0]); if (!message) return JS_FALSE; argv[0].setString(message); } else { message = cx->runtime->emptyString; } @@ -763,41 +760,46 @@ Exception(JSContext *cx, JSObject *obj, if (!ValueToECMAUint32(cx, argv[2], &lineno)) return JS_FALSE; } else { if (!fp) fp = js_GetScriptedCaller(cx, NULL); lineno = (fp && fp->pc(cx)) ? js_FramePCToLineNumber(cx, fp) : 0; } - return (obj->getClass() != &js_ErrorClass) || - InitExnPrivate(cx, obj, message, filename, lineno, NULL); + if (obj->getClass() == &js_ErrorClass && + !InitExnPrivate(cx, obj, message, filename, lineno, NULL)) { + return JS_FALSE; + } + + vp->setObject(*obj); + return JS_TRUE; } /* * Convert to string. * * This method only uses JavaScript-modifiable properties name, message. It * is left to the host to check for private data and report filename and line * number information along with this message. */ static JSBool -exn_toString(JSContext *cx, uintN argc, jsval *vp) +exn_toString(JSContext *cx, uintN argc, Value *vp) { JSObject *obj; jsval v; JSString *name, *message, *result; jschar *chars, *cp; size_t name_length, message_length, length; - obj = JS_THIS_OBJECT(cx, vp); + obj = ComputeThisFromVp(cx, vp); if (!obj || !obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.nameAtom), Valueify(&v))) return JS_FALSE; name = JSVAL_IS_STRING(v) ? JSVAL_TO_STRING(v) : cx->runtime->emptyString; - *vp = STRING_TO_JSVAL(name); + vp->setString(name); if (!JS_GetProperty(cx, obj, js_message_str, &v)) return JS_FALSE; message = JSVAL_IS_STRING(v) ? JSVAL_TO_STRING(v) : cx->runtime->emptyString; if (message->length() != 0) { name_length = name->length(); @@ -820,40 +822,40 @@ exn_toString(JSContext *cx, uintN argc, if (!result) { cx->free(chars); return JS_FALSE; } } else { result = name; } - *vp = STRING_TO_JSVAL(result); + vp->setString(result); return JS_TRUE; } #if JS_HAS_TOSOURCE /* * Return a string that may eval to something similar to the original object. */ static JSBool -exn_toSource(JSContext *cx, uintN argc, jsval *vp) +exn_toSource(JSContext *cx, uintN argc, Value *vp) { JSObject *obj; JSString *name, *message, *filename, *lineno_as_str, *result; jsval localroots[3] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL}; size_t lineno_length, name_length, message_length, filename_length, length; jschar *chars, *cp; - obj = JS_THIS_OBJECT(cx, vp); - if (!obj || !obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.nameAtom), Valueify(vp))) + obj = ComputeThisFromVp(cx, vp); + if (!obj || !obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.nameAtom), vp)) return false; - name = js_ValueToString(cx, Valueify(*vp)); + name = js_ValueToString(cx, *vp); if (!name) return false; - *vp = STRING_TO_JSVAL(name); + vp->setString(name); { AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(localroots), Valueify(localroots)); #ifdef __GNUC__ message = filename = NULL; #endif if (!JS_GetProperty(cx, obj, js_message_str, &localroots[0]) || @@ -943,17 +945,17 @@ exn_toSource(JSContext *cx, uintN argc, *cp++ = ')'; *cp++ = ')'; *cp = 0; result = js_NewString(cx, chars, length); if (!result) { cx->free(chars); return false; } - *vp = STRING_TO_JSVAL(result); + vp->setString(result); return true; } } #endif static JSFunctionSpec exception_methods[] = { #if JS_HAS_TOSOURCE JS_FN(js_toSource_str, exn_toSource, 0,0), @@ -1025,17 +1027,17 @@ js_InitExceptionClasses(JSContext *cx, J } /* So exn_finalize knows whether to destroy private data. */ proto->setPrivate(NULL); /* 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, 0); + JSFunction *fun = js_DefineFunction(cx, obj, atom, Exception, 3, JSFUN_CONSTRUCTOR); if (!fun) return NULL; roots[2] = OBJECT_TO_JSVAL(FUN_OBJECT(fun)); /* Make this constructor make objects of class Exception. */ FUN_CLASP(fun) = &js_ErrorClass; /* Make the prototype and constructor links. */
--- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -2157,18 +2157,16 @@ JS_PUBLIC_DATA(Class) js_FunctionClass = NULL, /* checkAccess */ NULL, /* call */ NULL, /* construct */ js_XDRFunctionObject, fun_hasInstance, JS_CLASS_TRACE(fun_trace) }; -namespace js { - JSString * fun_toStringHelper(JSContext *cx, JSObject *obj, uintN indent) { if (!obj->isFunction()) { if (obj->isFunctionProxy()) return JSProxy::fun_toString(cx, obj, indent); JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO, @@ -2178,18 +2176,16 @@ fun_toStringHelper(JSContext *cx, JSObje } JSFunction *fun = GET_FUNCTION_PRIVATE(cx, obj); if (!fun) return NULL; return JS_DecompileFunction(cx, fun, indent); } -} /* namespace js */ - static JSBool fun_toString(JSContext *cx, uintN argc, Value *vp) { JS_ASSERT(IsFunctionObject(vp[0])); uint32_t indent = 0; if (argc != 0 && !ValueToECMAUint32(cx, vp[2], &indent)) return false; @@ -2388,30 +2384,25 @@ js_fun_apply(JSContext *cx, uintN argc, /* Step 9. */ if (!Invoke(cx, args, 0)) return false; *vp = args.rval(); return true; } namespace { -Native -FastNativeToNative(FastNative fn) -{ - return reinterpret_cast<Native>(fn); -} JSBool CallOrConstructBoundFunction(JSContext *cx, uintN argc, Value *vp); } bool JSFunction::isBound() const { - return isFastNative() && u.n.native == FastNativeToNative(CallOrConstructBoundFunction); + return isNative() && u.n.native == CallOrConstructBoundFunction; } inline bool JSObject::initBoundFunction(JSContext *cx, const Value &thisArg, const Value *args, uintN argslen) { JS_ASSERT(isFunction()); JS_ASSERT(getFunctionPrivate()->isBound()); @@ -2475,17 +2466,17 @@ JSBool CallOrConstructBoundFunction(JSContext *cx, uintN argc, Value *vp) { JSObject *obj = &vp[0].toObject(); JS_ASSERT(obj->isFunction()); JS_ASSERT(obj->getFunctionPrivate()->isBound()); LeaveTrace(cx); - bool constructing = vp[1].isMagic(JS_FAST_CONSTRUCTOR); + bool constructing = IsConstructing(vp); /* 15.3.4.5.1 step 1, 15.3.4.5.2 step 3. */ uintN argslen; const Value *boundArgs = obj->getBoundFunctionArguments(argslen); if (argc + argslen > JS_ARGS_LENGTH_MAX) { js_ReportAllocationOverflow(cx); return false; @@ -2569,18 +2560,18 @@ fun_bind(JSContext *cx, uintN argc, Valu length = nargs - argslen; } /* Step 4-6, 10-11. */ JSAtom *name = target->isFunction() ? target->getFunctionPrivate()->atom : NULL; /* NB: Bound functions abuse |parent| to store their target. */ JSObject *funobj = - js_NewFunction(cx, NULL, FastNativeToNative(CallOrConstructBoundFunction), length, - JSFUN_FAST_NATIVE | JSFUN_FAST_NATIVE_CTOR, target, name); + js_NewFunction(cx, NULL, CallOrConstructBoundFunction, length, + JSFUN_CONSTRUCTOR, target, name); if (!funobj) return false; /* Steps 7-9. */ Value thisArg = argc >= 1 ? vp[2] : UndefinedValue(); if (!funobj->initBoundFunction(cx, thisArg, args, argslen)) return false; @@ -2601,78 +2592,55 @@ static JSFunctionSpec function_methods[] JS_FN(js_toString_str, fun_toString, 0,0), JS_FN(js_apply_str, js_fun_apply, 2,0), JS_FN(js_call_str, js_fun_call, 1,0), JS_FN("bind", fun_bind, 1,0), JS_FS_END }; static JSBool -Function(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) +Function(JSContext *cx, uintN argc, Value *vp) { - JSFunction *fun; - JSObject *parent; - JSStackFrame *fp, *caller; - uintN i, n, lineno; - JSAtom *atom; - const char *filename; - JSBool ok; - JSString *str, *arg; - TokenStream ts(cx); - JSPrincipals *principals; - jschar *collected_args, *cp; - void *mark; - size_t arg_length, args_length, old_args_length; - TokenKind tt; - - if (!JS_IsConstructing(cx)) { - obj = NewFunction(cx, NULL); - if (!obj) - return JS_FALSE; - rval->setObject(*obj); - } else { - /* - * The constructor is called before the private slot is initialized so - * we must use getPrivate, not GET_FUNCTION_PRIVATE here. - */ - if (obj->getPrivate()) - return JS_TRUE; - } + JSObject *obj = NewFunction(cx, NULL); + if (!obj) + return JS_FALSE; + + /* N.B. overwriting callee with return value */ + JSObject *parent = vp[0].toObject().getParent(); + vp[0].setObject(*obj); /* * NB: (new Function) is not lexically closed by its caller, it's just an * anonymous function in the top-level scope that its constructor inhabits. * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42, * and so would a call to f from another top-level's script or function. * * In older versions, before call objects, a new Function was adopted by * its running context's globalObject, which might be different from the * top-level reachable from scopeChain (in HTML frames, e.g.). */ - parent = argv[-2].toObject().getParent(); - - fun = js_NewFunction(cx, obj, NULL, 0, JSFUN_LAMBDA | JSFUN_INTERPRETED, - parent, cx->runtime->atomState.anonymousAtom); - + JSFunction *fun = js_NewFunction(cx, obj, NULL, 0, JSFUN_LAMBDA | JSFUN_INTERPRETED, + parent, cx->runtime->atomState.anonymousAtom); if (!fun) return JS_FALSE; /* * Function is static and not called directly by other functions in this * file, therefore it is callable only as a native function by js_Invoke. * Find the scripted caller, possibly skipping other native frames such as * are built for Function.prototype.call or .apply activations that invoke * Function indirectly from a script. */ - fp = js_GetTopStackFrame(cx); - JS_ASSERT(!fp->hasScript() && fp->hasFunction() && - fp->getFunction()->u.n.native == Function); - caller = js_GetScriptedCaller(cx, fp); + JSStackFrame *caller = js_GetScriptedCaller(cx, NULL); + uintN lineno; + const char *filename; + JSPrincipals *principals; if (caller) { - principals = JS_EvalFramePrincipals(cx, fp, caller); + JSObject *callee = &JS_CALLEE(cx, vp).toObject(); + principals = js_EvalFramePrincipals(cx, callee, caller); filename = js_ComputeFilename(cx, caller, principals, &lineno); } else { filename = NULL; lineno = 0; principals = NULL; } /* Belt-and-braces: check that the caller has access to parent. */ @@ -2686,121 +2654,124 @@ Function(JSContext *cx, JSObject *obj, u * Report errors via CSP is done in the script security manager. * js_CheckContentSecurityPolicy is defined in jsobj.cpp */ if (!js_CheckContentSecurityPolicy(cx)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CSP_BLOCKED_FUNCTION); return JS_FALSE; } - n = argc ? argc - 1 : 0; + Value *argv = vp + 2; + uintN n = argc ? argc - 1 : 0; if (n > 0) { enum { OK, BAD, BAD_FORMAL } state; /* * Collect the function-argument arguments into one string, separated * by commas, then make a tokenstream from that string, and scan it to * get the arguments. We need to throw the full scanner at the * problem, because the argument string can legitimately contain * comments and linefeeds. XXX It might be better to concatenate * everything up into a function definition and pass it to the * compiler, but doing it this way is less of a delta from the old * code. See ECMA 15.3.2.1. */ state = BAD_FORMAL; - args_length = 0; - for (i = 0; i < n; i++) { + size_t args_length = 0; + for (uintN i = 0; i < n; i++) { /* Collect the lengths for all the function-argument arguments. */ - arg = js_ValueToString(cx, argv[i]); + JSString *arg = js_ValueToString(cx, argv[i]); if (!arg) return JS_FALSE; argv[i].setString(arg); /* * Check for overflow. The < test works because the maximum * JSString length fits in 2 fewer bits than size_t has. */ - old_args_length = args_length; + size_t old_args_length = args_length; args_length = old_args_length + arg->length(); if (args_length < old_args_length) { js_ReportAllocationOverflow(cx); return JS_FALSE; } } /* Add 1 for each joining comma and check for overflow (two ways). */ - old_args_length = args_length; + size_t old_args_length = args_length; args_length = old_args_length + n - 1; if (args_length < old_args_length || args_length >= ~(size_t)0 / sizeof(jschar)) { js_ReportAllocationOverflow(cx); return JS_FALSE; } /* * Allocate a string to hold the concatenated arguments, including room * for a terminating 0. Mark cx->tempPool for later release, to free * collected_args and its tokenstream in one swoop. */ - mark = JS_ARENA_MARK(&cx->tempPool); + void *mark = JS_ARENA_MARK(&cx->tempPool); + jschar *cp; JS_ARENA_ALLOCATE_CAST(cp, jschar *, &cx->tempPool, (args_length+1) * sizeof(jschar)); if (!cp) { js_ReportOutOfScriptQuota(cx); return JS_FALSE; } - collected_args = cp; + jschar *collected_args = cp; /* * Concatenate the arguments into the new string, separated by commas. */ - for (i = 0; i < n; i++) { - arg = argv[i].toString(); - arg_length = arg->length(); + for (uintN i = 0; i < n; i++) { + JSString *arg = argv[i].toString(); + size_t arg_length = arg->length(); (void) js_strncpy(cp, arg->chars(), arg_length); cp += arg_length; /* Add separating comma or terminating 0. */ *cp++ = (i + 1 < n) ? ',' : 0; } /* Initialize a tokenstream that reads from the given string. */ + TokenStream ts(cx); if (!ts.init(collected_args, args_length, NULL, filename, lineno)) { JS_ARENA_RELEASE(&cx->tempPool, mark); return JS_FALSE; } /* The argument string may be empty or contain no tokens. */ - tt = ts.getToken(); + TokenKind tt = ts.getToken(); if (tt != TOK_EOF) { for (;;) { /* * Check that it's a name. This also implicitly guards against * TOK_ERROR, which was already reported. */ if (tt != TOK_NAME) goto after_args; /* * Get the atom corresponding to the name from the token * stream; we're assured at this point that it's a valid * identifier. */ - atom = ts.currentToken().t_atom; + JSAtom *atom = ts.currentToken().t_atom; /* Check for a duplicate parameter name. */ if (fun->lookupLocal(cx, atom, NULL) != JSLOCAL_NONE) { const char *name; name = js_AtomToPrintableString(cx, atom); - ok = name && ReportCompileErrorNumber(cx, &ts, NULL, + if (!name && ReportCompileErrorNumber(cx, &ts, NULL, JSREPORT_WARNING | JSREPORT_STRICT, - JSMSG_DUPLICATE_FORMAL, name); - if (!ok) + JSMSG_DUPLICATE_FORMAL, name)) { goto after_args; + } } if (!fun->addLocal(cx, atom, JSLOCAL_ARG)) goto after_args; /* * Get the next token. Stop on end of stream. Otherwise * insist on a comma, get another name, and iterate. */ @@ -2824,16 +2795,17 @@ Function(JSContext *cx, JSObject *obj, u JSMSG_BAD_FORMAL); } ts.close(); JS_ARENA_RELEASE(&cx->tempPool, mark); if (state != OK) return JS_FALSE; } + JSString *str; if (argc) { str = js_ValueToString(cx, argv[argc-1]); if (!str) return JS_FALSE; argv[argc-1].setString(str); } else { str = cx->runtime->emptyString; } @@ -2867,17 +2839,17 @@ js_InitFunctionClass(JSContext *cx, JSOb if (!fun) return NULL; fun->u.i.script = JSScript::emptyScript(); if (obj->getClass()->flags & JSCLASS_IS_GLOBAL) { /* ES5 13.2.3: Construct the unique [[ThrowTypeError]] function object. */ JSObject *throwTypeError = js_NewFunction(cx, NULL, reinterpret_cast<Native>(ThrowTypeError), 0, - JSFUN_FAST_NATIVE, obj, NULL); + 0, obj, NULL); if (!throwTypeError) return NULL; JS_ALWAYS_TRUE(js_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_THROWTYPEERROR, ObjectValue(*throwTypeError))); } return proto; @@ -2897,30 +2869,27 @@ js_NewFunction(JSContext *cx, JSObject * if (!funobj) return NULL; } JS_ASSERT(!funobj->getPrivate()); fun = (JSFunction *) funobj; /* Initialize all function members. */ fun->nargs = uint16(nargs); - fun->flags = flags & (JSFUN_FLAGS_MASK | JSFUN_KINDMASK | - JSFUN_TRCINFO | JSFUN_FAST_NATIVE_CTOR); + fun->flags = flags & (JSFUN_FLAGS_MASK | JSFUN_KINDMASK | JSFUN_TRCINFO); if ((flags & JSFUN_KINDMASK) >= JSFUN_INTERPRETED) { JS_ASSERT(!native); JS_ASSERT(nargs == 0); fun->u.i.nvars = 0; fun->u.i.nupvars = 0; fun->u.i.skipmin = 0; fun->u.i.wrapper = false; fun->u.i.script = NULL; fun->u.i.names = cx->runtime->emptyCallShape; } else { - fun->u.n.extra = 0; - fun->u.n.spare = 0; fun->u.n.clasp = NULL; if (flags & JSFUN_TRCINFO) { #ifdef JS_TRACER JSNativeTraceInfo *trcinfo = JS_FUNC_TO_DATA_PTR(JSNativeTraceInfo *, native); fun->u.n.native = (js::Native) trcinfo->native; fun->u.n.trcinfo = trcinfo; #else @@ -3044,17 +3013,18 @@ js_DefineFunction(JSContext *cx, JSObjec * for more on this. */ attrs &= ~JSFUN_STUB_GSOPS; gsop = PropertyStub; } else { gsop = NULL; } fun = js_NewFunction(cx, NULL, native, nargs, - attrs & (JSFUN_FLAGS_MASK | JSFUN_TRCINFO), obj, atom); + attrs & (JSFUN_FLAGS_MASK | JSFUN_TRCINFO), + obj, atom); if (!fun) return NULL; if (!obj->defineProperty(cx, ATOM_TO_JSID(atom), ObjectValue(*fun), gsop, gsop, attrs & ~JSFUN_FLAGS_MASK)) { return NULL; } return fun; }
--- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -81,52 +81,33 @@ * If we need more bits in the future, all flags for FUN_INTERPRETED functions * can move to u.i.script->flags. For now we use function flag bits to minimize * pointer-chasing. */ #define JSFUN_JOINABLE 0x0001 /* function is null closure that does not appear to call itself via its own name or arguments.callee */ -#define JSFUN_FAST_NATIVE_CTOR 0x0002 /* JSFastNative directly invokable - * during construction. */ - -/* - * Extra JSCLASS flag indicating the native passed to JS_InitClass is - * a fast native constructor. This is internal for now as the 'this' value passed - * to such a constructor is a magic value, and there is no way to query this - * in the API. See bug 581263. - */ -#define JSCLASS_FAST_CONSTRUCTOR (1<<4) - #define JSFUN_EXPR_CLOSURE 0x1000 /* expression closure: function(x) x*x */ #define JSFUN_TRCINFO 0x2000 /* when set, u.n.trcinfo is non-null, JSFunctionSpec::call points to a JSNativeTraceInfo. */ #define JSFUN_INTERPRETED 0x4000 /* use u.i if kind >= this value else u.n */ #define JSFUN_FLAT_CLOSURE 0x8000 /* flag (aka "display") closure */ #define JSFUN_NULL_CLOSURE 0xc000 /* null closure entrains no scope chain */ #define JSFUN_KINDMASK 0xc000 /* encode interp vs. native and closure optimization level -- see above */ #define FUN_OBJECT(fun) (static_cast<JSObject *>(fun)) #define FUN_KIND(fun) ((fun)->flags & JSFUN_KINDMASK) #define FUN_SET_KIND(fun,k) ((fun)->flags = ((fun)->flags & ~JSFUN_KINDMASK) | (k)) #define FUN_INTERPRETED(fun) (FUN_KIND(fun) >= JSFUN_INTERPRETED) #define FUN_FLAT_CLOSURE(fun)(FUN_KIND(fun) == JSFUN_FLAT_CLOSURE) #define FUN_NULL_CLOSURE(fun)(FUN_KIND(fun) == JSFUN_NULL_CLOSURE) -#define FUN_SLOW_NATIVE(fun) (!FUN_INTERPRETED(fun) && !((fun)->flags & JSFUN_FAST_NATIVE)) #define FUN_SCRIPT(fun) (FUN_INTERPRETED(fun) ? (fun)->u.i.script : NULL) -#define FUN_NATIVE(fun) (FUN_SLOW_NATIVE(fun) ? (fun)->u.n.native : NULL) -#define FUN_FAST_NATIVE(fun) (((fun)->flags & JSFUN_FAST_NATIVE) \ - ? (js::FastNative) (fun)->u.n.native \ - : NULL) -#define FUN_MINARGS(fun) (((fun)->flags & JSFUN_FAST_NATIVE) \ - ? 0 \ - : (fun)->nargs) #define FUN_CLASP(fun) (JS_ASSERT(!FUN_INTERPRETED(fun)), \ fun->u.n.clasp) #define FUN_TRCINFO(fun) (JS_ASSERT(!FUN_INTERPRETED(fun)), \ JS_ASSERT((fun)->flags & JSFUN_TRCINFO), \ fun->u.n.trcinfo) /* * Formal parameters, local variables, and upvars are stored in a shape tree @@ -153,18 +134,16 @@ enum JSLocalKind { struct JSFunction : public JSObject { uint16 nargs; /* maximum number of specified arguments, reflected as f.length/f.arity */ uint16 flags; /* flags, see JSFUN_* below and in jsapi.h */ union U { struct { - uint16 extra; /* number of arg slots for local GC roots */ - uint16 spare; /* reserved for future use */ js::Native native; /* native method pointer or null */ js::Class *clasp; /* class of objects constructed by this function */ JSNativeTraceInfo *trcinfo; } n; struct Scripted { uint16 nvars; /* number of local variables */ uint16 nupvars; /* number of upvars (computable from script @@ -182,20 +161,20 @@ struct JSFunction : public JSObject js::Shape *names; /* argument and variable names */ } i; } u; JSAtom *atom; /* name for diagnostics and decompiling */ bool optimizedClosure() const { return FUN_KIND(this) > JSFUN_INTERPRETED; } bool needsWrapper() const { return FUN_NULL_CLOSURE(this) && u.i.skipmin != 0; } bool isInterpreted() const { return FUN_INTERPRETED(this); } - bool isFastNative() const { return !!(flags & JSFUN_FAST_NATIVE); } - bool isFastConstructor() const { return !!(flags & JSFUN_FAST_NATIVE_CTOR); } + bool isNative() const { return !FUN_INTERPRETED(this); } + bool isConstructor() const { return flags & JSFUN_CONSTRUCTOR; } bool isHeavyweight() const { return JSFUN_HEAVYWEIGHT_TEST(flags); } - unsigned minArgs() const { return FUN_MINARGS(this); } + unsigned minArgs() const { return isInterpreted() ? nargs : 0; } inline bool inStrictMode() const; bool isBound() const; uintN countVars() const { JS_ASSERT(FUN_INTERPRETED(this)); return u.i.nvars; @@ -304,33 +283,37 @@ struct JSFunction : public JSObject : NULL; } void setMethodAtom(JSAtom *atom) { JS_ASSERT(joinable()); fslots[METHOD_ATOM_SLOT].setString(ATOM_TO_STRING(atom)); } + js::Native maybeNative() const { + return isInterpreted() ? NULL : u.n.native; + } + /* Number of extra fixed function object slots besides JSSLOT_PRIVATE. */ static const uint32 CLASS_RESERVED_SLOTS = JSObject::FUN_CLASS_RESERVED_SLOTS; static const uint32 FIRST_FREE_SLOT = JSSLOT_PRIVATE + CLASS_RESERVED_SLOTS + 1; }; JS_STATIC_ASSERT(sizeof(JSFunction) % JS_GCTHING_ALIGN == 0); /* * Trace-annotated native. This expands to a JSFunctionSpec initializer (like * JS_FN in jsapi.h). fastcall is a FastNative; trcinfo is a * JSNativeTraceInfo*. */ #ifdef JS_TRACER /* MSVC demands the intermediate (void *) cast here. */ # define JS_TN(name,fastcall,nargs,flags,trcinfo) \ - JS_FN(name, JS_DATA_TO_FUNC_PTR(JSNative, trcinfo), nargs, \ - (flags) | JSFUN_FAST_NATIVE | JSFUN_STUB_GSOPS | JSFUN_TRCINFO) + JS_FN(name, JS_DATA_TO_FUNC_PTR(Native, trcinfo), nargs, \ + (flags) | JSFUN_STUB_GSOPS | JSFUN_TRCINFO) #else # define JS_TN(name,fastcall,nargs,flags,trcinfo) \ JS_FN(name, fastcall, nargs, flags) #endif /* * NB: the Arguments classes are uninitialized internal classes that masquerade * (according to Object.prototype.toString.call(arguments)) as "Arguments", @@ -390,16 +373,25 @@ JSObject::isCall() const } inline bool JSObject::isFunction() const { return getClass() == &js_FunctionClass; } +inline JSFunction * +JSObject::getFunctionPrivate() const +{ + JS_ASSERT(isFunction()); + return reinterpret_cast<JSFunction *>(getPrivate()); +} + +namespace js { + /* * NB: jsapi.h and jsobj.h must be included before any call to this macro. */ #define VALUE_IS_FUNCTION(cx, v) \ (!JSVAL_IS_PRIMITIVE(v) && JSVAL_TO_OBJECT(v)->isFunction()) static JS_ALWAYS_INLINE bool IsFunctionObject(const js::Value &v) @@ -408,47 +400,89 @@ IsFunctionObject(const js::Value &v) } static JS_ALWAYS_INLINE bool IsFunctionObject(const js::Value &v, JSObject **funobj) { return v.isObject() && (*funobj = &v.toObject())->isFunction(); } +static JS_ALWAYS_INLINE bool +IsFunctionObject(const js::Value &v, JSFunction **fun) +{ + JSObject *funobj; + bool b = IsFunctionObject(v, &funobj); + if (b) + *fun = funobj->getFunctionPrivate(); + return b; +} + /* * Macro to access the private slot of the function object after the slot is * initialized. */ #define GET_FUNCTION_PRIVATE(cx, funobj) \ (JS_ASSERT((funobj)->isFunction()), \ (JSFunction *) (funobj)->getPrivate()) -extern JSFunction * -js_NewFunction(JSContext *cx, JSObject *funobj, js::Native native, uintN nargs, - uintN flags, JSObject *parent, JSAtom *atom); - -namespace js { - /* * Return true if this is a compiler-created internal function accessed by * its own object. Such a function object must not be accessible to script * or embedding code. */ inline bool IsInternalFunctionObject(JSObject *funobj) { JS_ASSERT(funobj->isFunction()); JSFunction *fun = (JSFunction *) funobj->getPrivate(); return funobj == fun && (fun->flags & JSFUN_LAMBDA) && !funobj->getParent(); } +/* Valueified JS_IsConstructing. */ +static JS_ALWAYS_INLINE bool +IsConstructing(const Value *vp) +{ +#ifdef DEBUG + JSObject *callee = &JS_CALLEE(cx, vp).toObject(); + if (callee->isFunction()) { + JSFunction *fun = callee->getFunctionPrivate(); + JS_ASSERT((fun->flags & JSFUN_CONSTRUCTOR) != 0); + } else { + JS_ASSERT(callee->getClass()->construct != NULL); + } +#endif + return vp[1].isMagic(); +} + +static JS_ALWAYS_INLINE bool +IsConstructing_PossiblyWithGivenThisObject(const Value *vp, JSObject **ctorThis) +{ +#ifdef DEBUG + JSObject *callee = &JS_CALLEE(cx, vp).toObject(); + if (callee->isFunction()) { + JSFunction *fun = callee->getFunctionPrivate(); + JS_ASSERT((fun->flags & JSFUN_CONSTRUCTOR) != 0); + } else { + JS_ASSERT(callee->getClass()->construct != NULL); + } +#endif + bool isCtor = vp[1].isMagic(); + if (isCtor) + *ctorThis = vp[1].getMagicObjectOrNullPayload(); + return isCtor; +} + +} /* namespace js */ + extern JSString * fun_toStringHelper(JSContext *cx, JSObject *obj, uintN indent); -} /* namespace js */ +extern JSFunction * +js_NewFunction(JSContext *cx, JSObject *funobj, js::Native native, uintN nargs, + uintN flags, JSObject *parent, JSAtom *atom); extern JSObject * js_InitFunctionClass(JSContext *cx, JSObject *obj); extern JSObject * js_InitArgumentsClass(JSContext *cx, JSObject *obj); extern void
--- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -463,67 +463,79 @@ RunScript(JSContext *cx, JSScript *scrip if (status == mjit::Compile_Okay) return mjit::JaegerShot(cx); #endif return Interpret(cx, cx->fp()); } -static JS_REQUIRES_STACK bool -CallJSNative(JSContext *cx, CallOp callOp, JSObject *thisp, uintN argc, Value *argv, Value *rval) -{ - Value *vp = argv - 2; - if (CallJSFastNative(cx, callOp, argc, vp)) { - *rval = JS_RVAL(cx, vp); - return true; - } - return false; -} - -template <typename T> -static JS_REQUIRES_STACK bool -InvokeCommon(JSContext *cx, JSFunction *fun, JSScript *script, T native, - const CallArgs &argsRef, uintN flags) +/* + * Find a function reference and its 'this' value implicit first parameter + * under argc arguments on cx's stack, and call the function. Push missing + * required arguments, allocate declared local variables, and pop everything + * when done. Then push the return value. + */ +JS_REQUIRES_STACK bool +Invoke(JSContext *cx, const CallArgs &argsRef, uintN flags) { CallArgs args = argsRef; - - if (native && fun && fun->isFastNative()) { -#ifdef DEBUG_NOT_THROWING - JSBool alreadyThrowing = cx->throwing; + JS_ASSERT(args.argc() <= JS_ARGS_LENGTH_MAX); + + if (args.callee().isPrimitive()) { + js_ReportIsNotFunction(cx, &args.callee(), flags & JSINVOKE_FUNFLAGS); + return false; + } + + JSObject *callee = &args.callee().toObject(); + Class *clasp = callee->getClass(); + + /* Invoke non-functions. */ + if (JS_UNLIKELY(clasp != &js_FunctionClass)) { +#if JS_HAS_NO_SUCH_METHOD + if (JS_UNLIKELY(clasp == &js_NoSuchMethodClass)) + return NoSuchMethod(cx, args.argc(), args.base(), 0); #endif - JSBool ok = CallJSFastNative(cx, (FastNative) native, args.argc(), args.base()); - JS_RUNTIME_METER(cx->runtime, nativeCalls); -#ifdef DEBUG_NOT_THROWING - if (ok && !alreadyThrowing) - ASSERT_NOT_THROWING(cx); -#endif - return ok; - } + JS_ASSERT_IF(flags & JSINVOKE_CONSTRUCT, !clasp->construct); + if (!clasp->call) { + js_ReportIsNotFunction(cx, &args.callee(), flags); + return false; + } + return CallJSNative(cx, clasp->call, args.argc(), args.base()); + } + + /* Invoke native functions. */ + JSFunction *fun = callee->getFunctionPrivate(); + JS_ASSERT_IF(flags & JSINVOKE_CONSTRUCT, !fun->isConstructor()); + if (fun->isNative()) { + JS_ASSERT(args.thisv().isObjectOrNull() || PrimitiveThisTest(fun, args.thisv())); + return CallJSNative(cx, fun->u.n.native, args.argc(), args.base()); + } + + JS_ASSERT(fun->isInterpreted()); + JSScript *script = fun->u.i.script; + + /* Handle the empty-script special case. */ + if (JS_UNLIKELY(script->isEmpty())) { + if (flags & JSINVOKE_CONSTRUCT) { + JS_ASSERT(args.thisv().isObject()); + args.rval() = args.thisv(); + } else { + args.rval().setUndefined(); + } + return true; + } + + JS_ASSERT_IF(flags & JSINVOKE_CONSTRUCT, args.thisv().isObject()); /* Calculate slot usage. */ - uintN nmissing; - uintN nvars; - if (fun) { - if (fun->isInterpreted()) { - uintN minargs = fun->nargs; - nmissing = minargs > args.argc() ? minargs - args.argc() : 0; - nvars = fun->u.i.nvars; - } else if (fun->isFastNative()) { - nvars = nmissing = 0; - } else { - uintN minargs = fun->nargs; - nmissing = (minargs > args.argc() ? minargs - args.argc() : 0) + fun->u.n.extra; - nvars = 0; - } - } else { - nvars = nmissing = 0; - } - - uintN nfixed = script ? script->nslots : 0; + uintN minargs = fun->nargs; + uintN nmissing = minargs > args.argc() ? minargs - args.argc() : 0; + uintN nvars = fun->u.i.nvars; + uintN nfixed = script->nslots; /* * Get a pointer to new frame/slots. This memory is not "claimed", so the * code before pushInvokeFrame must not reenter the interpreter. */ InvokeFrameGuard frame; if (!cx->stack().getInvokeFrame(cx, args, nmissing, nfixed, frame)) return false; @@ -538,55 +550,37 @@ InvokeCommon(JSContext *cx, JSFunction * fp->setThisValue(args.thisv()); fp->setCallObj(NULL); fp->setArgsObj(NULL); fp->setScript(script); fp->setFunction(fun); fp->setNumActualArgs(args.argc()); fp->argv = args.argv(); fp->setAnnotation(NULL); - fp->setScopeChain(NULL); + fp->setScopeChain(callee->getParent()); fp->setBlockChain(NULL); fp->flags = flags; JS_ASSERT(!fp->hasIMacroPC()); if (flags & JSINVOKE_CONSTRUCT) fp->setReturnValue(fp->getThisValue()); else fp->clearReturnValue(); /* Initialize regs. */ JSFrameRegs ®s = frame.getRegs(); - if (script) { - regs.pc = script->code; - regs.sp = fp->slots() + script->nfixed; - } else { - regs.pc = NULL; - regs.sp = fp->slots(); - } - - /* Officially push |fp|. |frame|'s destructor pops. */ + regs.pc = script->code; + regs.sp = fp->slots() + script->nfixed; + + /* Officially push fp. frame's destructor pops. */ cx->stack().pushInvokeFrame(cx, args, frame); /* Now that the frame has been pushed, fix up the scope chain. */ - JSObject *parent = args.callee().toObject().getParent(); - if (native) { - /* Slow natives and call ops expect the caller's scopeChain as their scopeChain. */ - if (JSStackFrame *down = fp->down) - fp->setScopeChain(down->maybeScopeChain()); - - /* Ensure that we have a scope chain. */ - if (!fp->hasScopeChain()) - fp->setScopeChain(parent); - } else { - /* Use parent scope so js_GetCallObject can find the right "Call". */ - fp->setScopeChain(parent); - if (fun->isHeavyweight() && !js_GetCallObject(cx, fp)) - return false; - } + if (fun->isHeavyweight() && !js_GetCallObject(cx, fp)) + return false; /* * Compute |this|. Currently, this must happen after the frame is pushed * and fp->scopeChain is correct because the thisObject hook may call * JS_GetScopeChain. */ JS_ASSERT_IF(flags & JSINVOKE_CONSTRUCT, !args.thisv().isPrimitive()); if (args.thisv().isObject() && !(flags & JSINVOKE_CONSTRUCT)) { @@ -603,223 +597,76 @@ InvokeCommon(JSContext *cx, JSFunction * thisp = thisp->thisObject(cx); if (!thisp) return false; args.thisv().setObject(*thisp); fp->setThisValue(ObjectValue(*thisp)); } JS_ASSERT_IF(!args.thisv().isPrimitive(), IsSaneThisObject(args.thisv().toObject())); - /* Call the hook if present after we fully initialized the frame. */ JSInterpreterHook hook = cx->debugHooks->callHook; void *hookData = NULL; - if (hook) + if (JS_UNLIKELY(hook != NULL)) hookData = hook(cx, fp, JS_TRUE, 0, cx->debugHooks->callHookData); - Probes::enterJSFun(cx, fun); - - /* Call the function, either a native method or an interpreted script. */ JSBool ok; - if (native) { -#ifdef DEBUG_NOT_THROWING - JSBool alreadyThrowing = cx->throwing; -#endif - /* Primitive |this| should not be passed to slow natives. */ - JSObject *thisp = fun ? fp->getThisObject(cx) : fp->getThisValue().toObjectOrNull(); - ok = CallJSNative(cx, native, thisp, fp->numActualArgs(), fp->argv, - fp->addressReturnValue()); - - JS_ASSERT(cx->fp() == fp); - JS_RUNTIME_METER(cx->runtime, nativeCalls); -#ifdef DEBUG_NOT_THROWING - if (ok && !alreadyThrowing) - ASSERT_NOT_THROWING(cx); -#endif - } else { - JS_ASSERT(script); + { AutoPreserveEnumerators preserve(cx); + Probes::enterJSFun(cx, fun); ok = RunScript(cx, script, fun, fp->getScopeChain()); - } - - Probes::exitJSFun(cx, fun); - - if (hookData) { + Probes::exitJSFun(cx, fun); + } + + if (JS_UNLIKELY(hookData != NULL)) { hook = cx->debugHooks->callHook; if (hook) hook(cx, fp, JS_FALSE, &ok, hookData); } fp->putActivationObjects(cx); + args.rval() = fp->getReturnValue(); return ok; } -static JSBool -DoConstruct(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) -{ - - Class *clasp = argv[-2].toObject().getClass(); - if (!clasp->construct) { - js_ReportIsNotFunction(cx, &argv[-2], JSV2F_CONSTRUCT); - return JS_FALSE; - } - return clasp->construct(cx, obj, argc, argv, rval); -} - -static JSBool -DoSlowCall(JSContext *cx, uintN argc, Value *vp) -{ - JSStackFrame *fp = cx->fp(); - JSObject *obj = fp->getThisObject(cx); - if (!obj) - return false; - JS_ASSERT(ObjectValue(*obj) == fp->getThisValue()); - - JSObject *callee = &JS_CALLEE(cx, vp).toObject(); - Class *clasp = callee->getClass(); - JS_ASSERT(!(clasp->flags & Class::CALL_IS_FAST)); - if (!clasp->call) { - js_ReportIsNotFunction(cx, &vp[0], 0); - return JS_FALSE; - } - AutoValueRooter rval(cx); - JSBool ok = clasp->call(cx, obj, argc, JS_ARGV(cx, vp), rval.addr()); - if (ok) - JS_SET_RVAL(cx, vp, rval.value()); - return ok; -} - -/* - * Find a function reference and its 'this' value implicit first parameter - * under argc arguments on cx's stack, and call the function. Push missing - * required arguments, allocate declared local variables, and pop everything - * when done. Then push the return value. - */ -JS_REQUIRES_STACK bool -Invoke(JSContext *cx, const CallArgs &args, uintN flags) -{ - JS_ASSERT(args.argc() <= JS_ARGS_LENGTH_MAX); - - if (args.callee().isPrimitive()) { - js_ReportIsNotFunction(cx, &args.callee(), flags & JSINVOKE_FUNFLAGS); - return false; - } - - JSObject *funobj = &args.callee().toObject(); - Class *clasp = funobj->getClass(); - - if (clasp == &js_FunctionClass) { - /* Get private data and set derived locals from it. */ - JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj); - Native native; - JSScript *script; - if (FUN_INTERPRETED(fun)) { - native = NULL; - script = fun->u.i.script; - JS_ASSERT(script); - - if (script->isEmpty()) { - if (flags & JSINVOKE_CONSTRUCT) { - JS_ASSERT(args.thisv().isObject()); - args.rval() = args.thisv(); - } else { - args.rval().setUndefined(); - } - return true; - } - } else { - native = fun->u.n.native; - script = NULL; - } - - if (!args.thisv().isObjectOrNull()) { - JS_ASSERT(!(flags & JSINVOKE_CONSTRUCT)); - if (PrimitiveThisTest(fun, args.thisv())) - return InvokeCommon(cx, fun, script, native, args, flags); - } - - if (flags & JSINVOKE_CONSTRUCT) { - JS_ASSERT(args.thisv().isObject()); - } else { - /* - * We must call js_ComputeThis in case we are not called from the - * interpreter, where a prior bytecode has computed an appropriate - * |this| already. - * - * But we need to compute |this| eagerly only for so-called "slow" - * (i.e., not fast) native functions. Fast natives must use either - * JS_THIS or JS_THIS_OBJECT, and scripted functions will go through - * the appropriate this-computing bytecode, e.g., JSOP_THIS. - */ - if (native && (!fun || !(fun->flags & JSFUN_FAST_NATIVE))) { - if (!args.computeThis(cx)) - return false; - } - } - return InvokeCommon(cx, fun, script, native, args, flags); - } - -#if JS_HAS_NO_SUCH_METHOD - if (clasp == &js_NoSuchMethodClass) - return NoSuchMethod(cx, args.argc(), args.base(), flags); -#endif - - /* Try a call or construct native object op. */ - if (flags & JSINVOKE_CONSTRUCT) { - if (!args.thisv().isObjectOrNull()) { - if (!js_PrimitiveToObject(cx, &args.thisv())) - return false; - } - return InvokeCommon(cx, NULL, NULL, DoConstruct, args, flags); - } - CallOp callOp = (clasp->flags & Class::CALL_IS_FAST) ? (CallOp) clasp->call : DoSlowCall; - return InvokeCommon(cx, NULL, NULL, callOp, args, flags); -} - -extern JS_REQUIRES_STACK JS_FRIEND_API(bool) -InvokeFriendAPI(JSContext *cx, const InvokeArgsGuard &args, uintN flags) -{ - return Invoke(cx, args, flags); -} - -JSBool -InternalInvoke(JSContext *cx, const Value &thisv, const Value &fval, uintN flags, - uintN argc, Value *argv, Value *rval) +bool +ExternalInvoke(JSContext *cx, const Value &thisv, const Value &fval, + uintN argc, Value *argv, Value *rval) { LeaveTrace(cx); InvokeArgsGuard args; if (!cx->stack().pushInvokeArgs(cx, argc, args)) return JS_FALSE; args.callee() = fval; args.thisv() = thisv; memcpy(args.argv(), argv, argc * sizeof(Value)); - if (!Invoke(cx, args, flags)) + if (!Invoke(cx, args, 0)) return JS_FALSE; *rval = args.rval(); return JS_TRUE; } bool -InternalGetOrSet(JSContext *cx, JSObject *obj, jsid id, const Value &fval, +ExternalGetOrSet(JSContext *cx, JSObject *obj, jsid id, const Value &fval, JSAccessMode mode, uintN argc, Value *argv, Value *rval) { LeaveTrace(cx); /* - * InternalInvoke could result in another try to get or set the same id + * ExternalInvoke could result in another try to get or set the same id * again, see bug 355497. */ JS_CHECK_RECURSION(cx, return JS_FALSE); - return InternalCall(cx, obj, fval, argc, argv, rval); + return ExternalInvoke(cx, obj, fval, argc, argv, rval); } bool Execute(JSContext *cx, JSObject *chain, JSScript *script, JSStackFrame *down, uintN flags, Value *result) { if (script->isEmpty()) { if (result) @@ -1180,76 +1027,92 @@ InstanceOfSlow(JSContext *cx, JSObject * } JS_REQUIRES_STACK bool InvokeConstructor(JSContext *cx, const CallArgs &argsRef) { JS_ASSERT(!js_FunctionClass.construct); CallArgs args = argsRef; - JSObject *obj2; - if (args.callee().isPrimitive() || !(obj2 = &args.callee().toObject())->getParent()) { - /* Use js_ValueToFunction to report an error. */ - JS_ALWAYS_TRUE(!js_ValueToFunction(cx, &args.callee(), JSV2F_CONSTRUCT)); + JSObject *callee; + if (args.callee().isPrimitive() || !(callee = &args.callee().toObject())->getParent()) { + js_ReportIsNotFunction(cx, &args.callee(), JSV2F_CONSTRUCT); return false; } - Class *clasp = &js_ObjectClass; - - /* - * Call fast constructors without making the object first. - * The native will be able to make the right new object faster. - */ - if (obj2->isFunction()) { - JSFunction *fun = GET_FUNCTION_PRIVATE(cx, obj2); - if (fun->isFastConstructor()) { - args.thisv().setMagic(JS_FAST_CONSTRUCTOR); - - FastNative fn = (FastNative)fun->u.n.native; - if (!fn(cx, args.argc(), args.base())) - return JS_FALSE; - JS_ASSERT(!args.rval().isPrimitive()); - return JS_TRUE; + /* Handle the fast-constructors cases before falling into the general case . */ + Class *clasp = callee->getClass(); + if (clasp == &js_FunctionClass) { + JSFunction *fun = callee->getFunctionPrivate(); + if (fun->isConstructor()) { + args.thisv().setMagicWithObjectOrNullPayload(NULL); + return CallJSNativeConstructor(cx, fun->u.n.native, args.argc(), args.base()); } - - /* Get the class, for natives that aren't fast constructors. */ - if (!fun->isInterpreted() && fun->u.n.clasp) - clasp = fun->u.n.clasp; - } - - Value protov; - if (!obj2->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), &protov)) + } else if (clasp->construct) { + args.thisv().setMagicWithObjectOrNullPayload(NULL); + return CallJSNativeConstructor(cx, clasp->construct, args.argc(), args.base()); + } + + /* Construct 'this'. */ + JSObject *obj = js_NewInstance(cx, callee); + if (!obj) return false; - - JSObject *proto = protov.isObjectOrNull() ? protov.toObjectOrNull() : NULL; - JSObject *parent = obj2->getParent(); - - JSObject* obj = NewObject<WithProto::Class>(cx, clasp, proto, parent); - if (!obj) - return JS_FALSE; - - /* Now we have an object with a constructor method; call it. */ args.thisv().setObject(*obj); + if (!Invoke(cx, args, JSINVOKE_CONSTRUCT)) - return JS_FALSE; + return false; /* Check the return value and if it's primitive, force it to be obj. */ if (args.rval().isPrimitive()) { - if (obj2->getClass() != &js_FunctionClass) { + if (callee->getClass() != &js_FunctionClass) { /* native [[Construct]] returning primitive is error */ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_NEW_RESULT, js_ValueToPrintableString(cx, args.rval())); - return JS_FALSE; + return false; } args.rval().setObject(*obj); } JS_RUNTIME_METER(cx->runtime, constructs); - return JS_TRUE; + return true; +} + +bool +InvokeConstructorWithGivenThis(JSContext *cx, JSObject *thisobj, const Value &fval, + uintN argc, Value *argv, Value *rval) +{ + LeaveTrace(cx); + + InvokeArgsGuard args; + if (!cx->stack().pushInvokeArgs(cx, argc, args)) + return JS_FALSE; + + args.callee() = fval; + /* Initialize args.thisv on all paths below. */ + memcpy(args.argv(), argv, argc * sizeof(Value)); + + /* Handle the fast-constructor cases before calling the general case. */ + JSObject &callee = fval.toObject(); + Class *clasp = callee.getClass(); + JSFunction *fun; + bool ok; + if (clasp == &js_FunctionClass && (fun = callee.getFunctionPrivate())->isConstructor()) { + args.thisv().setMagicWithObjectOrNullPayload(thisobj); + ok = CallJSNativeConstructor(cx, fun->u.n.native, args.argc(), args.base()); + } else if (clasp->construct) { + args.thisv().setMagicWithObjectOrNullPayload(thisobj); + ok = CallJSNativeConstructor(cx, clasp->construct, args.argc(), args.base()); + } else { + args.thisv().setObjectOrNull(thisobj); + ok = Invoke(cx, args, JSINVOKE_CONSTRUCT); + } + + *rval = args.rval(); + return ok; } bool ValueToId(JSContext *cx, const Value &v, jsid *idp) { int32_t i; if (ValueFitsInInt32(v, &i) && INT_FITS_IN_JSID(i)) { *idp = INT_TO_JSID(i); @@ -1668,17 +1531,16 @@ namespace reprmeter { DOUBLE, BOOLEAN_PROPER, BOOLEAN_OTHER, STRING, OBJECT_NULL, OBJECT_PLAIN, FUNCTION_INTERPRETED, FUNCTION_FASTNATIVE, - FUNCTION_SLOWNATIVE, ARRAY_SLOW, ARRAY_DENSE }; // Return the |repr| value giving the representation of the given jsval. static Repr GetRepr(jsval v) { @@ -1696,34 +1558,32 @@ namespace reprmeter { JS_ASSERT(JSVAL_IS_OBJECT(v)); JSObject *obj = JSVAL_TO_OBJECT(v); if (VALUE_IS_FUNCTION(cx, v)) { JSFunction *fun = GET_FUNCTION_PRIVATE(cx, obj); if (FUN_INTERPRETED(fun)) return FUNCTION_INTERPRETED; - if (fun->flags & JSFUN_FAST_NATIVE) - return FUNCTION_FASTNATIVE; - return FUNCTION_SLOWNATIVE; + return FUNCTION_FASTNATIVE; } // This must come before the general array test, because that // one subsumes this one. if (!obj) return OBJECT_NULL; if (obj->isDenseArray()) return ARRAY_DENSE; if (obj->isArray()) return ARRAY_SLOW; return OBJECT_PLAIN; } static const char *reprName[] = { "invalid", "int", "double", "bool", "special", "string", "null", "object", - "fun:interp", "fun:fast", "fun:slow", + "fun:interp", "fun:native" "array:slow", "array:dense" }; // Logically, a tuple of (JSOp, repr_1, ..., repr_n) where repr_i is // the |repr| of the ith input to the JSOp. struct OpInput { enum { max_uses = 16 }; JSOp op; @@ -1874,30 +1734,16 @@ namespace reprmeter { /* Test whether v is an int in the range [-2^31 + 1, 2^31 - 2] */ static JS_ALWAYS_INLINE bool CanIncDecWithoutOverflow(int32_t i) { return (i > JSVAL_INT_MIN) && (i < JSVAL_INT_MAX); } /* - * Conditional assert to detect failure to clear a pending exception that is - * suppressed (or unintentional suppression of a wanted exception). - */ -#if defined DEBUG_brendan || defined DEBUG_mrbkap || defined DEBUG_shaver -# define DEBUG_NOT_THROWING 1 -#endif - -#ifdef DEBUG_NOT_THROWING -# define ASSERT_NOT_THROWING(cx) JS_ASSERT(!(cx)->throwing) -#else -# define ASSERT_NOT_THROWING(cx) /* nothing */ -#endif - -/* * Define JS_OPMETER to instrument bytecode succession, generating a .dot file * on shutdown that shows the graph of significant predecessor/successor pairs * executed, where the edge labels give the succession counts. The .dot file * is named by the JS_OPMETER_FILE envariable, and defaults to /tmp/ops.dot. * * Bonus feature: JS_OPMETER also enables counters for stack-addressing ops * such as JSOP_GETLOCAL, JSOP_INCARG, via METER_SLOT_OP. The resulting counts * are written to JS_OPMETER_HIST, defaulting to /tmp/ops.hist. @@ -2447,25 +2293,18 @@ Interpret(JSContext *cx, JSStackFrame *e JS_ASSERT(prevContextRegs == &cx->generatorFor(fp)->savedRegs); JS_ASSERT((size_t) (regs.pc - script->code) <= script->length); JS_ASSERT((size_t) (regs.sp - fp->base()) <= StackDepth(script)); /* * To support generator_throw and to catch ignored exceptions, * fail if cx->throwing is set. */ - if (cx->throwing) { -#ifdef DEBUG_NOT_THROWING - if (cx->exception != JSVAL_ARETURN) { - printf("JS INTERPRETER CALLED WITH PENDING EXCEPTION %lx\n", - (unsigned long) cx->exception); - } -#endif + if (cx->throwing) goto error; - } } #endif #ifdef JS_TRACER /* * The method JIT may have already initiated a recording, in which case * there should already be a valid recorder. Otherwise... * we cannot reenter the interpreter while recording. @@ -2660,17 +2499,16 @@ BEGIN_CASE(JSOP_POPN) <= regs.sp); } #endif } END_CASE(JSOP_POPN) BEGIN_CASE(JSOP_SETRVAL) BEGIN_CASE(JSOP_POPV) - ASSERT_NOT_THROWING(cx); POP_RETURN_VALUE(); END_CASE(JSOP_POPV) BEGIN_CASE(JSOP_ENTERWITH) if (!js_EnterWith(cx, -1)) goto error; /* @@ -2697,17 +2535,16 @@ BEGIN_CASE(JSOP_RETURN) BEGIN_CASE(JSOP_RETRVAL) /* fp return value already set */ BEGIN_CASE(JSOP_STOP) { /* * When the inlined frame exits with an exception or an error, ok will be * false after the inline_return label. */ - ASSERT_NOT_THROWING(cx); CHECK_BRANCH(); #ifdef JS_TRACER if (fp->hasIMacroPC()) { /* * If we are at the end of an imacro, return to its caller in the * current frame. */ @@ -4762,29 +4599,26 @@ BEGIN_CASE(JSOP_APPLY) } #endif /* Load first op and dispatch it (safe since JSOP_STOP). */ op = (JSOp) *regs.pc; DO_OP(); } - if (fun->flags & JSFUN_FAST_NATIVE) { - Probes::enterJSFun(cx, fun); - - JS_ASSERT(fun->u.n.extra == 0); - JS_ASSERT(vp[1].isObjectOrNull() || PrimitiveThisTest(fun, vp[1])); - JSBool ok = ((FastNative) fun->u.n.native)(cx, argc, vp); - Probes::exitJSFun(cx, fun); - regs.sp = vp + 1; - if (!ok) - goto error; - TRACE_0(NativeCallComplete); - goto end_call; - } + JS_ASSERT(vp[1].isObjectOrNull() || PrimitiveThisTest(fun, vp[1])); + + Probes::enterJSFun(cx, fun); + JSBool ok = fun->u.n.native(cx, argc, vp); + Probes::exitJSFun(cx, fun); + regs.sp = vp + 1; + if (!ok) + goto error; + TRACE_0(NativeCallComplete); + goto end_call; } bool ok; ok = Invoke(cx, InvokeArgsAlreadyOnTheStack(vp, argc), 0); regs.sp = vp + 1; CHECK_INTERRUPT_HANDLER(); if (!ok) goto error; @@ -5748,24 +5582,22 @@ BEGIN_CASE(JSOP_LAMBDA) * so regs.sp[1 - (iargc + 2)], and not regs.sp[-(iargc + 2)], * is the callee for this JSOP_CALL. */ const Value &cref = regs.sp[1 - (iargc + 2)]; JSObject *callee; if (IsFunctionObject(cref, &callee)) { JSFunction *calleeFun = GET_FUNCTION_PRIVATE(cx, callee); - FastNative fastNative = FUN_FAST_NATIVE(calleeFun); - - if (fastNative) { - if (iargc == 1 && fastNative == array_sort) { + if (Native native = calleeFun->maybeNative()) { + if (iargc == 1 && native == array_sort) { JS_FUNCTION_METER(cx, joinedsort); break; } - if (iargc == 2 && fastNative == str_replace) { + if (iargc == 2 && native == str_replace) { JS_FUNCTION_METER(cx, joinedreplace); break; } } } } else if (op2 == JSOP_NULL) { pc2 += JSOP_NULL_LENGTH; op2 = JSOp(*pc2); @@ -6721,31 +6553,31 @@ BEGIN_CASE(JSOP_LEAVEBLOCK) JS_ASSERT(fp->base() + blockDepth == regs.sp); } } END_CASE(JSOP_LEAVEBLOCK) #if JS_HAS_GENERATORS BEGIN_CASE(JSOP_GENERATOR) { - ASSERT_NOT_THROWING(cx); + JS_ASSERT(!cx->throwing); regs.pc += JSOP_GENERATOR_LENGTH; JSObject *obj = js_NewGenerator(cx); if (!obj) goto error; JS_ASSERT(!fp->hasCallObj() && !fp->hasArgsObj()); fp->setReturnValue(ObjectValue(*obj)); interpReturnOK = true; if (entryFrame != fp) goto inline_return; goto exit; } BEGIN_CASE(JSOP_YIELD) - ASSERT_NOT_THROWING(cx); + JS_ASSERT(!cx->throwing); if (cx->generatorFor(fp)->state == JSGEN_CLOSING) { js_ReportValueError(cx, JSMSG_BAD_GENERATOR_YIELD, JSDVG_SEARCH_STACK, fp->argv[-2], NULL); goto error; } fp->setReturnValue(regs.sp[-1]); fp->flags |= JSFRAME_YIELDING; regs.pc += JSOP_YIELD_LENGTH;
--- a/js/src/jsinterp.h +++ b/js/src/jsinterp.h @@ -680,48 +680,62 @@ Invoke(JSContext *cx, const CallArgs &ar #define JSINVOKE_CONSTRUCT JSFRAME_CONSTRUCTING /* * Mask to isolate construct and iterator flags for use with jsfun.h functions. */ #define JSINVOKE_FUNFLAGS JSINVOKE_CONSTRUCT /* - * "Internal" calls may come from C or C++ code using a JSContext on which no + * "External" calls may come from C or C++ code using a JSContext on which no * JS is running (!cx->fp), so they may need to push a dummy JSStackFrame. */ -extern JSBool -InternalInvoke(JSContext *cx, const Value &thisv, const Value &fval, uintN flags, + +extern bool +ExternalInvoke(JSContext *cx, const Value &thisv, const Value &fval, uintN argc, Value *argv, Value *rval); static JS_ALWAYS_INLINE bool -InternalCall(JSContext *cx, JSObject *obj, const Value &fval, - uintN argc, Value *argv, Value *rval) +ExternalInvoke(JSContext *cx, JSObject *obj, const Value &fval, + uintN argc, Value *argv, Value *rval) { - return InternalInvoke(cx, ObjectOrNullValue(obj), fval, 0, argc, argv, rval); -} - -static JS_ALWAYS_INLINE bool -InternalConstruct(JSContext *cx, JSObject *obj, const Value &fval, - uintN argc, Value *argv, Value *rval) -{ - return InternalInvoke(cx, ObjectOrNullValue(obj), fval, JSINVOKE_CONSTRUCT, argc, argv, rval); + return ExternalInvoke(cx, ObjectOrNullValue(obj), fval, argc, argv, rval); } extern bool -InternalGetOrSet(JSContext *cx, JSObject *obj, jsid id, const Value &fval, +ExternalGetOrSet(JSContext *cx, JSObject *obj, jsid id, const Value &fval, JSAccessMode mode, uintN argc, Value *argv, Value *rval); +/* + * These two functions invoke a function called from a constructor context + * (e.g. 'new'). InvokeConstructor handles the general case where a new object + * needs to be created for/by the constructor. ConstructWithGivenThis directly + * calls the constructor with the given 'this', hence the caller must + * understand the semantics of the constructor call. + */ + +extern JS_REQUIRES_STACK bool +InvokeConstructor(JSContext *cx, const CallArgs &args); + +extern JS_REQUIRES_STACK bool +InvokeConstructorWithGivenThis(JSContext *cx, JSObject *thisobj, const Value &fval, + uintN argc, Value *argv, Value *rval); + +/* + * Executes a script with the given scope chain in the context of the given + * frame. + */ extern JS_FORCES_STACK bool Execute(JSContext *cx, JSObject *chain, JSScript *script, JSStackFrame *down, uintN flags, Value *result); -extern JS_REQUIRES_STACK bool -InvokeConstructor(JSContext *cx, const CallArgs &args); - +/* + * Execute the caller-initialized frame for a user-defined script or function + * pointed to by cx->fp until completion or error. + */ extern JS_REQUIRES_STACK bool Interpret(JSContext *cx, JSStackFrame *stopFp, uintN inlineCallCount = 0); extern JS_REQUIRES_STACK bool RunScript(JSContext *cx, JSScript *script, JSFunction *fun, JSObject *scopeChain); #define JSPROP_INITIALIZER 0x100 /* NB: Not a valid property attribute. */
--- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -82,17 +82,18 @@ using namespace js; static void iterator_finalize(JSContext *cx, JSObject *obj); static void iterator_trace(JSTracer *trc, JSObject *obj); static JSObject *iterator_iterator(JSContext *cx, JSObject *obj, JSBool keysonly); Class js_IteratorClass = { "Iterator", - JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Iterator) | JSCLASS_MARK_IS_TRACE, + JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Iterator) | + JSCLASS_MARK_IS_TRACE, PropertyStub, /* addProperty */ PropertyStub, /* delProperty */ PropertyStub, /* getProperty */ PropertyStub, /* setProperty */ EnumerateStub, ResolveStub, ConvertStub, iterator_finalize, @@ -402,17 +403,17 @@ GetCustomIterator(JSContext *cx, JSObjec /* If there is no custom __iterator__ method, we are done here. */ if (vp->isUndefined()) return true; /* Otherwise call it and return that object. */ LeaveTrace(cx); Value arg = BooleanValue((flags & JSITER_FOREACH) == 0); - if (!InternalCall(cx, obj, *vp, 1, &arg, vp)) + if (!ExternalInvoke(cx, obj, *vp, 1, &arg, vp)) return false; if (vp->isPrimitive()) { /* * 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). */ js_ReportValueError2(cx, JSMSG_BAD_TRAP_RETURN_VALUE, -1, ObjectValue(*obj), NULL, @@ -724,25 +725,23 @@ GetIterator(JSContext *cx, JSObject *obj static JSObject * iterator_iterator(JSContext *cx, JSObject *obj, JSBool keysonly) { return obj; } static JSBool -Iterator(JSContext *cx, JSObject *iterobj, uintN argc, Value *argv, Value *rval) +Iterator(JSContext *cx, uintN argc, Value *vp) { - JSBool keyonly; - uintN flags; - - keyonly = js_ValueToBoolean(argv[1]); - flags = JSITER_OWNONLY | (keyonly ? 0 : (JSITER_FOREACH | JSITER_KEYVALUE)); - *rval = argv[0]; - return js_ValueToIterator(cx, flags, rval); + Value *argv = JS_ARGV(cx, vp); + bool keyonly = argc >= 2 ? js_ValueToBoolean(argv[1]) : false; + uintN flags = JSITER_OWNONLY | (keyonly ? 0 : (JSITER_FOREACH | JSITER_KEYVALUE)); + *vp = argc >= 1 ? argv[0] : UndefinedValue(); + return js_ValueToIterator(cx, flags, vp); } JSBool js_ThrowStopIteration(JSContext *cx) { Value v; JS_ASSERT(!JS_IsExceptionPending(cx)); @@ -962,17 +961,17 @@ js_IteratorMore(JSContext *cx, JSObject rval->setBoolean(true); return true; } /* Fetch and cache the next value from the iterator. */ jsid id = ATOM_TO_JSID(cx->runtime->atomState.nextAtom); if (!js_GetMethod(cx, iterobj, id, JSGET_METHOD_BARRIER, rval)) return false; - if (!InternalCall(cx, iterobj, *rval, 0, NULL, rval)) { + if (!ExternalInvoke(cx, iterobj, *rval, 0, NULL, rval)) { /* Check for StopIteration. */ if (!cx->throwing || !js_ValueIsStopIteration(cx->exception)) return false; /* Inline JS_ClearPendingException(cx). */ cx->throwing = JS_FALSE; cx->exception.setUndefined(); cx->iterValue.setMagic(JS_NO_ITER_VALUE);
--- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -526,28 +526,37 @@ Class js_NumberClass = { PropertyStub, /* getProperty */ PropertyStub, /* setProperty */ EnumerateStub, ResolveStub, ConvertStub }; static JSBool -Number(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) +Number(JSContext *cx, uintN argc, Value *vp) { - if (argc != 0) { - if (!ValueToNumber(cx, &argv[0])) - return JS_FALSE; + /* Sample JS_CALLEE before clobbering. */ + bool isConstructing = IsConstructing(vp); + + if (argc > 0) { + if (!ValueToNumber(cx, &vp[2])) + return false; + vp[0] = vp[2]; } else { - argv[0].setInt32(0); + vp[0].setInt32(0); } - if (!JS_IsConstructing(cx)) - *rval = argv[0]; - else - obj->setPrimitiveThis(argv[0]); + + if (!isConstructing) + return true; + + JSObject *obj = NewBuiltinClassInstance(cx, &js_NumberClass); + if (!obj) + return false; + obj->setPrimitiveThis(vp[0]); + vp->setObject(*obj); return true; } #if JS_HAS_TOSOURCE static JSBool num_toSource(JSContext *cx, uintN argc, Value *vp) { char numBuf[DTOSTR_STANDARD_BUFFER_SIZE], *numStr;
--- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -102,18 +102,17 @@ #include "jsautooplen.h" using namespace js; JS_FRIEND_DATA(const JSObjectMap) JSObjectMap::sharedNonNative(JSObjectMap::SHAPELESS); Class js_ObjectClass = { js_Object_str, - JSCLASS_HAS_CACHED_PROTO(JSProto_Object) | - JSCLASS_FAST_CONSTRUCTOR, + JSCLASS_HAS_CACHED_PROTO(JSProto_Object), PropertyStub, /* addProperty */ PropertyStub, /* delProperty */ PropertyStub, /* getProperty */ PropertyStub, /* setProperty */ EnumerateStub, ResolveStub, ConvertStub }; @@ -1086,17 +1085,17 @@ obj_eval(JSContext *cx, uintN argc, Valu * this so the compiler can make assumptions about what bindings may or * may not exist in the current frame if it doesn't see 'eval'. */ if (indirectCall) { /* Pretend that we're top level. */ staticLevel = 0; if (!js_CheckPrincipalsAccess(cx, obj, - JS_StackFramePrincipals(cx, caller), + js_StackFramePrincipals(cx, caller), cx->runtime->atomState.evalAtom)) { return JS_FALSE; } /* NB: We know inner is a global object here. */ JS_ASSERT(!obj->getParent()); scopeobj = obj; } else { @@ -1285,17 +1284,17 @@ obj_watch_handler(JSContext *cx, JSObjec /* Skip over any obj_watch_* frames between us and the real subject. */ caller = js_GetScriptedCaller(cx, NULL); if (caller) { /* * Only call the watch handler if the watcher is allowed to watch * the currently executing script. */ watcher = callbacks->findObjectPrincipals(cx, callable); - subject = JS_StackFramePrincipals(cx, caller); + subject = js_StackFramePrincipals(cx, caller); if (watcher && subject && !watcher->subsume(watcher, subject)) { /* Silently don't call the watch handler. */ return JS_TRUE; } } } @@ -1306,17 +1305,17 @@ obj_watch_handler(JSContext *cx, JSObjec return JS_FALSE; if (!entry) return JS_TRUE; generation = cx->resolvingTable->generation; argv[0] = IdToValue(id); argv[1] = Valueify(old); argv[2] = Valueify(*nvp); - ok = InternalCall(cx, obj, ObjectOrNullValue(callable), 3, argv, Valueify(nvp)); + ok = ExternalInvoke(cx, obj, ObjectOrNullValue(callable), 3, argv, Valueify(nvp)); js_StopResolving(cx, &key, JSRESFLAG_WATCH, entry, generation); return ok; } static JSBool obj_watch(JSContext *cx, uintN argc, Value *vp) { if (argc <= 1) { @@ -2579,16 +2578,37 @@ js_Object(JSContext *cx, uintN argc, Val obj = NewBuiltinClassInstance(cx, &js_ObjectClass); if (!obj) return JS_FALSE; } vp->setObject(*obj); return JS_TRUE; } +JSObject* +js_NewInstance(JSContext *cx, JSObject *callee) +{ + Class *clasp = callee->getClass(); + + Class *newclasp = &js_ObjectClass; + if (clasp == &js_FunctionClass) { + JSFunction *fun = callee->getFunctionPrivate(); + if (fun->isNative() && fun->u.n.clasp) + newclasp = fun->u.n.clasp; + } + + Value protov; + if (!callee->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), &protov)) + return NULL; + + JSObject *proto = protov.isObjectOrNull() ? protov.toObjectOrNull() : NULL; + JSObject *parent = callee->getParent(); + return NewObject<WithProto::Class>(cx, newclasp, proto, parent); +} + #ifdef JS_TRACER JSObject* js_NewObjectWithClassProto(JSContext *cx, Class *clasp, JSObject *proto, const Value &privateSlotValue) { JS_ASSERT(clasp->isNative()); @@ -2620,17 +2640,17 @@ js_NonEmptyObject(JSContext* cx, JSObjec JSObject *obj = js_NewObjectWithClassProto(cx, &js_ObjectClass, proto, UndefinedValue()); return (obj && obj->ensureClassReservedSlotsForEmptyObject(cx)) ? obj : NULL; } JS_DEFINE_CALLINFO_2(extern, CONSTRUCTOR_RETRY, js_NonEmptyObject, CONTEXT, CALLEE_PROTOTYPE, 0, nanojit::ACCSET_STORE_ANY) JSObject* FASTCALL -js_NewInstance(JSContext *cx, Class *clasp, JSObject *ctor) +js_NewInstanceFromTrace(JSContext *cx, Class *clasp, JSObject *ctor) { JS_ASSERT(JS_ON_TRACE(cx)); JS_ASSERT(ctor->isFunction()); #ifdef JS_THREADSAFE if (ctor->title.ownercx != cx) return NULL; #endif @@ -2671,17 +2691,17 @@ js_NewInstance(JSContext *cx, Class *cla /* * FIXME: 561785 at least. Quasi-natives including XML objects prevent us * from easily or unconditionally calling NewNativeClassInstance here. */ return NewNonFunction<WithProto::Given>(cx, clasp, proto, parent); } -JS_DEFINE_CALLINFO_3(extern, CONSTRUCTOR_RETRY, js_NewInstance, CONTEXT, CLASS, OBJECT, 0, +JS_DEFINE_CALLINFO_3(extern, CONSTRUCTOR_RETRY, js_NewInstanceFromTrace, CONTEXT, CLASS, OBJECT, 0, nanojit::ACCSET_STORE_ANY) #else /* !JS_TRACER */ # define js_Object_trcinfo NULL #endif /* !JS_TRACER */ @@ -3239,25 +3259,24 @@ Class js_BlockClass = { EnumerateStub, ResolveStub, ConvertStub }; JSObject * js_InitObjectClass(JSContext *cx, JSObject *obj) { - JSObject *proto = js_InitClass(cx, obj, NULL, &js_ObjectClass, (Native) js_Object, 1, + JSObject *proto = js_InitClass(cx, obj, NULL, &js_ObjectClass, js_Object, 1, object_props, object_methods, NULL, object_static_methods); if (!proto) 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, - (Native)obj_eval, 1, - JSFUN_FAST_NATIVE | JSFUN_STUB_GSOPS)) { + if (!js_DefineFunction(cx, obj, cx->runtime->atomState.evalAtom, obj_eval, 1, + JSFUN_STUB_GSOPS)) { return NULL; } return proto; } static bool DefineStandardSlot(JSContext *cx, JSObject *obj, JSProtoKey key, JSAtom *atom, @@ -3385,21 +3404,17 @@ js_InitClass(JSContext *cx, JSObject *ob ? JSPROP_READONLY | JSPROP_PERMANENT : 0; if (!DefineStandardSlot(cx, obj, key, atom, ObjectValue(*proto), attrs, named)) goto bad; } ctor = proto; } else { - uint16 flags = 0; - if (clasp->flags & JSCLASS_FAST_CONSTRUCTOR) - flags |= JSFUN_FAST_NATIVE | JSFUN_FAST_NATIVE_CTOR; - - fun = js_NewFunction(cx, NULL, constructor, nargs, flags, obj, atom); + fun = js_NewFunction(cx, NULL, constructor, nargs, JSFUN_CONSTRUCTOR, obj, atom); if (!fun) goto bad; AutoValueRooter tvr2(cx, ObjectValue(*fun)); if (!DefineStandardSlot(cx, obj, key, atom, tvr2.value(), 0, named)) goto bad; /* @@ -3413,18 +3428,20 @@ js_InitClass(JSContext *cx, JSObject *ob * Optionally construct the prototype object, before the class has * been fully initialized. Allow the ctor to replace proto with a * different object, as is done for operator new -- and as at least * XML support requires. */ ctor = FUN_OBJECT(fun); if (clasp->flags & JSCLASS_CONSTRUCT_PROTOTYPE) { Value rval; - if (!InternalConstruct(cx, proto, ObjectOrNullValue(ctor), 0, NULL, &rval)) + if (!InvokeConstructorWithGivenThis(cx, proto, ObjectOrNullValue(ctor), + 0, NULL, &rval)) { goto bad; + } if (rval.isObject() && &rval.toObject() != proto) proto = &rval.toObject(); } /* Connect constructor and prototype by named properties. */ if (!js_SetClassPrototype(cx, ctor, proto, JSPROP_READONLY | JSPROP_PERMANENT)) { goto bad; @@ -3830,17 +3847,17 @@ js_ConstructObject(JSContext *cx, Class proto = rval.toObjectOrNull(); } JSObject *obj = NewObject<WithProto::Class>(cx, clasp, proto, parent); if (!obj) return NULL; Value rval; - if (!InternalConstruct(cx, obj, cval, argc, argv, &rval)) + if (!InvokeConstructorWithGivenThis(cx, obj, cval, argc, argv, &rval)) return NULL; if (rval.isPrimitive()) return obj; /* * If the instance's class differs from what was requested, throw a type * error. If the given class has both the JSCLASS_HAS_PRIVATE and the @@ -5294,19 +5311,18 @@ DefaultValue(JSContext *cx, JSObject *ob } } if (shape && shape->hasDefaultGetter() && pobj->containsSlot(shape->slot)) { const Value &fval = pobj->lockedGetSlot(shape->slot); JSObject *funobj; if (IsFunctionObject(fval, &funobj)) { - JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj); - - if (FUN_FAST_NATIVE(fun) == js_str_toString) { + JSFunction *fun = funobj->getFunctionPrivate(); + if (fun->maybeNative() == js_str_toString) { JS_UNLOCK_OBJ(cx, lockedobj); *vp = obj->getPrimitiveThis(); return JS_TRUE; } } } JS_UNLOCK_OBJ(cx, lockedobj); } @@ -5698,17 +5714,17 @@ js_TryMethod(JSContext *cx, JSObject *ob Value fval; JSBool ok = js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, &fval); JS_SetErrorReporter(cx, older); if (!ok) return false; if (fval.isPrimitive()) return JS_TRUE; - return InternalCall(cx, obj, fval, argc, argv, rval); + return ExternalInvoke(cx, obj, fval, argc, argv, rval); } #if JS_HAS_XDR JSBool js_XDRObject(JSXDRState *xdr, JSObject **objp) { JSContext *cx;
--- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -1349,16 +1349,19 @@ js_SetClassObject(JSContext *cx, JSObjec extern JSBool js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey key, js::Value *vp, js::Class *clasp = NULL); extern JSObject * js_ConstructObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent, uintN argc, js::Value *argv); +extern JSObject * +js_NewInstance(JSContext *cx, JSObject *callee); + extern jsid js_CheckForStringIndex(jsid id); /* * js_PurgeScopeChain does nothing if obj is not itself a prototype or parent * scope, else it reshapes the scope and prototype chains it links. It calls * js_PurgeScopeChainHelper, which asserts that obj is flagged as a delegate * (i.e., obj has ever been on a prototype or parent chain).
--- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -448,23 +448,16 @@ JSObject::getDateUTCTime() const inline void JSObject::setDateUTCTime(const js::Value &time) { JS_ASSERT(isDate()); fslots[JSSLOT_DATE_UTC_TIME] = time; } -inline JSFunction * -JSObject::getFunctionPrivate() const -{ - JS_ASSERT(isFunction()); - return reinterpret_cast<JSFunction *>(getPrivate()); -} - inline js::Value * JSObject::getFlatClosureUpvars() const { JS_ASSERT(isFunction()); JS_ASSERT(FUN_FLAT_CLOSURE(getFunctionPrivate())); return (js::Value *) fslots[JSSLOT_FLAT_CLOSURE_UPVARS].toPrivate(); }
--- a/js/src/jsprobes.cpp +++ b/js/src/jsprobes.cpp @@ -91,16 +91,17 @@ Probes::FunctionLineNumber(JSContext *cx * All are presented as void * for DTrace consumers to use, after shifting or * masking out the JavaScript type bits. This allows D scripts to use ints and * booleans directly and copyinstr() for string arguments, when types are known * beforehand. * * This is used by the function-args and function-rval probes, which also * provide raw (unmasked) jsvals should type info be useful from D scripts. */ +#if 0 static void * jsprobes_jsvaltovoid(JSContext *cx, const js::Value &argval) { if (argval.isNull()) return (void *)JS_TYPE_STR(JSTYPE_NULL); if (argval.isUndefined()) return (void *)JS_TYPE_STR(JSTYPE_VOID); @@ -115,16 +116,17 @@ jsprobes_jsvaltovoid(JSContext *cx, cons if (argval.isInt32()) return (void *)argval.toInt32(); // FIXME Now what? //return (void *)argval.toDouble(); } return argval.asGCThing(); } +#endif const char * Probes::FunctionName(JSContext *cx, const JSFunction *fun) { if (!fun) return nullName; JSAtom *atom = fun->atom;
--- a/js/src/jsproxy.cpp +++ b/js/src/jsproxy.cpp @@ -120,17 +120,17 @@ JSProxyHandler::get(JSContext *cx, JSObj vp->setUndefined(); return true; } if (!desc.getter) { *vp = desc.value; return true; } if (desc.attrs & JSPROP_GETTER) { - return InternalGetOrSet(cx, proxy, id, CastAsObjectJsval(desc.getter), + return ExternalGetOrSet(cx, proxy, id, CastAsObjectJsval(desc.getter), JSACC_READ, 0, 0, vp); } if (desc.attrs & JSPROP_SHORTID) id = INT_TO_JSID(desc.shortid); return CallJSPropertyOp(cx, desc.getter, proxy, id, vp); } bool @@ -139,34 +139,34 @@ JSProxyHandler::set(JSContext *cx, JSObj JS_ASSERT(OperationInProgress(cx, proxy)); AutoPropertyDescriptorRooter desc(cx); if (!getOwnPropertyDescriptor(cx, proxy, id, &desc)) return false; /* The control-flow here differs from ::get() because of the fall-through case below. */ if (desc.obj) { if (desc.setter) { if (desc.attrs & JSPROP_SETTER) { - return InternalGetOrSet(cx, proxy, id, CastAsObjectJsval(desc.setter), + return ExternalGetOrSet(cx, proxy, id, CastAsObjectJsval(desc.setter), JSACC_READ, 0, 0, vp); } if (desc.attrs & JSPROP_SHORTID) id = INT_TO_JSID(desc.shortid); return CallJSPropertyOpSetter(cx, desc.setter, proxy, id, vp); } if (desc.attrs & JSPROP_READONLY) return true; desc.value = *vp; return defineProperty(cx, proxy, id, &desc); } if (!getPropertyDescriptor(cx, proxy, id, &desc)) return false; if (desc.obj) { if (desc.setter) { if (desc.attrs & JSPROP_SETTER) { - return InternalGetOrSet(cx, proxy, id, CastAsObjectJsval(desc.setter), + return ExternalGetOrSet(cx, proxy, id, CastAsObjectJsval(desc.setter), JSACC_READ, 0, 0, vp); } if (desc.attrs & JSPROP_SHORTID) id = INT_TO_JSID(desc.shortid); return CallJSPropertyOpSetter(cx, desc.setter, proxy, id, vp); } if (desc.attrs & JSPROP_READONLY) return true; @@ -244,17 +244,17 @@ JSProxyHandler::fun_toString(JSContext * return fun_toStringHelper(cx, &fval.toObject(), indent); } bool JSProxyHandler::call(JSContext *cx, JSObject *proxy, uintN argc, Value *vp) { JS_ASSERT(OperationInProgress(cx, proxy)); AutoValueRooter rval(cx); - JSBool ok = InternalInvoke(cx, vp[1], GetCall(proxy), 0, argc, JS_ARGV(cx, vp), + JSBool ok = ExternalInvoke(cx, vp[1], GetCall(proxy), argc, JS_ARGV(cx, vp), rval.addr()); if (ok) JS_SET_RVAL(cx, vp, rval.value()); return ok; } bool JSProxyHandler::construct(JSContext *cx, JSObject *proxy, @@ -272,17 +272,17 @@ JSProxyHandler::construct(JSContext *cx, } /* * FIXME: The Proxy proposal says to pass undefined as the this argument, * but primitive this is not supported yet. See bug 576644. */ JS_ASSERT(fval.isObject()); JSObject *thisobj = fval.toObject().getGlobal(); - return InternalCall(cx, thisobj, fval, argc, argv, rval); + return ExternalInvoke(cx, thisobj, fval, argc, argv, rval); } void JSProxyHandler::finalize(JSContext *cx, JSObject *proxy) { } void @@ -324,17 +324,17 @@ DerivedTrap(JSContext *cx, JSObject *han return GetTrap(cx, handler, atom, fvalp); } static bool Trap(JSContext *cx, JSObject *handler, Value fval, uintN argc, Value* argv, Value *rval) { JS_CHECK_RECURSION(cx, return false); - return InternalCall(cx, handler, fval, argc, argv, rval); + return ExternalInvoke(cx, handler, fval, argc, argv, rval); } static bool Trap1(JSContext *cx, JSObject *handler, Value fval, jsid id, Value *rval) { JSString *str = js_ValueToString(cx, IdToValue(id)); if (!str) return false; @@ -943,45 +943,48 @@ JSBool proxy_Call(JSContext *cx, uintN argc, Value *vp) { JSObject *proxy = &JS_CALLEE(cx, vp).toObject(); JS_ASSERT(proxy->isProxy()); return JSProxy::call(cx, proxy, argc, vp); } JSBool -proxy_Construct(JSContext *cx, JSObject * /*obj*/, uintN argc, Value *argv, Value *rval) +proxy_Construct(JSContext *cx, uintN argc, Value *vp) { - JSObject *proxy = &argv[-2].toObject(); + JSObject *proxy = &JS_CALLEE(cx, vp).toObject(); JS_ASSERT(proxy->isProxy()); - return JSProxy::construct(cx, proxy, argc, argv, rval); + Value rval; + bool ok = JSProxy::construct(cx, proxy, argc, JS_ARGV(cx, vp), &rval); + *vp = rval; + return ok; } static JSType proxy_TypeOf_fun(JSContext *cx, JSObject *obj) { return JSTYPE_FUNCTION; } #define proxy_HasInstance js_FunctionClass.hasInstance JS_FRIEND_API(Class) FunctionProxyClass = { "Proxy", - Class::NON_NATIVE | JSCLASS_HAS_RESERVED_SLOTS(4) | Class::CALL_IS_FAST, + Class::NON_NATIVE | JSCLASS_HAS_RESERVED_SLOTS(4), PropertyStub, /* addProperty */ PropertyStub, /* delProperty */ PropertyStub, /* getProperty */ PropertyStub, /* setProperty */ EnumerateStub, ResolveStub, ConvertStub, NULL, /* finalize */ NULL, /* reserved0 */ NULL, /* checkAccess */ - CastCallOpAsNative(proxy_Call), + proxy_Call, proxy_Construct, NULL, /* xdrObject */ proxy_HasInstance, NULL, /* mark */ JS_NULL_CLASS_EXT, { proxy_LookupProperty, proxy_DefineProperty, @@ -1148,64 +1151,80 @@ static JSFunctionSpec static_methods[] = }; extern Class CallableObjectClass; static const uint32 JSSLOT_CALLABLE_CALL = JSSLOT_PRIVATE; static const uint32 JSSLOT_CALLABLE_CONSTRUCT = JSSLOT_PRIVATE + 1; static JSBool -callable_Call(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) +callable_Call(JSContext *cx, uintN argc, Value *vp) { - JSObject *callable = &argv[-2].toObject(); + JSObject *thisobj = ComputeThisFromVp(cx, vp); + if (!thisobj) + return false; + + JSObject *callable = &JS_CALLEE(cx, vp).toObject(); JS_ASSERT(callable->getClass() == &CallableObjectClass); const Value &fval = callable->fslots[JSSLOT_CALLABLE_CALL]; - return InternalCall(cx, obj, fval, argc, argv, rval); + Value rval; + bool ok = ExternalInvoke(cx, thisobj, fval, argc, JS_ARGV(cx, vp), &rval); + *vp = rval; + return ok; } static JSBool -callable_Construct(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) +callable_Construct(JSContext *cx, uintN argc, Value *vp) { - JSObject *callable = &argv[-2].toObject(); + JSObject *thisobj = js_NewInstance(cx, &JS_CALLEE(cx, vp).toObject()); + if (!thisobj) + return false; + + JSObject *callable = &vp[0].toObject(); JS_ASSERT(callable->getClass() == &CallableObjectClass); Value fval = callable->fslots[JSSLOT_CALLABLE_CONSTRUCT]; if (fval.isUndefined()) { /* We don't have an explicit constructor so allocate a new object and use the call. */ fval = callable->fslots[JSSLOT_CALLABLE_CALL]; JS_ASSERT(fval.isObject()); /* callable is the constructor, so get callable.prototype is the proto of the new object. */ - if (!callable->getProperty(cx, ATOM_TO_JSID(ATOM(classPrototype)), rval)) + Value protov; + if (!callable->getProperty(cx, ATOM_TO_JSID(ATOM(classPrototype)), &protov)) return false; JSObject *proto; - if (rval->isObject()) { - proto = &rval->toObject(); + if (protov.isObject()) { + proto = &protov.toObject(); } else { if (!js_GetClassPrototype(cx, NULL, JSProto_Object, &proto)) return false; } JSObject *newobj = NewNativeClassInstance(cx, &js_ObjectClass, proto, proto->getParent()); if (!newobj) return false; - rval->setObject(*newobj); - /* If the call returns an object, return that, otherwise the original newobj. */ - if (!InternalCall(cx, newobj, callable->fslots[JSSLOT_CALLABLE_CALL], - argc, argv, rval)) { + Value rval; + if (!ExternalInvoke(cx, newobj, callable->fslots[JSSLOT_CALLABLE_CALL], + argc, vp + 2, &rval)) { return false; } - if (rval->isPrimitive()) - rval->setObject(*newobj); - + if (rval.isPrimitive()) + vp->setObject(*newobj); + else + *vp = rval; return true; } - return InternalCall(cx, obj, fval, argc, argv, rval); + + Value rval; + bool ok = ExternalInvoke(cx, thisobj, fval, argc, vp + 2, &rval); + *vp = rval; + return ok; } Class CallableObjectClass = { "Function", JSCLASS_HAS_RESERVED_SLOTS(2), PropertyStub, /* addProperty */ PropertyStub, /* delProperty */ PropertyStub, /* getProperty */
--- a/js/src/jsprvtd.h +++ b/js/src/jsprvtd.h @@ -324,24 +324,16 @@ typedef JSBool /* * Get or set attributes of the property obj[id]. Return false on error or * exception, true with current attributes in *attrsp. */ typedef JSBool (* JSAttributesOp)(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp); /* - * The type of ops->call. Same argument types as JSFastNative, but a different - * contract. A JSCallOp expects a dummy stack frame with the caller's - * scopeChain. - */ -typedef JSBool -(* JSCallOp)(JSContext *cx, uintN argc, jsval *vp); - -/* * A generic type for functions mapping an object to another object, or null * if an error or exception was thrown on cx. */ typedef JSObject * (* JSObjectOp)(JSContext *cx, JSObject *obj); /* * Hook that creates an iterator object for a given object. Returns the
--- a/js/src/jspubtd.h +++ b/js/src/jspubtd.h @@ -391,25 +391,24 @@ typedef void * a string describing the reference traced with JS_CallTracer. */ typedef void (* JSTraceNamePrinter)(JSTracer *trc, char *buf, size_t bufsize); typedef JSBool (* JSEqualityOp)(JSContext *cx, JSObject *obj, const jsval *v, JSBool *bp); -/* Typedef for native functions called by the JS VM. */ +/* + * Typedef for native functions called by the JS VM. + * + * See jsapi.h, the JS_CALLEE, JS_THIS, etc. macros. + */ typedef JSBool -(* JSNative)(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval); - -/* See jsapi.h, the JS_CALLEE, JS_THIS, etc. macros. */ -typedef JSBool -(* JSFastNative)(JSContext *cx, uintN argc, jsval *vp); +(* JSNative)(JSContext *cx, uintN argc, jsval *vp); /* Callbacks and their arguments. */ typedef enum JSContextOp { JSCONTEXT_NEW, JSCONTEXT_DESTROY } JSContextOp;
--- a/js/src/jsregexp.cpp +++ b/js/src/jsregexp.cpp @@ -571,19 +571,19 @@ regexp_finalize(JSContext *cx, JSObject re->decref(cx); } /* Forward static prototype. */ static JSBool regexp_exec_sub(JSContext *cx, JSObject *obj, uintN argc, Value *argv, JSBool test, Value *rval); static JSBool -regexp_call(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) +regexp_call(JSContext *cx, uintN argc, Value *vp) { - return regexp_exec_sub(cx, argv[-2].toObjectOrNull(), argc, argv, JS_FALSE, rval); + return regexp_exec_sub(cx, &JS_CALLEE(cx, vp).toObject(), argc, JS_ARGV(cx, vp), false, vp); } #if JS_HAS_XDR #include "jsxdrapi.h" JSBool js_XDRRegExpObject(JSXDRState *xdr, JSObject **objp) @@ -955,42 +955,36 @@ static JSFunctionSpec regexp_methods[] = JS_FN(js_toString_str, regexp_toString, 0,0), JS_FN("compile", regexp_compile, 2,0), JS_FN("exec", regexp_exec, 1,0), JS_FN("test", regexp_test, 1,0), JS_FS_END }; static JSBool -regexp_construct(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) +regexp_construct(JSContext *cx, uintN argc, Value *vp) { - if (!JS_IsConstructing(cx)) { - /* - * If first arg is regexp and no flags are given, just return the arg. - * (regexp_compile_sub detects the regexp + flags case and throws a - * TypeError.) See 10.15.3.1. - */ - if ((argc < 2 || argv[1].isUndefined()) && !argv[0].isPrimitive() && - argv[0].toObject().getClass() == &js_RegExpClass) { - *rval = argv[0]; - return true; - } + /* + * If first arg is regexp and no flags are given, just return the arg. + * (regexp_compile_sub detects the regexp + flags case and throws a + * TypeError.) See 10.15.3.1. + */ + Value *argv = vp + 2; + if ((argc < 2 || argv[1].isUndefined()) && argv[0].isObject() && + argv[0].toObject().getClass() == &js_RegExpClass) { + *vp = argv[0]; + return true; + } - /* Otherwise, replace obj with a new RegExp object. */ - obj = NewBuiltinClassInstance(cx, &js_RegExpClass); - if (!obj) - return false; + /* Otherwise, replace obj with a new RegExp object. */ + JSObject *obj = NewBuiltinClassInstance(cx, &js_RegExpClass); + if (!obj) + return false; - /* - * regexp_compile_sub does not use rval to root its temporaries so we - * can use it to root obj. - */ - *rval = ObjectValue(*obj); - } - return regexp_compile_sub(cx, obj, argc, argv, rval); + return regexp_compile_sub(cx, obj, argc, argv, vp); } JSObject * js_InitRegExpClass(JSContext *cx, JSObject *obj) { JSObject *proto = js_InitClass(cx, obj, NULL, &js_RegExpClass, regexp_construct, 1, NULL, regexp_methods, regexp_static_props, NULL); if (!proto)
--- a/js/src/jsscopeinlines.h +++ b/js/src/jsscopeinlines.h @@ -210,17 +210,17 @@ inline bool Shape::get(JSContext* cx, JSObject* obj, JSObject *pobj, js::Value* vp) const { JS_ASSERT(!JSID_IS_VOID(this->id)); JS_ASSERT(!hasDefaultGetter()); if (hasGetterValue()) { JS_ASSERT(!isMethod()); js::Value fval = getterValue(); - return js::InternalGetOrSet(cx, obj, id, fval, JSACC_READ, 0, 0, vp); + return js::ExternalGetOrSet(cx, obj, id, fval, JSACC_READ, 0, 0, vp); } if (isMethod()) { vp->setObject(methodObject()); return pobj->methodReadBarrier(cx, *this, vp); } /* @@ -234,17 +234,17 @@ Shape::get(JSContext* cx, JSObject* obj, inline bool Shape::set(JSContext* cx, JSObject* obj, js::Value* vp) const { JS_ASSERT_IF(hasDefaultSetter(), hasGetterValue()); if (attrs & JSPROP_SETTER) { js::Value fval = setterValue(); - return js::InternalGetOrSet(cx, obj, id, fval, JSACC_WRITE, 1, vp, vp); + return js::ExternalGetOrSet(cx, obj, id, fval, JSACC_WRITE, 1, vp, vp); } if (attrs & JSPROP_GETTER) return js_ReportGetterOnlyAssignment(cx); /* See the comment in js::Shape::get as to why we check for With. */ if (obj->getClass() == &js_WithClass) obj = js_UnwrapWithObject(cx, obj);
--- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -827,18 +827,17 @@ str_resolve(JSContext *cx, JSObject *obj *objp = obj; } return JS_TRUE; } Class js_StringClass = { js_String_str, JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_NEW_RESOLVE | - JSCLASS_HAS_CACHED_PROTO(JSProto_String) | - JSCLASS_FAST_CONSTRUCTOR, + JSCLASS_HAS_CACHED_PROTO(JSProto_String), PropertyStub, /* addProperty */ PropertyStub, /* delProperty */ str_getProperty, PropertyStub, /* setProperty */ str_enumerate, (JSResolveOp)str_resolve, ConvertStub }; @@ -3259,37 +3258,37 @@ const char JSString::deflatedUnitStringT }; #undef U #undef U8 JSBool js_String(JSContext *cx, uintN argc, Value *vp) { + Value *argv = vp + 2; + JSString *str; - if (argc > 0) { - str = js_ValueToString(cx, vp[2]); + str = js_ValueToString(cx, argv[0]); if (!str) - return JS_FALSE; - vp[2].setString(str); + return false; } else { str = cx->runtime->emptyString; } - if (vp[1].isMagic(JS_FAST_CONSTRUCTOR)) { + if (IsConstructing(vp)) { JSObject *obj = NewBuiltinClassInstance(cx, &js_StringClass); if (!obj) - return JS_FALSE; + return false; obj->setPrimitiveThis(StringValue(str)); vp->setObject(*obj); } else { vp->setString(str); } - return JS_TRUE; + return true; } #ifdef JS_TRACER JSObject* FASTCALL js_String_tn(JSContext* cx, JSObject* proto, JSString* str) { JS_ASSERT(JS_ON_TRACE(cx)); @@ -3368,17 +3367,17 @@ JSObject * js_InitStringClass(JSContext *cx, JSObject *obj) { JSObject *proto; /* Define the escape, unescape functions in the global object. */ if (!JS_DefineFunctions(cx, obj, string_functions)) return NULL; - proto = js_InitClass(cx, obj, NULL, &js_StringClass, (Native) js_String, 1, + proto = js_InitClass(cx, obj, NULL, &js_StringClass, js_String, 1, NULL, string_methods, NULL, string_static_methods); if (!proto) return NULL; proto->setPrimitiveThis(StringValue(cx->runtime->emptyString)); if (!js_DefineNativeProperty(cx, proto, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), UndefinedValue(), NULL, NULL, JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0,
--- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -461,16 +461,18 @@ InitJITStatsClass(JSContext *cx, JSObjec #define INS_CONSTOBJ(obj) addName(insImmObj(obj), #obj) #define INS_CONSTFUN(fun) addName(insImmFun(fun), #fun) #define INS_CONSTSTR(str) addName(insImmStr(str), #str) #define INS_CONSTSHAPE(shape) addName(insImmShape(shape), #shape) #define INS_CONSTID(id) addName(insImmId(id), #id) #define INS_ATOM(atom) INS_CONSTSTR(ATOM_TO_STRING(atom)) #define INS_NULL() INS_CONSTPTR(NULL) #define INS_UNDEFINED() INS_CONST(0) +#define INS_MAGIC_WHY(why) INS_CONSTWORD((size_t)why) +#define INS_MAGIC_NULL() INS_NULL() static const size_t sPayloadOffset = offsetof(jsval_layout, s.payload); #if JS_BITS_PER_WORD == 32 static const size_t sTagOffset = offsetof(jsval_layout, s.tag); #endif static avmplus::AvmCore s_core = avmplus::AvmCore(); static avmplus::AvmCore* core = &s_core; @@ -4278,17 +4280,16 @@ TraceRecorder::snapshot(ExitType exitTyp exit->exitType = exitType; exit->block = fp->maybeBlockChain(); if (fp->hasBlockChain()) tree->gcthings.addUnique(ObjectValue(*fp->getBlockChain())); exit->pc = pc; exit->imacpc = fp->maybeIMacroPC(); exit->sp_adj = (stackSlots * sizeof(double)) - tree->nativeStackBase; exit->rp_adj = exit->calldepth * sizeof(FrameInfo*); - exit->nativeCalleeWord = 0; exit->lookupFlags = js_InferFlags(cx, 0); memcpy(exit->fullTypeMap(), typemap, typemap_size); #if defined JS_JIT_SPEW TreevisLogExit(cx, exit); #endif return exit; } @@ -5724,56 +5725,16 @@ SynthesizeFrame(JSContext* cx, const Fra * everything down to the caller's fp->slots (where vars start) and avoid * some of the complexity? */ return (fi.spdist - newfp->down->getFixedCount()) + ((fun->nargs > newfp->numActualArgs()) ? fun->nargs - newfp->numActualArgs() : 0) + newscript->nfixed + SPECIAL_FRAME_SLOTS; } -JS_REQUIRES_STACK static void -SynthesizeSlowNativeFrame(TracerState& state, JSContext *cx, VMSideExit *exit) -{ - /* - * StackSpace::getInlineFrame calls js_ReportOutOfScriptQuota if there is - * no space (which will try to deep bail, which is bad), however we already - * check on entry to ExecuteTree that there is enough space. - */ - StackSegment *seg; - JSStackFrame *fp; - cx->stack().getSynthesizedSlowNativeFrame(cx, seg, fp); - -#ifdef DEBUG - JSObject *callee = &state.nativeVp[0].toObject(); - JSFunction *fun = GET_FUNCTION_PRIVATE(cx, callee); - JS_ASSERT(!fun->isInterpreted() && !fun->isFastNative()); - JS_ASSERT(fun->u.n.extra == 0); -#endif - - fp->setCallObj(NULL); - fp->setArgsObj(NULL); - fp->setScript(NULL); - fp->setThisValue(state.nativeVp[1]); - fp->setNumActualArgs(state.nativeVpLen - 2); - fp->argv = state.nativeVp + 2; - fp->setFunction(GET_FUNCTION_PRIVATE(cx, fp->callee())); - fp->clearReturnValue(); - fp->setAnnotation(NULL); - fp->setScopeChain(cx->fp()->getScopeChain()); - fp->setBlockChain(NULL); - fp->flags = exit->constructing() ? JSFRAME_CONSTRUCTING : 0; - JS_ASSERT(!fp->hasIMacroPC()); - - state.bailedSlowNativeRegs.fp = fp; - state.bailedSlowNativeRegs.pc = NULL; - state.bailedSlowNativeRegs.sp = fp->slots(); - - cx->stack().pushSynthesizedSlowNativeFrame(cx, seg, state.bailedSlowNativeRegs); -} - static JS_REQUIRES_STACK bool RecordTree(JSContext* cx, TreeFragment* first, jsbytecode* outer, uint32 outerArgc, SlotList* globalSlots) { TraceMonitor* tm = &JS_TRACE_MONITOR(cx); /* Try to find an unused peer fragment, or allocate a new one. */ JS_ASSERT(first->first == first); @@ -6765,25 +6726,17 @@ LeaveTree(TraceMonitor *tm, TracerState& bool bailed = innermost->exitType == STATUS_EXIT && (bs & BUILTIN_BAILED); if (bailed) { /* * Deep-bail case. * * A _FAIL native already called LeaveTree. We already reconstructed * the interpreter stack, in pre-call state, with pc pointing to the * CALL/APPLY op, for correctness. Then we continued in native code. - * - * First, if we just returned from a slow native, pop its stack frame. */ - if (!cx->fp()->hasScript()) { - JS_ASSERT(cx->regs == &state.bailedSlowNativeRegs); - cx->stack().popSynthesizedSlowNativeFrame(cx); - } - JS_ASSERT(cx->fp()->hasScript()); - if (!(bs & (BUILTIN_ERROR | BUILTIN_NO_FIXUP_NEEDED))) { /* * The builtin or native deep-bailed but finished successfully * (no exception or error). * * After it returned, the JIT code stored the results of the * builtin or native at the top of the native stack and then * immediately flunked the guard on state->builtinStatus. @@ -6995,19 +6948,16 @@ LeaveTree(TraceMonitor *tm, TracerState& #ifdef DEBUG int slots = #endif FlushNativeStackFrame(cx, innermost->calldepth, innermost->stackTypeMap(), stack, NULL); JS_ASSERT(unsigned(slots) == innermost->numStackSlots); - if (innermost->nativeCalleeWord) - SynthesizeSlowNativeFrame(state, cx, innermost); - /* Write back interned globals. */ JS_ASSERT(state.eos == state.stackBase + MAX_NATIVE_STACK_SLOTS); JSObject* globalObj = outermostTree->globalObj; FlushNativeGlobalFrame(cx, globalObj, state.eos, ngslots, gslots, globalTypeMap); #ifdef DEBUG /* Verify that our state restoration worked. */ for (JSStackFrame* fp = cx->fp(); fp; fp = fp->down) { JS_ASSERT_IF(fp->argv, fp->argv[-1].isObjectOrNull()); @@ -9788,17 +9738,17 @@ inline nanojit::LIns* TraceRecorder::unbox_non_double_object(LIns* v_ins, JSValueType type, VMSideExit* exit) { JS_ASSERT(type <= JSVAL_UPPER_INCL_TYPE_OF_VALUE_SET); LIns *unboxed_ins; if (type == JSVAL_TYPE_UNDEFINED) { unboxed_ins = INS_UNDEFINED(); } else if (type == JSVAL_TYPE_NULL) { unboxed_ins = INS_NULL(); - } else if (type >= JSVAL_LOWER_INCL_TYPE_OF_GCTHING_SET) { + } else if (type >= JSVAL_LOWER_INCL_TYPE_OF_PTR_PAYLOAD_SET) { unboxed_ins = unpack_ptr(v_ins); } else { JS_ASSERT(type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN || type == JSVAL_TYPE_MAGIC); unboxed_ins = lir->ins1(LIR_q2i, v_ins); } guard(true, non_double_object_value_has_type(v_ins, type), exit); return unboxed_ins; @@ -9884,17 +9834,17 @@ TraceRecorder::box_value_for_native_call return INS_CONSTQWORD(JSVAL_BITS(JSVAL_NULL)); if (v.isUndefined()) return INS_CONSTQWORD(JSVAL_BITS(JSVAL_VOID)); JSValueTag tag = v.isObject() ? JSVAL_TAG_OBJECT : v.extractNonDoubleObjectTraceTag(); uint64 shiftedTag = ((uint64)tag) << JSVAL_TAG_SHIFT; LIns *shiftedTag_ins = INS_CONSTQWORD(shiftedTag); - if (v.isGCThing()) + if (v.hasPtrPayload()) return lir->ins2(LIR_orq, v_ins, shiftedTag_ins); return lir->ins2(LIR_orq, lir->ins1(LIR_ui2uq, v_ins), shiftedTag_ins); } void TraceRecorder::box_value_into(const Value &v, LIns *v_ins, LIns *dstaddr_ins, ptrdiff_t offset, AccSet accSet) { @@ -11005,32 +10955,23 @@ TraceRecorder::emitNativePropertyOp(cons (int) offsetof(TracerState, builtinStatus), ACCSET_OTHER); propagateFailureToBuiltinStatus(ok_ins, status_ins); guard(true, lir->insEqI_0(status_ins), STATUS_EXIT); } JS_REQUIRES_STACK RecordingStatus TraceRecorder::emitNativeCall(JSSpecializedNative* sn, uintN argc, LIns* args[], bool rooted) { - bool constructing = !!(sn->flags & JSTN_CONSTRUCTOR); - if (JSTN_ERRTYPE(sn) == FAIL_STATUS) { // This needs to capture the pre-call state of the stack. So do not set // pendingSpecializedNative before taking this snapshot. JS_ASSERT(!pendingSpecializedNative); // Take snapshot for DeepBail and store it in cx->bailExit. - // If we are calling a slow native, add information to the side exit - // for SynthesizeSlowNativeFrame. - VMSideExit* exit = enterDeepBailCall(); - JSObject* funobj = &stackval(0 - (2 + argc)).toObject(); - if (FUN_SLOW_NATIVE(GET_FUNCTION_PRIVATE(cx, funobj))) { - exit->setNativeCallee(funobj, constructing); - tree->gcthings.addUnique(ObjectValue(*funobj)); - } + enterDeepBailCall(); } LIns* res_ins = lir->insCall(sn->builtin, args); // Immediately unroot the vp as soon we return since we might deep bail next. if (rooted) lir->insStore(INS_NULL(), lirbuf->state, offsetof(TracerState, nativeVp), ACCSET_OTHER); @@ -11179,38 +11120,38 @@ TraceRecorder::callNative(uintN argc, JS { LIns* args[5]; JS_ASSERT(mode == JSOP_CALL || mode == JSOP_NEW || mode == JSOP_APPLY); Value* vp = &stackval(0 - (2 + argc)); JSObject* funobj = &vp[0].toObject(); JSFunction* fun = GET_FUNCTION_PRIVATE(cx, funobj); - FastNative native = (FastNative)fun->u.n.native; + Native native = fun->u.n.native; switch (argc) { case 1: if (vp[2].isNumber() && mode == JSOP_CALL) { if (native == js_math_ceil || native == js_math_floor || native == js_math_round) { LIns* a = get(&vp[2]); if (isPromote(a)) { set(&vp[0], a); pendingSpecializedNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK; return RECORD_CONTINUE; } } if (vp[1].isString()) { JSString *str = vp[1].toString(); - if (native == (FastNative)js_str_charAt) { + if (native == js_str_charAt) { LIns* str_ins = get(&vp[1]); LIns* idx_ins = get(&vp[2]); set(&vp[0], getCharAt(str, str_ins, idx_ins, mode)); pendingSpecializedNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK; return RECORD_CONTINUE; - } else if (native == (FastNative)js_str_charCodeAt) { + } else if (native == js_str_charCodeAt) { jsdouble i = vp[2].toNumber(); if (i < 0 || i >= str->length()) RETURN_STOP("charCodeAt out of bounds"); LIns* str_ins = get(&vp[1]); LIns* idx_ins = get(&vp[2]); set(&vp[0], getCharCodeAt(str, str_ins, idx_ins)); pendingSpecializedNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK; return RECORD_CONTINUE; @@ -11237,36 +11178,31 @@ TraceRecorder::callNative(uintN argc, JS return RECORD_CONTINUE; } } break; } if (fun->flags & JSFUN_TRCINFO) { JSNativeTraceInfo *trcinfo = FUN_TRCINFO(fun); - JS_ASSERT(trcinfo && (JSFastNative)fun->u.n.native == trcinfo->native); + JS_ASSERT(trcinfo && fun->u.n.native == trcinfo->native); /* Try to call a type specialized version of the native. */ if (trcinfo->specializations) { RecordingStatus status = callSpecializedNative(trcinfo, argc, mode == JSOP_NEW); if (status != RECORD_STOP) return status; } } if (native == js_fun_apply || native == js_fun_call) RETURN_STOP("trying to call native apply or call"); - if (fun->u.n.extra > 0) - RETURN_STOP("trying to trace slow native with fun->u.n.extra > 0"); - // Allocate the vp vector and emit code to root it. - uintN vplen = 2 + JS_MAX(argc, unsigned(FUN_MINARGS(fun))); - if (!(fun->flags & JSFUN_FAST_NATIVE)) - vplen++; // slow native return value slot + uintN vplen = 2 + argc; LIns* invokevp_ins = lir->insAlloc(vplen * sizeof(Value)); // vp[0] is the callee. box_value_into(vp[0], INS_CONSTOBJ(funobj), invokevp_ins, 0, ACCSET_OTHER); // Calculate |this|. LIns* this_ins; if (mode == JSOP_NEW) { @@ -11280,68 +11216,43 @@ TraceRecorder::callNative(uintN argc, JS // sized JSObject, not a Function-sized one. (The Function ctor would // deep-bail anyway but let's not go there.) if (clasp == &js_FunctionClass) RETURN_STOP("new Function"); if (!clasp->isNative()) RETURN_STOP("new with non-native ops"); - if (fun->isFastConstructor()) { - vp[1].setMagic(JS_FAST_CONSTRUCTOR); - newobj_ins = INS_CONST(JS_FAST_CONSTRUCTOR); + if (fun->isConstructor()) { + vp[1].setMagicWithObjectOrNullPayload(NULL); + newobj_ins = INS_MAGIC_NULL(); /* Treat this as a regular call, the constructor will behave correctly. */ mode = JSOP_CALL; } else { args[0] = INS_CONSTOBJ(funobj); args[1] = INS_CONSTPTR(clasp); args[2] = cx_ins; - newobj_ins = lir->insCall(&js_NewInstance_ci, args); + newobj_ins = lir->insCall(&js_NewInstanceFromTrace_ci, args); guard(false, lir->insEqP_0(newobj_ins), OOM_EXIT); /* * emitNativeCall may take a snapshot below. To avoid having a type * mismatch (e.g., where get(&vp[1]) is an object and vp[1] is * null), we make sure vp[1] is some object. The actual object * doesn't matter; JSOP_NEW and InvokeConstructor both overwrite * vp[1] without observing its value. * * N.B. tracing specializes for functions, so pick a non-function. */ vp[1].setObject(*globalObj); } this_ins = newobj_ins; } else { this_ins = get(&vp[1]); - - /* - * For fast natives, 'null' or primitives are fine as as 'this' value. - * For slow natives we have to ensure the object is substituted for the - * appropriate global object or boxed object value. JSOP_NEW allocates its - * own object so it's guaranteed to have a valid 'this' value. - */ - if (!(fun->flags & JSFUN_FAST_NATIVE)) { - if (vp[1].isNull()) { - JSObject* thisObj = ComputeThisFromVp(cx, vp); - if (!thisObj) - RETURN_ERROR("error in js_ComputeGlobalThis"); - this_ins = INS_CONSTOBJ(thisObj); - } else if (!vp[1].isObject()) { - RETURN_STOP("slow native(primitive, args)"); - } else { - if (vp[1].toObject().hasClass(&js_WithClass)) - RETURN_STOP("can't trace slow native invocation on With object"); - guardNotClass(this_ins, &js_WithClass, snapshot(MISMATCH_EXIT), LOAD_CONST); - - this_ins = lir->insChoose(lir->insEqP_0(stobj_get_parent(this_ins)), - INS_CONSTOBJ(globalObj), - this_ins, avmplus::AvmCore::use_cmov()); - } - } } set(&vp[1], this_ins); box_value_into(vp[1], this_ins, invokevp_ins, 1 * sizeof(Value), ACCSET_OTHER); // Populate argv. for (uintN n = 2; n < 2 + argc; n++) { box_value_into(vp[n], get(&vp[n]), invokevp_ins, n * sizeof(Value), ACCSET_OTHER); // For a very long argument list we might run out of LIR space, so @@ -11355,36 +11266,23 @@ TraceRecorder::callNative(uintN argc, JS for (uintN n = 2 + argc; n < vplen; n++) { box_undefined_into(invokevp_ins, n * sizeof(Value), ACCSET_OTHER); if (outOfMemory()) RETURN_STOP("out of memory in extra slots"); } } // Set up arguments for the JSNative or JSFastNative. - uint32 typesig; - if (fun->flags & JSFUN_FAST_NATIVE) { - if (mode == JSOP_NEW && !(fun->flags & JSFUN_FAST_NATIVE_CTOR)) - RETURN_STOP("untraceable fast native constructor"); - native_rval_ins = invokevp_ins; - args[0] = invokevp_ins; - args[1] = lir->insImmI(argc); - args[2] = cx_ins; - typesig = CallInfo::typeSig3(ARGTYPE_I, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P); - } else { - int32_t offset = (vplen - 1) * sizeof(Value); - native_rval_ins = lir->ins2(LIR_addp, invokevp_ins, INS_CONSTWORD(offset)); - args[0] = native_rval_ins; - args[1] = lir->ins2(LIR_addp, invokevp_ins, INS_CONSTWORD(2 * sizeof(Value))); - args[2] = lir->insImmI(argc); - args[3] = this_ins; - args[4] = cx_ins; - typesig = CallInfo::typeSig5(ARGTYPE_I, - ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P, ARGTYPE_P); - } + if (mode == JSOP_NEW) + RETURN_STOP("untraceable fast native constructor"); + native_rval_ins = invokevp_ins; + args[0] = invokevp_ins; + args[1] = lir->insImmI(argc); + args[2] = cx_ins; + uint32 typesig = CallInfo::typeSig3(ARGTYPE_I, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P); // Generate CallInfo and a JSSpecializedNative structure on the fly. // Do not use JSTN_UNBOX_AFTER for mode JSOP_NEW because // record_NativeCallComplete unboxes the result specially. CallInfo* ci = new (traceAlloc()) CallInfo(); ci->_address = uintptr_t(fun->u.n.native); ci->_isPure = 0; @@ -11456,24 +11354,24 @@ TraceRecorder::functionCall(uintN argc, guard(false, lir->insEqI_0(call_ins), MISMATCH_EXIT); } } #endif if (FUN_INTERPRETED(fun)) { if (mode == JSOP_NEW) { LIns* args[] = { get(&fval), INS_CONSTPTR(&js_ObjectClass), cx_ins }; - LIns* tv_ins = lir->insCall(&js_NewInstance_ci, args); + LIns* tv_ins = lir->insCall(&js_NewInstanceFromTrace_ci, args); guard(false, lir->insEqP_0(tv_ins), OOM_EXIT); set(&tval, tv_ins); } return interpretedFunctionCall(fval, fun, argc, mode == JSOP_NEW); } - FastNative native = FUN_FAST_NATIVE(fun); + Native native = fun->maybeNative(); Value* argv = &tval + 1; if (native == js_Array) return newArray(&fval.toObject(), argc, argv, &fval); if (native == js_String && argc == 1) { if (mode == JSOP_NEW) return newString(&fval.toObject(), 1, argv, &fval); if (!argv[0].isPrimitive()) { CHECK_STATUS(guardNativeConversion(argv[0])); @@ -13314,18 +13212,18 @@ TraceRecorder::record_JSOP_APPLY() return record_JSOP_CALL(); RETURN_IF_XML_A(vp[0]); JSObject* obj = &vp[0].toObject(); JSFunction* fun = GET_FUNCTION_PRIVATE(cx, obj); if (FUN_INTERPRETED(fun)) return record_JSOP_CALL(); - bool apply = (FastNative)fun->u.n.native == js_fun_apply; - if (!apply && (FastNative)fun->u.n.native != js_fun_call) + bool apply = fun->u.n.native == js_fun_apply; + if (!apply && fun->u.n.native != js_fun_call) return record_JSOP_CALL(); /* * We don't trace apply and call with a primitive 'this', which is the * first positional parameter. */ if (argc > 0 && !vp[2].isObject()) return record_JSOP_CALL(); @@ -14343,18 +14241,18 @@ TraceRecorder::record_JSOP_ENDITER() return ARECORD_CONTINUE; } #if JS_BITS_PER_WORD == 32 JS_REQUIRES_STACK void TraceRecorder::storeMagic(JSWhyMagic why, nanojit::LIns *addr_ins, ptrdiff_t offset, AccSet accSet) { - lir->insStore(INS_CONSTU(why), addr_ins, offset + sPayloadOffset, accSet); - lir->insStore(INS_CONSTU(JSVAL_TAG_MAGIC), addr_ins, offset + sTagOffset, accSet); + lir->insStore(INS_MAGIC_WHY(why), addr_ins, offset + sPayloadOffset, accSet); + lir->insStore(INS_MAGIC_WHY(JSVAL_TAG_MAGIC), addr_ins, offset + sTagOffset, accSet); } #elif JS_BITS_PER_WORD == 64 JS_REQUIRES_STACK void TraceRecorder::storeMagic(JSWhyMagic why, nanojit::LIns *addr_ins, ptrdiff_t offset, AccSet accSet) { LIns *magic = INS_CONSTQWORD(BUILD_JSVAL(JSVAL_TAG_MAGIC, why)); lir->insStore(magic, addr_ins, offset, accSet); } @@ -14951,21 +14849,21 @@ TraceRecorder::record_JSOP_LAMBDA() * Note that we have not yet pushed obj as the final argument, * so regs.sp[1 - (iargc + 2)], and not regs.sp[-(iargc + 2)], * is the callee for this JSOP_CALL. */ const Value &cref = cx->regs->sp[1 - (iargc + 2)]; JSObject *callee; if (IsFunctionObject(cref, &callee)) { - JSFunction *calleeFun = GET_FUNCTION_PRIVATE(cx, callee); - FastNative fastNative = FUN_FAST_NATIVE(calleeFun); - - if ((iargc == 1 && fastNative == array_sort) || - (iargc == 2 && fastNative == str_replace)) { + JSFunction *calleeFun = callee->getFunctionPrivate(); + Native native = calleeFun->maybeNative(); + + if ((iargc == 1 && native == array_sort) || + (iargc == 2 && native == str_replace)) { stack(0, INS_CONSTOBJ(FUN_OBJECT(fun))); return ARECORD_CONTINUE; } } } else if (op2 == JSOP_NULL) { pc2 += JSOP_NULL_LENGTH; op2 = JSOp(*pc2); @@ -15857,17 +15755,17 @@ TraceRecorder::record_JSOP_NEWARRAY() stack(-int(len), v_ins); return ARECORD_CONTINUE; } JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_HOLE() { - stack(0, INS_CONST(JS_ARRAY_HOLE)); + stack(0, INS_MAGIC_WHY(JS_ARRAY_HOLE)); return ARECORD_CONTINUE; } AbortableRecordingStatus TraceRecorder::record_JSOP_TRACE() { return ARECORD_CONTINUE; }
--- a/js/src/jstracer.h +++ b/js/src/jstracer.h @@ -409,34 +409,16 @@ struct VMSideExit : public nanojit::Side int32_t calldepth; uint32 numGlobalSlots; uint32 numStackSlots; uint32 numStackSlotsBelowCurrentFrame; ExitType exitType; uintN lookupFlags; unsigned hitcount; - /* - * Ordinarily 0. If a slow native function is atop the stack, the 1 bit is - * set if constructing and the other bits are a pointer to the funobj. - */ - uintptr_t nativeCalleeWord; - - JSObject * nativeCallee() { - return (JSObject *) (nativeCalleeWord & ~1); - } - - bool constructing() { - return bool(nativeCalleeWord & 1); - } - - void setNativeCallee(JSObject *callee, bool constructing) { - nativeCalleeWord = uintptr_t(callee) | (constructing ? 1 : 0); - } - inline JSValueType* stackTypeMap() { return (JSValueType*)(this + 1); } inline JSValueType& stackType(unsigned i) { JS_ASSERT(i < numStackSlots); return stackTypeMap()[i]; }
--- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -97,39 +97,29 @@ ArrayBuffer::class_finalize(JSContext *c abuf->freeStorage(cx); delete abuf; } /* * new ArrayBuffer(byteLength) */ JSBool -ArrayBuffer::class_constructor(JSContext *cx, JSObject *obj, - uintN argc, Value *argv, Value *rval) +ArrayBuffer::class_constructor(JSContext *cx, uintN argc, Value *vp) { - if (!JS_IsConstructing(cx)) { - obj = NewBuiltinClassInstance(cx, &ArrayBuffer::jsclass); - if (!obj) - return false; - rval->setObject(*obj); - } - - return create(cx, obj, argc, argv, rval); + return create(cx, argc, JS_ARGV(cx, vp), vp); } bool -ArrayBuffer::create(JSContext *cx, JSObject *obj, - uintN argc, Value *argv, Value *rval) +ArrayBuffer::create(JSContext *cx, uintN argc, Value *argv, Value *rval) { - if (!obj) { - obj = NewBuiltinClassInstance(cx, &ArrayBuffer::jsclass); - if (!obj) - return false; - rval->setObject(*obj); - } + /* N.B. there may not be an argv[-2]/argv[-1]. */ + + JSObject *obj = NewBuiltinClassInstance(cx, &ArrayBuffer::jsclass); + if (!obj) + return false; int32_t nbytes = 0; if (argc > 0) { if (!ValueToECMAInt32(cx, argv[0], &nbytes)) return false; } if (nbytes < 0) { @@ -150,16 +140,17 @@ ArrayBuffer::create(JSContext *cx, JSObj } if (!abuf->allocateStorage(cx, nbytes)) { delete abuf; return false; } obj->setPrivate(abuf); + rval->setObject(*obj); return true; } bool ArrayBuffer::allocateStorage(JSContext *cx, uint32 nbytes) { JS_ASSERT(data == 0); @@ -708,42 +699,30 @@ class TypedArrayTemplate /* * new [Type]Array(length) * new [Type]Array(otherTypedArray) * new [Type]Array(JSArray) * new [Type]Array(ArrayBuffer, [optional] byteOffset, [optional] length) */ static JSBool - class_constructor(JSContext *cx, JSObject *obj, - uintN argc, Value *argv, Value *rval) + class_constructor(JSContext *cx, uintN argc, Value *vp) { - // - // Note: this is a constructor for slowClass, not fastClass! - // - - if (!JS_IsConstructing(cx)) { - obj = NewBuiltinClassInstance(cx, slowClass()); - if (!obj) - return false; - rval->setObject(*obj); - } - - return create(cx, obj, argc, argv, rval); + /* N.B. this is a constructor for slowClass, not fastClass! */ + return create(cx, argc, JS_ARGV(cx, vp), vp); } - static bool - create(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) + static JSBool + create(JSContext *cx, uintN argc, Value *argv, Value *rval) { - if (!obj) { - obj = NewBuiltinClassInstance(cx, slowClass()); - if (!obj) - return false; - rval->setObject(*obj); - } + /* N.B. there may not be an argv[-2]/argv[-1]. */ + + JSObject *obj = NewBuiltinClassInstance(cx, slowClass()); + if (!obj) + return false; ThisTypeArray *tarray = 0; // figure out the type of the first argument; // no args is treated like an int arg of 0. if (argc == 0 || argv[0].isInt32()) { int32 len = 0; @@ -802,16 +781,17 @@ class TypedArrayTemplate } } else { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TYPED_ARRAY_BAD_ARGS); return false; } makeFastWithPrivate(cx, obj, tarray); + rval->setObject(*obj); return true; } static void class_finalize(JSContext *cx, JSObject *obj) { ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj); delete tarray; @@ -1336,22 +1316,21 @@ class TypedArrayTemplate length = count; return true; } bool createBufferWithByteLength(JSContext *cx, int32 bytes) { - Value argv = Int32Value(bytes); - AutoValueRooter tvr(cx); - if (!ArrayBuffer::create(cx, NULL, 1, &argv, tvr.addr())) + Value arg = Int32Value(bytes), rval; + if (!ArrayBuffer::create(cx, 1, &arg, &rval)) return false; - JSObject *obj = &tvr.value().toObject(); + JSObject *obj = &rval.toObject(); bufferJS = obj; buffer = ArrayBuffer::fromJSObject(obj); byteOffset = 0; byteLength = bytes; data = buffer->data; @@ -1631,57 +1610,52 @@ js_IsTypedArray(JSObject *obj) Class *clasp = obj->getClass(); return clasp >= &TypedArray::fastClasses[0] && clasp < &TypedArray::fastClasses[TypedArray::TYPE_MAX]; } JS_FRIEND_API(JSObject *) js_CreateArrayBuffer(JSContext *cx, jsuint nbytes) { - Value vals[2]; - vals[0].setNumber(nbytes); - vals[1].setUndefined(); - - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals); - if (!ArrayBuffer::create(cx, NULL, 1, &vals[0], &vals[1])) + Value arg = NumberValue(nbytes), rval; + if (!ArrayBuffer::create(cx, 1, &arg, &rval)) return NULL; - - return &vals[1].toObject(); + return &rval.toObject(); } static inline JSBool TypedArrayConstruct(JSContext *cx, jsint atype, uintN argc, Value *argv, Value *rv) { switch (atype) { case TypedArray::TYPE_INT8: - return !!Int8Array::create(cx, NULL, argc, argv, rv); + return Int8Array::create(cx, argc, argv, rv); case TypedArray::TYPE_UINT8: - return !!Uint8Array::create(cx, NULL, argc, argv, rv); + return Uint8Array::create(cx, argc, argv, rv); case TypedArray::TYPE_INT16: - return !!Int16Array::create(cx, NULL, argc, argv, rv); + return Int16Array::create(cx, argc, argv, rv); case TypedArray::TYPE_UINT16: - return !!Uint16Array::create(cx, NULL, argc, argv, rv); + return Uint16Array::create(cx, argc, argv, rv); case TypedArray::TYPE_INT32: - return !!Int32Array::create(cx, NULL, argc, argv, rv); + return Int32Array::create(cx, argc, argv, rv); case TypedArray::TYPE_UINT32: - return !!Uint32Array::create(cx, NULL, argc, argv, rv); + return Uint32Array::create(cx, argc, argv, rv); case TypedArray::TYPE_FLOAT32: - return !!Float32Array::create(cx, NULL, argc, argv, rv); + return Float32Array::create(cx, argc, argv, rv); case TypedArray::TYPE_FLOAT64: - return !!Float64Array::create(cx, NULL, argc, argv, rv); + return Float64Array::create(cx, argc, argv, rv); case TypedArray::TYPE_UINT8_CLAMPED: - return !!Uint8ClampedArray::create(cx, NULL, argc, argv, rv); + return Uint8ClampedArray::create(cx, argc, argv, rv); default: JS_NOT_REACHED("shouldn't have gotten here"); return false; } } JS_FRIEND_API(JSObject *)
--- a/js/src/jstypedarray.h +++ b/js/src/jstypedarray.h @@ -57,21 +57,19 @@ namespace js { */ struct JS_FRIEND_API(ArrayBuffer) { static Class jsclass; static JSPropertySpec jsprops[]; static JSBool prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp); static void class_finalize(JSContext *cx, JSObject *obj); - static JSBool class_constructor(JSContext *cx, JSObject *obj, uintN argc, Value *argv, - Value *rval); + static JSBool class_constructor(JSContext *cx, uintN argc, Value *vp); - static bool create(JSContext *cx, JSObject *obj, uintN argc, - Value *argv, Value *rval); + static bool create(JSContext *cx, uintN argc, Value *argv, Value *rval); static ArrayBuffer *fromJSObject(JSObject *obj); ArrayBuffer() : data(0), byteLength() { }
--- a/js/src/jsval.h +++ b/js/src/jsval.h @@ -217,17 +217,17 @@ typedef uint64 JSValueShiftedTag; #define JSVAL_SHIFTED_TAG_OBJECT (((uint64)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT) #endif /* JS_BITS_PER_WORD */ #endif /* defined(__cplusplus) && !defined(__SUNPRO_CC) */ #define JSVAL_LOWER_INCL_TYPE_OF_OBJ_OR_NULL_SET JSVAL_TYPE_NULL #define JSVAL_UPPER_EXCL_TYPE_OF_PRIMITIVE_SET JSVAL_TYPE_OBJECT #define JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET JSVAL_TYPE_INT32 -#define JSVAL_LOWER_INCL_TYPE_OF_GCTHING_SET JSVAL_TYPE_STRING +#define JSVAL_LOWER_INCL_TYPE_OF_PTR_PAYLOAD_SET JSVAL_TYPE_MAGIC #define JSVAL_UPPER_INCL_TYPE_OF_VALUE_SET JSVAL_TYPE_OBJECT #define JSVAL_UPPER_INCL_TYPE_OF_BOXABLE_SET JSVAL_TYPE_FUNOBJ #if JS_BITS_PER_WORD == 32 #define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_CLEAR | (type))) #define JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET JSVAL_TAG_NULL @@ -240,30 +240,30 @@ typedef uint64 JSValueShiftedTag; #define JSVAL_PAYLOAD_MASK 0x00007FFFFFFFFFFFLL #define JSVAL_TAG_MASK 0xFFFF800000000000LL #define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_MAX_DOUBLE | (type))) #define JSVAL_TYPE_TO_SHIFTED_TAG(type) (((uint64)JSVAL_TYPE_TO_TAG(type)) << JSVAL_TAG_SHIFT) #define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET JSVAL_SHIFTED_TAG_NULL #define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET JSVAL_SHIFTED_TAG_OBJECT #define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET JSVAL_SHIFTED_TAG_UNDEFINED +#define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_PTR_PAYLOAD_SET JSVAL_SHIFTED_TAG_MAGIC #define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET JSVAL_SHIFTED_TAG_STRING #endif /* JS_BITS_PER_WORD */ typedef enum JSWhyMagic { JS_ARRAY_HOLE, /* a hole in a dense array */ JS_ARGS_HOLE, /* a hole in the args object's array */ JS_NATIVE_ENUMERATE, /* indicates that a custom enumerate hook forwarded * to js_Enumerate, which really means the object can be * enumerated like a native object. */ JS_NO_ITER_VALUE, /* there is not a pending iterator value */ JS_GENERATOR_CLOSING, /* exception value thrown when closing a generator */ - JS_FAST_CONSTRUCTOR, /* 'this' value for fast natives invoked with 'new' */ JS_NO_CONSTANT, /* compiler sentinel value */ JS_THIS_POISON, /* used in debug builds to catch tracing errors */ JS_SERIALIZE_NO_NODE, /* an empty subnode in the AST serializer */ JS_GENERIC_MAGIC /* for local use */ } JSWhyMagic; typedef struct JSString JSString; typedef struct JSObject JSObject; @@ -429,16 +429,29 @@ BOOLEAN_TO_JSVAL_IMPL(JSBool b) { jsval_layout l; l.s.tag = JSVAL_TAG_BOOLEAN; l.s.payload.boo = b; return l; } static JS_ALWAYS_INLINE JSBool +JSVAL_IS_MAGIC_IMPL(jsval_layout l) +{ + return l.s.tag == JSVAL_TAG_MAGIC; +} + +static JS_ALWAYS_INLINE JSObject * +MAGIC_JSVAL_TO_OBJECT_OR_NULL_IMPL(jsval_layout l) +{ + JS_ASSERT(JSVAL_IS_MAGIC_IMPL(l)); + return l.s.payload.obj; +} + +static JS_ALWAYS_INLINE JSBool JSVAL_IS_OBJECT_IMPL(jsval_layout l) { return l.s.tag == JSVAL_TAG_OBJECT; } static JS_ALWAYS_INLINE JSBool JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l) { @@ -457,16 +470,17 @@ JSVAL_TO_OBJECT_IMPL(jsval_layout l) { return l.s.payload.obj; } static JS_ALWAYS_INLINE jsval_layout OBJECT_TO_JSVAL_IMPL(JSObject *obj) { jsval_layout l; + JS_ASSERT(obj); l.s.tag = JSVAL_TAG_OBJECT; l.s.payload.obj = obj; return l; } static JS_ALWAYS_INLINE JSBool JSVAL_IS_NULL_IMPL(jsval_layout l) { @@ -605,16 +619,31 @@ static JS_ALWAYS_INLINE jsval_layout BOOLEAN_TO_JSVAL_IMPL(JSBool b) { jsval_layout l; l.asBits = ((uint64)(uint32)b) | JSVAL_SHIFTED_TAG_BOOLEAN; return l; } static JS_ALWAYS_INLINE JSBool +JSVAL_IS_MAGIC_IMPL(jsval_layout l) +{ + return (l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_MAGIC; +} + +static JS_ALWAYS_INLINE JSObject * +MAGIC_JSVAL_TO_OBJECT_OR_NULL_IMPL(jsval_layout l) +{ + JS_ASSERT(JSVAL_IS_MAGIC_IMPL(l)); + uint64 ptrBits = l.asBits & JSVAL_PAYLOAD_MASK; + JS_ASSERT((ptrBits >> JSVAL_TAG_SHIFT) == 0); + return (JSObject *)ptrBits; +} + +static JS_ALWAYS_INLINE JSBool JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l) { return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET; } static JS_ALWAYS_INLINE JSBool JSVAL_IS_OBJECT_IMPL(jsval_layout l) { @@ -636,16 +665,17 @@ JSVAL_TO_OBJECT_IMPL(jsval_layout l) JS_ASSERT((ptrBits & 0x7) == 0); return (JSObject *)ptrBits; } static JS_ALWAYS_INLINE jsval_layout OBJECT_TO_JSVAL_IMPL(JSObject *obj) { jsval_layout l; + JS_ASSERT(obj); uint64 objBits = (uint64)obj; JS_ASSERT((objBits >> JSVAL_TAG_SHIFT) == 0); l.asBits = objBits | JSVAL_SHIFTED_TAG_OBJECT; return l; } static JS_ALWAYS_INLINE JSBool JSVAL_IS_NULL_IMPL(jsval_layout l)
--- a/js/src/jsvalue.h +++ b/js/src/jsvalue.h @@ -130,31 +130,34 @@ JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layou } static JS_ALWAYS_INLINE JSBool JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, JSBool b) { return (l.s.tag == JSVAL_TAG_BOOLEAN) && (l.s.payload.boo == b); } -static JS_ALWAYS_INLINE JSBool -JSVAL_IS_MAGIC_IMPL(jsval_layout l) -{ - return l.s.tag == JSVAL_TAG_MAGIC; -} - static JS_ALWAYS_INLINE jsval_layout MAGIC_TO_JSVAL_IMPL(JSWhyMagic why) { jsval_layout l; l.s.tag = JSVAL_TAG_MAGIC; l.s.payload.why = why; return l; } +static JS_ALWAYS_INLINE jsval_layout +MAGIC_TO_JSVAL_IMPL(JSObject *obj) +{ + jsval_layout l; + l.s.tag = JSVAL_TAG_MAGIC; + l.s.payload.obj = obj; + return l; +} + static JS_ALWAYS_INLINE JSBool JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs) { JSValueTag ltag = lhs.s.tag, rtag = rhs.s.tag; return ltag == rtag || (ltag < JSVAL_TAG_CLEAR && rtag < JSVAL_TAG_CLEAR); } static JS_ALWAYS_INLINE jsval_layout @@ -220,30 +223,32 @@ JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layou } static JS_ALWAYS_INLINE JSBool JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, JSBool b) { return l.asBits == (((uint64)(uint32)b) | JSVAL_SHIFTED_TAG_BOOLEAN); } -static JS_ALWAYS_INLINE JSBool -JSVAL_IS_MAGIC_IMPL(jsval_layout l) -{ - return (l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_MAGIC; -} - static JS_ALWAYS_INLINE jsval_layout MAGIC_TO_JSVAL_IMPL(JSWhyMagic why) { jsval_layout l; l.asBits = ((uint64)(uint32)why) | JSVAL_SHIFTED_TAG_MAGIC; return l; } +static JS_ALWAYS_INLINE jsval_layout +MAGIC_TO_JSVAL_IMPL(JSObject *obj) +{ + jsval_layout l; + l.asBits = ((uint64)obj) | JSVAL_SHIFTED_TAG_MAGIC; + return l; +} + static JS_ALWAYS_INLINE JSBool JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs) { uint64 lbits = lhs.asBits, rbits = rhs.asBits; return (lbits <= JSVAL_TAG_MAX_DOUBLE && rbits <= JSVAL_TAG_MAX_DOUBLE) || (((lbits ^ rbits) & 0xFFFF800000000000LL) == 0); } @@ -286,17 +291,17 @@ JS_STATIC_ASSERT((JSVAL_TYPE_FUNOBJ & 0x #endif static JS_ALWAYS_INLINE jsval_layout BOX_NON_DOUBLE_JSVAL(JSValueType type, uint64 *slot) { /* N.B. for 32-bit payloads, the high 32 bits of the slot are trash. */ jsval_layout l; JS_ASSERT(type > JSVAL_TYPE_DOUBLE && type <= JSVAL_UPPER_INCL_TYPE_OF_BOXABLE_SET); - uint32 isI32 = (uint32)(type < JSVAL_LOWER_INCL_TYPE_OF_GCTHING_SET); + uint32 isI32 = (uint32)(type < JSVAL_LOWER_INCL_TYPE_OF_PTR_PAYLOAD_SET); uint32 shift = isI32 * 32; uint64 mask = ((uint64)-1) >> shift; uint64 payload = *slot & mask; l.asBits = payload | JSVAL_TYPE_TO_SHIFTED_TAG(type & 0xF); return l; } static JS_ALWAYS_INLINE void @@ -317,60 +322,80 @@ class Value public: /* * N.B. the default constructor leaves Value unitialized. Adding a default * constructor prevents Value from being stored in a union. */ /*** Mutatators ***/ + JS_ALWAYS_INLINE void setNull() { data.asBits = JSVAL_BITS(JSVAL_NULL); } + JS_ALWAYS_INLINE void setUndefined() { data.asBits = JSVAL_BITS(JSVAL_VOID); } + JS_ALWAYS_INLINE void setInt32(int32 i) { data = INT32_TO_JSVAL_IMPL(i); } + JS_ALWAYS_INLINE int32 &getInt32Ref() { JS_ASSERT(isInt32()); return data.s.payload.i32; } + JS_ALWAYS_INLINE void setDouble(double d) { data = DOUBLE_TO_JSVAL_IMPL(d); } + JS_ALWAYS_INLINE double &getDoubleRef() { JS_ASSERT(isDouble()); return data.asDouble; } + JS_ALWAYS_INLINE void setString(JSString *str) { data = STRING_TO_JSVAL_IMPL(str); } + JS_ALWAYS_INLINE void setObject(JSObject &obj) { JS_ASSERT(&obj != NULL); data = OBJECT_TO_JSVAL_IMPL(&obj); } + JS_ALWAYS_INLINE void setBoolean(bool b) { data = BOOLEAN_TO_JSVAL_IMPL(b); } + JS_ALWAYS_INLINE void setMagic(JSWhyMagic why) { data = MAGIC_TO_JSVAL_IMPL(why); } JS_ALWAYS_INLINE + void setMagicWithObjectOrNullPayload(JSObject *obj) { + data = MAGIC_TO_JSVAL_IMPL(obj); + } + + JS_ALWAYS_INLINE + JSObject *getMagicObjectOrNullPayload() const { + return MAGIC_JSVAL_TO_OBJECT_OR_NULL_IMPL(data); + } + + JS_ALWAYS_INLINE void setNumber(uint32 ui) { if (ui > JSVAL_INT_MAX) setDouble((double)ui); else setInt32((int32)ui); } JS_ALWAYS_INLINE @@ -393,238 +418,290 @@ class Value JS_ALWAYS_INLINE void setObjectOrUndefined(JSObject *arg) { if (arg) setObject(*arg); else setUndefined(); } + JS_ALWAYS_INLINE void swap(Value &rhs) { uint64 tmp = rhs.data.asBits; rhs.data.asBits = data.asBits; data.asBits = tmp; } /*** Value type queries ***/ + JS_ALWAYS_INLINE bool isUndefined() const { return JSVAL_IS_UNDEFINED_IMPL(data); } + JS_ALWAYS_INLINE bool isNull() const { return JSVAL_IS_NULL_IMPL(data); } + JS_ALWAYS_INLINE bool isNullOrUndefined() const { return isNull() || isUndefined(); } + JS_ALWAYS_INLINE bool isInt32() const { return JSVAL_IS_INT32_IMPL(data); } + JS_ALWAYS_INLINE bool isInt32(int32 i32) const { return JSVAL_IS_SPECIFIC_INT32_IMPL(data, i32); } + JS_ALWAYS_INLINE bool isDouble() const { return JSVAL_IS_DOUBLE_IMPL(data); } + JS_ALWAYS_INLINE bool isNumber() const { return JSVAL_IS_NUMBER_IMPL(data); } + JS_ALWAYS_INLINE bool isString() const { return JSVAL_IS_STRING_IMPL(data); } + JS_ALWAYS_INLINE bool isObject() const { return JSVAL_IS_OBJECT_IMPL(data); } + JS_ALWAYS_INLINE bool isPrimitive() const { return JSVAL_IS_PRIMITIVE_IMPL(data); } + JS_ALWAYS_INLINE bool isObjectOrNull() const { return JSVAL_IS_OBJECT_OR_NULL_IMPL(data); } + JS_ALWAYS_INLINE bool isGCThing() const { return JSVAL_IS_GCTHING_IMPL(data); } + JS_ALWAYS_INLINE bool isBoolean() const { return JSVAL_IS_BOOLEAN_IMPL(data); } + JS_ALWAYS_INLINE bool isTrue() const { return JSVAL_IS_SPECIFIC_BOOLEAN(data, true); } + JS_ALWAYS_INLINE bool isFalse() const { return JSVAL_IS_SPECIFIC_BOOLEAN(data, false); } + JS_ALWAYS_INLINE bool isMagic() const { return JSVAL_IS_MAGIC_IMPL(data); } + JS_ALWAYS_INLINE bool isMagic(JSWhyMagic why) const { JS_ASSERT_IF(isMagic(), data.s.payload.why == why); return JSVAL_IS_MAGIC_IMPL(data); } +#if JS_BITS_PER_WORD == 64 + JS_ALWAYS_INLINE + bool hasPtrPayload() const { + return data.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_PTR_PAYLOAD_SET; + } +#endif + + JS_ALWAYS_INLINE bool isMarkable() const { return JSVAL_IS_TRACEABLE_IMPL(data); } + JS_ALWAYS_INLINE int32 gcKind() const { JS_ASSERT(isMarkable()); return JSVAL_TRACE_KIND_IMPL(data); } #ifdef DEBUG + JS_ALWAYS_INLINE JSWhyMagic whyMagic() const { JS_ASSERT(isMagic()); return data.s.payload.why; } #endif /*** Comparison ***/ + JS_ALWAYS_INLINE bool operator==(const Value &rhs) const { return data.asBits == rhs.data.asBits; } + JS_ALWAYS_INLINE bool operator!=(const Value &rhs) const { return data.asBits != rhs.data.asBits; } + JS_ALWAYS_INLINE friend bool SameType(const Value &lhs, const Value &rhs) { return JSVAL_SAME_TYPE_IMPL(lhs.data, rhs.data); } /*** Extract the value's typed payload ***/ + JS_ALWAYS_INLINE int32 toInt32() const { JS_ASSERT(isInt32()); return JSVAL_TO_INT32_IMPL(data); } + JS_ALWAYS_INLINE double toDouble() const { JS_ASSERT(isDouble()); return data.asDouble; } + JS_ALWAYS_INLINE double toNumber() const { JS_ASSERT(isNumber()); return isDouble() ? toDouble() : double(toInt32()); } + JS_ALWAYS_INLINE JSString *toString() const { JS_ASSERT(isString()); return JSVAL_TO_STRING_IMPL(data); } + JS_ALWAYS_INLINE JSObject &toObject() const { JS_ASSERT(isObject()); return *JSVAL_TO_OBJECT_IMPL(data); } + JS_ALWAYS_INLINE JSObject *toObjectOrNull() const { JS_ASSERT(isObjectOrNull()); return JSVAL_TO_OBJECT_IMPL(data); } + JS_ALWAYS_INLINE void *asGCThing() const { JS_ASSERT(isGCThing()); return JSVAL_TO_GCTHING_IMPL(data); } + JS_ALWAYS_INLINE bool toBoolean() const { JS_ASSERT(isBoolean()); return JSVAL_TO_BOOLEAN_IMPL(data); } + JS_ALWAYS_INLINE uint32 payloadAsRawUint32() const { JS_ASSERT(!isDouble()); return data.s.payload.u32; } + JS_ALWAYS_INLINE uint64 asRawBits() const { return data.asBits; } /* * In the extract/box/unbox functions below, "NonDouble" means this * functions must not be called on a value that is a double. This allows * these operations to be implemented more efficiently, since doubles * generally already require special handling by the caller. */ + JS_ALWAYS_INLINE JSValueType extractNonDoubleType() const { return JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(data); } + JS_ALWAYS_INLINE JSValueTag extractNonDoubleTag() const { return JSVAL_EXTRACT_NON_DOUBLE_TAG_IMPL(data); } + JS_ALWAYS_INLINE void unboxNonDoubleTo(uint64 *out) const { UNBOX_NON_DOUBLE_JSVAL(data, out); } + JS_ALWAYS_INLINE void boxNonDoubleFrom(JSValueType type, uint64 *out) { data = BOX_NON_DOUBLE_JSVAL(type, out); } /* * The trace-jit specializes JSVAL_TYPE_OBJECT into JSVAL_TYPE_FUNOBJ and * JSVAL_TYPE_NONFUNOBJ. Since these two operations just return the type of * a value, the caller must handle JSVAL_TYPE_OBJECT separately. */ + JS_ALWAYS_INLINE JSValueType extractNonDoubleObjectTraceType() const { JS_ASSERT(!isObject()); return JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(data); } + JS_ALWAYS_INLINE JSValueTag extractNonDoubleObjectTraceTag() const { JS_ASSERT(!isObject()); return JSVAL_EXTRACT_NON_DOUBLE_TAG_IMPL(data); } /* * Private API * * Private setters/getters allow the caller to read/write arbitrary types * that fit in the 64-bit payload. It is the caller's responsibility, after * storing to a value with setPrivateX to read only using getPrivateX. * Privates values are given a type type which ensures they are not marked. */ + JS_ALWAYS_INLINE void setPrivate(void *ptr) { data = PRIVATE_PTR_TO_JSVAL_IMPL(ptr); } + JS_ALWAYS_INLINE void *toPrivate() const { JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(data)); return JSVAL_TO_PRIVATE_PTR_IMPL(data); } + JS_ALWAYS_INLINE void setPrivateUint32(uint32 ui) { data = PRIVATE_UINT32_TO_JSVAL_IMPL(ui); } + JS_ALWAYS_INLINE uint32 toPrivateUint32() const { JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(data)); return JSVAL_TO_PRIVATE_UINT32_IMPL(data); } + JS_ALWAYS_INLINE uint32 &getPrivateUint32Ref() { JS_ASSERT(isDouble()); return data.s.payload.u32; } private: void staticAssertions() { JS_STATIC_ASSERT(sizeof(JSValueType) == 1); @@ -759,19 +836,17 @@ static inline Value * Valueify(js static inline const Value * Valueify(const jsval *v) { return (const Value *)v; } static inline Value ** Valueify(jsval **v) { return (Value **)v; } static inline Value & Valueify(jsval &v) { return (Value &)v; } static inline const Value & Valueify(const jsval &v) { return (const Value &)v; } struct Class; typedef JSBool -(* Native)(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval); -typedef JSBool -(* FastNative)(JSContext *cx, uintN argc, Value *vp); +(* Native)(JSContext *cx, uintN argc, Value *vp); typedef JSBool (* PropertyOp)(JSContext *cx, JSObject *obj, jsid id, Value *vp); typedef JSBool (* ConvertOp)(JSContext *cx, JSObject *obj, JSType type, Value *vp); typedef JSBool (* NewEnumerateOp)(JSContext *cx, JSObject *obj, JSIterateOp enum_op, Value *statep, jsid *idp); typedef JSBool @@ -786,36 +861,32 @@ typedef JSBool PropertyOp getter, PropertyOp setter, uintN attrs); typedef JSBool (* PropertyIdOp)(JSContext *cx, JSObject *obj, jsid id, Value *vp); typedef JSBool (* CallOp)(JSContext *cx, uintN argc, Value *vp); static inline Native Valueify(JSNative f) { return (Native)f; } static inline JSNative Jsvalify(Native f) { return (JSNative)f; } -static inline FastNative Valueify(JSFastNative f) { return (FastNative)f; } -static inline JSFastNative Jsvalify(FastNative f) { return (JSFastNative)f; } static inline PropertyOp Valueify(JSPropertyOp f) { return (PropertyOp)f; } static inline JSPropertyOp Jsvalify(PropertyOp f) { return (JSPropertyOp)f; } static inline ConvertOp Valueify(JSConvertOp f) { return (ConvertOp)f; } static inline JSConvertOp Jsvalify(ConvertOp f) { return (JSConvertOp)f; } static inline NewEnumerateOp Valueify(JSNewEnumerateOp f) { return (NewEnumerateOp)f; } static inline JSNewEnumerateOp Jsvalify(NewEnumerateOp f) { return (JSNewEnumerateOp)f; } static inline HasInstanceOp Valueify(JSHasInstanceOp f) { return (HasInstanceOp)f; } static inline JSHasInstanceOp Jsvalify(HasInstanceOp f) { return (JSHasInstanceOp)f; } static inline CheckAccessOp Valueify(JSCheckAccessOp f) { return (CheckAccessOp)f; } static inline JSCheckAccessOp Jsvalify(CheckAccessOp f) { return (JSCheckAccessOp)f; } static inline EqualityOp Valueify(JSEqualityOp f); /* Same type as JSHasInstanceOp */ static inline JSEqualityOp Jsvalify(EqualityOp f); /* Same type as HasInstanceOp */ static inline DefinePropOp Valueify(JSDefinePropOp f) { return (DefinePropOp)f; } static inline JSDefinePropOp Jsvalify(DefinePropOp f) { return (JSDefinePropOp)f; } static inline PropertyIdOp Valueify(JSPropertyIdOp f); /* Same type as JSPropertyOp */ static inline JSPropertyIdOp Jsvalify(PropertyIdOp f); /* Same type as PropertyOp */ -static inline CallOp Valueify(JSCallOp f); /* Same type as JSFastNative */ -static inline JSCallOp Jsvalify(CallOp f); /* Same type as FastNative */ static const PropertyOp PropertyStub = (PropertyOp)JS_PropertyStub; static const JSEnumerateOp EnumerateStub = JS_EnumerateStub; static const JSResolveOp ResolveStub = JS_ResolveStub; static const ConvertOp ConvertStub = (ConvertOp)JS_ConvertStub; static const JSFinalizeOp FinalizeStub = JS_FinalizeStub; #define JS_CLASS_MEMBERS \ @@ -880,34 +951,24 @@ struct ObjectOps { struct Class { JS_CLASS_MEMBERS; ClassExtension ext; ObjectOps ops; uint8 pad[sizeof(JSClass) - sizeof(ClassSizeMeasurement) - sizeof(ClassExtension) - sizeof(ObjectOps)]; - /* Flag indicating that Class::call is a fast native. */ - static const uint32 CALL_IS_FAST = JSCLASS_INTERNAL_FLAG1; - /* Class is not native and its map is not a scope. */ static const uint32 NON_NATIVE = JSCLASS_INTERNAL_FLAG2; bool isNative() const { return !(flags & NON_NATIVE); } }; -/* Helper to initialize Class::call when Class::CALL_IS_FAST. */ -inline Native -CastCallOpAsNative(CallOp op) -{ - return reinterpret_cast<Native>(op); -} - JS_STATIC_ASSERT(offsetof(JSClass, name) == offsetof(Class, name)); JS_STATIC_ASSERT(offsetof(JSClass, flags) == offsetof(Class, flags)); JS_STATIC_ASSERT(offsetof(JSClass, addProperty) == offsetof(Class, addProperty)); JS_STATIC_ASSERT(offsetof(JSClass, delProperty) == offsetof(Class, delProperty)); JS_STATIC_ASSERT(offsetof(JSClass, getProperty) == offsetof(Class, getProperty)); JS_STATIC_ASSERT(offsetof(JSClass, setProperty) == offsetof(Class, setProperty)); JS_STATIC_ASSERT(offsetof(JSClass, enumerate) == offsetof(Class, enumerate)); JS_STATIC_ASSERT(offsetof(JSClass, resolve) == offsetof(Class, resolve)); @@ -941,16 +1002,48 @@ JS_STATIC_ASSERT(sizeof(JSPropertyDescri static JS_ALWAYS_INLINE JSClass * Jsvalify(Class *c) { return (JSClass *)c; } static JS_ALWAYS_INLINE Class * Valueify(JSClass *c) { return (Class *)c; } static JS_ALWAYS_INLINE JSPropertyDescriptor * Jsvalify(PropertyDescriptor *p) { return (JSPropertyDescriptor *) p; } static JS_ALWAYS_INLINE PropertyDescriptor * Valueify(JSPropertyDescriptor *p) { return (PropertyDescriptor *) p; } /******************************************************************************/ /* + * Any cast-via-function-call, inlined or not, will cause initialization to + * happen at startup, rather than statically, so just cast in release builds. + */ +#ifdef DEBUG + +static inline JSNative JsvalifyNative(Native n) { return (JSNative)n; } +static inline JSNative JsvalifyNative(JSNative n) { return n; } +static inline Native ValueifyNative(JSNative n) { return (Native)n; } +static inline Native ValueifyNative(Native n) { return n; } + +# define JS_VALUEIFY_NATIVE(n) js::ValueifyNative(n) +# define JS_JSVALIFY_NATIVE(n) js::JsvalifyNative(n) + +#else + +# define JS_VALUEIFY_NATIVE(n) ((js::Native)n) +# define JS_JSVALIFY_NATIVE(n) ((JSNative)n) + +#endif + +/* + * JSFunctionSpec uses JSAPI jsval in function signatures whereas the engine + * uses js::Value. To avoid widespread (JSNative) casting, have JS_FN perfom a + * type-safe cast. + */ +#undef JS_FN +#define JS_FN(name,call,nargs,flags) \ + {name, JS_JSVALIFY_NATIVE(call), nargs, (flags) | JSFUN_STUB_GSOPS} + +/******************************************************************************/ + +/* * In some cases (quickstubs) we want to take a value in whatever manner is * appropriate for the architecture and normalize to a const js::Value &. On * x64, passing a js::Value may cause the to unnecessarily be passed through * memory instead of registers, so jsval, which is a builtin uint64 is used. */ #if JS_BITS_PER_WORD == 32 typedef const js::Value *ValueArgType;
--- a/js/src/jsxml.cpp +++ b/js/src/jsxml.cpp @@ -192,20 +192,19 @@ IsDeclared(const JSObject *obj) JS_ASSERT(obj->getClass() == &js_NamespaceClass); v = obj->getNamespaceDeclared(); JS_ASSERT(JSVAL_IS_VOID(v) || v == JSVAL_TRUE); return v == JSVAL_TRUE; } static JSBool -xml_isXMLName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - *rval = BOOLEAN_TO_JSVAL(js_IsXMLName(cx, argv[0])); +xml_isXMLName(JSContext *cx, uintN argc, jsval *vp) +{ + *vp = BOOLEAN_TO_JSVAL(js_IsXMLName(cx, argc ? vp[2] : JSVAL_VOID)); return JS_TRUE; } static inline bool AppendString(JSCharBuffer &cb, JSString *str) { const jschar *chars, *end; str->getCharsAndEnd(chars, end); @@ -282,24 +281,24 @@ JS_FRIEND_DATA(Class) js_NamespaceClass static JSPropertySpec namespace_props[] = { {js_prefix_str, 0, NAMESPACE_ATTRS, NamePrefix_getter, 0}, {js_uri_str, 0, NAMESPACE_ATTRS, NameURI_getter, 0}, {0,0,0,0,0} }; static JSBool -namespace_toString(JSContext *cx, uintN argc, jsval *vp) +namespace_toString(JSContext *cx, uintN argc, Value *vp) { JSObject *obj; - obj = JS_THIS_OBJECT(cx, vp); - if (!JS_InstanceOf(cx, obj, Jsvalify(&js_NamespaceClass), vp + 2)) + obj = ComputeThisFromVp(cx, vp); + if (!JS_InstanceOf(cx, obj, Jsvalify(&js_NamespaceClass), Jsvalify(vp + 2))) return JS_FALSE; - *vp = obj->getNameURI(); + *vp = Valueify(obj->getNameURI()); return JS_TRUE; } static JSFunctionSpec namespace_methods[] = { JS_FN(js_toString_str, namespace_toString, 0,0), JS_FS_END }; @@ -435,31 +434,31 @@ JS_FRIEND_DATA(Class) js_AnyNameClass = static JSPropertySpec qname_props[] = { {js_uri_str, 0, QNAME_ATTRS, QNameNameURI_getter, 0}, {js_localName_str, 0, QNAME_ATTRS, QNameLocalName_getter, 0}, {0,0,0,0,0} }; static JSBool -qname_toString(JSContext *cx, uintN argc, jsval *vp) +qname_toString(JSContext *cx, uintN argc, Value *vp) { JSObject *obj; Class *clasp; JSString *uri, *str, *qualstr; size_t length; jschar *chars; - obj = JS_THIS_OBJECT(cx, vp); + obj = ComputeThisFromVp(cx, vp); if (!obj) return JS_FALSE; clasp = obj->getClass(); if (clasp != &js_AttributeNameClass && clasp != &js_AnyNameClass && - !JS_InstanceOf(cx, obj, Jsvalify(&js_QNameClass), vp + 2)) { + !JS_InstanceOf(cx, obj, Jsvalify(&js_QNameClass), Jsvalify(vp + 2))) { return JS_FALSE; } uri = GetURI(obj); if (!uri) { /* No uri means wildcard qualifier. */ str = ATOM_TO_STRING(cx->runtime->atomState.starQualifierAtom); } else if (uri->empty()) { @@ -485,17 +484,17 @@ qname_toString(JSContext *cx, uintN argc chars[++length] = 0; str = js_NewString(cx, chars, length); if (!str) { cx->free(chars); return JS_FALSE; } } - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return JS_TRUE; } static JSFunctionSpec qname_methods[] = { JS_FN(js_toString_str, qname_toString, 0,0), JS_FS_END }; @@ -630,18 +629,18 @@ NamespaceHelper(JSContext *cx, JSObject /* Namespace called with one Namespace argument is identity. */ *rval = urival; return JS_TRUE; } obj = NewBuiltinClassInstance(cx, &js_NamespaceClass); if (!obj) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(obj); - } + } + *rval = OBJECT_TO_JSVAL(obj); METER(xml_stats.xmlnamespace); empty = cx->runtime->emptyString; obj->setNamePrefix(STRING_TO_JSVAL(empty)); obj->setNameURI(STRING_TO_JSVAL(empty)); if (argc == 1 || argc == -1) { if (isNamespace) { @@ -684,26 +683,25 @@ NamespaceHelper(JSContext *cx, JSObject obj->setNamePrefix(JSVAL_VOID); } else { prefix = js_ValueToString(cx, Valueify(prefixval)); if (!prefix) return JS_FALSE; obj->setNamePrefix(STRING_TO_JSVAL(prefix)); } } - return JS_TRUE; } static JSBool -Namespace(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) -{ - return NamespaceHelper(cx, - cx->isConstructing() ? obj : NULL, - argc, Jsvalify(argv), Jsvalify(rval)); +Namespace(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *thisobj = NULL; + (void)IsConstructing_PossiblyWithGivenThisObject(vp, &thisobj); + return NamespaceHelper(cx, thisobj, argc, Jsvalify(vp + 2), Jsvalify(vp)); } /* * When argc is -1, it indicates argv is empty but the code should behave as * if argc is 1 and argv[0] is JSVAL_VOID. */ static JSBool QNameHelper(JSContext *cx, JSObject *obj, Class *clasp, intN argc, @@ -737,18 +735,18 @@ QNameHelper(JSContext *cx, JSObject *obj /* * Create and return a new QName or AttributeName object exactly as if * constructed. */ obj = NewBuiltinClassInstance(cx, clasp); if (!obj) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(obj); - } + } + *rval = OBJECT_TO_JSVAL(obj); METER(xml_stats.qname); if (isQName) { /* If namespace is not specified and name is a QName, clone it. */ qn = JSVAL_TO_OBJECT(nameval); if (argc == 1) { uri = GetURI(qn); prefix = GetPrefix(qn); @@ -824,28 +822,29 @@ QNameHelper(JSContext *cx, JSObject *obj } out: InitXMLQName(obj, uri, prefix, name); return JS_TRUE; } static JSBool -QName(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) -{ - return QNameHelper(cx, cx->isConstructing() ? obj : NULL, - &js_QNameClass, argc, Jsvalify(argv), Jsvalify(rval)); +QName(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *thisobj = NULL; + (void)IsConstructing_PossiblyWithGivenThisObject(vp, &thisobj); + return QNameHelper(cx, thisobj, &js_QNameClass, argc, Jsvalify(vp + 2), Jsvalify(vp)); } static JSBool -AttributeName(JSContext *cx, JSObject *obj, uintN argc, Value *argv, - Value *rval) -{ - return QNameHelper(cx, cx->isConstructing() ? obj : NULL, - &js_AttributeNameClass, argc, Jsvalify(argv), Jsvalify(rval)); +AttributeName(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *thisobj = NULL; + (void)IsConstructing_PossiblyWithGivenThisObject(vp, &thisobj); + return QNameHelper(cx, thisobj, &js_AttributeNameClass, argc, Jsvalify(vp + 2), Jsvalify(vp)); } /* * XMLArray library functions. */ static JSBool namespace_identity(const void *a, const void *b) { @@ -5066,17 +5065,18 @@ js_ConcatenateXML(JSContext *cx, JSObjec vp->setObject(*listobj); out: js_LeaveLocalRootScopeWithResult(cx, *vp); return ok; } JS_FRIEND_DATA(Class) js_XMLClass = { js_XML_str, - JSCLASS_HAS_PRIVATE | JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_XML), + JSCLASS_HAS_PRIVATE | JSCLASS_MARK_IS_TRACE | + JSCLASS_HAS_CACHED_PROTO(JSProto_XML), PropertyStub, /* addProperty */ PropertyStub, /* delProperty */ PropertyStub, /* getProperty */ PropertyStub, /* setProperty */ EnumerateStub, ResolveStub, xml_convert, xml_finalize, @@ -6814,85 +6814,84 @@ xml_defaultSettings(JSContext *cx, uintN static JSFunctionSpec xml_static_methods[] = { JS_FN("settings", xml_settings, 0,0), JS_FN("setSettings", xml_setSettings, 1,0), JS_FN("defaultSettings", xml_defaultSettings, 0,0), JS_FS_END }; static JSBool -XML(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - jsval v; +XML(JSContext *cx, uintN argc, Value *vp) +{ JSXML *xml, *copy; JSObject *xobj, *vobj; Class *clasp; - v = argv[0]; + jsval v = argc ? Jsvalify(vp[2]) : JSVAL_VOID; + if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) v = STRING_TO_JSVAL(cx->runtime->emptyString); xobj = ToXML(cx, v); if (!xobj) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(xobj); xml = (JSXML *) xobj->getPrivate(); - if (cx->isConstructing() && !JSVAL_IS_PRIMITIVE(v)) { + if (IsConstructing(vp) && !JSVAL_IS_PRIMITIVE(v)) { vobj = JSVAL_TO_OBJECT(v); clasp = vobj->getClass(); if (clasp == &js_XMLClass || (clasp->flags & JSCLASS_DOCUMENT_OBSERVER)) { - /* No need to lock obj, it's newly constructed and thread local. */ - copy = DeepCopy(cx, xml, obj, 0); + copy = DeepCopy(cx, xml, NULL, 0); if (!copy) return JS_FALSE; - JS_ASSERT(copy->object == obj); - *rval = OBJECT_TO_JSVAL(obj); + vp->setObject(*copy->object); return JS_TRUE; } } + + vp->setObject(*xobj); return JS_TRUE; } static JSBool -XMLList(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - jsval v; +XMLList(JSContext *cx, uintN argc, jsval *vp) +{ JSObject *vobj, *listobj; JSXML *xml, *list; - v = argv[0]; + jsval v = argc ? vp[2] : JSVAL_VOID; + if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) v = STRING_TO_JSVAL(cx->runtime->emptyString); - if (cx->isConstructing() && !JSVAL_IS_PRIMITIVE(v)) { + if (IsConstructing(Valueify(vp)) && !JSVAL_IS_PRIMITIVE(v)) { vobj = JSVAL_TO_OBJECT(v); if (vobj->isXML()) { xml = (JSXML *) vobj->getPrivate(); if (xml->xml_class == JSXML_CLASS_LIST) { listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); if (!listobj) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(listobj); + *vp = OBJECT_TO_JSVAL(listobj); list = (JSXML *) listobj->getPrivate(); if (!Append(cx, list, xml)) return JS_FALSE; return JS_TRUE; } } } /* Toggle on XML support since the script has explicitly requested it. */ listobj = ToXMLList(cx, v); if (!listobj) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(listobj); + *vp = OBJECT_TO_JSVAL(listobj); return JS_TRUE; } #ifdef DEBUG_notme JSCList xml_leaks = JS_INIT_STATIC_CLIST(&xml_leaks); uint32 xml_serial; #endif @@ -7074,17 +7073,17 @@ js_InitXMLClass(JSContext *cx, JSObject Shape *shape; jsval cval, vp[3]; /* Define the isXMLName function. */ if (!JS_DefineFunction(cx, obj, js_isXMLName_str, xml_isXMLName, 1, 0)) return NULL; /* Define the XML class constructor and prototype. */ - proto = js_InitClass(cx, obj, NULL, &js_XMLClass, Valueify(XML), 1, + proto = js_InitClass(cx, obj, NULL, &js_XMLClass, XML, 1, NULL, xml_methods, xml_static_props, xml_static_methods); if (!proto) return NULL; xml = js_NewXML(cx, JSXML_CLASS_TEXT); if (!xml) return NULL; @@ -7113,17 +7112,17 @@ js_InitXMLClass(JSContext *cx, JSObject /* Set default settings. */ vp[0] = JSVAL_NULL; vp[1] = cval; vp[2] = JSVAL_VOID; if (!xml_setSettings(cx, 1, vp)) return NULL; /* Define the XMLList function and give it the same prototype as XML. */ - fun = JS_DefineFunction(cx, obj, js_XMLList_str, XMLList, 1, 0); + fun = JS_DefineFunction(cx, obj, js_XMLList_str, XMLList, 1, JSFUN_CONSTRUCTOR); if (!fun) return NULL; if (!js_SetClassPrototype(cx, FUN_OBJECT(fun), proto, JSPROP_READONLY | JSPROP_PERMANENT)) { return NULL; } return proto; } @@ -7214,24 +7213,23 @@ js_GetFunctionNamespace(JSContext *cx, V * its v argument as the uri of a new Namespace, with "" as the prefix. See * ECMA-357 12.1 and 12.1.1. Note that if Set is called with a Namespace n, * the default XML namespace will be set to ("", n.uri). So the uri string * is really the only usefully stored value of the default namespace. */ JSBool js_GetDefaultXMLNamespace(JSContext *cx, jsval *vp) { - JSStackFrame *fp; JSObject *ns, *obj, *tmp; jsval v; - fp = js_GetTopStackFrame(cx); + JSObject *scopeChain = JS_GetScopeChain(cx); obj = NULL; - for (tmp = fp->getScopeChain(); tmp; tmp = tmp->getParent()) { + for (tmp = scopeChain; tmp; tmp = tmp->getParent()) { Class *clasp = tmp->getClass(); if (clasp == &js_BlockClass || clasp == &js_WithClass) continue; if (!tmp->getProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, Valueify(&v))) return JS_FALSE; if (!JSVAL_IS_PRIMITIVE(v)) { *vp = v; return JS_TRUE; @@ -7332,20 +7330,19 @@ js_EscapeElementValue(JSContext *cx, JSS JSString * js_ValueToXMLString(JSContext *cx, const Value &v) { return ToXMLString(cx, Jsvalify(v), 0); } static JSBool -anyname_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - *rval = ATOM_TO_JSVAL(cx->runtime->atomState.starAtom); +anyname_toString(JSContext *cx, uintN argc, jsval *vp) +{ + *vp = ATOM_TO_JSVAL(cx->runtime->atomState.starAtom); return JS_TRUE; } JSBool js_GetAnyName(JSContext *cx, jsid *idp) { JSRuntime *rt; JSObject *obj;
--- a/js/src/methodjit/InvokeHelpers.cpp +++ b/js/src/methodjit/InvokeHelpers.cpp @@ -392,25 +392,24 @@ stubs::SlowCall(VMFrame &f, uint32 argc) } if (!InlineCall(f, 0, &ret, argc)) THROWV(NULL); return ret; } - if (fun->isFastNative()) { + if (fun->isNative()) { #ifdef JS_MONOIC #ifdef JS_CPU_X86 - ic::CallFastNative(cx, f.fp()->getScript(), mic, fun, false); + ic::CallNative(cx, f.fp()->getScript(), mic, fun, false); #endif #endif - FastNative fn = (FastNative)fun->u.n.native; - if (!fn(cx, argc, vp)) + if (!fun->u.n.native(cx, argc, vp)) THROWV(NULL); return NULL; } } if (!Invoke(f.cx, InvokeArgsAlreadyOnTheStack(vp, argc), 0)) THROWV(NULL); @@ -447,27 +446,26 @@ stubs::SlowNew(VMFrame &f, uint32 argc) void *ret; vp[1].setObject(*obj2); if (!InlineCall(f, JSFRAME_CONSTRUCTING, &ret, argc)) THROWV(NULL); return ret; } - if (fun->isFastConstructor()) { + if (fun->isConstructor()) { #ifdef JS_MONOIC #ifdef JS_CPU_X86 - ic::CallFastNative(cx, f.fp()->getScript(), mic, fun, true); + ic::CallNative(cx, f.fp()->getScript(), mic, fun, true); #endif #endif - vp[1].setMagic(JS_FAST_CONSTRUCTOR); + vp[1].setMagicWithObjectOrNullPayload(NULL); - FastNative fn = (FastNative)fun->u.n.native; - if (!fn(cx, argc, vp)) + if (!fun->u.n.native(cx, argc, vp)) THROWV(NULL); JS_ASSERT(!vp->isPrimitive()); return NULL; } } if (!InvokeConstructor(cx, InvokeArgsAlreadyOnTheStack(vp, argc)))
--- a/js/src/methodjit/MonoIC.cpp +++ b/js/src/methodjit/MonoIC.cpp @@ -224,29 +224,29 @@ ic::NativeCallCompiler::finish(JSScript /* Patch all jumps with the correct target. */ JSC::LinkBuffer linkmasm(result, masm.size()); for (size_t i = 0; i < jumps.length(); i++) linkmasm.link(jumps[i].from, JSC::CodeLocationLabel(jumps[i].to)); } void -ic::CallFastNative(JSContext *cx, JSScript *script, MICInfo &mic, JSFunction *fun, bool isNew) +ic::CallNative(JSContext *cx, JSScript *script, MICInfo &mic, JSFunction *fun, bool isNew) { if (mic.u.generated) { /* Already generated a MIC at this site, don't make another one. */ return; } mic.u.generated = true; - JS_ASSERT(fun->isFastNative()); + JS_ASSERT(fun->isNative()); if (isNew) - JS_ASSERT(fun->isFastConstructor()); + JS_ASSERT(fun->isConstructor()); - FastNative fn = (FastNative)fun->u.n.native; + Native native = fun->u.n.native; typedef JSC::MacroAssembler::ImmPtr ImmPtr; typedef JSC::MacroAssembler::Imm32 Imm32; typedef JSC::MacroAssembler::Address Address; typedef JSC::MacroAssembler::Jump Jump; uint8 *start = (uint8*) mic.knownObject.executableAddress(); uint8 *stubEntry = (uint8*) mic.stubEntry.executableAddress(); @@ -276,29 +276,31 @@ ic::CallFastNative(JSContext *cx, JSScri ncc.masm.sub32(Imm32(stackAdjustment), JSC::X86Registers::esp); /* Compute and push vp */ uint32 vpOffset = sizeof(JSStackFrame) + mic.frameDepth * sizeof(jsval); ncc.masm.addPtr(Imm32(vpOffset), JSFrameReg, temp); ncc.masm.storePtr(temp, Address(JSC::X86Registers::esp, 0x8)); if (isNew) { - /* Mark vp[1] as magic. */ - ncc.masm.storeValue(MagicValue(JS_FAST_CONSTRUCTOR), Address(temp, sizeof(Value))); + /* Mark 'this' as magic. */ + Value magicCtorThis; + magicCtorThis.setMagicWithObjectOrNullPayload(NULL); + ncc.masm.storeValue(magicCtorThis, Address(temp, sizeof(Value))); } /* Push argc */ ncc.masm.store32(Imm32(mic.argc), Address(JSC::X86Registers::esp, 0x4)); /* Push cx. The VMFrame is homed at the stack register, so adjust for the amount we pushed. */ ncc.masm.loadPtr(FrameAddress(stackAdjustment + offsetof(VMFrame, cx)), temp); ncc.masm.storePtr(temp, Address(JSC::X86Registers::esp, 0)); /* Do the call. */ - ncc.masm.call(JS_FUNC_TO_DATA_PTR(void *, fn)); + ncc.masm.call(JS_FUNC_TO_DATA_PTR(void *, native)); /* Restore stack. */ ncc.masm.add32(Imm32(stackAdjustment), JSC::X86Registers::esp); #if defined(JS_NO_FASTCALL) && defined(JS_CPU_X86) // Usually JaegerThrowpoline got called from return address. // So in JaegerThrowpoline without fastcall, esp was added by 8. // If we just want to jump there, we need to sub esp by 8 first.
--- a/js/src/methodjit/MonoIC.h +++ b/js/src/methodjit/MonoIC.h @@ -153,17 +153,17 @@ class NativeCallCompiler /* * Finish up this native, and add an incoming jump from start * and an outgoing jump to fallthrough. */ void finish(JSScript *script, uint8 *start, uint8 *fallthrough); }; -void CallFastNative(JSContext *cx, JSScript *script, MICInfo &mic, JSFunction *fun, bool isNew); +void CallNative(JSContext *cx, JSScript *script, MICInfo &mic, JSFunction *fun, bool isNew); #endif /* JS_CPU_X86 */ void PurgeMICs(JSContext *cx, JSScript *script); } /* namespace ic */ } /* namespace mjit */ } /* namespace js */
--- a/js/src/methodjit/StubCalls.cpp +++ b/js/src/methodjit/StubCalls.cpp @@ -1604,23 +1604,23 @@ stubs::LambdaJoinableForCall(VMFrame &f, * Note that we have not yet pushed obj as the final argument, * so regs.sp[1 - (iargc + 2)], and not regs.sp[-(iargc + 2)], * is the callee for this JSOP_CALL. */ const Value &cref = f.regs.sp[1 - (iargc + 2)]; JSObject *callee; if (IsFunctionObject(cref, &callee)) { - JSFunction *calleeFun = GET_FUNCTION_PRIVATE(cx, callee); - FastNative fastNative = FUN_FAST_NATIVE(calleeFun); + JSFunction *calleeFun = callee->getFunctionPrivate(); + Native native = calleeFun->maybeNative(); - if (fastNative) { - if (iargc == 1 && fastNative == array_sort) + if (native) { + if (iargc == 1 && native == array_sort) return obj; - if (iargc == 2 && fastNative == str_replace) + if (iargc == 2 && native == str_replace) return obj; } } } return Lambda(f, fun); } JSObject * JS_FASTCALL
--- a/js/src/perf/jsperf.cpp +++ b/js/src/perf/jsperf.cpp @@ -45,32 +45,37 @@ using JS::PerfMeasurement; // You cannot forward-declare a static object in C++, so instead // we have to forward-declare the helper functions that refer to it. static PerfMeasurement* GetPM(JSContext* cx, JSObject* obj, const char* fname); static PerfMeasurement* GetPMFromThis(JSContext* cx, jsval* vp); // Constructor and destructor static JSBool -pm_construct(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval) +pm_construct(JSContext* cx, uintN argc, jsval* vp) { uint32 mask; - if (!JS_ConvertArguments(cx, argc, argv, "u", &mask)) + if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "u", &mask)) + return JS_FALSE; + + JSObject *obj = JS_NewObjectForConstructor(cx, vp); + if (!obj) return JS_FALSE; if (!JS_SealObject(cx, obj, JS_FALSE)) return JS_FALSE; PerfMeasurement* p = new PerfMeasurement(PerfMeasurement::EventMask(mask)); if (!p) { JS_ReportOutOfMemory(cx); return JS_FALSE; } JS_SetPrivate(cx, obj, p); + *vp = OBJECT_TO_JSVAL(obj); return JS_TRUE; } static void pm_finalize(JSContext* cx, JSObject* obj) { delete (PerfMeasurement*) JS_GetPrivate(cx, obj); }
--- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -859,35 +859,37 @@ ProcessArgs(JSContext *cx, JSObject *obj } if (filename || isInteractive) Process(cx, obj, filename, forceTTY); return gExitCode; } static JSBool -Version(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +Version(JSContext *cx, uintN argc, jsval *vp) { + jsval *argv = JS_ARGV(cx, vp); if (argc > 0 && JSVAL_IS_INT(argv[0])) - *rval = INT_TO_JSVAL(JS_SetVersion(cx, (JSVersion) JSVAL_TO_INT(argv[0]))); + *vp = INT_TO_JSVAL(JS_SetVersion(cx, (JSVersion) JSVAL_TO_INT(argv[0]))); else - *rval = INT_TO_JSVAL(JS_GetVersion(cx)); + *vp = INT_TO_JSVAL(JS_GetVersion(cx)); return JS_TRUE; } static JSBool -Options(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +Options(JSContext *cx, uintN argc, jsval *vp) { uint32 optset, flag; JSString *str; const char *opt; char *names; JSBool found; optset = 0; + jsval *argv = JS_ARGV(cx, vp); for (uintN i = 0; i < argc; i++) { str = JS_ValueToString(cx, argv[i]); if (!str) return JS_FALSE; argv[i] = STRING_TO_JSVAL(str); opt = JS_GetStringBytes(str); if (!opt) return JS_FALSE; @@ -915,46 +917,51 @@ Options(JSContext *cx, JSObject *obj, ui JS_ReportOutOfMemory(cx); return JS_FALSE; } str = JS_NewString(cx, names, strlen(names)); if (!str) { free(names); return JS_FALSE; } - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } static JSBool -Load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +Load(JSContext *cx, uintN argc, jsval *vp) { uintN i; JSString *str; const char *filename; JSScript *script; JSBool ok; uint32 oldopts; + JSObject *thisobj = JS_THIS_OBJECT(cx, vp); + if (!thisobj) + return JS_FALSE; + + jsval *argv = JS_ARGV(cx, vp); for (i = 0; i < argc; i++) { str = JS_ValueToString(cx, argv[i]); if (!str) return JS_FALSE; argv[i] = STRING_TO_JSVAL(str); filename = JS_GetStringBytes(str); errno = 0; oldopts = JS_GetOptions(cx); JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO | JSOPTION_NO_SCRIPT_RVAL); - script = JS_CompileFile(cx, obj, filename); + script = JS_CompileFile(cx, thisobj, filename); JS_SetOptions(cx, oldopts); if (!script) { ok = JS_FALSE; } else { ok = !compileOnly - ? JS_ExecuteScript(cx, obj, script, NULL) + ? JS_ExecuteScript(cx, thisobj, script, NULL) : JS_TRUE; JS_DestroyScript(cx, script); } if (!ok) return JS_FALSE; } return JS_TRUE; @@ -1097,22 +1104,22 @@ Print(JSContext *cx, uintN argc, jsval * fputc('\n', gOutFile); fflush(gOutFile); JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } static JSBool -Help(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); +Help(JSContext *cx, uintN argc, jsval *vp); static JSBool -Quit(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +Quit(JSContext *cx, uintN argc, jsval *vp) { - JS_ConvertArguments(cx, argc, argv,"/ i", &gExitCode); + JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "/ i", &gExitCode); gQuitting = JS_TRUE; #ifdef JS_THREADSAFE if (gWorkers) js::workers::terminateAll(cx, gWorkers); #endif return JS_FALSE; } @@ -1467,26 +1474,27 @@ ValueToScript(JSContext *cx, jsval v) JSSMSG_SCRIPTS_ONLY); } } return script; } static JSBool -SetDebug(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +SetDebug(JSContext *cx, uintN argc, jsval *vp) { + jsval *argv = JS_ARGV(cx, vp); if (argc == 0 || !JSVAL_IS_BOOLEAN(argv[0])) { JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_NOT_ENOUGH_ARGS, "setDebug"); return JS_FALSE; } js_SetDebugMode(cx, JSVAL_TO_BOOLEAN(argv[0])); - *rval = JSVAL_VOID; + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } static JSBool GetTrapArgs(JSContext *cx, uintN argc, jsval *argv, JSScript **scriptp, int32 *ip) { jsval v; @@ -1529,129 +1537,132 @@ TrapHandler(JSContext *cx, JSScript *scr return JSTRAP_ERROR; } if (!JSVAL_IS_VOID(*rval)) return JSTRAP_RETURN; return JSTRAP_CONTINUE; } static JSBool -Trap(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +Trap(JSContext *cx, uintN argc, jsval *vp) { JSString *str; JSScript *script; int32 i; + jsval *argv = JS_ARGV(cx, vp); if (argc == 0) { JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_TRAP_USAGE); return JS_FALSE; } argc--; str = JS_ValueToString(cx, argv[argc]); if (!str) return JS_FALSE; argv[argc] = STRING_TO_JSVAL(str); if (!GetTrapArgs(cx, argc, argv, &script, &i)) return JS_FALSE; + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_SetTrap(cx, script, script->code + i, TrapHandler, STRING_TO_JSVAL(str)); } static JSBool -Untrap(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +Untrap(JSContext *cx, uintN argc, jsval *vp) { JSScript *script; int32 i; - if (!GetTrapArgs(cx, argc, argv, &script, &i)) + if (!GetTrapArgs(cx, argc, JS_ARGV(cx, vp), &script, &i)) return JS_FALSE; JS_ClearTrap(cx, script, script->code + i, NULL, NULL); + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } static JSTrapStatus DebuggerAndThrowHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure) { return TrapHandler(cx, script, pc, rval, STRING_TO_JSVAL((JSString *)closure)); } static JSBool -SetDebuggerHandler(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +SetDebuggerHandler(JSContext *cx, uintN argc, jsval *vp) { JSString *str; if (argc == 0) { JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_NOT_ENOUGH_ARGS, "setDebuggerHandler"); return JS_FALSE; } - str = JS_ValueToString(cx, argv[0]); + str = JS_ValueToString(cx, JS_ARGV(cx, vp)[0]); if (!str) return JS_FALSE; JS_SetDebuggerHandler(cx->runtime, DebuggerAndThrowHandler, str); - *rval = JSVAL_VOID; + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } static JSBool -SetThrowHook(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +SetThrowHook(JSContext *cx, uintN argc, jsval *vp) { JSString *str; if (argc == 0) { JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_NOT_ENOUGH_ARGS, "setThrowHook"); return JS_FALSE; } - str = JS_ValueToString(cx, argv[0]); + str = JS_ValueToString(cx, JS_ARGV(cx, vp)[0]); if (!str) return JS_FALSE; JS_SetThrowHook(cx->runtime, DebuggerAndThrowHandler, str); - *rval = JSVAL_VOID; + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } static JSBool -LineToPC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +LineToPC(JSContext *cx, uintN argc, jsval *vp) { JSScript *script; int32 i; uintN lineno; jsbytecode *pc; if (argc == 0) { JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_LINE2PC_USAGE); return JS_FALSE; } script = JS_GetScriptedCaller(cx, NULL)->getScript(); - if (!GetTrapArgs(cx, argc, argv, &script, &i)) + if (!GetTrapArgs(cx, argc, JS_ARGV(cx, vp), &script, &i)) return JS_FALSE; lineno = (i == 0) ? script->lineno : (uintN)i; pc = JS_LineNumberToPC(cx, script, lineno); if (!pc) return JS_FALSE; - *rval = INT_TO_JSVAL(pc - script->code); + *vp = INT_TO_JSVAL(pc - script->code); return JS_TRUE; } static JSBool -PCToLine(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +PCToLine(JSContext *cx, uintN argc, jsval *vp) { JSScript *script; int32 i; uintN lineno; - if (!GetTrapArgs(cx, argc, argv, &script, &i)) + if (!GetTrapArgs(cx, argc, JS_ARGV(cx, vp), &script, &i)) return JS_FALSE; lineno = JS_PCToLineNumber(cx, script, script->code + i); if (!lineno) return JS_FALSE; - *rval = INT_TO_JSVAL(lineno); + *vp = INT_TO_JSVAL(lineno); return JS_TRUE; } #ifdef DEBUG static void UpdateSwitchTableBounds(JSContext *cx, JSScript *script, uintN offset, uintN *start, uintN *end) @@ -1801,28 +1812,30 @@ SrcNotes(JSContext *cx, JSScript *script break; default:; } fputc('\n', gOutFile); } } static JSBool -Notes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +Notes(JSContext *cx, uintN argc, jsval *vp) { uintN i; JSScript *script; + jsval *argv = JS_ARGV(cx, vp); for (i = 0; i < argc; i++) { script = ValueToScript(cx, argv[i]); if (!script) continue; SrcNotes(cx, script); } + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } JS_STATIC_ASSERT(JSTRY_CATCH == 0); JS_STATIC_ASSERT(JSTRY_FINALLY == 1); JS_STATIC_ASSERT(JSTRY_ITER == 2); static const char* const TryNoteNames[] = { "catch", "finally", "iter" }; @@ -1922,89 +1935,94 @@ DisassembleValue(JSContext *cx, jsval v, } } } } return true; } static JSBool -Disassemble(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +Disassemble(JSContext *cx, uintN argc, jsval *vp) { bool lines = false, recursive = false; + jsval *argv = JS_ARGV(cx, vp); while (argc > 0 && JSVAL_IS_STRING(argv[0])) { const char *bytes = JS_GetStringBytes(JSVAL_TO_STRING(argv[0])); lines = !strcmp(bytes, "-l"); recursive = !strcmp(bytes, "-r"); if (!lines && !recursive) break; argv++, argc--; } for (uintN i = 0; i < argc; i++) { if (!DisassembleValue(cx, argv[i], lines, recursive)) return false; } + JS_SET_RVAL(cx, vp, JSVAL_VOID); return true; } static JSBool -DisassFile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +DisassFile(JSContext *cx, uintN argc, jsval *vp) { JSString *str; const char *filename; JSScript *script; JSBool ok; uint32 oldopts; if (!argc) return JS_TRUE; - str = JS_ValueToString(cx, argv[0]); + JSObject *thisobj = JS_THIS_OBJECT(cx, vp); + if (!thisobj) + return JS_FALSE; + + str = JS_ValueToString(cx, vp[2]); if (!str) return JS_FALSE; - argv[0] = STRING_TO_JSVAL(str); filename = JS_GetStringBytes(str); oldopts = JS_GetOptions(cx); JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO | JSOPTION_NO_SCRIPT_RVAL); - script = JS_CompileFile(cx, obj, filename); + script = JS_CompileFile(cx, thisobj, filename); JS_SetOptions(cx, oldopts); if (!script) return JS_FALSE; if (script->isEmpty()) return JS_TRUE; - obj = JS_NewScriptObject(cx, script); + JSObject *obj = JS_NewScriptObject(cx, script); if (!obj) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(obj); /* I like to root it, root it. */ - ok = Disassemble(cx, obj, 1, rval, rval); /* gross, but works! */ - *rval = JSVAL_VOID; + *vp = OBJECT_TO_JSVAL(obj); /* I like to root it, root it. */ + ok = Disassemble(cx, 1, vp); /* gross, but works! */ + JS_SET_RVAL(cx, vp, JSVAL_VOID); return ok; } static JSBool -DisassWithSrc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +DisassWithSrc(JSContext *cx, uintN argc, jsval *vp) { #define LINE_BUF_LEN 512 uintN i, len, line1, line2, bupline; JSScript *script; FILE *file; char linebuf[LINE_BUF_LEN]; jsbytecode *pc, *end; JSBool ok; static char sep[] = ";-------------------------"; ok = JS_TRUE; + jsval *argv = JS_ARGV(cx, vp); for (i = 0; ok && i < argc; i++) { script = ValueToScript(cx, argv[i]); if (!script) return JS_FALSE; if (!script->filename) { JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_FILE_SCRIPTS_ONLY); @@ -2068,30 +2086,32 @@ DisassWithSrc(JSContext *cx, JSObject *o goto bail; } pc += len; } bail: fclose(file); } + JS_SET_RVAL(cx, vp, JSVAL_VOID); return ok; #undef LINE_BUF_LEN } static JSBool -Tracing(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +Tracing(JSContext *cx, uintN argc, jsval *vp) { FILE *file; if (argc == 0) { - *rval = BOOLEAN_TO_JSVAL(cx->tracefp != 0); + *vp = BOOLEAN_TO_JSVAL(cx->tracefp != 0); return JS_TRUE; } + jsval *argv = JS_ARGV(cx, vp); switch (JS_TypeOfValue(cx, argv[0])) { case JSTYPE_NUMBER: case JSTYPE_BOOLEAN: { JSBool bval; JS_ValueToBoolean(cx, argv[0], &bval); file = bval ? stderr : NULL; break; } @@ -2107,16 +2127,17 @@ Tracing(JSContext *cx, JSObject *obj, ui } default: goto bad_argument; } if (cx->tracefp && cx->tracefp != stderr) fclose((FILE *)cx->tracefp); cx->tracefp = file; cx->tracePrevPc = NULL; + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; bad_argument: JSString *str = JS_ValueToString(cx, argv[0]); if (!str) return JS_FALSE; JS_ReportError(cx, "tracing: illegal argument %s", JS_GetStringBytes(str)); @@ -2129,26 +2150,27 @@ DumpScope(JSContext *cx, JSObject *obj, uintN i = 0; for (JSScopeProperty *sprop = NULL; JS_PropertyIterator(obj, &sprop);) { fprintf(fp, "%3u %p ", i++, (void *) sprop); ((Shape *) sprop)->dump(cx, fp); } } static JSBool -DumpStats(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +DumpStats(JSContext *cx, uintN argc, jsval *vp) { uintN i; JSString *str; const char *bytes; jsid id; JSObject *obj2; JSProperty *prop; Value value; + jsval *argv = JS_ARGV(cx, vp); for (i = 0; i < argc; i++) { str = JS_ValueToString(cx, argv[i]); if (!str) return JS_FALSE; argv[i] = STRING_TO_JSVAL(str); bytes = JS_GetStringBytes(str); if (strcmp(bytes, "arena") == 0) { #ifdef JS_ARENAMETER @@ -2156,16 +2178,17 @@ DumpStats(JSContext *cx, JSObject *obj, #endif } else if (strcmp(bytes, "atom") == 0) { js_DumpAtoms(cx, gOutFile); } else if (strcmp(bytes, "global") == 0) { DumpScope(cx, cx->globalObject, stdout); } else { if (!JS_ValueToId(cx, STRING_TO_JSVAL(str), &id)) return JS_FALSE; + JSObject *obj; if (!js_FindProperty(cx, id, &obj, &obj2, &prop)) return JS_FALSE; if (prop) { obj2->dropProperty(cx, prop); if (!obj->getProperty(cx, id, &value)) return JS_FALSE; } if (!prop || !value.isObjectOrNull()) { @@ -2173,16 +2196,17 @@ DumpStats(JSContext *cx, JSObject *obj, bytes); continue; } obj = value.toObjectOrNull(); if (obj) DumpScope(cx, obj, stdout); } } + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } static JSBool DumpHeap(JSContext *cx, uintN argc, jsval *vp) { char *fileName; jsval v; @@ -2274,24 +2298,25 @@ DumpHeap(JSContext *cx, uintN argc, jsva not_traceable_arg: JS_ReportError(cx, "argument '%s' is not null or a heap-allocated thing", badTraceArg); return JS_FALSE; } JSBool -DumpObject(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +DumpObject(JSContext *cx, uintN argc, jsval *vp) { JSObject *arg0 = NULL; - if (!JS_ConvertArguments(cx, argc, argv, "o", &arg0)) + if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "o", &arg0)) return JS_FALSE; js_DumpObject(arg0); + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } #endif /* DEBUG */ #ifdef TEST_CVTARGS #include <ctype.h> @@ -2366,34 +2391,34 @@ ZZ_formatter(JSContext *cx, const char * } *vpp = vp + 2; *app = ap; printf("leaving ZZ_formatter"); return JS_TRUE; } static JSBool -ConvertArgs(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +ConvertArgs(JSContext *cx, uintN argc, jsval *vp) { JSBool b = JS_FALSE; jschar c = 0; int32 i = 0, j = 0; uint32 u = 0; jsdouble d = 0, I = 0, re = 0, im = 0; char *s = NULL; JSString *str = NULL; jschar *w = NULL; JSObject *obj2 = NULL; JSFunction *fun = NULL; jsval v = JSVAL_VOID; JSBool ok; if (!JS_AddArgumentFormatter(cx, "ZZ", ZZ_formatter)) return JS_FALSE; - ok = JS_ConvertArguments(cx, argc, argv, "b/ciujdIsSWofvZZ*", + ok = JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "b/ciujdIsSWofvZZ*", &b, &c, &i, &u, &j, &d, &I, &s, &str, &w, &obj2, &fun, &v, &re, &im); JS_RemoveArgumentFormatter(cx, "ZZ"); if (!ok) return JS_FALSE; fprintf(gOutFile, "b %u, c %x (%c), i %ld, u %lu, j %ld\n", b, c, (char)c, i, u, j); @@ -2409,16 +2434,17 @@ ConvertArgs(JSContext *cx, JSObject *obj } fprintf(gOutFile, "d %g, I %g, s %s, S %s, W %s, obj %s, fun %s\n" "v %s, re %g, im %g\n", d, I, s, str ? JS_GetStringBytes(str) : "", EscapeWideString(w), obj2string.getBytes(), fun ? func : "", valueString.getBytes(), re, im); + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } #endif static JSBool BuildDate(JSContext *cx, uintN argc, jsval *vp) { char version[20] = "\n"; @@ -2426,21 +2452,23 @@ BuildDate(JSContext *cx, uintN argc, jsv sprintf(version, " for version %d\n", JS_VERSION); #endif fprintf(gOutFile, "built on %s at %s%s", __DATE__, __TIME__, version); *vp = JSVAL_VOID; return JS_TRUE; } static JSBool -Clear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +Clear(JSContext *cx, uintN argc, jsval *vp) { - if (argc != 0 && !JS_ValueToObject(cx, argv[0], &obj)) + JSObject *obj; + if (argc != 0 && !JS_ValueToObject(cx, JS_ARGV(cx, vp)[0], &obj)) return JS_FALSE; JS_ClearScope(cx, obj); + JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } static JSBool Intern(JSContext *cx, uintN argc, jsval *vp) { JSString *str; @@ -2451,20 +2479,24 @@ Intern(JSContext *cx, uintN argc, jsval JS_GetStringLength(str))) { return JS_FALSE; } *vp = JSVAL_VOID; return JS_TRUE; } static JSBool -Clone(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +Clone(JSContext *cx, uintN argc, jsval *vp) { JSObject *funobj, *parent, *clone; + if (!argc) + return JS_FALSE; + + jsval *argv = JS_ARGV(cx, vp); if (VALUE_IS_FUNCTION(cx, argv[0])) { funobj = JSVAL_TO_OBJECT(argv[0]); } else { JSFunction *fun = JS_ValueToFunction(cx, argv[0]); if (!fun) return JS_FALSE; funobj = JS_GetFunctionObject(fun); } @@ -2472,28 +2504,29 @@ Clone(JSContext *cx, JSObject *obj, uint if (!JS_ValueToObject(cx, argv[1], &parent)) return JS_FALSE; } else { parent = JS_GetParent(cx, funobj); } clone = JS_CloneFunctionObject(cx, funobj, parent); if (!clone) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(clone); + *vp = OBJECT_TO_JSVAL(clone); return JS_TRUE; } static JSBool -Seal(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +Seal(JSContext *cx, uintN argc, jsval *vp) { JSObject *target; JSBool deep = JS_FALSE; - if (!JS_ConvertArguments(cx, argc, argv, "o/b", &target, &deep)) + if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "o/b", &target, &deep)) return JS_FALSE; + JS_SET_RVAL(cx, vp, JSVAL_VOID); if (!target) return JS_TRUE; return JS_SealObject(cx, target, deep); } static JSBool GetPDA(JSContext *cx, uintN argc, jsval *vp) { @@ -2565,20 +2598,19 @@ ToInt32(JSContext *cx, uintN argc, jsval int32 i; if (!JS_ValueToInt32(cx, argc == 0 ? JSVAL_VOID : vp[2], &i)) return JS_FALSE; return JS_NewNumberValue(cx, i, vp); } static JSBool -StringsAreUTF8(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +StringsAreUTF8(JSContext *cx, uintN argc, jsval *vp) { - *rval = JS_CStringsAreUTF8() ? JSVAL_TRUE : JSVAL_FALSE; + *vp = JS_CStringsAreUTF8() ? JSVAL_TRUE : JSVAL_FALSE; return JS_TRUE; } static JSBool StackQuota(JSContext *cx, uintN argc, jsval *vp) { uint32 n; @@ -2592,24 +2624,24 @@ StackQuota(JSContext *cx, uintN argc, js return JS_TRUE; } static const char* badUTF8 = "...\xC0..."; static const char* bigUTF8 = "...\xFB\xBF\xBF\xBF\xBF..."; static const jschar badSurrogate[] = { 'A', 'B', 'C', 0xDEEE, 'D', 'E', 0 }; static JSBool -TestUTF8(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +TestUTF8(JSContext *cx, uintN argc, jsval *vp) { int32 mode = 1; jschar chars[20]; size_t charsLength = 5; char bytes[20]; size_t bytesLength = 20; - if (argc && !JS_ValueToInt32(cx, *argv, &mode)) + if (argc && !JS_ValueToInt32(cx, *JS_ARGV(cx, vp), &mode)) return JS_FALSE; /* The following throw errors if compiled with UTF-8. */ switch (mode) { /* mode 1: malformed UTF-8 string. */ case 1: JS_NewStringCopyZ(cx, badUTF8); break; @@ -2624,21 +2656,22 @@ TestUTF8(JSContext *cx, JSObject *obj, u /* mode 4: use a too small buffer. */ case 4: JS_DecodeBytes(cx, "1234567890", 10, chars, &charsLength); break; default: JS_ReportError(cx, "invalid mode parameter"); return JS_FALSE; } + JS_SET_RVAL(cx, vp, JSVAL_VOID); return !JS_IsExceptionPending (cx); } static JSBool -ThrowError(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +ThrowError(JSContext *cx, uintN argc, jsval *vp) { JS_ReportError(cx, "This is an error"); return JS_FALSE; } #define LAZY_STANDARD_CLASSES /* A class for easily testing the inner/outer object callbacks. */ @@ -3112,22 +3145,21 @@ NewSandbox(JSContext *cx, bool lazy, boo AutoObjectRooter objroot(cx, obj); if (!cx->compartment->wrap(cx, objroot.addr())) return NULL; return objroot.object(); } static JSBool -EvalInContext(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +EvalInContext(JSContext *cx, uintN argc, jsval *vp) { JSString *str; JSObject *sobj = NULL; - if (!JS_ConvertArguments(cx, argc, argv, "S / o", &str, &sobj)) + if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "S / o", &str, &sobj)) return false; const jschar *src = JS_GetStringChars(str); size_t srclen = JS_GetStringLength(str); bool split = false, lazy = false; if (srclen == 4) { if (src[0] == 'l' && src[1] == 'a' && src[2] == 'z' && src[3] == 'y') { lazy = true; @@ -3141,17 +3173,17 @@ EvalInContext(JSContext *cx, JSObject *o } if (!sobj) { sobj = NewSandbox(cx, lazy, split); if (!sobj) return false; } - *rval = OBJECT_TO_JSVAL(sobj); + *vp = OBJECT_TO_JSVAL(sobj); if (srclen == 0) return true; JSStackFrame *fp = JS_GetScriptedCaller(cx, NULL); { JSAutoCrossCompartmentCall ac; if (JSCrossCompartmentWrapper::isCrossCompartmentWrapper(sobj)) { sobj = sobj->unwrap(); @@ -3164,21 +3196,21 @@ EvalInContext(JSContext *cx, JSObject *o return false; if (!(sobj->getClass()->flags & JSCLASS_IS_GLOBAL)) { JS_ReportError(cx, "Invalid scope argument to evalcx"); return false; } if (!JS_EvaluateUCScript(cx, sobj, src, srclen, fp->getScript()->filename, JS_PCToLineNumber(cx, fp->getScript(), fp->pc(cx)), - rval)) { + vp)) { return false; } } - return cx->compartment->wrap(cx, Valueify(rval)); + return cx->compartment->wrap(cx, Valueify(vp)); } static JSBool EvalInFrame(JSContext *cx, uintN argc, jsval *vp) { jsval *argv = JS_ARGV(cx, vp); if (argc < 2 || !JSVAL_IS_INT(argv[0]) || @@ -3913,28 +3945,31 @@ Parse(JSContext *cx, uintN argc, jsval * NULL, "<string>", 0); if (!parser.parse(NULL)) return JS_FALSE; JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; } static JSBool -Snarf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +Snarf(JSContext *cx, uintN argc, jsval *vp) { JSString *str; const char *filename; const char *pathname; JSStackFrame *fp; JSBool ok; size_t cc, len; char *buf; FILE *file; - str = JS_ValueToString(cx, argv[0]); + if (!argc) + return JS_FALSE; + + str = JS_ValueToString(cx, JS_ARGV(cx, vp)[0]); if (!str) return JS_FALSE; filename = JS_GetStringBytes(str); /* Get the currently executing script's name. */ fp = JS_GetScriptedCaller(cx, NULL); JS_ASSERT(fp && fp->getScript()->filename); #ifdef XP_UNIX @@ -3981,44 +4016,49 @@ Snarf(JSContext *cx, JSObject *obj, uint