зеркало из https://github.com/mozilla/pjs.git
merge m-c to devtools
This commit is contained in:
Коммит
86c8e2019d
|
@ -299,6 +299,8 @@ pref("browser.urlbar.match.url", "@");
|
||||||
// 2 = only bookmarks, 3 = visited bookmarks, 1+16 = history matching in the url
|
// 2 = only bookmarks, 3 = visited bookmarks, 1+16 = history matching in the url
|
||||||
pref("browser.urlbar.default.behavior", 0);
|
pref("browser.urlbar.default.behavior", 0);
|
||||||
|
|
||||||
|
pref("browser.urlbar.formatting.enabled", true);
|
||||||
|
|
||||||
// Number of milliseconds to wait for the http headers (and thus
|
// Number of milliseconds to wait for the http headers (and thus
|
||||||
// the Content-Disposition filename) before giving up and falling back to
|
// the Content-Disposition filename) before giving up and falling back to
|
||||||
// picking a filename without that info in hand so that the user sees some
|
// picking a filename without that info in hand so that the user sees some
|
||||||
|
|
|
@ -222,6 +222,7 @@ _BROWSER_FILES = \
|
||||||
browser_tabfocus.js \
|
browser_tabfocus.js \
|
||||||
browser_tabs_isActive.js \
|
browser_tabs_isActive.js \
|
||||||
browser_tabs_owner.js \
|
browser_tabs_owner.js \
|
||||||
|
browser_urlHighlight.js \
|
||||||
browser_visibleFindSelection.js \
|
browser_visibleFindSelection.js \
|
||||||
browser_visibleTabs.js \
|
browser_visibleTabs.js \
|
||||||
browser_visibleTabs_contextMenu.js \
|
browser_visibleTabs_contextMenu.js \
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
function testVal(aExpected) {
|
||||||
|
gURLBar.value = aExpected.replace(/[<>]/g, "");
|
||||||
|
|
||||||
|
let selectionController = gURLBar.editor.selectionController;
|
||||||
|
let selection = selectionController.getSelection(selectionController.SELECTION_URLSECONDARY);
|
||||||
|
let value = gURLBar.editor.rootElement.textContent;
|
||||||
|
let result = "";
|
||||||
|
for (let i = 0; i < selection.rangeCount; i++) {
|
||||||
|
let range = selection.getRangeAt(i).toString();
|
||||||
|
let pos = value.indexOf(range);
|
||||||
|
result += value.substring(0, pos) + "<" + range + ">";
|
||||||
|
value = value.substring(pos + range.length);
|
||||||
|
}
|
||||||
|
result += value;
|
||||||
|
is(result, aExpected);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
const prefname = "browser.urlbar.formatting.enabled";
|
||||||
|
|
||||||
|
registerCleanupFunction(function () {
|
||||||
|
Services.prefs.clearUserPref(prefname);
|
||||||
|
URLBarSetURI();
|
||||||
|
});
|
||||||
|
|
||||||
|
Services.prefs.setBoolPref(prefname, true);
|
||||||
|
|
||||||
|
testVal("<http://>mozilla.org");
|
||||||
|
testVal("<http://>mozilla.org</>");
|
||||||
|
testVal("<http://>mözilla.org</>");
|
||||||
|
testVal("<http://>mozilla.imaginatory</>");
|
||||||
|
testVal("<http://www.>mozilla.org</>");
|
||||||
|
testVal("<http://sub.>mozilla.org</>");
|
||||||
|
testVal("<http://sub1.sub2.sub3.>mozilla.org</>");
|
||||||
|
testVal("<http://ftp.>mozilla.org</>");
|
||||||
|
testVal("<ftp://ftp.>mozilla.org</>");
|
||||||
|
|
||||||
|
testVal("<https://sub.>mozilla.org</>");
|
||||||
|
testVal("<https://sub1.sub2.sub3.>mozilla.org</>");
|
||||||
|
testVal("<https://user:pass@sub1.sub2.sub3.>mozilla.org</>");
|
||||||
|
testVal("<https://user:pass@>mozilla.org</>");
|
||||||
|
|
||||||
|
testVal("<http://>mozilla.org</file.ext>");
|
||||||
|
testVal("<http://>mozilla.org</sub/file.ext>");
|
||||||
|
testVal("<http://>mozilla.org</sub/file.ext?foo>");
|
||||||
|
testVal("<http://>mozilla.org</sub/file.ext?foo&bar>");
|
||||||
|
testVal("<http://>mozilla.org</sub/file.ext?foo&bar#top>");
|
||||||
|
|
||||||
|
testVal("<http://sub.>mozilla.org<:666/file.ext>");
|
||||||
|
|
||||||
|
testVal("mailto:admin@mozilla.org");
|
||||||
|
testVal("gopher://mozilla.org/");
|
||||||
|
testVal("about:config");
|
||||||
|
|
||||||
|
Services.prefs.setBoolPref(prefname, false);
|
||||||
|
|
||||||
|
testVal("http://mozilla.org/");
|
||||||
|
}
|
|
@ -90,6 +90,7 @@
|
||||||
this.doubleClickSelectsAll = this._prefs.getBoolPref("doubleClickSelectsAll");
|
this.doubleClickSelectsAll = this._prefs.getBoolPref("doubleClickSelectsAll");
|
||||||
this.completeDefaultIndex = this._prefs.getBoolPref("autoFill");
|
this.completeDefaultIndex = this._prefs.getBoolPref("autoFill");
|
||||||
this.timeout = this._prefs.getIntPref("delay");
|
this.timeout = this._prefs.getIntPref("delay");
|
||||||
|
this._formattingEnabled = this._prefs.getBoolPref("formatting.enabled");
|
||||||
|
|
||||||
this._urlTooltip = document.getElementById("urlTooltip");
|
this._urlTooltip = document.getElementById("urlTooltip");
|
||||||
|
|
||||||
|
@ -179,6 +180,46 @@
|
||||||
]]></body>
|
]]></body>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
|
<field name="_formattingEnabled">true</field>
|
||||||
|
<method name="formatValue">
|
||||||
|
<body><![CDATA[
|
||||||
|
if (!this._formattingEnabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let controller = this.editor.selectionController;
|
||||||
|
let selection = controller.getSelection(controller.SELECTION_URLSECONDARY);
|
||||||
|
selection.removeAllRanges();
|
||||||
|
|
||||||
|
let textNode = this.editor.rootElement.firstChild;
|
||||||
|
let value = textNode.textContent;
|
||||||
|
let matchedURL = value.match(/^((?:http|https|ftp):\/\/(?:[^\/]+@)?)([^\/:]+)/);
|
||||||
|
if (!matchedURL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let [, preDomain, domain] = matchedURL;
|
||||||
|
let baseDomain = domain;
|
||||||
|
try {
|
||||||
|
baseDomain = Services.eTLD.getBaseDomainFromHost(domain);
|
||||||
|
} catch (e) {}
|
||||||
|
let segments = function (s) s.replace(/[^.]*/g, "").length + 1;
|
||||||
|
let subSegments = segments(domain) - segments(baseDomain);
|
||||||
|
let subDomain = domain.match(new RegExp("(?:[^.]*\.){" + subSegments + "}"))[0];
|
||||||
|
|
||||||
|
let range = document.createRange();
|
||||||
|
range.setStart(textNode, 0);
|
||||||
|
range.setEnd(textNode, preDomain.length + subDomain.length);
|
||||||
|
selection.addRange(range);
|
||||||
|
|
||||||
|
let startRest = preDomain.length + domain.length;
|
||||||
|
if (startRest < value.length) {
|
||||||
|
range = document.createRange();
|
||||||
|
range.setStart(textNode, startRest);
|
||||||
|
range.setEnd(textNode, value.length);
|
||||||
|
selection.addRange(range);
|
||||||
|
}
|
||||||
|
]]></body>
|
||||||
|
</method>
|
||||||
|
|
||||||
<method name="handleRevert">
|
<method name="handleRevert">
|
||||||
<body><![CDATA[
|
<body><![CDATA[
|
||||||
var isScrolling = this.popupOpen;
|
var isScrolling = this.popupOpen;
|
||||||
|
@ -494,6 +535,9 @@
|
||||||
case "delay":
|
case "delay":
|
||||||
this.timeout = this._prefs.getIntPref(aData);
|
this.timeout = this._prefs.getIntPref(aData);
|
||||||
break;
|
break;
|
||||||
|
case "formatting.enabled":
|
||||||
|
this._formattingEnabled = this._prefs.getBoolPref(aData);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]]></body>
|
]]></body>
|
||||||
|
|
|
@ -54,10 +54,19 @@ namespace std {
|
||||||
#if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)
|
#if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)
|
||||||
/* Instantiate these templates to avoid GLIBCXX_3.4.14 symbol versions
|
/* Instantiate these templates to avoid GLIBCXX_3.4.14 symbol versions
|
||||||
* in debug builds */
|
* in debug builds */
|
||||||
template char *basic_string<char, char_traits<char>, allocator<char> >::_S_construct_aux_2(size_type, char, allocator<char> const&);
|
template char *string::_S_construct_aux_2(size_type, char, allocator<char> const&);
|
||||||
template wchar_t *basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >::_S_construct_aux_2(size_type, wchar_t, allocator<wchar_t> const&);
|
#ifdef _GLIBCXX_USE_WCHAR_T
|
||||||
#endif
|
template wchar_t *wstring::_S_construct_aux_2(size_type, wchar_t, allocator<wchar_t> const&);
|
||||||
#endif
|
#endif /* _GLIBCXX_USE_WCHAR_T */
|
||||||
|
#ifdef __GXX_EXPERIMENTAL_CXX0X__
|
||||||
|
template string::basic_string(string&&);
|
||||||
|
template string& string::operator=(string&&);
|
||||||
|
template wstring::basic_string(wstring&&);
|
||||||
|
template wstring& wstring::operator=(wstring&&);
|
||||||
|
template wstring& wstring::assign(wstring&&);
|
||||||
|
#endif /* __GXX_EXPERIMENTAL_CXX0X__ */
|
||||||
|
#endif /* (__GNUC__ == 4) && (__GNUC_MINOR__ >= 5) */
|
||||||
|
#endif /* DEBUG */
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace std __attribute__((visibility("default"))) {
|
namespace std __attribute__((visibility("default"))) {
|
||||||
|
|
|
@ -2963,6 +2963,11 @@ fi
|
||||||
|
|
||||||
AC_LANG_CPLUSPLUS
|
AC_LANG_CPLUSPLUS
|
||||||
|
|
||||||
|
if test "$GNU_CXX"; then
|
||||||
|
_SAVE_CXXFLAGS=$CXXFLAGS
|
||||||
|
CXXFLAGS="$CXXFLAGS -std=gnu++0x"
|
||||||
|
fi
|
||||||
|
|
||||||
dnl Check for usable char16_t (2 bytes, unsigned)
|
dnl Check for usable char16_t (2 bytes, unsigned)
|
||||||
dnl (we might not need the unsignedness check anymore)
|
dnl (we might not need the unsignedness check anymore)
|
||||||
AC_CACHE_CHECK(for usable char16_t (2 bytes, unsigned),
|
AC_CACHE_CHECK(for usable char16_t (2 bytes, unsigned),
|
||||||
|
@ -2978,6 +2983,8 @@ AC_CACHE_CHECK(for usable char16_t (2 bytes, unsigned),
|
||||||
if test "$ac_cv_have_usable_char16_t" = "yes"; then
|
if test "$ac_cv_have_usable_char16_t" = "yes"; then
|
||||||
AC_DEFINE(HAVE_CPP_CHAR16_T)
|
AC_DEFINE(HAVE_CPP_CHAR16_T)
|
||||||
HAVE_CPP_CHAR16_T=1
|
HAVE_CPP_CHAR16_T=1
|
||||||
|
else
|
||||||
|
CXXFLAGS="$_SAVE_CXXFLAGS"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
dnl Check for usable wchar_t (2 bytes, unsigned)
|
dnl Check for usable wchar_t (2 bytes, unsigned)
|
||||||
|
|
|
@ -51,7 +51,7 @@ interface nsIDOMNode;
|
||||||
interface nsISelection;
|
interface nsISelection;
|
||||||
interface nsISelectionDisplay;
|
interface nsISelectionDisplay;
|
||||||
|
|
||||||
[scriptable, uuid(ff11fa25-788f-444f-8f69-dcdf14348fb3)]
|
[scriptable, uuid(e0dd9365-470b-4ee8-b644-54add1c4c73f)]
|
||||||
interface nsISelectionController : nsISelectionDisplay
|
interface nsISelectionController : nsISelectionDisplay
|
||||||
{
|
{
|
||||||
const short SELECTION_NONE=0;
|
const short SELECTION_NONE=0;
|
||||||
|
@ -63,7 +63,8 @@ interface nsISelectionController : nsISelectionDisplay
|
||||||
const short SELECTION_IME_SELECTEDCONVERTEDTEXT=32;
|
const short SELECTION_IME_SELECTEDCONVERTEDTEXT=32;
|
||||||
const short SELECTION_ACCESSIBILITY=64; // For accessibility API usage
|
const short SELECTION_ACCESSIBILITY=64; // For accessibility API usage
|
||||||
const short SELECTION_FIND=128;
|
const short SELECTION_FIND=128;
|
||||||
const short NUM_SELECTIONTYPES=9;
|
const short SELECTION_URLSECONDARY=256;
|
||||||
|
const short NUM_SELECTIONTYPES=10;
|
||||||
|
|
||||||
const short SELECTION_ANCHOR_REGION = 0;
|
const short SELECTION_ANCHOR_REGION = 0;
|
||||||
const short SELECTION_FOCUS_REGION = 1;
|
const short SELECTION_FOCUS_REGION = 1;
|
||||||
|
|
|
@ -179,15 +179,16 @@ public:
|
||||||
{}
|
{}
|
||||||
|
|
||||||
SVGNumberListAndInfo(nsSVGElement *aElement)
|
SVGNumberListAndInfo(nsSVGElement *aElement)
|
||||||
: mElement(aElement)
|
: mElement(do_GetWeakReference(static_cast<nsINode*>(aElement)))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void SetInfo(nsSVGElement *aElement) {
|
void SetInfo(nsSVGElement *aElement) {
|
||||||
mElement = aElement;
|
mElement = do_GetWeakReference(static_cast<nsINode*>(aElement));
|
||||||
}
|
}
|
||||||
|
|
||||||
nsSVGElement* Element() const {
|
nsSVGElement* Element() const {
|
||||||
return mElement; // .get();
|
nsCOMPtr<nsIContent> e = do_QueryReferent(mElement);
|
||||||
|
return static_cast<nsSVGElement*>(e.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult CopyFrom(const SVGNumberListAndInfo& rhs) {
|
nsresult CopyFrom(const SVGNumberListAndInfo& rhs) {
|
||||||
|
@ -218,10 +219,11 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// We must keep a strong reference to our element because we may belong to a
|
// We must keep a weak reference to our element because we may belong to a
|
||||||
// cached baseVal nsSMILValue. See the comments starting at:
|
// cached baseVal nsSMILValue. See the comments starting at:
|
||||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=515116#c15
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=515116#c15
|
||||||
nsRefPtr<nsSVGElement> mElement;
|
// See also https://bugzilla.mozilla.org/show_bug.cgi?id=653497
|
||||||
|
nsWeakPtr mElement;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
@ -63,6 +63,7 @@
|
||||||
#include "prmem.h"
|
#include "prmem.h"
|
||||||
#include "jsapi.h" // for JSAutoRequest
|
#include "jsapi.h" // for JSAutoRequest
|
||||||
#include "jsdbgapi.h" // for JS_ClearWatchPointsForObject
|
#include "jsdbgapi.h" // for JS_ClearWatchPointsForObject
|
||||||
|
#include "jsfriendapi.h" // for JS_GetFrameScopeChainRaw
|
||||||
#include "nsReadableUtils.h"
|
#include "nsReadableUtils.h"
|
||||||
#include "nsDOMClassInfo.h"
|
#include "nsDOMClassInfo.h"
|
||||||
#include "nsJSEnvironment.h"
|
#include "nsJSEnvironment.h"
|
||||||
|
@ -5797,13 +5798,13 @@ nsGlobalWindow::CallerInnerWindow()
|
||||||
JSStackFrame *fp = nsnull;
|
JSStackFrame *fp = nsnull;
|
||||||
JS_FrameIterator(cx, &fp);
|
JS_FrameIterator(cx, &fp);
|
||||||
if (fp) {
|
if (fp) {
|
||||||
while (fp->isDummyFrame()) {
|
while (!JS_IsScriptFrame(cx, fp)) {
|
||||||
if (!JS_FrameIterator(cx, &fp))
|
if (!JS_FrameIterator(cx, &fp))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fp)
|
if (fp)
|
||||||
scope = &fp->scopeChain();
|
scope = JS_GetFrameScopeChainRaw(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!scope)
|
if (!scope)
|
||||||
|
|
|
@ -116,6 +116,8 @@
|
||||||
|
|
||||||
#include "mozilla/FunctionTimer.h"
|
#include "mozilla/FunctionTimer.h"
|
||||||
|
|
||||||
|
using namespace mozilla;
|
||||||
|
|
||||||
const size_t gStackSize = 8192;
|
const size_t gStackSize = 8192;
|
||||||
|
|
||||||
#ifdef PR_LOGGING
|
#ifdef PR_LOGGING
|
||||||
|
@ -1884,8 +1886,8 @@ nsJSContext::CallEventHandler(nsISupports* aTarget, void *aScope, void *aHandler
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
js::LazilyConstructed<nsAutoPoolRelease> poolRelease;
|
Maybe<nsAutoPoolRelease> poolRelease;
|
||||||
js::LazilyConstructed<js::AutoArrayRooter> tvr;
|
Maybe<js::AutoArrayRooter> tvr;
|
||||||
|
|
||||||
// Use |target| as the scope for wrapping the arguments, since aScope is
|
// Use |target| as the scope for wrapping the arguments, since aScope is
|
||||||
// the safe scope in many cases, which isn't very useful. Wrapping aTarget
|
// the safe scope in many cases, which isn't very useful. Wrapping aTarget
|
||||||
|
@ -2373,8 +2375,8 @@ nsJSContext::SetProperty(void *aTarget, const char *aPropName, nsISupports *aArg
|
||||||
|
|
||||||
JSAutoRequest ar(mContext);
|
JSAutoRequest ar(mContext);
|
||||||
|
|
||||||
js::LazilyConstructed<nsAutoPoolRelease> poolRelease;
|
Maybe<nsAutoPoolRelease> poolRelease;
|
||||||
js::LazilyConstructed<js::AutoArrayRooter> tvr;
|
Maybe<js::AutoArrayRooter> tvr;
|
||||||
|
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
rv = ConvertSupportsTojsvals(aArgs, GetNativeGlobal(), &argc,
|
rv = ConvertSupportsTojsvals(aArgs, GetNativeGlobal(), &argc,
|
||||||
|
@ -2414,8 +2416,8 @@ nsJSContext::ConvertSupportsTojsvals(nsISupports *aArgs,
|
||||||
void *aScope,
|
void *aScope,
|
||||||
PRUint32 *aArgc,
|
PRUint32 *aArgc,
|
||||||
jsval **aArgv,
|
jsval **aArgv,
|
||||||
js::LazilyConstructed<nsAutoPoolRelease> &aPoolRelease,
|
Maybe<nsAutoPoolRelease> &aPoolRelease,
|
||||||
js::LazilyConstructed<js::AutoArrayRooter> &aRooter)
|
Maybe<js::AutoArrayRooter> &aRooter)
|
||||||
{
|
{
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,9 @@ class nsIXPConnectJSObjectHolder;
|
||||||
class nsAutoPoolRelease;
|
class nsAutoPoolRelease;
|
||||||
namespace js {
|
namespace js {
|
||||||
class AutoArrayRooter;
|
class AutoArrayRooter;
|
||||||
template <class> class LazilyConstructed;
|
}
|
||||||
|
namespace mozilla {
|
||||||
|
template <class> class Maybe;
|
||||||
}
|
}
|
||||||
|
|
||||||
class nsJSContext : public nsIScriptContext,
|
class nsJSContext : public nsIScriptContext,
|
||||||
|
@ -205,8 +207,8 @@ protected:
|
||||||
void *aScope,
|
void *aScope,
|
||||||
PRUint32 *aArgc,
|
PRUint32 *aArgc,
|
||||||
jsval **aArgv,
|
jsval **aArgv,
|
||||||
js::LazilyConstructed<nsAutoPoolRelease> &aPoolRelease,
|
mozilla::Maybe<nsAutoPoolRelease> &aPoolRelease,
|
||||||
js::LazilyConstructed<js::AutoArrayRooter> &aRooter);
|
mozilla::Maybe<js::AutoArrayRooter> &aRooter);
|
||||||
|
|
||||||
nsresult AddSupportsPrimitiveTojsvals(nsISupports *aArg, jsval *aArgv);
|
nsresult AddSupportsPrimitiveTojsvals(nsISupports *aArg, jsval *aArgv);
|
||||||
|
|
||||||
|
|
|
@ -46,8 +46,6 @@
|
||||||
#include "base/basictypes.h"
|
#include "base/basictypes.h"
|
||||||
|
|
||||||
#include "jsapi.h"
|
#include "jsapi.h"
|
||||||
#include "jscntxt.h"
|
|
||||||
#include "jsdbgapi.h"
|
|
||||||
#include "jsprf.h"
|
#include "jsprf.h"
|
||||||
|
|
||||||
#include "xpcpublic.h"
|
#include "xpcpublic.h"
|
||||||
|
@ -406,13 +404,14 @@ GC(JSContext *cx,
|
||||||
jsval *vp)
|
jsval *vp)
|
||||||
{
|
{
|
||||||
JSRuntime *rt;
|
JSRuntime *rt;
|
||||||
uint32 preBytes;
|
uint32 preBytes, postBytes;
|
||||||
|
|
||||||
rt = cx->runtime;
|
rt = JS_GetRuntime(cx);
|
||||||
preBytes = rt->gcBytes;
|
preBytes = JS_GetGCParameter(rt, JSGC_BYTES);
|
||||||
JS_GC(cx);
|
JS_GC(cx);
|
||||||
|
postBytes = JS_GetGCParameter(rt, JSGC_BYTES);
|
||||||
fprintf(stdout, "before %lu, after %lu, break %08lx\n",
|
fprintf(stdout, "before %lu, after %lu, break %08lx\n",
|
||||||
(unsigned long)preBytes, (unsigned long)rt->gcBytes,
|
(unsigned long)preBytes, (unsigned long)postBytes,
|
||||||
#ifdef XP_UNIX
|
#ifdef XP_UNIX
|
||||||
(unsigned long)sbrk(0)
|
(unsigned long)sbrk(0)
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -40,7 +40,6 @@
|
||||||
#include "jscntxt.h"
|
#include "jscntxt.h"
|
||||||
|
|
||||||
#include "jsapi.h"
|
#include "jsapi.h"
|
||||||
#include "jstl.h"
|
|
||||||
#include "jshashtable.h"
|
#include "jshashtable.h"
|
||||||
|
|
||||||
#include "mozilla/jetpack/JetpackActorCommon.h"
|
#include "mozilla/jetpack/JetpackActorCommon.h"
|
||||||
|
@ -51,15 +50,7 @@
|
||||||
|
|
||||||
#include "nsJSUtils.h"
|
#include "nsJSUtils.h"
|
||||||
|
|
||||||
using mozilla::jetpack::JetpackActorCommon;
|
using namespace mozilla::jetpack;
|
||||||
using mozilla::jetpack::PHandleParent;
|
|
||||||
using mozilla::jetpack::HandleParent;
|
|
||||||
using mozilla::jetpack::PHandleChild;
|
|
||||||
using mozilla::jetpack::HandleChild;
|
|
||||||
using mozilla::jetpack::KeyValue;
|
|
||||||
using mozilla::jetpack::PrimVariant;
|
|
||||||
using mozilla::jetpack::CompVariant;
|
|
||||||
using mozilla::jetpack::Variant;
|
|
||||||
|
|
||||||
class JetpackActorCommon::OpaqueSeenType
|
class JetpackActorCommon::OpaqueSeenType
|
||||||
{
|
{
|
||||||
|
@ -176,7 +167,7 @@ JetpackActorCommon::jsval_to_CompVariant(JSContext* cx, JSType type, jsval from,
|
||||||
if (type != JSTYPE_OBJECT)
|
if (type != JSTYPE_OBJECT)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
js::LazilyConstructed<OpaqueSeenType> lost;
|
Maybe<OpaqueSeenType> lost;
|
||||||
if (!seen) {
|
if (!seen) {
|
||||||
lost.construct();
|
lost.construct();
|
||||||
seen = lost.addr();
|
seen = lost.addr();
|
||||||
|
@ -337,7 +328,7 @@ JetpackActorCommon::jsval_from_CompVariant(JSContext* cx,
|
||||||
jsval* to,
|
jsval* to,
|
||||||
OpaqueSeenType* seen)
|
OpaqueSeenType* seen)
|
||||||
{
|
{
|
||||||
js::LazilyConstructed<OpaqueSeenType> lost;
|
Maybe<OpaqueSeenType> lost;
|
||||||
if (!seen) {
|
if (!seen) {
|
||||||
lost.construct();
|
lost.construct();
|
||||||
seen = lost.addr();
|
seen = lost.addr();
|
||||||
|
|
|
@ -181,6 +181,7 @@ CPPSRCS = \
|
||||||
jsxml.cpp \
|
jsxml.cpp \
|
||||||
prmjtime.cpp \
|
prmjtime.cpp \
|
||||||
sharkctl.cpp \
|
sharkctl.cpp \
|
||||||
|
Stack.cpp \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
INSTALLED_HEADERS = \
|
INSTALLED_HEADERS = \
|
||||||
|
@ -267,6 +268,20 @@ INSTALLED_HEADERS = \
|
||||||
prmjtime.h \
|
prmjtime.h \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
|
###############################################
|
||||||
|
# BEGIN include sources for the vm subdirectory
|
||||||
|
#
|
||||||
|
VPATH += \
|
||||||
|
$(srcdir)/vm \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
EXPORTS_NAMESPACES = vm
|
||||||
|
|
||||||
|
EXPORTS_vm = \
|
||||||
|
Stack.h \
|
||||||
|
StringObject.h \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
###############################################
|
###############################################
|
||||||
# BEGIN include sources for low-level code shared with Gecko
|
# BEGIN include sources for low-level code shared with Gecko
|
||||||
#
|
#
|
||||||
|
@ -274,9 +289,10 @@ VPATH += \
|
||||||
$(srcdir)/../../mfbt \
|
$(srcdir)/../../mfbt \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
EXPORTS_NAMESPACES = mozilla
|
EXPORTS_NAMESPACES += mozilla
|
||||||
|
|
||||||
EXPORTS_mozilla = \
|
EXPORTS_mozilla = \
|
||||||
|
Types.h \
|
||||||
Util.h \
|
Util.h \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
|
@ -636,7 +652,7 @@ check-malloc-function-usage: $(filter-out %jsalloc.h %jscntxt.h %jsutil.h, $(ALL
|
||||||
|
|
||||||
# We desire these numbers to go down, not up. See "User guide to memory
|
# We desire these numbers to go down, not up. See "User guide to memory
|
||||||
# management within SpiderMonkey" in jsutil.h.
|
# management within SpiderMonkey" in jsutil.h.
|
||||||
$(srcdir)/config/check_source_count.py OffTheBooks:: 53 \
|
$(srcdir)/config/check_source_count.py OffTheBooks:: 52 \
|
||||||
"in Makefile.in" "{cx,rt}->{new_,new_array,malloc_,calloc_,realloc_}" $^
|
"in Makefile.in" "{cx,rt}->{new_,new_array,malloc_,calloc_,realloc_}" $^
|
||||||
# This should go to zero, if possible.
|
# This should go to zero, if possible.
|
||||||
$(srcdir)/config/check_source_count.py UnwantedForeground:: 34 \
|
$(srcdir)/config/check_source_count.py UnwantedForeground:: 34 \
|
||||||
|
@ -713,6 +729,11 @@ export::
|
||||||
|
|
||||||
DEFINES += -DEXPORT_JS_API
|
DEFINES += -DEXPORT_JS_API
|
||||||
|
|
||||||
|
# mfbt is always packed with us, so if we're building a shared object,
|
||||||
|
# we need to declare "exported" mfbt symbols on its behalf when we use
|
||||||
|
# its headers.
|
||||||
|
DEFINES += -DIMPL_MFBT
|
||||||
|
|
||||||
# Some platforms that have stdint.h include it in system headers. So
|
# Some platforms that have stdint.h include it in system headers. So
|
||||||
# to reliably get limit macros defined, we'd always have to define the
|
# to reliably get limit macros defined, we'd always have to define the
|
||||||
# one below before including any header, but that's obscure and
|
# one below before including any header, but that's obscure and
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
var n1 = Number.prototype.toFixed;
|
||||||
|
var s1 = String.prototype.split;
|
||||||
|
delete Number;
|
||||||
|
delete String;
|
||||||
|
|
||||||
|
var n2 = (5).toFixed;
|
||||||
|
var s2 = ("foo").split;
|
||||||
|
|
||||||
|
// Check enumeration doesn't resurrect deleted standard classes
|
||||||
|
for (x in this) {}
|
||||||
|
|
||||||
|
// Ensure the prototypes are shared.
|
||||||
|
var n3 = (5).toFixed;
|
||||||
|
var s3 = ("foo").split;
|
||||||
|
|
||||||
|
assertEq(s1, s2);
|
||||||
|
assertEq(s1, s3);
|
||||||
|
assertEq(n1, n2);
|
||||||
|
assertEq(n1, n3);
|
|
@ -0,0 +1,104 @@
|
||||||
|
function failWrapper(callback) {
|
||||||
|
try {
|
||||||
|
callback(); // this should fail
|
||||||
|
throw "test-error"; // and if it didn't we have a problem`
|
||||||
|
} catch (e) {
|
||||||
|
if (e == "test-error")
|
||||||
|
throw ("Testing error when running " + callback.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
print ("Deleting standard classes");
|
||||||
|
delete Function;
|
||||||
|
delete Object;
|
||||||
|
delete Array;
|
||||||
|
delete Boolean;
|
||||||
|
delete JSON;
|
||||||
|
delete Date;
|
||||||
|
delete Math;
|
||||||
|
delete Number;
|
||||||
|
delete String;
|
||||||
|
delete Regexp;
|
||||||
|
delete XML;
|
||||||
|
delete Reflect;
|
||||||
|
delete Proxy;
|
||||||
|
delete Error;
|
||||||
|
delete Iterator;
|
||||||
|
delete Generator;
|
||||||
|
delete StopIteration;
|
||||||
|
delete Float32Array;
|
||||||
|
delete Float64Array;
|
||||||
|
delete Int16Array;
|
||||||
|
delete Int32Array;
|
||||||
|
delete Int32Array;
|
||||||
|
delete Uint16Array;
|
||||||
|
delete Uint32Array;
|
||||||
|
delete Uint8Array;
|
||||||
|
delete Uint8ClampedArray;
|
||||||
|
delete Weakmap;
|
||||||
|
|
||||||
|
|
||||||
|
print ("Accessing standard classes shouldn't recreate them");
|
||||||
|
failWrapper(function () { Function; });
|
||||||
|
failWrapper(function () { Object; });
|
||||||
|
failWrapper(function () { Array; });
|
||||||
|
failWrapper(function () { Boolean; });
|
||||||
|
failWrapper(function () { JSON; });
|
||||||
|
failWrapper(function () { Date; });
|
||||||
|
failWrapper(function () { Math; });
|
||||||
|
failWrapper(function () { Number; });
|
||||||
|
failWrapper(function () { String; });
|
||||||
|
failWrapper(function () { Regexp; });
|
||||||
|
failWrapper(function () { XML; });
|
||||||
|
failWrapper(function () { Reflect; });
|
||||||
|
failWrapper(function () { Proxy; });
|
||||||
|
failWrapper(function () { Error; });
|
||||||
|
failWrapper(function () { Iterator; });
|
||||||
|
failWrapper(function () { Generator; });
|
||||||
|
failWrapper(function () { StopIteration; });
|
||||||
|
failWrapper(function () { Float32Array; });
|
||||||
|
failWrapper(function () { Float64Array; });
|
||||||
|
failWrapper(function () { Int16Array; });
|
||||||
|
failWrapper(function () { Int32Array; });
|
||||||
|
failWrapper(function () { Int32Array; });
|
||||||
|
failWrapper(function () { Uint16Array; });
|
||||||
|
failWrapper(function () { Uint32Array; });
|
||||||
|
failWrapper(function () { Uint8Array; });
|
||||||
|
failWrapper(function () { Uint8ClampedArray; });
|
||||||
|
failWrapper(function () { Weakmap; });
|
||||||
|
|
||||||
|
|
||||||
|
print ("Enumerate over the global object");
|
||||||
|
for (c in this) {}
|
||||||
|
|
||||||
|
print ("That shouldn't have recreated the standard classes either");
|
||||||
|
failWrapper(function () { Function; });
|
||||||
|
failWrapper(function () { Object; });
|
||||||
|
failWrapper(function () { Array; });
|
||||||
|
failWrapper(function () { Boolean; });
|
||||||
|
failWrapper(function () { JSON; });
|
||||||
|
failWrapper(function () { Date; });
|
||||||
|
failWrapper(function () { Math; });
|
||||||
|
failWrapper(function () { Number; });
|
||||||
|
failWrapper(function () { String; });
|
||||||
|
failWrapper(function () { Regexp; });
|
||||||
|
failWrapper(function () { XML; });
|
||||||
|
failWrapper(function () { Reflect; });
|
||||||
|
failWrapper(function () { Proxy; });
|
||||||
|
failWrapper(function () { Error; });
|
||||||
|
failWrapper(function () { Iterator; });
|
||||||
|
failWrapper(function () { Generator; });
|
||||||
|
failWrapper(function () { StopIteration; });
|
||||||
|
failWrapper(function () { Float32Array; });
|
||||||
|
failWrapper(function () { Float64Array; });
|
||||||
|
failWrapper(function () { Int16Array; });
|
||||||
|
failWrapper(function () { Int32Array; });
|
||||||
|
failWrapper(function () { Int32Array; });
|
||||||
|
failWrapper(function () { Uint16Array; });
|
||||||
|
failWrapper(function () { Uint32Array; });
|
||||||
|
failWrapper(function () { Uint8Array; });
|
||||||
|
failWrapper(function () { Uint8ClampedArray; });
|
||||||
|
failWrapper(function () { Weakmap; });
|
||||||
|
|
||||||
|
print ("success");
|
|
@ -0,0 +1,5 @@
|
||||||
|
// Catch memory leaks when enumerating over the global object.
|
||||||
|
|
||||||
|
for (let z = 1; z <= 16000; ++z) {
|
||||||
|
for each (y in this);
|
||||||
|
}
|
|
@ -112,7 +112,7 @@ MSG_DEF(JSMSG_BAD_SHARP_DEF, 29, 1, JSEXN_ERR, "invalid sharp variable
|
||||||
MSG_DEF(JSMSG_BAD_SHARP_USE, 30, 1, JSEXN_ERR, "invalid sharp variable use #{0}#")
|
MSG_DEF(JSMSG_BAD_SHARP_USE, 30, 1, JSEXN_ERR, "invalid sharp variable use #{0}#")
|
||||||
MSG_DEF(JSMSG_BAD_INSTANCEOF_RHS, 31, 1, JSEXN_TYPEERR, "invalid 'instanceof' operand {0}")
|
MSG_DEF(JSMSG_BAD_INSTANCEOF_RHS, 31, 1, JSEXN_TYPEERR, "invalid 'instanceof' operand {0}")
|
||||||
MSG_DEF(JSMSG_BAD_BYTECODE, 32, 1, JSEXN_INTERNALERR, "unimplemented JavaScript bytecode {0}")
|
MSG_DEF(JSMSG_BAD_BYTECODE, 32, 1, JSEXN_INTERNALERR, "unimplemented JavaScript bytecode {0}")
|
||||||
MSG_DEF(JSMSG_BAD_RADIX, 33, 1, JSEXN_ERR, "illegal radix {0}")
|
MSG_DEF(JSMSG_BAD_RADIX, 33, 0, JSEXN_RANGEERR, "radix must be an integer at least 2 and no greater than 36")
|
||||||
MSG_DEF(JSMSG_PAREN_BEFORE_LET, 34, 0, JSEXN_SYNTAXERR, "missing ( before let head")
|
MSG_DEF(JSMSG_PAREN_BEFORE_LET, 34, 0, JSEXN_SYNTAXERR, "missing ( before let head")
|
||||||
MSG_DEF(JSMSG_CANT_CONVERT, 35, 1, JSEXN_ERR, "can't convert {0} to an integer")
|
MSG_DEF(JSMSG_CANT_CONVERT, 35, 1, JSEXN_ERR, "can't convert {0} to an integer")
|
||||||
MSG_DEF(JSMSG_CYCLIC_VALUE, 36, 1, JSEXN_TYPEERR, "cyclic {0} value")
|
MSG_DEF(JSMSG_CYCLIC_VALUE, 36, 1, JSEXN_TYPEERR, "cyclic {0} value")
|
||||||
|
|
|
@ -90,16 +90,15 @@
|
||||||
#include "jstypedarray.h"
|
#include "jstypedarray.h"
|
||||||
|
|
||||||
#include "jsatominlines.h"
|
#include "jsatominlines.h"
|
||||||
#include "jscntxtinlines.h"
|
|
||||||
#include "jsinterpinlines.h"
|
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
#include "jsscopeinlines.h"
|
#include "jsscopeinlines.h"
|
||||||
#include "jscntxtinlines.h"
|
|
||||||
#include "jsregexpinlines.h"
|
#include "jsregexpinlines.h"
|
||||||
#include "jsscriptinlines.h"
|
#include "jsscriptinlines.h"
|
||||||
#include "jsstrinlines.h"
|
#include "jsstrinlines.h"
|
||||||
#include "assembler/wtf/Platform.h"
|
#include "assembler/wtf/Platform.h"
|
||||||
|
|
||||||
|
#include "vm/Stack-inl.h"
|
||||||
|
|
||||||
#if ENABLE_YARR_JIT
|
#if ENABLE_YARR_JIT
|
||||||
#include "assembler/jit/ExecutableAllocator.h"
|
#include "assembler/jit/ExecutableAllocator.h"
|
||||||
#include "methodjit/Logging.h"
|
#include "methodjit/Logging.h"
|
||||||
|
@ -845,7 +844,7 @@ JS_SetRuntimePrivate(JSRuntime *rt, void *data)
|
||||||
static void
|
static void
|
||||||
StartRequest(JSContext *cx)
|
StartRequest(JSContext *cx)
|
||||||
{
|
{
|
||||||
JSThread *t = cx->thread;
|
JSThread *t = cx->thread();
|
||||||
JS_ASSERT(CURRENT_THREAD_IS_ME(t));
|
JS_ASSERT(CURRENT_THREAD_IS_ME(t));
|
||||||
|
|
||||||
if (t->data.requestDepth) {
|
if (t->data.requestDepth) {
|
||||||
|
@ -855,7 +854,7 @@ StartRequest(JSContext *cx)
|
||||||
AutoLockGC lock(rt);
|
AutoLockGC lock(rt);
|
||||||
|
|
||||||
/* Wait until the GC is finished. */
|
/* Wait until the GC is finished. */
|
||||||
if (rt->gcThread != cx->thread) {
|
if (rt->gcThread != cx->thread()) {
|
||||||
while (rt->gcThread)
|
while (rt->gcThread)
|
||||||
JS_AWAIT_GC_DONE(rt);
|
JS_AWAIT_GC_DONE(rt);
|
||||||
}
|
}
|
||||||
|
@ -879,7 +878,7 @@ StartRequest(JSContext *cx)
|
||||||
static void
|
static void
|
||||||
StopRequest(JSContext *cx)
|
StopRequest(JSContext *cx)
|
||||||
{
|
{
|
||||||
JSThread *t = cx->thread;
|
JSThread *t = cx->thread();
|
||||||
JS_ASSERT(CURRENT_THREAD_IS_ME(t));
|
JS_ASSERT(CURRENT_THREAD_IS_ME(t));
|
||||||
JS_ASSERT(t->data.requestDepth != 0);
|
JS_ASSERT(t->data.requestDepth != 0);
|
||||||
if (t->data.requestDepth != 1) {
|
if (t->data.requestDepth != 1) {
|
||||||
|
@ -947,7 +946,7 @@ JS_PUBLIC_API(jsrefcount)
|
||||||
JS_SuspendRequest(JSContext *cx)
|
JS_SuspendRequest(JSContext *cx)
|
||||||
{
|
{
|
||||||
#ifdef JS_THREADSAFE
|
#ifdef JS_THREADSAFE
|
||||||
JSThread *t = cx->thread;
|
JSThread *t = cx->thread();
|
||||||
JS_ASSERT(CURRENT_THREAD_IS_ME(t));
|
JS_ASSERT(CURRENT_THREAD_IS_ME(t));
|
||||||
|
|
||||||
jsrefcount saveDepth = t->data.requestDepth;
|
jsrefcount saveDepth = t->data.requestDepth;
|
||||||
|
@ -967,7 +966,7 @@ JS_PUBLIC_API(void)
|
||||||
JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth)
|
JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth)
|
||||||
{
|
{
|
||||||
#ifdef JS_THREADSAFE
|
#ifdef JS_THREADSAFE
|
||||||
JSThread *t = cx->thread;
|
JSThread *t = cx->thread();
|
||||||
JS_ASSERT(CURRENT_THREAD_IS_ME(t));
|
JS_ASSERT(CURRENT_THREAD_IS_ME(t));
|
||||||
if (saveDepth == 0)
|
if (saveDepth == 0)
|
||||||
return;
|
return;
|
||||||
|
@ -984,7 +983,7 @@ JS_PUBLIC_API(JSBool)
|
||||||
JS_IsInRequest(JSContext *cx)
|
JS_IsInRequest(JSContext *cx)
|
||||||
{
|
{
|
||||||
#ifdef JS_THREADSAFE
|
#ifdef JS_THREADSAFE
|
||||||
JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
|
JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread()));
|
||||||
return JS_THREAD_DATA(cx)->requestDepth != 0;
|
return JS_THREAD_DATA(cx)->requestDepth != 0;
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
|
@ -1519,7 +1518,7 @@ JS_SetGlobalObject(JSContext *cx, JSObject *obj)
|
||||||
CHECK_REQUEST(cx);
|
CHECK_REQUEST(cx);
|
||||||
|
|
||||||
cx->globalObject = obj;
|
cx->globalObject = obj;
|
||||||
if (!cx->hasfp())
|
if (!cx->running())
|
||||||
cx->resetCompartment();
|
cx->resetCompartment();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1775,8 +1774,7 @@ JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsid id, JSBool *resolved)
|
||||||
if (stdnm->clasp->flags & JSCLASS_IS_ANONYMOUS)
|
if (stdnm->clasp->flags & JSCLASS_IS_ANONYMOUS)
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
|
|
||||||
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(stdnm->clasp);
|
if (IsStandardClassResolved(obj, stdnm->clasp))
|
||||||
if (obj->getReservedSlot(key).isObject())
|
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
|
|
||||||
if (!stdnm->init(cx, obj))
|
if (!stdnm->init(cx, obj))
|
||||||
|
@ -1797,7 +1795,10 @@ JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
|
||||||
assertSameCompartment(cx, obj);
|
assertSameCompartment(cx, obj);
|
||||||
rt = cx->runtime;
|
rt = cx->runtime;
|
||||||
|
|
||||||
/* Check whether we need to bind 'undefined' and define it if so. */
|
/*
|
||||||
|
* Check whether we need to bind 'undefined' and define it if so.
|
||||||
|
* Since ES5 15.1.1.3 undefined can't be deleted.
|
||||||
|
*/
|
||||||
atom = rt->atomState.typeAtoms[JSTYPE_VOID];
|
atom = rt->atomState.typeAtoms[JSTYPE_VOID];
|
||||||
if (!obj->nativeContains(ATOM_TO_JSID(atom)) &&
|
if (!obj->nativeContains(ATOM_TO_JSID(atom)) &&
|
||||||
!obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(),
|
!obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(),
|
||||||
|
@ -1806,12 +1807,12 @@ JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize any classes that have not been resolved yet. */
|
/* Initialize any classes that have not been initialized yet. */
|
||||||
for (i = 0; standard_class_atoms[i].init; i++) {
|
for (i = 0; standard_class_atoms[i].init; i++) {
|
||||||
atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
|
if (!js::IsStandardClassResolved(obj, standard_class_atoms[i].clasp) &&
|
||||||
if (!obj->nativeContains(ATOM_TO_JSID(atom)) &&
|
!standard_class_atoms[i].init(cx, obj))
|
||||||
!standard_class_atoms[i].init(cx, obj)) {
|
{
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2762,7 +2763,7 @@ JS_PUBLIC_API(void)
|
||||||
JS_SetNativeStackQuota(JSContext *cx, size_t stackSize)
|
JS_SetNativeStackQuota(JSContext *cx, size_t stackSize)
|
||||||
{
|
{
|
||||||
#ifdef JS_THREADSAFE
|
#ifdef JS_THREADSAFE
|
||||||
JS_ASSERT(cx->thread);
|
JS_ASSERT(cx->thread());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if JS_STACK_GROWTH_DIRECTION > 0
|
#if JS_STACK_GROWTH_DIRECTION > 0
|
||||||
|
@ -4210,7 +4211,7 @@ JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
|
||||||
CHECK_REQUEST(cx);
|
CHECK_REQUEST(cx);
|
||||||
assertSameCompartment(cx, parent); // XXX no funobj for now
|
assertSameCompartment(cx, parent); // XXX no funobj for now
|
||||||
if (!parent) {
|
if (!parent) {
|
||||||
if (cx->hasfp())
|
if (cx->running())
|
||||||
parent = GetScopeChain(cx, cx->fp());
|
parent = GetScopeChain(cx, cx->fp());
|
||||||
if (!parent)
|
if (!parent)
|
||||||
parent = cx->globalObject;
|
parent = cx->globalObject;
|
||||||
|
@ -5107,7 +5108,7 @@ JS_New(JSContext *cx, JSObject *ctor, uintN argc, jsval *argv)
|
||||||
// of object to create, create it, and clamp the return value to an object,
|
// of object to create, create it, and clamp the return value to an object,
|
||||||
// among other details. js_InvokeConstructor does the hard work.
|
// among other details. js_InvokeConstructor does the hard work.
|
||||||
InvokeArgsGuard args;
|
InvokeArgsGuard args;
|
||||||
if (!cx->stack().pushInvokeArgs(cx, argc, &args))
|
if (!cx->stack.pushInvokeArgs(cx, argc, &args))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
args.calleev().setObject(*ctor);
|
args.calleev().setObject(*ctor);
|
||||||
|
@ -5141,7 +5142,7 @@ JS_PUBLIC_API(JSOperationCallback)
|
||||||
JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback)
|
JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback)
|
||||||
{
|
{
|
||||||
#ifdef JS_THREADSAFE
|
#ifdef JS_THREADSAFE
|
||||||
JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
|
JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread()));
|
||||||
#endif
|
#endif
|
||||||
JSOperationCallback old = cx->operationCallback;
|
JSOperationCallback old = cx->operationCallback;
|
||||||
cx->operationCallback = callback;
|
cx->operationCallback = callback;
|
||||||
|
@ -5183,9 +5184,9 @@ JS_IsRunning(JSContext *cx)
|
||||||
VOUCH_DOES_NOT_REQUIRE_STACK();
|
VOUCH_DOES_NOT_REQUIRE_STACK();
|
||||||
|
|
||||||
#ifdef JS_TRACER
|
#ifdef JS_TRACER
|
||||||
JS_ASSERT_IF(JS_ON_TRACE(cx) && JS_TRACE_MONITOR_ON_TRACE(cx)->tracecx == cx, cx->hasfp());
|
JS_ASSERT_IF(JS_ON_TRACE(cx) && JS_TRACE_MONITOR_ON_TRACE(cx)->tracecx == cx, cx->running());
|
||||||
#endif
|
#endif
|
||||||
JSStackFrame *fp = cx->maybefp();
|
StackFrame *fp = cx->maybefp();
|
||||||
while (fp && fp->isDummyFrame())
|
while (fp && fp->isDummyFrame())
|
||||||
fp = fp->prev();
|
fp = fp->prev();
|
||||||
return fp != NULL;
|
return fp != NULL;
|
||||||
|
@ -5195,11 +5196,11 @@ JS_PUBLIC_API(JSStackFrame *)
|
||||||
JS_SaveFrameChain(JSContext *cx)
|
JS_SaveFrameChain(JSContext *cx)
|
||||||
{
|
{
|
||||||
CHECK_REQUEST(cx);
|
CHECK_REQUEST(cx);
|
||||||
JSStackFrame *fp = js_GetTopStackFrame(cx);
|
StackFrame *fp = js_GetTopStackFrame(cx);
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return NULL;
|
return NULL;
|
||||||
cx->saveActiveSegment();
|
cx->stack.saveActiveSegment();
|
||||||
return fp;
|
return Jsvalify(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(void)
|
JS_PUBLIC_API(void)
|
||||||
|
@ -5207,10 +5208,10 @@ JS_RestoreFrameChain(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
CHECK_REQUEST(cx);
|
CHECK_REQUEST(cx);
|
||||||
JS_ASSERT_NOT_ON_TRACE(cx);
|
JS_ASSERT_NOT_ON_TRACE(cx);
|
||||||
JS_ASSERT(!cx->hasfp());
|
JS_ASSERT(!cx->running());
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return;
|
return;
|
||||||
cx->restoreSegment();
|
cx->stack.restoreSegment();
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
@ -5580,7 +5581,6 @@ JS_WriteStructuredClone(JSContext *cx, jsval v, uint64 **bufp, size_t *nbytesp,
|
||||||
|
|
||||||
JS_PUBLIC_API(JSBool)
|
JS_PUBLIC_API(JSBool)
|
||||||
JS_StructuredClone(JSContext *cx, jsval v, jsval *vp,
|
JS_StructuredClone(JSContext *cx, jsval v, jsval *vp,
|
||||||
ReadStructuredCloneOp optionalReadOp,
|
|
||||||
const JSStructuredCloneCallbacks *optionalCallbacks,
|
const JSStructuredCloneCallbacks *optionalCallbacks,
|
||||||
void *closure)
|
void *closure)
|
||||||
{
|
{
|
||||||
|
@ -6031,9 +6031,9 @@ JS_SetContextThread(JSContext *cx)
|
||||||
{
|
{
|
||||||
#ifdef JS_THREADSAFE
|
#ifdef JS_THREADSAFE
|
||||||
JS_ASSERT(!cx->outstandingRequests);
|
JS_ASSERT(!cx->outstandingRequests);
|
||||||
if (cx->thread) {
|
if (cx->thread()) {
|
||||||
JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
|
JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread()));
|
||||||
return reinterpret_cast<jsword>(cx->thread->id);
|
return reinterpret_cast<jsword>(cx->thread()->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!js_InitContextThread(cx)) {
|
if (!js_InitContextThread(cx)) {
|
||||||
|
@ -6057,7 +6057,7 @@ JS_ClearContextThread(JSContext *cx)
|
||||||
* is a harmless no-op.
|
* is a harmless no-op.
|
||||||
*/
|
*/
|
||||||
JS_ASSERT(cx->outstandingRequests == 0);
|
JS_ASSERT(cx->outstandingRequests == 0);
|
||||||
JSThread *t = cx->thread;
|
JSThread *t = cx->thread();
|
||||||
if (!t)
|
if (!t)
|
||||||
return 0;
|
return 0;
|
||||||
JS_ASSERT(CURRENT_THREAD_IS_ME(t));
|
JS_ASSERT(CURRENT_THREAD_IS_ME(t));
|
||||||
|
|
|
@ -111,6 +111,8 @@
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
#include "jsstrinlines.h"
|
#include "jsstrinlines.h"
|
||||||
|
|
||||||
|
#include "vm/Stack-inl.h"
|
||||||
|
|
||||||
using namespace js;
|
using namespace js;
|
||||||
using namespace js::gc;
|
using namespace js::gc;
|
||||||
|
|
||||||
|
@ -366,7 +368,7 @@ GetElement(JSContext *cx, JSObject *obj, jsdouble index, JSBool *hole, Value *vp
|
||||||
index < obj->getArgsInitialLength() &&
|
index < obj->getArgsInitialLength() &&
|
||||||
!(*vp = obj->getArgsElement(uint32(index))).isMagic(JS_ARGS_HOLE)) {
|
!(*vp = obj->getArgsElement(uint32(index))).isMagic(JS_ARGS_HOLE)) {
|
||||||
*hole = JS_FALSE;
|
*hole = JS_FALSE;
|
||||||
JSStackFrame *fp = (JSStackFrame *)obj->getPrivate();
|
StackFrame *fp = (StackFrame *)obj->getPrivate();
|
||||||
if (fp != JS_ARGUMENTS_OBJECT_ON_TRACE) {
|
if (fp != JS_ARGUMENTS_OBJECT_ON_TRACE) {
|
||||||
if (fp)
|
if (fp)
|
||||||
*vp = fp->canonicalActualArg(index);
|
*vp = fp->canonicalActualArg(index);
|
||||||
|
@ -434,7 +436,7 @@ GetElements(JSContext *cx, JSObject *aobj, jsuint length, Value *vp)
|
||||||
* fast path for deleted properties (MagicValue(JS_ARGS_HOLE) since
|
* fast path for deleted properties (MagicValue(JS_ARGS_HOLE) since
|
||||||
* this requires general-purpose property lookup.
|
* this requires general-purpose property lookup.
|
||||||
*/
|
*/
|
||||||
if (JSStackFrame *fp = (JSStackFrame *) aobj->getPrivate()) {
|
if (StackFrame *fp = (StackFrame *) aobj->getPrivate()) {
|
||||||
JS_ASSERT(fp->numActualArgs() <= JS_ARGS_LENGTH_MAX);
|
JS_ASSERT(fp->numActualArgs() <= JS_ARGS_LENGTH_MAX);
|
||||||
if (!fp->forEachCanonicalActualArg(CopyNonHoleArgsTo(aobj, vp)))
|
if (!fp->forEachCanonicalActualArg(CopyNonHoleArgsTo(aobj, vp)))
|
||||||
goto found_deleted_prop;
|
goto found_deleted_prop;
|
||||||
|
@ -1062,7 +1064,7 @@ JSObject::makeDenseArraySlow(JSContext *cx)
|
||||||
|
|
||||||
/* Create a native scope. */
|
/* Create a native scope. */
|
||||||
JSObject *arrayProto = getProto();
|
JSObject *arrayProto = getProto();
|
||||||
js::gc::FinalizeKind kind = js::gc::FinalizeKind(arena()->header()->thingKind);
|
js::gc::FinalizeKind kind = js::gc::FinalizeKind(arenaHeader()->getThingKind());
|
||||||
if (!InitScopeForObject(cx, this, &js_SlowArrayClass, arrayProto, kind))
|
if (!InitScopeForObject(cx, this, &js_SlowArrayClass, arrayProto, kind))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1310,8 +1312,6 @@ static JSBool
|
||||||
array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
|
array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
|
||||||
JSString *sepstr, Value *rval)
|
JSString *sepstr, Value *rval)
|
||||||
{
|
{
|
||||||
JS_CHECK_RECURSION(cx, return false);
|
|
||||||
|
|
||||||
static const jschar comma = ',';
|
static const jschar comma = ',';
|
||||||
const jschar *sep;
|
const jschar *sep;
|
||||||
size_t seplen;
|
size_t seplen;
|
||||||
|
@ -1393,6 +1393,8 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
|
||||||
static JSBool
|
static JSBool
|
||||||
array_toString(JSContext *cx, uintN argc, Value *vp)
|
array_toString(JSContext *cx, uintN argc, Value *vp)
|
||||||
{
|
{
|
||||||
|
JS_CHECK_RECURSION(cx, return false);
|
||||||
|
|
||||||
JSObject *obj = ToObject(cx, &vp[1]);
|
JSObject *obj = ToObject(cx, &vp[1]);
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return false;
|
return false;
|
||||||
|
@ -1411,14 +1413,14 @@ array_toString(JSContext *cx, uintN argc, Value *vp)
|
||||||
|
|
||||||
LeaveTrace(cx);
|
LeaveTrace(cx);
|
||||||
InvokeArgsGuard args;
|
InvokeArgsGuard args;
|
||||||
if (!cx->stack().pushInvokeArgs(cx, 0, &args))
|
if (!cx->stack.pushInvokeArgs(cx, 0, &args))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
args.calleev() = join;
|
args.calleev() = join;
|
||||||
args.thisv().setObject(*obj);
|
args.thisv().setObject(*obj);
|
||||||
|
|
||||||
/* Do the call. */
|
/* Do the call. */
|
||||||
if (!Invoke(cx, args, 0))
|
if (!Invoke(cx, args))
|
||||||
return false;
|
return false;
|
||||||
*vp = args.rval();
|
*vp = args.rval();
|
||||||
return true;
|
return true;
|
||||||
|
@ -1427,6 +1429,8 @@ array_toString(JSContext *cx, uintN argc, Value *vp)
|
||||||
static JSBool
|
static JSBool
|
||||||
array_toLocaleString(JSContext *cx, uintN argc, Value *vp)
|
array_toLocaleString(JSContext *cx, uintN argc, Value *vp)
|
||||||
{
|
{
|
||||||
|
JS_CHECK_RECURSION(cx, return false);
|
||||||
|
|
||||||
JSObject *obj = ToObject(cx, &vp[1]);
|
JSObject *obj = ToObject(cx, &vp[1]);
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return false;
|
return false;
|
||||||
|
@ -1524,6 +1528,8 @@ InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, const Value *vector
|
||||||
static JSBool
|
static JSBool
|
||||||
array_join(JSContext *cx, uintN argc, Value *vp)
|
array_join(JSContext *cx, uintN argc, Value *vp)
|
||||||
{
|
{
|
||||||
|
JS_CHECK_RECURSION(cx, return false);
|
||||||
|
|
||||||
JSString *str;
|
JSString *str;
|
||||||
if (argc == 0 || vp[2].isUndefined()) {
|
if (argc == 0 || vp[2].isUndefined()) {
|
||||||
str = NULL;
|
str = NULL;
|
||||||
|
@ -2394,9 +2400,8 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
|
||||||
|
|
||||||
/* Convert the first argument into a starting index. */
|
/* Convert the first argument into a starting index. */
|
||||||
jsdouble d;
|
jsdouble d;
|
||||||
if (!ValueToNumber(cx, *argv, &d))
|
if (!ToInteger(cx, *argv, &d))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
d = js_DoubleToInteger(d);
|
|
||||||
if (d < 0) {
|
if (d < 0) {
|
||||||
d += length;
|
d += length;
|
||||||
if (d < 0)
|
if (d < 0)
|
||||||
|
@ -2414,9 +2419,8 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
|
||||||
count = delta;
|
count = delta;
|
||||||
end = length;
|
end = length;
|
||||||
} else {
|
} else {
|
||||||
if (!ValueToNumber(cx, *argv, &d))
|
if (!ToInteger(cx, *argv, &d))
|
||||||
return JS_FALSE;
|
return false;
|
||||||
d = js_DoubleToInteger(d);
|
|
||||||
if (d < 0)
|
if (d < 0)
|
||||||
d = 0;
|
d = 0;
|
||||||
else if (d > delta)
|
else if (d > delta)
|
||||||
|
@ -2638,9 +2642,8 @@ array_slice(JSContext *cx, uintN argc, Value *vp)
|
||||||
|
|
||||||
if (argc > 0) {
|
if (argc > 0) {
|
||||||
jsdouble d;
|
jsdouble d;
|
||||||
if (!ValueToNumber(cx, argv[0], &d))
|
if (!ToInteger(cx, argv[0], &d))
|
||||||
return JS_FALSE;
|
return false;
|
||||||
d = js_DoubleToInteger(d);
|
|
||||||
if (d < 0) {
|
if (d < 0) {
|
||||||
d += length;
|
d += length;
|
||||||
if (d < 0)
|
if (d < 0)
|
||||||
|
@ -2651,9 +2654,8 @@ array_slice(JSContext *cx, uintN argc, Value *vp)
|
||||||
begin = (jsuint)d;
|
begin = (jsuint)d;
|
||||||
|
|
||||||
if (argc > 1 && !argv[1].isUndefined()) {
|
if (argc > 1 && !argv[1].isUndefined()) {
|
||||||
if (!ValueToNumber(cx, argv[1], &d))
|
if (!ToInteger(cx, argv[1], &d))
|
||||||
return JS_FALSE;
|
return false;
|
||||||
d = js_DoubleToInteger(d);
|
|
||||||
if (d < 0) {
|
if (d < 0) {
|
||||||
d += length;
|
d += length;
|
||||||
if (d < 0)
|
if (d < 0)
|
||||||
|
@ -2721,9 +2723,8 @@ array_indexOfHelper(JSContext *cx, JSBool isLast, uintN argc, Value *vp)
|
||||||
jsdouble start;
|
jsdouble start;
|
||||||
|
|
||||||
tosearch = vp[2];
|
tosearch = vp[2];
|
||||||
if (!ValueToNumber(cx, vp[3], &start))
|
if (!ToInteger(cx, vp[3], &start))
|
||||||
return JS_FALSE;
|
return false;
|
||||||
start = js_DoubleToInteger(start);
|
|
||||||
if (start < 0) {
|
if (start < 0) {
|
||||||
start += length;
|
start += length;
|
||||||
if (start < 0) {
|
if (start < 0) {
|
||||||
|
|
|
@ -125,6 +125,20 @@ IdToString(JSContext *cx, jsid id)
|
||||||
return js_ValueToString(cx, IdToValue(id));
|
return js_ValueToString(cx, IdToValue(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct DefaultHasher<jsid>
|
||||||
|
{
|
||||||
|
typedef jsid Lookup;
|
||||||
|
static HashNumber hash(const Lookup &l) {
|
||||||
|
JS_ASSERT(l == js_CheckForStringIndex(l));
|
||||||
|
return JSID_BITS(l);
|
||||||
|
}
|
||||||
|
static bool match(const jsid &id, const Lookup &l) {
|
||||||
|
JS_ASSERT(l == js_CheckForStringIndex(l));
|
||||||
|
return id == l;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if JS_BYTES_PER_WORD == 4
|
#if JS_BYTES_PER_WORD == 4
|
||||||
|
|
|
@ -47,6 +47,7 @@ namespace gc {
|
||||||
|
|
||||||
template <typename T> struct Arena;
|
template <typename T> struct Arena;
|
||||||
struct ArenaBitmap;
|
struct ArenaBitmap;
|
||||||
|
struct ArenaHeader;
|
||||||
struct MarkingDelay;
|
struct MarkingDelay;
|
||||||
struct Chunk;
|
struct Chunk;
|
||||||
struct FreeCell;
|
struct FreeCell;
|
||||||
|
@ -64,7 +65,8 @@ struct Cell {
|
||||||
static const size_t CellSize = size_t(1) << CellShift;
|
static const size_t CellSize = size_t(1) << CellShift;
|
||||||
static const size_t CellMask = CellSize - 1;
|
static const size_t CellMask = CellSize - 1;
|
||||||
|
|
||||||
inline Arena<Cell> *arena() const;
|
inline uintptr_t address() const;
|
||||||
|
inline ArenaHeader *arenaHeader() const;
|
||||||
inline Chunk *chunk() const;
|
inline Chunk *chunk() const;
|
||||||
inline ArenaBitmap *bitmap() const;
|
inline ArenaBitmap *bitmap() const;
|
||||||
JS_ALWAYS_INLINE size_t cellIndex() const;
|
JS_ALWAYS_INLINE size_t cellIndex() const;
|
||||||
|
@ -82,9 +84,12 @@ struct Cell {
|
||||||
JS_ALWAYS_INLINE const js::gc::FreeCell *asFreeCell() const {
|
JS_ALWAYS_INLINE const js::gc::FreeCell *asFreeCell() const {
|
||||||
return reinterpret_cast<const FreeCell *>(this);
|
return reinterpret_cast<const FreeCell *>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
inline bool isAligned() const;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/* FreeCell has always size 8 */
|
|
||||||
struct FreeCell : Cell {
|
struct FreeCell : Cell {
|
||||||
union {
|
union {
|
||||||
FreeCell *link;
|
FreeCell *link;
|
||||||
|
@ -92,7 +97,7 @@ struct FreeCell : Cell {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
JS_STATIC_ASSERT(sizeof(FreeCell) == 8);
|
JS_STATIC_ASSERT(sizeof(FreeCell) == Cell::CellSize);
|
||||||
|
|
||||||
} /* namespace gc */
|
} /* namespace gc */
|
||||||
} /* namespace js */
|
} /* namespace js */
|
||||||
|
|
|
@ -74,6 +74,7 @@
|
||||||
#include "jsobj.h"
|
#include "jsobj.h"
|
||||||
#include "jsopcode.h"
|
#include "jsopcode.h"
|
||||||
#include "jspubtd.h"
|
#include "jspubtd.h"
|
||||||
|
#include "jsscan.h"
|
||||||
#include "jsscope.h"
|
#include "jsscope.h"
|
||||||
#include "jsscript.h"
|
#include "jsscript.h"
|
||||||
#include "jsstaticcheck.h"
|
#include "jsstaticcheck.h"
|
||||||
|
@ -86,449 +87,11 @@
|
||||||
|
|
||||||
#include "jscntxtinlines.h"
|
#include "jscntxtinlines.h"
|
||||||
#include "jscompartment.h"
|
#include "jscompartment.h"
|
||||||
#include "jsinterpinlines.h"
|
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
|
|
||||||
#ifdef XP_WIN
|
|
||||||
# include "jswin.h"
|
|
||||||
#elif defined(XP_OS2)
|
|
||||||
# define INCL_DOSMEMMGR
|
|
||||||
# include <os2.h>
|
|
||||||
#else
|
|
||||||
# include <unistd.h>
|
|
||||||
# include <sys/mman.h>
|
|
||||||
# if !defined(MAP_ANONYMOUS)
|
|
||||||
# if defined(MAP_ANON)
|
|
||||||
# define MAP_ANONYMOUS MAP_ANON
|
|
||||||
# else
|
|
||||||
# define MAP_ANONYMOUS 0
|
|
||||||
# endif
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace js;
|
using namespace js;
|
||||||
using namespace js::gc;
|
using namespace js::gc;
|
||||||
|
|
||||||
JS_REQUIRES_STACK bool
|
|
||||||
StackSegment::contains(const JSStackFrame *fp) const
|
|
||||||
{
|
|
||||||
JS_ASSERT(inContext());
|
|
||||||
|
|
||||||
if (fp < initialFrame)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
JSStackFrame *start;
|
|
||||||
if (isActive()) {
|
|
||||||
JS_ASSERT(cx->hasfp() && this == cx->activeSegment());
|
|
||||||
start = cx->fp();
|
|
||||||
} else {
|
|
||||||
JS_ASSERT(suspendedRegs && suspendedRegs->fp);
|
|
||||||
start = suspendedRegs->fp;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fp > start)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
bool found = false;
|
|
||||||
JSStackFrame *stop = initialFrame->prev();
|
|
||||||
for (JSStackFrame *f = start; !found && f != stop; f = f->prev()) {
|
|
||||||
if (f == fp) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
JS_ASSERT(found);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSStackFrame *
|
|
||||||
StackSegment::computeNextFrame(JSStackFrame *fp) const
|
|
||||||
{
|
|
||||||
JS_ASSERT(contains(fp));
|
|
||||||
JS_ASSERT(fp != getCurrentFrame());
|
|
||||||
|
|
||||||
JSStackFrame *next = getCurrentFrame();
|
|
||||||
JSStackFrame *prev;
|
|
||||||
while ((prev = next->prev()) != fp)
|
|
||||||
next = prev;
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
StackSpace::StackSpace()
|
|
||||||
: base(NULL),
|
|
||||||
#ifdef XP_WIN
|
|
||||||
commitEnd(NULL),
|
|
||||||
#endif
|
|
||||||
end(NULL),
|
|
||||||
currentSegment(NULL),
|
|
||||||
#ifdef DEBUG
|
|
||||||
invokeSegment(NULL),
|
|
||||||
invokeFrame(NULL),
|
|
||||||
#endif
|
|
||||||
invokeArgEnd(NULL)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
StackSpace::init()
|
|
||||||
{
|
|
||||||
void *p;
|
|
||||||
#ifdef XP_WIN
|
|
||||||
p = VirtualAlloc(NULL, CAPACITY_BYTES, MEM_RESERVE, PAGE_READWRITE);
|
|
||||||
if (!p)
|
|
||||||
return false;
|
|
||||||
void *check = VirtualAlloc(p, COMMIT_BYTES, MEM_COMMIT, PAGE_READWRITE);
|
|
||||||
if (p != check)
|
|
||||||
return false;
|
|
||||||
base = reinterpret_cast<Value *>(p);
|
|
||||||
commitEnd = base + COMMIT_VALS;
|
|
||||||
end = base + CAPACITY_VALS;
|
|
||||||
#elif defined(XP_OS2)
|
|
||||||
if (DosAllocMem(&p, CAPACITY_BYTES, PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_ANY) &&
|
|
||||||
DosAllocMem(&p, CAPACITY_BYTES, PAG_COMMIT | PAG_READ | PAG_WRITE))
|
|
||||||
return false;
|
|
||||||
base = reinterpret_cast<Value *>(p);
|
|
||||||
end = base + CAPACITY_VALS;
|
|
||||||
#else
|
|
||||||
JS_ASSERT(CAPACITY_BYTES % getpagesize() == 0);
|
|
||||||
p = mmap(NULL, CAPACITY_BYTES, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
|
||||||
if (p == MAP_FAILED)
|
|
||||||
return false;
|
|
||||||
base = reinterpret_cast<Value *>(p);
|
|
||||||
end = base + CAPACITY_VALS;
|
|
||||||
#endif
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
StackSpace::~StackSpace()
|
|
||||||
{
|
|
||||||
if (!base)
|
|
||||||
return;
|
|
||||||
#ifdef XP_WIN
|
|
||||||
VirtualFree(base, (commitEnd - base) * sizeof(Value), MEM_DECOMMIT);
|
|
||||||
VirtualFree(base, 0, MEM_RELEASE);
|
|
||||||
#elif defined(XP_OS2)
|
|
||||||
DosFreeMem(base);
|
|
||||||
#else
|
|
||||||
#ifdef SOLARIS
|
|
||||||
munmap((caddr_t)base, CAPACITY_BYTES);
|
|
||||||
#else
|
|
||||||
munmap(base, CAPACITY_BYTES);
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef XP_WIN
|
|
||||||
JS_FRIEND_API(bool)
|
|
||||||
StackSpace::bumpCommit(Value *from, ptrdiff_t nvals) const
|
|
||||||
{
|
|
||||||
JS_ASSERT(end - from >= nvals);
|
|
||||||
Value *newCommit = commitEnd;
|
|
||||||
Value *request = from + nvals;
|
|
||||||
|
|
||||||
/* Use a dumb loop; will probably execute once. */
|
|
||||||
JS_ASSERT((end - newCommit) % COMMIT_VALS == 0);
|
|
||||||
do {
|
|
||||||
newCommit += COMMIT_VALS;
|
|
||||||
JS_ASSERT((end - newCommit) >= 0);
|
|
||||||
} while (newCommit < request);
|
|
||||||
|
|
||||||
/* The cast is safe because CAPACITY_BYTES is small. */
|
|
||||||
int32 size = static_cast<int32>(newCommit - commitEnd) * sizeof(Value);
|
|
||||||
|
|
||||||
if (!VirtualAlloc(commitEnd, size, MEM_COMMIT, PAGE_READWRITE))
|
|
||||||
return false;
|
|
||||||
commitEnd = newCommit;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void
|
|
||||||
StackSpace::mark(JSTracer *trc)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* The correctness/completeness of marking depends on the continuity
|
|
||||||
* invariants described by the StackSegment and StackSpace definitions.
|
|
||||||
*
|
|
||||||
* NB:
|
|
||||||
* Stack slots might be torn or uninitialized in the presence of method
|
|
||||||
* JIT'd code. Arguments are an exception and are always fully synced
|
|
||||||
* (so they can be read by functions).
|
|
||||||
*/
|
|
||||||
Value *end = firstUnused();
|
|
||||||
for (StackSegment *seg = currentSegment; seg; seg = seg->getPreviousInMemory()) {
|
|
||||||
STATIC_ASSERT(ubound(end) >= 0);
|
|
||||||
if (seg->inContext()) {
|
|
||||||
/* This may be the only pointer to the initialVarObj. */
|
|
||||||
if (seg->hasInitialVarObj())
|
|
||||||
MarkObject(trc, seg->getInitialVarObj(), "varobj");
|
|
||||||
|
|
||||||
/* Mark slots/args trailing off of the last stack frame. */
|
|
||||||
JSStackFrame *fp = seg->getCurrentFrame();
|
|
||||||
MarkStackRangeConservatively(trc, fp->slots(), end);
|
|
||||||
|
|
||||||
/* Mark stack frames and slots/args between stack frames. */
|
|
||||||
JSStackFrame *initial = seg->getInitialFrame();
|
|
||||||
for (JSStackFrame *f = fp; f != initial; f = f->prev()) {
|
|
||||||
js_TraceStackFrame(trc, f);
|
|
||||||
MarkStackRangeConservatively(trc, f->prev()->slots(), (Value *)f);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Mark initial stack frame and leading args. */
|
|
||||||
js_TraceStackFrame(trc, initial);
|
|
||||||
MarkStackRangeConservatively(trc, seg->valueRangeBegin(), (Value *)initial);
|
|
||||||
} else {
|
|
||||||
/* Mark slots/args trailing off segment. */
|
|
||||||
MarkValueRange(trc, seg->valueRangeBegin(), end, "stack");
|
|
||||||
}
|
|
||||||
end = (Value *)seg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
StackSpace::pushSegmentForInvoke(JSContext *cx, uintN argc, InvokeArgsGuard *ag)
|
|
||||||
{
|
|
||||||
Value *start = firstUnused();
|
|
||||||
ptrdiff_t nvals = VALUES_PER_STACK_SEGMENT + 2 + argc;
|
|
||||||
if (!ensureSpace(cx, start, nvals))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
StackSegment *seg = new(start) StackSegment;
|
|
||||||
seg->setPreviousInMemory(currentSegment);
|
|
||||||
currentSegment = seg;
|
|
||||||
|
|
||||||
ag->cx = cx;
|
|
||||||
ag->seg = seg;
|
|
||||||
ImplicitCast<CallArgs>(*ag) = CallArgsFromVp(argc, seg->valueRangeBegin());
|
|
||||||
|
|
||||||
/* Use invokeArgEnd to root [vp, vpend) until the frame is pushed. */
|
|
||||||
#ifdef DEBUG
|
|
||||||
ag->prevInvokeSegment = invokeSegment;
|
|
||||||
invokeSegment = seg;
|
|
||||||
ag->prevInvokeFrame = invokeFrame;
|
|
||||||
invokeFrame = NULL;
|
|
||||||
#endif
|
|
||||||
ag->prevInvokeArgEnd = invokeArgEnd;
|
|
||||||
invokeArgEnd = ag->argv() + ag->argc();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
StackSpace::popSegmentForInvoke(const InvokeArgsGuard &ag)
|
|
||||||
{
|
|
||||||
JS_ASSERT(!currentSegment->inContext());
|
|
||||||
JS_ASSERT(ag.seg == currentSegment);
|
|
||||||
JS_ASSERT(invokeSegment == currentSegment);
|
|
||||||
JS_ASSERT(invokeArgEnd == ag.argv() + ag.argc());
|
|
||||||
|
|
||||||
currentSegment = currentSegment->getPreviousInMemory();
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
invokeSegment = ag.prevInvokeSegment;
|
|
||||||
invokeFrame = ag.prevInvokeFrame;
|
|
||||||
#endif
|
|
||||||
invokeArgEnd = ag.prevInvokeArgEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
StackSpace::getSegmentAndFrame(JSContext *cx, uintN vplen, uintN nslots,
|
|
||||||
FrameGuard *fg) const
|
|
||||||
{
|
|
||||||
Value *start = firstUnused();
|
|
||||||
uintN nvals = VALUES_PER_STACK_SEGMENT + vplen + VALUES_PER_STACK_FRAME + nslots;
|
|
||||||
if (!ensureSpace(cx, start, nvals))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
fg->seg_ = new(start) StackSegment;
|
|
||||||
fg->vp_ = start + VALUES_PER_STACK_SEGMENT;
|
|
||||||
fg->fp_ = reinterpret_cast<JSStackFrame *>(fg->vp() + vplen);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
StackSpace::pushSegmentAndFrame(JSContext *cx, JSFrameRegs *regs, FrameGuard *fg)
|
|
||||||
{
|
|
||||||
/* Caller should have already initialized regs. */
|
|
||||||
JS_ASSERT(regs->fp == fg->fp());
|
|
||||||
StackSegment *seg = fg->segment();
|
|
||||||
|
|
||||||
/* Register new segment/frame with the context. */
|
|
||||||
cx->pushSegmentAndFrame(seg, *regs);
|
|
||||||
|
|
||||||
/* Officially push the segment/frame on the stack. */
|
|
||||||
seg->setPreviousInMemory(currentSegment);
|
|
||||||
currentSegment = seg;
|
|
||||||
|
|
||||||
/* Mark as 'pushed' in the guard. */
|
|
||||||
fg->cx_ = cx;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
StackSpace::popSegmentAndFrame(JSContext *cx)
|
|
||||||
{
|
|
||||||
JS_ASSERT(isCurrentAndActive(cx));
|
|
||||||
JS_ASSERT(cx->hasActiveSegment());
|
|
||||||
|
|
||||||
PutActivationObjects(cx, cx->fp());
|
|
||||||
|
|
||||||
/* Officially pop the segment/frame from the stack. */
|
|
||||||
currentSegment = currentSegment->getPreviousInMemory();
|
|
||||||
|
|
||||||
/* Unregister pushed segment/frame from the context. */
|
|
||||||
cx->popSegmentAndFrame();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* N.B. This StackSpace should be GC-able without any operations after
|
|
||||||
* cx->popSegmentAndFrame executes since it can trigger GC.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
FrameGuard::~FrameGuard()
|
|
||||||
{
|
|
||||||
if (!pushed())
|
|
||||||
return;
|
|
||||||
JS_ASSERT(cx_->activeSegment() == segment());
|
|
||||||
JS_ASSERT(cx_->maybefp() == fp());
|
|
||||||
cx_->stack().popSegmentAndFrame(cx_);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
StackSpace::getExecuteFrame(JSContext *cx, JSScript *script, ExecuteFrameGuard *fg) const
|
|
||||||
{
|
|
||||||
return getSegmentAndFrame(cx, 2, script->nslots, fg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
StackSpace::pushExecuteFrame(JSContext *cx, JSObject *initialVarObj, ExecuteFrameGuard *fg)
|
|
||||||
{
|
|
||||||
JSStackFrame *fp = fg->fp();
|
|
||||||
JSScript *script = fp->script();
|
|
||||||
fg->regs_.pc = script->code;
|
|
||||||
fg->regs_.fp = fp;
|
|
||||||
fg->regs_.sp = fp->base();
|
|
||||||
pushSegmentAndFrame(cx, &fg->regs_, fg);
|
|
||||||
fg->seg_->setInitialVarObj(initialVarObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
StackSpace::pushDummyFrame(JSContext *cx, JSObject &scopeChain, DummyFrameGuard *fg)
|
|
||||||
{
|
|
||||||
if (!getSegmentAndFrame(cx, 0 /*vplen*/, 0 /*nslots*/, fg))
|
|
||||||
return false;
|
|
||||||
fg->fp()->initDummyFrame(cx, scopeChain);
|
|
||||||
fg->regs_.fp = fg->fp();
|
|
||||||
fg->regs_.pc = NULL;
|
|
||||||
fg->regs_.sp = fg->fp()->slots();
|
|
||||||
pushSegmentAndFrame(cx, &fg->regs_, fg);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
StackSpace::getGeneratorFrame(JSContext *cx, uintN vplen, uintN nslots, GeneratorFrameGuard *fg)
|
|
||||||
{
|
|
||||||
return getSegmentAndFrame(cx, vplen, nslots, fg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
StackSpace::pushGeneratorFrame(JSContext *cx, JSFrameRegs *regs, GeneratorFrameGuard *fg)
|
|
||||||
{
|
|
||||||
JS_ASSERT(regs->fp == fg->fp());
|
|
||||||
JS_ASSERT(regs->fp->prev() == cx->maybefp());
|
|
||||||
pushSegmentAndFrame(cx, regs, fg);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
StackSpace::bumpCommitAndLimit(JSStackFrame *base, Value *sp, uintN nvals, Value **limit) const
|
|
||||||
{
|
|
||||||
JS_ASSERT(sp >= firstUnused());
|
|
||||||
JS_ASSERT(sp + nvals >= *limit);
|
|
||||||
#ifdef XP_WIN
|
|
||||||
if (commitEnd <= *limit) {
|
|
||||||
Value *quotaEnd = (Value *)base + STACK_QUOTA;
|
|
||||||
if (sp + nvals < quotaEnd) {
|
|
||||||
if (!ensureSpace(NULL, sp, nvals))
|
|
||||||
return false;
|
|
||||||
*limit = Min(quotaEnd, commitEnd);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
FrameRegsIter::initSlow()
|
|
||||||
{
|
|
||||||
if (!curseg) {
|
|
||||||
curfp = NULL;
|
|
||||||
cursp = NULL;
|
|
||||||
curpc = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_ASSERT(curseg->isSuspended());
|
|
||||||
curfp = curseg->getSuspendedFrame();
|
|
||||||
cursp = curseg->getSuspendedRegs()->sp;
|
|
||||||
curpc = curseg->getSuspendedRegs()->pc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Using the invariant described in the js::StackSegment comment, we know that,
|
|
||||||
* when a pair of prev-linked stack frames are in the same segment, the
|
|
||||||
* first frame's address is the top of the prev-frame's stack, modulo missing
|
|
||||||
* arguments.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
FrameRegsIter::incSlow(JSStackFrame *fp, JSStackFrame *prev)
|
|
||||||
{
|
|
||||||
JS_ASSERT(prev);
|
|
||||||
JS_ASSERT(curpc == curfp->pc(cx, fp));
|
|
||||||
JS_ASSERT(fp == curseg->getInitialFrame());
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If fp is in cs and the prev-frame is in csprev, it is not necessarily
|
|
||||||
* the case that |cs->getPreviousInContext == csprev| or that
|
|
||||||
* |csprev->getSuspendedFrame == prev| (because of indirect eval and
|
|
||||||
* JS_EvaluateInStackFrame). To compute prev's sp, we need to do a linear
|
|
||||||
* scan, keeping track of what is immediately after prev in memory.
|
|
||||||
*/
|
|
||||||
curseg = curseg->getPreviousInContext();
|
|
||||||
cursp = curseg->getSuspendedRegs()->sp;
|
|
||||||
JSStackFrame *f = curseg->getSuspendedFrame();
|
|
||||||
while (f != prev) {
|
|
||||||
if (f == curseg->getInitialFrame()) {
|
|
||||||
curseg = curseg->getPreviousInContext();
|
|
||||||
cursp = curseg->getSuspendedRegs()->sp;
|
|
||||||
f = curseg->getSuspendedFrame();
|
|
||||||
} else {
|
|
||||||
cursp = f->formalArgsEnd();
|
|
||||||
f = f->prev();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AllFramesIter::AllFramesIter(JSContext *cx)
|
|
||||||
: curcs(cx->stack().getCurrentSegment()),
|
|
||||||
curfp(curcs ? curcs->getCurrentFrame() : NULL)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
AllFramesIter&
|
|
||||||
AllFramesIter::operator++()
|
|
||||||
{
|
|
||||||
JS_ASSERT(!done());
|
|
||||||
if (curfp == curcs->getInitialFrame()) {
|
|
||||||
curcs = curcs->getPreviousInMemory();
|
|
||||||
curfp = curcs ? curcs->getCurrentFrame() : NULL;
|
|
||||||
} else {
|
|
||||||
curfp = curfp->prev();
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
ThreadData::ThreadData()
|
ThreadData::ThreadData()
|
||||||
|
@ -649,16 +212,23 @@ js_InitContextThread(JSContext *cx)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
JS_APPEND_LINK(&cx->threadLinks, &thread->contextList);
|
JS_APPEND_LINK(&cx->threadLinks, &thread->contextList);
|
||||||
cx->thread = thread;
|
cx->setThread(thread);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
JSContext::setThread(JSThread *thread)
|
||||||
|
{
|
||||||
|
thread_ = thread;
|
||||||
|
stack.threadReset();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
js_ClearContextThread(JSContext *cx)
|
js_ClearContextThread(JSContext *cx)
|
||||||
{
|
{
|
||||||
JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
|
JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread()));
|
||||||
JS_REMOVE_AND_INIT_LINK(&cx->threadLinks);
|
JS_REMOVE_AND_INIT_LINK(&cx->threadLinks);
|
||||||
cx->thread = NULL;
|
cx->setThread(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* JS_THREADSAFE */
|
#endif /* JS_THREADSAFE */
|
||||||
|
@ -711,7 +281,7 @@ js_PurgeThreads(JSContext *cx)
|
||||||
JSThread *thread = e.front().value;
|
JSThread *thread = e.front().value;
|
||||||
|
|
||||||
if (JS_CLIST_IS_EMPTY(&thread->contextList)) {
|
if (JS_CLIST_IS_EMPTY(&thread->contextList)) {
|
||||||
JS_ASSERT(cx->thread != thread);
|
JS_ASSERT(cx->thread() != thread);
|
||||||
Foreground::delete_(thread);
|
Foreground::delete_(thread);
|
||||||
e.removeFront();
|
e.removeFront();
|
||||||
} else {
|
} else {
|
||||||
|
@ -892,7 +462,7 @@ DumpEvalCacheMeter(JSContext *cx)
|
||||||
|
|
||||||
fprintf(fp, "eval cache meter (%p):\n",
|
fprintf(fp, "eval cache meter (%p):\n",
|
||||||
#ifdef JS_THREADSAFE
|
#ifdef JS_THREADSAFE
|
||||||
(void *) cx->thread
|
(void *) cx->thread()
|
||||||
#else
|
#else
|
||||||
(void *) cx->runtime
|
(void *) cx->runtime
|
||||||
#endif
|
#endif
|
||||||
|
@ -980,8 +550,8 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
|
||||||
* optimized builds. We assume that the embedding knows that an OOM error
|
* optimized builds. We assume that the embedding knows that an OOM error
|
||||||
* cannot happen in JS_SetContextThread.
|
* cannot happen in JS_SetContextThread.
|
||||||
*/
|
*/
|
||||||
JS_ASSERT(cx->thread && CURRENT_THREAD_IS_ME(cx->thread));
|
JS_ASSERT(cx->thread() && CURRENT_THREAD_IS_ME(cx->thread()));
|
||||||
if (!cx->thread)
|
if (!cx->thread())
|
||||||
JS_SetContextThread(cx);
|
JS_SetContextThread(cx);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -990,7 +560,7 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
|
||||||
* on this cx contributes to cx->thread->data.requestDepth and there is no
|
* on this cx contributes to cx->thread->data.requestDepth and there is no
|
||||||
* JS_SuspendRequest calls that set aside the counter.
|
* JS_SuspendRequest calls that set aside the counter.
|
||||||
*/
|
*/
|
||||||
JS_ASSERT(cx->outstandingRequests <= cx->thread->data.requestDepth);
|
JS_ASSERT(cx->outstandingRequests <= cx->thread()->data.requestDepth);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (mode != JSDCM_NEW_FAILED) {
|
if (mode != JSDCM_NEW_FAILED) {
|
||||||
|
@ -1012,7 +582,7 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
|
||||||
* Typically we are called outside a request, so ensure that the GC is not
|
* Typically we are called outside a request, so ensure that the GC is not
|
||||||
* running before removing the context from rt->contextList, see bug 477021.
|
* running before removing the context from rt->contextList, see bug 477021.
|
||||||
*/
|
*/
|
||||||
if (cx->thread->data.requestDepth == 0)
|
if (cx->thread()->data.requestDepth == 0)
|
||||||
js_WaitForGC(rt);
|
js_WaitForGC(rt);
|
||||||
#endif
|
#endif
|
||||||
JS_REMOVE_LINK(&cx->link);
|
JS_REMOVE_LINK(&cx->link);
|
||||||
|
@ -1043,7 +613,7 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
|
||||||
* force or maybe run the GC, but by that point, rt->state will
|
* force or maybe run the GC, but by that point, rt->state will
|
||||||
* not be JSRTS_UP, and that GC attempt will return early.
|
* not be JSRTS_UP, and that GC attempt will return early.
|
||||||
*/
|
*/
|
||||||
if (cx->thread->data.requestDepth == 0)
|
if (cx->thread()->data.requestDepth == 0)
|
||||||
JS_BeginRequest(cx);
|
JS_BeginRequest(cx);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1089,7 +659,7 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
|
||||||
}
|
}
|
||||||
#ifdef JS_THREADSAFE
|
#ifdef JS_THREADSAFE
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
JSThread *t = cx->thread;
|
JSThread *t = cx->thread();
|
||||||
#endif
|
#endif
|
||||||
js_ClearContextThread(cx);
|
js_ClearContextThread(cx);
|
||||||
JS_ASSERT_IF(JS_CLIST_IS_EMPTY(&t->contextList), !t->data.requestDepth);
|
JS_ASSERT_IF(JS_CLIST_IS_EMPTY(&t->contextList), !t->data.requestDepth);
|
||||||
|
@ -1109,7 +679,9 @@ js_ContextIterator(JSRuntime *rt, JSBool unlocked, JSContext **iterp)
|
||||||
{
|
{
|
||||||
JSContext *cx = *iterp;
|
JSContext *cx = *iterp;
|
||||||
|
|
||||||
Conditionally<AutoLockGC> lockIf(!!unlocked, rt);
|
Maybe<AutoLockGC> lockIf;
|
||||||
|
if (unlocked)
|
||||||
|
lockIf.construct(rt);
|
||||||
cx = js_ContextFromLinkField(cx ? cx->link.next : rt->contextList.next);
|
cx = js_ContextFromLinkField(cx ? cx->link.next : rt->contextList.next);
|
||||||
if (&cx->link == &rt->contextList)
|
if (&cx->link == &rt->contextList)
|
||||||
cx = NULL;
|
cx = NULL;
|
||||||
|
@ -1123,7 +695,7 @@ js_NextActiveContext(JSRuntime *rt, JSContext *cx)
|
||||||
JSContext *iter = cx;
|
JSContext *iter = cx;
|
||||||
#ifdef JS_THREADSAFE
|
#ifdef JS_THREADSAFE
|
||||||
while ((cx = js_ContextIterator(rt, JS_FALSE, &iter)) != NULL) {
|
while ((cx = js_ContextIterator(rt, JS_FALSE, &iter)) != NULL) {
|
||||||
if (cx->outstandingRequests && cx->thread->data.requestDepth)
|
if (cx->outstandingRequests && cx->thread()->data.requestDepth)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return cx;
|
return cx;
|
||||||
|
@ -1191,7 +763,7 @@ PopulateReportBlame(JSContext *cx, JSErrorReport *report)
|
||||||
* Walk stack until we find a frame that is associated with some script
|
* Walk stack until we find a frame that is associated with some script
|
||||||
* rather than a native frame.
|
* rather than a native frame.
|
||||||
*/
|
*/
|
||||||
for (JSStackFrame *fp = js_GetTopStackFrame(cx); fp; fp = fp->prev()) {
|
for (StackFrame *fp = js_GetTopStackFrame(cx); fp; fp = fp->prev()) {
|
||||||
if (fp->pc(cx)) {
|
if (fp->pc(cx)) {
|
||||||
report->filename = fp->script()->filename;
|
report->filename = fp->script()->filename;
|
||||||
report->lineno = js_FramePCToLineNumber(cx, fp);
|
report->lineno = js_FramePCToLineNumber(cx, fp);
|
||||||
|
@ -1253,22 +825,24 @@ js_ReportOutOfMemory(JSContext *cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
js_ReportOutOfScriptQuota(JSContext *cx)
|
js_ReportOutOfScriptQuota(JSContext *maybecx)
|
||||||
{
|
{
|
||||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
if (maybecx)
|
||||||
JSMSG_SCRIPT_STACK_QUOTA);
|
JS_ReportErrorNumber(maybecx, js_GetErrorMessage, NULL, JSMSG_SCRIPT_STACK_QUOTA);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_FRIEND_API(void)
|
JS_FRIEND_API(void)
|
||||||
js_ReportOverRecursed(JSContext *cx)
|
js_ReportOverRecursed(JSContext *maybecx)
|
||||||
{
|
{
|
||||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED);
|
if (maybecx)
|
||||||
|
JS_ReportErrorNumber(maybecx, js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
js_ReportAllocationOverflow(JSContext *cx)
|
js_ReportAllocationOverflow(JSContext *maybecx)
|
||||||
{
|
{
|
||||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_ALLOC_OVERFLOW);
|
if (maybecx)
|
||||||
|
JS_ReportErrorNumber(maybecx, js_GetErrorMessage, NULL, JSMSG_ALLOC_OVERFLOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1286,7 +860,7 @@ checkReportFlags(JSContext *cx, uintN *flags)
|
||||||
* We assume that if the top frame is a native, then it is strict if
|
* We assume that if the top frame is a native, then it is strict if
|
||||||
* the nearest scripted frame is strict, see bug 536306.
|
* the nearest scripted frame is strict, see bug 536306.
|
||||||
*/
|
*/
|
||||||
JSStackFrame *fp = js_GetScriptedCaller(cx, NULL);
|
StackFrame *fp = js_GetScriptedCaller(cx, NULL);
|
||||||
if (fp && fp->script()->strictModeCode)
|
if (fp && fp->script()->strictModeCode)
|
||||||
*flags &= ~JSREPORT_WARNING;
|
*flags &= ~JSREPORT_WARNING;
|
||||||
else if (cx->hasStrictOption())
|
else if (cx->hasStrictOption())
|
||||||
|
@ -1781,7 +1355,7 @@ TriggerOperationCallback(JSContext *cx)
|
||||||
*/
|
*/
|
||||||
ThreadData *td;
|
ThreadData *td;
|
||||||
#ifdef JS_THREADSAFE
|
#ifdef JS_THREADSAFE
|
||||||
JSThread *thread = cx->thread;
|
JSThread *thread = cx->thread();
|
||||||
if (!thread)
|
if (!thread)
|
||||||
return;
|
return;
|
||||||
td = &thread->data;
|
td = &thread->data;
|
||||||
|
@ -1800,8 +1374,8 @@ TriggerAllOperationCallbacks(JSRuntime *rt)
|
||||||
|
|
||||||
} /* namespace js */
|
} /* namespace js */
|
||||||
|
|
||||||
JSStackFrame *
|
StackFrame *
|
||||||
js_GetScriptedCaller(JSContext *cx, JSStackFrame *fp)
|
js_GetScriptedCaller(JSContext *cx, StackFrame *fp)
|
||||||
{
|
{
|
||||||
if (!fp)
|
if (!fp)
|
||||||
fp = js_GetTopStackFrame(cx);
|
fp = js_GetTopStackFrame(cx);
|
||||||
|
@ -1824,7 +1398,7 @@ js_GetCurrentBytecodePC(JSContext* cx)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
JS_ASSERT_NOT_ON_TRACE(cx); /* for static analysis */
|
JS_ASSERT_NOT_ON_TRACE(cx); /* for static analysis */
|
||||||
pc = cx->regs ? cx->regs->pc : NULL;
|
pc = cx->running() ? cx->regs().pc : NULL;
|
||||||
if (!pc)
|
if (!pc)
|
||||||
return NULL;
|
return NULL;
|
||||||
imacpc = cx->fp()->maybeImacropc();
|
imacpc = cx->fp()->maybeImacropc();
|
||||||
|
@ -1891,14 +1465,14 @@ JSContext::JSContext(JSRuntime *rt)
|
||||||
: hasVersionOverride(false),
|
: hasVersionOverride(false),
|
||||||
runtime(rt),
|
runtime(rt),
|
||||||
compartment(NULL),
|
compartment(NULL),
|
||||||
regs(NULL),
|
stack(thisDuringConstruction()),
|
||||||
busyArrays()
|
busyArrays()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
JSContext::~JSContext()
|
JSContext::~JSContext()
|
||||||
{
|
{
|
||||||
#ifdef JS_THREADSAFE
|
#ifdef JS_THREADSAFE
|
||||||
JS_ASSERT(!thread);
|
JS_ASSERT(!thread_);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Free the stuff hanging off of cx. */
|
/* Free the stuff hanging off of cx. */
|
||||||
|
@ -1924,7 +1498,7 @@ void
|
||||||
JSContext::resetCompartment()
|
JSContext::resetCompartment()
|
||||||
{
|
{
|
||||||
JSObject *scopeobj;
|
JSObject *scopeobj;
|
||||||
if (hasfp()) {
|
if (stack.running()) {
|
||||||
scopeobj = &fp()->scopeChain();
|
scopeobj = &fp()->scopeChain();
|
||||||
} else {
|
} else {
|
||||||
scopeobj = globalObject;
|
scopeobj = globalObject;
|
||||||
|
@ -1969,71 +1543,10 @@ JSContext::wrapPendingException()
|
||||||
setPendingException(v);
|
setPendingException(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
JSContext::pushSegmentAndFrame(js::StackSegment *newseg, JSFrameRegs &newregs)
|
|
||||||
{
|
|
||||||
JS_ASSERT(regs != &newregs);
|
|
||||||
if (hasActiveSegment())
|
|
||||||
currentSegment->suspend(regs);
|
|
||||||
newseg->setPreviousInContext(currentSegment);
|
|
||||||
currentSegment = newseg;
|
|
||||||
setCurrentRegs(&newregs);
|
|
||||||
newseg->joinContext(this, newregs.fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
JSContext::popSegmentAndFrame()
|
|
||||||
{
|
|
||||||
JS_ASSERT_IF(regs->fp->hasCallObj(), !regs->fp->callObj().getPrivate());
|
|
||||||
JS_ASSERT_IF(regs->fp->hasArgsObj(), !regs->fp->argsObj().getPrivate());
|
|
||||||
JS_ASSERT(currentSegment->maybeContext() == this);
|
|
||||||
JS_ASSERT(currentSegment->getInitialFrame() == regs->fp);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* NB: This function calls resetCompartment, which may GC, so the stack needs
|
|
||||||
* to be in a GC-able state by that point.
|
|
||||||
*/
|
|
||||||
|
|
||||||
currentSegment->leaveContext();
|
|
||||||
currentSegment = currentSegment->getPreviousInContext();
|
|
||||||
if (currentSegment) {
|
|
||||||
if (currentSegment->isSaved()) {
|
|
||||||
setCurrentRegs(NULL);
|
|
||||||
resetCompartment();
|
|
||||||
} else {
|
|
||||||
setCurrentRegs(currentSegment->getSuspendedRegs());
|
|
||||||
currentSegment->resume();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
JS_ASSERT(regs->fp->prev() == NULL);
|
|
||||||
setCurrentRegs(NULL);
|
|
||||||
resetCompartment();
|
|
||||||
}
|
|
||||||
maybeMigrateVersionOverride();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
JSContext::saveActiveSegment()
|
|
||||||
{
|
|
||||||
JS_ASSERT(hasActiveSegment());
|
|
||||||
currentSegment->save(regs);
|
|
||||||
setCurrentRegs(NULL);
|
|
||||||
resetCompartment();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
JSContext::restoreSegment()
|
|
||||||
{
|
|
||||||
js::StackSegment *ccs = currentSegment;
|
|
||||||
setCurrentRegs(ccs->getSuspendedRegs());
|
|
||||||
ccs->restore();
|
|
||||||
resetCompartment();
|
|
||||||
}
|
|
||||||
|
|
||||||
JSGenerator *
|
JSGenerator *
|
||||||
JSContext::generatorFor(JSStackFrame *fp) const
|
JSContext::generatorFor(StackFrame *fp) const
|
||||||
{
|
{
|
||||||
JS_ASSERT(stack().contains(fp) && fp->isGeneratorFrame());
|
JS_ASSERT(stack.contains(fp) && fp->isGeneratorFrame());
|
||||||
JS_ASSERT(!fp->isFloatingGenerator());
|
JS_ASSERT(!fp->isFloatingGenerator());
|
||||||
JS_ASSERT(!genStack.empty());
|
JS_ASSERT(!genStack.empty());
|
||||||
|
|
||||||
|
@ -2049,17 +1562,6 @@ JSContext::generatorFor(JSStackFrame *fp) const
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
StackSegment *
|
|
||||||
StackSpace::containingSegment(const JSStackFrame *target)
|
|
||||||
{
|
|
||||||
for (StackSegment *seg = currentSegment; seg; seg = seg->getPreviousInMemory()) {
|
|
||||||
if (seg->contains(target))
|
|
||||||
return seg;
|
|
||||||
}
|
|
||||||
JS_NOT_REACHED("frame not in stack space");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_FRIEND_API(void)
|
JS_FRIEND_API(void)
|
||||||
JSRuntime::onTooMuchMalloc()
|
JSRuntime::onTooMuchMalloc()
|
||||||
{
|
{
|
||||||
|
|
842
js/src/jscntxt.h
842
js/src/jscntxt.h
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -43,7 +43,6 @@
|
||||||
|
|
||||||
#include "jscntxt.h"
|
#include "jscntxt.h"
|
||||||
#include "jscompartment.h"
|
#include "jscompartment.h"
|
||||||
#include "jsparse.h"
|
|
||||||
#include "jsstaticcheck.h"
|
#include "jsstaticcheck.h"
|
||||||
#include "jsxml.h"
|
#include "jsxml.h"
|
||||||
#include "jsregexp.h"
|
#include "jsregexp.h"
|
||||||
|
@ -64,7 +63,7 @@ GetGlobalForScopeChain(JSContext *cx)
|
||||||
*/
|
*/
|
||||||
VOUCH_DOES_NOT_REQUIRE_STACK();
|
VOUCH_DOES_NOT_REQUIRE_STACK();
|
||||||
|
|
||||||
if (cx->hasfp())
|
if (cx->running())
|
||||||
return cx->fp()->scopeChain().getGlobal();
|
return cx->fp()->scopeChain().getGlobal();
|
||||||
|
|
||||||
JSObject *scope = cx->globalObject;
|
JSObject *scope = cx->globalObject;
|
||||||
|
@ -76,425 +75,6 @@ GetGlobalForScopeChain(JSContext *cx)
|
||||||
return scope->asGlobal();
|
return scope->asGlobal();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef JS_METHODJIT
|
|
||||||
inline js::mjit::JaegerCompartment *JSContext::jaegerCompartment()
|
|
||||||
{
|
|
||||||
return compartment->jaegerCompartment;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
inline bool
|
|
||||||
JSContext::ensureGeneratorStackSpace()
|
|
||||||
{
|
|
||||||
bool ok = genStack.reserve(genStack.length() + 1);
|
|
||||||
if (!ok)
|
|
||||||
js_ReportOutOfMemory(this);
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline js::RegExpStatics *
|
|
||||||
JSContext::regExpStatics()
|
|
||||||
{
|
|
||||||
return js::RegExpStatics::extractFrom(js::GetGlobalForScopeChain(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace js {
|
|
||||||
|
|
||||||
JS_REQUIRES_STACK JS_ALWAYS_INLINE JSFrameRegs *
|
|
||||||
StackSegment::getCurrentRegs() const
|
|
||||||
{
|
|
||||||
JS_ASSERT(inContext());
|
|
||||||
return isActive() ? cx->regs : getSuspendedRegs();
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_REQUIRES_STACK JS_ALWAYS_INLINE JSStackFrame *
|
|
||||||
StackSegment::getCurrentFrame() const
|
|
||||||
{
|
|
||||||
return getCurrentRegs()->fp;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_REQUIRES_STACK inline Value *
|
|
||||||
StackSpace::firstUnused() const
|
|
||||||
{
|
|
||||||
StackSegment *seg = currentSegment;
|
|
||||||
if (!seg) {
|
|
||||||
JS_ASSERT(invokeArgEnd == NULL);
|
|
||||||
return base;
|
|
||||||
}
|
|
||||||
if (seg->inContext()) {
|
|
||||||
Value *sp = seg->getCurrentRegs()->sp;
|
|
||||||
if (invokeArgEnd > sp) {
|
|
||||||
JS_ASSERT(invokeSegment == currentSegment);
|
|
||||||
JS_ASSERT_IF(seg->maybeContext()->hasfp(),
|
|
||||||
invokeFrame == seg->maybeContext()->fp());
|
|
||||||
return invokeArgEnd;
|
|
||||||
}
|
|
||||||
return sp;
|
|
||||||
}
|
|
||||||
JS_ASSERT(invokeArgEnd);
|
|
||||||
JS_ASSERT(invokeSegment == currentSegment);
|
|
||||||
return invokeArgEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Inline so we don't need the friend API. */
|
|
||||||
JS_ALWAYS_INLINE bool
|
|
||||||
StackSpace::isCurrentAndActive(JSContext *cx) const
|
|
||||||
{
|
|
||||||
#ifdef DEBUG
|
|
||||||
JS_ASSERT_IF(cx->getCurrentSegment(),
|
|
||||||
cx->getCurrentSegment()->maybeContext() == cx);
|
|
||||||
cx->assertSegmentsInSync();
|
|
||||||
#endif
|
|
||||||
return currentSegment &&
|
|
||||||
currentSegment->isActive() &&
|
|
||||||
currentSegment == cx->getCurrentSegment();
|
|
||||||
}
|
|
||||||
|
|
||||||
STATIC_POSTCONDITION(!return || ubound(from) >= nvals)
|
|
||||||
JS_ALWAYS_INLINE bool
|
|
||||||
StackSpace::ensureSpace(JSContext *maybecx, Value *from, ptrdiff_t nvals) const
|
|
||||||
{
|
|
||||||
JS_ASSERT(from >= firstUnused());
|
|
||||||
#ifdef XP_WIN
|
|
||||||
JS_ASSERT(from <= commitEnd);
|
|
||||||
if (commitEnd - from >= nvals)
|
|
||||||
goto success;
|
|
||||||
if (end - from < nvals) {
|
|
||||||
if (maybecx)
|
|
||||||
js_ReportOutOfScriptQuota(maybecx);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!bumpCommit(from, nvals)) {
|
|
||||||
if (maybecx)
|
|
||||||
js_ReportOutOfScriptQuota(maybecx);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
goto success;
|
|
||||||
#else
|
|
||||||
if (end - from < nvals) {
|
|
||||||
if (maybecx)
|
|
||||||
js_ReportOutOfScriptQuota(maybecx);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
goto success;
|
|
||||||
#endif
|
|
||||||
success:
|
|
||||||
#ifdef DEBUG
|
|
||||||
memset(from, 0xde, nvals * sizeof(js::Value));
|
|
||||||
#endif
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_ALWAYS_INLINE bool
|
|
||||||
StackSpace::ensureEnoughSpaceToEnterTrace()
|
|
||||||
{
|
|
||||||
#ifdef XP_WIN
|
|
||||||
return ensureSpace(NULL, firstUnused(), MAX_TRACE_SPACE_VALS);
|
|
||||||
#endif
|
|
||||||
return end - firstUnused() > MAX_TRACE_SPACE_VALS;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_ALWAYS_INLINE bool
|
|
||||||
StackSpace::EnsureSpaceCheck::operator()(const StackSpace &stack, JSContext *cx,
|
|
||||||
Value *from, uintN nvals)
|
|
||||||
{
|
|
||||||
return stack.ensureSpace(cx, from, nvals);
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_ALWAYS_INLINE bool
|
|
||||||
StackSpace::LimitCheck::operator()(const StackSpace &stack, JSContext *cx,
|
|
||||||
Value *from, uintN nvals)
|
|
||||||
{
|
|
||||||
JS_ASSERT(from == stack.firstUnused());
|
|
||||||
JS_ASSERT(from < *limit);
|
|
||||||
if (*limit - from >= ptrdiff_t(nvals))
|
|
||||||
return true;
|
|
||||||
if (stack.bumpCommitAndLimit(base, from, nvals, limit))
|
|
||||||
return true;
|
|
||||||
js_ReportOverRecursed(cx);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_REQUIRES_STACK JS_ALWAYS_INLINE bool
|
|
||||||
StackSpace::pushInvokeArgs(JSContext *cx, uintN argc, InvokeArgsGuard *ag)
|
|
||||||
{
|
|
||||||
if (JS_UNLIKELY(!isCurrentAndActive(cx)))
|
|
||||||
return pushSegmentForInvoke(cx, argc, ag);
|
|
||||||
|
|
||||||
Value *sp = cx->regs->sp;
|
|
||||||
Value *start = invokeArgEnd > sp ? invokeArgEnd : sp;
|
|
||||||
JS_ASSERT(start == firstUnused());
|
|
||||||
uintN nvals = 2 + argc;
|
|
||||||
if (!ensureSpace(cx, start, nvals))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Value *vp = start;
|
|
||||||
Value *vpend = vp + nvals;
|
|
||||||
/* Don't need to MakeRangeGCSafe: the VM stack is conservatively marked. */
|
|
||||||
|
|
||||||
/* Use invokeArgEnd to root [vp, vpend) until the frame is pushed. */
|
|
||||||
ag->prevInvokeArgEnd = invokeArgEnd;
|
|
||||||
invokeArgEnd = vpend;
|
|
||||||
#ifdef DEBUG
|
|
||||||
ag->prevInvokeSegment = invokeSegment;
|
|
||||||
invokeSegment = currentSegment;
|
|
||||||
ag->prevInvokeFrame = invokeFrame;
|
|
||||||
invokeFrame = cx->maybefp();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ag->cx = cx;
|
|
||||||
ImplicitCast<CallArgs>(*ag) = CallArgsFromVp(argc, vp);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_REQUIRES_STACK JS_ALWAYS_INLINE void
|
|
||||||
StackSpace::popInvokeArgs(const InvokeArgsGuard &ag)
|
|
||||||
{
|
|
||||||
if (JS_UNLIKELY(ag.seg != NULL)) {
|
|
||||||
popSegmentForInvoke(ag);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_ASSERT(isCurrentAndActive(ag.cx));
|
|
||||||
JS_ASSERT(invokeSegment == currentSegment);
|
|
||||||
JS_ASSERT(invokeFrame == ag.cx->maybefp());
|
|
||||||
JS_ASSERT(invokeArgEnd == ag.argv() + ag.argc());
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
invokeSegment = ag.prevInvokeSegment;
|
|
||||||
invokeFrame = ag.prevInvokeFrame;
|
|
||||||
#endif
|
|
||||||
invokeArgEnd = ag.prevInvokeArgEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_ALWAYS_INLINE
|
|
||||||
InvokeArgsGuard::~InvokeArgsGuard()
|
|
||||||
{
|
|
||||||
if (JS_UNLIKELY(!pushed()))
|
|
||||||
return;
|
|
||||||
cx->stack().popInvokeArgs(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Check>
|
|
||||||
JS_REQUIRES_STACK JS_ALWAYS_INLINE JSStackFrame *
|
|
||||||
StackSpace::getCallFrame(JSContext *cx, Value *firstUnused, uintN nactual,
|
|
||||||
JSFunction *fun, JSScript *script, uint32 *flags,
|
|
||||||
Check check) const
|
|
||||||
{
|
|
||||||
JS_ASSERT(fun->script() == script);
|
|
||||||
|
|
||||||
/* Include an extra sizeof(JSStackFrame) for the method-jit. */
|
|
||||||
uintN nvals = VALUES_PER_STACK_FRAME + script->nslots;
|
|
||||||
uintN nformal = fun->nargs;
|
|
||||||
|
|
||||||
/* Maintain layout invariant: &formalArgs[0] == ((Value *)fp) - nformal. */
|
|
||||||
|
|
||||||
if (nactual == nformal) {
|
|
||||||
if (JS_UNLIKELY(!check(*this, cx, firstUnused, nvals)))
|
|
||||||
return NULL;
|
|
||||||
return reinterpret_cast<JSStackFrame *>(firstUnused);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nactual < nformal) {
|
|
||||||
*flags |= JSFRAME_UNDERFLOW_ARGS;
|
|
||||||
uintN nmissing = nformal - nactual;
|
|
||||||
if (JS_UNLIKELY(!check(*this, cx, firstUnused, nmissing + nvals)))
|
|
||||||
return NULL;
|
|
||||||
SetValueRangeToUndefined(firstUnused, nmissing);
|
|
||||||
return reinterpret_cast<JSStackFrame *>(firstUnused + nmissing);
|
|
||||||
}
|
|
||||||
|
|
||||||
*flags |= JSFRAME_OVERFLOW_ARGS;
|
|
||||||
uintN ncopy = 2 + nformal;
|
|
||||||
if (JS_UNLIKELY(!check(*this, cx, firstUnused, ncopy + nvals)))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
Value *dst = firstUnused;
|
|
||||||
Value *src = firstUnused - (2 + nactual);
|
|
||||||
PodCopy(dst, src, ncopy);
|
|
||||||
Debug_SetValueRangeToCrashOnTouch(src, ncopy);
|
|
||||||
return reinterpret_cast<JSStackFrame *>(firstUnused + ncopy);
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_REQUIRES_STACK JS_ALWAYS_INLINE bool
|
|
||||||
StackSpace::getInvokeFrame(JSContext *cx, const CallArgs &args,
|
|
||||||
JSFunction *fun, JSScript *script,
|
|
||||||
uint32 *flags, InvokeFrameGuard *fg) const
|
|
||||||
{
|
|
||||||
JS_ASSERT(firstUnused() == args.argv() + args.argc());
|
|
||||||
|
|
||||||
Value *firstUnused = args.argv() + args.argc();
|
|
||||||
fg->regs_.fp = getCallFrame(cx, firstUnused, args.argc(), fun, script, flags,
|
|
||||||
EnsureSpaceCheck());
|
|
||||||
fg->regs_.sp = fg->regs_.fp->slots() + script->nfixed;
|
|
||||||
fg->regs_.pc = script->code;
|
|
||||||
|
|
||||||
return fg->regs_.fp != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_REQUIRES_STACK JS_ALWAYS_INLINE void
|
|
||||||
StackSpace::pushInvokeFrame(JSContext *cx, const CallArgs &args,
|
|
||||||
InvokeFrameGuard *fg)
|
|
||||||
{
|
|
||||||
JS_ASSERT(firstUnused() == args.argv() + args.argc());
|
|
||||||
|
|
||||||
if (JS_UNLIKELY(!currentSegment->inContext())) {
|
|
||||||
cx->pushSegmentAndFrame(currentSegment, fg->regs_);
|
|
||||||
} else {
|
|
||||||
fg->prevRegs_ = cx->regs;
|
|
||||||
cx->setCurrentRegs(&fg->regs_);
|
|
||||||
}
|
|
||||||
|
|
||||||
fg->cx_ = cx;
|
|
||||||
JS_ASSERT(isCurrentAndActive(cx));
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_REQUIRES_STACK JS_ALWAYS_INLINE void
|
|
||||||
StackSpace::popInvokeFrame(const InvokeFrameGuard &fg)
|
|
||||||
{
|
|
||||||
JSContext *cx = fg.cx_;
|
|
||||||
JSStackFrame *fp = fg.regs_.fp;
|
|
||||||
|
|
||||||
PutActivationObjects(cx, fp);
|
|
||||||
|
|
||||||
JS_ASSERT(isCurrentAndActive(cx));
|
|
||||||
if (JS_UNLIKELY(currentSegment->getInitialFrame() == fp)) {
|
|
||||||
cx->popSegmentAndFrame();
|
|
||||||
} else {
|
|
||||||
JS_ASSERT(&fg.regs_ == cx->regs);
|
|
||||||
JS_ASSERT(fp->prev_ == fg.prevRegs_->fp);
|
|
||||||
JS_ASSERT(fp->prevpc() == fg.prevRegs_->pc);
|
|
||||||
cx->setCurrentRegs(fg.prevRegs_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_ALWAYS_INLINE void
|
|
||||||
InvokeFrameGuard::pop()
|
|
||||||
{
|
|
||||||
JS_ASSERT(pushed());
|
|
||||||
cx_->stack().popInvokeFrame(*this);
|
|
||||||
cx_ = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_REQUIRES_STACK JS_ALWAYS_INLINE JSStackFrame *
|
|
||||||
StackSpace::getInlineFrame(JSContext *cx, Value *sp, uintN nactual,
|
|
||||||
JSFunction *fun, JSScript *script, uint32 *flags) const
|
|
||||||
{
|
|
||||||
JS_ASSERT(isCurrentAndActive(cx));
|
|
||||||
JS_ASSERT(cx->hasActiveSegment());
|
|
||||||
JS_ASSERT(cx->regs->sp == sp);
|
|
||||||
|
|
||||||
return getCallFrame(cx, sp, nactual, fun, script, flags, EnsureSpaceCheck());
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_REQUIRES_STACK JS_ALWAYS_INLINE JSStackFrame *
|
|
||||||
StackSpace::getInlineFrameWithinLimit(JSContext *cx, Value *sp, uintN nactual,
|
|
||||||
JSFunction *fun, JSScript *script, uint32 *flags,
|
|
||||||
JSStackFrame *base, Value **limit) const
|
|
||||||
{
|
|
||||||
JS_ASSERT(isCurrentAndActive(cx));
|
|
||||||
JS_ASSERT(cx->hasActiveSegment());
|
|
||||||
JS_ASSERT(cx->regs->sp == sp);
|
|
||||||
|
|
||||||
return getCallFrame(cx, sp, nactual, fun, script, flags, LimitCheck(base, limit));
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_REQUIRES_STACK JS_ALWAYS_INLINE void
|
|
||||||
StackSpace::pushInlineFrame(JSContext *cx, JSScript *script, JSStackFrame *fp,
|
|
||||||
JSFrameRegs *regs)
|
|
||||||
{
|
|
||||||
JS_ASSERT(isCurrentAndActive(cx));
|
|
||||||
JS_ASSERT(cx->regs == regs && script == fp->script());
|
|
||||||
|
|
||||||
regs->fp = fp;
|
|
||||||
regs->pc = script->code;
|
|
||||||
regs->sp = fp->slots() + script->nfixed;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_REQUIRES_STACK JS_ALWAYS_INLINE void
|
|
||||||
StackSpace::popInlineFrame(JSContext *cx, JSStackFrame *prev, Value *newsp)
|
|
||||||
{
|
|
||||||
JSFrameRegs *regs = cx->regs;
|
|
||||||
JSStackFrame *fp = regs->fp;
|
|
||||||
|
|
||||||
JS_ASSERT(isCurrentAndActive(cx));
|
|
||||||
JS_ASSERT(cx->hasActiveSegment());
|
|
||||||
JS_ASSERT(fp->prev_ == prev);
|
|
||||||
JS_ASSERT(!fp->hasImacropc());
|
|
||||||
JS_ASSERT(prev->base() <= newsp && newsp <= fp->formalArgsEnd());
|
|
||||||
|
|
||||||
PutActivationObjects(cx, fp);
|
|
||||||
|
|
||||||
regs->pc = prev->pc(cx, fp);
|
|
||||||
regs->fp = prev;
|
|
||||||
regs->sp = newsp;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_ALWAYS_INLINE Value *
|
|
||||||
StackSpace::getStackLimit(JSContext *cx)
|
|
||||||
{
|
|
||||||
Value *sp = cx->regs->sp;
|
|
||||||
JS_ASSERT(sp == firstUnused());
|
|
||||||
Value *limit = sp + STACK_QUOTA;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Try to reserve the whole STACK_QUOTA. If that fails, though, just
|
|
||||||
* reserve the minimum required space: enough for the nslots + an
|
|
||||||
* additional stack frame.
|
|
||||||
*/
|
|
||||||
#ifdef XP_WIN
|
|
||||||
if (JS_LIKELY(limit <= commitEnd))
|
|
||||||
return limit;
|
|
||||||
if (ensureSpace(NULL /* don't report error */, sp, STACK_QUOTA))
|
|
||||||
return limit;
|
|
||||||
uintN minimum = cx->fp()->numSlots() + VALUES_PER_STACK_FRAME;
|
|
||||||
return ensureSpace(cx, sp, minimum) ? sp + minimum : NULL;
|
|
||||||
#else
|
|
||||||
if (JS_LIKELY(limit <= end))
|
|
||||||
return limit;
|
|
||||||
uintN minimum = cx->fp()->numSlots() + VALUES_PER_STACK_FRAME;
|
|
||||||
return ensureSpace(cx, sp, minimum) ? sp + minimum : NULL;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_REQUIRES_STACK inline
|
|
||||||
FrameRegsIter::FrameRegsIter(JSContext *cx)
|
|
||||||
: cx(cx)
|
|
||||||
{
|
|
||||||
curseg = cx->getCurrentSegment();
|
|
||||||
if (JS_UNLIKELY(!curseg || !curseg->isActive())) {
|
|
||||||
initSlow();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
JS_ASSERT(cx->regs->fp);
|
|
||||||
curfp = cx->regs->fp;
|
|
||||||
cursp = cx->regs->sp;
|
|
||||||
curpc = cx->regs->pc;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline FrameRegsIter &
|
|
||||||
FrameRegsIter::operator++()
|
|
||||||
{
|
|
||||||
JSStackFrame *fp = curfp;
|
|
||||||
JSStackFrame *prev = curfp = curfp->prev();
|
|
||||||
if (!prev)
|
|
||||||
return *this;
|
|
||||||
|
|
||||||
curpc = curfp->pc(cx, fp);
|
|
||||||
|
|
||||||
if (JS_UNLIKELY(fp == curseg->getInitialFrame())) {
|
|
||||||
incSlow(fp, prev);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
cursp = fp->formalArgsEnd();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline GSNCache *
|
inline GSNCache *
|
||||||
GetGSNCache(JSContext *cx)
|
GetGSNCache(JSContext *cx)
|
||||||
{
|
{
|
||||||
|
@ -528,7 +108,7 @@ class CompartmentChecker
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit CompartmentChecker(JSContext *cx) : context(cx), compartment(cx->compartment) {
|
explicit CompartmentChecker(JSContext *cx) : context(cx), compartment(cx->compartment) {
|
||||||
check(cx->hasfp() ? JS_GetGlobalForScopeChain(cx) : cx->globalObject);
|
check(cx->running() ? JS_GetGlobalForScopeChain(cx) : cx->globalObject);
|
||||||
VOUCH_DOES_NOT_REQUIRE_STACK();
|
VOUCH_DOES_NOT_REQUIRE_STACK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -613,7 +193,7 @@ class CompartmentChecker
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void check(JSStackFrame *fp) {
|
void check(StackFrame *fp) {
|
||||||
check(&fp->scopeChain());
|
check(&fp->scopeChain());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -811,6 +391,28 @@ CanLeaveTrace(JSContext *cx)
|
||||||
|
|
||||||
} /* namespace js */
|
} /* namespace js */
|
||||||
|
|
||||||
|
#ifdef JS_METHODJIT
|
||||||
|
inline js::mjit::JaegerCompartment *JSContext::jaegerCompartment()
|
||||||
|
{
|
||||||
|
return compartment->jaegerCompartment;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
JSContext::ensureGeneratorStackSpace()
|
||||||
|
{
|
||||||
|
bool ok = genStack.reserve(genStack.length() + 1);
|
||||||
|
if (!ok)
|
||||||
|
js_ReportOutOfMemory(this);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline js::RegExpStatics *
|
||||||
|
JSContext::regExpStatics()
|
||||||
|
{
|
||||||
|
return js::RegExpStatics::extractFrom(js::GetGlobalForScopeChain(this));
|
||||||
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
JSContext::setPendingException(js::Value v) {
|
JSContext::setPendingException(js::Value v) {
|
||||||
this->throwing = true;
|
this->throwing = true;
|
||||||
|
|
|
@ -222,7 +222,7 @@ JSCompartment::wrap(JSContext *cx, Value *vp)
|
||||||
* This loses us some transparency, and is generally very cheesy.
|
* This loses us some transparency, and is generally very cheesy.
|
||||||
*/
|
*/
|
||||||
JSObject *global;
|
JSObject *global;
|
||||||
if (cx->hasfp()) {
|
if (cx->running()) {
|
||||||
global = cx->fp()->scopeChain().getGlobal();
|
global = cx->fp()->scopeChain().getGlobal();
|
||||||
} else {
|
} else {
|
||||||
global = cx->globalObject;
|
global = cx->globalObject;
|
||||||
|
|
|
@ -136,6 +136,10 @@ struct TracerState
|
||||||
*/
|
*/
|
||||||
struct TraceNativeStorage
|
struct TraceNativeStorage
|
||||||
{
|
{
|
||||||
|
/* Max number of stack slots/frame that may need to be restored in LeaveTree. */
|
||||||
|
static const size_t MAX_NATIVE_STACK_SLOTS = 4096;
|
||||||
|
static const size_t MAX_CALL_STACK_ENTRIES = 500;
|
||||||
|
|
||||||
double stack_global_buf[MAX_NATIVE_STACK_SLOTS + GLOBAL_SLOTS_BUFFER_SIZE];
|
double stack_global_buf[MAX_NATIVE_STACK_SLOTS + GLOBAL_SLOTS_BUFFER_SIZE];
|
||||||
FrameInfo *callstack_buf[MAX_CALL_STACK_ENTRIES];
|
FrameInfo *callstack_buf[MAX_CALL_STACK_ENTRIES];
|
||||||
|
|
||||||
|
@ -456,7 +460,7 @@ struct JS_FRIEND_API(JSCompartment) {
|
||||||
|
|
||||||
js::NativeIterCache nativeIterCache;
|
js::NativeIterCache nativeIterCache;
|
||||||
|
|
||||||
typedef js::LazilyConstructed<js::ToSourceCache> LazyToSourceCache;
|
typedef js::Maybe<js::ToSourceCache> LazyToSourceCache;
|
||||||
LazyToSourceCache toSourceCache;
|
LazyToSourceCache toSourceCache;
|
||||||
|
|
||||||
JSCompartment(JSRuntime *rt);
|
JSCompartment(JSRuntime *rt);
|
||||||
|
|
|
@ -73,6 +73,8 @@
|
||||||
|
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
|
|
||||||
|
#include "vm/Stack-inl.h"
|
||||||
|
|
||||||
using namespace js;
|
using namespace js;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2106,13 +2108,13 @@ date_toJSON(JSContext *cx, uintN argc, Value *vp)
|
||||||
/* Step 6. */
|
/* Step 6. */
|
||||||
LeaveTrace(cx);
|
LeaveTrace(cx);
|
||||||
InvokeArgsGuard args;
|
InvokeArgsGuard args;
|
||||||
if (!cx->stack().pushInvokeArgs(cx, 0, &args))
|
if (!cx->stack.pushInvokeArgs(cx, 0, &args))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
args.calleev() = toISO;
|
args.calleev() = toISO;
|
||||||
args.thisv().setObject(*obj);
|
args.thisv().setObject(*obj);
|
||||||
|
|
||||||
if (!Invoke(cx, args, 0))
|
if (!Invoke(cx, args))
|
||||||
return false;
|
return false;
|
||||||
*vp = args.rval();
|
*vp = args.rval();
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -69,11 +69,13 @@
|
||||||
|
|
||||||
#include "jsatominlines.h"
|
#include "jsatominlines.h"
|
||||||
#include "jsdbgapiinlines.h"
|
#include "jsdbgapiinlines.h"
|
||||||
#include "jsinterpinlines.h"
|
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
|
#include "jsinterpinlines.h"
|
||||||
#include "jsscopeinlines.h"
|
#include "jsscopeinlines.h"
|
||||||
#include "jsscriptinlines.h"
|
#include "jsscriptinlines.h"
|
||||||
|
|
||||||
|
#include "vm/Stack-inl.h"
|
||||||
|
|
||||||
#include "jsautooplen.h"
|
#include "jsautooplen.h"
|
||||||
|
|
||||||
#include "methodjit/MethodJIT.h"
|
#include "methodjit/MethodJIT.h"
|
||||||
|
@ -116,21 +118,21 @@ JS_SetRuntimeDebugMode(JSRuntime *rt, JSBool debug)
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
void
|
void
|
||||||
ScriptDebugPrologue(JSContext *cx, JSStackFrame *fp)
|
ScriptDebugPrologue(JSContext *cx, StackFrame *fp)
|
||||||
{
|
{
|
||||||
if (fp->isFramePushedByExecute()) {
|
if (fp->isFramePushedByExecute()) {
|
||||||
if (JSInterpreterHook hook = cx->debugHooks->executeHook)
|
if (JSInterpreterHook hook = cx->debugHooks->executeHook)
|
||||||
fp->setHookData(hook(cx, fp, true, 0, cx->debugHooks->executeHookData));
|
fp->setHookData(hook(cx, Jsvalify(fp), true, 0, cx->debugHooks->executeHookData));
|
||||||
} else {
|
} else {
|
||||||
if (JSInterpreterHook hook = cx->debugHooks->callHook)
|
if (JSInterpreterHook hook = cx->debugHooks->callHook)
|
||||||
fp->setHookData(hook(cx, fp, true, 0, cx->debugHooks->callHookData));
|
fp->setHookData(hook(cx, Jsvalify(fp), true, 0, cx->debugHooks->callHookData));
|
||||||
}
|
}
|
||||||
|
|
||||||
Probes::enterJSFun(cx, fp->maybeFun(), fp->script());
|
Probes::enterJSFun(cx, fp->maybeFun(), fp->script());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ScriptDebugEpilogue(JSContext *cx, JSStackFrame *fp, bool okArg)
|
ScriptDebugEpilogue(JSContext *cx, StackFrame *fp, bool okArg)
|
||||||
{
|
{
|
||||||
JSBool ok = okArg;
|
JSBool ok = okArg;
|
||||||
|
|
||||||
|
@ -139,10 +141,10 @@ ScriptDebugEpilogue(JSContext *cx, JSStackFrame *fp, bool okArg)
|
||||||
if (void *hookData = fp->maybeHookData()) {
|
if (void *hookData = fp->maybeHookData()) {
|
||||||
if (fp->isFramePushedByExecute()) {
|
if (fp->isFramePushedByExecute()) {
|
||||||
if (JSInterpreterHook hook = cx->debugHooks->executeHook)
|
if (JSInterpreterHook hook = cx->debugHooks->executeHook)
|
||||||
hook(cx, fp, false, &ok, hookData);
|
hook(cx, Jsvalify(fp), false, &ok, hookData);
|
||||||
} else {
|
} else {
|
||||||
if (JSInterpreterHook hook = cx->debugHooks->callHook)
|
if (JSInterpreterHook hook = cx->debugHooks->callHook)
|
||||||
hook(cx, fp, false, &ok, hookData);
|
hook(cx, Jsvalify(fp), false, &ok, hookData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -836,7 +838,9 @@ js_watch_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Conditionally<AutoShapeRooter> tvr(needMethodSlotWrite, cx, needMethodSlotWrite);
|
Maybe<AutoShapeRooter> tvr;
|
||||||
|
if (needMethodSlotWrite)
|
||||||
|
tvr.construct(cx, needMethodSlotWrite);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Call the handler. This invalidates shape, so re-lookup the shape.
|
* Call the handler. This invalidates shape, so re-lookup the shape.
|
||||||
|
@ -1361,33 +1365,35 @@ JS_GetScriptPrincipals(JSContext *cx, JSScript *script)
|
||||||
JS_PUBLIC_API(JSStackFrame *)
|
JS_PUBLIC_API(JSStackFrame *)
|
||||||
JS_FrameIterator(JSContext *cx, JSStackFrame **iteratorp)
|
JS_FrameIterator(JSContext *cx, JSStackFrame **iteratorp)
|
||||||
{
|
{
|
||||||
*iteratorp = (*iteratorp == NULL) ? js_GetTopStackFrame(cx) : (*iteratorp)->prev();
|
StackFrame *fp = Valueify(*iteratorp);
|
||||||
|
*iteratorp = Jsvalify((fp == NULL) ? js_GetTopStackFrame(cx) : fp->prev());
|
||||||
return *iteratorp;
|
return *iteratorp;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSScript *)
|
JS_PUBLIC_API(JSScript *)
|
||||||
JS_GetFrameScript(JSContext *cx, JSStackFrame *fp)
|
JS_GetFrameScript(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
return fp->maybeScript();
|
return Valueify(fp)->maybeScript();
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(jsbytecode *)
|
JS_PUBLIC_API(jsbytecode *)
|
||||||
JS_GetFramePC(JSContext *cx, JSStackFrame *fp)
|
JS_GetFramePC(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
return fp->pc(cx);
|
return Valueify(fp)->pc(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSStackFrame *)
|
JS_PUBLIC_API(JSStackFrame *)
|
||||||
JS_GetScriptedCaller(JSContext *cx, JSStackFrame *fp)
|
JS_GetScriptedCaller(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
return js_GetScriptedCaller(cx, fp);
|
return Jsvalify(js_GetScriptedCaller(cx, Valueify(fp)));
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(void *)
|
JS_PUBLIC_API(void *)
|
||||||
JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp)
|
JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fpArg)
|
||||||
{
|
{
|
||||||
|
StackFrame *fp = Valueify(fpArg);
|
||||||
if (fp->annotation() && fp->isScriptFrame()) {
|
if (fp->annotation() && fp->isScriptFrame()) {
|
||||||
JSPrincipals *principals = fp->principals(cx);
|
JSPrincipals *principals = fp->scopeChain().principals(cx);
|
||||||
|
|
||||||
if (principals && principals->globalPrivilegesEnabled(cx, principals)) {
|
if (principals && principals->globalPrivilegesEnabled(cx, principals)) {
|
||||||
/*
|
/*
|
||||||
|
@ -1404,7 +1410,7 @@ JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp)
|
||||||
JS_PUBLIC_API(void)
|
JS_PUBLIC_API(void)
|
||||||
JS_SetFrameAnnotation(JSContext *cx, JSStackFrame *fp, void *annotation)
|
JS_SetFrameAnnotation(JSContext *cx, JSStackFrame *fp, void *annotation)
|
||||||
{
|
{
|
||||||
fp->setAnnotation(annotation);
|
Valueify(fp)->setAnnotation(annotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(void *)
|
JS_PUBLIC_API(void *)
|
||||||
|
@ -1412,7 +1418,7 @@ JS_GetFramePrincipalArray(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
JSPrincipals *principals;
|
JSPrincipals *principals;
|
||||||
|
|
||||||
principals = fp->principals(cx);
|
principals = Valueify(fp)->scopeChain().principals(cx);
|
||||||
if (!principals)
|
if (!principals)
|
||||||
return NULL;
|
return NULL;
|
||||||
return principals->getPrincipalArray(cx, principals);
|
return principals->getPrincipalArray(cx, principals);
|
||||||
|
@ -1421,34 +1427,36 @@ JS_GetFramePrincipalArray(JSContext *cx, JSStackFrame *fp)
|
||||||
JS_PUBLIC_API(JSBool)
|
JS_PUBLIC_API(JSBool)
|
||||||
JS_IsScriptFrame(JSContext *cx, JSStackFrame *fp)
|
JS_IsScriptFrame(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
return !fp->isDummyFrame();
|
return !Valueify(fp)->isDummyFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* this is deprecated, use JS_GetFrameScopeChain instead */
|
/* this is deprecated, use JS_GetFrameScopeChain instead */
|
||||||
JS_PUBLIC_API(JSObject *)
|
JS_PUBLIC_API(JSObject *)
|
||||||
JS_GetFrameObject(JSContext *cx, JSStackFrame *fp)
|
JS_GetFrameObject(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
return &fp->scopeChain();
|
return &Valueify(fp)->scopeChain();
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSObject *)
|
JS_PUBLIC_API(JSObject *)
|
||||||
JS_GetFrameScopeChain(JSContext *cx, JSStackFrame *fp)
|
JS_GetFrameScopeChain(JSContext *cx, JSStackFrame *fpArg)
|
||||||
{
|
{
|
||||||
JS_ASSERT(cx->stack().contains(fp));
|
StackFrame *fp = Valueify(fpArg);
|
||||||
|
JS_ASSERT(cx->stack.contains(fp));
|
||||||
|
|
||||||
js::AutoCompartment ac(cx, &fp->scopeChain());
|
js::AutoCompartment ac(cx, &fp->scopeChain());
|
||||||
if (!ac.enter())
|
if (!ac.enter())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Force creation of argument and call objects if not yet created */
|
/* Force creation of argument and call objects if not yet created */
|
||||||
(void) JS_GetFrameCallObject(cx, fp);
|
(void) JS_GetFrameCallObject(cx, Jsvalify(fp));
|
||||||
return GetScopeChain(cx, fp);
|
return GetScopeChain(cx, fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSObject *)
|
JS_PUBLIC_API(JSObject *)
|
||||||
JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fp)
|
JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fpArg)
|
||||||
{
|
{
|
||||||
JS_ASSERT(cx->stack().contains(fp));
|
StackFrame *fp = Valueify(fpArg);
|
||||||
|
JS_ASSERT(cx->stack.contains(fp));
|
||||||
|
|
||||||
if (!fp->isFunctionFrame())
|
if (!fp->isFunctionFrame())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1467,8 +1475,9 @@ JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fp)
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSBool)
|
JS_PUBLIC_API(JSBool)
|
||||||
JS_GetFrameThis(JSContext *cx, JSStackFrame *fp, jsval *thisv)
|
JS_GetFrameThis(JSContext *cx, JSStackFrame *fpArg, jsval *thisv)
|
||||||
{
|
{
|
||||||
|
StackFrame *fp = Valueify(fpArg);
|
||||||
if (fp->isDummyFrame())
|
if (fp->isDummyFrame())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1485,12 +1494,13 @@ JS_GetFrameThis(JSContext *cx, JSStackFrame *fp, jsval *thisv)
|
||||||
JS_PUBLIC_API(JSFunction *)
|
JS_PUBLIC_API(JSFunction *)
|
||||||
JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp)
|
JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
return fp->maybeFun();
|
return Valueify(fp)->maybeFun();
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSObject *)
|
JS_PUBLIC_API(JSObject *)
|
||||||
JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fp)
|
JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fpArg)
|
||||||
{
|
{
|
||||||
|
StackFrame *fp = Valueify(fpArg);
|
||||||
if (!fp->isFunctionFrame())
|
if (!fp->isFunctionFrame())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -1502,13 +1512,13 @@ JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fp)
|
||||||
JS_PUBLIC_API(JSBool)
|
JS_PUBLIC_API(JSBool)
|
||||||
JS_IsConstructorFrame(JSContext *cx, JSStackFrame *fp)
|
JS_IsConstructorFrame(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
return fp->isConstructing();
|
return Valueify(fp)->isConstructing();
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSObject *)
|
JS_PUBLIC_API(JSObject *)
|
||||||
JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp)
|
JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
return fp->maybeCallee();
|
return Valueify(fp)->maybeCallee();
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSBool)
|
JS_PUBLIC_API(JSBool)
|
||||||
|
@ -1516,7 +1526,7 @@ JS_GetValidFrameCalleeObject(JSContext *cx, JSStackFrame *fp, jsval *vp)
|
||||||
{
|
{
|
||||||
Value v;
|
Value v;
|
||||||
|
|
||||||
if (!fp->getValidCalleeObject(cx, &v))
|
if (!Valueify(fp)->getValidCalleeObject(cx, &v))
|
||||||
return false;
|
return false;
|
||||||
*vp = Jsvalify(v);
|
*vp = Jsvalify(v);
|
||||||
return true;
|
return true;
|
||||||
|
@ -1525,18 +1535,19 @@ JS_GetValidFrameCalleeObject(JSContext *cx, JSStackFrame *fp, jsval *vp)
|
||||||
JS_PUBLIC_API(JSBool)
|
JS_PUBLIC_API(JSBool)
|
||||||
JS_IsDebuggerFrame(JSContext *cx, JSStackFrame *fp)
|
JS_IsDebuggerFrame(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
return fp->isDebuggerFrame();
|
return Valueify(fp)->isDebuggerFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(jsval)
|
JS_PUBLIC_API(jsval)
|
||||||
JS_GetFrameReturnValue(JSContext *cx, JSStackFrame *fp)
|
JS_GetFrameReturnValue(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
return Jsvalify(fp->returnValue());
|
return Jsvalify(Valueify(fp)->returnValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(void)
|
JS_PUBLIC_API(void)
|
||||||
JS_SetFrameReturnValue(JSContext *cx, JSStackFrame *fp, jsval rval)
|
JS_SetFrameReturnValue(JSContext *cx, JSStackFrame *fpArg, jsval rval)
|
||||||
{
|
{
|
||||||
|
StackFrame *fp = Valueify(fpArg);
|
||||||
#ifdef JS_METHODJIT
|
#ifdef JS_METHODJIT
|
||||||
JS_ASSERT_IF(fp->isScriptFrame(), fp->script()->debugMode);
|
JS_ASSERT_IF(fp->isScriptFrame(), fp->script()->debugMode);
|
||||||
#endif
|
#endif
|
||||||
|
@ -1590,7 +1601,7 @@ JS_SetDestroyScriptHook(JSRuntime *rt, JSDestroyScriptHook hook,
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
||||||
JS_PUBLIC_API(JSBool)
|
JS_PUBLIC_API(JSBool)
|
||||||
JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp,
|
JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fpArg,
|
||||||
const jschar *chars, uintN length,
|
const jschar *chars, uintN length,
|
||||||
const char *filename, uintN lineno,
|
const char *filename, uintN lineno,
|
||||||
jsval *rval)
|
jsval *rval)
|
||||||
|
@ -1600,7 +1611,7 @@ JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp,
|
||||||
if (!CheckDebugMode(cx))
|
if (!CheckDebugMode(cx))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
JSObject *scobj = JS_GetFrameScopeChain(cx, fp);
|
JSObject *scobj = JS_GetFrameScopeChain(cx, fpArg);
|
||||||
if (!scobj)
|
if (!scobj)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1614,7 +1625,8 @@ JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp,
|
||||||
* we use a static level that will cause us not to attempt to optimize
|
* we use a static level that will cause us not to attempt to optimize
|
||||||
* variable references made by this frame.
|
* variable references made by this frame.
|
||||||
*/
|
*/
|
||||||
JSScript *script = Compiler::compileScript(cx, scobj, fp, fp->principals(cx),
|
StackFrame *fp = Valueify(fpArg);
|
||||||
|
JSScript *script = Compiler::compileScript(cx, scobj, fp, fp->scopeChain().principals(cx),
|
||||||
TCF_COMPILE_N_GO, chars, length,
|
TCF_COMPILE_N_GO, chars, length,
|
||||||
filename, lineno, cx->findVersion(),
|
filename, lineno, cx->findVersion(),
|
||||||
NULL, UpvarCookie::UPVAR_LEVEL_LIMIT);
|
NULL, UpvarCookie::UPVAR_LEVEL_LIMIT);
|
||||||
|
@ -1622,7 +1634,8 @@ JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp,
|
||||||
if (!script)
|
if (!script)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool ok = Execute(cx, *scobj, script, fp, JSFRAME_DEBUGGER | JSFRAME_EVAL, Valueify(rval));
|
uintN evalFlags = StackFrame::DEBUGGER | StackFrame::EVAL;
|
||||||
|
bool ok = Execute(cx, *scobj, script, fp, evalFlags, Valueify(rval));
|
||||||
|
|
||||||
js_DestroyScript(cx, script);
|
js_DestroyScript(cx, script);
|
||||||
return ok;
|
return ok;
|
||||||
|
@ -2423,7 +2436,7 @@ jstv_Lineno(JSContext *cx, JSStackFrame *fp)
|
||||||
JS_FRIEND_API(void)
|
JS_FRIEND_API(void)
|
||||||
js::StoreTraceVisState(JSContext *cx, TraceVisState s, TraceVisExitReason r)
|
js::StoreTraceVisState(JSContext *cx, TraceVisState s, TraceVisExitReason r)
|
||||||
{
|
{
|
||||||
JSStackFrame *fp = cx->fp();
|
StackFrame *fp = cx->fp();
|
||||||
|
|
||||||
char *script_file = jstv_Filename(fp);
|
char *script_file = jstv_Filename(fp);
|
||||||
JSHashNumber hash = JS_HashString(script_file);
|
JSHashNumber hash = JS_HashString(script_file);
|
||||||
|
|
|
@ -2211,7 +2211,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cookie.isFree()) {
|
if (cookie.isFree()) {
|
||||||
JSStackFrame *caller = cg->parser->callerFrame;
|
StackFrame *caller = cg->parser->callerFrame;
|
||||||
if (caller) {
|
if (caller) {
|
||||||
JS_ASSERT(cg->compileAndGo());
|
JS_ASSERT(cg->compileAndGo());
|
||||||
|
|
||||||
|
|
|
@ -64,10 +64,10 @@
|
||||||
#include "jsstaticcheck.h"
|
#include "jsstaticcheck.h"
|
||||||
#include "jswrapper.h"
|
#include "jswrapper.h"
|
||||||
|
|
||||||
#include "jscntxtinlines.h"
|
|
||||||
#include "jsinterpinlines.h"
|
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
|
|
||||||
|
#include "vm/Stack-inl.h"
|
||||||
|
|
||||||
using namespace js;
|
using namespace js;
|
||||||
using namespace js::gc;
|
using namespace js::gc;
|
||||||
|
|
||||||
|
@ -267,7 +267,7 @@ InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
|
||||||
JSErrorReporter older;
|
JSErrorReporter older;
|
||||||
JSExceptionState *state;
|
JSExceptionState *state;
|
||||||
jsid callerid;
|
jsid callerid;
|
||||||
JSStackFrame *fp, *fpstop;
|
StackFrame *fp, *fpstop;
|
||||||
size_t stackDepth, valueCount, size;
|
size_t stackDepth, valueCount, size;
|
||||||
JSBool overflow;
|
JSBool overflow;
|
||||||
JSExnPrivate *priv;
|
JSExnPrivate *priv;
|
||||||
|
@ -693,7 +693,7 @@ static JSBool
|
||||||
Exception(JSContext *cx, uintN argc, Value *vp)
|
Exception(JSContext *cx, uintN argc, Value *vp)
|
||||||
{
|
{
|
||||||
JSString *message, *filename;
|
JSString *message, *filename;
|
||||||
JSStackFrame *fp;
|
StackFrame *fp;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when
|
* ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when
|
||||||
|
|
|
@ -74,3 +74,9 @@ JS_UnwrapObject(JSObject *obj)
|
||||||
{
|
{
|
||||||
return obj->unwrap();
|
return obj->unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JS_FRIEND_API(JSObject *)
|
||||||
|
JS_GetFrameScopeChainRaw(JSStackFrame *fp)
|
||||||
|
{
|
||||||
|
return &Valueify(fp)->scopeChain();
|
||||||
|
}
|
||||||
|
|
|
@ -54,6 +54,9 @@ JS_FindCompilationScope(JSContext *cx, JSObject *obj);
|
||||||
extern JS_FRIEND_API(JSObject *)
|
extern JS_FRIEND_API(JSObject *)
|
||||||
JS_UnwrapObject(JSObject *obj);
|
JS_UnwrapObject(JSObject *obj);
|
||||||
|
|
||||||
|
extern JS_FRIEND_API(JSObject *)
|
||||||
|
JS_GetFrameScopeChainRaw(JSStackFrame *fp);
|
||||||
|
|
||||||
JS_END_EXTERN_C
|
JS_END_EXTERN_C
|
||||||
|
|
||||||
#endif /* jsfriendapi_h___ */
|
#endif /* jsfriendapi_h___ */
|
||||||
|
|
|
@ -86,12 +86,12 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "jsatominlines.h"
|
#include "jsatominlines.h"
|
||||||
#include "jscntxtinlines.h"
|
|
||||||
#include "jsfuninlines.h"
|
#include "jsfuninlines.h"
|
||||||
#include "jsinterpinlines.h"
|
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
#include "jsscriptinlines.h"
|
#include "jsscriptinlines.h"
|
||||||
|
|
||||||
|
#include "vm/Stack-inl.h"
|
||||||
|
|
||||||
using namespace js;
|
using namespace js;
|
||||||
using namespace js::gc;
|
using namespace js::gc;
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ JSObject::getThrowTypeError() const
|
||||||
}
|
}
|
||||||
|
|
||||||
JSBool
|
JSBool
|
||||||
js_GetArgsValue(JSContext *cx, JSStackFrame *fp, Value *vp)
|
js_GetArgsValue(JSContext *cx, StackFrame *fp, Value *vp)
|
||||||
{
|
{
|
||||||
JSObject *argsobj;
|
JSObject *argsobj;
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ js_GetArgsValue(JSContext *cx, JSStackFrame *fp, Value *vp)
|
||||||
}
|
}
|
||||||
|
|
||||||
JSBool
|
JSBool
|
||||||
js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, Value *vp)
|
js_GetArgsProperty(JSContext *cx, StackFrame *fp, jsid id, Value *vp)
|
||||||
{
|
{
|
||||||
JS_ASSERT(fp->isFunctionFrame());
|
JS_ASSERT(fp->isFunctionFrame());
|
||||||
|
|
||||||
|
@ -233,7 +233,7 @@ struct STATIC_SKIP_INFERENCE PutArg
|
||||||
};
|
};
|
||||||
|
|
||||||
JSObject *
|
JSObject *
|
||||||
js_GetArgsObject(JSContext *cx, JSStackFrame *fp)
|
js_GetArgsObject(JSContext *cx, StackFrame *fp)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* We must be in a function activation; the function must be lightweight
|
* We must be in a function activation; the function must be lightweight
|
||||||
|
@ -273,7 +273,7 @@ js_GetArgsObject(JSContext *cx, JSStackFrame *fp)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
js_PutArgsObject(JSContext *cx, JSStackFrame *fp)
|
js_PutArgsObject(StackFrame *fp)
|
||||||
{
|
{
|
||||||
JSObject &argsobj = fp->argsObj();
|
JSObject &argsobj = fp->argsObj();
|
||||||
if (argsobj.isNormalArguments()) {
|
if (argsobj.isNormalArguments()) {
|
||||||
|
@ -357,7 +357,7 @@ args_delProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||||
}
|
}
|
||||||
|
|
||||||
static JS_REQUIRES_STACK JSObject *
|
static JS_REQUIRES_STACK JSObject *
|
||||||
WrapEscapingClosure(JSContext *cx, JSStackFrame *fp, JSFunction *fun)
|
WrapEscapingClosure(JSContext *cx, StackFrame *fp, JSFunction *fun)
|
||||||
{
|
{
|
||||||
JS_ASSERT(fun->optimizedClosure());
|
JS_ASSERT(fun->optimizedClosure());
|
||||||
JS_ASSERT(!fun->u.i.wrapper);
|
JS_ASSERT(!fun->u.i.wrapper);
|
||||||
|
@ -526,7 +526,7 @@ ArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||||
uintN arg = uintN(JSID_TO_INT(id));
|
uintN arg = uintN(JSID_TO_INT(id));
|
||||||
if (arg < obj->getArgsInitialLength()) {
|
if (arg < obj->getArgsInitialLength()) {
|
||||||
JS_ASSERT(!obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE));
|
JS_ASSERT(!obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE));
|
||||||
if (JSStackFrame *fp = (JSStackFrame *) obj->getPrivate())
|
if (StackFrame *fp = (StackFrame *) obj->getPrivate())
|
||||||
*vp = fp->canonicalActualArg(arg);
|
*vp = fp->canonicalActualArg(arg);
|
||||||
else
|
else
|
||||||
*vp = obj->getArgsElement(arg);
|
*vp = obj->getArgsElement(arg);
|
||||||
|
@ -575,7 +575,7 @@ ArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
||||||
if (JSID_IS_INT(id)) {
|
if (JSID_IS_INT(id)) {
|
||||||
uintN arg = uintN(JSID_TO_INT(id));
|
uintN arg = uintN(JSID_TO_INT(id));
|
||||||
if (arg < obj->getArgsInitialLength()) {
|
if (arg < obj->getArgsInitialLength()) {
|
||||||
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
|
StackFrame *fp = (StackFrame *) obj->getPrivate();
|
||||||
if (fp) {
|
if (fp) {
|
||||||
JSScript *script = fp->functionScript();
|
JSScript *script = fp->functionScript();
|
||||||
if (script->usesArguments)
|
if (script->usesArguments)
|
||||||
|
@ -798,13 +798,13 @@ args_finalize(JSContext *cx, JSObject *obj)
|
||||||
* otherwise reachable. An executing generator is rooted by its invocation. To
|
* otherwise reachable. An executing generator is rooted by its invocation. To
|
||||||
* distinguish the two cases (which imply different access paths to the
|
* distinguish the two cases (which imply different access paths to the
|
||||||
* generator object), we use the JSFRAME_FLOATING_GENERATOR flag, which is only
|
* generator object), we use the JSFRAME_FLOATING_GENERATOR flag, which is only
|
||||||
* set on the JSStackFrame kept in the generator object's JSGenerator.
|
* set on the StackFrame kept in the generator object's JSGenerator.
|
||||||
*/
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
MaybeMarkGenerator(JSTracer *trc, JSObject *obj)
|
MaybeMarkGenerator(JSTracer *trc, JSObject *obj)
|
||||||
{
|
{
|
||||||
#if JS_HAS_GENERATORS
|
#if JS_HAS_GENERATORS
|
||||||
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
|
StackFrame *fp = (StackFrame *) obj->getPrivate();
|
||||||
if (fp && fp->isFloatingGenerator()) {
|
if (fp && fp->isFloatingGenerator()) {
|
||||||
JSObject *genobj = js_FloatingFrameToGenerator(fp)->obj;
|
JSObject *genobj = js_FloatingFrameToGenerator(fp)->obj;
|
||||||
MarkObject(trc, *genobj, "generator object");
|
MarkObject(trc, *genobj, "generator object");
|
||||||
|
@ -838,7 +838,7 @@ args_trace(JSTracer *trc, JSObject *obj)
|
||||||
*
|
*
|
||||||
* The JSClass functions below collaborate to lazily reflect and synchronize
|
* The JSClass functions below collaborate to lazily reflect and synchronize
|
||||||
* actual argument values, argument count, and callee function object stored
|
* actual argument values, argument count, and callee function object stored
|
||||||
* in a JSStackFrame with their corresponding property values in the frame's
|
* in a StackFrame with their corresponding property values in the frame's
|
||||||
* arguments object.
|
* arguments object.
|
||||||
*/
|
*/
|
||||||
Class js_ArgumentsClass = {
|
Class js_ArgumentsClass = {
|
||||||
|
@ -895,7 +895,7 @@ Class StrictArgumentsClass = {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A Declarative Environment object stores its active JSStackFrame pointer in
|
* A Declarative Environment object stores its active StackFrame pointer in
|
||||||
* its private slot, just as Call and Arguments objects do.
|
* its private slot, just as Call and Arguments objects do.
|
||||||
*/
|
*/
|
||||||
Class js_DeclEnvClass = {
|
Class js_DeclEnvClass = {
|
||||||
|
@ -930,7 +930,7 @@ CheckForEscapingClosure(JSContext *cx, JSObject *obj, Value *vp)
|
||||||
if (fun->needsWrapper()) {
|
if (fun->needsWrapper()) {
|
||||||
LeaveTrace(cx);
|
LeaveTrace(cx);
|
||||||
|
|
||||||
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
|
StackFrame *fp = (StackFrame *) obj->getPrivate();
|
||||||
if (fp) {
|
if (fp) {
|
||||||
JSObject *wrapper = WrapEscapingClosure(cx, fp, fun);
|
JSObject *wrapper = WrapEscapingClosure(cx, fp, fun);
|
||||||
if (!wrapper)
|
if (!wrapper)
|
||||||
|
@ -993,7 +993,7 @@ NewCallObject(JSContext *cx, JSScript *script, JSObject &scopeChain, JSObject *c
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline JSObject *
|
static inline JSObject *
|
||||||
NewDeclEnvObject(JSContext *cx, JSStackFrame *fp)
|
NewDeclEnvObject(JSContext *cx, StackFrame *fp)
|
||||||
{
|
{
|
||||||
JSObject *envobj = js_NewGCObject(cx, FINALIZE_OBJECT2);
|
JSObject *envobj = js_NewGCObject(cx, FINALIZE_OBJECT2);
|
||||||
if (!envobj)
|
if (!envobj)
|
||||||
|
@ -1011,7 +1011,7 @@ NewDeclEnvObject(JSContext *cx, JSStackFrame *fp)
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
JSObject *
|
JSObject *
|
||||||
CreateFunCallObject(JSContext *cx, JSStackFrame *fp)
|
CreateFunCallObject(JSContext *cx, StackFrame *fp)
|
||||||
{
|
{
|
||||||
JS_ASSERT(fp->isNonEvalFunctionFrame());
|
JS_ASSERT(fp->isNonEvalFunctionFrame());
|
||||||
JS_ASSERT(!fp->hasCallObj());
|
JS_ASSERT(!fp->hasCallObj());
|
||||||
|
@ -1048,7 +1048,7 @@ CreateFunCallObject(JSContext *cx, JSStackFrame *fp)
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject *
|
JSObject *
|
||||||
CreateEvalCallObject(JSContext *cx, JSStackFrame *fp)
|
CreateEvalCallObject(JSContext *cx, StackFrame *fp)
|
||||||
{
|
{
|
||||||
JSObject *callobj = NewCallObject(cx, fp->script(), fp->scopeChain(), NULL);
|
JSObject *callobj = NewCallObject(cx, fp->script(), fp->scopeChain(), NULL);
|
||||||
if (!callobj)
|
if (!callobj)
|
||||||
|
@ -1083,7 +1083,7 @@ CopyValuesToCallObject(JSObject &callobj, uintN nargs, Value *argv, uintN nvars,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
js_PutCallObject(JSContext *cx, JSStackFrame *fp)
|
js_PutCallObject(StackFrame *fp)
|
||||||
{
|
{
|
||||||
JSObject &callobj = fp->callObj();
|
JSObject &callobj = fp->callObj();
|
||||||
JS_ASSERT(callobj.getPrivate() == fp);
|
JS_ASSERT(callobj.getPrivate() == fp);
|
||||||
|
@ -1094,7 +1094,7 @@ js_PutCallObject(JSContext *cx, JSStackFrame *fp)
|
||||||
if (fp->hasArgsObj()) {
|
if (fp->hasArgsObj()) {
|
||||||
if (!fp->hasOverriddenArgs())
|
if (!fp->hasOverriddenArgs())
|
||||||
callobj.setCallObjArguments(ObjectValue(fp->argsObj()));
|
callobj.setCallObjArguments(ObjectValue(fp->argsObj()));
|
||||||
js_PutArgsObject(cx, fp);
|
js_PutArgsObject(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSScript *script = fp->script();
|
JSScript *script = fp->script();
|
||||||
|
@ -1160,7 +1160,7 @@ js_PutCallObject(JSContext *cx, JSStackFrame *fp)
|
||||||
}
|
}
|
||||||
|
|
||||||
JSBool JS_FASTCALL
|
JSBool JS_FASTCALL
|
||||||
js_PutCallObjectOnTrace(JSContext *cx, JSObject *callobj, uint32 nargs, Value *argv,
|
js_PutCallObjectOnTrace(JSObject *callobj, uint32 nargs, Value *argv,
|
||||||
uint32 nvars, Value *slots)
|
uint32 nvars, Value *slots)
|
||||||
{
|
{
|
||||||
JS_ASSERT(callobj->isCall());
|
JS_ASSERT(callobj->isCall());
|
||||||
|
@ -1173,7 +1173,7 @@ js_PutCallObjectOnTrace(JSContext *cx, JSObject *callobj, uint32 nargs, Value *a
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_DEFINE_CALLINFO_6(extern, BOOL, js_PutCallObjectOnTrace, CONTEXT, OBJECT, UINT32, VALUEPTR,
|
JS_DEFINE_CALLINFO_5(extern, BOOL, js_PutCallObjectOnTrace, OBJECT, UINT32, VALUEPTR,
|
||||||
UINT32, VALUEPTR, 0, nanojit::ACCSET_STORE_ANY)
|
UINT32, VALUEPTR, 0, nanojit::ACCSET_STORE_ANY)
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
@ -1181,7 +1181,7 @@ namespace js {
|
||||||
static JSBool
|
static JSBool
|
||||||
GetCallArguments(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
GetCallArguments(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||||
{
|
{
|
||||||
JSStackFrame *fp = obj->maybeCallObjStackFrame();
|
StackFrame *fp = obj->maybeCallObjStackFrame();
|
||||||
if (fp && !fp->hasOverriddenArgs()) {
|
if (fp && !fp->hasOverriddenArgs()) {
|
||||||
JSObject *argsobj = js_GetArgsObject(cx, fp);
|
JSObject *argsobj = js_GetArgsObject(cx, fp);
|
||||||
if (!argsobj)
|
if (!argsobj)
|
||||||
|
@ -1196,7 +1196,7 @@ GetCallArguments(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||||
static JSBool
|
static JSBool
|
||||||
SetCallArguments(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
SetCallArguments(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
||||||
{
|
{
|
||||||
if (JSStackFrame *fp = obj->maybeCallObjStackFrame())
|
if (StackFrame *fp = obj->maybeCallObjStackFrame())
|
||||||
fp->setOverriddenArgs();
|
fp->setOverriddenArgs();
|
||||||
obj->setCallObjArguments(*vp);
|
obj->setCallObjArguments(*vp);
|
||||||
return true;
|
return true;
|
||||||
|
@ -1208,7 +1208,7 @@ GetCallArg(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||||
JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
|
JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
|
||||||
uintN i = (uint16) JSID_TO_INT(id);
|
uintN i = (uint16) JSID_TO_INT(id);
|
||||||
|
|
||||||
if (JSStackFrame *fp = obj->maybeCallObjStackFrame())
|
if (StackFrame *fp = obj->maybeCallObjStackFrame())
|
||||||
*vp = fp->formalArg(i);
|
*vp = fp->formalArg(i);
|
||||||
else
|
else
|
||||||
*vp = obj->callObjArg(i);
|
*vp = obj->callObjArg(i);
|
||||||
|
@ -1222,7 +1222,7 @@ SetCallArg(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
||||||
uintN i = (uint16) JSID_TO_INT(id);
|
uintN i = (uint16) JSID_TO_INT(id);
|
||||||
|
|
||||||
Value *argp;
|
Value *argp;
|
||||||
if (JSStackFrame *fp = obj->maybeCallObjStackFrame())
|
if (StackFrame *fp = obj->maybeCallObjStackFrame())
|
||||||
argp = &fp->formalArg(i);
|
argp = &fp->formalArg(i);
|
||||||
else
|
else
|
||||||
argp = &obj->callObjArg(i);
|
argp = &obj->callObjArg(i);
|
||||||
|
@ -1261,7 +1261,7 @@ GetCallVar(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||||
JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
|
JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
|
||||||
uintN i = (uint16) JSID_TO_INT(id);
|
uintN i = (uint16) JSID_TO_INT(id);
|
||||||
|
|
||||||
if (JSStackFrame *fp = obj->maybeCallObjStackFrame())
|
if (StackFrame *fp = obj->maybeCallObjStackFrame())
|
||||||
*vp = fp->varSlot(i);
|
*vp = fp->varSlot(i);
|
||||||
else
|
else
|
||||||
*vp = obj->callObjVar(i);
|
*vp = obj->callObjVar(i);
|
||||||
|
@ -1302,7 +1302,7 @@ SetCallVar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Value *varp;
|
Value *varp;
|
||||||
if (JSStackFrame *fp = obj->maybeCallObjStackFrame())
|
if (StackFrame *fp = obj->maybeCallObjStackFrame())
|
||||||
varp = &fp->varSlot(i);
|
varp = &fp->varSlot(i);
|
||||||
else
|
else
|
||||||
varp = &obj->callObjVar(i);
|
varp = &obj->callObjVar(i);
|
||||||
|
@ -1379,7 +1379,7 @@ static void
|
||||||
call_trace(JSTracer *trc, JSObject *obj)
|
call_trace(JSTracer *trc, JSObject *obj)
|
||||||
{
|
{
|
||||||
JS_ASSERT(obj->isCall());
|
JS_ASSERT(obj->isCall());
|
||||||
if (JSStackFrame *fp = obj->maybeCallObjStackFrame()) {
|
if (StackFrame *fp = obj->maybeCallObjStackFrame()) {
|
||||||
/*
|
/*
|
||||||
* FIXME: Hide copies of stack values rooted by fp from the Cycle
|
* FIXME: Hide copies of stack values rooted by fp from the Cycle
|
||||||
* Collector, which currently lacks a non-stub Unlink implementation
|
* Collector, which currently lacks a non-stub Unlink implementation
|
||||||
|
@ -1420,7 +1420,7 @@ JS_PUBLIC_DATA(Class) js_CallClass = {
|
||||||
};
|
};
|
||||||
|
|
||||||
bool
|
bool
|
||||||
JSStackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
|
StackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
|
||||||
{
|
{
|
||||||
if (!isFunctionFrame()) {
|
if (!isFunctionFrame()) {
|
||||||
vp->setUndefined();
|
vp->setUndefined();
|
||||||
|
@ -1584,7 +1584,7 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||||
JSFunction *fun = obj->getFunctionPrivate();
|
JSFunction *fun = obj->getFunctionPrivate();
|
||||||
|
|
||||||
/* Find fun's top-most activation record. */
|
/* Find fun's top-most activation record. */
|
||||||
JSStackFrame *fp;
|
StackFrame *fp;
|
||||||
for (fp = js_GetTopStackFrame(cx);
|
for (fp = js_GetTopStackFrame(cx);
|
||||||
fp && (fp->maybeFun() != fun || fp->isEvalOrDebuggerFrame());
|
fp && (fp->maybeFun() != fun || fp->isEvalOrDebuggerFrame());
|
||||||
fp = fp->prev()) {
|
fp = fp->prev()) {
|
||||||
|
@ -2058,7 +2058,7 @@ fun_toStringHelper(JSContext *cx, JSObject *obj, uintN indent)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (!indent) {
|
if (!indent) {
|
||||||
LazilyConstructed<ToSourceCache> &lazy = cx->compartment->toSourceCache;
|
Maybe<ToSourceCache> &lazy = cx->compartment->toSourceCache;
|
||||||
|
|
||||||
if (lazy.empty()) {
|
if (lazy.empty()) {
|
||||||
lazy.construct();
|
lazy.construct();
|
||||||
|
@ -2137,7 +2137,7 @@ js_fun_call(JSContext *cx, uintN argc, Value *vp)
|
||||||
|
|
||||||
/* Allocate stack space for fval, obj, and the args. */
|
/* Allocate stack space for fval, obj, and the args. */
|
||||||
InvokeArgsGuard args;
|
InvokeArgsGuard args;
|
||||||
if (!cx->stack().pushInvokeArgs(cx, argc, &args))
|
if (!cx->stack.pushInvokeArgs(cx, argc, &args))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
/* Push fval, thisv, and the args. */
|
/* Push fval, thisv, and the args. */
|
||||||
|
@ -2145,7 +2145,7 @@ js_fun_call(JSContext *cx, uintN argc, Value *vp)
|
||||||
args.thisv() = thisv;
|
args.thisv() = thisv;
|
||||||
memcpy(args.argv(), argv, argc * sizeof *argv);
|
memcpy(args.argv(), argv, argc * sizeof *argv);
|
||||||
|
|
||||||
bool ok = Invoke(cx, args, 0);
|
bool ok = Invoke(cx, args);
|
||||||
*vp = args.rval();
|
*vp = args.rval();
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
@ -2188,7 +2188,7 @@ js_fun_apply(JSContext *cx, uintN argc, Value *vp)
|
||||||
uintN n = uintN(JS_MIN(length, JS_ARGS_LENGTH_MAX));
|
uintN n = uintN(JS_MIN(length, JS_ARGS_LENGTH_MAX));
|
||||||
|
|
||||||
InvokeArgsGuard args;
|
InvokeArgsGuard args;
|
||||||
if (!cx->stack().pushInvokeArgs(cx, n, &args))
|
if (!cx->stack.pushInvokeArgs(cx, n, &args))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Push fval, obj, and aobj's elements as args. */
|
/* Push fval, obj, and aobj's elements as args. */
|
||||||
|
@ -2200,7 +2200,7 @@ js_fun_apply(JSContext *cx, uintN argc, Value *vp)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Step 9. */
|
/* Step 9. */
|
||||||
if (!Invoke(cx, args, 0))
|
if (!Invoke(cx, args))
|
||||||
return false;
|
return false;
|
||||||
*vp = args.rval();
|
*vp = args.rval();
|
||||||
return true;
|
return true;
|
||||||
|
@ -2301,7 +2301,7 @@ CallOrConstructBoundFunction(JSContext *cx, uintN argc, Value *vp)
|
||||||
const Value &boundThis = obj->getBoundFunctionThis();
|
const Value &boundThis = obj->getBoundFunctionThis();
|
||||||
|
|
||||||
InvokeArgsGuard args;
|
InvokeArgsGuard args;
|
||||||
if (!cx->stack().pushInvokeArgs(cx, argc + argslen, &args))
|
if (!cx->stack.pushInvokeArgs(cx, argc + argslen, &args))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* 15.3.4.5.1, 15.3.4.5.2 step 4. */
|
/* 15.3.4.5.1, 15.3.4.5.2 step 4. */
|
||||||
|
@ -2314,7 +2314,7 @@ CallOrConstructBoundFunction(JSContext *cx, uintN argc, Value *vp)
|
||||||
if (!constructing)
|
if (!constructing)
|
||||||
args.thisv() = boundThis;
|
args.thisv() = boundThis;
|
||||||
|
|
||||||
if (constructing ? !InvokeConstructor(cx, args) : !Invoke(cx, args, 0))
|
if (constructing ? !InvokeConstructor(cx, args) : !Invoke(cx, args))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
*vp = args.rval();
|
*vp = args.rval();
|
||||||
|
@ -2961,9 +2961,7 @@ js_DefineFunction(JSContext *cx, JSObject *obj, jsid id, Native native,
|
||||||
return fun;
|
return fun;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (JSV2F_CONSTRUCT & JSV2F_SEARCH_STACK)
|
JS_STATIC_ASSERT((JSV2F_CONSTRUCT & JSV2F_SEARCH_STACK) == 0);
|
||||||
# error "JSINVOKE_CONSTRUCT and JSV2F_SEARCH_STACK are not disjoint!"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
JSFunction *
|
JSFunction *
|
||||||
js_ValueToFunction(JSContext *cx, const Value *vp, uintN flags)
|
js_ValueToFunction(JSContext *cx, const Value *vp, uintN flags)
|
||||||
|
|
|
@ -489,7 +489,7 @@ js_DefineFunction(JSContext *cx, JSObject *obj, jsid id, js::Native native,
|
||||||
* fact that JSINVOKE_CONSTRUCT (aka JSFRAME_CONSTRUCTING) is 1, and test that
|
* fact that JSINVOKE_CONSTRUCT (aka JSFRAME_CONSTRUCTING) is 1, and test that
|
||||||
* with #if/#error in jsfun.c.
|
* with #if/#error in jsfun.c.
|
||||||
*/
|
*/
|
||||||
#define JSV2F_CONSTRUCT JSINVOKE_CONSTRUCT
|
#define JSV2F_CONSTRUCT ((uintN)js::INVOKE_CONSTRUCTOR)
|
||||||
#define JSV2F_SEARCH_STACK 0x10000
|
#define JSV2F_SEARCH_STACK 0x10000
|
||||||
|
|
||||||
extern JSFunction *
|
extern JSFunction *
|
||||||
|
@ -508,19 +508,19 @@ extern JSObject * JS_FASTCALL
|
||||||
js_CreateCallObjectOnTrace(JSContext *cx, JSFunction *fun, JSObject *callee, JSObject *scopeChain);
|
js_CreateCallObjectOnTrace(JSContext *cx, JSFunction *fun, JSObject *callee, JSObject *scopeChain);
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
js_PutCallObject(JSContext *cx, JSStackFrame *fp);
|
js_PutCallObject(js::StackFrame *fp);
|
||||||
|
|
||||||
extern JSBool JS_FASTCALL
|
extern JSBool JS_FASTCALL
|
||||||
js_PutCallObjectOnTrace(JSContext *cx, JSObject *scopeChain, uint32 nargs,
|
js_PutCallObjectOnTrace(JSObject *scopeChain, uint32 nargs, js::Value *argv,
|
||||||
js::Value *argv, uint32 nvars, js::Value *slots);
|
uint32 nvars, js::Value *slots);
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
JSObject *
|
JSObject *
|
||||||
CreateFunCallObject(JSContext *cx, JSStackFrame *fp);
|
CreateFunCallObject(JSContext *cx, StackFrame *fp);
|
||||||
|
|
||||||
JSObject *
|
JSObject *
|
||||||
CreateEvalCallObject(JSContext *cx, JSStackFrame *fp);
|
CreateEvalCallObject(JSContext *cx, StackFrame *fp);
|
||||||
|
|
||||||
extern JSBool
|
extern JSBool
|
||||||
GetCallArg(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
|
GetCallArg(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
|
||||||
|
@ -550,10 +550,10 @@ SetCallUpvar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, js::Value *vp
|
||||||
} // namespace js
|
} // namespace js
|
||||||
|
|
||||||
extern JSBool
|
extern JSBool
|
||||||
js_GetArgsValue(JSContext *cx, JSStackFrame *fp, js::Value *vp);
|
js_GetArgsValue(JSContext *cx, js::StackFrame *fp, js::Value *vp);
|
||||||
|
|
||||||
extern JSBool
|
extern JSBool
|
||||||
js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, js::Value *vp);
|
js_GetArgsProperty(JSContext *cx, js::StackFrame *fp, jsid id, js::Value *vp);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the arguments object for the given frame. If the frame is strict mode
|
* Get the arguments object for the given frame. If the frame is strict mode
|
||||||
|
@ -566,10 +566,10 @@ js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, js::Value *vp);
|
||||||
* function.
|
* function.
|
||||||
*/
|
*/
|
||||||
extern JSObject *
|
extern JSObject *
|
||||||
js_GetArgsObject(JSContext *cx, JSStackFrame *fp);
|
js_GetArgsObject(JSContext *cx, js::StackFrame *fp);
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
js_PutArgsObject(JSContext *cx, JSStackFrame *fp);
|
js_PutArgsObject(js::StackFrame *fp);
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
js_IsNamedLambda(JSFunction *fun) { return (fun->flags & JSFUN_LAMBDA) && fun->atom; }
|
js_IsNamedLambda(JSFunction *fun) { return (fun->flags & JSFUN_LAMBDA) && fun->atom; }
|
||||||
|
|
710
js/src/jsgc.cpp
710
js/src/jsgc.cpp
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
421
js/src/jsgc.h
421
js/src/jsgc.h
|
@ -92,6 +92,7 @@ enum FinalizeKind {
|
||||||
FINALIZE_OBJECT16_BACKGROUND,
|
FINALIZE_OBJECT16_BACKGROUND,
|
||||||
FINALIZE_OBJECT_LAST = FINALIZE_OBJECT16_BACKGROUND,
|
FINALIZE_OBJECT_LAST = FINALIZE_OBJECT16_BACKGROUND,
|
||||||
FINALIZE_FUNCTION,
|
FINALIZE_FUNCTION,
|
||||||
|
FINALIZE_FUNCTION_AND_OBJECT_LAST = FINALIZE_FUNCTION,
|
||||||
FINALIZE_SHAPE,
|
FINALIZE_SHAPE,
|
||||||
#if JS_HAS_XML_SUPPORT
|
#if JS_HAS_XML_SUPPORT
|
||||||
FINALIZE_XML,
|
FINALIZE_XML,
|
||||||
|
@ -102,18 +103,43 @@ enum FinalizeKind {
|
||||||
FINALIZE_LIMIT
|
FINALIZE_LIMIT
|
||||||
};
|
};
|
||||||
|
|
||||||
const uintN JS_FINALIZE_OBJECT_LIMIT = 12;
|
const size_t ArenaShift = 12;
|
||||||
|
const size_t ArenaSize = size_t(1) << ArenaShift;
|
||||||
|
const size_t ArenaMask = ArenaSize - 1;
|
||||||
|
|
||||||
|
template <typename T> struct Arena;
|
||||||
|
|
||||||
/* Every arena has a header. */
|
/* Every arena has a header. */
|
||||||
struct ArenaHeader {
|
struct ArenaHeader {
|
||||||
JSCompartment *compartment;
|
JSCompartment *compartment;
|
||||||
Arena<FreeCell> *next;
|
ArenaHeader *next;
|
||||||
FreeCell *freeList;
|
FreeCell *freeList;
|
||||||
|
|
||||||
|
private:
|
||||||
unsigned thingKind;
|
unsigned thingKind;
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline uintptr_t address() const;
|
||||||
|
inline Chunk *chunk() const;
|
||||||
|
inline ArenaBitmap *bitmap() const;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Arena<T> *getArena() {
|
||||||
|
return reinterpret_cast<Arena<T> *>(address());
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned getThingKind() const {
|
||||||
|
return thingKind;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setThingKind(unsigned kind) {
|
||||||
|
thingKind = kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline MarkingDelay *getMarkingDelay() const;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
size_t thingSize;
|
JS_FRIEND_API(size_t) getThingSize() const;
|
||||||
bool isUsed;
|
|
||||||
bool hasFreeThings;
|
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -143,10 +169,6 @@ struct Things<T, N, 0, 0> {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct Arena {
|
struct Arena {
|
||||||
static const size_t ArenaSize = 4096;
|
|
||||||
|
|
||||||
ArenaHeader aheader;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Layout of an arena:
|
* Layout of an arena:
|
||||||
* An arena is 4K. We want it to have a header followed by a list of T
|
* An arena is 4K. We want it to have a header followed by a list of T
|
||||||
|
@ -171,35 +193,28 @@ struct Arena {
|
||||||
static const size_t SpaceAfterHeader = ArenaSize - HeaderSize;
|
static const size_t SpaceAfterHeader = ArenaSize - HeaderSize;
|
||||||
static const size_t Filler2Size = SpaceAfterHeader % sizeof(T);
|
static const size_t Filler2Size = SpaceAfterHeader % sizeof(T);
|
||||||
static const size_t ThingsPerArena = SpaceAfterHeader / sizeof(T);
|
static const size_t ThingsPerArena = SpaceAfterHeader / sizeof(T);
|
||||||
|
static const size_t FirstThingOffset = HeaderSize;
|
||||||
|
static const size_t ThingsSpan = ThingsPerArena * sizeof(T);
|
||||||
|
|
||||||
|
ArenaHeader aheader;
|
||||||
Things<T, ThingsPerArena, Filler1Size, Filler2Size> t;
|
Things<T, ThingsPerArena, Filler1Size, Filler2Size> t;
|
||||||
|
|
||||||
static void staticAsserts() {
|
static void staticAsserts() {
|
||||||
|
/*
|
||||||
|
* Everything we store in the heap must be a multiple of the cell
|
||||||
|
* size.
|
||||||
|
*/
|
||||||
|
JS_STATIC_ASSERT(sizeof(T) % Cell::CellSize == 0);
|
||||||
JS_STATIC_ASSERT(offsetof(Arena<T>, t.things) % sizeof(T) == 0);
|
JS_STATIC_ASSERT(offsetof(Arena<T>, t.things) % sizeof(T) == 0);
|
||||||
JS_STATIC_ASSERT(sizeof(Arena<T>) == ArenaSize);
|
JS_STATIC_ASSERT(sizeof(Arena<T>) == ArenaSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Chunk *chunk() const;
|
inline FreeCell *buildFreeList();
|
||||||
inline size_t arenaIndex() const;
|
|
||||||
|
|
||||||
inline ArenaHeader *header() { return &aheader; };
|
|
||||||
|
|
||||||
inline MarkingDelay *getMarkingDelay() const;
|
|
||||||
inline ArenaBitmap *bitmap() const;
|
|
||||||
|
|
||||||
inline ConservativeGCTest mark(T *thing, JSTracer *trc);
|
|
||||||
void markDelayedChildren(JSTracer *trc);
|
|
||||||
inline bool inFreeList(void *thing) const;
|
|
||||||
inline T *getAlignedThing(const void *thing);
|
|
||||||
#ifdef DEBUG
|
|
||||||
inline bool assureThingIsAligned(void *thing);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void init(JSCompartment *compartment, unsigned thingKind);
|
|
||||||
bool finalize(JSContext *cx);
|
bool finalize(JSContext *cx);
|
||||||
};
|
};
|
||||||
|
|
||||||
void FinalizeArena(Arena<FreeCell> *a);
|
void FinalizeArena(ArenaHeader *aheader);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Live objects are marked black. How many other additional colors are available
|
* Live objects are marked black. How many other additional colors are available
|
||||||
|
@ -209,7 +224,7 @@ static const uint32 BLACK = 0;
|
||||||
|
|
||||||
/* An arena bitmap contains enough mark bits for all the cells in an arena. */
|
/* An arena bitmap contains enough mark bits for all the cells in an arena. */
|
||||||
struct ArenaBitmap {
|
struct ArenaBitmap {
|
||||||
static const size_t BitCount = Arena<FreeCell>::ArenaSize / Cell::CellSize;
|
static const size_t BitCount = ArenaSize / Cell::CellSize;
|
||||||
static const size_t BitWords = BitCount / JS_BITS_PER_WORD;
|
static const size_t BitWords = BitCount / JS_BITS_PER_WORD;
|
||||||
|
|
||||||
uintptr_t bitmap[BitWords];
|
uintptr_t bitmap[BitWords];
|
||||||
|
@ -258,100 +273,76 @@ struct ArenaBitmap {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Ensure that bitmap covers the whole arena. */
|
/* Ensure that bitmap covers the whole arena. */
|
||||||
JS_STATIC_ASSERT(Arena<FreeCell>::ArenaSize % Cell::CellSize == 0);
|
JS_STATIC_ASSERT(ArenaSize % Cell::CellSize == 0);
|
||||||
JS_STATIC_ASSERT(ArenaBitmap::BitCount % JS_BITS_PER_WORD == 0);
|
JS_STATIC_ASSERT(ArenaBitmap::BitCount % JS_BITS_PER_WORD == 0);
|
||||||
|
|
||||||
/* Marking delay is used to resume marking later when recursive marking uses too much stack. */
|
/*
|
||||||
|
* When recursive marking uses too much stack the marking is delayed and
|
||||||
|
* the corresponding arenas are put into a stack using a linked via the
|
||||||
|
* following per arena structure.
|
||||||
|
*/
|
||||||
struct MarkingDelay {
|
struct MarkingDelay {
|
||||||
Arena<Cell> *link;
|
ArenaHeader *link;
|
||||||
uintptr_t unmarkedChildren;
|
|
||||||
jsuword start;
|
|
||||||
|
|
||||||
void init()
|
void init()
|
||||||
{
|
{
|
||||||
link = NULL;
|
link = NULL;
|
||||||
unmarkedChildren = 0;
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To separate arenas without things to mark later from the arena at the
|
||||||
|
* marked delay stack bottom we use for the latter a special sentinel
|
||||||
|
* value. We set it to the header for the second arena in the chunk
|
||||||
|
* starting the 0 address.
|
||||||
|
*/
|
||||||
|
static ArenaHeader *stackBottom() {
|
||||||
|
return reinterpret_cast<ArenaHeader *>(ArenaSize);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EmptyArenaLists {
|
struct EmptyArenaLists {
|
||||||
/* Arenas with no internal freelist prepared. */
|
/* Arenas with no internal freelist prepared. */
|
||||||
Arena<FreeCell> *cellFreeList;
|
ArenaHeader *cellFreeList;
|
||||||
|
|
||||||
/* Arenas with internal freelists prepared for a given finalize kind. */
|
/* Arenas with internal freelists prepared for a given finalize kind. */
|
||||||
Arena<FreeCell> *freeLists[FINALIZE_LIMIT];
|
ArenaHeader *freeLists[FINALIZE_LIMIT];
|
||||||
|
|
||||||
void init() {
|
void init() {
|
||||||
PodZero(this);
|
PodZero(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Arena<FreeCell> *getOtherArena() {
|
ArenaHeader *getOtherArena() {
|
||||||
Arena<FreeCell> *arena = cellFreeList;
|
ArenaHeader *aheader = cellFreeList;
|
||||||
if (arena) {
|
if (aheader) {
|
||||||
cellFreeList = arena->header()->next;
|
cellFreeList = aheader->next;
|
||||||
return arena;
|
return aheader;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < FINALIZE_LIMIT; i++) {
|
for (int i = 0; i < FINALIZE_LIMIT; i++) {
|
||||||
if ((arena = (Arena<FreeCell> *) freeLists[i])) {
|
aheader = freeLists[i];
|
||||||
freeLists[i] = freeLists[i]->header()->next;
|
if (aheader) {
|
||||||
return arena;
|
freeLists[i] = aheader->next;
|
||||||
|
return aheader;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
JS_NOT_REACHED("No arena");
|
JS_NOT_REACHED("No arena");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
ArenaHeader *getTypedFreeList(unsigned thingKind) {
|
||||||
inline Arena<T> *getTypedFreeList(unsigned thingKind);
|
JS_ASSERT(thingKind < FINALIZE_LIMIT);
|
||||||
|
ArenaHeader *aheader = freeLists[thingKind];
|
||||||
|
if (aheader)
|
||||||
|
freeLists[thingKind] = aheader->next;
|
||||||
|
return aheader;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
void insert(ArenaHeader *aheader) {
|
||||||
inline Arena<T> *getNext(JSCompartment *comp, unsigned thingKind);
|
unsigned thingKind = aheader->getThingKind();
|
||||||
|
aheader->next = freeLists[thingKind];
|
||||||
template <typename T>
|
freeLists[thingKind] = aheader;
|
||||||
inline void insert(Arena<T> *arena);
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
inline Arena<T> *
|
|
||||||
EmptyArenaLists::getTypedFreeList(unsigned thingKind) {
|
|
||||||
JS_ASSERT(thingKind < FINALIZE_LIMIT);
|
|
||||||
Arena<T> *arena = (Arena<T>*) freeLists[thingKind];
|
|
||||||
if (arena) {
|
|
||||||
freeLists[thingKind] = freeLists[thingKind]->header()->next;
|
|
||||||
return arena;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline Arena<T> *
|
|
||||||
EmptyArenaLists::getNext(JSCompartment *comp, unsigned thingKind) {
|
|
||||||
Arena<T> *arena = getTypedFreeList<T>(thingKind);
|
|
||||||
if (arena) {
|
|
||||||
JS_ASSERT(arena->header()->isUsed == false);
|
|
||||||
JS_ASSERT(arena->header()->thingSize == sizeof(T));
|
|
||||||
#ifdef DEBUG
|
|
||||||
arena->header()->isUsed = true;
|
|
||||||
#endif
|
|
||||||
arena->header()->thingKind = thingKind;
|
|
||||||
arena->header()->compartment = comp;
|
|
||||||
return arena;
|
|
||||||
}
|
|
||||||
arena = (Arena<T> *)getOtherArena();
|
|
||||||
JS_ASSERT(arena->header()->isUsed == false);
|
|
||||||
arena->init(comp, thingKind);
|
|
||||||
return arena;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
inline void
|
|
||||||
EmptyArenaLists::insert(Arena<T> *arena) {
|
|
||||||
unsigned thingKind = arena->header()->thingKind;
|
|
||||||
JS_ASSERT(thingKind < FINALIZE_LIMIT);
|
|
||||||
arena->header()->next = freeLists[thingKind];
|
|
||||||
freeLists[thingKind] = (Arena<FreeCell> *) arena;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The chunk header (located at the end of the chunk to preserve arena alignment). */
|
/* The chunk header (located at the end of the chunk to preserve arena alignment). */
|
||||||
struct ChunkInfo {
|
struct ChunkInfo {
|
||||||
Chunk *link;
|
Chunk *link;
|
||||||
|
@ -366,7 +357,7 @@ struct ChunkInfo {
|
||||||
|
|
||||||
/* Chunks contain arenas and associated data structures (mark bitmap, delayed marking state). */
|
/* Chunks contain arenas and associated data structures (mark bitmap, delayed marking state). */
|
||||||
struct Chunk {
|
struct Chunk {
|
||||||
static const size_t BytesPerArena = sizeof(Arena<FreeCell>) +
|
static const size_t BytesPerArena = ArenaSize +
|
||||||
sizeof(ArenaBitmap) +
|
sizeof(ArenaBitmap) +
|
||||||
sizeof(MarkingDelay);
|
sizeof(MarkingDelay);
|
||||||
|
|
||||||
|
@ -378,6 +369,21 @@ struct Chunk {
|
||||||
|
|
||||||
ChunkInfo info;
|
ChunkInfo info;
|
||||||
|
|
||||||
|
static Chunk *fromAddress(uintptr_t addr) {
|
||||||
|
addr &= ~GC_CHUNK_MASK;
|
||||||
|
return reinterpret_cast<Chunk *>(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool withinArenasRange(uintptr_t addr) {
|
||||||
|
uintptr_t offset = addr & GC_CHUNK_MASK;
|
||||||
|
return offset < ArenasPerChunk * ArenaSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t arenaIndex(uintptr_t addr) {
|
||||||
|
JS_ASSERT(withinArenasRange(addr));
|
||||||
|
return (addr & GC_CHUNK_MASK) >> ArenaShift;
|
||||||
|
}
|
||||||
|
|
||||||
void clearMarkBitmap();
|
void clearMarkBitmap();
|
||||||
bool init(JSRuntime *rt);
|
bool init(JSRuntime *rt);
|
||||||
|
|
||||||
|
@ -386,30 +392,37 @@ struct Chunk {
|
||||||
bool withinArenasRange(Cell *cell);
|
bool withinArenasRange(Cell *cell);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Arena<T> *allocateArena(JSContext *cx, unsigned thingKind);
|
ArenaHeader *allocateArena(JSContext *cx, unsigned thingKind);
|
||||||
|
|
||||||
template <typename T>
|
void releaseArena(ArenaHeader *aheader);
|
||||||
void releaseArena(Arena<T> *a);
|
|
||||||
|
|
||||||
JSRuntime *getRuntime();
|
JSRuntime *getRuntime();
|
||||||
};
|
};
|
||||||
JS_STATIC_ASSERT(sizeof(Chunk) <= GC_CHUNK_SIZE);
|
JS_STATIC_ASSERT(sizeof(Chunk) <= GC_CHUNK_SIZE);
|
||||||
JS_STATIC_ASSERT(sizeof(Chunk) + Chunk::BytesPerArena > GC_CHUNK_SIZE);
|
JS_STATIC_ASSERT(sizeof(Chunk) + Chunk::BytesPerArena > GC_CHUNK_SIZE);
|
||||||
|
|
||||||
Arena<Cell> *
|
inline uintptr_t
|
||||||
Cell::arena() const
|
Cell::address() const
|
||||||
{
|
{
|
||||||
uintptr_t addr = uintptr_t(this);
|
uintptr_t addr = uintptr_t(this);
|
||||||
JS_ASSERT(addr % sizeof(FreeCell) == 0);
|
JS_ASSERT(addr % Cell::CellSize == 0);
|
||||||
addr &= ~(Arena<FreeCell>::ArenaSize - 1);
|
JS_ASSERT(Chunk::withinArenasRange(addr));
|
||||||
return reinterpret_cast<Arena<Cell> *>(addr);
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ArenaHeader *
|
||||||
|
Cell::arenaHeader() const
|
||||||
|
{
|
||||||
|
uintptr_t addr = address();
|
||||||
|
addr &= ~ArenaMask;
|
||||||
|
return reinterpret_cast<ArenaHeader *>(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Chunk *
|
Chunk *
|
||||||
Cell::chunk() const
|
Cell::chunk() const
|
||||||
{
|
{
|
||||||
uintptr_t addr = uintptr_t(this);
|
uintptr_t addr = uintptr_t(this);
|
||||||
JS_ASSERT(addr % sizeof(FreeCell) == 0);
|
JS_ASSERT(addr % Cell::CellSize == 0);
|
||||||
addr &= ~(GC_CHUNK_SIZE - 1);
|
addr &= ~(GC_CHUNK_SIZE - 1);
|
||||||
return reinterpret_cast<Chunk *>(addr);
|
return reinterpret_cast<Chunk *>(addr);
|
||||||
}
|
}
|
||||||
|
@ -417,70 +430,60 @@ Cell::chunk() const
|
||||||
ArenaBitmap *
|
ArenaBitmap *
|
||||||
Cell::bitmap() const
|
Cell::bitmap() const
|
||||||
{
|
{
|
||||||
return &chunk()->bitmaps[arena()->arenaIndex()];
|
return &chunk()->bitmaps[Chunk::arenaIndex(address())];
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC_POSTCONDITION_ASSUME(return < ArenaBitmap::BitCount)
|
STATIC_POSTCONDITION_ASSUME(return < ArenaBitmap::BitCount)
|
||||||
size_t
|
size_t
|
||||||
Cell::cellIndex() const
|
Cell::cellIndex() const
|
||||||
{
|
{
|
||||||
return this->asFreeCell() - arena()->t.things[0].asFreeCell();
|
uintptr_t addr = address();
|
||||||
}
|
return (addr & ArenaMask) >> Cell::CellShift;
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Chunk *
|
|
||||||
Arena<T>::chunk() const
|
|
||||||
{
|
|
||||||
uintptr_t addr = uintptr_t(this);
|
|
||||||
JS_ASSERT(addr % sizeof(FreeCell) == 0);
|
|
||||||
addr &= ~(GC_CHUNK_SIZE - 1);
|
|
||||||
return reinterpret_cast<Chunk *>(addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
size_t
|
|
||||||
Arena<T>::arenaIndex() const
|
|
||||||
{
|
|
||||||
return reinterpret_cast<const Arena<FreeCell> *>(this) - chunk()->arenas;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
MarkingDelay *
|
|
||||||
Arena<T>::getMarkingDelay() const
|
|
||||||
{
|
|
||||||
return &chunk()->markingDelay[arenaIndex()];
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
ArenaBitmap *
|
|
||||||
Arena<T>::bitmap() const
|
|
||||||
{
|
|
||||||
return &chunk()->bitmaps[arenaIndex()];
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
inline T *
|
|
||||||
Arena<T>::getAlignedThing(const void *thing)
|
|
||||||
{
|
|
||||||
jsuword start = reinterpret_cast<jsuword>(&t.things[0]);
|
|
||||||
jsuword offset = reinterpret_cast<jsuword>(thing) - start;
|
|
||||||
offset -= offset % sizeof(T);
|
|
||||||
return reinterpret_cast<T *>(start + offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
template <typename T>
|
|
||||||
inline bool
|
inline bool
|
||||||
Arena<T>::assureThingIsAligned(void *thing)
|
Cell::isAligned() const
|
||||||
{
|
{
|
||||||
return (getAlignedThing(thing) == thing);
|
uintptr_t offset = address() & ArenaMask;
|
||||||
|
return offset % arenaHeader()->getThingSize() == 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
inline uintptr_t
|
||||||
|
ArenaHeader::address() const
|
||||||
|
{
|
||||||
|
uintptr_t addr = reinterpret_cast<uintptr_t>(this);
|
||||||
|
JS_ASSERT(!(addr & ArenaMask));
|
||||||
|
JS_ASSERT(Chunk::withinArenasRange(addr));
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Chunk *
|
||||||
|
ArenaHeader::chunk() const
|
||||||
|
{
|
||||||
|
return Chunk::fromAddress(address());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ArenaBitmap *
|
||||||
|
ArenaHeader::bitmap() const
|
||||||
|
{
|
||||||
|
return &chunk()->bitmaps[Chunk::arenaIndex(address())];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline MarkingDelay *
|
||||||
|
ArenaHeader::getMarkingDelay() const
|
||||||
|
{
|
||||||
|
return &chunk()->markingDelay[Chunk::arenaIndex(address())];
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
AssertValidColor(const void *thing, uint32 color)
|
AssertValidColor(const void *thing, uint32 color)
|
||||||
{
|
{
|
||||||
JS_ASSERT_IF(color, color < reinterpret_cast<const js::gc::FreeCell *>(thing)->arena()->header()->thingSize / sizeof(FreeCell));
|
#ifdef DEBUG
|
||||||
|
ArenaHeader *aheader = reinterpret_cast<const js::gc::Cell *>(thing)->arenaHeader();
|
||||||
|
JS_ASSERT_IF(color, color < aheader->getThingSize() / Cell::CellSize);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
|
@ -508,15 +511,7 @@ Cell::unmark(uint32 color) const
|
||||||
JSCompartment *
|
JSCompartment *
|
||||||
Cell::compartment() const
|
Cell::compartment() const
|
||||||
{
|
{
|
||||||
return arena()->header()->compartment;
|
return arenaHeader()->compartment;
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static inline
|
|
||||||
Arena<T> *
|
|
||||||
GetArena(Cell *cell)
|
|
||||||
{
|
|
||||||
return reinterpret_cast<Arena<T> *>(cell->arena());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define JSTRACE_XML 3
|
#define JSTRACE_XML 3
|
||||||
|
@ -580,15 +575,10 @@ GetGCThingRuntime(void *thing)
|
||||||
return reinterpret_cast<FreeCell *>(thing)->chunk()->info.runtime;
|
return reinterpret_cast<FreeCell *>(thing)->chunk()->info.runtime;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
extern bool
|
|
||||||
checkArenaListsForThing(JSCompartment *comp, jsuword thing);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* The arenas in a list have uniform kind. */
|
/* The arenas in a list have uniform kind. */
|
||||||
struct ArenaList {
|
struct ArenaList {
|
||||||
Arena<FreeCell> *head; /* list start */
|
ArenaHeader *head; /* list start */
|
||||||
Arena<FreeCell> *cursor; /* arena with free things */
|
ArenaHeader *cursor; /* arena with free things */
|
||||||
volatile bool hasToBeFinalized;
|
volatile bool hasToBeFinalized;
|
||||||
|
|
||||||
inline void init() {
|
inline void init() {
|
||||||
|
@ -597,47 +587,35 @@ struct ArenaList {
|
||||||
hasToBeFinalized = false;
|
hasToBeFinalized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Arena<FreeCell> *getNextWithFreeList(JSContext *cx) {
|
inline ArenaHeader *getNextWithFreeList() {
|
||||||
JS_ASSERT(!hasToBeFinalized);
|
JS_ASSERT(!hasToBeFinalized);
|
||||||
Arena<FreeCell> *a;
|
while (cursor) {
|
||||||
while (cursor != NULL) {
|
ArenaHeader *aheader = cursor;
|
||||||
ArenaHeader *aheader = cursor->header();
|
|
||||||
a = cursor;
|
|
||||||
cursor = aheader->next;
|
cursor = aheader->next;
|
||||||
if (aheader->freeList)
|
if (aheader->freeList)
|
||||||
return a;
|
return aheader;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
template <typename T>
|
|
||||||
bool arenasContainThing(void *thing) {
|
|
||||||
for (Arena<T> *a = (Arena<T> *) head; a; a = (Arena<T> *) a->header()->next) {
|
|
||||||
JS_ASSERT(a->header()->isUsed);
|
|
||||||
if (thing >= &a->t.things[0] && thing < &a->t.things[a->ThingsPerArena])
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool markedThingsInArenaList() {
|
bool markedThingsInArenaList() {
|
||||||
for (Arena<FreeCell> *a = (Arena<FreeCell> *) head; a; a = (Arena<FreeCell> *) a->header()->next) {
|
for (ArenaHeader *aheader = head; aheader; aheader = aheader->next) {
|
||||||
if (!a->bitmap()->noBitsSet())
|
if (!aheader->bitmap()->noBitsSet())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inline void insert(Arena<FreeCell> *a) {
|
inline void insert(ArenaHeader *aheader) {
|
||||||
a->header()->next = head;
|
aheader->next = head;
|
||||||
head = a;
|
head = aheader;
|
||||||
}
|
}
|
||||||
|
|
||||||
void releaseAll() {
|
void releaseAll(unsigned thingKind) {
|
||||||
while (head) {
|
while (head) {
|
||||||
Arena<FreeCell> *next = head->header()->next;
|
ArenaHeader *next = head->next;
|
||||||
head->chunk()->releaseArena(head);
|
head->chunk()->releaseArena(head);
|
||||||
head = next;
|
head = next;
|
||||||
}
|
}
|
||||||
|
@ -646,7 +624,7 @@ struct ArenaList {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool isEmpty() const {
|
inline bool isEmpty() const {
|
||||||
return (head == NULL);
|
return !head;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -664,17 +642,12 @@ struct FreeLists {
|
||||||
} else {
|
} else {
|
||||||
finalizables[kind] = NULL;
|
finalizables[kind] = NULL;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
|
||||||
if (top && !top->link)
|
|
||||||
top->arena()->header()->hasFreeThings = false;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
return top;
|
return top;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
void populate(ArenaHeader *aheader, uint32 thingKind) {
|
||||||
inline void populate(Arena<T> *a, uint32 thingKind) {
|
finalizables[thingKind] = &aheader->freeList;
|
||||||
finalizables[thingKind] = &a->header()->freeList;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -744,9 +717,7 @@ CheckGCFreeListLink(js::gc::FreeCell *cell)
|
||||||
* The GC things on the free lists come from one arena and the things on
|
* The GC things on the free lists come from one arena and the things on
|
||||||
* the free list are linked in ascending address order.
|
* the free list are linked in ascending address order.
|
||||||
*/
|
*/
|
||||||
JS_ASSERT_IF(cell->link,
|
JS_ASSERT_IF(cell->link, cell->arenaHeader() == cell->link->arenaHeader());
|
||||||
cell->arena() ==
|
|
||||||
cell->link->arena());
|
|
||||||
JS_ASSERT_IF(cell->link, cell < cell->link);
|
JS_ASSERT_IF(cell->link, cell < cell->link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -821,7 +792,7 @@ extern JS_FRIEND_API(bool)
|
||||||
js_GCThingIsMarked(void *thing, uintN color);
|
js_GCThingIsMarked(void *thing, uintN color);
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp);
|
js_TraceStackFrame(JSTracer *trc, js::StackFrame *fp);
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
|
@ -885,7 +856,7 @@ extern void
|
||||||
js_DestroyScriptsToGC(JSContext *cx, JSCompartment *comp);
|
js_DestroyScriptsToGC(JSContext *cx, JSCompartment *comp);
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
FinalizeArenaList(JSContext *cx, js::gc::ArenaList *arenaList, js::gc::Arena<js::gc::FreeCell> *head);
|
FinalizeArenaList(JSContext *cx, js::gc::ArenaList *arenaList, js::gc::ArenaHeader *head);
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
|
@ -914,15 +885,18 @@ class GCHelperThread {
|
||||||
Vector<void **, 16, js::SystemAllocPolicy> freeVector;
|
Vector<void **, 16, js::SystemAllocPolicy> freeVector;
|
||||||
void **freeCursor;
|
void **freeCursor;
|
||||||
void **freeCursorEnd;
|
void **freeCursorEnd;
|
||||||
Vector<void **, 16, js::SystemAllocPolicy> finalizeVector;
|
|
||||||
void **finalizeCursor;
|
struct FinalizeListAndHead {
|
||||||
void **finalizeCursorEnd;
|
js::gc::ArenaList *list;
|
||||||
|
js::gc::ArenaHeader *head;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
Vector<FinalizeListAndHead, 64, js::SystemAllocPolicy> finalizeVector;
|
||||||
|
|
||||||
JS_FRIEND_API(void)
|
JS_FRIEND_API(void)
|
||||||
replenishAndFreeLater(void *ptr);
|
replenishAndFreeLater(void *ptr);
|
||||||
|
|
||||||
void replenishAndFinalizeLater(js::gc::ArenaList *list);
|
|
||||||
|
|
||||||
static void freeElementsAndArray(void **array, void **end) {
|
static void freeElementsAndArray(void **array, void **end) {
|
||||||
JS_ASSERT(array <= end);
|
JS_ASSERT(array <= end);
|
||||||
for (void **p = array; p != end; ++p)
|
for (void **p = array; p != end; ++p)
|
||||||
|
@ -930,17 +904,6 @@ class GCHelperThread {
|
||||||
js::Foreground::free_(array);
|
js::Foreground::free_(array);
|
||||||
}
|
}
|
||||||
|
|
||||||
void finalizeElementsAndArray(void **array, void **end) {
|
|
||||||
JS_ASSERT(array <= end);
|
|
||||||
for (void **p = array; p != end; p += 2) {
|
|
||||||
js::gc::ArenaList *list = (js::gc::ArenaList *)*p;
|
|
||||||
js::gc::Arena<js::gc::FreeCell> *head = (js::gc::Arena<js::gc::FreeCell> *)*(p+1);
|
|
||||||
|
|
||||||
FinalizeArenaList(cx, list, head);
|
|
||||||
}
|
|
||||||
js::Foreground::free_(array);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void threadMain(void* arg);
|
static void threadMain(void* arg);
|
||||||
|
|
||||||
void threadLoop(JSRuntime *rt);
|
void threadLoop(JSRuntime *rt);
|
||||||
|
@ -954,8 +917,6 @@ class GCHelperThread {
|
||||||
shutdown(false),
|
shutdown(false),
|
||||||
freeCursor(NULL),
|
freeCursor(NULL),
|
||||||
freeCursorEnd(NULL),
|
freeCursorEnd(NULL),
|
||||||
finalizeCursor(NULL),
|
|
||||||
finalizeCursorEnd(NULL),
|
|
||||||
sweeping(false) { }
|
sweeping(false) { }
|
||||||
|
|
||||||
volatile bool sweeping;
|
volatile bool sweeping;
|
||||||
|
@ -976,19 +937,16 @@ class GCHelperThread {
|
||||||
replenishAndFreeLater(ptr);
|
replenishAndFreeLater(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void finalizeLater(js::gc::ArenaList *list) {
|
bool finalizeLater(js::gc::ArenaList *list) {
|
||||||
|
JS_ASSERT(!sweeping);
|
||||||
JS_ASSERT(!list->hasToBeFinalized);
|
JS_ASSERT(!list->hasToBeFinalized);
|
||||||
if (!list->head)
|
if (!list->head)
|
||||||
return;
|
return true;
|
||||||
|
FinalizeListAndHead f = {list, list->head};
|
||||||
|
if (!finalizeVector.append(f))
|
||||||
|
return false;
|
||||||
list->hasToBeFinalized = true;
|
list->hasToBeFinalized = true;
|
||||||
JS_ASSERT(!sweeping);
|
return true;
|
||||||
if (finalizeCursor + 1 < finalizeCursorEnd) {
|
|
||||||
*finalizeCursor++ = list;
|
|
||||||
*finalizeCursor++ = list->head;
|
|
||||||
} else {
|
|
||||||
replenishAndFinalizeLater(list);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setContext(JSContext *context) { cx = context; }
|
void setContext(JSContext *context) { cx = context; }
|
||||||
|
@ -1119,9 +1077,9 @@ struct GCMarker : public JSTracer {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/* See comments before delayMarkingChildren is jsgc.cpp. */
|
/* See comments before delayMarkingChildren is jsgc.cpp. */
|
||||||
js::gc::Arena<js::gc::Cell> *unmarkedArenaStackTop;
|
js::gc::ArenaHeader *unmarkedArenaStackTop;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
size_t markLaterCount;
|
size_t markLaterArenas;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(JS_DUMP_CONSERVATIVE_GC_ROOTS) || defined(JS_GCMETER)
|
#if defined(JS_DUMP_CONSERVATIVE_GC_ROOTS) || defined(JS_GCMETER)
|
||||||
|
@ -1129,8 +1087,7 @@ struct GCMarker : public JSTracer {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS
|
#ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS
|
||||||
struct ConservativeRoot { void *thing; uint32 thingKind; };
|
Vector<void *, 0, SystemAllocPolicy> conservativeRoots;
|
||||||
Vector<ConservativeRoot, 0, SystemAllocPolicy> conservativeRoots;
|
|
||||||
const char *conservativeDumpFileName;
|
const char *conservativeDumpFileName;
|
||||||
|
|
||||||
void dumpConservativeRoots();
|
void dumpConservativeRoots();
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||||
*
|
*
|
||||||
* ***** BEGIN LICENSE BLOCK *****
|
* ***** BEGIN LICENSE BLOCK *****
|
||||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
@ -114,7 +114,7 @@ GetGCThingTraceKind(const void *thing)
|
||||||
if (JSAtom::isStatic(thing))
|
if (JSAtom::isStatic(thing))
|
||||||
return JSTRACE_STRING;
|
return JSTRACE_STRING;
|
||||||
const Cell *cell = reinterpret_cast<const Cell *>(thing);
|
const Cell *cell = reinterpret_cast<const Cell *>(thing);
|
||||||
return GetFinalizableTraceKind(cell->arena()->header()->thingKind);
|
return GetFinalizableTraceKind(cell->arenaHeader()->getThingKind());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Capacity for slotsToThingKind */
|
/* Capacity for slotsToThingKind */
|
||||||
|
|
|
@ -77,14 +77,17 @@ Mark(JSTracer *trc, T *thing)
|
||||||
JS_ASSERT(JS_IS_VALID_TRACE_KIND(GetGCThingTraceKind(thing)));
|
JS_ASSERT(JS_IS_VALID_TRACE_KIND(GetGCThingTraceKind(thing)));
|
||||||
JS_ASSERT(trc->debugPrinter || trc->debugPrintArg);
|
JS_ASSERT(trc->debugPrinter || trc->debugPrintArg);
|
||||||
|
|
||||||
/* Per-Compartment GC only with GCMarker and no custom JSTracer */
|
JS_ASSERT(!JSAtom::isStatic(thing));
|
||||||
JS_ASSERT_IF(trc->context->runtime->gcCurrentCompartment, IS_GC_MARKING_TRACER(trc));
|
JS_ASSERT(thing->asFreeCell()->isAligned());
|
||||||
|
|
||||||
JSRuntime *rt = trc->context->runtime;
|
JSRuntime *rt = trc->context->runtime;
|
||||||
JS_ASSERT(thing->arena()->header()->compartment);
|
JS_ASSERT(thing->arenaHeader()->compartment);
|
||||||
JS_ASSERT(thing->arena()->header()->compartment->rt == rt);
|
JS_ASSERT(thing->arenaHeader()->compartment->rt == rt);
|
||||||
|
|
||||||
/* Don't mark things outside a compartment if we are in a per-compartment GC */
|
/*
|
||||||
|
* Don't mark things outside a compartment if we are in a per-compartment
|
||||||
|
* GC.
|
||||||
|
*/
|
||||||
if (!rt->gcCurrentCompartment || thing->compartment() == rt->gcCurrentCompartment) {
|
if (!rt->gcCurrentCompartment || thing->compartment() == rt->gcCurrentCompartment) {
|
||||||
if (IS_GC_MARKING_TRACER(trc))
|
if (IS_GC_MARKING_TRACER(trc))
|
||||||
PushMarkStack(static_cast<GCMarker *>(trc), thing);
|
PushMarkStack(static_cast<GCMarker *>(trc), thing);
|
||||||
|
@ -104,7 +107,6 @@ MarkString(JSTracer *trc, JSString *str)
|
||||||
JS_ASSERT(str);
|
JS_ASSERT(str);
|
||||||
if (str->isStaticAtom())
|
if (str->isStaticAtom())
|
||||||
return;
|
return;
|
||||||
JS_ASSERT(GetArena<JSString>((Cell *)str)->assureThingIsAligned((JSString *)str));
|
|
||||||
Mark(trc, str);
|
Mark(trc, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,13 +124,6 @@ MarkObject(JSTracer *trc, JSObject &obj, const char *name)
|
||||||
JS_ASSERT(trc);
|
JS_ASSERT(trc);
|
||||||
JS_ASSERT(&obj);
|
JS_ASSERT(&obj);
|
||||||
JS_SET_TRACING_NAME(trc, name);
|
JS_SET_TRACING_NAME(trc, name);
|
||||||
JS_ASSERT(GetArena<JSObject>((Cell *)&obj)->assureThingIsAligned(&obj) ||
|
|
||||||
GetArena<JSObject_Slots2>((Cell *)&obj)->assureThingIsAligned(&obj) ||
|
|
||||||
GetArena<JSObject_Slots4>((Cell *)&obj)->assureThingIsAligned(&obj) ||
|
|
||||||
GetArena<JSObject_Slots8>((Cell *)&obj)->assureThingIsAligned(&obj) ||
|
|
||||||
GetArena<JSObject_Slots12>((Cell *)&obj)->assureThingIsAligned(&obj) ||
|
|
||||||
GetArena<JSObject_Slots16>((Cell *)&obj)->assureThingIsAligned(&obj) ||
|
|
||||||
GetArena<JSFunction>((Cell *)&obj)->assureThingIsAligned(&obj));
|
|
||||||
Mark(trc, &obj);
|
Mark(trc, &obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,13 +134,6 @@ MarkObjectWithPrinter(JSTracer *trc, JSObject &obj, JSTraceNamePrinter printer,
|
||||||
JS_ASSERT(trc);
|
JS_ASSERT(trc);
|
||||||
JS_ASSERT(&obj);
|
JS_ASSERT(&obj);
|
||||||
JS_SET_TRACING_DETAILS(trc, printer, arg, index);
|
JS_SET_TRACING_DETAILS(trc, printer, arg, index);
|
||||||
JS_ASSERT(GetArena<JSObject>((Cell *)&obj)->assureThingIsAligned(&obj) ||
|
|
||||||
GetArena<JSObject_Slots2>((Cell *)&obj)->assureThingIsAligned(&obj) ||
|
|
||||||
GetArena<JSObject_Slots4>((Cell *)&obj)->assureThingIsAligned(&obj) ||
|
|
||||||
GetArena<JSObject_Slots8>((Cell *)&obj)->assureThingIsAligned(&obj) ||
|
|
||||||
GetArena<JSObject_Slots12>((Cell *)&obj)->assureThingIsAligned(&obj) ||
|
|
||||||
GetArena<JSObject_Slots16>((Cell *)&obj)->assureThingIsAligned(&obj) ||
|
|
||||||
GetArena<JSFunction>((Cell *)&obj)->assureThingIsAligned(&obj));
|
|
||||||
Mark(trc, &obj);
|
Mark(trc, &obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,19 +143,19 @@ MarkShape(JSTracer *trc, const Shape *shape, const char *name)
|
||||||
JS_ASSERT(trc);
|
JS_ASSERT(trc);
|
||||||
JS_ASSERT(shape);
|
JS_ASSERT(shape);
|
||||||
JS_SET_TRACING_NAME(trc, name);
|
JS_SET_TRACING_NAME(trc, name);
|
||||||
JS_ASSERT(GetArena<Shape>((Cell *)shape)->assureThingIsAligned((void *)shape));
|
|
||||||
Mark(trc, shape);
|
Mark(trc, shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if JS_HAS_XML_SUPPORT
|
||||||
void
|
void
|
||||||
MarkXML(JSTracer *trc, JSXML *xml, const char *name)
|
MarkXML(JSTracer *trc, JSXML *xml, const char *name)
|
||||||
{
|
{
|
||||||
JS_ASSERT(trc);
|
JS_ASSERT(trc);
|
||||||
JS_ASSERT(xml);
|
JS_ASSERT(xml);
|
||||||
JS_SET_TRACING_NAME(trc, name);
|
JS_SET_TRACING_NAME(trc, name);
|
||||||
JS_ASSERT(GetArena<JSXML>(xml)->assureThingIsAligned(xml));
|
|
||||||
Mark(trc, xml);
|
Mark(trc, xml);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void
|
void
|
||||||
PushMarkStack(GCMarker *gcmarker, JSXML *thing)
|
PushMarkStack(GCMarker *gcmarker, JSXML *thing)
|
||||||
|
|
|
@ -44,6 +44,8 @@
|
||||||
#include "jsbuiltins.h"
|
#include "jsbuiltins.h"
|
||||||
#include "jscompartment.h"
|
#include "jscompartment.h"
|
||||||
|
|
||||||
|
#include "jsgcinlines.h"
|
||||||
|
|
||||||
using namespace js;
|
using namespace js;
|
||||||
using namespace js::gc;
|
using namespace js::gc;
|
||||||
|
|
||||||
|
@ -72,7 +74,7 @@ ConservativeGCStats::dump(FILE *fp)
|
||||||
fprintf(fp, " excluded, wrong tag: %lu\n", ULSTAT(counter[CGCT_WRONGTAG]));
|
fprintf(fp, " excluded, wrong tag: %lu\n", ULSTAT(counter[CGCT_WRONGTAG]));
|
||||||
fprintf(fp, " excluded, not live: %lu\n", ULSTAT(counter[CGCT_NOTLIVE]));
|
fprintf(fp, " excluded, not live: %lu\n", ULSTAT(counter[CGCT_NOTLIVE]));
|
||||||
fprintf(fp, " valid GC things: %lu\n", ULSTAT(counter[CGCT_VALID]));
|
fprintf(fp, " valid GC things: %lu\n", ULSTAT(counter[CGCT_VALID]));
|
||||||
fprintf(fp, " valid but not aligned: %lu\n", ULSTAT(counter[CGCT_VALIDWITHOFFSET]));
|
fprintf(fp, " valid but not aligned: %lu\n", ULSTAT(unaligned));
|
||||||
#undef ULSTAT
|
#undef ULSTAT
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -143,49 +145,6 @@ GetSizeAndThings(size_t &thingSize, size_t &thingsPerArena)
|
||||||
thingsPerArena = Arena<T>::ThingsPerArena;
|
thingsPerArena = Arena<T>::ThingsPerArena;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined JS_DUMP_CONSERVATIVE_GC_ROOTS
|
|
||||||
void *
|
|
||||||
GetAlignedThing(void *thing, int thingKind)
|
|
||||||
{
|
|
||||||
Cell *cell = (Cell *)thing;
|
|
||||||
switch (thingKind) {
|
|
||||||
case FINALIZE_OBJECT0:
|
|
||||||
case FINALIZE_OBJECT0_BACKGROUND:
|
|
||||||
return (void *)GetArena<JSObject>(cell)->getAlignedThing(thing);
|
|
||||||
case FINALIZE_OBJECT2:
|
|
||||||
case FINALIZE_OBJECT2_BACKGROUND:
|
|
||||||
return (void *)GetArena<JSObject_Slots2>(cell)->getAlignedThing(thing);
|
|
||||||
case FINALIZE_OBJECT4:
|
|
||||||
case FINALIZE_OBJECT4_BACKGROUND:
|
|
||||||
return (void *)GetArena<JSObject_Slots4>(cell)->getAlignedThing(thing);
|
|
||||||
case FINALIZE_OBJECT8:
|
|
||||||
case FINALIZE_OBJECT8_BACKGROUND:
|
|
||||||
return (void *)GetArena<JSObject_Slots8>(cell)->getAlignedThing(thing);
|
|
||||||
case FINALIZE_OBJECT12:
|
|
||||||
case FINALIZE_OBJECT12_BACKGROUND:
|
|
||||||
return (void *)GetArena<JSObject_Slots12>(cell)->getAlignedThing(thing);
|
|
||||||
case FINALIZE_OBJECT16:
|
|
||||||
case FINALIZE_OBJECT16_BACKGROUND:
|
|
||||||
return (void *)GetArena<JSObject_Slots16>(cell)->getAlignedThing(thing);
|
|
||||||
case FINALIZE_STRING:
|
|
||||||
return (void *)GetArena<JSString>(cell)->getAlignedThing(thing);
|
|
||||||
case FINALIZE_EXTERNAL_STRING:
|
|
||||||
return (void *)GetArena<JSExternalString>(cell)->getAlignedThing(thing);
|
|
||||||
case FINALIZE_SHORT_STRING:
|
|
||||||
return (void *)GetArena<JSShortString>(cell)->getAlignedThing(thing);
|
|
||||||
case FINALIZE_FUNCTION:
|
|
||||||
return (void *)GetArena<JSFunction>(cell)->getAlignedThing(thing);
|
|
||||||
#if JS_HAS_XML_SUPPORT
|
|
||||||
case FINALIZE_XML:
|
|
||||||
return (void *)GetArena<JSXML>(cell)->getAlignedThing(thing);
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
JS_NOT_REACHED("wrong kind");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void GetSizeAndThingsPerArena(int thingKind, size_t &thingSize, size_t &thingsPerArena)
|
void GetSizeAndThingsPerArena(int thingKind, size_t &thingSize, size_t &thingsPerArena)
|
||||||
{
|
{
|
||||||
switch (thingKind) {
|
switch (thingKind) {
|
||||||
|
@ -366,16 +325,16 @@ GCMarker::dumpConservativeRoots()
|
||||||
|
|
||||||
conservativeStats.dump(fp);
|
conservativeStats.dump(fp);
|
||||||
|
|
||||||
for (ConservativeRoot *i = conservativeRoots.begin();
|
for (void **thingp = conservativeRoots.begin(); thingp != conservativeRoots.end(); ++thingp) {
|
||||||
i != conservativeRoots.end();
|
void *thing = thingp;
|
||||||
++i) {
|
fprintf(fp, " %p: ", thing);
|
||||||
fprintf(fp, " %p: ", i->thing);
|
|
||||||
switch (GetFinalizableTraceKind(i->thingKind)) {
|
switch (GetGCThingTraceKind(thing)) {
|
||||||
default:
|
default:
|
||||||
JS_NOT_REACHED("Unknown trace kind");
|
JS_NOT_REACHED("Unknown trace kind");
|
||||||
|
|
||||||
case JSTRACE_OBJECT: {
|
case JSTRACE_OBJECT: {
|
||||||
JSObject *obj = (JSObject *) i->thing;
|
JSObject *obj = (JSObject *) thing;
|
||||||
fprintf(fp, "object %s", obj->getClass()->name);
|
fprintf(fp, "object %s", obj->getClass()->name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -384,7 +343,7 @@ GCMarker::dumpConservativeRoots()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case JSTRACE_STRING: {
|
case JSTRACE_STRING: {
|
||||||
JSString *str = (JSString *) i->thing;
|
JSString *str = (JSString *) thing;
|
||||||
if (str->isLinear()) {
|
if (str->isLinear()) {
|
||||||
char buf[50];
|
char buf[50];
|
||||||
PutEscapedString(buf, sizeof buf, &str->asLinear(), '"');
|
PutEscapedString(buf, sizeof buf, &str->asLinear(), '"');
|
||||||
|
@ -396,7 +355,7 @@ GCMarker::dumpConservativeRoots()
|
||||||
}
|
}
|
||||||
# if JS_HAS_XML_SUPPORT
|
# if JS_HAS_XML_SUPPORT
|
||||||
case JSTRACE_XML: {
|
case JSTRACE_XML: {
|
||||||
JSXML *xml = (JSXML *) i->thing;
|
JSXML *xml = (JSXML *) thing;
|
||||||
fprintf(fp, "xml %u", (unsigned)xml->xml_class);
|
fprintf(fp, "xml %u", (unsigned)xml->xml_class);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,6 @@ namespace gc {
|
||||||
*/
|
*/
|
||||||
enum ConservativeGCTest {
|
enum ConservativeGCTest {
|
||||||
CGCT_VALID,
|
CGCT_VALID,
|
||||||
CGCT_VALIDWITHOFFSET, /* points within an object */
|
|
||||||
CGCT_LOWBITSET, /* excluded because one of the low bits was set */
|
CGCT_LOWBITSET, /* excluded because one of the low bits was set */
|
||||||
CGCT_NOTARENA, /* not within arena range in a chunk */
|
CGCT_NOTARENA, /* not within arena range in a chunk */
|
||||||
CGCT_NOTCHUNK, /* not within a valid chunk */
|
CGCT_NOTCHUNK, /* not within a valid chunk */
|
||||||
|
@ -75,7 +74,9 @@ enum ConservativeGCTest {
|
||||||
|
|
||||||
struct ConservativeGCStats {
|
struct ConservativeGCStats {
|
||||||
uint32 counter[gc::CGCT_END]; /* ConservativeGCTest classification
|
uint32 counter[gc::CGCT_END]; /* ConservativeGCTest classification
|
||||||
counters */
|
counters */
|
||||||
|
uint32 unaligned; /* number of valid but not aligned on
|
||||||
|
thing start pointers */
|
||||||
|
|
||||||
void add(const ConservativeGCStats &another) {
|
void add(const ConservativeGCStats &another) {
|
||||||
for (size_t i = 0; i != JS_ARRAY_LENGTH(counter); ++i)
|
for (size_t i = 0; i != JS_ARRAY_LENGTH(counter); ++i)
|
||||||
|
@ -129,10 +130,6 @@ UpdateCompartmentStats(JSCompartment *comp, unsigned thingKind, uint32 nlivearen
|
||||||
uint32 nkilledArenas, uint32 nthings);
|
uint32 nkilledArenas, uint32 nthings);
|
||||||
#endif /* JS_GCMETER */
|
#endif /* JS_GCMETER */
|
||||||
|
|
||||||
#if defined JS_DUMP_CONSERVATIVE_GC_ROOTS
|
|
||||||
void *GetAlignedThing(void *thing, int thingKind);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} //gc
|
} //gc
|
||||||
|
|
||||||
#ifdef MOZ_GCTIMER
|
#ifdef MOZ_GCTIMER
|
||||||
|
|
|
@ -796,6 +796,8 @@ struct PointerHasher
|
||||||
template <class T>
|
template <class T>
|
||||||
struct DefaultHasher<T *>: PointerHasher<T *, tl::FloorLog2<sizeof(void *)>::result> { };
|
struct DefaultHasher<T *>: PointerHasher<T *, tl::FloorLog2<sizeof(void *)>::result> { };
|
||||||
|
|
||||||
|
/* Looking for a hasher for jsid? Try the DefaultHasher<jsid> in jsatom.h. */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* JS-friendly, STL-like container providing a hash-based map from keys to
|
* JS-friendly, STL-like container providing a hash-based map from keys to
|
||||||
* values. In particular, HashMap calls constructors and destructors of all
|
* values. In particular, HashMap calls constructors and destructors of all
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -45,807 +45,19 @@
|
||||||
*/
|
*/
|
||||||
#include "jsprvtd.h"
|
#include "jsprvtd.h"
|
||||||
#include "jspubtd.h"
|
#include "jspubtd.h"
|
||||||
#include "jsfun.h"
|
|
||||||
#include "jsopcode.h"
|
#include "jsopcode.h"
|
||||||
#include "jsscript.h"
|
#include "jsscript.h"
|
||||||
#include "jsvalue.h"
|
#include "jsvalue.h"
|
||||||
|
|
||||||
struct JSFrameRegs
|
#include "vm/Stack.h"
|
||||||
{
|
|
||||||
STATIC_SKIP_INFERENCE
|
|
||||||
js::Value *sp; /* stack pointer */
|
|
||||||
jsbytecode *pc; /* program counter */
|
|
||||||
JSStackFrame *fp; /* active frame */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Flags to toggle js::Interpret() execution. */
|
|
||||||
enum JSInterpMode
|
|
||||||
{
|
|
||||||
JSINTERP_NORMAL = 0, /* interpreter is running normally */
|
|
||||||
JSINTERP_RECORD = 1, /* interpreter has been started to record/run traces */
|
|
||||||
JSINTERP_SAFEPOINT = 2, /* interpreter should leave on a method JIT safe point */
|
|
||||||
JSINTERP_PROFILE = 3 /* interpreter should profile a loop */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Flags used in JSStackFrame::flags_ */
|
|
||||||
enum JSFrameFlags
|
|
||||||
{
|
|
||||||
/* Primary frame type */
|
|
||||||
JSFRAME_GLOBAL = 0x1, /* frame pushed for a global script */
|
|
||||||
JSFRAME_FUNCTION = 0x2, /* frame pushed for a scripted call */
|
|
||||||
JSFRAME_DUMMY = 0x4, /* frame pushed for bookkeeping */
|
|
||||||
|
|
||||||
/* Frame subtypes */
|
|
||||||
JSFRAME_EVAL = 0x8, /* frame pushed for eval() or debugger eval */
|
|
||||||
JSFRAME_DEBUGGER = 0x10, /* frame pushed for debugger eval */
|
|
||||||
JSFRAME_GENERATOR = 0x20, /* frame is associated with a generator */
|
|
||||||
JSFRAME_FLOATING_GENERATOR = 0x40, /* frame is is in generator obj, not on stack */
|
|
||||||
JSFRAME_CONSTRUCTING = 0x80, /* frame is for a constructor invocation */
|
|
||||||
|
|
||||||
/* Temporary frame states */
|
|
||||||
JSFRAME_YIELDING = 0x200, /* js::Interpret dispatched JSOP_YIELD */
|
|
||||||
JSFRAME_FINISHED_IN_INTERP = 0x400, /* set if frame finished in Interpret() */
|
|
||||||
|
|
||||||
/* Concerning function arguments */
|
|
||||||
JSFRAME_OVERRIDE_ARGS = 0x1000, /* overridden arguments local variable */
|
|
||||||
JSFRAME_OVERFLOW_ARGS = 0x2000, /* numActualArgs > numFormalArgs */
|
|
||||||
JSFRAME_UNDERFLOW_ARGS = 0x4000, /* numActualArgs < numFormalArgs */
|
|
||||||
|
|
||||||
/* Lazy frame initialization */
|
|
||||||
JSFRAME_HAS_IMACRO_PC = 0x8000, /* frame has imacpc value available */
|
|
||||||
JSFRAME_HAS_CALL_OBJ = 0x10000, /* frame has a callobj reachable from scopeChain_ */
|
|
||||||
JSFRAME_HAS_ARGS_OBJ = 0x20000, /* frame has an argsobj in JSStackFrame::args */
|
|
||||||
JSFRAME_HAS_HOOK_DATA = 0x40000, /* frame has hookData_ set */
|
|
||||||
JSFRAME_HAS_ANNOTATION = 0x80000, /* frame has annotation_ set */
|
|
||||||
JSFRAME_HAS_RVAL = 0x100000, /* frame has rval_ set */
|
|
||||||
JSFRAME_HAS_SCOPECHAIN = 0x200000, /* frame has scopeChain_ set */
|
|
||||||
JSFRAME_HAS_PREVPC = 0x400000 /* frame has prevpc_ set */
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace js { namespace mjit { struct JITScript; } }
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A stack frame is a part of a stack segment (see js::StackSegment) which is
|
|
||||||
* on the per-thread VM stack (see js::StackSpace).
|
|
||||||
*/
|
|
||||||
struct JSStackFrame
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
mutable uint32 flags_; /* bits described by JSFrameFlags */
|
|
||||||
union { /* describes what code is executing in a */
|
|
||||||
JSScript *script; /* global frame */
|
|
||||||
JSFunction *fun; /* function frame, pre GetScopeChain */
|
|
||||||
} exec;
|
|
||||||
union { /* describes the arguments of a function */
|
|
||||||
uintN nactual; /* pre GetArgumentsObject */
|
|
||||||
JSObject *obj; /* post GetArgumentsObject */
|
|
||||||
JSScript *script; /* eval has no args, but needs a script */
|
|
||||||
} args;
|
|
||||||
mutable JSObject *scopeChain_; /* current scope chain */
|
|
||||||
JSStackFrame *prev_; /* previous cx->regs->fp */
|
|
||||||
void *ncode_; /* return address for method JIT */
|
|
||||||
|
|
||||||
/* Lazily initialized */
|
|
||||||
js::Value rval_; /* return value of the frame */
|
|
||||||
jsbytecode *prevpc_; /* pc of previous frame*/
|
|
||||||
jsbytecode *imacropc_; /* pc of macro caller */
|
|
||||||
void *hookData_; /* closure returned by call hook */
|
|
||||||
void *annotation_; /* perhaps remove with bug 546848 */
|
|
||||||
|
|
||||||
friend class js::StackSpace;
|
|
||||||
friend class js::FrameRegsIter;
|
|
||||||
friend struct JSContext;
|
|
||||||
|
|
||||||
inline void initPrev(JSContext *cx);
|
|
||||||
|
|
||||||
public:
|
|
||||||
/*
|
|
||||||
* Stack frame sort (see JSStackFrame comment above)
|
|
||||||
*
|
|
||||||
* A stack frame may have one of three types, which determines which
|
|
||||||
* members of the frame may be accessed and other invariants:
|
|
||||||
*
|
|
||||||
* global frame: execution of global code or an eval in global code
|
|
||||||
* function frame: execution of function code or an eval in a function
|
|
||||||
* dummy frame: bookkeeping frame (read: hack)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool isFunctionFrame() const {
|
|
||||||
return !!(flags_ & JSFRAME_FUNCTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isGlobalFrame() const {
|
|
||||||
return !!(flags_ & JSFRAME_GLOBAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isDummyFrame() const {
|
|
||||||
return !!(flags_ & JSFRAME_DUMMY);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isScriptFrame() const {
|
|
||||||
bool retval = !!(flags_ & (JSFRAME_FUNCTION | JSFRAME_GLOBAL));
|
|
||||||
JS_ASSERT(retval == !isDummyFrame());
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Eval frames
|
|
||||||
*
|
|
||||||
* As noted above, global and function frames may optionally be 'eval
|
|
||||||
* frames'. Eval code shares its parent's arguments which means that the
|
|
||||||
* arg-access members of JSStackFrame may not be used for eval frames.
|
|
||||||
* Search for 'hasArgs' below for more details.
|
|
||||||
*
|
|
||||||
* A further sub-classification of eval frames is whether the frame was
|
|
||||||
* pushed for an ES5 strict-mode eval().
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool isEvalFrame() const {
|
|
||||||
JS_ASSERT_IF(flags_ & JSFRAME_EVAL, isScriptFrame());
|
|
||||||
return flags_ & JSFRAME_EVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isNonEvalFunctionFrame() const {
|
|
||||||
return (flags_ & (JSFRAME_FUNCTION | JSFRAME_EVAL)) == JSFRAME_FUNCTION;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isStrictEvalFrame() const {
|
|
||||||
return isEvalFrame() && script()->strictModeCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isNonStrictEvalFrame() const {
|
|
||||||
return isEvalFrame() && !script()->strictModeCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Frame initialization
|
|
||||||
*
|
|
||||||
* After acquiring a pointer to an uninitialized stack frame on the VM
|
|
||||||
* stack from js::StackSpace, these members are used to initialize the
|
|
||||||
* stack frame before officially pushing the frame into the context.
|
|
||||||
* Collecting frame initialization into a set of inline helpers allows
|
|
||||||
* simpler reasoning and makes call-optimization easier.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Used for Invoke, Interpret, trace-jit LeaveTree, and method-jit stubs. */
|
|
||||||
inline void initCallFrame(JSContext *cx, JSObject &callee, JSFunction *fun,
|
|
||||||
uint32 nactual, uint32 flags);
|
|
||||||
|
|
||||||
/* Used for SessionInvoke. */
|
|
||||||
inline void resetInvokeCallFrame();
|
|
||||||
|
|
||||||
/* Called by method-jit stubs and serve as a specification for jit-code. */
|
|
||||||
inline void initCallFrameCallerHalf(JSContext *cx, uint32 flags, void *ncode);
|
|
||||||
inline void initCallFrameEarlyPrologue(JSFunction *fun, uint32 nactual);
|
|
||||||
inline void initCallFrameLatePrologue();
|
|
||||||
|
|
||||||
/* Used for eval. */
|
|
||||||
inline void initEvalFrame(JSContext *cx, JSScript *script, JSStackFrame *prev,
|
|
||||||
uint32 flags);
|
|
||||||
inline void initGlobalFrame(JSScript *script, JSObject &chain, uint32 flags);
|
|
||||||
|
|
||||||
/* Used when activating generators. */
|
|
||||||
inline void stealFrameAndSlots(js::Value *vp, JSStackFrame *otherfp,
|
|
||||||
js::Value *othervp, js::Value *othersp);
|
|
||||||
|
|
||||||
/* Perhaps one fine day we will remove dummy frames. */
|
|
||||||
inline void initDummyFrame(JSContext *cx, JSObject &chain);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Previous frame
|
|
||||||
*
|
|
||||||
* A frame's 'prev' frame is either null or the previous frame pointed to
|
|
||||||
* by cx->regs->fp when this frame was pushed. Often, given two prev-linked
|
|
||||||
* frames, the next-frame is a function or eval that was called by the
|
|
||||||
* prev-frame, but not always: the prev-frame may have called a native that
|
|
||||||
* reentered the VM through JS_CallFunctionValue on the same context
|
|
||||||
* (without calling JS_SaveFrameChain) which pushed the next-frame. Thus,
|
|
||||||
* 'prev' has little semantic meaning and basically just tells the VM what
|
|
||||||
* to set cx->regs->fp to when this frame is popped.
|
|
||||||
*/
|
|
||||||
|
|
||||||
JSStackFrame *prev() const {
|
|
||||||
return prev_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void resetGeneratorPrev(JSContext *cx);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Frame slots
|
|
||||||
*
|
|
||||||
* A frame's 'slots' are the fixed slots associated with the frame (like
|
|
||||||
* local variables) followed by an expression stack holding temporary
|
|
||||||
* values. A frame's 'base' is the base of the expression stack.
|
|
||||||
*/
|
|
||||||
|
|
||||||
js::Value *slots() const {
|
|
||||||
return (js::Value *)(this + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
js::Value *base() const {
|
|
||||||
return slots() + script()->nfixed;
|
|
||||||
}
|
|
||||||
|
|
||||||
js::Value &varSlot(uintN i) {
|
|
||||||
JS_ASSERT(i < script()->nfixed);
|
|
||||||
JS_ASSERT_IF(maybeFun(), i < script()->bindings.countVars());
|
|
||||||
return slots()[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Script
|
|
||||||
*
|
|
||||||
* All function and global frames have an associated JSScript which holds
|
|
||||||
* the bytecode being executed for the frame.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get the frame's current bytecode, assuming |this| is in |cx|.
|
|
||||||
* next is frame whose prev == this, NULL if not known or if this == cx->fp().
|
|
||||||
*/
|
|
||||||
jsbytecode *pc(JSContext *cx, JSStackFrame *next = NULL);
|
|
||||||
|
|
||||||
jsbytecode *prevpc() {
|
|
||||||
JS_ASSERT((prev_ != NULL) && (flags_ & JSFRAME_HAS_PREVPC));
|
|
||||||
return prevpc_;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSScript *script() const {
|
|
||||||
JS_ASSERT(isScriptFrame());
|
|
||||||
return isFunctionFrame()
|
|
||||||
? isEvalFrame() ? args.script : fun()->script()
|
|
||||||
: exec.script;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSScript *functionScript() const {
|
|
||||||
JS_ASSERT(isFunctionFrame());
|
|
||||||
return isEvalFrame() ? args.script : fun()->script();
|
|
||||||
}
|
|
||||||
|
|
||||||
JSScript *globalScript() const {
|
|
||||||
JS_ASSERT(isGlobalFrame());
|
|
||||||
return exec.script;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSScript *maybeScript() const {
|
|
||||||
return isScriptFrame() ? script() : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t numFixed() const {
|
|
||||||
return script()->nfixed;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t numSlots() const {
|
|
||||||
return script()->nslots;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t numGlobalVars() const {
|
|
||||||
JS_ASSERT(isGlobalFrame());
|
|
||||||
return exec.script->nfixed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Function
|
|
||||||
*
|
|
||||||
* All function frames have an associated interpreted JSFunction.
|
|
||||||
*/
|
|
||||||
|
|
||||||
JSFunction* fun() const {
|
|
||||||
JS_ASSERT(isFunctionFrame());
|
|
||||||
return exec.fun;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSFunction* maybeFun() const {
|
|
||||||
return isFunctionFrame() ? fun() : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Arguments
|
|
||||||
*
|
|
||||||
* Only non-eval function frames have arguments. A frame follows its
|
|
||||||
* arguments contiguously in memory. The arguments pushed by the caller are
|
|
||||||
* the 'actual' arguments. The declared arguments of the callee are the
|
|
||||||
* 'formal' arguments. When the caller passes less or equal actual
|
|
||||||
* arguments, the actual and formal arguments are the same array (but with
|
|
||||||
* different extents). When the caller passes too many arguments, the
|
|
||||||
* formal subset of the actual arguments is copied onto the top of the
|
|
||||||
* stack. This allows the engine to maintain a jit-time constant offset of
|
|
||||||
* arguments from the frame pointer. Since the formal subset of the actual
|
|
||||||
* arguments is potentially on the stack twice, it is important for all
|
|
||||||
* reads/writes to refer to the same canonical memory location.
|
|
||||||
*
|
|
||||||
* An arguments object (the object returned by the 'arguments' keyword) is
|
|
||||||
* lazily created, so a given function frame may or may not have one.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* True if this frame has arguments. Contrast with hasArgsObj. */
|
|
||||||
bool hasArgs() const {
|
|
||||||
return isNonEvalFunctionFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
uintN numFormalArgs() const {
|
|
||||||
JS_ASSERT(hasArgs());
|
|
||||||
return fun()->nargs;
|
|
||||||
}
|
|
||||||
|
|
||||||
js::Value &formalArg(uintN i) const {
|
|
||||||
JS_ASSERT(i < numFormalArgs());
|
|
||||||
return formalArgs()[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
js::Value *formalArgs() const {
|
|
||||||
JS_ASSERT(hasArgs());
|
|
||||||
return (js::Value *)this - numFormalArgs();
|
|
||||||
}
|
|
||||||
|
|
||||||
js::Value *formalArgsEnd() const {
|
|
||||||
JS_ASSERT(hasArgs());
|
|
||||||
return (js::Value *)this;
|
|
||||||
}
|
|
||||||
|
|
||||||
js::Value *maybeFormalArgs() const {
|
|
||||||
return (flags_ & (JSFRAME_FUNCTION | JSFRAME_EVAL)) == JSFRAME_FUNCTION
|
|
||||||
? formalArgs()
|
|
||||||
: NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uintN numActualArgs() const;
|
|
||||||
inline js::Value *actualArgs() const;
|
|
||||||
inline js::Value *actualArgsEnd() const;
|
|
||||||
|
|
||||||
inline js::Value &canonicalActualArg(uintN i) const;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Apply 'op' to each arg of the specified type. Stop if 'op' returns
|
|
||||||
* false. Return 'true' iff all 'op' calls returned true.
|
|
||||||
*/
|
|
||||||
template <class Op> inline bool forEachCanonicalActualArg(Op op);
|
|
||||||
template <class Op> inline bool forEachFormalArg(Op op);
|
|
||||||
|
|
||||||
inline void clearMissingArgs();
|
|
||||||
|
|
||||||
bool hasArgsObj() const {
|
|
||||||
return !!(flags_ & JSFRAME_HAS_ARGS_OBJ);
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObject &argsObj() const {
|
|
||||||
JS_ASSERT(hasArgsObj());
|
|
||||||
JS_ASSERT(!isEvalFrame());
|
|
||||||
return *args.obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObject *maybeArgsObj() const {
|
|
||||||
return hasArgsObj() ? &argsObj() : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void setArgsObj(JSObject &obj);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This value
|
|
||||||
*
|
|
||||||
* Every frame has a this value although, until 'this' is computed, the
|
|
||||||
* value may not be the semantically-correct 'this' value.
|
|
||||||
*
|
|
||||||
* The 'this' value is stored before the formal arguments for function
|
|
||||||
* frames and directly before the frame for global frames. The *Args
|
|
||||||
* members assert !isEvalFrame(), so we implement specialized inline
|
|
||||||
* methods for accessing 'this'. When the caller has static knowledge that
|
|
||||||
* a frame is a function or global frame, 'functionThis' and 'globalThis',
|
|
||||||
* respectively, allow more efficient access.
|
|
||||||
*/
|
|
||||||
|
|
||||||
js::Value &functionThis() const {
|
|
||||||
JS_ASSERT(isFunctionFrame());
|
|
||||||
if (isEvalFrame())
|
|
||||||
return ((js::Value *)this)[-1];
|
|
||||||
return formalArgs()[-1];
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObject &constructorThis() const {
|
|
||||||
JS_ASSERT(hasArgs());
|
|
||||||
return formalArgs()[-1].toObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
js::Value &globalThis() const {
|
|
||||||
JS_ASSERT(isGlobalFrame());
|
|
||||||
return ((js::Value *)this)[-1];
|
|
||||||
}
|
|
||||||
|
|
||||||
js::Value &thisValue() const {
|
|
||||||
if (flags_ & (JSFRAME_EVAL | JSFRAME_GLOBAL))
|
|
||||||
return ((js::Value *)this)[-1];
|
|
||||||
return formalArgs()[-1];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Callee
|
|
||||||
*
|
|
||||||
* Only function frames have a callee. An eval frame in a function has the
|
|
||||||
* same caller as its containing function frame.
|
|
||||||
*/
|
|
||||||
|
|
||||||
js::Value &calleev() const {
|
|
||||||
JS_ASSERT(isFunctionFrame());
|
|
||||||
if (isEvalFrame())
|
|
||||||
return ((js::Value *)this)[-2];
|
|
||||||
return formalArgs()[-2];
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObject &callee() const {
|
|
||||||
JS_ASSERT(isFunctionFrame());
|
|
||||||
return calleev().toObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObject *maybeCallee() const {
|
|
||||||
return isFunctionFrame() ? &callee() : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
js::CallReceiver callReceiver() const {
|
|
||||||
return js::CallReceiverFromArgv(formalArgs());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* getValidCalleeObject is a fallible getter to compute the correct callee
|
|
||||||
* function object, which may require deferred cloning due to the JSObject
|
|
||||||
* methodReadBarrier. For a non-function frame, return true with *vp set
|
|
||||||
* from calleev, which may not be an object (it could be undefined).
|
|
||||||
*/
|
|
||||||
bool getValidCalleeObject(JSContext *cx, js::Value *vp);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Scope chain
|
|
||||||
*
|
|
||||||
* Every frame has a scopeChain which, when traversed via the 'parent' link
|
|
||||||
* to the root, indicates the current global object. A 'call object' is a
|
|
||||||
* node on a scope chain representing a function's activation record. A
|
|
||||||
* call object is used for dynamically-scoped name lookup and lexically-
|
|
||||||
* scoped upvar access. The call object holds the values of locals and
|
|
||||||
* arguments when a function returns (and its stack frame is popped). For
|
|
||||||
* performance reasons, call objects are created lazily for 'lightweight'
|
|
||||||
* functions, i.e., functions which are not statically known to require a
|
|
||||||
* call object. Thus, a given function frame may or may not have a call
|
|
||||||
* object. When a function does have a call object, it is found by walking
|
|
||||||
* up the scope chain until the first call object. Thus, it is important,
|
|
||||||
* when setting the scope chain, to indicate whether the new scope chain
|
|
||||||
* contains a new call object and thus changes the 'hasCallObj' state.
|
|
||||||
*
|
|
||||||
* NB: 'fp->hasCallObj()' implies that fp->callObj() needs to be 'put' when
|
|
||||||
* the frame is popped. Since the scope chain of a non-strict eval frame
|
|
||||||
* contains the call object of the parent (function) frame, it is possible
|
|
||||||
* to have:
|
|
||||||
* !fp->hasCall() && fp->scopeChain().isCall()
|
|
||||||
*/
|
|
||||||
|
|
||||||
JSObject &scopeChain() const {
|
|
||||||
JS_ASSERT_IF(!(flags_ & JSFRAME_HAS_SCOPECHAIN), isFunctionFrame());
|
|
||||||
if (!(flags_ & JSFRAME_HAS_SCOPECHAIN)) {
|
|
||||||
scopeChain_ = callee().getParent();
|
|
||||||
flags_ |= JSFRAME_HAS_SCOPECHAIN;
|
|
||||||
}
|
|
||||||
return *scopeChain_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasCallObj() const {
|
|
||||||
bool ret = !!(flags_ & JSFRAME_HAS_CALL_OBJ);
|
|
||||||
JS_ASSERT_IF(ret, !isNonStrictEvalFrame());
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline JSObject &callObj() const;
|
|
||||||
inline void setScopeChainNoCallObj(JSObject &obj);
|
|
||||||
inline void setScopeChainWithOwnCallObj(JSObject &obj);
|
|
||||||
|
|
||||||
inline void markActivationObjectsAsPut();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Frame compartment
|
|
||||||
*
|
|
||||||
* A stack frame's compartment is the frame's containing context's
|
|
||||||
* compartment when the frame was pushed.
|
|
||||||
*/
|
|
||||||
|
|
||||||
JSCompartment *compartment() const {
|
|
||||||
JS_ASSERT_IF(isScriptFrame(), scopeChain().compartment() == script()->compartment);
|
|
||||||
return scopeChain().compartment();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline JSPrincipals *principals(JSContext *cx) const;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Imacropc
|
|
||||||
*
|
|
||||||
* A frame's IMacro pc is the bytecode address when an imacro started
|
|
||||||
* executing (guaranteed non-null). An imacro does not push a frame, so
|
|
||||||
* when the imacro finishes, the frame's IMacro pc becomes the current pc.
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool hasImacropc() const {
|
|
||||||
return flags_ & JSFRAME_HAS_IMACRO_PC;
|
|
||||||
}
|
|
||||||
|
|
||||||
jsbytecode *imacropc() const {
|
|
||||||
JS_ASSERT(hasImacropc());
|
|
||||||
return imacropc_;
|
|
||||||
}
|
|
||||||
|
|
||||||
jsbytecode *maybeImacropc() const {
|
|
||||||
return hasImacropc() ? imacropc() : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearImacropc() {
|
|
||||||
flags_ &= ~JSFRAME_HAS_IMACRO_PC;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setImacropc(jsbytecode *pc) {
|
|
||||||
JS_ASSERT(pc);
|
|
||||||
JS_ASSERT(!(flags_ & JSFRAME_HAS_IMACRO_PC));
|
|
||||||
imacropc_ = pc;
|
|
||||||
flags_ |= JSFRAME_HAS_IMACRO_PC;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Annotation (will be removed after bug 546848) */
|
|
||||||
|
|
||||||
void* annotation() const {
|
|
||||||
return (flags_ & JSFRAME_HAS_ANNOTATION) ? annotation_ : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setAnnotation(void *annot) {
|
|
||||||
flags_ |= JSFRAME_HAS_ANNOTATION;
|
|
||||||
annotation_ = annot;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Debugger hook data */
|
|
||||||
|
|
||||||
bool hasHookData() const {
|
|
||||||
return !!(flags_ & JSFRAME_HAS_HOOK_DATA);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* hookData() const {
|
|
||||||
JS_ASSERT(hasHookData());
|
|
||||||
return hookData_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* maybeHookData() const {
|
|
||||||
return hasHookData() ? hookData_ : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setHookData(void *v) {
|
|
||||||
hookData_ = v;
|
|
||||||
flags_ |= JSFRAME_HAS_HOOK_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return value */
|
|
||||||
|
|
||||||
const js::Value &returnValue() {
|
|
||||||
if (!(flags_ & JSFRAME_HAS_RVAL))
|
|
||||||
rval_.setUndefined();
|
|
||||||
return rval_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void markReturnValue() {
|
|
||||||
flags_ |= JSFRAME_HAS_RVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setReturnValue(const js::Value &v) {
|
|
||||||
rval_ = v;
|
|
||||||
markReturnValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearReturnValue() {
|
|
||||||
rval_.setUndefined();
|
|
||||||
markReturnValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Native-code return address */
|
|
||||||
|
|
||||||
void *nativeReturnAddress() const {
|
|
||||||
return ncode_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setNativeReturnAddress(void *addr) {
|
|
||||||
ncode_ = addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void **addressOfNativeReturnAddress() {
|
|
||||||
return &ncode_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Generator-specific members
|
|
||||||
*
|
|
||||||
* A non-eval function frame may optionally be the activation of a
|
|
||||||
* generator. For the most part, generator frames act like ordinary frames.
|
|
||||||
* For exceptions, see js_FloatingFrameIfGenerator.
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool isGeneratorFrame() const {
|
|
||||||
return !!(flags_ & JSFRAME_GENERATOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isFloatingGenerator() const {
|
|
||||||
JS_ASSERT_IF(flags_ & JSFRAME_FLOATING_GENERATOR, isGeneratorFrame());
|
|
||||||
return !!(flags_ & JSFRAME_FLOATING_GENERATOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
void initFloatingGenerator() {
|
|
||||||
JS_ASSERT(!(flags_ & JSFRAME_GENERATOR));
|
|
||||||
flags_ |= (JSFRAME_GENERATOR | JSFRAME_FLOATING_GENERATOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
void unsetFloatingGenerator() {
|
|
||||||
flags_ &= ~JSFRAME_FLOATING_GENERATOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setFloatingGenerator() {
|
|
||||||
flags_ |= JSFRAME_FLOATING_GENERATOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* js::Execute pushes both global and function frames (since eval() in a
|
|
||||||
* function pushes a frame with isFunctionFrame() && isEvalFrame()). Most
|
|
||||||
* code should not care where a frame was pushed, but if it is necessary to
|
|
||||||
* pick out frames pushed by js::Execute, this is the right query:
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool isFramePushedByExecute() const {
|
|
||||||
return !!(flags_ & (JSFRAME_GLOBAL | JSFRAME_EVAL));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Other flags
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool isConstructing() const {
|
|
||||||
return !!(flags_ & JSFRAME_CONSTRUCTING);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 isConstructingFlag() const {
|
|
||||||
JS_ASSERT(isFunctionFrame());
|
|
||||||
JS_ASSERT((flags_ & ~(JSFRAME_CONSTRUCTING | JSFRAME_FUNCTION)) == 0);
|
|
||||||
return flags_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isDebuggerFrame() const {
|
|
||||||
return !!(flags_ & JSFRAME_DEBUGGER);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isEvalOrDebuggerFrame() const {
|
|
||||||
return !!(flags_ & (JSFRAME_EVAL | JSFRAME_DEBUGGER));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasOverriddenArgs() const {
|
|
||||||
return !!(flags_ & JSFRAME_OVERRIDE_ARGS);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasOverflowArgs() const {
|
|
||||||
return !!(flags_ & JSFRAME_OVERFLOW_ARGS);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setOverriddenArgs() {
|
|
||||||
flags_ |= JSFRAME_OVERRIDE_ARGS;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isYielding() {
|
|
||||||
return !!(flags_ & JSFRAME_YIELDING);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setYielding() {
|
|
||||||
flags_ |= JSFRAME_YIELDING;
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearYielding() {
|
|
||||||
flags_ &= ~JSFRAME_YIELDING;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setFinishedInInterpreter() {
|
|
||||||
flags_ |= JSFRAME_FINISHED_IN_INTERP;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool finishedInInterpreter() const {
|
|
||||||
return !!(flags_ & JSFRAME_FINISHED_IN_INTERP);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Variables object accessors
|
|
||||||
*
|
|
||||||
* A stack frame's 'varobj' refers to the 'variables object' (ES3 term)
|
|
||||||
* associated with the Execution Context's VariableEnvironment (ES5 10.3).
|
|
||||||
*
|
|
||||||
* To compute the frame's varobj, the caller must supply the segment
|
|
||||||
* containing the frame (see js::StackSegment comment). As an abbreviation,
|
|
||||||
* the caller may pass the context if the frame is contained in that
|
|
||||||
* context's active segment.
|
|
||||||
*/
|
|
||||||
|
|
||||||
inline JSObject &varobj(js::StackSegment *seg) const;
|
|
||||||
inline JSObject &varobj(JSContext *cx) const;
|
|
||||||
|
|
||||||
/* Access to privates from the jits. */
|
|
||||||
|
|
||||||
static size_t offsetOfFlags() {
|
|
||||||
return offsetof(JSStackFrame, flags_);
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t offsetOfExec() {
|
|
||||||
return offsetof(JSStackFrame, exec);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *addressOfArgs() {
|
|
||||||
return &args;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t offsetOfScopeChain() {
|
|
||||||
return offsetof(JSStackFrame, scopeChain_);
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObject **addressOfScopeChain() {
|
|
||||||
JS_ASSERT(flags_ & JSFRAME_HAS_SCOPECHAIN);
|
|
||||||
return &scopeChain_;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t offsetOfPrev() {
|
|
||||||
return offsetof(JSStackFrame, prev_);
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t offsetOfReturnValue() {
|
|
||||||
return offsetof(JSStackFrame, rval_);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ptrdiff_t offsetOfncode() {
|
|
||||||
return offsetof(JSStackFrame, ncode_);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ptrdiff_t offsetOfCallee(JSFunction *fun) {
|
|
||||||
JS_ASSERT(fun != NULL);
|
|
||||||
return -(fun->nargs + 2) * sizeof(js::Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ptrdiff_t offsetOfThis(JSFunction *fun) {
|
|
||||||
return fun == NULL
|
|
||||||
? -1 * ptrdiff_t(sizeof(js::Value))
|
|
||||||
: -(fun->nargs + 1) * ptrdiff_t(sizeof(js::Value));
|
|
||||||
}
|
|
||||||
|
|
||||||
static ptrdiff_t offsetOfFormalArg(JSFunction *fun, uintN i) {
|
|
||||||
JS_ASSERT(i < fun->nargs);
|
|
||||||
return (-(int)fun->nargs + i) * sizeof(js::Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t offsetOfFixed(uintN i) {
|
|
||||||
return sizeof(JSStackFrame) + i * sizeof(js::Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Workaround for static asserts on private members. */
|
|
||||||
|
|
||||||
void staticAsserts() {
|
|
||||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, rval_) % sizeof(js::Value) == 0);
|
|
||||||
JS_STATIC_ASSERT(sizeof(JSStackFrame) % sizeof(js::Value) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef JS_METHODJIT
|
|
||||||
js::mjit::JITScript *jit() {
|
|
||||||
return script()->getJIT(isConstructing());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void methodjitStaticAsserts();
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
/* Poison scopeChain value set before a frame is flushed. */
|
|
||||||
static JSObject *const sInvalidScopeChain;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
static const size_t VALUES_PER_STACK_FRAME = sizeof(JSStackFrame) / sizeof(Value);
|
extern JSObject *
|
||||||
|
GetBlockChain(JSContext *cx, StackFrame *fp);
|
||||||
|
|
||||||
extern JSObject *
|
extern JSObject *
|
||||||
GetBlockChain(JSContext *cx, JSStackFrame *fp);
|
GetBlockChainFast(JSContext *cx, StackFrame *fp, JSOp op, size_t oplen);
|
||||||
|
|
||||||
extern JSObject *
|
|
||||||
GetBlockChainFast(JSContext *cx, JSStackFrame *fp, JSOp op, size_t oplen);
|
|
||||||
|
|
||||||
extern JSObject *
|
extern JSObject *
|
||||||
GetScopeChain(JSContext *cx);
|
GetScopeChain(JSContext *cx);
|
||||||
|
@ -858,10 +70,10 @@ GetScopeChain(JSContext *cx);
|
||||||
* must reflect at runtime.
|
* must reflect at runtime.
|
||||||
*/
|
*/
|
||||||
extern JSObject *
|
extern JSObject *
|
||||||
GetScopeChain(JSContext *cx, JSStackFrame *fp);
|
GetScopeChain(JSContext *cx, StackFrame *fp);
|
||||||
|
|
||||||
extern JSObject *
|
extern JSObject *
|
||||||
GetScopeChainFast(JSContext *cx, JSStackFrame *fp, JSOp op, size_t oplen);
|
GetScopeChainFast(JSContext *cx, StackFrame *fp, JSOp op, size_t oplen);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Report an error that the this value passed as |this| in the given arguments
|
* Report an error that the this value passed as |this| in the given arguments
|
||||||
|
@ -881,16 +93,6 @@ ReportIncompatibleMethod(JSContext *cx, Value *vp, Class *clasp);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool GetPrimitiveThis(JSContext *cx, Value *vp, T *v);
|
bool GetPrimitiveThis(JSContext *cx, Value *vp, T *v);
|
||||||
|
|
||||||
inline void
|
|
||||||
PutActivationObjects(JSContext *cx, JSStackFrame *fp)
|
|
||||||
{
|
|
||||||
/* The order is important since js_PutCallObject does js_PutArgsObject. */
|
|
||||||
if (fp->hasCallObj())
|
|
||||||
js_PutCallObject(cx, fp);
|
|
||||||
else if (fp->hasArgsObj())
|
|
||||||
js_PutArgsObject(cx, fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ScriptPrologue/ScriptEpilogue must be called in pairs. ScriptPrologue
|
* ScriptPrologue/ScriptEpilogue must be called in pairs. ScriptPrologue
|
||||||
* must be called before the script executes. ScriptEpilogue must be called
|
* must be called before the script executes. ScriptEpilogue must be called
|
||||||
|
@ -898,10 +100,10 @@ PutActivationObjects(JSContext *cx, JSStackFrame *fp)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
ScriptPrologue(JSContext *cx, JSStackFrame *fp, JSScript *script);
|
ScriptPrologue(JSContext *cx, StackFrame *fp, JSScript *script);
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
ScriptEpilogue(JSContext *cx, JSStackFrame *fp, bool ok);
|
ScriptEpilogue(JSContext *cx, StackFrame *fp, bool ok);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* It is not valid to call ScriptPrologue when a generator is resumed or to
|
* It is not valid to call ScriptPrologue when a generator is resumed or to
|
||||||
|
@ -911,18 +113,18 @@ ScriptEpilogue(JSContext *cx, JSStackFrame *fp, bool ok);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
ScriptPrologueOrGeneratorResume(JSContext *cx, JSStackFrame *fp);
|
ScriptPrologueOrGeneratorResume(JSContext *cx, StackFrame *fp);
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
ScriptEpilogueOrGeneratorYield(JSContext *cx, JSStackFrame *fp, bool ok);
|
ScriptEpilogueOrGeneratorYield(JSContext *cx, StackFrame *fp, bool ok);
|
||||||
|
|
||||||
/* Implemented in jsdbgapi: */
|
/* Implemented in jsdbgapi: */
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
ScriptDebugPrologue(JSContext *cx, JSStackFrame *fp);
|
ScriptDebugPrologue(JSContext *cx, StackFrame *fp);
|
||||||
|
|
||||||
extern bool
|
extern bool
|
||||||
ScriptDebugEpilogue(JSContext *cx, JSStackFrame *fp, bool ok);
|
ScriptDebugEpilogue(JSContext *cx, StackFrame *fp, bool ok);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For a given |call|, convert null/undefined |this| into the global object for
|
* For a given |call|, convert null/undefined |this| into the global object for
|
||||||
|
@ -940,18 +142,40 @@ BoxNonStrictThis(JSContext *cx, const CallReceiver &call);
|
||||||
* an optimization to avoid global-this computation).
|
* an optimization to avoid global-this computation).
|
||||||
*/
|
*/
|
||||||
inline bool
|
inline bool
|
||||||
ComputeThis(JSContext *cx, JSStackFrame *fp);
|
ComputeThis(JSContext *cx, StackFrame *fp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Choose enumerator values so that the enum can be passed used directly as the
|
||||||
|
* stack frame flags.
|
||||||
|
*/
|
||||||
|
enum ConstructOption {
|
||||||
|
INVOKE_NORMAL = 0,
|
||||||
|
INVOKE_CONSTRUCTOR = StackFrame::CONSTRUCTING
|
||||||
|
};
|
||||||
|
JS_STATIC_ASSERT(INVOKE_CONSTRUCTOR != INVOKE_NORMAL);
|
||||||
|
|
||||||
|
static inline uintN
|
||||||
|
ToReportFlags(ConstructOption option)
|
||||||
|
{
|
||||||
|
return (uintN)option;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32
|
||||||
|
ToFrameFlags(ConstructOption option)
|
||||||
|
{
|
||||||
|
return (uintN)option;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The js::InvokeArgumentsGuard passed to js_Invoke must come from an
|
* The js::InvokeArgumentsGuard passed to js_Invoke must come from an
|
||||||
* immediately-enclosing successful call to js::StackSpace::pushInvokeArgs,
|
* immediately-enclosing successful call to js::StackSpace::pushInvokeArgs,
|
||||||
* i.e., there must have been no un-popped pushes to cx->stack(). Furthermore,
|
* i.e., there must have been no un-popped pushes to cx->stack. Furthermore,
|
||||||
* |args.getvp()[0]| should be the callee, |args.getvp()[1]| should be |this|,
|
* |args.getvp()[0]| should be the callee, |args.getvp()[1]| should be |this|,
|
||||||
* and the range [args.getvp() + 2, args.getvp() + 2 + args.getArgc()) should
|
* and the range [args.getvp() + 2, args.getvp() + 2 + args.getArgc()) should
|
||||||
* be initialized actual arguments.
|
* be initialized actual arguments.
|
||||||
*/
|
*/
|
||||||
extern JS_REQUIRES_STACK bool
|
extern JS_REQUIRES_STACK bool
|
||||||
Invoke(JSContext *cx, const CallArgs &args, uint32 flags);
|
Invoke(JSContext *cx, const CallArgs &args, ConstructOption option = INVOKE_NORMAL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Natives like sort/forEach/replace call Invoke repeatedly with the same
|
* Natives like sort/forEach/replace call Invoke repeatedly with the same
|
||||||
|
@ -979,29 +203,9 @@ Invoke(JSContext *cx, const CallArgs &args, uint32 flags);
|
||||||
*/
|
*/
|
||||||
class InvokeSessionGuard;
|
class InvokeSessionGuard;
|
||||||
|
|
||||||
/*
|
|
||||||
* Consolidated js_Invoke flags simply rename certain JSFRAME_* flags, so that
|
|
||||||
* we can share bits stored in JSStackFrame.flags and passed to:
|
|
||||||
*
|
|
||||||
* js_Invoke
|
|
||||||
* js_InternalInvoke
|
|
||||||
* js_ValueToFunction
|
|
||||||
* js_ValueToFunctionObject
|
|
||||||
* js_ValueToCallableObject
|
|
||||||
* js_ReportIsNotFunction
|
|
||||||
*
|
|
||||||
* See jsfun.h for the latter four and flag renaming macros.
|
|
||||||
*/
|
|
||||||
#define JSINVOKE_CONSTRUCT JSFRAME_CONSTRUCTING
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Mask to isolate construct and iterator flags for use with jsfun.h functions.
|
|
||||||
*/
|
|
||||||
#define JSINVOKE_FUNFLAGS JSINVOKE_CONSTRUCT
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "External" 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.
|
* JS is running (!cx->fp), so they may need to push a dummy StackFrame.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern bool
|
extern bool
|
||||||
|
@ -1037,17 +241,26 @@ ExternalInvokeConstructor(JSContext *cx, const Value &fval, uintN argc, Value *a
|
||||||
*/
|
*/
|
||||||
extern JS_FORCES_STACK bool
|
extern JS_FORCES_STACK bool
|
||||||
Execute(JSContext *cx, JSObject &chain, JSScript *script,
|
Execute(JSContext *cx, JSObject &chain, JSScript *script,
|
||||||
JSStackFrame *prev, uintN flags, Value *result);
|
StackFrame *prev, uintN flags, Value *result);
|
||||||
|
|
||||||
|
/* Flags to toggle js::Interpret() execution. */
|
||||||
|
enum InterpMode
|
||||||
|
{
|
||||||
|
JSINTERP_NORMAL = 0, /* interpreter is running normally */
|
||||||
|
JSINTERP_RECORD = 1, /* interpreter has been started to record/run traces */
|
||||||
|
JSINTERP_SAFEPOINT = 2, /* interpreter should leave on a method JIT safe point */
|
||||||
|
JSINTERP_PROFILE = 3 /* interpreter should profile a loop */
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Execute the caller-initialized frame for a user-defined script or function
|
* Execute the caller-initialized frame for a user-defined script or function
|
||||||
* pointed to by cx->fp until completion or error.
|
* pointed to by cx->fp until completion or error.
|
||||||
*/
|
*/
|
||||||
extern JS_REQUIRES_STACK JS_NEVER_INLINE bool
|
extern JS_REQUIRES_STACK JS_NEVER_INLINE bool
|
||||||
Interpret(JSContext *cx, JSStackFrame *stopFp, uintN inlineCallCount = 0, JSInterpMode mode = JSINTERP_NORMAL);
|
Interpret(JSContext *cx, StackFrame *stopFp, uintN inlineCallCount = 0, InterpMode mode = JSINTERP_NORMAL);
|
||||||
|
|
||||||
extern JS_REQUIRES_STACK bool
|
extern JS_REQUIRES_STACK bool
|
||||||
RunScript(JSContext *cx, JSScript *script, JSStackFrame *fp);
|
RunScript(JSContext *cx, JSScript *script, StackFrame *fp);
|
||||||
|
|
||||||
extern bool
|
extern bool
|
||||||
CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs);
|
CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs);
|
||||||
|
@ -1102,8 +315,6 @@ GetUpvar(JSContext *cx, uintN level, js::UpvarCookie cookie);
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define JS_MAX_INLINE_CALL_COUNT 3000
|
|
||||||
|
|
||||||
#if !JS_LONE_INTERPRET
|
#if !JS_LONE_INTERPRET
|
||||||
# define JS_STATIC_INTERPRET static
|
# define JS_STATIC_INTERPRET static
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -52,425 +52,7 @@
|
||||||
|
|
||||||
#include "jsfuninlines.h"
|
#include "jsfuninlines.h"
|
||||||
|
|
||||||
inline void
|
#include "vm/Stack-inl.h"
|
||||||
JSStackFrame::initPrev(JSContext *cx)
|
|
||||||
{
|
|
||||||
JS_ASSERT(flags_ & JSFRAME_HAS_PREVPC);
|
|
||||||
if (JSFrameRegs *regs = cx->regs) {
|
|
||||||
prev_ = regs->fp;
|
|
||||||
prevpc_ = regs->pc;
|
|
||||||
JS_ASSERT_IF(!prev_->isDummyFrame() && !prev_->hasImacropc(),
|
|
||||||
uint32(prevpc_ - prev_->script()->code) < prev_->script()->length);
|
|
||||||
} else {
|
|
||||||
prev_ = NULL;
|
|
||||||
#ifdef DEBUG
|
|
||||||
prevpc_ = (jsbytecode *)0xbadc;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
JSStackFrame::resetGeneratorPrev(JSContext *cx)
|
|
||||||
{
|
|
||||||
flags_ |= JSFRAME_HAS_PREVPC;
|
|
||||||
initPrev(cx);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
JSStackFrame::initCallFrame(JSContext *cx, JSObject &callee, JSFunction *fun,
|
|
||||||
uint32 nactual, uint32 flagsArg)
|
|
||||||
{
|
|
||||||
JS_ASSERT((flagsArg & ~(JSFRAME_CONSTRUCTING |
|
|
||||||
JSFRAME_OVERFLOW_ARGS |
|
|
||||||
JSFRAME_UNDERFLOW_ARGS)) == 0);
|
|
||||||
JS_ASSERT(fun == callee.getFunctionPrivate());
|
|
||||||
|
|
||||||
/* Initialize stack frame members. */
|
|
||||||
flags_ = JSFRAME_FUNCTION | JSFRAME_HAS_PREVPC | JSFRAME_HAS_SCOPECHAIN | flagsArg;
|
|
||||||
exec.fun = fun;
|
|
||||||
args.nactual = nactual; /* only need to write if over/under-flow */
|
|
||||||
scopeChain_ = callee.getParent();
|
|
||||||
initPrev(cx);
|
|
||||||
JS_ASSERT(!hasImacropc());
|
|
||||||
JS_ASSERT(!hasHookData());
|
|
||||||
JS_ASSERT(annotation() == NULL);
|
|
||||||
JS_ASSERT(!hasCallObj());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
JSStackFrame::resetInvokeCallFrame()
|
|
||||||
{
|
|
||||||
/* Undo changes to frame made during execution; see initCallFrame */
|
|
||||||
|
|
||||||
JS_ASSERT(!(flags_ & ~(JSFRAME_FUNCTION |
|
|
||||||
JSFRAME_OVERFLOW_ARGS |
|
|
||||||
JSFRAME_UNDERFLOW_ARGS |
|
|
||||||
JSFRAME_OVERRIDE_ARGS |
|
|
||||||
JSFRAME_HAS_PREVPC |
|
|
||||||
JSFRAME_HAS_RVAL |
|
|
||||||
JSFRAME_HAS_SCOPECHAIN |
|
|
||||||
JSFRAME_HAS_ANNOTATION |
|
|
||||||
JSFRAME_HAS_HOOK_DATA |
|
|
||||||
JSFRAME_HAS_CALL_OBJ |
|
|
||||||
JSFRAME_HAS_ARGS_OBJ |
|
|
||||||
JSFRAME_FINISHED_IN_INTERP)));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Since the stack frame is usually popped after PutActivationObjects,
|
|
||||||
* these bits aren't cleared. The activation objects must have actually
|
|
||||||
* been put, though.
|
|
||||||
*/
|
|
||||||
JS_ASSERT_IF(flags_ & JSFRAME_HAS_CALL_OBJ, callObj().getPrivate() == NULL);
|
|
||||||
JS_ASSERT_IF(flags_ & JSFRAME_HAS_ARGS_OBJ, argsObj().getPrivate() == NULL);
|
|
||||||
|
|
||||||
flags_ &= JSFRAME_FUNCTION |
|
|
||||||
JSFRAME_OVERFLOW_ARGS |
|
|
||||||
JSFRAME_HAS_PREVPC |
|
|
||||||
JSFRAME_UNDERFLOW_ARGS;
|
|
||||||
|
|
||||||
JS_ASSERT(exec.fun == callee().getFunctionPrivate());
|
|
||||||
scopeChain_ = callee().getParent();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
JSStackFrame::initCallFrameCallerHalf(JSContext *cx, uint32 flagsArg,
|
|
||||||
void *ncode)
|
|
||||||
{
|
|
||||||
JS_ASSERT((flagsArg & ~(JSFRAME_CONSTRUCTING |
|
|
||||||
JSFRAME_FUNCTION |
|
|
||||||
JSFRAME_OVERFLOW_ARGS |
|
|
||||||
JSFRAME_UNDERFLOW_ARGS)) == 0);
|
|
||||||
|
|
||||||
flags_ = JSFRAME_FUNCTION | flagsArg;
|
|
||||||
prev_ = cx->regs->fp;
|
|
||||||
ncode_ = ncode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The "early prologue" refers to the members that are stored for the benefit
|
|
||||||
* of slow paths before initializing the rest of the members.
|
|
||||||
*/
|
|
||||||
inline void
|
|
||||||
JSStackFrame::initCallFrameEarlyPrologue(JSFunction *fun, uint32 nactual)
|
|
||||||
{
|
|
||||||
exec.fun = fun;
|
|
||||||
if (flags_ & (JSFRAME_OVERFLOW_ARGS | JSFRAME_UNDERFLOW_ARGS))
|
|
||||||
args.nactual = nactual;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The "late prologue" refers to the members that are stored after having
|
|
||||||
* checked for stack overflow and formal/actual arg mismatch.
|
|
||||||
*/
|
|
||||||
inline void
|
|
||||||
JSStackFrame::initCallFrameLatePrologue()
|
|
||||||
{
|
|
||||||
SetValueRangeToUndefined(slots(), script()->nfixed);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
JSStackFrame::initEvalFrame(JSContext *cx, JSScript *script, JSStackFrame *prev, uint32 flagsArg)
|
|
||||||
{
|
|
||||||
JS_ASSERT(flagsArg & JSFRAME_EVAL);
|
|
||||||
JS_ASSERT((flagsArg & ~(JSFRAME_EVAL | JSFRAME_DEBUGGER)) == 0);
|
|
||||||
JS_ASSERT(prev->isScriptFrame());
|
|
||||||
|
|
||||||
/* Copy (callee, thisv). */
|
|
||||||
js::Value *dstvp = (js::Value *)this - 2;
|
|
||||||
js::Value *srcvp = prev->hasArgs()
|
|
||||||
? prev->formalArgs() - 2
|
|
||||||
: (js::Value *)prev - 2;
|
|
||||||
dstvp[0] = srcvp[0];
|
|
||||||
dstvp[1] = srcvp[1];
|
|
||||||
JS_ASSERT_IF(prev->isFunctionFrame(),
|
|
||||||
dstvp[0].toObject().isFunction());
|
|
||||||
|
|
||||||
/* Initialize stack frame members. */
|
|
||||||
flags_ = flagsArg | JSFRAME_HAS_PREVPC | JSFRAME_HAS_SCOPECHAIN |
|
|
||||||
(prev->flags_ & (JSFRAME_FUNCTION | JSFRAME_GLOBAL));
|
|
||||||
if (isFunctionFrame()) {
|
|
||||||
exec = prev->exec;
|
|
||||||
args.script = script;
|
|
||||||
} else {
|
|
||||||
exec.script = script;
|
|
||||||
}
|
|
||||||
|
|
||||||
scopeChain_ = &prev->scopeChain();
|
|
||||||
prev_ = prev;
|
|
||||||
prevpc_ = prev->pc(cx);
|
|
||||||
JS_ASSERT(!hasImacropc());
|
|
||||||
JS_ASSERT(!hasHookData());
|
|
||||||
setAnnotation(prev->annotation());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
JSStackFrame::initGlobalFrame(JSScript *script, JSObject &chain, uint32 flagsArg)
|
|
||||||
{
|
|
||||||
JS_ASSERT((flagsArg & ~(JSFRAME_EVAL | JSFRAME_DEBUGGER)) == 0);
|
|
||||||
|
|
||||||
/* Initialize (callee, thisv). */
|
|
||||||
js::Value *vp = (js::Value *)this - 2;
|
|
||||||
vp[0].setUndefined();
|
|
||||||
vp[1].setUndefined(); /* Set after frame pushed using thisObject */
|
|
||||||
|
|
||||||
/* Initialize stack frame members. */
|
|
||||||
flags_ = flagsArg | JSFRAME_GLOBAL | JSFRAME_HAS_PREVPC | JSFRAME_HAS_SCOPECHAIN;
|
|
||||||
exec.script = script;
|
|
||||||
args.script = (JSScript *)0xbad;
|
|
||||||
scopeChain_ = &chain;
|
|
||||||
prev_ = NULL;
|
|
||||||
JS_ASSERT(!hasImacropc());
|
|
||||||
JS_ASSERT(!hasHookData());
|
|
||||||
JS_ASSERT(annotation() == NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
JSStackFrame::initDummyFrame(JSContext *cx, JSObject &chain)
|
|
||||||
{
|
|
||||||
js::PodZero(this);
|
|
||||||
flags_ = JSFRAME_DUMMY | JSFRAME_HAS_PREVPC | JSFRAME_HAS_SCOPECHAIN;
|
|
||||||
initPrev(cx);
|
|
||||||
chain.isGlobal();
|
|
||||||
setScopeChainNoCallObj(chain);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
JSStackFrame::stealFrameAndSlots(js::Value *vp, JSStackFrame *otherfp,
|
|
||||||
js::Value *othervp, js::Value *othersp)
|
|
||||||
{
|
|
||||||
JS_ASSERT(vp == (js::Value *)this - (otherfp->formalArgsEnd() - othervp));
|
|
||||||
JS_ASSERT(othervp == otherfp->actualArgs() - 2);
|
|
||||||
JS_ASSERT(othersp >= otherfp->slots());
|
|
||||||
JS_ASSERT(othersp <= otherfp->base() + otherfp->numSlots());
|
|
||||||
|
|
||||||
PodCopy(vp, othervp, othersp - othervp);
|
|
||||||
JS_ASSERT(vp == this->actualArgs() - 2);
|
|
||||||
|
|
||||||
/* Catch bad-touching of non-canonical args (e.g., generator_trace). */
|
|
||||||
if (otherfp->hasOverflowArgs())
|
|
||||||
Debug_SetValueRangeToCrashOnTouch(othervp, othervp + 2 + otherfp->numFormalArgs());
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Repoint Call, Arguments, Block and With objects to the new live frame.
|
|
||||||
* Call and Arguments are done directly because we have pointers to them.
|
|
||||||
* Block and With objects are done indirectly through 'liveFrame'. See
|
|
||||||
* js_LiveFrameToFloating comment in jsiter.h.
|
|
||||||
*/
|
|
||||||
if (hasCallObj()) {
|
|
||||||
JSObject &obj = callObj();
|
|
||||||
obj.setPrivate(this);
|
|
||||||
otherfp->flags_ &= ~JSFRAME_HAS_CALL_OBJ;
|
|
||||||
if (js_IsNamedLambda(fun())) {
|
|
||||||
JSObject *env = obj.getParent();
|
|
||||||
JS_ASSERT(env->getClass() == &js_DeclEnvClass);
|
|
||||||
env->setPrivate(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (hasArgsObj()) {
|
|
||||||
JSObject &args = argsObj();
|
|
||||||
JS_ASSERT(args.isArguments());
|
|
||||||
if (args.isNormalArguments())
|
|
||||||
args.setPrivate(this);
|
|
||||||
else
|
|
||||||
JS_ASSERT(!args.getPrivate());
|
|
||||||
otherfp->flags_ &= ~JSFRAME_HAS_ARGS_OBJ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline js::Value &
|
|
||||||
JSStackFrame::canonicalActualArg(uintN i) const
|
|
||||||
{
|
|
||||||
if (i < numFormalArgs())
|
|
||||||
return formalArg(i);
|
|
||||||
JS_ASSERT(i < numActualArgs());
|
|
||||||
return actualArgs()[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Op>
|
|
||||||
inline bool
|
|
||||||
JSStackFrame::forEachCanonicalActualArg(Op op)
|
|
||||||
{
|
|
||||||
uintN nformal = fun()->nargs;
|
|
||||||
js::Value *formals = formalArgsEnd() - nformal;
|
|
||||||
uintN nactual = numActualArgs();
|
|
||||||
if (nactual <= nformal) {
|
|
||||||
uintN i = 0;
|
|
||||||
js::Value *actualsEnd = formals + nactual;
|
|
||||||
for (js::Value *p = formals; p != actualsEnd; ++p, ++i) {
|
|
||||||
if (!op(i, p))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
uintN i = 0;
|
|
||||||
js::Value *formalsEnd = formalArgsEnd();
|
|
||||||
for (js::Value *p = formals; p != formalsEnd; ++p, ++i) {
|
|
||||||
if (!op(i, p))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
js::Value *actuals = formalsEnd - (nactual + 2);
|
|
||||||
js::Value *actualsEnd = formals - 2;
|
|
||||||
for (js::Value *p = actuals; p != actualsEnd; ++p, ++i) {
|
|
||||||
if (!op(i, p))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Op>
|
|
||||||
inline bool
|
|
||||||
JSStackFrame::forEachFormalArg(Op op)
|
|
||||||
{
|
|
||||||
js::Value *formals = formalArgsEnd() - fun()->nargs;
|
|
||||||
js::Value *formalsEnd = formalArgsEnd();
|
|
||||||
uintN i = 0;
|
|
||||||
for (js::Value *p = formals; p != formalsEnd; ++p, ++i) {
|
|
||||||
if (!op(i, p))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace js {
|
|
||||||
|
|
||||||
struct CopyTo
|
|
||||||
{
|
|
||||||
Value *dst;
|
|
||||||
CopyTo(Value *dst) : dst(dst) {}
|
|
||||||
bool operator()(uintN, Value *src) {
|
|
||||||
*dst++ = *src;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_ALWAYS_INLINE void
|
|
||||||
JSStackFrame::clearMissingArgs()
|
|
||||||
{
|
|
||||||
if (flags_ & JSFRAME_UNDERFLOW_ARGS)
|
|
||||||
SetValueRangeToUndefined(formalArgs() + numActualArgs(), formalArgsEnd());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline JSObject &
|
|
||||||
JSStackFrame::varobj(js::StackSegment *seg) const
|
|
||||||
{
|
|
||||||
JS_ASSERT(seg->contains(this));
|
|
||||||
return isFunctionFrame() ? callObj() : seg->getInitialVarObj();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline JSObject &
|
|
||||||
JSStackFrame::varobj(JSContext *cx) const
|
|
||||||
{
|
|
||||||
JS_ASSERT(cx->activeSegment()->contains(this));
|
|
||||||
return isFunctionFrame() ? callObj() : cx->activeSegment()->getInitialVarObj();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uintN
|
|
||||||
JSStackFrame::numActualArgs() const
|
|
||||||
{
|
|
||||||
JS_ASSERT(hasArgs());
|
|
||||||
if (JS_UNLIKELY(flags_ & (JSFRAME_OVERFLOW_ARGS | JSFRAME_UNDERFLOW_ARGS)))
|
|
||||||
return hasArgsObj() ? argsObj().getArgsInitialLength() : args.nactual;
|
|
||||||
return numFormalArgs();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline js::Value *
|
|
||||||
JSStackFrame::actualArgs() const
|
|
||||||
{
|
|
||||||
JS_ASSERT(hasArgs());
|
|
||||||
js::Value *argv = formalArgs();
|
|
||||||
if (JS_UNLIKELY(flags_ & JSFRAME_OVERFLOW_ARGS)) {
|
|
||||||
uintN nactual = hasArgsObj() ? argsObj().getArgsInitialLength() : args.nactual;
|
|
||||||
return argv - (2 + nactual);
|
|
||||||
}
|
|
||||||
return argv;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline js::Value *
|
|
||||||
JSStackFrame::actualArgsEnd() const
|
|
||||||
{
|
|
||||||
JS_ASSERT(hasArgs());
|
|
||||||
if (JS_UNLIKELY(flags_ & JSFRAME_OVERFLOW_ARGS))
|
|
||||||
return formalArgs() - 2;
|
|
||||||
return formalArgs() + numActualArgs();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
JSStackFrame::setArgsObj(JSObject &obj)
|
|
||||||
{
|
|
||||||
JS_ASSERT_IF(hasArgsObj(), &obj == args.obj);
|
|
||||||
JS_ASSERT_IF(!hasArgsObj(), numActualArgs() == obj.getArgsInitialLength());
|
|
||||||
args.obj = &obj;
|
|
||||||
flags_ |= JSFRAME_HAS_ARGS_OBJ;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
JSStackFrame::setScopeChainNoCallObj(JSObject &obj)
|
|
||||||
{
|
|
||||||
#ifdef DEBUG
|
|
||||||
JS_ASSERT(&obj != NULL);
|
|
||||||
if (&obj != sInvalidScopeChain) {
|
|
||||||
if (hasCallObj()) {
|
|
||||||
JSObject *pobj = &obj;
|
|
||||||
while (pobj && pobj->getPrivate() != this)
|
|
||||||
pobj = pobj->getParent();
|
|
||||||
JS_ASSERT(pobj);
|
|
||||||
} else {
|
|
||||||
for (JSObject *pobj = &obj; pobj; pobj = pobj->getParent())
|
|
||||||
JS_ASSERT_IF(pobj->isCall(), pobj->getPrivate() != this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
scopeChain_ = &obj;
|
|
||||||
flags_ |= JSFRAME_HAS_SCOPECHAIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
JSStackFrame::setScopeChainWithOwnCallObj(JSObject &obj)
|
|
||||||
{
|
|
||||||
JS_ASSERT(&obj != NULL);
|
|
||||||
JS_ASSERT(!hasCallObj() && obj.isCall() && obj.getPrivate() == this);
|
|
||||||
scopeChain_ = &obj;
|
|
||||||
flags_ |= JSFRAME_HAS_SCOPECHAIN | JSFRAME_HAS_CALL_OBJ;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline JSObject &
|
|
||||||
JSStackFrame::callObj() const
|
|
||||||
{
|
|
||||||
JS_ASSERT_IF(isNonEvalFunctionFrame() || isStrictEvalFrame(), hasCallObj());
|
|
||||||
|
|
||||||
JSObject *pobj = &scopeChain();
|
|
||||||
while (JS_UNLIKELY(pobj->getClass() != &js_CallClass)) {
|
|
||||||
JS_ASSERT(js::IsCacheableNonGlobalScope(pobj) || pobj->isWith());
|
|
||||||
pobj = pobj->getParent();
|
|
||||||
}
|
|
||||||
return *pobj;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
JSStackFrame::markActivationObjectsAsPut()
|
|
||||||
{
|
|
||||||
if (flags_ & (JSFRAME_HAS_ARGS_OBJ | JSFRAME_HAS_CALL_OBJ)) {
|
|
||||||
if (hasArgsObj() && !argsObj().getPrivate()) {
|
|
||||||
args.nactual = args.obj->getArgsInitialLength();
|
|
||||||
flags_ &= ~JSFRAME_HAS_ARGS_OBJ;
|
|
||||||
}
|
|
||||||
if (hasCallObj() && !callObj().getPrivate()) {
|
|
||||||
/*
|
|
||||||
* For function frames, the call object may or may not have have an
|
|
||||||
* enclosing DeclEnv object, so we use the callee's parent, since
|
|
||||||
* it was the initial scope chain. For global (strict) eval frames,
|
|
||||||
* there is no calle, but the call object's parent is the initial
|
|
||||||
* scope chain.
|
|
||||||
*/
|
|
||||||
scopeChain_ = isFunctionFrame()
|
|
||||||
? callee().getParent()
|
|
||||||
: scopeChain_->getParent();
|
|
||||||
flags_ &= ~JSFRAME_HAS_CALL_OBJ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
|
@ -548,12 +130,11 @@ InvokeSessionGuard::invoke(JSContext *cx) const
|
||||||
#else
|
#else
|
||||||
if (!optimized())
|
if (!optimized())
|
||||||
#endif
|
#endif
|
||||||
return Invoke(cx, args_, 0);
|
return Invoke(cx, args_);
|
||||||
|
|
||||||
/* Clear any garbage left from the last Invoke. */
|
/* Clear any garbage left from the last Invoke. */
|
||||||
JSStackFrame *fp = frame_.fp();
|
StackFrame *fp = frame_.fp();
|
||||||
fp->clearMissingArgs();
|
fp->clearMissingArgs();
|
||||||
PutActivationObjects(cx, frame_.fp());
|
|
||||||
fp->resetInvokeCallFrame();
|
fp->resetInvokeCallFrame();
|
||||||
SetValueRangeToUndefined(fp->slots(), script_->nfixed);
|
SetValueRangeToUndefined(fp->slots(), script_->nfixed);
|
||||||
|
|
||||||
|
@ -563,9 +144,9 @@ InvokeSessionGuard::invoke(JSContext *cx) const
|
||||||
Probes::enterJSFun(cx, fp->fun(), script_);
|
Probes::enterJSFun(cx, fp->fun(), script_);
|
||||||
#ifdef JS_METHODJIT
|
#ifdef JS_METHODJIT
|
||||||
ok = mjit::EnterMethodJIT(cx, fp, code, stackLimit_);
|
ok = mjit::EnterMethodJIT(cx, fp, code, stackLimit_);
|
||||||
cx->regs->pc = stop_;
|
cx->regs().pc = stop_;
|
||||||
#else
|
#else
|
||||||
cx->regs->pc = script_->code;
|
cx->regs().pc = script_->code;
|
||||||
ok = Interpret(cx, cx->fp());
|
ok = Interpret(cx, cx->fp());
|
||||||
#endif
|
#endif
|
||||||
Probes::exitJSFun(cx, fp->fun(), script_);
|
Probes::exitJSFun(cx, fp->fun(), script_);
|
||||||
|
@ -606,7 +187,7 @@ class PrimitiveBehavior<double> {
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool
|
inline bool
|
||||||
GetPrimitiveThis(JSContext *cx, Value *vp, T *v)
|
GetPrimitiveThis(JSContext *cx, Value *vp, T *v)
|
||||||
{
|
{
|
||||||
typedef detail::PrimitiveBehavior<T> Behavior;
|
typedef detail::PrimitiveBehavior<T> Behavior;
|
||||||
|
@ -704,7 +285,7 @@ ComputeImplicitThis(JSContext *cx, JSObject *obj, const Value &funval, Value *vp
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
ComputeThis(JSContext *cx, JSStackFrame *fp)
|
ComputeThis(JSContext *cx, StackFrame *fp)
|
||||||
{
|
{
|
||||||
Value &thisv = fp->thisValue();
|
Value &thisv = fp->thisValue();
|
||||||
if (thisv.isObject())
|
if (thisv.isObject())
|
||||||
|
@ -761,7 +342,7 @@ ValuePropertyBearer(JSContext *cx, const Value &v, int spindex)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
ScriptPrologue(JSContext *cx, JSStackFrame *fp)
|
ScriptPrologue(JSContext *cx, StackFrame *fp)
|
||||||
{
|
{
|
||||||
JS_ASSERT_IF(fp->isNonEvalFunctionFrame() && fp->fun()->isHeavyweight(), fp->hasCallObj());
|
JS_ASSERT_IF(fp->isNonEvalFunctionFrame() && fp->fun()->isHeavyweight(), fp->hasCallObj());
|
||||||
|
|
||||||
|
@ -778,7 +359,7 @@ ScriptPrologue(JSContext *cx, JSStackFrame *fp)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
ScriptEpilogue(JSContext *cx, JSStackFrame *fp, bool ok)
|
ScriptEpilogue(JSContext *cx, StackFrame *fp, bool ok)
|
||||||
{
|
{
|
||||||
if (cx->compartment->debugMode)
|
if (cx->compartment->debugMode)
|
||||||
ok = ScriptDebugEpilogue(cx, fp, ok);
|
ok = ScriptDebugEpilogue(cx, fp, ok);
|
||||||
|
@ -797,7 +378,7 @@ ScriptEpilogue(JSContext *cx, JSStackFrame *fp, bool ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
ScriptPrologueOrGeneratorResume(JSContext *cx, JSStackFrame *fp)
|
ScriptPrologueOrGeneratorResume(JSContext *cx, StackFrame *fp)
|
||||||
{
|
{
|
||||||
if (!fp->isGeneratorFrame())
|
if (!fp->isGeneratorFrame())
|
||||||
return ScriptPrologue(cx, fp);
|
return ScriptPrologue(cx, fp);
|
||||||
|
@ -807,7 +388,7 @@ ScriptPrologueOrGeneratorResume(JSContext *cx, JSStackFrame *fp)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
ScriptEpilogueOrGeneratorYield(JSContext *cx, JSStackFrame *fp, bool ok)
|
ScriptEpilogueOrGeneratorYield(JSContext *cx, StackFrame *fp, bool ok)
|
||||||
{
|
{
|
||||||
if (!fp->isYielding())
|
if (!fp->isYielding())
|
||||||
return ScriptEpilogue(cx, fp, ok);
|
return ScriptEpilogue(cx, fp, ok);
|
||||||
|
@ -816,6 +397,6 @@ ScriptEpilogueOrGeneratorYield(JSContext *cx, JSStackFrame *fp, bool ok)
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} /* namespace js */
|
||||||
|
|
||||||
#endif /* jsinterpinlines_h__ */
|
#endif /* jsinterpinlines_h__ */
|
||||||
|
|
|
@ -65,6 +65,7 @@
|
||||||
#include "jsobj.h"
|
#include "jsobj.h"
|
||||||
#include "jsopcode.h"
|
#include "jsopcode.h"
|
||||||
#include "jsproxy.h"
|
#include "jsproxy.h"
|
||||||
|
#include "jsscan.h"
|
||||||
#include "jsscope.h"
|
#include "jsscope.h"
|
||||||
#include "jsscript.h"
|
#include "jsscript.h"
|
||||||
#include "jsstaticcheck.h"
|
#include "jsstaticcheck.h"
|
||||||
|
@ -74,11 +75,11 @@
|
||||||
#include "jsxml.h"
|
#include "jsxml.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "jscntxtinlines.h"
|
|
||||||
#include "jsinterpinlines.h"
|
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
#include "jsstrinlines.h"
|
#include "jsstrinlines.h"
|
||||||
|
|
||||||
|
#include "vm/Stack-inl.h"
|
||||||
|
|
||||||
using namespace js;
|
using namespace js;
|
||||||
using namespace js::gc;
|
using namespace js::gc;
|
||||||
|
|
||||||
|
@ -1091,7 +1092,7 @@ generator_trace(JSTracer *trc, JSObject *obj)
|
||||||
if (gen->state == JSGEN_RUNNING || gen->state == JSGEN_CLOSING)
|
if (gen->state == JSGEN_RUNNING || gen->state == JSGEN_CLOSING)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
JSStackFrame *fp = gen->floatingFrame();
|
StackFrame *fp = gen->floatingFrame();
|
||||||
JS_ASSERT(gen->liveFrame() == fp);
|
JS_ASSERT(gen->liveFrame() == fp);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1134,17 +1135,10 @@ Class js_GeneratorClass = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void
|
|
||||||
RebaseRegsFromTo(JSFrameRegs *regs, JSStackFrame *from, JSStackFrame *to)
|
|
||||||
{
|
|
||||||
regs->fp = to;
|
|
||||||
regs->sp = to->slots() + (regs->sp - from->slots());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called from the JSOP_GENERATOR case in the interpreter, with fp referring
|
* Called from the JSOP_GENERATOR case in the interpreter, with fp referring
|
||||||
* to the frame by which the generator function was activated. Create a new
|
* to the frame by which the generator function was activated. Create a new
|
||||||
* JSGenerator object, which contains its own JSStackFrame that we populate
|
* JSGenerator object, which contains its own StackFrame that we populate
|
||||||
* from *fp. We know that upon return, the JSOP_GENERATOR opcode will return
|
* from *fp. We know that upon return, the JSOP_GENERATOR opcode will return
|
||||||
* from the activation in fp, so we can steal away fp->callobj and fp->argsobj
|
* from the activation in fp, so we can steal away fp->callobj and fp->argsobj
|
||||||
* if they are non-null.
|
* if they are non-null.
|
||||||
|
@ -1156,8 +1150,8 @@ js_NewGenerator(JSContext *cx)
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
JSStackFrame *stackfp = cx->fp();
|
StackFrame *stackfp = cx->fp();
|
||||||
JS_ASSERT(stackfp->base() == cx->regs->sp);
|
JS_ASSERT(stackfp->base() == cx->regs().sp);
|
||||||
JS_ASSERT(stackfp->actualArgs() <= stackfp->formalArgs());
|
JS_ASSERT(stackfp->actualArgs() <= stackfp->formalArgs());
|
||||||
|
|
||||||
/* Load and compute stack slot counts. */
|
/* Load and compute stack slot counts. */
|
||||||
|
@ -1177,7 +1171,7 @@ js_NewGenerator(JSContext *cx)
|
||||||
|
|
||||||
/* Cut up floatingStack space. */
|
/* Cut up floatingStack space. */
|
||||||
Value *genvp = gen->floatingStack;
|
Value *genvp = gen->floatingStack;
|
||||||
JSStackFrame *genfp = reinterpret_cast<JSStackFrame *>(genvp + vplen);
|
StackFrame *genfp = reinterpret_cast<StackFrame *>(genvp + vplen);
|
||||||
|
|
||||||
/* Initialize JSGenerator. */
|
/* Initialize JSGenerator. */
|
||||||
gen->obj = obj;
|
gen->obj = obj;
|
||||||
|
@ -1186,11 +1180,11 @@ js_NewGenerator(JSContext *cx)
|
||||||
gen->floating = genfp;
|
gen->floating = genfp;
|
||||||
|
|
||||||
/* Initialize regs stored in generator. */
|
/* Initialize regs stored in generator. */
|
||||||
gen->regs = *cx->regs;
|
gen->regs = cx->regs();
|
||||||
RebaseRegsFromTo(&gen->regs, stackfp, genfp);
|
gen->regs.rebaseFromTo(stackfp, genfp);
|
||||||
|
|
||||||
/* Copy frame off the stack. */
|
/* Copy frame off the stack. */
|
||||||
genfp->stealFrameAndSlots(genvp, stackfp, stackvp, cx->regs->sp);
|
genfp->stealFrameAndSlots(genvp, stackfp, stackvp, cx->regs().sp);
|
||||||
genfp->initFloatingGenerator();
|
genfp->initFloatingGenerator();
|
||||||
|
|
||||||
obj->setPrivate(gen);
|
obj->setPrivate(gen);
|
||||||
|
@ -1198,7 +1192,7 @@ js_NewGenerator(JSContext *cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
JSGenerator *
|
JSGenerator *
|
||||||
js_FloatingFrameToGenerator(JSStackFrame *fp)
|
js_FloatingFrameToGenerator(StackFrame *fp)
|
||||||
{
|
{
|
||||||
JS_ASSERT(fp->isGeneratorFrame() && fp->isFloatingGenerator());
|
JS_ASSERT(fp->isGeneratorFrame() && fp->isFloatingGenerator());
|
||||||
char *floatingStackp = (char *)(fp->actualArgs() - 2);
|
char *floatingStackp = (char *)(fp->actualArgs() - 2);
|
||||||
|
@ -1258,11 +1252,11 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSStackFrame *genfp = gen->floatingFrame();
|
StackFrame *genfp = gen->floatingFrame();
|
||||||
Value *genvp = gen->floatingStack;
|
Value *genvp = gen->floatingStack;
|
||||||
uintN vplen = genfp->formalArgsEnd() - genvp;
|
uintN vplen = genfp->formalArgsEnd() - genvp;
|
||||||
|
|
||||||
JSStackFrame *stackfp;
|
StackFrame *stackfp;
|
||||||
Value *stackvp;
|
Value *stackvp;
|
||||||
JSBool ok;
|
JSBool ok;
|
||||||
{
|
{
|
||||||
|
@ -1271,7 +1265,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
|
||||||
* the code before pushExecuteFrame must not reenter the interpreter.
|
* the code before pushExecuteFrame must not reenter the interpreter.
|
||||||
*/
|
*/
|
||||||
GeneratorFrameGuard frame;
|
GeneratorFrameGuard frame;
|
||||||
if (!cx->stack().getGeneratorFrame(cx, vplen, genfp->numSlots(), &frame)) {
|
if (!cx->stack.getGeneratorFrame(cx, vplen, genfp->numSlots(), &frame)) {
|
||||||
gen->state = JSGEN_CLOSED;
|
gen->state = JSGEN_CLOSED;
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
@ -1282,11 +1276,11 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
|
||||||
stackfp->stealFrameAndSlots(stackvp, genfp, genvp, gen->regs.sp);
|
stackfp->stealFrameAndSlots(stackvp, genfp, genvp, gen->regs.sp);
|
||||||
stackfp->resetGeneratorPrev(cx);
|
stackfp->resetGeneratorPrev(cx);
|
||||||
stackfp->unsetFloatingGenerator();
|
stackfp->unsetFloatingGenerator();
|
||||||
RebaseRegsFromTo(&gen->regs, genfp, stackfp);
|
gen->regs.rebaseFromTo(genfp, stackfp);
|
||||||
MUST_FLOW_THROUGH("restore");
|
MUST_FLOW_THROUGH("restore");
|
||||||
|
|
||||||
/* Officially push frame. frame's destructor pops. */
|
/* Officially push frame. frame's destructor pops. */
|
||||||
cx->stack().pushGeneratorFrame(cx, &gen->regs, &frame);
|
cx->stack.pushGeneratorFrame(gen->regs, &frame);
|
||||||
|
|
||||||
cx->enterGenerator(gen); /* OOM check above. */
|
cx->enterGenerator(gen); /* OOM check above. */
|
||||||
JSObject *enumerators = cx->enumerators;
|
JSObject *enumerators = cx->enumerators;
|
||||||
|
@ -1306,7 +1300,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
|
||||||
genfp->setFloatingGenerator();
|
genfp->setFloatingGenerator();
|
||||||
}
|
}
|
||||||
MUST_FLOW_LABEL(restore)
|
MUST_FLOW_LABEL(restore)
|
||||||
RebaseRegsFromTo(&gen->regs, stackfp, genfp);
|
gen->regs.rebaseFromTo(stackfp, genfp);
|
||||||
|
|
||||||
if (gen->floatingFrame()->isYielding()) {
|
if (gen->floatingFrame()->isYielding()) {
|
||||||
/* Yield cannot fail, throw or be called on closing. */
|
/* Yield cannot fail, throw or be called on closing. */
|
||||||
|
|
|
@ -181,19 +181,19 @@ typedef enum JSGeneratorState {
|
||||||
struct JSGenerator {
|
struct JSGenerator {
|
||||||
JSObject *obj;
|
JSObject *obj;
|
||||||
JSGeneratorState state;
|
JSGeneratorState state;
|
||||||
JSFrameRegs regs;
|
js::FrameRegs regs;
|
||||||
JSObject *enumerators;
|
JSObject *enumerators;
|
||||||
JSStackFrame *floating;
|
js::StackFrame *floating;
|
||||||
js::Value floatingStack[1];
|
js::Value floatingStack[1];
|
||||||
|
|
||||||
JSStackFrame *floatingFrame() {
|
js::StackFrame *floatingFrame() {
|
||||||
return floating;
|
return floating;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSStackFrame *liveFrame() {
|
js::StackFrame *liveFrame() {
|
||||||
JS_ASSERT((state == JSGEN_RUNNING || state == JSGEN_CLOSING) ==
|
JS_ASSERT((state == JSGEN_RUNNING || state == JSGEN_CLOSING) ==
|
||||||
(regs.fp != floatingFrame()));
|
(regs.fp() != floatingFrame()));
|
||||||
return regs.fp;
|
return regs.fp();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -211,10 +211,10 @@ js_NewGenerator(JSContext *cx);
|
||||||
* Block and With objects must "normalize" to and from the floating/live frames
|
* Block and With objects must "normalize" to and from the floating/live frames
|
||||||
* in the case of generators using the following functions.
|
* in the case of generators using the following functions.
|
||||||
*/
|
*/
|
||||||
inline JSStackFrame *
|
inline js::StackFrame *
|
||||||
js_FloatingFrameIfGenerator(JSContext *cx, JSStackFrame *fp)
|
js_FloatingFrameIfGenerator(JSContext *cx, js::StackFrame *fp)
|
||||||
{
|
{
|
||||||
JS_ASSERT(cx->stack().contains(fp));
|
JS_ASSERT(cx->stack.contains(fp));
|
||||||
if (JS_UNLIKELY(fp->isGeneratorFrame()))
|
if (JS_UNLIKELY(fp->isGeneratorFrame()))
|
||||||
return cx->generatorFor(fp)->floatingFrame();
|
return cx->generatorFor(fp)->floatingFrame();
|
||||||
return fp;
|
return fp;
|
||||||
|
@ -222,10 +222,10 @@ js_FloatingFrameIfGenerator(JSContext *cx, JSStackFrame *fp)
|
||||||
|
|
||||||
/* Given a floating frame, given the JSGenerator containing it. */
|
/* Given a floating frame, given the JSGenerator containing it. */
|
||||||
extern JSGenerator *
|
extern JSGenerator *
|
||||||
js_FloatingFrameToGenerator(JSStackFrame *fp);
|
js_FloatingFrameToGenerator(js::StackFrame *fp);
|
||||||
|
|
||||||
inline JSStackFrame *
|
inline js::StackFrame *
|
||||||
js_LiveFrameIfGenerator(JSStackFrame *fp)
|
js_LiveFrameIfGenerator(js::StackFrame *fp)
|
||||||
{
|
{
|
||||||
return fp->isGeneratorFrame() ? js_FloatingFrameToGenerator(fp)->liveFrame() : fp;
|
return fp->isGeneratorFrame() ? js_FloatingFrameToGenerator(fp)->liveFrame() : fp;
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@ typedef struct JSThinLock {
|
||||||
JSFatLock *fat;
|
JSFatLock *fat;
|
||||||
} JSThinLock;
|
} JSThinLock;
|
||||||
|
|
||||||
#define CX_THINLOCK_ID(cx) ((jsword)(cx)->thread)
|
#define CX_THINLOCK_ID(cx) ((jsword)(cx)->thread())
|
||||||
#define CURRENT_THREAD_IS_ME(me) (((JSThread *)me)->id == js_CurrentThreadId())
|
#define CURRENT_THREAD_IS_ME(me) (((JSThread *)me)->id == js_CurrentThreadId())
|
||||||
|
|
||||||
typedef PRLock JSLock;
|
typedef PRLock JSLock;
|
||||||
|
|
|
@ -881,5 +881,8 @@ js_InitMathClass(JSContext *cx, JSObject *obj)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (!JS_DefineConstDoubles(cx, Math, math_constants))
|
if (!JS_DefineConstDoubles(cx, Math, math_constants))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
MarkStandardClassInitializedNoProto(obj, &js_MathClass);
|
||||||
|
|
||||||
return Math;
|
return Math;
|
||||||
}
|
}
|
||||||
|
|
|
@ -700,19 +700,18 @@ num_toString(JSContext *cx, uintN argc, Value *vp)
|
||||||
if (!GetPrimitiveThis(cx, vp, &d))
|
if (!GetPrimitiveThis(cx, vp, &d))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
int32_t base = 10;
|
int32 base = 10;
|
||||||
if (argc != 0 && !vp[2].isUndefined()) {
|
if (argc != 0 && !vp[2].isUndefined()) {
|
||||||
if (!ValueToECMAInt32(cx, vp[2], &base))
|
jsdouble d2;
|
||||||
return JS_FALSE;
|
if (!ToInteger(cx, vp[2], &d2))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (base < 2 || base > 36) {
|
if (d2 < 2 || d2 > 36) {
|
||||||
ToCStringBuf cbuf;
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_RADIX);
|
||||||
char *numStr = IntToCString(&cbuf, base); /* convert the base itself to a string */
|
return false;
|
||||||
JS_ASSERT(numStr);
|
|
||||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_RADIX,
|
|
||||||
numStr);
|
|
||||||
return JS_FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
base = int32(d2);
|
||||||
}
|
}
|
||||||
JSString *str = js_NumberToStringWithBase(cx, d, base);
|
JSString *str = js_NumberToStringWithBase(cx, d, base);
|
||||||
if (!str) {
|
if (!str) {
|
||||||
|
@ -874,9 +873,8 @@ num_to(JSContext *cx, JSDToStrMode zeroArgMode, JSDToStrMode oneArgMode,
|
||||||
precision = 0.0;
|
precision = 0.0;
|
||||||
oneArgMode = zeroArgMode;
|
oneArgMode = zeroArgMode;
|
||||||
} else {
|
} else {
|
||||||
if (!ValueToNumber(cx, vp[2], &precision))
|
if (!ToInteger(cx, vp[2], &precision))
|
||||||
return JS_FALSE;
|
return false;
|
||||||
precision = js_DoubleToInteger(precision);
|
|
||||||
if (precision < precisionMin || precision > precisionMax) {
|
if (precision < precisionMin || precision > precisionMax) {
|
||||||
ToCStringBuf cbuf;
|
ToCStringBuf cbuf;
|
||||||
numStr = IntToCString(&cbuf, jsint(precision));
|
numStr = IntToCString(&cbuf, jsint(precision));
|
||||||
|
|
|
@ -696,6 +696,26 @@ StringToNumberType(JSContext *cx, JSString *str, T *result)
|
||||||
*result = NumberTraits<T>::toSelfType(d);
|
*result = NumberTraits<T>::toSelfType(d);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ES5 9.4 ToInteger. */
|
||||||
|
static inline bool
|
||||||
|
ToInteger(JSContext *cx, const js::Value &v, jsdouble *dp)
|
||||||
|
{
|
||||||
|
if (v.isInt32()) {
|
||||||
|
*dp = v.toInt32();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (v.isDouble()) {
|
||||||
|
*dp = v.toDouble();
|
||||||
|
} else {
|
||||||
|
extern bool ValueToNumberSlow(JSContext *cx, js::Value v, double *dp);
|
||||||
|
if (!ValueToNumberSlow(cx, v, dp))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*dp = js_DoubleToInteger(*dp);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} /* namespace js */
|
||||||
|
|
||||||
#endif /* jsnum_h___ */
|
#endif /* jsnum_h___ */
|
||||||
|
|
125
js/src/jsobj.cpp
125
js/src/jsobj.cpp
|
@ -86,6 +86,8 @@
|
||||||
#include "jsscriptinlines.h"
|
#include "jsscriptinlines.h"
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
|
|
||||||
|
#include "vm/StringObject-inl.h"
|
||||||
|
|
||||||
#if JS_HAS_GENERATORS
|
#if JS_HAS_GENERATORS
|
||||||
#include "jsiter.h"
|
#include "jsiter.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -959,7 +961,7 @@ EvalCacheHash(JSContext *cx, JSLinearString *str)
|
||||||
}
|
}
|
||||||
|
|
||||||
static JS_ALWAYS_INLINE JSScript *
|
static JS_ALWAYS_INLINE JSScript *
|
||||||
EvalCacheLookup(JSContext *cx, JSLinearString *str, JSStackFrame *caller, uintN staticLevel,
|
EvalCacheLookup(JSContext *cx, JSLinearString *str, StackFrame *caller, uintN staticLevel,
|
||||||
JSPrincipals *principals, JSObject &scopeobj, JSScript **bucket)
|
JSPrincipals *principals, JSObject &scopeobj, JSScript **bucket)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -1082,7 +1084,7 @@ class EvalScriptGuard
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void lookupInEvalCache(JSStackFrame *caller, uintN staticLevel,
|
void lookupInEvalCache(StackFrame *caller, uintN staticLevel,
|
||||||
JSPrincipals *principals, JSObject &scopeobj) {
|
JSPrincipals *principals, JSObject &scopeobj) {
|
||||||
if (JSScript *found = EvalCacheLookup(cx_, str_, caller, staticLevel,
|
if (JSScript *found = EvalCacheLookup(cx_, str_, caller, staticLevel,
|
||||||
principals, scopeobj, bucket_)) {
|
principals, scopeobj, bucket_)) {
|
||||||
|
@ -1120,7 +1122,7 @@ class EvalScriptGuard
|
||||||
enum EvalType { DIRECT_EVAL, INDIRECT_EVAL };
|
enum EvalType { DIRECT_EVAL, INDIRECT_EVAL };
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
EvalKernel(JSContext *cx, const CallArgs &call, EvalType evalType, JSStackFrame *caller,
|
EvalKernel(JSContext *cx, const CallArgs &call, EvalType evalType, StackFrame *caller,
|
||||||
JSObject &scopeobj)
|
JSObject &scopeobj)
|
||||||
{
|
{
|
||||||
JS_ASSERT((evalType == INDIRECT_EVAL) == (caller == NULL));
|
JS_ASSERT((evalType == INDIRECT_EVAL) == (caller == NULL));
|
||||||
|
@ -1235,7 +1237,7 @@ EvalKernel(JSContext *cx, const CallArgs &call, EvalType evalType, JSStackFrame
|
||||||
esg.setNewScript(compiled);
|
esg.setNewScript(compiled);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Execute(cx, scopeobj, esg.script(), caller, JSFRAME_EVAL, &call.rval());
|
return Execute(cx, scopeobj, esg.script(), caller, StackFrame::EVAL, &call.rval());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1247,7 +1249,7 @@ static inline bool
|
||||||
WarnOnTooManyArgs(JSContext *cx, const CallArgs &call)
|
WarnOnTooManyArgs(JSContext *cx, const CallArgs &call)
|
||||||
{
|
{
|
||||||
if (call.argc() > 1) {
|
if (call.argc() > 1) {
|
||||||
if (JSStackFrame *caller = js_GetScriptedCaller(cx, NULL)) {
|
if (StackFrame *caller = js_GetScriptedCaller(cx, NULL)) {
|
||||||
if (!caller->script()->warnedAboutTwoArgumentEval) {
|
if (!caller->script()->warnedAboutTwoArgumentEval) {
|
||||||
static const char TWO_ARGUMENT_WARNING[] =
|
static const char TWO_ARGUMENT_WARNING[] =
|
||||||
"Support for eval(code, scopeObject) has been removed. "
|
"Support for eval(code, scopeObject) has been removed. "
|
||||||
|
@ -1286,10 +1288,10 @@ bool
|
||||||
DirectEval(JSContext *cx, const CallArgs &call)
|
DirectEval(JSContext *cx, const CallArgs &call)
|
||||||
{
|
{
|
||||||
/* Direct eval can assume it was called from an interpreted frame. */
|
/* Direct eval can assume it was called from an interpreted frame. */
|
||||||
JSStackFrame *caller = cx->fp();
|
StackFrame *caller = cx->fp();
|
||||||
JS_ASSERT(caller->isScriptFrame());
|
JS_ASSERT(caller->isScriptFrame());
|
||||||
JS_ASSERT(IsBuiltinEvalForScope(&caller->scopeChain(), call.calleev()));
|
JS_ASSERT(IsBuiltinEvalForScope(&caller->scopeChain(), call.calleev()));
|
||||||
JS_ASSERT(*cx->regs->pc == JSOP_EVAL);
|
JS_ASSERT(*cx->regs().pc == JSOP_EVAL);
|
||||||
|
|
||||||
AutoFunctionCallProbe callProbe(cx, call.callee().getFunctionPrivate(), caller->script());
|
AutoFunctionCallProbe callProbe(cx, call.callee().getFunctionPrivate(), caller->script());
|
||||||
|
|
||||||
|
@ -1339,8 +1341,8 @@ PrincipalsForCompiledCode(const CallArgs &call, JSContext *cx)
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (calleePrincipals) {
|
if (calleePrincipals) {
|
||||||
if (JSStackFrame *caller = js_GetScriptedCaller(cx, NULL)) {
|
if (StackFrame *caller = js_GetScriptedCaller(cx, NULL)) {
|
||||||
if (JSPrincipals *callerPrincipals = caller->principals(cx)) {
|
if (JSPrincipals *callerPrincipals = caller->scopeChain().principals(cx)) {
|
||||||
JS_ASSERT(callerPrincipals->subsume(callerPrincipals, calleePrincipals));
|
JS_ASSERT(callerPrincipals->subsume(callerPrincipals, calleePrincipals));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1360,8 +1362,8 @@ obj_watch_handler(JSContext *cx, JSObject *obj, jsid id, jsval old,
|
||||||
{
|
{
|
||||||
JSObject *callable = (JSObject *) closure;
|
JSObject *callable = (JSObject *) closure;
|
||||||
if (JSPrincipals *watcher = callable->principals(cx)) {
|
if (JSPrincipals *watcher = callable->principals(cx)) {
|
||||||
if (JSStackFrame *caller = js_GetScriptedCaller(cx, NULL)) {
|
if (StackFrame *caller = js_GetScriptedCaller(cx, NULL)) {
|
||||||
if (JSPrincipals *subject = caller->principals(cx)) {
|
if (JSPrincipals *subject = caller->scopeChain().principals(cx)) {
|
||||||
if (!watcher->subsume(watcher, subject)) {
|
if (!watcher->subsume(watcher, subject)) {
|
||||||
/* Silently don't call the watch handler. */
|
/* Silently don't call the watch handler. */
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
|
@ -2930,25 +2932,6 @@ js_CreateThisForFunction(JSContext *cx, JSObject *callee)
|
||||||
|
|
||||||
#ifdef JS_TRACER
|
#ifdef JS_TRACER
|
||||||
|
|
||||||
static JS_ALWAYS_INLINE JSObject*
|
|
||||||
NewObjectWithClassProto(JSContext *cx, Class *clasp, JSObject *proto,
|
|
||||||
/*gc::FinalizeKind*/ unsigned _kind)
|
|
||||||
{
|
|
||||||
JS_ASSERT(clasp->isNative());
|
|
||||||
gc::FinalizeKind kind = gc::FinalizeKind(_kind);
|
|
||||||
|
|
||||||
if (CanBeFinalizedInBackground(kind, clasp))
|
|
||||||
kind = (gc::FinalizeKind)(kind + 1);
|
|
||||||
|
|
||||||
JSObject* obj = js_NewGCObject(cx, kind);
|
|
||||||
if (!obj)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (!obj->initSharingEmptyShape(cx, clasp, proto, proto->getParent(), NULL, kind))
|
|
||||||
return NULL;
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObject* FASTCALL
|
JSObject* FASTCALL
|
||||||
js_Object_tn(JSContext* cx, JSObject* proto)
|
js_Object_tn(JSContext* cx, JSObject* proto)
|
||||||
{
|
{
|
||||||
|
@ -2978,11 +2961,8 @@ JSObject* FASTCALL
|
||||||
js_String_tn(JSContext* cx, JSObject* proto, JSString* str)
|
js_String_tn(JSContext* cx, JSObject* proto, JSString* str)
|
||||||
{
|
{
|
||||||
JS_ASSERT(JS_ON_TRACE(cx));
|
JS_ASSERT(JS_ON_TRACE(cx));
|
||||||
JS_ASSERT(FINALIZE_OBJECT2 == gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(&js_StringClass)));
|
JS_ASSERT(proto);
|
||||||
JSObject *obj = NewObjectWithClassProto(cx, &js_StringClass, proto, FINALIZE_OBJECT2);
|
return StringObject::createWithProto(cx, str, *proto);
|
||||||
if (!obj || !obj->initString(cx, str))
|
|
||||||
return NULL;
|
|
||||||
return obj;
|
|
||||||
}
|
}
|
||||||
JS_DEFINE_CALLINFO_3(extern, OBJECT, js_String_tn, CONTEXT, CALLEE_PROTOTYPE, STRING, 0,
|
JS_DEFINE_CALLINFO_3(extern, OBJECT, js_String_tn, CONTEXT, CALLEE_PROTOTYPE, STRING, 0,
|
||||||
nanojit::ACCSET_STORE_ANY)
|
nanojit::ACCSET_STORE_ANY)
|
||||||
|
@ -3110,8 +3090,8 @@ js_InferFlags(JSContext *cx, uintN defaultFlags)
|
||||||
uint32 format;
|
uint32 format;
|
||||||
uintN flags = 0;
|
uintN flags = 0;
|
||||||
|
|
||||||
JSStackFrame *const fp = js_GetTopStackFrame(cx);
|
StackFrame *const fp = js_GetTopStackFrame(cx);
|
||||||
if (!fp || !(pc = cx->regs->pc))
|
if (!fp || !(pc = cx->regs().pc))
|
||||||
return defaultFlags;
|
return defaultFlags;
|
||||||
cs = &js_CodeSpec[js_GetOpcode(cx, fp->script(), pc)];
|
cs = &js_CodeSpec[js_GetOpcode(cx, fp->script(), pc)];
|
||||||
format = cs->format;
|
format = cs->format;
|
||||||
|
@ -3239,7 +3219,7 @@ js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth)
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
JSStackFrame *priv = js_FloatingFrameIfGenerator(cx, cx->fp());
|
StackFrame *priv = js_FloatingFrameIfGenerator(cx, cx->fp());
|
||||||
|
|
||||||
EmptyShape *emptyWithShape = EmptyShape::getEmptyWithShape(cx);
|
EmptyShape *emptyWithShape = EmptyShape::getEmptyWithShape(cx);
|
||||||
if (!emptyWithShape)
|
if (!emptyWithShape)
|
||||||
|
@ -3281,7 +3261,7 @@ js_NewBlockObject(JSContext *cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject *
|
JSObject *
|
||||||
js_CloneBlockObject(JSContext *cx, JSObject *proto, JSStackFrame *fp)
|
js_CloneBlockObject(JSContext *cx, JSObject *proto, StackFrame *fp)
|
||||||
{
|
{
|
||||||
JS_ASSERT(proto->isStaticBlock());
|
JS_ASSERT(proto->isStaticBlock());
|
||||||
|
|
||||||
|
@ -3292,7 +3272,7 @@ js_CloneBlockObject(JSContext *cx, JSObject *proto, JSStackFrame *fp)
|
||||||
if (!clone)
|
if (!clone)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
JSStackFrame *priv = js_FloatingFrameIfGenerator(cx, fp);
|
StackFrame *priv = js_FloatingFrameIfGenerator(cx, fp);
|
||||||
|
|
||||||
/* The caller sets parent on its own. */
|
/* The caller sets parent on its own. */
|
||||||
clone->initClonedBlock(cx, proto, priv);
|
clone->initClonedBlock(cx, proto, priv);
|
||||||
|
@ -3309,7 +3289,7 @@ js_CloneBlockObject(JSContext *cx, JSObject *proto, JSStackFrame *fp)
|
||||||
JS_REQUIRES_STACK JSBool
|
JS_REQUIRES_STACK JSBool
|
||||||
js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
|
js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
|
||||||
{
|
{
|
||||||
JSStackFrame *const fp = cx->fp();
|
StackFrame *const fp = cx->fp();
|
||||||
JSObject *obj = &fp->scopeChain();
|
JSObject *obj = &fp->scopeChain();
|
||||||
JS_ASSERT(obj->isClonedBlock());
|
JS_ASSERT(obj->isClonedBlock());
|
||||||
JS_ASSERT(obj->getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp()));
|
JS_ASSERT(obj->getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp()));
|
||||||
|
@ -3320,8 +3300,8 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
|
||||||
|
|
||||||
/* The block and its locals must be on the current stack for GC safety. */
|
/* The block and its locals must be on the current stack for GC safety. */
|
||||||
uintN depth = OBJ_BLOCK_DEPTH(cx, obj);
|
uintN depth = OBJ_BLOCK_DEPTH(cx, obj);
|
||||||
JS_ASSERT(depth <= size_t(cx->regs->sp - fp->base()));
|
JS_ASSERT(depth <= size_t(cx->regs().sp - fp->base()));
|
||||||
JS_ASSERT(count <= size_t(cx->regs->sp - fp->base() - depth));
|
JS_ASSERT(count <= size_t(cx->regs().sp - fp->base() - depth));
|
||||||
|
|
||||||
/* See comments in CheckDestructuring from jsparse.cpp. */
|
/* See comments in CheckDestructuring from jsparse.cpp. */
|
||||||
JS_ASSERT(count >= 1);
|
JS_ASSERT(count >= 1);
|
||||||
|
@ -3350,7 +3330,7 @@ block_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||||
uintN index = (uintN) JSID_TO_INT(id);
|
uintN index = (uintN) JSID_TO_INT(id);
|
||||||
JS_ASSERT(index < OBJ_BLOCK_COUNT(cx, obj));
|
JS_ASSERT(index < OBJ_BLOCK_COUNT(cx, obj));
|
||||||
|
|
||||||
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
|
StackFrame *fp = (StackFrame *) obj->getPrivate();
|
||||||
if (fp) {
|
if (fp) {
|
||||||
fp = js_LiveFrameIfGenerator(fp);
|
fp = js_LiveFrameIfGenerator(fp);
|
||||||
index += fp->numFixed() + OBJ_BLOCK_DEPTH(cx, obj);
|
index += fp->numFixed() + OBJ_BLOCK_DEPTH(cx, obj);
|
||||||
|
@ -3371,7 +3351,7 @@ block_setProperty(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *v
|
||||||
uintN index = (uintN) JSID_TO_INT(id);
|
uintN index = (uintN) JSID_TO_INT(id);
|
||||||
JS_ASSERT(index < OBJ_BLOCK_COUNT(cx, obj));
|
JS_ASSERT(index < OBJ_BLOCK_COUNT(cx, obj));
|
||||||
|
|
||||||
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
|
StackFrame *fp = (StackFrame *) obj->getPrivate();
|
||||||
if (fp) {
|
if (fp) {
|
||||||
fp = js_LiveFrameIfGenerator(fp);
|
fp = js_LiveFrameIfGenerator(fp);
|
||||||
index += fp->numFixed() + OBJ_BLOCK_DEPTH(cx, obj);
|
index += fp->numFixed() + OBJ_BLOCK_DEPTH(cx, obj);
|
||||||
|
@ -3976,6 +3956,37 @@ bad:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lazy standard classes need a way to indicate if they have been initialized.
|
||||||
|
* Otherwise, when we delete them, we might accidentally recreate them via a
|
||||||
|
* lazy initialization. We use the presence of a ctor or proto in the
|
||||||
|
* globalObject's slot to indicate that they've been constructed, but this only
|
||||||
|
* works for classes which have a proto and ctor. Classes which don't have one
|
||||||
|
* can call MarkStandardClassInitializedNoProto(), and we can always check
|
||||||
|
* whether a class is initialized by calling IsStandardClassResolved().
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
IsStandardClassResolved(JSObject *obj, js::Class *clasp)
|
||||||
|
{
|
||||||
|
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(clasp);
|
||||||
|
|
||||||
|
/* If the constructor is undefined, then it hasn't been initialized. */
|
||||||
|
return (obj->getReservedSlot(key) != UndefinedValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MarkStandardClassInitializedNoProto(JSObject* obj, js::Class *clasp)
|
||||||
|
{
|
||||||
|
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(clasp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We use True so that it's obvious what we're doing (instead of, say,
|
||||||
|
* Null, which might be miscontrued as an error in setting Undefined).
|
||||||
|
*/
|
||||||
|
if (obj->getReservedSlot(key) == UndefinedValue())
|
||||||
|
obj->setSlot(key, BooleanValue(true));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject *
|
JSObject *
|
||||||
|
@ -4227,7 +4238,7 @@ JSBool
|
||||||
js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey protoKey,
|
js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey protoKey,
|
||||||
Value *vp, Class *clasp)
|
Value *vp, Class *clasp)
|
||||||
{
|
{
|
||||||
JSStackFrame *fp;
|
StackFrame *fp;
|
||||||
JSObject *obj, *cobj, *pobj;
|
JSObject *obj, *cobj, *pobj;
|
||||||
jsid id;
|
jsid id;
|
||||||
JSProperty *prop;
|
JSProperty *prop;
|
||||||
|
@ -4945,7 +4956,7 @@ js_LookupPropertyWithFlagsInline(JSContext *cx, JSObject *obj, jsid id, uintN fl
|
||||||
* Non-native objects must have either non-native lookup results,
|
* Non-native objects must have either non-native lookup results,
|
||||||
* or else native results from the non-native's prototype chain.
|
* or else native results from the non-native's prototype chain.
|
||||||
*
|
*
|
||||||
* See JSStackFrame::getValidCalleeObject, where we depend on this
|
* See StackFrame::getValidCalleeObject, where we depend on this
|
||||||
* fact to force a prototype-delegated joined method accessed via
|
* fact to force a prototype-delegated joined method accessed via
|
||||||
* arguments.callee through the delegating |this| object's method
|
* arguments.callee through the delegating |this| object's method
|
||||||
* read barrier.
|
* read barrier.
|
||||||
|
@ -5459,7 +5470,7 @@ js_GetMethod(JSContext *cx, JSObject *obj, jsid id, uintN getHow, Value *vp)
|
||||||
JS_FRIEND_API(bool)
|
JS_FRIEND_API(bool)
|
||||||
js_CheckUndeclaredVarAssignment(JSContext *cx, JSString *propname)
|
js_CheckUndeclaredVarAssignment(JSContext *cx, JSString *propname)
|
||||||
{
|
{
|
||||||
JSStackFrame *const fp = js_GetTopStackFrame(cx);
|
StackFrame *const fp = js_GetTopStackFrame(cx);
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -5873,7 +5884,7 @@ js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool str
|
||||||
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
|
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
|
||||||
|
|
||||||
if (fun != funobj) {
|
if (fun != funobj) {
|
||||||
for (JSStackFrame *fp = cx->maybefp(); fp; fp = fp->prev()) {
|
for (StackFrame *fp = cx->maybefp(); fp; fp = fp->prev()) {
|
||||||
if (fp->isFunctionFrame() &&
|
if (fp->isFunctionFrame() &&
|
||||||
fp->callee() == fun->compiledFunObj() &&
|
fp->callee() == fun->compiledFunObj() &&
|
||||||
fp->thisValue().isObject())
|
fp->thisValue().isObject())
|
||||||
|
@ -6157,7 +6168,7 @@ js_GetClassPrototype(JSContext *cx, JSObject *scopeobj, JSProtoKey protoKey,
|
||||||
|
|
||||||
if (protoKey != JSProto_Null) {
|
if (protoKey != JSProto_Null) {
|
||||||
if (!scopeobj) {
|
if (!scopeobj) {
|
||||||
if (cx->hasfp())
|
if (cx->running())
|
||||||
scopeobj = &cx->fp()->scopeChain();
|
scopeobj = &cx->fp()->scopeChain();
|
||||||
if (!scopeobj) {
|
if (!scopeobj) {
|
||||||
scopeobj = cx->globalObject;
|
scopeobj = cx->globalObject;
|
||||||
|
@ -6205,12 +6216,8 @@ js_SetClassPrototype(JSContext *cx, JSObject *ctor, JSObject *proto, uintN attrs
|
||||||
JSObject *
|
JSObject *
|
||||||
PrimitiveToObject(JSContext *cx, const Value &v)
|
PrimitiveToObject(JSContext *cx, const Value &v)
|
||||||
{
|
{
|
||||||
if (v.isString()) {
|
if (v.isString())
|
||||||
JSObject *obj = NewBuiltinClassInstance(cx, &js_StringClass);
|
return StringObject::create(cx, v.toString());
|
||||||
if (!obj || !obj->initString(cx, v.toString()))
|
|
||||||
return NULL;
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_ASSERT(v.isNumber() || v.isBoolean());
|
JS_ASSERT(v.isNumber() || v.isBoolean());
|
||||||
Class *clasp = v.isNumber() ? &js_NumberClass : &js_BooleanClass;
|
Class *clasp = v.isNumber() ? &js_NumberClass : &js_BooleanClass;
|
||||||
|
@ -6858,7 +6865,7 @@ MaybeDumpValue(const char *name, const Value &v)
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_FRIEND_API(void)
|
JS_FRIEND_API(void)
|
||||||
js_DumpStackFrame(JSContext *cx, JSStackFrame *start)
|
js_DumpStackFrame(JSContext *cx, StackFrame *start)
|
||||||
{
|
{
|
||||||
/* This should only called during live debugging. */
|
/* This should only called during live debugging. */
|
||||||
VOUCH_DOES_NOT_REQUIRE_STACK();
|
VOUCH_DOES_NOT_REQUIRE_STACK();
|
||||||
|
@ -6875,9 +6882,9 @@ js_DumpStackFrame(JSContext *cx, JSStackFrame *start)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; !i.done(); ++i) {
|
for (; !i.done(); ++i) {
|
||||||
JSStackFrame *const fp = i.fp();
|
StackFrame *const fp = i.fp();
|
||||||
|
|
||||||
fprintf(stderr, "JSStackFrame at %p\n", (void *) fp);
|
fprintf(stderr, "StackFrame at %p\n", (void *) fp);
|
||||||
if (fp->isFunctionFrame()) {
|
if (fp->isFunctionFrame()) {
|
||||||
fprintf(stderr, "callee fun: ");
|
fprintf(stderr, "callee fun: ");
|
||||||
dumpValue(ObjectValue(fp->callee()));
|
dumpValue(ObjectValue(fp->callee()));
|
||||||
|
|
|
@ -262,6 +262,7 @@ namespace js {
|
||||||
struct NativeIterator;
|
struct NativeIterator;
|
||||||
class RegExp;
|
class RegExp;
|
||||||
class GlobalObject;
|
class GlobalObject;
|
||||||
|
class StringObject;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,6 +331,9 @@ struct JSObject : js::gc::Cell {
|
||||||
inline void setLastProperty(const js::Shape *shape);
|
inline void setLastProperty(const js::Shape *shape);
|
||||||
inline void removeLastProperty();
|
inline void removeLastProperty();
|
||||||
|
|
||||||
|
/* For setLastProperty() only. */
|
||||||
|
friend class js::StringObject;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
void checkShapeConsistency();
|
void checkShapeConsistency();
|
||||||
#endif
|
#endif
|
||||||
|
@ -477,7 +481,7 @@ struct JSObject : js::gc::Cell {
|
||||||
|
|
||||||
/* Functions for setting up scope chain object maps and shapes. */
|
/* Functions for setting up scope chain object maps and shapes. */
|
||||||
void initCall(JSContext *cx, const js::Bindings &bindings, JSObject *parent);
|
void initCall(JSContext *cx, const js::Bindings &bindings, JSObject *parent);
|
||||||
void initClonedBlock(JSContext *cx, JSObject *proto, JSStackFrame *priv);
|
void initClonedBlock(JSContext *cx, JSObject *proto, js::StackFrame *priv);
|
||||||
void setBlockOwnShape(JSContext *cx);
|
void setBlockOwnShape(JSContext *cx);
|
||||||
|
|
||||||
void deletingShapeChange(JSContext *cx, const js::Shape &shape);
|
void deletingShapeChange(JSContext *cx, const js::Shape &shape);
|
||||||
|
@ -755,23 +759,8 @@ struct JSObject : js::gc::Cell {
|
||||||
inline const js::Value &getPrimitiveThis() const;
|
inline const js::Value &getPrimitiveThis() const;
|
||||||
inline void setPrimitiveThis(const js::Value &pthis);
|
inline void setPrimitiveThis(const js::Value &pthis);
|
||||||
|
|
||||||
private:
|
|
||||||
/* 0 is JSSLOT_PRIMITIVE_THIS */
|
|
||||||
static const uint32 JSSLOT_STRING_LENGTH = 1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Compute the initial shape to associate with fresh String objects,
|
|
||||||
* encoding the initial length property. Return the shape after changing
|
|
||||||
* this String object's last property to it.
|
|
||||||
*/
|
|
||||||
const js::Shape *assignInitialStringShape(JSContext *cx);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const uint32 STRING_RESERVED_SLOTS = 2;
|
inline js::StringObject *asString();
|
||||||
|
|
||||||
inline size_t getStringLength() const;
|
|
||||||
|
|
||||||
inline bool initString(JSContext *cx, JSString *str);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Array-specific getters and setters (for both dense and slow arrays).
|
* Array-specific getters and setters (for both dense and slow arrays).
|
||||||
|
@ -916,7 +905,7 @@ struct JSObject : js::gc::Cell {
|
||||||
inline bool callIsForEval() const;
|
inline bool callIsForEval() const;
|
||||||
|
|
||||||
/* The stack frame for this Call object, if the frame is still active. */
|
/* The stack frame for this Call object, if the frame is still active. */
|
||||||
inline JSStackFrame *maybeCallObjStackFrame() const;
|
inline js::StackFrame *maybeCallObjStackFrame() const;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The callee function if this Call object was created for a function
|
* The callee function if this Call object was created for a function
|
||||||
|
@ -1416,7 +1405,7 @@ inline bool JSObject::isBlock() const { return getClass() == &js_BlockClass; }
|
||||||
/*
|
/*
|
||||||
* Block scope object macros. The slots reserved by js_BlockClass are:
|
* Block scope object macros. The slots reserved by js_BlockClass are:
|
||||||
*
|
*
|
||||||
* private JSStackFrame * active frame pointer or null
|
* private StackFrame * active frame pointer or null
|
||||||
* JSSLOT_BLOCK_DEPTH int depth of block slots in frame
|
* JSSLOT_BLOCK_DEPTH int depth of block slots in frame
|
||||||
*
|
*
|
||||||
* After JSSLOT_BLOCK_DEPTH come one or more slots for the block locals.
|
* After JSSLOT_BLOCK_DEPTH come one or more slots for the block locals.
|
||||||
|
@ -1424,7 +1413,7 @@ inline bool JSObject::isBlock() const { return getClass() == &js_BlockClass; }
|
||||||
* A With object is like a Block object, in that both have one reserved slot
|
* A With object is like a Block object, in that both have one reserved slot
|
||||||
* telling the stack depth of the relevant slots (the slot whose value is the
|
* telling the stack depth of the relevant slots (the slot whose value is the
|
||||||
* object named in the with statement, the slots containing the block's local
|
* object named in the with statement, the slots containing the block's local
|
||||||
* variables); and both have a private slot referring to the JSStackFrame in
|
* variables); and both have a private slot referring to the StackFrame in
|
||||||
* whose activation they were created (or null if the with or block object
|
* whose activation they were created (or null if the with or block object
|
||||||
* outlives the frame).
|
* outlives the frame).
|
||||||
*/
|
*/
|
||||||
|
@ -1480,7 +1469,7 @@ extern JSObject *
|
||||||
js_NewBlockObject(JSContext *cx);
|
js_NewBlockObject(JSContext *cx);
|
||||||
|
|
||||||
extern JSObject *
|
extern JSObject *
|
||||||
js_CloneBlockObject(JSContext *cx, JSObject *proto, JSStackFrame *fp);
|
js_CloneBlockObject(JSContext *cx, JSObject *proto, js::StackFrame *fp);
|
||||||
|
|
||||||
extern JS_REQUIRES_STACK JSBool
|
extern JS_REQUIRES_STACK JSBool
|
||||||
js_PutBlockObject(JSContext *cx, JSBool normalUnwind);
|
js_PutBlockObject(JSContext *cx, JSBool normalUnwind);
|
||||||
|
@ -1548,6 +1537,13 @@ DefineConstructorAndPrototype(JSContext *cx, JSObject *obj, JSProtoKey key, JSAt
|
||||||
Native constructor, uintN nargs,
|
Native constructor, uintN nargs,
|
||||||
JSPropertySpec *ps, JSFunctionSpec *fs,
|
JSPropertySpec *ps, JSFunctionSpec *fs,
|
||||||
JSPropertySpec *static_ps, JSFunctionSpec *static_fs);
|
JSPropertySpec *static_ps, JSFunctionSpec *static_fs);
|
||||||
|
|
||||||
|
bool
|
||||||
|
IsStandardClassResolved(JSObject *obj, js::Class *clasp);
|
||||||
|
|
||||||
|
void
|
||||||
|
MarkStandardClassInitializedNoProto(JSObject *obj, js::Class *clasp);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern JSObject *
|
extern JSObject *
|
||||||
|
@ -1912,7 +1908,7 @@ JS_FRIEND_API(void) js_DumpAtom(JSAtom *atom);
|
||||||
JS_FRIEND_API(void) js_DumpObject(JSObject *obj);
|
JS_FRIEND_API(void) js_DumpObject(JSObject *obj);
|
||||||
JS_FRIEND_API(void) js_DumpValue(const js::Value &val);
|
JS_FRIEND_API(void) js_DumpValue(const js::Value &val);
|
||||||
JS_FRIEND_API(void) js_DumpId(jsid id);
|
JS_FRIEND_API(void) js_DumpId(jsid id);
|
||||||
JS_FRIEND_API(void) js_DumpStackFrame(JSContext *cx, JSStackFrame *start = NULL);
|
JS_FRIEND_API(void) js_DumpStackFrame(JSContext *cx, js::StackFrame *start = NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern uintN
|
extern uintN
|
||||||
|
@ -1922,7 +1918,6 @@ js_InferFlags(JSContext *cx, uintN defaultFlags);
|
||||||
JSBool
|
JSBool
|
||||||
js_Object(JSContext *cx, uintN argc, js::Value *vp);
|
js_Object(JSContext *cx, uintN argc, js::Value *vp);
|
||||||
|
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
extern bool
|
extern bool
|
||||||
|
|
|
@ -169,7 +169,7 @@ JSObject::initCall(JSContext *cx, const js::Bindings &bindings, JSObject *parent
|
||||||
* shape.
|
* shape.
|
||||||
*/
|
*/
|
||||||
inline void
|
inline void
|
||||||
JSObject::initClonedBlock(JSContext *cx, JSObject *proto, JSStackFrame *frame)
|
JSObject::initClonedBlock(JSContext *cx, JSObject *proto, js::StackFrame *frame)
|
||||||
{
|
{
|
||||||
init(cx, &js_BlockClass, proto, NULL, frame, false);
|
init(cx, &js_BlockClass, proto, NULL, frame, false);
|
||||||
|
|
||||||
|
@ -327,7 +327,7 @@ JSObject::setPrimitiveThis(const js::Value &pthis)
|
||||||
inline /* gc::FinalizeKind */ unsigned
|
inline /* gc::FinalizeKind */ unsigned
|
||||||
JSObject::finalizeKind() const
|
JSObject::finalizeKind() const
|
||||||
{
|
{
|
||||||
return js::gc::FinalizeKind(arena()->header()->thingKind);
|
return js::gc::FinalizeKind(arenaHeader()->getThingKind());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline size_t
|
inline size_t
|
||||||
|
@ -509,11 +509,11 @@ JSObject::callIsForEval() const
|
||||||
return getSlot(JSSLOT_CALL_CALLEE).isNull();
|
return getSlot(JSSLOT_CALL_CALLEE).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline JSStackFrame *
|
inline js::StackFrame *
|
||||||
JSObject::maybeCallObjStackFrame() const
|
JSObject::maybeCallObjStackFrame() const
|
||||||
{
|
{
|
||||||
JS_ASSERT(isCall());
|
JS_ASSERT(isCall());
|
||||||
return reinterpret_cast<JSStackFrame *>(getPrivate());
|
return reinterpret_cast<js::StackFrame *>(getPrivate());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
|
@ -881,12 +881,6 @@ JSObject::principals(JSContext *cx)
|
||||||
return compPrincipals;
|
return compPrincipals;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline JSPrincipals *
|
|
||||||
JSStackFrame::principals(JSContext *cx) const
|
|
||||||
{
|
|
||||||
return scopeChain().principals(cx);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint32
|
inline uint32
|
||||||
JSObject::slotSpan() const
|
JSObject::slotSpan() const
|
||||||
{
|
{
|
||||||
|
@ -1222,7 +1216,7 @@ NewBuiltinClassInstance(JSContext *cx, Class *clasp, gc::FinalizeKind kind)
|
||||||
|
|
||||||
/* NB: inline-expanded and specialized version of js_GetClassPrototype. */
|
/* NB: inline-expanded and specialized version of js_GetClassPrototype. */
|
||||||
JSObject *global;
|
JSObject *global;
|
||||||
if (!cx->hasfp()) {
|
if (!cx->running()) {
|
||||||
global = cx->globalObject;
|
global = cx->globalObject;
|
||||||
OBJ_TO_INNER_OBJECT(cx, global);
|
OBJ_TO_INNER_OBJECT(cx, global);
|
||||||
if (!global)
|
if (!global)
|
||||||
|
@ -1429,6 +1423,25 @@ NewObjectGCKind(JSContext *cx, js::Class *clasp)
|
||||||
return gc::FINALIZE_OBJECT4;
|
return gc::FINALIZE_OBJECT4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static JS_ALWAYS_INLINE JSObject*
|
||||||
|
NewObjectWithClassProto(JSContext *cx, Class *clasp, JSObject *proto,
|
||||||
|
/*gc::FinalizeKind*/ unsigned _kind)
|
||||||
|
{
|
||||||
|
JS_ASSERT(clasp->isNative());
|
||||||
|
gc::FinalizeKind kind = gc::FinalizeKind(_kind);
|
||||||
|
|
||||||
|
if (CanBeFinalizedInBackground(kind, clasp))
|
||||||
|
kind = (gc::FinalizeKind)(kind + 1);
|
||||||
|
|
||||||
|
JSObject* obj = js_NewGCObject(cx, kind);
|
||||||
|
if (!obj)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!obj->initSharingEmptyShape(cx, clasp, proto, proto->getParent(), NULL, kind))
|
||||||
|
return NULL;
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
/* Make an object with pregenerated shape from a NEWOBJECT bytecode. */
|
/* Make an object with pregenerated shape from a NEWOBJECT bytecode. */
|
||||||
static inline JSObject *
|
static inline JSObject *
|
||||||
CopyInitializerObject(JSContext *cx, JSObject *baseobj)
|
CopyInitializerObject(JSContext *cx, JSObject *baseobj)
|
||||||
|
|
422
js/src/json.cpp
422
js/src/json.cpp
|
@ -67,6 +67,8 @@
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
#include "jsstrinlines.h"
|
#include "jsstrinlines.h"
|
||||||
|
|
||||||
|
#include "vm/Stack-inl.h"
|
||||||
|
|
||||||
using namespace js;
|
using namespace js;
|
||||||
using namespace js::gc;
|
using namespace js::gc;
|
||||||
|
|
||||||
|
@ -129,21 +131,19 @@ js_json_parse(JSContext *cx, uintN argc, Value *vp)
|
||||||
return ParseJSONWithReviver(cx, linearStr->chars(), linearStr->length(), reviver, vp);
|
return ParseJSONWithReviver(cx, linearStr->chars(), linearStr->length(), reviver, vp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ES5 15.12.3. */
|
||||||
JSBool
|
JSBool
|
||||||
js_json_stringify(JSContext *cx, uintN argc, Value *vp)
|
js_json_stringify(JSContext *cx, uintN argc, Value *vp)
|
||||||
{
|
{
|
||||||
Value *argv = vp + 2;
|
*vp = (argc >= 1) ? vp[2] : UndefinedValue();
|
||||||
AutoValueRooter space(cx);
|
JSObject *replacer = (argc >= 2 && vp[3].isObject())
|
||||||
AutoObjectRooter replacer(cx);
|
? &vp[3].toObject()
|
||||||
|
: NULL;
|
||||||
// Must throw an Error if there isn't a first arg
|
Value space = (argc >= 3) ? vp[4] : UndefinedValue();
|
||||||
if (!JS_ConvertArguments(cx, argc, Jsvalify(argv), "v / o v", vp, replacer.addr(), space.addr()))
|
|
||||||
return JS_FALSE;
|
|
||||||
|
|
||||||
StringBuffer sb(cx);
|
StringBuffer sb(cx);
|
||||||
|
if (!js_Stringify(cx, vp, replacer, space, sb))
|
||||||
if (!js_Stringify(cx, vp, replacer.object(), space.value(), sb))
|
return false;
|
||||||
return JS_FALSE;
|
|
||||||
|
|
||||||
// XXX This can never happen to nsJSON.cpp, but the JSON object
|
// XXX This can never happen to nsJSON.cpp, but the JSON object
|
||||||
// needs to support returning undefined. So this is a little awkward
|
// needs to support returning undefined. So this is a little awkward
|
||||||
|
@ -151,13 +151,13 @@ js_json_stringify(JSContext *cx, uintN argc, Value *vp)
|
||||||
if (!sb.empty()) {
|
if (!sb.empty()) {
|
||||||
JSString *str = sb.finishString();
|
JSString *str = sb.finishString();
|
||||||
if (!str)
|
if (!str)
|
||||||
return JS_FALSE;
|
return false;
|
||||||
vp->setString(str);
|
vp->setString(str);
|
||||||
} else {
|
} else {
|
||||||
vp->setUndefined();
|
vp->setUndefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
return JS_TRUE;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSBool
|
JSBool
|
||||||
|
@ -179,84 +179,91 @@ js_TryJSON(JSContext *cx, Value *vp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const char quote = '\"';
|
static inline bool IsQuoteSpecialCharacter(jschar c)
|
||||||
static const char backslash = '\\';
|
|
||||||
static const char unicodeEscape[] = "\\u00";
|
|
||||||
|
|
||||||
static JSBool
|
|
||||||
write_string(JSContext *cx, StringBuffer &sb, const jschar *buf, uint32 len)
|
|
||||||
{
|
{
|
||||||
if (!sb.append(quote))
|
JS_STATIC_ASSERT('\b' < ' ');
|
||||||
return JS_FALSE;
|
JS_STATIC_ASSERT('\f' < ' ');
|
||||||
|
JS_STATIC_ASSERT('\n' < ' ');
|
||||||
|
JS_STATIC_ASSERT('\r' < ' ');
|
||||||
|
JS_STATIC_ASSERT('\t' < ' ');
|
||||||
|
return c == '"' || c == '\\' || c < ' ';
|
||||||
|
}
|
||||||
|
|
||||||
uint32 mark = 0;
|
/* ES5 15.12.3 Quote. */
|
||||||
uint32 i;
|
static bool
|
||||||
for (i = 0; i < len; ++i) {
|
Quote(JSContext *cx, StringBuffer &sb, JSString *str)
|
||||||
if (buf[i] == quote || buf[i] == backslash) {
|
{
|
||||||
if (!sb.append(&buf[mark], i - mark) || !sb.append(backslash) ||
|
JS::Anchor<JSString *> anchor(str);
|
||||||
!sb.append(buf[i])) {
|
size_t len = str->length();
|
||||||
return JS_FALSE;
|
const jschar *buf = str->getChars(cx);
|
||||||
}
|
if (!buf)
|
||||||
mark = i + 1;
|
return false;
|
||||||
} else if (buf[i] <= 31 || buf[i] == 127) {
|
|
||||||
if (!sb.append(&buf[mark], i - mark) ||
|
/* Step 1. */
|
||||||
!sb.append(unicodeEscape)) {
|
if (!sb.append('"'))
|
||||||
return JS_FALSE;
|
return false;
|
||||||
}
|
|
||||||
char ubuf[3];
|
/* Step 2. */
|
||||||
size_t len = JS_snprintf(ubuf, sizeof(ubuf), "%.2x", buf[i]);
|
for (size_t i = 0; i < len; ++i) {
|
||||||
JS_ASSERT(len == 2);
|
/* Batch-append maximal character sequences containing no escapes. */
|
||||||
jschar wbuf[3];
|
size_t mark = i;
|
||||||
size_t wbufSize = JS_ARRAY_LENGTH(wbuf);
|
do {
|
||||||
if (!js_InflateStringToBuffer(cx, ubuf, len, wbuf, &wbufSize) ||
|
if (IsQuoteSpecialCharacter(buf[i]))
|
||||||
!sb.append(wbuf, wbufSize)) {
|
break;
|
||||||
return JS_FALSE;
|
} while (++i < len);
|
||||||
}
|
if (i > mark) {
|
||||||
mark = i + 1;
|
if (!sb.append(&buf[mark], i - mark))
|
||||||
|
return false;
|
||||||
|
if (i == len)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
jschar c = buf[i];
|
||||||
|
if (c == '"' || c == '\\') {
|
||||||
|
if (!sb.append('\\') || !sb.append(c))
|
||||||
|
return false;
|
||||||
|
} else if (c == '\b' || c == '\f' || c == '\n' || c == '\r' || c == '\t') {
|
||||||
|
jschar abbrev = (c == '\b')
|
||||||
|
? 'b'
|
||||||
|
: (c == '\f')
|
||||||
|
? 'f'
|
||||||
|
: (c == '\n')
|
||||||
|
? 'n'
|
||||||
|
: (c == '\r')
|
||||||
|
? 'r'
|
||||||
|
: 't';
|
||||||
|
if (!sb.append('\\') || !sb.append(abbrev))
|
||||||
|
return false;
|
||||||
|
mark = i + 1;
|
||||||
|
} else {
|
||||||
|
JS_ASSERT(c < ' ');
|
||||||
|
if (!sb.append("\\u00"))
|
||||||
|
return false;
|
||||||
|
JS_ASSERT((c >> 4) < 10);
|
||||||
|
uint8 x = c >> 4, y = c % 16;
|
||||||
|
if (!sb.append('0' + x) || !sb.append(y < 10 ? '0' + y : 'a' + (y - 10)))
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mark < len && !sb.append(&buf[mark], len - mark))
|
/* Steps 3-4. */
|
||||||
return JS_FALSE;
|
return sb.append('"');
|
||||||
|
|
||||||
return sb.append(quote);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class StringifyContext
|
class StringifyContext
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
StringifyContext(JSContext *cx, StringBuffer &sb, JSObject *replacer)
|
StringifyContext(JSContext *cx, StringBuffer &sb, const StringBuffer &gap,
|
||||||
: sb(sb), gap(cx), replacer(replacer), depth(0), objectStack(cx)
|
JSObject *replacer, const AutoIdVector &propertyList)
|
||||||
|
: sb(sb),
|
||||||
|
gap(gap),
|
||||||
|
replacer(replacer),
|
||||||
|
propertyList(propertyList),
|
||||||
|
depth(0),
|
||||||
|
objectStack(cx)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool initializeGap(JSContext *cx, const Value &space) {
|
bool init() {
|
||||||
AutoValueRooter gapValue(cx, space);
|
|
||||||
|
|
||||||
if (space.isObject()) {
|
|
||||||
JSObject &obj = space.toObject();
|
|
||||||
Class *clasp = obj.getClass();
|
|
||||||
if (clasp == &js_NumberClass || clasp == &js_StringClass)
|
|
||||||
*gapValue.addr() = obj.getPrimitiveThis();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gapValue.value().isString()) {
|
|
||||||
if (!gap.append(gapValue.value().toString()))
|
|
||||||
return false;
|
|
||||||
if (gap.length() > 10)
|
|
||||||
gap.resize(10);
|
|
||||||
} else if (gapValue.value().isNumber()) {
|
|
||||||
jsdouble d = gapValue.value().isInt32()
|
|
||||||
? gapValue.value().toInt32()
|
|
||||||
: js_DoubleToInteger(gapValue.value().toDouble());
|
|
||||||
d = JS_MIN(10, d);
|
|
||||||
if (d >= 1 && !gap.appendN(' ', uint32(d)))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool initializeStack() {
|
|
||||||
return objectStack.init(16);
|
return objectStack.init(16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,8 +272,9 @@ public:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
StringBuffer &sb;
|
StringBuffer &sb;
|
||||||
StringBuffer gap;
|
const StringBuffer ⪆
|
||||||
JSObject *replacer;
|
JSObject * const replacer;
|
||||||
|
const AutoIdVector &propertyList;
|
||||||
uint32 depth;
|
uint32 depth;
|
||||||
HashSet<JSObject *> objectStack;
|
HashSet<JSObject *> objectStack;
|
||||||
};
|
};
|
||||||
|
@ -336,14 +344,14 @@ PreprocessValue(JSContext *cx, JSObject *holder, jsid key, Value *vp, StringifyC
|
||||||
|
|
||||||
LeaveTrace(cx);
|
LeaveTrace(cx);
|
||||||
InvokeArgsGuard args;
|
InvokeArgsGuard args;
|
||||||
if (!cx->stack().pushInvokeArgs(cx, 1, &args))
|
if (!cx->stack.pushInvokeArgs(cx, 1, &args))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
args.calleev() = toJSON;
|
args.calleev() = toJSON;
|
||||||
args.thisv() = *vp;
|
args.thisv() = *vp;
|
||||||
args[0] = StringValue(keyStr);
|
args[0] = StringValue(keyStr);
|
||||||
|
|
||||||
if (!Invoke(cx, args, 0))
|
if (!Invoke(cx, args))
|
||||||
return false;
|
return false;
|
||||||
*vp = args.rval();
|
*vp = args.rval();
|
||||||
}
|
}
|
||||||
|
@ -359,7 +367,7 @@ PreprocessValue(JSContext *cx, JSObject *holder, jsid key, Value *vp, StringifyC
|
||||||
|
|
||||||
LeaveTrace(cx);
|
LeaveTrace(cx);
|
||||||
InvokeArgsGuard args;
|
InvokeArgsGuard args;
|
||||||
if (!cx->stack().pushInvokeArgs(cx, 2, &args))
|
if (!cx->stack.pushInvokeArgs(cx, 2, &args))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
args.calleev() = ObjectValue(*scx->replacer);
|
args.calleev() = ObjectValue(*scx->replacer);
|
||||||
|
@ -367,7 +375,7 @@ PreprocessValue(JSContext *cx, JSObject *holder, jsid key, Value *vp, StringifyC
|
||||||
args[0] = StringValue(keyStr);
|
args[0] = StringValue(keyStr);
|
||||||
args[1] = *vp;
|
args[1] = *vp;
|
||||||
|
|
||||||
if (!Invoke(cx, args, 0))
|
if (!Invoke(cx, args))
|
||||||
return false;
|
return false;
|
||||||
*vp = args.rval();
|
*vp = args.rval();
|
||||||
}
|
}
|
||||||
|
@ -430,44 +438,25 @@ JO(JSContext *cx, JSObject *obj, StringifyContext *scx)
|
||||||
if (!scx->sb.append('{'))
|
if (!scx->sb.append('{'))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
AutoIdRooter idr(cx);
|
|
||||||
jsid& id = *idr.addr();
|
|
||||||
|
|
||||||
/* Steps 5-7. */
|
/* Steps 5-7. */
|
||||||
/* XXX Bug 648471: Do this in js_Stringify, rename keySource. */
|
AutoIdVector ids(cx);
|
||||||
Value keySource = ObjectValue(*obj);
|
const AutoIdVector *props;
|
||||||
bool usingWhitelist = false;
|
if (scx->replacer && !scx->replacer->isCallable()) {
|
||||||
|
JS_ASSERT(JS_IsArrayObject(cx, scx->replacer));
|
||||||
// if the replacer is an array, we use the keys from it
|
props = &scx->propertyList;
|
||||||
if (scx->replacer && JS_IsArrayObject(cx, scx->replacer)) {
|
} else {
|
||||||
usingWhitelist = true;
|
JS_ASSERT_IF(scx->replacer, scx->propertyList.length() == 0);
|
||||||
keySource.setObject(*scx->replacer);
|
if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &ids))
|
||||||
|
return false;
|
||||||
|
props = &ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wroteMember = false;
|
/* My kingdom for not-quite-initialized-from-the-start references. */
|
||||||
AutoIdVector props(cx);
|
const AutoIdVector &propertyList = *props;
|
||||||
if (!GetPropertyNames(cx, &keySource.toObject(), JSITER_OWNONLY, &props))
|
|
||||||
return JS_FALSE;
|
|
||||||
|
|
||||||
/* Steps 8-10, 13. */
|
/* Steps 8-10, 13. */
|
||||||
for (size_t i = 0, len = props.length(); i < len; i++) {
|
bool wroteMember = false;
|
||||||
if (!usingWhitelist) {
|
for (size_t i = 0, len = propertyList.length(); i < len; i++) {
|
||||||
if (!js_ValueToStringId(cx, IdToValue(props[i]), &id))
|
|
||||||
return JS_FALSE;
|
|
||||||
} else {
|
|
||||||
// skip non-index properties
|
|
||||||
jsuint index = 0;
|
|
||||||
if (!js_IdIsIndex(props[i], &index))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Value whitelistElement;
|
|
||||||
if (!scx->replacer->getProperty(cx, props[i], &whitelistElement))
|
|
||||||
return JS_FALSE;
|
|
||||||
|
|
||||||
if (!js_ValueToStringId(cx, whitelistElement, &id))
|
|
||||||
return JS_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Steps 8a-8b. Note that the call to Str is broken up into 1) getting
|
* Steps 8a-8b. Note that the call to Str is broken up into 1) getting
|
||||||
* the property; 2) processing for toJSON, calling the replacer, and
|
* the property; 2) processing for toJSON, calling the replacer, and
|
||||||
|
@ -475,43 +464,38 @@ JO(JSContext *cx, JSObject *obj, StringifyContext *scx)
|
||||||
* values which process to |undefined|, and 4) stringifying all values
|
* values which process to |undefined|, and 4) stringifying all values
|
||||||
* which pass the filter.
|
* which pass the filter.
|
||||||
*/
|
*/
|
||||||
|
const jsid &id = propertyList[i];
|
||||||
Value outputValue;
|
Value outputValue;
|
||||||
if (!obj->getProperty(cx, id, &outputValue))
|
if (!obj->getProperty(cx, id, &outputValue))
|
||||||
return JS_FALSE;
|
return false;
|
||||||
if (!PreprocessValue(cx, obj, id, &outputValue, scx))
|
if (!PreprocessValue(cx, obj, id, &outputValue, scx))
|
||||||
return JS_FALSE;
|
return false;
|
||||||
if (IsFilteredValue(outputValue))
|
if (IsFilteredValue(outputValue))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Output a comma unless this is the first member to write. */
|
/* Output a comma unless this is the first member to write. */
|
||||||
if (wroteMember && !scx->sb.append(','))
|
if (wroteMember && !scx->sb.append(','))
|
||||||
return JS_FALSE;
|
return false;
|
||||||
wroteMember = true;
|
wroteMember = true;
|
||||||
|
|
||||||
if (!WriteIndent(cx, scx, scx->depth))
|
if (!WriteIndent(cx, scx, scx->depth))
|
||||||
return JS_FALSE;
|
return false;
|
||||||
|
|
||||||
// Be careful below: this string is weakly rooted!
|
JSString *s = IdToString(cx, id);
|
||||||
JSString *s = js_ValueToString(cx, IdToValue(id));
|
|
||||||
if (!s)
|
if (!s)
|
||||||
return JS_FALSE;
|
return false;
|
||||||
|
|
||||||
JS::Anchor<JSString *> anchor(s);
|
if (!Quote(cx, scx->sb, s) ||
|
||||||
size_t length = s->length();
|
|
||||||
const jschar *chars = s->getChars(cx);
|
|
||||||
if (!chars)
|
|
||||||
return JS_FALSE;
|
|
||||||
|
|
||||||
if (!write_string(cx, scx->sb, chars, length) ||
|
|
||||||
!scx->sb.append(':') ||
|
!scx->sb.append(':') ||
|
||||||
!(scx->gap.empty() || scx->sb.append(' ')) ||
|
!(scx->gap.empty() || scx->sb.append(' ')) ||
|
||||||
!Str(cx, outputValue, scx)) {
|
!Str(cx, outputValue, scx))
|
||||||
return JS_FALSE;
|
{
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wroteMember && !WriteIndent(cx, scx, scx->depth - 1))
|
if (wroteMember && !WriteIndent(cx, scx, scx->depth - 1))
|
||||||
return JS_FALSE;
|
return false;
|
||||||
|
|
||||||
return scx->sb.append('}');
|
return scx->sb.append('}');
|
||||||
}
|
}
|
||||||
|
@ -611,14 +595,8 @@ Str(JSContext *cx, const Value &v, StringifyContext *scx)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Step 8. */
|
/* Step 8. */
|
||||||
if (v.isString()) {
|
if (v.isString())
|
||||||
JSString *str = v.toString();
|
return Quote(cx, scx->sb, v.toString());
|
||||||
size_t length = str->length();
|
|
||||||
const jschar *chars = str->getChars(cx);
|
|
||||||
if (!chars)
|
|
||||||
return false;
|
|
||||||
return write_string(cx, scx->sb, chars, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Step 5. */
|
/* Step 5. */
|
||||||
if (v.isNull())
|
if (v.isNull())
|
||||||
|
@ -653,27 +631,155 @@ Str(JSContext *cx, const Value &v, StringifyContext *scx)
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ES5 15.12.3. */
|
||||||
JSBool
|
JSBool
|
||||||
js_Stringify(JSContext *cx, Value *vp, JSObject *replacer, const Value &space,
|
js_Stringify(JSContext *cx, Value *vp, JSObject *replacer, Value space, StringBuffer &sb)
|
||||||
StringBuffer &sb)
|
|
||||||
{
|
{
|
||||||
StringifyContext scx(cx, sb, replacer);
|
/*
|
||||||
if (!scx.initializeGap(cx, space) || !scx.initializeStack())
|
* Step 4.
|
||||||
return JS_FALSE;
|
*
|
||||||
|
* The spec algorithm is unhelpfully vague in 15.12.3 step 4b about the
|
||||||
|
* exact steps taken when the replacer is an array, regarding the exact
|
||||||
|
* sequence of [[Get]] calls for the array's elements, when its overall
|
||||||
|
* length is calculated, whether own or own plus inherited properties are
|
||||||
|
* considered, and so on. A rewrite of the step was proposed in
|
||||||
|
* <https://mail.mozilla.org/pipermail/es5-discuss/2011-April/003976.html>,
|
||||||
|
* whose steps are copied below, and which are implemented here.
|
||||||
|
*
|
||||||
|
* i. Let PropertyList be an empty internal List.
|
||||||
|
* ii. Let len be the result of calling the [[Get]] internal method of
|
||||||
|
* replacer with the argument "length".
|
||||||
|
* iii. Let i be 0.
|
||||||
|
* iv. While i < len:
|
||||||
|
* 1. Let item be undefined.
|
||||||
|
* 2. Let v be the result of calling the [[Get]] internal method of
|
||||||
|
* replacer with the argument ToString(i).
|
||||||
|
* 3. If Type(v) is String then let item be v.
|
||||||
|
* 4. Else if Type(v) is Number then let item be ToString(v).
|
||||||
|
* 5. Else if Type(v) is Object then
|
||||||
|
* a. If the [[Class]] internal property of v is "String" or
|
||||||
|
* "Number" then let item be ToString(v).
|
||||||
|
* 6. If item is not undefined and item is not currently an element of
|
||||||
|
* PropertyList then,
|
||||||
|
* a. Append item to the end of PropertyList.
|
||||||
|
* 7. Let i be i + 1.
|
||||||
|
*/
|
||||||
|
AutoIdVector propertyList(cx);
|
||||||
|
if (replacer && JS_IsArrayObject(cx, replacer)) {
|
||||||
|
/* Step 4b(ii). */
|
||||||
|
jsuint len;
|
||||||
|
JS_ALWAYS_TRUE(js_GetLengthProperty(cx, replacer, &len));
|
||||||
|
if (replacer->isDenseArray())
|
||||||
|
len = JS_MIN(len, replacer->getDenseArrayCapacity());
|
||||||
|
|
||||||
JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass);
|
HashSet<jsid> idSet(cx);
|
||||||
if (!obj)
|
if (!idSet.init(len))
|
||||||
return JS_FALSE;
|
return false;
|
||||||
|
|
||||||
AutoObjectRooter tvr(cx, obj);
|
/* Step 4b(iii). */
|
||||||
|
jsuint i = 0;
|
||||||
|
|
||||||
|
/* Step 4b(iv). */
|
||||||
|
for (; i < len; i++) {
|
||||||
|
/* Step 4b(iv)(2). */
|
||||||
|
Value v;
|
||||||
|
if (!replacer->getProperty(cx, INT_TO_JSID(i), &v))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
jsid id;
|
||||||
|
if (v.isNumber()) {
|
||||||
|
/* Step 4b(iv)(4). */
|
||||||
|
int32_t n;
|
||||||
|
if (v.isNumber() && ValueFitsInInt32(v, &n) && INT_FITS_IN_JSID(n)) {
|
||||||
|
id = INT_TO_JSID(n);
|
||||||
|
} else {
|
||||||
|
if (!js_ValueToStringId(cx, v, &id))
|
||||||
|
return false;
|
||||||
|
id = js_CheckForStringIndex(id);
|
||||||
|
}
|
||||||
|
} else if (v.isString() ||
|
||||||
|
(v.isObject() && (v.toObject().isString() || v.toObject().isNumber())))
|
||||||
|
{
|
||||||
|
/* Step 4b(iv)(3), 4b(iv)(5). */
|
||||||
|
if (!js_ValueToStringId(cx, v, &id))
|
||||||
|
return false;
|
||||||
|
id = js_CheckForStringIndex(id);
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Step 4b(iv)(6). */
|
||||||
|
HashSet<jsid>::AddPtr p = idSet.lookupForAdd(id);
|
||||||
|
if (!p) {
|
||||||
|
/* Step 4b(iv)(6)(a). */
|
||||||
|
if (!idSet.add(p, id) || !propertyList.append(id))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Step 5. */
|
||||||
|
if (space.isObject()) {
|
||||||
|
JSObject &spaceObj = space.toObject();
|
||||||
|
if (spaceObj.isNumber()) {
|
||||||
|
jsdouble d;
|
||||||
|
if (!ValueToNumber(cx, space, &d))
|
||||||
|
return false;
|
||||||
|
space = NumberValue(d);
|
||||||
|
} else if (spaceObj.isString()) {
|
||||||
|
JSString *str = js_ValueToString(cx, space);
|
||||||
|
if (!str)
|
||||||
|
return false;
|
||||||
|
space = StringValue(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuffer gap(cx);
|
||||||
|
|
||||||
|
if (space.isNumber()) {
|
||||||
|
/* Step 6. */
|
||||||
|
jsdouble d;
|
||||||
|
JS_ALWAYS_TRUE(ToInteger(cx, space, &d));
|
||||||
|
d = JS_MIN(10, d);
|
||||||
|
if (d >= 1 && !gap.appendN(' ', uint32(d)))
|
||||||
|
return false;
|
||||||
|
} else if (space.isString()) {
|
||||||
|
/* Step 7. */
|
||||||
|
JSLinearString *str = space.toString()->ensureLinear(cx);
|
||||||
|
if (!str)
|
||||||
|
return false;
|
||||||
|
JS::Anchor<JSString *> anchor(str);
|
||||||
|
size_t len = JS_MIN(10, space.toString()->length());
|
||||||
|
if (!gap.append(str->chars(), len))
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
/* Step 8. */
|
||||||
|
JS_ASSERT(gap.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Step 9. */
|
||||||
|
JSObject *wrapper = NewBuiltinClassInstance(cx, &js_ObjectClass);
|
||||||
|
if (!wrapper)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Step 10. */
|
||||||
jsid emptyId = ATOM_TO_JSID(cx->runtime->atomState.emptyAtom);
|
jsid emptyId = ATOM_TO_JSID(cx->runtime->atomState.emptyAtom);
|
||||||
if (!obj->defineProperty(cx, emptyId, *vp, NULL, NULL, JSPROP_ENUMERATE))
|
if (!js_DefineNativeProperty(cx, wrapper, emptyId, *vp, PropertyStub, StrictPropertyStub,
|
||||||
return JS_FALSE;
|
JSPROP_ENUMERATE, 0, 0, NULL))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!PreprocessValue(cx, obj, emptyId, vp, &scx))
|
/* Step 11. */
|
||||||
return JS_FALSE;
|
StringifyContext scx(cx, sb, gap, replacer, propertyList);
|
||||||
|
if (!scx.init())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!PreprocessValue(cx, wrapper, emptyId, vp, &scx))
|
||||||
|
return false;
|
||||||
if (IsFilteredValue(*vp))
|
if (IsFilteredValue(*vp))
|
||||||
return JS_TRUE;
|
return true;
|
||||||
|
|
||||||
return Str(cx, *vp, &scx);
|
return Str(cx, *vp, &scx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1397,5 +1503,7 @@ js_InitJSONClass(JSContext *cx, JSObject *obj)
|
||||||
if (!JS_DefineFunctions(cx, JSON, json_static_methods))
|
if (!JS_DefineFunctions(cx, JSON, json_static_methods))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
MarkStandardClassInitializedNoProto(obj, &js_JSONClass);
|
||||||
|
|
||||||
return JSON;
|
return JSON;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,8 +52,8 @@ extern JSObject *
|
||||||
js_InitJSONClass(JSContext *cx, JSObject *obj);
|
js_InitJSONClass(JSContext *cx, JSObject *obj);
|
||||||
|
|
||||||
extern JSBool
|
extern JSBool
|
||||||
js_Stringify(JSContext *cx, js::Value *vp, JSObject *replacer,
|
js_Stringify(JSContext *cx, js::Value *vp, JSObject *replacer, js::Value space,
|
||||||
const js::Value &space, js::StringBuffer &sb);
|
js::StringBuffer &sb);
|
||||||
|
|
||||||
extern JSBool js_TryJSON(JSContext *cx, js::Value *vp);
|
extern JSBool js_TryJSON(JSContext *cx, js::Value *vp);
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,6 @@
|
||||||
#include "jsstaticcheck.h"
|
#include "jsstaticcheck.h"
|
||||||
#include "jsvector.h"
|
#include "jsvector.h"
|
||||||
|
|
||||||
#include "jsinterpinlines.h"
|
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
#include "jsscriptinlines.h"
|
#include "jsscriptinlines.h"
|
||||||
#include "jscntxtinlines.h"
|
#include "jscntxtinlines.h"
|
||||||
|
@ -311,7 +310,7 @@ js_DumpPC(JSContext *cx)
|
||||||
void *mark = JS_ARENA_MARK(&cx->tempPool);
|
void *mark = JS_ARENA_MARK(&cx->tempPool);
|
||||||
Sprinter sprinter;
|
Sprinter sprinter;
|
||||||
INIT_SPRINTER(cx, &sprinter, &cx->tempPool, 0);
|
INIT_SPRINTER(cx, &sprinter, &cx->tempPool, 0);
|
||||||
JSBool ok = js_DisassembleAtPC(cx, cx->fp()->script(), true, cx->regs->pc, &sprinter);
|
JSBool ok = js_DisassembleAtPC(cx, cx->fp()->script(), true, cx->regs().pc, &sprinter);
|
||||||
fprintf(stdout, "%s", sprinter.base);
|
fprintf(stdout, "%s", sprinter.base);
|
||||||
JS_ARENA_RELEASE(&cx->tempPool, mark);
|
JS_ARENA_RELEASE(&cx->tempPool, mark);
|
||||||
return ok;
|
return ok;
|
||||||
|
@ -2053,7 +2052,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||||
token = CodeToken[op];
|
token = CodeToken[op];
|
||||||
|
|
||||||
if (pc + oplen == jp->dvgfence) {
|
if (pc + oplen == jp->dvgfence) {
|
||||||
JSStackFrame *fp;
|
StackFrame *fp;
|
||||||
uint32 format, mode, type;
|
uint32 format, mode, type;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2915,7 +2914,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||||
* object that's not a constructor, causing us to be
|
* object that's not a constructor, causing us to be
|
||||||
* called with an intervening frame on the stack.
|
* called with an intervening frame on the stack.
|
||||||
*/
|
*/
|
||||||
JSStackFrame *fp = js_GetTopStackFrame(cx);
|
StackFrame *fp = js_GetTopStackFrame(cx);
|
||||||
if (fp) {
|
if (fp) {
|
||||||
while (!fp->isEvalFrame())
|
while (!fp->isEvalFrame())
|
||||||
fp = fp->prev();
|
fp = fp->prev();
|
||||||
|
@ -5088,7 +5087,7 @@ char *
|
||||||
js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v_in,
|
js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v_in,
|
||||||
JSString *fallback)
|
JSString *fallback)
|
||||||
{
|
{
|
||||||
JSStackFrame *fp;
|
StackFrame *fp;
|
||||||
JSScript *script;
|
JSScript *script;
|
||||||
jsbytecode *pc;
|
jsbytecode *pc;
|
||||||
|
|
||||||
|
@ -5100,12 +5099,12 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v_in,
|
||||||
|
|
||||||
LeaveTrace(cx);
|
LeaveTrace(cx);
|
||||||
|
|
||||||
if (!cx->regs || !cx->regs->fp || !cx->regs->fp->isScriptFrame())
|
if (!cx->running() || !cx->fp()->isScriptFrame())
|
||||||
goto do_fallback;
|
goto do_fallback;
|
||||||
|
|
||||||
fp = cx->regs->fp;
|
fp = cx->fp();
|
||||||
script = fp->script();
|
script = fp->script();
|
||||||
pc = fp->hasImacropc() ? fp->imacropc() : cx->regs->pc;
|
pc = fp->hasImacropc() ? fp->imacropc() : cx->regs().pc;
|
||||||
JS_ASSERT(script->code <= pc && pc < script->code + script->length);
|
JS_ASSERT(script->code <= pc && pc < script->code + script->length);
|
||||||
|
|
||||||
if (pc < script->main)
|
if (pc < script->main)
|
||||||
|
@ -5139,7 +5138,7 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v_in,
|
||||||
* it that caused exception, see bug 328664.
|
* it that caused exception, see bug 328664.
|
||||||
*/
|
*/
|
||||||
Value *stackBase = fp->base();
|
Value *stackBase = fp->base();
|
||||||
Value *sp = cx->regs->sp;
|
Value *sp = cx->regs().sp;
|
||||||
do {
|
do {
|
||||||
if (sp == stackBase) {
|
if (sp == stackBase) {
|
||||||
pcdepth = -1;
|
pcdepth = -1;
|
||||||
|
@ -5167,11 +5166,10 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v_in,
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
jsbytecode* basepc = cx->regs->pc;
|
jsbytecode* basepc = cx->regs().pc;
|
||||||
jsbytecode* savedImacropc = fp->maybeImacropc();
|
jsbytecode* savedImacropc = fp->maybeImacropc();
|
||||||
if (savedImacropc) {
|
if (savedImacropc) {
|
||||||
JS_ASSERT(cx->hasfp());
|
cx->regs().pc = savedImacropc;
|
||||||
cx->regs->pc = savedImacropc;
|
|
||||||
fp->clearImacropc();
|
fp->clearImacropc();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5186,8 +5184,7 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v_in,
|
||||||
name = DecompileExpression(cx, script, fp->maybeFun(), pc);
|
name = DecompileExpression(cx, script, fp->maybeFun(), pc);
|
||||||
|
|
||||||
if (savedImacropc) {
|
if (savedImacropc) {
|
||||||
JS_ASSERT(cx->hasfp());
|
cx->regs().pc = basepc;
|
||||||
cx->regs->pc = basepc;
|
|
||||||
fp->setImacropc(savedImacropc);
|
fp->setImacropc(savedImacropc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5467,7 +5464,7 @@ ReconstructImacroPCStack(JSContext *cx, JSScript *script,
|
||||||
* Begin with a recursive call back to ReconstructPCStack to pick up
|
* Begin with a recursive call back to ReconstructPCStack to pick up
|
||||||
* the state-of-the-world at the *start* of the imacro.
|
* the state-of-the-world at the *start* of the imacro.
|
||||||
*/
|
*/
|
||||||
JSStackFrame *fp = js_GetScriptedCaller(cx, NULL);
|
StackFrame *fp = js_GetScriptedCaller(cx, NULL);
|
||||||
JS_ASSERT(fp->hasImacropc());
|
JS_ASSERT(fp->hasImacropc());
|
||||||
intN pcdepth = ReconstructPCStack(cx, script, fp->imacropc(), pcstack);
|
intN pcdepth = ReconstructPCStack(cx, script, fp->imacropc(), pcstack);
|
||||||
if (pcdepth < 0)
|
if (pcdepth < 0)
|
||||||
|
|
|
@ -91,7 +91,6 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "jsatominlines.h"
|
#include "jsatominlines.h"
|
||||||
#include "jsinterpinlines.h"
|
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
#include "jsregexpinlines.h"
|
#include "jsregexpinlines.h"
|
||||||
#include "jsscriptinlines.h"
|
#include "jsscriptinlines.h"
|
||||||
|
@ -185,14 +184,14 @@ JSParseNode::clear()
|
||||||
pn_parens = false;
|
pn_parens = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Parser::Parser(JSContext *cx, JSPrincipals *prin, JSStackFrame *cfp)
|
Parser::Parser(JSContext *cx, JSPrincipals *prin, StackFrame *cfp)
|
||||||
: js::AutoGCRooter(cx, PARSER),
|
: js::AutoGCRooter(cx, PARSER),
|
||||||
context(cx),
|
context(cx),
|
||||||
aleFreeList(NULL),
|
aleFreeList(NULL),
|
||||||
tokenStream(cx),
|
tokenStream(cx),
|
||||||
principals(NULL),
|
principals(NULL),
|
||||||
callerFrame(cfp),
|
callerFrame(cfp),
|
||||||
callerVarObj(cfp ? &cfp->varobj(cx->stack().containingSegment(cfp)) : NULL),
|
callerVarObj(cfp ? &cx->stack.space().varObjForFrame(cfp) : NULL),
|
||||||
nodeList(NULL),
|
nodeList(NULL),
|
||||||
functionCount(0),
|
functionCount(0),
|
||||||
traceListHead(NULL),
|
traceListHead(NULL),
|
||||||
|
@ -891,13 +890,13 @@ SetStaticLevel(JSTreeContext *tc, uintN staticLevel)
|
||||||
/*
|
/*
|
||||||
* Compile a top-level script.
|
* Compile a top-level script.
|
||||||
*/
|
*/
|
||||||
Compiler::Compiler(JSContext *cx, JSPrincipals *prin, JSStackFrame *cfp)
|
Compiler::Compiler(JSContext *cx, JSPrincipals *prin, StackFrame *cfp)
|
||||||
: parser(cx, prin, cfp)
|
: parser(cx, prin, cfp)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
JSScript *
|
JSScript *
|
||||||
Compiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *callerFrame,
|
Compiler::compileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerFrame,
|
||||||
JSPrincipals *principals, uint32 tcflags,
|
JSPrincipals *principals, uint32 tcflags,
|
||||||
const jschar *chars, size_t length,
|
const jschar *chars, size_t length,
|
||||||
const char *filename, uintN lineno, JSVersion version,
|
const char *filename, uintN lineno, JSVersion version,
|
||||||
|
@ -8762,7 +8761,7 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
JSObject *obj;
|
JSObject *obj;
|
||||||
if (context->hasfp()) {
|
if (context->running()) {
|
||||||
obj = RegExp::createObject(context, context->regExpStatics(),
|
obj = RegExp::createObject(context, context->regExpStatics(),
|
||||||
tokenStream.getTokenbuf().begin(),
|
tokenStream.getTokenbuf().begin(),
|
||||||
tokenStream.getTokenbuf().length(),
|
tokenStream.getTokenbuf().length(),
|
||||||
|
|
|
@ -1048,14 +1048,14 @@ namespace js {
|
||||||
|
|
||||||
struct Parser : private js::AutoGCRooter
|
struct Parser : private js::AutoGCRooter
|
||||||
{
|
{
|
||||||
JSContext * const context; /* FIXME Bug 551291: use AutoGCRooter::context? */
|
JSContext *const context; /* FIXME Bug 551291: use AutoGCRooter::context? */
|
||||||
JSAtomListElement *aleFreeList;
|
JSAtomListElement *aleFreeList;
|
||||||
void *tempFreeList[NUM_TEMP_FREELISTS];
|
void *tempFreeList[NUM_TEMP_FREELISTS];
|
||||||
TokenStream tokenStream;
|
TokenStream tokenStream;
|
||||||
void *tempPoolMark; /* initial JSContext.tempPool mark */
|
void *tempPoolMark; /* initial JSContext.tempPool mark */
|
||||||
JSPrincipals *principals; /* principals associated with source */
|
JSPrincipals *principals; /* principals associated with source */
|
||||||
JSStackFrame *const callerFrame; /* scripted caller frame for eval and dbgapi */
|
StackFrame *const callerFrame; /* scripted caller frame for eval and dbgapi */
|
||||||
JSObject *const callerVarObj; /* callerFrame's varObj */
|
JSObject *const callerVarObj; /* callerFrame's varObj */
|
||||||
JSParseNode *nodeList; /* list of recyclable parse-node structs */
|
JSParseNode *nodeList; /* list of recyclable parse-node structs */
|
||||||
uint32 functionCount; /* number of functions in current unit */
|
uint32 functionCount; /* number of functions in current unit */
|
||||||
JSObjectBox *traceListHead; /* list of parsed object for GC tracing */
|
JSObjectBox *traceListHead; /* list of parsed object for GC tracing */
|
||||||
|
@ -1065,7 +1065,7 @@ struct Parser : private js::AutoGCRooter
|
||||||
/* Root atoms and objects allocated for the parsed tree. */
|
/* Root atoms and objects allocated for the parsed tree. */
|
||||||
js::AutoKeepAtoms keepAtoms;
|
js::AutoKeepAtoms keepAtoms;
|
||||||
|
|
||||||
Parser(JSContext *cx, JSPrincipals *prin = NULL, JSStackFrame *cfp = NULL);
|
Parser(JSContext *cx, JSPrincipals *prin = NULL, StackFrame *cfp = NULL);
|
||||||
~Parser();
|
~Parser();
|
||||||
|
|
||||||
friend void js::AutoGCRooter::trace(JSTracer *trc);
|
friend void js::AutoGCRooter::trace(JSTracer *trc);
|
||||||
|
@ -1238,7 +1238,7 @@ struct Compiler
|
||||||
Parser parser;
|
Parser parser;
|
||||||
GlobalScope *globalScope;
|
GlobalScope *globalScope;
|
||||||
|
|
||||||
Compiler(JSContext *cx, JSPrincipals *prin = NULL, JSStackFrame *cfp = NULL);
|
Compiler(JSContext *cx, JSPrincipals *prin = NULL, StackFrame *cfp = NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize a compiler. Parameters are passed on to init parser.
|
* Initialize a compiler. Parameters are passed on to init parser.
|
||||||
|
@ -1255,7 +1255,7 @@ struct Compiler
|
||||||
const char *filename, uintN lineno, JSVersion version);
|
const char *filename, uintN lineno, JSVersion version);
|
||||||
|
|
||||||
static JSScript *
|
static JSScript *
|
||||||
compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *callerFrame,
|
compileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerFrame,
|
||||||
JSPrincipals *principals, uint32 tcflags,
|
JSPrincipals *principals, uint32 tcflags,
|
||||||
const jschar *chars, size_t length,
|
const jschar *chars, size_t length,
|
||||||
const char *filename, uintN lineno, JSVersion version,
|
const char *filename, uintN lineno, JSVersion version,
|
||||||
|
|
|
@ -135,7 +135,7 @@ PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, uintN protoI
|
||||||
* Optimize the cached vword based on our parameters and the current pc's
|
* Optimize the cached vword based on our parameters and the current pc's
|
||||||
* opcode format flags.
|
* opcode format flags.
|
||||||
*/
|
*/
|
||||||
pc = cx->regs->pc;
|
pc = cx->regs().pc;
|
||||||
op = js_GetOpcode(cx, cx->fp()->script(), pc);
|
op = js_GetOpcode(cx, cx->fp()->script(), pc);
|
||||||
cs = &js_CodeSpec[op];
|
cs = &js_CodeSpec[op];
|
||||||
kshape = 0;
|
kshape = 0;
|
||||||
|
@ -324,7 +324,7 @@ PropertyCache::fullTest(JSContext *cx, jsbytecode *pc, JSObject **objp, JSObject
|
||||||
JSObject *obj, *pobj, *tmp;
|
JSObject *obj, *pobj, *tmp;
|
||||||
uint32 vcap;
|
uint32 vcap;
|
||||||
|
|
||||||
JSStackFrame *fp = cx->fp();
|
StackFrame *fp = cx->fp();
|
||||||
|
|
||||||
JS_ASSERT(this == &JS_PROPERTY_CACHE(cx));
|
JS_ASSERT(this == &JS_PROPERTY_CACHE(cx));
|
||||||
JS_ASSERT(uintN((fp->hasImacropc() ? fp->imacropc() : pc) - fp->script()->code)
|
JS_ASSERT(uintN((fp->hasImacropc() ? fp->imacropc() : pc) - fp->script()->code)
|
||||||
|
|
|
@ -1406,7 +1406,7 @@ FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp)
|
||||||
* Make a blank object from the recipe fix provided to us. This must have
|
* Make a blank object from the recipe fix provided to us. This must have
|
||||||
* number of fixed slots as the proxy so that we can swap their contents.
|
* number of fixed slots as the proxy so that we can swap their contents.
|
||||||
*/
|
*/
|
||||||
gc::FinalizeKind kind = gc::FinalizeKind(proxy->arena()->header()->thingKind);
|
gc::FinalizeKind kind = gc::FinalizeKind(proxy->arenaHeader()->getThingKind());
|
||||||
JSObject *newborn = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent, kind);
|
JSObject *newborn = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent, kind);
|
||||||
if (!newborn)
|
if (!newborn)
|
||||||
return false;
|
return false;
|
||||||
|
@ -1459,5 +1459,8 @@ js_InitProxyClass(JSContext *cx, JSObject *obj)
|
||||||
}
|
}
|
||||||
if (!JS_DefineFunctions(cx, module, static_methods))
|
if (!JS_DefineFunctions(cx, module, static_methods))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
MarkStandardClassInitializedNoProto(obj, &js_ProxyClass);
|
||||||
|
|
||||||
return module;
|
return module;
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,12 +138,18 @@ class ExecuteArgsGuard;
|
||||||
class InvokeFrameGuard;
|
class InvokeFrameGuard;
|
||||||
class InvokeArgsGuard;
|
class InvokeArgsGuard;
|
||||||
class InvokeSessionGuard;
|
class InvokeSessionGuard;
|
||||||
|
class StringBuffer;
|
||||||
class TraceRecorder;
|
class TraceRecorder;
|
||||||
struct TraceMonitor;
|
struct TraceMonitor;
|
||||||
class StackSpace;
|
|
||||||
|
class FrameRegs;
|
||||||
|
class StackFrame;
|
||||||
class StackSegment;
|
class StackSegment;
|
||||||
|
class StackSpace;
|
||||||
|
class ContextStack;
|
||||||
class FrameRegsIter;
|
class FrameRegsIter;
|
||||||
class StringBuffer;
|
class CallReceiver;
|
||||||
|
class CallArgs;
|
||||||
|
|
||||||
struct Compiler;
|
struct Compiler;
|
||||||
struct Parser;
|
struct Parser;
|
||||||
|
|
|
@ -3314,5 +3314,7 @@ js_InitReflectClass(JSContext *cx, JSObject *obj)
|
||||||
if (!JS_DefineFunctions(cx, Reflect, static_methods))
|
if (!JS_DefineFunctions(cx, Reflect, static_methods))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
MarkStandardClassInitializedNoProto(obj, &js_ReflectClass);
|
||||||
|
|
||||||
return Reflect;
|
return Reflect;
|
||||||
}
|
}
|
||||||
|
|
|
@ -678,15 +678,8 @@ ExecuteRegExp(JSContext *cx, ExecType execType, uintN argc, Value *vp)
|
||||||
|
|
||||||
/* Step 5. */
|
/* Step 5. */
|
||||||
jsdouble i;
|
jsdouble i;
|
||||||
if (lastIndex.isInt32()) {
|
if (!ToInteger(cx, lastIndex, &i))
|
||||||
i = lastIndex.toInt32();
|
return false;
|
||||||
} else {
|
|
||||||
if (lastIndex.isDouble())
|
|
||||||
i = lastIndex.toDouble();
|
|
||||||
else if (!ValueToNumber(cx, lastIndex, &i))
|
|
||||||
return false;
|
|
||||||
i = js_DoubleToInteger(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Steps 6-7 (with sticky extension). */
|
/* Steps 6-7 (with sticky extension). */
|
||||||
if (!re->global() && !re->sticky())
|
if (!re->global() && !re->sticky())
|
||||||
|
|
|
@ -49,8 +49,10 @@
|
||||||
#include "jsscope.h"
|
#include "jsscope.h"
|
||||||
#include "jsgc.h"
|
#include "jsgc.h"
|
||||||
|
|
||||||
#include "jsgcinlines.h"
|
#include "vm/StringObject.h"
|
||||||
|
|
||||||
#include "jscntxtinlines.h"
|
#include "jscntxtinlines.h"
|
||||||
|
#include "jsgcinlines.h"
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
|
@ -71,7 +73,7 @@ JSObject::getEmptyShape(JSContext *cx, js::Class *aclasp,
|
||||||
|
|
||||||
if (!emptyShapes) {
|
if (!emptyShapes) {
|
||||||
emptyShapes = (js::EmptyShape**)
|
emptyShapes = (js::EmptyShape**)
|
||||||
cx->calloc_(sizeof(js::EmptyShape*) * js::gc::JS_FINALIZE_OBJECT_LIMIT);
|
cx->calloc_(sizeof(js::EmptyShape*) * js::gc::FINALIZE_FUNCTION_AND_OBJECT_LAST);
|
||||||
if (!emptyShapes)
|
if (!emptyShapes)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -134,34 +136,29 @@ JSObject::extend(JSContext *cx, const js::Shape *shape, bool isDefinitelyAtom)
|
||||||
updateShape(cx);
|
updateShape(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace js {
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
JSObject::initString(JSContext *cx, JSString *str)
|
StringObject::init(JSContext *cx, JSString *str)
|
||||||
{
|
{
|
||||||
JS_ASSERT(isString());
|
|
||||||
JS_ASSERT(nativeEmpty());
|
JS_ASSERT(nativeEmpty());
|
||||||
|
|
||||||
const js::Shape **shapep = &cx->compartment->initialStringShape;
|
const Shape **shapep = &cx->compartment->initialStringShape;
|
||||||
if (*shapep) {
|
if (*shapep) {
|
||||||
setLastProperty(*shapep);
|
setLastProperty(*shapep);
|
||||||
} else {
|
} else {
|
||||||
*shapep = assignInitialStringShape(cx);
|
*shapep = assignInitialShape(cx);
|
||||||
if (!*shapep)
|
if (!*shapep)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
JS_ASSERT(*shapep == lastProperty());
|
JS_ASSERT(*shapep == lastProperty());
|
||||||
JS_ASSERT(!nativeEmpty());
|
JS_ASSERT(!nativeEmpty());
|
||||||
|
JS_ASSERT(nativeLookup(ATOM_TO_JSID(cx->runtime->atomState.lengthAtom))->slot == LENGTH_SLOT);
|
||||||
|
|
||||||
JS_ASSERT(nativeLookup(ATOM_TO_JSID(cx->runtime->atomState.lengthAtom))->slot ==
|
setStringThis(str);
|
||||||
JSObject::JSSLOT_STRING_LENGTH);
|
|
||||||
|
|
||||||
setPrimitiveThis(js::StringValue(str));
|
|
||||||
JS_ASSERT(str->length() <= JSString::MAX_LENGTH);
|
|
||||||
setSlot(JSSLOT_STRING_LENGTH, js::Int32Value(int32(str->length())));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace js {
|
|
||||||
|
|
||||||
inline
|
inline
|
||||||
Shape::Shape(jsid id, js::PropertyOp getter, js::StrictPropertyOp setter, uint32 slot, uintN attrs,
|
Shape::Shape(jsid id, js::PropertyOp getter, js::StrictPropertyOp setter, uint32 slot, uintN attrs,
|
||||||
uintN flags, intN shortid, uint32 shape, uint32 slotSpan)
|
uintN flags, intN shortid, uint32 shape, uint32 slotSpan)
|
||||||
|
|
|
@ -68,7 +68,6 @@
|
||||||
#endif
|
#endif
|
||||||
#include "methodjit/MethodJIT.h"
|
#include "methodjit/MethodJIT.h"
|
||||||
|
|
||||||
#include "jsinterpinlines.h"
|
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
#include "jsscriptinlines.h"
|
#include "jsscriptinlines.h"
|
||||||
|
|
||||||
|
@ -1225,7 +1224,7 @@ JSScript::NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natom
|
||||||
|
|
||||||
script->compartment = cx->compartment;
|
script->compartment = cx->compartment;
|
||||||
#ifdef CHECK_SCRIPT_OWNER
|
#ifdef CHECK_SCRIPT_OWNER
|
||||||
script->owner = cx->thread;
|
script->owner = cx->thread();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
JS_APPEND_LINK(&script->links, &cx->compartment->scripts);
|
JS_APPEND_LINK(&script->links, &cx->compartment->scripts);
|
||||||
|
@ -1470,7 +1469,7 @@ DestroyScript(JSContext *cx, JSScript *script)
|
||||||
JS_PROPERTY_CACHE(cx).purgeForScript(cx, script);
|
JS_PROPERTY_CACHE(cx).purgeForScript(cx, script);
|
||||||
|
|
||||||
#ifdef CHECK_SCRIPT_OWNER
|
#ifdef CHECK_SCRIPT_OWNER
|
||||||
JS_ASSERT(script->owner == cx->thread);
|
JS_ASSERT(script->owner == cx->thread());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1646,7 +1645,7 @@ js_GetSrcNoteCached(JSContext *cx, JSScript *script, jsbytecode *pc)
|
||||||
}
|
}
|
||||||
|
|
||||||
uintN
|
uintN
|
||||||
js_FramePCToLineNumber(JSContext *cx, JSStackFrame *fp)
|
js_FramePCToLineNumber(JSContext *cx, StackFrame *fp)
|
||||||
{
|
{
|
||||||
return js_PCToLineNumber(cx, fp->script(),
|
return js_PCToLineNumber(cx, fp->script(),
|
||||||
fp->hasImacropc() ? fp->imacropc() : fp->pc(cx));
|
fp->hasImacropc() ? fp->imacropc() : fp->pc(cx));
|
||||||
|
@ -1662,7 +1661,7 @@ js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc)
|
||||||
jssrcnote *sn;
|
jssrcnote *sn;
|
||||||
JSSrcNoteType type;
|
JSSrcNoteType type;
|
||||||
|
|
||||||
/* Cope with JSStackFrame.pc value prior to entering js_Interpret. */
|
/* Cope with StackFrame.pc value prior to entering js_Interpret. */
|
||||||
if (!pc)
|
if (!pc)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -1767,12 +1766,12 @@ js_GetScriptLineExtent(JSScript *script)
|
||||||
const char *
|
const char *
|
||||||
js::CurrentScriptFileAndLineSlow(JSContext *cx, uintN *linenop)
|
js::CurrentScriptFileAndLineSlow(JSContext *cx, uintN *linenop)
|
||||||
{
|
{
|
||||||
if (!cx->hasfp()) {
|
if (!cx->running()) {
|
||||||
*linenop = 0;
|
*linenop = 0;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSStackFrame *fp = cx->fp();
|
StackFrame *fp = cx->fp();
|
||||||
while (fp->isDummyFrame())
|
while (fp->isDummyFrame())
|
||||||
fp = fp->prev();
|
fp = fp->prev();
|
||||||
|
|
||||||
|
|
|
@ -738,7 +738,7 @@ js_GetSrcNoteCached(JSContext *cx, JSScript *script, jsbytecode *pc);
|
||||||
* fp->imacpc may be non-null, indicating an active imacro.
|
* fp->imacpc may be non-null, indicating an active imacro.
|
||||||
*/
|
*/
|
||||||
extern uintN
|
extern uintN
|
||||||
js_FramePCToLineNumber(JSContext *cx, JSStackFrame *fp);
|
js_FramePCToLineNumber(JSContext *cx, js::StackFrame *fp);
|
||||||
|
|
||||||
extern uintN
|
extern uintN
|
||||||
js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc);
|
js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc);
|
||||||
|
|
|
@ -102,9 +102,9 @@ inline const char *
|
||||||
CurrentScriptFileAndLine(JSContext *cx, uintN *linenop, LineOption opt)
|
CurrentScriptFileAndLine(JSContext *cx, uintN *linenop, LineOption opt)
|
||||||
{
|
{
|
||||||
if (opt == CALLED_FROM_JSOP_EVAL) {
|
if (opt == CALLED_FROM_JSOP_EVAL) {
|
||||||
JS_ASSERT(*cx->regs->pc == JSOP_EVAL);
|
JS_ASSERT(*cx->regs().pc == JSOP_EVAL);
|
||||||
JS_ASSERT(*(cx->regs->pc + JSOP_EVAL_LENGTH) == JSOP_LINENO);
|
JS_ASSERT(*(cx->regs().pc + JSOP_EVAL_LENGTH) == JSOP_LINENO);
|
||||||
*linenop = GET_UINT16(cx->regs->pc + JSOP_EVAL_LENGTH);
|
*linenop = GET_UINT16(cx->regs().pc + JSOP_EVAL_LENGTH);
|
||||||
return cx->fp()->script()->filename;
|
return cx->fp()->script()->filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,13 +76,14 @@
|
||||||
#include "jsvector.h"
|
#include "jsvector.h"
|
||||||
#include "jsversion.h"
|
#include "jsversion.h"
|
||||||
|
|
||||||
#include "jscntxtinlines.h"
|
|
||||||
#include "jsinterpinlines.h"
|
#include "jsinterpinlines.h"
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
#include "jsregexpinlines.h"
|
#include "jsregexpinlines.h"
|
||||||
#include "jsstrinlines.h"
|
#include "jsstrinlines.h"
|
||||||
#include "jsautooplen.h" // generated headers last
|
#include "jsautooplen.h" // generated headers last
|
||||||
|
|
||||||
|
#include "vm/StringObject-inl.h"
|
||||||
|
|
||||||
using namespace js;
|
using namespace js;
|
||||||
using namespace js::gc;
|
using namespace js::gc;
|
||||||
|
|
||||||
|
@ -90,7 +91,7 @@ using namespace js::gc;
|
||||||
bool
|
bool
|
||||||
JSString::isShort() const
|
JSString::isShort() const
|
||||||
{
|
{
|
||||||
bool is_short = arena()->header()->thingKind == FINALIZE_SHORT_STRING;
|
bool is_short = arenaHeader()->getThingKind() == FINALIZE_SHORT_STRING;
|
||||||
JS_ASSERT_IF(is_short, isFlat());
|
JS_ASSERT_IF(is_short, isFlat());
|
||||||
return is_short;
|
return is_short;
|
||||||
}
|
}
|
||||||
|
@ -105,7 +106,7 @@ JSString::isFixed() const
|
||||||
bool
|
bool
|
||||||
JSString::isExternal() const
|
JSString::isExternal() const
|
||||||
{
|
{
|
||||||
bool is_external = arena()->header()->thingKind == FINALIZE_EXTERNAL_STRING;
|
bool is_external = arenaHeader()->getThingKind() == FINALIZE_EXTERNAL_STRING;
|
||||||
JS_ASSERT_IF(is_external, isFixed());
|
JS_ASSERT_IF(is_external, isFixed());
|
||||||
return is_external;
|
return is_external;
|
||||||
}
|
}
|
||||||
|
@ -750,7 +751,7 @@ str_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
||||||
|
|
||||||
Class js_StringClass = {
|
Class js_StringClass = {
|
||||||
js_String_str,
|
js_String_str,
|
||||||
JSCLASS_HAS_RESERVED_SLOTS(JSObject::STRING_RESERVED_SLOTS) |
|
JSCLASS_HAS_RESERVED_SLOTS(StringObject::RESERVED_SLOTS) |
|
||||||
JSCLASS_NEW_RESOLVE | JSCLASS_HAS_CACHED_PROTO(JSProto_String),
|
JSCLASS_NEW_RESOLVE | JSCLASS_HAS_CACHED_PROTO(JSProto_String),
|
||||||
PropertyStub, /* addProperty */
|
PropertyStub, /* addProperty */
|
||||||
PropertyStub, /* delProperty */
|
PropertyStub, /* delProperty */
|
||||||
|
@ -882,11 +883,8 @@ ValueToIntegerRange(JSContext *cx, const Value &v, int32 *out)
|
||||||
*out = v.toInt32();
|
*out = v.toInt32();
|
||||||
} else {
|
} else {
|
||||||
double d;
|
double d;
|
||||||
|
if (!ToInteger(cx, v, &d))
|
||||||
if (!ValueToNumber(cx, v, &d))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
d = js_DoubleToInteger(d);
|
|
||||||
if (d > INT32_MAX)
|
if (d > INT32_MAX)
|
||||||
*out = INT32_MAX;
|
*out = INT32_MAX;
|
||||||
else if (d < INT32_MIN)
|
else if (d < INT32_MIN)
|
||||||
|
@ -1086,14 +1084,9 @@ js_str_charAt(JSContext *cx, uintN argc, Value *vp)
|
||||||
if (!str)
|
if (!str)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
double d;
|
double d = 0.0;
|
||||||
if (argc == 0) {
|
if (argc > 0 && !ToInteger(cx, vp[2], &d))
|
||||||
d = 0.0;
|
return false;
|
||||||
} else {
|
|
||||||
if (!ValueToNumber(cx, vp[2], &d))
|
|
||||||
return false;
|
|
||||||
d = js_DoubleToInteger(d);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (d < 0 || str->length() <= d)
|
if (d < 0 || str->length() <= d)
|
||||||
goto out_of_range;
|
goto out_of_range;
|
||||||
|
@ -1126,14 +1119,9 @@ js_str_charCodeAt(JSContext *cx, uintN argc, Value *vp)
|
||||||
if (!str)
|
if (!str)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
double d;
|
double d = 0.0;
|
||||||
if (argc == 0) {
|
if (argc > 0 && !ToInteger(cx, vp[2], &d))
|
||||||
d = 0.0;
|
return false;
|
||||||
} else {
|
|
||||||
if (!ValueToNumber(cx, vp[2], &d))
|
|
||||||
return false;
|
|
||||||
d = js_DoubleToInteger(d);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (d < 0 || str->length() <= d)
|
if (d < 0 || str->length() <= d)
|
||||||
goto out_of_range;
|
goto out_of_range;
|
||||||
|
@ -1468,9 +1456,8 @@ str_indexOf(JSContext *cx, uintN argc, Value *vp)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
jsdouble d;
|
jsdouble d;
|
||||||
if (!ValueToNumber(cx, vp[3], &d))
|
if (!ToInteger(cx, vp[3], &d))
|
||||||
return JS_FALSE;
|
return false;
|
||||||
d = js_DoubleToInteger(d);
|
|
||||||
if (d <= 0) {
|
if (d <= 0) {
|
||||||
start = 0;
|
start = 0;
|
||||||
} else if (d > textlen) {
|
} else if (d > textlen) {
|
||||||
|
@ -2452,7 +2439,7 @@ str_replace_flat_lambda(JSContext *cx, uintN argc, Value *vp, ReplaceData &rdata
|
||||||
|
|
||||||
/* lambda(matchStr, matchStart, textstr) */
|
/* lambda(matchStr, matchStart, textstr) */
|
||||||
static const uint32 lambdaArgc = 3;
|
static const uint32 lambdaArgc = 3;
|
||||||
if (!cx->stack().pushInvokeArgs(cx, lambdaArgc, &rdata.singleShot))
|
if (!cx->stack.pushInvokeArgs(cx, lambdaArgc, &rdata.singleShot))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
CallArgs &args = rdata.singleShot;
|
CallArgs &args = rdata.singleShot;
|
||||||
|
@ -2464,7 +2451,7 @@ str_replace_flat_lambda(JSContext *cx, uintN argc, Value *vp, ReplaceData &rdata
|
||||||
sp[1].setInt32(fm.match());
|
sp[1].setInt32(fm.match());
|
||||||
sp[2].setString(rdata.str);
|
sp[2].setString(rdata.str);
|
||||||
|
|
||||||
if (!Invoke(cx, rdata.singleShot, 0))
|
if (!Invoke(cx, rdata.singleShot))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
JSString *repstr = js_ValueToString(cx, args.rval());
|
JSString *repstr = js_ValueToString(cx, args.rval());
|
||||||
|
@ -2995,9 +2982,8 @@ str_slice(JSContext *cx, uintN argc, Value *vp)
|
||||||
if (argc != 0) {
|
if (argc != 0) {
|
||||||
double begin, end, length;
|
double begin, end, length;
|
||||||
|
|
||||||
if (!ValueToNumber(cx, vp[2], &begin))
|
if (!ToInteger(cx, vp[2], &begin))
|
||||||
return JS_FALSE;
|
return false;
|
||||||
begin = js_DoubleToInteger(begin);
|
|
||||||
length = str->length();
|
length = str->length();
|
||||||
if (begin < 0) {
|
if (begin < 0) {
|
||||||
begin += length;
|
begin += length;
|
||||||
|
@ -3010,9 +2996,8 @@ str_slice(JSContext *cx, uintN argc, Value *vp)
|
||||||
if (argc == 1 || vp[3].isUndefined()) {
|
if (argc == 1 || vp[3].isUndefined()) {
|
||||||
end = length;
|
end = length;
|
||||||
} else {
|
} else {
|
||||||
if (!ValueToNumber(cx, vp[3], &end))
|
if (!ToInteger(cx, vp[3], &end))
|
||||||
return JS_FALSE;
|
return false;
|
||||||
end = js_DoubleToInteger(end);
|
|
||||||
if (end < 0) {
|
if (end < 0) {
|
||||||
end += length;
|
end += length;
|
||||||
if (end < 0)
|
if (end < 0)
|
||||||
|
@ -3471,10 +3456,10 @@ js_String(JSContext *cx, uintN argc, Value *vp)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsConstructing(vp)) {
|
if (IsConstructing(vp)) {
|
||||||
JSObject *obj = NewBuiltinClassInstance(cx, &js_StringClass);
|
StringObject *strobj = StringObject::create(cx, str);
|
||||||
if (!obj || !obj->initString(cx, str))
|
if (!strobj)
|
||||||
return false;
|
return false;
|
||||||
vp->setObject(*obj);
|
vp->setObject(*strobj);
|
||||||
} else {
|
} else {
|
||||||
vp->setString(str);
|
vp->setString(str);
|
||||||
}
|
}
|
||||||
|
@ -3538,14 +3523,13 @@ static JSFunctionSpec string_static_methods[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const Shape *
|
const Shape *
|
||||||
JSObject::assignInitialStringShape(JSContext *cx)
|
StringObject::assignInitialShape(JSContext *cx)
|
||||||
{
|
{
|
||||||
JS_ASSERT(!cx->compartment->initialStringShape);
|
JS_ASSERT(!cx->compartment->initialStringShape);
|
||||||
JS_ASSERT(isString());
|
|
||||||
JS_ASSERT(nativeEmpty());
|
JS_ASSERT(nativeEmpty());
|
||||||
|
|
||||||
return addDataProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom),
|
return addDataProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom),
|
||||||
JSSLOT_STRING_LENGTH, JSPROP_PERMANENT | JSPROP_READONLY);
|
LENGTH_SLOT, JSPROP_PERMANENT | JSPROP_READONLY);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject *
|
JSObject *
|
||||||
|
@ -3567,7 +3551,7 @@ js_InitStringClass(JSContext *cx, JSObject *global)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
JSObject *proto = NewObject<WithProto::Class>(cx, &js_StringClass, objectProto, global);
|
JSObject *proto = NewObject<WithProto::Class>(cx, &js_StringClass, objectProto, global);
|
||||||
if (!proto || !proto->initString(cx, cx->runtime->emptyString))
|
if (!proto || !proto->asString()->init(cx, cx->runtime->emptyString))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Now create the String function. */
|
/* Now create the String function. */
|
||||||
|
@ -3906,6 +3890,8 @@ js::ValueToStringBufferSlow(JSContext *cx, const Value &arg, StringBuffer &sb)
|
||||||
JS_FRIEND_API(JSString *)
|
JS_FRIEND_API(JSString *)
|
||||||
js_ValueToSource(JSContext *cx, const Value &v)
|
js_ValueToSource(JSContext *cx, const Value &v)
|
||||||
{
|
{
|
||||||
|
JS_CHECK_RECURSION(cx, return NULL);
|
||||||
|
|
||||||
if (v.isUndefined())
|
if (v.isUndefined())
|
||||||
return cx->runtime->atomState.void0Atom;
|
return cx->runtime->atomState.void0Atom;
|
||||||
if (v.isString())
|
if (v.isString())
|
||||||
|
|
|
@ -551,10 +551,10 @@ inline void
|
||||||
JSAtom::finalize(JSRuntime *rt)
|
JSAtom::finalize(JSRuntime *rt)
|
||||||
{
|
{
|
||||||
JS_ASSERT(isAtom());
|
JS_ASSERT(isAtom());
|
||||||
if (arena()->header()->thingKind == js::gc::FINALIZE_STRING)
|
if (arenaHeader()->getThingKind() == js::gc::FINALIZE_STRING)
|
||||||
asFlat().finalize(rt);
|
asFlat().finalize(rt);
|
||||||
else
|
else
|
||||||
JS_ASSERT(arena()->header()->thingKind == js::gc::FINALIZE_SHORT_STRING);
|
JS_ASSERT(arenaHeader()->getThingKind() == js::gc::FINALIZE_SHORT_STRING);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
|
|
136
js/src/jstl.h
136
js/src/jstl.h
|
@ -234,142 +234,6 @@ PointerRangeSize(T *begin, T *end)
|
||||||
return (size_t(end) - size_t(begin)) / sizeof(T);
|
return (size_t(end) - size_t(begin)) / sizeof(T);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* This utility pales in comparison to Boost's aligned_storage. The utility
|
|
||||||
* simply assumes that JSUint64 is enough alignment for anyone. This may need
|
|
||||||
* to be extended one day...
|
|
||||||
*
|
|
||||||
* As an important side effect, pulling the storage into this template is
|
|
||||||
* enough obfuscation to confuse gcc's strict-aliasing analysis into not giving
|
|
||||||
* false negatives when we cast from the char buffer to whatever type we've
|
|
||||||
* constructed using the bytes.
|
|
||||||
*/
|
|
||||||
template <size_t nbytes>
|
|
||||||
struct AlignedStorage
|
|
||||||
{
|
|
||||||
union U {
|
|
||||||
char bytes[nbytes];
|
|
||||||
uint64 _;
|
|
||||||
} u;
|
|
||||||
|
|
||||||
const void *addr() const { return u.bytes; }
|
|
||||||
void *addr() { return u.bytes; }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
struct AlignedStorage2
|
|
||||||
{
|
|
||||||
union U {
|
|
||||||
char bytes[sizeof(T)];
|
|
||||||
uint64 _;
|
|
||||||
} u;
|
|
||||||
|
|
||||||
const T *addr() const { return (const T *)u.bytes; }
|
|
||||||
T *addr() { return (T *)u.bytes; }
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Small utility for lazily constructing objects without using dynamic storage.
|
|
||||||
* When a LazilyConstructed<T> is constructed, it is |empty()|, i.e., no value
|
|
||||||
* of T has been constructed and no T destructor will be called when the
|
|
||||||
* LazilyConstructed<T> is destroyed. Upon calling |construct|, a T object will
|
|
||||||
* be constructed with the given arguments and that object will be destroyed
|
|
||||||
* when the owning LazilyConstructed<T> is destroyed.
|
|
||||||
*
|
|
||||||
* N.B. GCC seems to miss some optimizations with LazilyConstructed and may
|
|
||||||
* generate extra branches/loads/stores. Use with caution on hot paths.
|
|
||||||
*/
|
|
||||||
template <class T>
|
|
||||||
class LazilyConstructed
|
|
||||||
{
|
|
||||||
AlignedStorage2<T> storage;
|
|
||||||
bool constructed;
|
|
||||||
|
|
||||||
T &asT() { return *storage.addr(); }
|
|
||||||
|
|
||||||
explicit LazilyConstructed(const LazilyConstructed &other);
|
|
||||||
const LazilyConstructed &operator=(const LazilyConstructed &other);
|
|
||||||
|
|
||||||
public:
|
|
||||||
LazilyConstructed() { constructed = false; }
|
|
||||||
~LazilyConstructed() { if (constructed) asT().~T(); }
|
|
||||||
|
|
||||||
bool empty() const { return !constructed; }
|
|
||||||
|
|
||||||
void construct() {
|
|
||||||
JS_ASSERT(!constructed);
|
|
||||||
new(storage.addr()) T();
|
|
||||||
constructed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T1>
|
|
||||||
void construct(const T1 &t1) {
|
|
||||||
JS_ASSERT(!constructed);
|
|
||||||
new(storage.addr()) T(t1);
|
|
||||||
constructed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T1, class T2>
|
|
||||||
void construct(const T1 &t1, const T2 &t2) {
|
|
||||||
JS_ASSERT(!constructed);
|
|
||||||
new(storage.addr()) T(t1, t2);
|
|
||||||
constructed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T1, class T2, class T3>
|
|
||||||
void construct(const T1 &t1, const T2 &t2, const T3 &t3) {
|
|
||||||
JS_ASSERT(!constructed);
|
|
||||||
new(storage.addr()) T(t1, t2, t3);
|
|
||||||
constructed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T1, class T2, class T3, class T4>
|
|
||||||
void construct(const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4) {
|
|
||||||
JS_ASSERT(!constructed);
|
|
||||||
new(storage.addr()) T(t1, t2, t3, t4);
|
|
||||||
constructed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
T *addr() {
|
|
||||||
JS_ASSERT(constructed);
|
|
||||||
return &asT();
|
|
||||||
}
|
|
||||||
|
|
||||||
T &ref() {
|
|
||||||
JS_ASSERT(constructed);
|
|
||||||
return asT();
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroy() {
|
|
||||||
ref().~T();
|
|
||||||
constructed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroyIfConstructed() {
|
|
||||||
if (!empty())
|
|
||||||
destroy();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* N.B. GCC seems to miss some optimizations with Conditionally and may
|
|
||||||
* generate extra branches/loads/stores. Use with caution on hot paths.
|
|
||||||
*/
|
|
||||||
template <class T>
|
|
||||||
class Conditionally {
|
|
||||||
LazilyConstructed<T> t;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Conditionally(bool b) { if (b) t.construct(); }
|
|
||||||
|
|
||||||
template <class T1>
|
|
||||||
Conditionally(bool b, const T1 &t1) { if (b) t.construct(t1); }
|
|
||||||
|
|
||||||
template <class T1, class T2>
|
|
||||||
Conditionally(bool b, const T1 &t1, const T2 &t2) { if (b) t.construct(t1, t2); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
class AlignedPtrAndFlag
|
class AlignedPtrAndFlag
|
||||||
{
|
{
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -653,7 +653,7 @@ public:
|
||||||
JSScript *entryScript;
|
JSScript *entryScript;
|
||||||
|
|
||||||
/* The stack frame where we started profiling. Only valid while profiling! */
|
/* The stack frame where we started profiling. Only valid while profiling! */
|
||||||
JSStackFrame *entryfp;
|
StackFrame *entryfp;
|
||||||
|
|
||||||
/* The bytecode locations of the loop header and the back edge. */
|
/* The bytecode locations of the loop header and the back edge. */
|
||||||
jsbytecode *top, *bottom;
|
jsbytecode *top, *bottom;
|
||||||
|
@ -716,12 +716,12 @@ public:
|
||||||
* and how many iterations we execute it.
|
* and how many iterations we execute it.
|
||||||
*/
|
*/
|
||||||
struct InnerLoop {
|
struct InnerLoop {
|
||||||
JSStackFrame *entryfp;
|
StackFrame *entryfp;
|
||||||
jsbytecode *top, *bottom;
|
jsbytecode *top, *bottom;
|
||||||
uintN iters;
|
uintN iters;
|
||||||
|
|
||||||
InnerLoop() {}
|
InnerLoop() {}
|
||||||
InnerLoop(JSStackFrame *entryfp, jsbytecode *top, jsbytecode *bottom)
|
InnerLoop(StackFrame *entryfp, jsbytecode *top, jsbytecode *bottom)
|
||||||
: entryfp(entryfp), top(top), bottom(bottom), iters(0) {}
|
: entryfp(entryfp), top(top), bottom(bottom), iters(0) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -772,7 +772,7 @@ public:
|
||||||
return StackValue(false);
|
return StackValue(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
LoopProfile(TraceMonitor *tm, JSStackFrame *entryfp, jsbytecode *top, jsbytecode *bottom);
|
LoopProfile(TraceMonitor *tm, StackFrame *entryfp, jsbytecode *top, jsbytecode *bottom);
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
|
@ -1188,9 +1188,9 @@ class TraceRecorder
|
||||||
JS_REQUIRES_STACK ptrdiff_t nativespOffsetImpl(const void* p) const;
|
JS_REQUIRES_STACK ptrdiff_t nativespOffsetImpl(const void* p) const;
|
||||||
JS_REQUIRES_STACK ptrdiff_t nativespOffset(const Value* p) const;
|
JS_REQUIRES_STACK ptrdiff_t nativespOffset(const Value* p) const;
|
||||||
JS_REQUIRES_STACK void importImpl(tjit::Address addr, const void* p, JSValueType t,
|
JS_REQUIRES_STACK void importImpl(tjit::Address addr, const void* p, JSValueType t,
|
||||||
const char *prefix, uintN index, JSStackFrame *fp);
|
const char *prefix, uintN index, StackFrame *fp);
|
||||||
JS_REQUIRES_STACK void import(tjit::Address addr, const Value* p, JSValueType t,
|
JS_REQUIRES_STACK void import(tjit::Address addr, const Value* p, JSValueType t,
|
||||||
const char *prefix, uintN index, JSStackFrame *fp);
|
const char *prefix, uintN index, StackFrame *fp);
|
||||||
JS_REQUIRES_STACK void import(TreeFragment* tree, nanojit::LIns* sp, unsigned stackSlots,
|
JS_REQUIRES_STACK void import(TreeFragment* tree, nanojit::LIns* sp, unsigned stackSlots,
|
||||||
unsigned callDepth, unsigned ngslots, JSValueType* typeMap);
|
unsigned callDepth, unsigned ngslots, JSValueType* typeMap);
|
||||||
void trackNativeStackUse(unsigned slots);
|
void trackNativeStackUse(unsigned slots);
|
||||||
|
@ -1265,7 +1265,7 @@ class TraceRecorder
|
||||||
JS_REQUIRES_STACK nanojit::LIns* scopeChain();
|
JS_REQUIRES_STACK nanojit::LIns* scopeChain();
|
||||||
JS_REQUIRES_STACK nanojit::LIns* entryScopeChain() const;
|
JS_REQUIRES_STACK nanojit::LIns* entryScopeChain() const;
|
||||||
JS_REQUIRES_STACK nanojit::LIns* entryFrameIns() const;
|
JS_REQUIRES_STACK nanojit::LIns* entryFrameIns() const;
|
||||||
JS_REQUIRES_STACK JSStackFrame* frameIfInRange(JSObject* obj, unsigned* depthp = NULL) const;
|
JS_REQUIRES_STACK StackFrame* frameIfInRange(JSObject* obj, unsigned* depthp = NULL) const;
|
||||||
JS_REQUIRES_STACK RecordingStatus traverseScopeChain(JSObject *obj, nanojit::LIns *obj_ins, JSObject *obj2, nanojit::LIns *&obj2_ins);
|
JS_REQUIRES_STACK RecordingStatus traverseScopeChain(JSObject *obj, nanojit::LIns *obj_ins, JSObject *obj2, nanojit::LIns *&obj2_ins);
|
||||||
JS_REQUIRES_STACK AbortableRecordingStatus scopeChainProp(JSObject* obj, Value*& vp, nanojit::LIns*& ins, NameResult& nr, JSObject **scopeObjp = NULL);
|
JS_REQUIRES_STACK AbortableRecordingStatus scopeChainProp(JSObject* obj, Value*& vp, nanojit::LIns*& ins, NameResult& nr, JSObject **scopeObjp = NULL);
|
||||||
JS_REQUIRES_STACK RecordingStatus callProp(JSObject* obj, JSProperty* shape, jsid id, Value*& vp, nanojit::LIns*& ins, NameResult& nr);
|
JS_REQUIRES_STACK RecordingStatus callProp(JSObject* obj, JSProperty* shape, jsid id, Value*& vp, nanojit::LIns*& ins, NameResult& nr);
|
||||||
|
@ -1482,8 +1482,8 @@ class TraceRecorder
|
||||||
JS_REQUIRES_STACK RecordingStatus createThis(JSObject& ctor, nanojit::LIns* ctor_ins,
|
JS_REQUIRES_STACK RecordingStatus createThis(JSObject& ctor, nanojit::LIns* ctor_ins,
|
||||||
nanojit::LIns** thisobj_insp);
|
nanojit::LIns** thisobj_insp);
|
||||||
JS_REQUIRES_STACK RecordingStatus guardCallee(Value& callee);
|
JS_REQUIRES_STACK RecordingStatus guardCallee(Value& callee);
|
||||||
JS_REQUIRES_STACK JSStackFrame *guardArguments(JSObject *obj, nanojit::LIns* obj_ins,
|
JS_REQUIRES_STACK StackFrame *guardArguments(JSObject *obj, nanojit::LIns* obj_ins,
|
||||||
unsigned *depthp);
|
unsigned *depthp);
|
||||||
JS_REQUIRES_STACK nanojit::LIns* guardArgsLengthNotAssigned(nanojit::LIns* argsobj_ins);
|
JS_REQUIRES_STACK nanojit::LIns* guardArgsLengthNotAssigned(nanojit::LIns* argsobj_ins);
|
||||||
JS_REQUIRES_STACK void guardNotHole(nanojit::LIns* argsobj_ins, nanojit::LIns* ids_ins);
|
JS_REQUIRES_STACK void guardNotHole(nanojit::LIns* argsobj_ins, nanojit::LIns* ids_ins);
|
||||||
JS_REQUIRES_STACK RecordingStatus getClassPrototype(JSObject* ctor,
|
JS_REQUIRES_STACK RecordingStatus getClassPrototype(JSObject* ctor,
|
||||||
|
@ -1683,7 +1683,7 @@ class TraceRecorder
|
||||||
#define TRACE_2(x,a,b) TRACE_ARGS(x, (a, b))
|
#define TRACE_2(x,a,b) TRACE_ARGS(x, (a, b))
|
||||||
|
|
||||||
extern JS_REQUIRES_STACK MonitorResult
|
extern JS_REQUIRES_STACK MonitorResult
|
||||||
MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount, JSInterpMode interpMode);
|
MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount, InterpMode interpMode);
|
||||||
|
|
||||||
extern JS_REQUIRES_STACK TracePointAction
|
extern JS_REQUIRES_STACK TracePointAction
|
||||||
RecordTracePoint(JSContext*, uintN& inlineCallCount, bool* blacklist);
|
RecordTracePoint(JSContext*, uintN& inlineCallCount, bool* blacklist);
|
||||||
|
|
|
@ -1236,87 +1236,5 @@ Debug_SetValueRangeToCrashOnTouch(Value *vec, size_t len)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Abstracts the layout of the (callee,this) receiver pair that is passed to
|
|
||||||
* natives and scripted functions.
|
|
||||||
*/
|
|
||||||
class CallReceiver
|
|
||||||
{
|
|
||||||
#ifdef DEBUG
|
|
||||||
mutable bool usedRval_;
|
|
||||||
#endif
|
|
||||||
protected:
|
|
||||||
Value *argv_;
|
|
||||||
CallReceiver() {}
|
|
||||||
CallReceiver(Value *argv) : argv_(argv) {
|
|
||||||
#ifdef DEBUG
|
|
||||||
usedRval_ = false;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
friend CallReceiver CallReceiverFromVp(Value *);
|
|
||||||
friend CallReceiver CallReceiverFromArgv(Value *);
|
|
||||||
Value *base() const { return argv_ - 2; }
|
|
||||||
JSObject &callee() const { JS_ASSERT(!usedRval_); return argv_[-2].toObject(); }
|
|
||||||
Value &calleev() const { JS_ASSERT(!usedRval_); return argv_[-2]; }
|
|
||||||
Value &thisv() const { return argv_[-1]; }
|
|
||||||
|
|
||||||
Value &rval() const {
|
|
||||||
#ifdef DEBUG
|
|
||||||
usedRval_ = true;
|
|
||||||
#endif
|
|
||||||
return argv_[-2];
|
|
||||||
}
|
|
||||||
|
|
||||||
void calleeHasBeenReset() const {
|
|
||||||
#ifdef DEBUG
|
|
||||||
usedRval_ = false;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
JS_ALWAYS_INLINE CallReceiver
|
|
||||||
CallReceiverFromVp(Value *vp)
|
|
||||||
{
|
|
||||||
return CallReceiver(vp + 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_ALWAYS_INLINE CallReceiver
|
|
||||||
CallReceiverFromArgv(Value *argv)
|
|
||||||
{
|
|
||||||
return CallReceiver(argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Abstracts the layout of the stack passed to natives from the engine and from
|
|
||||||
* natives to js::Invoke.
|
|
||||||
*/
|
|
||||||
class CallArgs : public CallReceiver
|
|
||||||
{
|
|
||||||
uintN argc_;
|
|
||||||
protected:
|
|
||||||
CallArgs() {}
|
|
||||||
CallArgs(uintN argc, Value *argv) : CallReceiver(argv), argc_(argc) {}
|
|
||||||
public:
|
|
||||||
friend CallArgs CallArgsFromVp(uintN, Value *);
|
|
||||||
friend CallArgs CallArgsFromArgv(uintN, Value *);
|
|
||||||
Value &operator[](unsigned i) const { JS_ASSERT(i < argc_); return argv_[i]; }
|
|
||||||
Value *argv() const { return argv_; }
|
|
||||||
uintN argc() const { return argc_; }
|
|
||||||
};
|
|
||||||
|
|
||||||
JS_ALWAYS_INLINE CallArgs
|
|
||||||
CallArgsFromVp(uintN argc, Value *vp)
|
|
||||||
{
|
|
||||||
return CallArgs(argc, vp + 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_ALWAYS_INLINE CallArgs
|
|
||||||
CallArgsFromArgv(uintN argc, Value *argv)
|
|
||||||
{
|
|
||||||
return CallArgs(argc, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* namespace js */
|
} /* namespace js */
|
||||||
#endif /* jsvalue_h__ */
|
#endif /* jsvalue_h__ */
|
||||||
|
|
|
@ -385,7 +385,7 @@ AutoCompartment::enter()
|
||||||
JS_ASSERT(scopeChain->isNative());
|
JS_ASSERT(scopeChain->isNative());
|
||||||
|
|
||||||
frame.construct();
|
frame.construct();
|
||||||
if (!context->stack().pushDummyFrame(context, *scopeChain, &frame.ref())) {
|
if (!context->stack.pushDummyFrame(context, *scopeChain, &frame.ref())) {
|
||||||
context->compartment = origin;
|
context->compartment = origin;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,8 +164,8 @@ class AutoCompartment
|
||||||
JSObject * const target;
|
JSObject * const target;
|
||||||
JSCompartment * const destination;
|
JSCompartment * const destination;
|
||||||
private:
|
private:
|
||||||
LazilyConstructed<DummyFrameGuard> frame;
|
Maybe<DummyFrameGuard> frame;
|
||||||
JSFrameRegs regs;
|
FrameRegs regs;
|
||||||
AutoStringRooter input;
|
AutoStringRooter input;
|
||||||
bool entered;
|
bool entered;
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,6 @@
|
||||||
#include "jsfun.h"
|
#include "jsfun.h"
|
||||||
#include "jsgc.h"
|
#include "jsgc.h"
|
||||||
#include "jsgcmark.h"
|
#include "jsgcmark.h"
|
||||||
#include "jsinterp.h"
|
|
||||||
#include "jslock.h"
|
#include "jslock.h"
|
||||||
#include "jsnum.h"
|
#include "jsnum.h"
|
||||||
#include "jsobj.h"
|
#include "jsobj.h"
|
||||||
|
@ -72,11 +71,11 @@
|
||||||
#include "jsvector.h"
|
#include "jsvector.h"
|
||||||
|
|
||||||
#include "jsatominlines.h"
|
#include "jsatominlines.h"
|
||||||
#include "jscntxtinlines.h"
|
|
||||||
#include "jsinterpinlines.h"
|
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
#include "jsstrinlines.h"
|
#include "jsstrinlines.h"
|
||||||
|
|
||||||
|
#include "vm/Stack-inl.h"
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#include <string.h> /* for #ifdef DEBUG memset calls */
|
#include <string.h> /* for #ifdef DEBUG memset calls */
|
||||||
#endif
|
#endif
|
||||||
|
@ -1745,7 +1744,7 @@ ParseXMLSource(JSContext *cx, JSString *src)
|
||||||
filename = NULL;
|
filename = NULL;
|
||||||
lineno = 1;
|
lineno = 1;
|
||||||
if (!i.done()) {
|
if (!i.done()) {
|
||||||
JSStackFrame *fp = i.fp();
|
StackFrame *fp = i.fp();
|
||||||
op = (JSOp) *i.pc();
|
op = (JSOp) *i.pc();
|
||||||
if (op == JSOP_TOXML || op == JSOP_TOXMLLIST) {
|
if (op == JSOP_TOXML || op == JSOP_TOXMLLIST) {
|
||||||
filename = fp->script()->filename;
|
filename = fp->script()->filename;
|
||||||
|
@ -7307,8 +7306,7 @@ js_SetDefaultXMLNamespace(JSContext *cx, const Value &v)
|
||||||
if (!ns)
|
if (!ns)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
JSStackFrame *fp = js_GetTopStackFrame(cx);
|
JSObject &varobj = cx->stack.currentVarObj();
|
||||||
JSObject &varobj = fp->varobj(cx);
|
|
||||||
if (!varobj.defineProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, ObjectValue(*ns),
|
if (!varobj.defineProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, ObjectValue(*ns),
|
||||||
PropertyStub, StrictPropertyStub, JSPROP_PERMANENT)) {
|
PropertyStub, StrictPropertyStub, JSPROP_PERMANENT)) {
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
@ -7386,7 +7384,7 @@ js_ValueToXMLString(JSContext *cx, const Value &v)
|
||||||
JSBool
|
JSBool
|
||||||
js_GetAnyName(JSContext *cx, jsid *idp)
|
js_GetAnyName(JSContext *cx, jsid *idp)
|
||||||
{
|
{
|
||||||
JSObject *global = cx->hasfp() ? cx->fp()->scopeChain().getGlobal() : cx->globalObject;
|
JSObject *global = cx->running() ? cx->fp()->scopeChain().getGlobal() : cx->globalObject;
|
||||||
Value v = global->getReservedSlot(JSProto_AnyName);
|
Value v = global->getReservedSlot(JSProto_AnyName);
|
||||||
if (v.isUndefined()) {
|
if (v.isUndefined()) {
|
||||||
JSObject *obj = NewNonFunction<WithProto::Given>(cx, &js_AnyNameClass, NULL, global);
|
JSObject *obj = NewNonFunction<WithProto::Given>(cx, &js_AnyNameClass, NULL, global);
|
||||||
|
@ -7627,7 +7625,7 @@ js_StepXMLListFilter(JSContext *cx, JSBool initialized)
|
||||||
JSXMLFilter *filter;
|
JSXMLFilter *filter;
|
||||||
|
|
||||||
LeaveTrace(cx);
|
LeaveTrace(cx);
|
||||||
sp = Jsvalify(cx->regs->sp);
|
sp = Jsvalify(cx->regs().sp);
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
/*
|
/*
|
||||||
* We haven't iterated yet, so initialize the filter based on the
|
* We haven't iterated yet, so initialize the filter based on the
|
||||||
|
|
|
@ -589,7 +589,7 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::SparcRegist
|
||||||
if (frameDepth >= 0) {
|
if (frameDepth >= 0) {
|
||||||
// sp = fp->slots() + frameDepth
|
// sp = fp->slots() + frameDepth
|
||||||
// regs->sp = sp
|
// regs->sp = sp
|
||||||
addPtr(Imm32(sizeof(JSStackFrame) + frameDepth * sizeof(jsval)),
|
addPtr(Imm32(sizeof(StackFrame) + frameDepth * sizeof(jsval)),
|
||||||
JSFrameReg,
|
JSFrameReg,
|
||||||
ClobberInCall);
|
ClobberInCall);
|
||||||
storePtr(ClobberInCall, FrameAddress(offsetof(VMFrame, regs.sp)));
|
storePtr(ClobberInCall, FrameAddress(offsetof(VMFrame, regs.sp)));
|
||||||
|
@ -605,11 +605,11 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::SparcRegist
|
||||||
setupInfallibleVMFrame(frameDepth);
|
setupInfallibleVMFrame(frameDepth);
|
||||||
|
|
||||||
/* regs->fp = fp */
|
/* regs->fp = fp */
|
||||||
storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp)));
|
storePtr(JSFrameReg, FrameAddress(VMFrame::offsetOfFp));
|
||||||
|
|
||||||
/* PC -> regs->pc :( */
|
/* PC -> regs->pc :( */
|
||||||
storePtr(ImmPtr(pc),
|
storePtr(ImmPtr(pc),
|
||||||
FrameAddress(offsetof(VMFrame, regs) + offsetof(JSFrameRegs, pc)));
|
FrameAddress(offsetof(VMFrame, regs) + offsetof(FrameRegs, pc)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// An infallible VM call is a stub call (taking a VMFrame & and one
|
// An infallible VM call is a stub call (taking a VMFrame & and one
|
||||||
|
@ -753,7 +753,7 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = Assembler::JSPar
|
||||||
struct FrameFlagsAddress : JSC::MacroAssembler::Address
|
struct FrameFlagsAddress : JSC::MacroAssembler::Address
|
||||||
{
|
{
|
||||||
FrameFlagsAddress()
|
FrameFlagsAddress()
|
||||||
: Address(JSFrameReg, JSStackFrame::offsetOfFlags())
|
: Address(JSFrameReg, StackFrame::offsetOfFlags())
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,7 @@ static const char *OpcodeNames[] = {
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mjit::Compiler::Compiler(JSContext *cx, JSStackFrame *fp)
|
mjit::Compiler::Compiler(JSContext *cx, StackFrame *fp)
|
||||||
: BaseCompiler(cx),
|
: BaseCompiler(cx),
|
||||||
fp(fp),
|
fp(fp),
|
||||||
script(fp->script()),
|
script(fp->script()),
|
||||||
|
@ -239,7 +239,7 @@ mjit::Compiler::~Compiler()
|
||||||
}
|
}
|
||||||
|
|
||||||
CompileStatus JS_NEVER_INLINE
|
CompileStatus JS_NEVER_INLINE
|
||||||
mjit::TryCompile(JSContext *cx, JSStackFrame *fp)
|
mjit::TryCompile(JSContext *cx, StackFrame *fp)
|
||||||
{
|
{
|
||||||
JS_ASSERT(cx->fp() == fp);
|
JS_ASSERT(cx->fp() == fp);
|
||||||
|
|
||||||
|
@ -294,7 +294,7 @@ mjit::Compiler::generatePrologue()
|
||||||
Label fastPath = masm.label();
|
Label fastPath = masm.label();
|
||||||
|
|
||||||
/* Store this early on so slow paths can access it. */
|
/* Store this early on so slow paths can access it. */
|
||||||
masm.storePtr(ImmPtr(fun), Address(JSFrameReg, JSStackFrame::offsetOfExec()));
|
masm.storePtr(ImmPtr(fun), Address(JSFrameReg, StackFrame::offsetOfExec()));
|
||||||
|
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -312,8 +312,8 @@ mjit::Compiler::generatePrologue()
|
||||||
stubcc.masm.move(JSParamReg_Argc, Registers::ArgReg1);
|
stubcc.masm.move(JSParamReg_Argc, Registers::ArgReg1);
|
||||||
|
|
||||||
/* Slow path - call the arity check function. Returns new fp. */
|
/* Slow path - call the arity check function. Returns new fp. */
|
||||||
stubcc.masm.storePtr(ImmPtr(fun), Address(JSFrameReg, JSStackFrame::offsetOfExec()));
|
stubcc.masm.storePtr(ImmPtr(fun), Address(JSFrameReg, StackFrame::offsetOfExec()));
|
||||||
stubcc.masm.storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp)));
|
stubcc.masm.storePtr(JSFrameReg, FrameAddress(VMFrame::offsetOfFp));
|
||||||
OOL_STUBCALL(stubs::FixupArity);
|
OOL_STUBCALL(stubs::FixupArity);
|
||||||
stubcc.masm.move(Registers::ReturnReg, JSFrameReg);
|
stubcc.masm.move(Registers::ReturnReg, JSFrameReg);
|
||||||
stubcc.crossJump(stubcc.masm.jump(), fastPath);
|
stubcc.crossJump(stubcc.masm.jump(), fastPath);
|
||||||
|
@ -343,7 +343,7 @@ mjit::Compiler::generatePrologue()
|
||||||
*/
|
*/
|
||||||
for (uint32 i = 0; i < script->nfixed; i++) {
|
for (uint32 i = 0; i < script->nfixed; i++) {
|
||||||
if (analysis->localHasUseBeforeDef(i) || addTraceHints) {
|
if (analysis->localHasUseBeforeDef(i) || addTraceHints) {
|
||||||
Address local(JSFrameReg, sizeof(JSStackFrame) + i * sizeof(Value));
|
Address local(JSFrameReg, sizeof(StackFrame) + i * sizeof(Value));
|
||||||
masm.storeValue(UndefinedValue(), local);
|
masm.storeValue(UndefinedValue(), local);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -364,10 +364,11 @@ mjit::Compiler::generatePrologue()
|
||||||
*/
|
*/
|
||||||
RegisterID t0 = Registers::ReturnReg;
|
RegisterID t0 = Registers::ReturnReg;
|
||||||
Jump hasScope = masm.branchTest32(Assembler::NonZero,
|
Jump hasScope = masm.branchTest32(Assembler::NonZero,
|
||||||
FrameFlagsAddress(), Imm32(JSFRAME_HAS_SCOPECHAIN));
|
FrameFlagsAddress(),
|
||||||
masm.loadPayload(Address(JSFrameReg, JSStackFrame::offsetOfCallee(fun)), t0);
|
Imm32(StackFrame::HAS_SCOPECHAIN));
|
||||||
|
masm.loadPayload(Address(JSFrameReg, StackFrame::offsetOfCallee(fun)), t0);
|
||||||
masm.loadPtr(Address(t0, offsetof(JSObject, parent)), t0);
|
masm.loadPtr(Address(t0, offsetof(JSObject, parent)), t0);
|
||||||
masm.storePtr(t0, Address(JSFrameReg, JSStackFrame::offsetOfScopeChain()));
|
masm.storePtr(t0, Address(JSFrameReg, StackFrame::offsetOfScopeChain()));
|
||||||
hasScope.linkTo(masm.label(), &masm);
|
hasScope.linkTo(masm.label(), &masm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -968,12 +969,12 @@ mjit::Compiler::generateMethod()
|
||||||
{
|
{
|
||||||
RegisterID reg = frame.allocReg();
|
RegisterID reg = frame.allocReg();
|
||||||
masm.load32(FrameFlagsAddress(), reg);
|
masm.load32(FrameFlagsAddress(), reg);
|
||||||
masm.or32(Imm32(JSFRAME_HAS_RVAL), reg);
|
masm.or32(Imm32(StackFrame::HAS_RVAL), reg);
|
||||||
masm.store32(reg, FrameFlagsAddress());
|
masm.store32(reg, FrameFlagsAddress());
|
||||||
frame.freeReg(reg);
|
frame.freeReg(reg);
|
||||||
|
|
||||||
FrameEntry *fe = frame.peek(-1);
|
FrameEntry *fe = frame.peek(-1);
|
||||||
frame.storeTo(fe, Address(JSFrameReg, JSStackFrame::offsetOfReturnValue()), true);
|
frame.storeTo(fe, Address(JSFrameReg, StackFrame::offsetOfReturnValue()), true);
|
||||||
frame.pop();
|
frame.pop();
|
||||||
}
|
}
|
||||||
END_CASE(JSOP_POPV)
|
END_CASE(JSOP_POPV)
|
||||||
|
@ -2119,7 +2120,7 @@ mjit::Compiler::jsop_getglobal(uint32 index)
|
||||||
void
|
void
|
||||||
mjit::Compiler::emitFinalReturn(Assembler &masm)
|
mjit::Compiler::emitFinalReturn(Assembler &masm)
|
||||||
{
|
{
|
||||||
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfncode()), Registers::ReturnReg);
|
masm.loadPtr(Address(JSFrameReg, StackFrame::offsetOfNcode()), Registers::ReturnReg);
|
||||||
masm.jump(Registers::ReturnReg);
|
masm.jump(Registers::ReturnReg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2166,8 +2167,8 @@ mjit::Compiler::loadReturnValue(Assembler *masm, FrameEntry *fe)
|
||||||
if (analysis->usesReturnValue()) {
|
if (analysis->usesReturnValue()) {
|
||||||
Jump rvalClear = masm->branchTest32(Assembler::Zero,
|
Jump rvalClear = masm->branchTest32(Assembler::Zero,
|
||||||
FrameFlagsAddress(),
|
FrameFlagsAddress(),
|
||||||
Imm32(JSFRAME_HAS_RVAL));
|
Imm32(StackFrame::HAS_RVAL));
|
||||||
Address rvalAddress(JSFrameReg, JSStackFrame::offsetOfReturnValue());
|
Address rvalAddress(JSFrameReg, StackFrame::offsetOfReturnValue());
|
||||||
masm->loadValueAsComponents(rvalAddress, typeReg, dataReg);
|
masm->loadValueAsComponents(rvalAddress, typeReg, dataReg);
|
||||||
rvalClear.linkTo(masm->label(), masm);
|
rvalClear.linkTo(masm->label(), masm);
|
||||||
}
|
}
|
||||||
|
@ -2184,7 +2185,7 @@ mjit::Compiler::fixPrimitiveReturn(Assembler *masm, FrameEntry *fe)
|
||||||
JS_ASSERT(isConstructing);
|
JS_ASSERT(isConstructing);
|
||||||
|
|
||||||
bool ool = (masm != &this->masm);
|
bool ool = (masm != &this->masm);
|
||||||
Address thisv(JSFrameReg, JSStackFrame::offsetOfThis(fun));
|
Address thisv(JSFrameReg, StackFrame::offsetOfThis(fun));
|
||||||
|
|
||||||
// We can just load |thisv| if either of the following is true:
|
// We can just load |thisv| if either of the following is true:
|
||||||
// (1) There is no explicit return value, AND fp->rval is not used.
|
// (1) There is no explicit return value, AND fp->rval is not used.
|
||||||
|
@ -2256,8 +2257,8 @@ mjit::Compiler::emitReturn(FrameEntry *fe)
|
||||||
} else {
|
} else {
|
||||||
/* if (hasCallObj() || hasArgsObj()) */
|
/* if (hasCallObj() || hasArgsObj()) */
|
||||||
Jump putObjs = masm.branchTest32(Assembler::NonZero,
|
Jump putObjs = masm.branchTest32(Assembler::NonZero,
|
||||||
Address(JSFrameReg, JSStackFrame::offsetOfFlags()),
|
Address(JSFrameReg, StackFrame::offsetOfFlags()),
|
||||||
Imm32(JSFRAME_HAS_CALL_OBJ | JSFRAME_HAS_ARGS_OBJ));
|
Imm32(StackFrame::HAS_CALL_OBJ | StackFrame::HAS_ARGS_OBJ));
|
||||||
stubcc.linkExit(putObjs, Uses(frame.frameSlots()));
|
stubcc.linkExit(putObjs, Uses(frame.frameSlots()));
|
||||||
|
|
||||||
stubcc.leave();
|
stubcc.leave();
|
||||||
|
@ -2338,7 +2339,7 @@ mjit::Compiler::interruptCheckHelper()
|
||||||
* interrupt is on another thread.
|
* interrupt is on another thread.
|
||||||
*/
|
*/
|
||||||
stubcc.masm.loadPtr(FrameAddress(offsetof(VMFrame, cx)), reg);
|
stubcc.masm.loadPtr(FrameAddress(offsetof(VMFrame, cx)), reg);
|
||||||
stubcc.masm.loadPtr(Address(reg, offsetof(JSContext, thread)), reg);
|
stubcc.masm.loadPtr(Address(reg, JSContext::threadOffset()), reg);
|
||||||
Address flag(reg, offsetof(JSThread, data.interruptFlags));
|
Address flag(reg, offsetof(JSThread, data.interruptFlags));
|
||||||
Jump noInterrupt = stubcc.masm.branchTest32(Assembler::Zero, flag);
|
Jump noInterrupt = stubcc.masm.branchTest32(Assembler::Zero, flag);
|
||||||
#endif
|
#endif
|
||||||
|
@ -2377,16 +2378,16 @@ mjit::Compiler::emitUncachedCall(uint32 argc, bool callingNew)
|
||||||
|
|
||||||
Jump notCompiled = masm.branchTestPtr(Assembler::Zero, r0, r0);
|
Jump notCompiled = masm.branchTestPtr(Assembler::Zero, r0, r0);
|
||||||
|
|
||||||
masm.loadPtr(FrameAddress(offsetof(VMFrame, regs.fp)), JSFrameReg);
|
masm.loadPtr(FrameAddress(VMFrame::offsetOfFp), JSFrameReg);
|
||||||
callPatch.hasFastNcode = true;
|
callPatch.hasFastNcode = true;
|
||||||
callPatch.fastNcodePatch =
|
callPatch.fastNcodePatch =
|
||||||
masm.storePtrWithPatch(ImmPtr(NULL),
|
masm.storePtrWithPatch(ImmPtr(NULL),
|
||||||
Address(JSFrameReg, JSStackFrame::offsetOfncode()));
|
Address(JSFrameReg, StackFrame::offsetOfNcode()));
|
||||||
|
|
||||||
masm.jump(r0);
|
masm.jump(r0);
|
||||||
callPatch.joinPoint = masm.label();
|
callPatch.joinPoint = masm.label();
|
||||||
addReturnSite(callPatch.joinPoint, __LINE__);
|
addReturnSite(callPatch.joinPoint, __LINE__);
|
||||||
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfPrev()), JSFrameReg);
|
masm.loadPtr(Address(JSFrameReg, StackFrame::offsetOfPrev()), JSFrameReg);
|
||||||
|
|
||||||
frame.popn(argc + 2);
|
frame.popn(argc + 2);
|
||||||
frame.takeReg(JSReturnReg_Type);
|
frame.takeReg(JSReturnReg_Type);
|
||||||
|
@ -2460,8 +2461,8 @@ mjit::Compiler::checkCallApplySpeculation(uint32 callImmArgc, uint32 speculatedA
|
||||||
RegisterID r0 = Registers::ReturnReg;
|
RegisterID r0 = Registers::ReturnReg;
|
||||||
Jump notCompiled = stubcc.masm.branchTestPtr(Assembler::Zero, r0, r0);
|
Jump notCompiled = stubcc.masm.branchTestPtr(Assembler::Zero, r0, r0);
|
||||||
|
|
||||||
stubcc.masm.loadPtr(FrameAddress(offsetof(VMFrame, regs.fp)), JSFrameReg);
|
stubcc.masm.loadPtr(FrameAddress(VMFrame::offsetOfFp), JSFrameReg);
|
||||||
Address ncodeAddr(JSFrameReg, JSStackFrame::offsetOfncode());
|
Address ncodeAddr(JSFrameReg, StackFrame::offsetOfNcode());
|
||||||
uncachedCallPatch->hasSlowNcode = true;
|
uncachedCallPatch->hasSlowNcode = true;
|
||||||
uncachedCallPatch->slowNcodePatch = stubcc.masm.storePtrWithPatch(ImmPtr(NULL), ncodeAddr);
|
uncachedCallPatch->slowNcodePatch = stubcc.masm.storePtrWithPatch(ImmPtr(NULL), ncodeAddr);
|
||||||
|
|
||||||
|
@ -2731,11 +2732,11 @@ mjit::Compiler::inlineCallHelper(uint32 callImmArgc, bool callingNew)
|
||||||
stubcc.masm.move(Imm32(callIC.frameSize.staticArgc()), JSParamReg_Argc);
|
stubcc.masm.move(Imm32(callIC.frameSize.staticArgc()), JSParamReg_Argc);
|
||||||
else
|
else
|
||||||
stubcc.masm.load32(FrameAddress(offsetof(VMFrame, u.call.dynamicArgc)), JSParamReg_Argc);
|
stubcc.masm.load32(FrameAddress(offsetof(VMFrame, u.call.dynamicArgc)), JSParamReg_Argc);
|
||||||
stubcc.masm.loadPtr(FrameAddress(offsetof(VMFrame, regs.fp)), JSFrameReg);
|
stubcc.masm.loadPtr(FrameAddress(VMFrame::offsetOfFp), JSFrameReg);
|
||||||
callPatch.hasSlowNcode = true;
|
callPatch.hasSlowNcode = true;
|
||||||
callPatch.slowNcodePatch =
|
callPatch.slowNcodePatch =
|
||||||
stubcc.masm.storePtrWithPatch(ImmPtr(NULL),
|
stubcc.masm.storePtrWithPatch(ImmPtr(NULL),
|
||||||
Address(JSFrameReg, JSStackFrame::offsetOfncode()));
|
Address(JSFrameReg, StackFrame::offsetOfNcode()));
|
||||||
stubcc.masm.jump(Registers::ReturnReg);
|
stubcc.masm.jump(Registers::ReturnReg);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2764,7 +2765,7 @@ mjit::Compiler::inlineCallHelper(uint32 callImmArgc, bool callingNew)
|
||||||
|
|
||||||
uint32 flags = 0;
|
uint32 flags = 0;
|
||||||
if (callingNew)
|
if (callingNew)
|
||||||
flags |= JSFRAME_CONSTRUCTING;
|
flags |= StackFrame::CONSTRUCTING;
|
||||||
|
|
||||||
InlineFrameAssembler inlFrame(masm, callIC, flags);
|
InlineFrameAssembler inlFrame(masm, callIC, flags);
|
||||||
callPatch.hasFastNcode = true;
|
callPatch.hasFastNcode = true;
|
||||||
|
@ -2775,7 +2776,7 @@ mjit::Compiler::inlineCallHelper(uint32 callImmArgc, bool callingNew)
|
||||||
addReturnSite(callPatch.joinPoint, __LINE__);
|
addReturnSite(callPatch.joinPoint, __LINE__);
|
||||||
if (lowerFunCallOrApply)
|
if (lowerFunCallOrApply)
|
||||||
uncachedCallPatch.joinPoint = callIC.joinPoint;
|
uncachedCallPatch.joinPoint = callIC.joinPoint;
|
||||||
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfPrev()), JSFrameReg);
|
masm.loadPtr(Address(JSFrameReg, StackFrame::offsetOfPrev()), JSFrameReg);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We've placed hotJump, joinPoint and hotPathLabel, and no other labels are located by offset
|
* We've placed hotJump, joinPoint and hotPathLabel, and no other labels are located by offset
|
||||||
|
@ -2818,7 +2819,7 @@ mjit::Compiler::inlineCallHelper(uint32 callImmArgc, bool callingNew)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function must be called immediately after any instruction which could
|
* This function must be called immediately after any instruction which could
|
||||||
* cause a new JSStackFrame to be pushed and could lead to a new debug trap
|
* cause a new StackFrame to be pushed and could lead to a new debug trap
|
||||||
* being set. This includes any API callbacks and any scripted or native call.
|
* being set. This includes any API callbacks and any scripted or native call.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
|
@ -2830,7 +2831,7 @@ mjit::Compiler::addCallSite(const InternalCallSite &site)
|
||||||
void
|
void
|
||||||
mjit::Compiler::restoreFrameRegs(Assembler &masm)
|
mjit::Compiler::restoreFrameRegs(Assembler &masm)
|
||||||
{
|
{
|
||||||
masm.loadPtr(FrameAddress(offsetof(VMFrame, regs.fp)), JSFrameReg);
|
masm.loadPtr(FrameAddress(VMFrame::offsetOfFp), JSFrameReg);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -3163,7 +3164,7 @@ mjit::Compiler::jsop_callprop_generic(JSAtom *atom)
|
||||||
* since a sync will be needed for the upcoming call.
|
* since a sync will be needed for the upcoming call.
|
||||||
*/
|
*/
|
||||||
uint32 thisvSlot = frame.localSlots();
|
uint32 thisvSlot = frame.localSlots();
|
||||||
Address thisv = Address(JSFrameReg, sizeof(JSStackFrame) + thisvSlot * sizeof(Value));
|
Address thisv = Address(JSFrameReg, sizeof(StackFrame) + thisvSlot * sizeof(Value));
|
||||||
|
|
||||||
#if defined JS_NUNBOX32
|
#if defined JS_NUNBOX32
|
||||||
masm.storeValueFromComponents(pic.typeReg, pic.objReg, thisv);
|
masm.storeValueFromComponents(pic.typeReg, pic.objReg, thisv);
|
||||||
|
@ -3622,7 +3623,7 @@ mjit::Compiler::jsop_bindname(JSAtom *atom, bool usePropCache)
|
||||||
pic.fastPathStart = masm.label();
|
pic.fastPathStart = masm.label();
|
||||||
|
|
||||||
Address parent(pic.objReg, offsetof(JSObject, parent));
|
Address parent(pic.objReg, offsetof(JSObject, parent));
|
||||||
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfScopeChain()), pic.objReg);
|
masm.loadPtr(Address(JSFrameReg, StackFrame::offsetOfScopeChain()), pic.objReg);
|
||||||
|
|
||||||
pic.shapeGuard = masm.label();
|
pic.shapeGuard = masm.label();
|
||||||
Jump inlineJump = masm.branchPtr(Assembler::NotEqual, parent, ImmPtr(0));
|
Jump inlineJump = masm.branchPtr(Assembler::NotEqual, parent, ImmPtr(0));
|
||||||
|
@ -3689,7 +3690,7 @@ void
|
||||||
mjit::Compiler::jsop_bindname(JSAtom *atom, bool usePropCache)
|
mjit::Compiler::jsop_bindname(JSAtom *atom, bool usePropCache)
|
||||||
{
|
{
|
||||||
RegisterID reg = frame.allocReg();
|
RegisterID reg = frame.allocReg();
|
||||||
Address scopeChain(JSFrameReg, JSStackFrame::offsetOfScopeChain());
|
Address scopeChain(JSFrameReg, StackFrame::offsetOfScopeChain());
|
||||||
masm.loadPtr(scopeChain, reg);
|
masm.loadPtr(scopeChain, reg);
|
||||||
|
|
||||||
Address address(reg, offsetof(JSObject, parent));
|
Address address(reg, offsetof(JSObject, parent));
|
||||||
|
|
|
@ -326,7 +326,7 @@ class Compiler : public BaseCompiler
|
||||||
size_t offsetIndex;
|
size_t offsetIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
JSStackFrame *fp;
|
StackFrame *fp;
|
||||||
JSScript *script;
|
JSScript *script;
|
||||||
JSObject *scopeChain;
|
JSObject *scopeChain;
|
||||||
JSObject *globalObj;
|
JSObject *globalObj;
|
||||||
|
@ -372,7 +372,7 @@ class Compiler : public BaseCompiler
|
||||||
// follows interpreter usage in JSOP_LENGTH.
|
// follows interpreter usage in JSOP_LENGTH.
|
||||||
enum { LengthAtomIndex = uint32(-2) };
|
enum { LengthAtomIndex = uint32(-2) };
|
||||||
|
|
||||||
Compiler(JSContext *cx, JSStackFrame *fp);
|
Compiler(JSContext *cx, StackFrame *fp);
|
||||||
~Compiler();
|
~Compiler();
|
||||||
|
|
||||||
CompileStatus compile();
|
CompileStatus compile();
|
||||||
|
|
|
@ -733,13 +733,13 @@ FrameState::addressOf(const FrameEntry *fe) const
|
||||||
{
|
{
|
||||||
int32 frameOffset = 0;
|
int32 frameOffset = 0;
|
||||||
if (fe >= locals)
|
if (fe >= locals)
|
||||||
frameOffset = JSStackFrame::offsetOfFixed(uint32(fe - locals));
|
frameOffset = StackFrame::offsetOfFixed(uint32(fe - locals));
|
||||||
else if (fe >= args)
|
else if (fe >= args)
|
||||||
frameOffset = JSStackFrame::offsetOfFormalArg(fun, uint32(fe - args));
|
frameOffset = StackFrame::offsetOfFormalArg(fun, uint32(fe - args));
|
||||||
else if (fe == this_)
|
else if (fe == this_)
|
||||||
frameOffset = JSStackFrame::offsetOfThis(fun);
|
frameOffset = StackFrame::offsetOfThis(fun);
|
||||||
else if (fe == callee_)
|
else if (fe == callee_)
|
||||||
frameOffset = JSStackFrame::offsetOfCallee(fun);
|
frameOffset = StackFrame::offsetOfCallee(fun);
|
||||||
JS_ASSERT(frameOffset);
|
JS_ASSERT(frameOffset);
|
||||||
return Address(JSFrameReg, frameOffset);
|
return Address(JSFrameReg, frameOffset);
|
||||||
}
|
}
|
||||||
|
|
|
@ -741,13 +741,13 @@ class FrameState
|
||||||
void assertValidRegisterState() const;
|
void assertValidRegisterState() const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Return an address, relative to the JSStackFrame, that represents where
|
// Return an address, relative to the StackFrame, that represents where
|
||||||
// this FrameEntry is stored in memory. Note that this is its canonical
|
// this FrameEntry is stored in memory. Note that this is its canonical
|
||||||
// address, not its backing store. There is no guarantee that the memory
|
// address, not its backing store. There is no guarantee that the memory
|
||||||
// is coherent.
|
// is coherent.
|
||||||
Address addressOf(const FrameEntry *fe) const;
|
Address addressOf(const FrameEntry *fe) const;
|
||||||
|
|
||||||
// Returns an address, relative to the JSStackFrame, that represents where
|
// Returns an address, relative to the StackFrame, that represents where
|
||||||
// this FrameEntry is backed in memory. This is not necessarily its
|
// this FrameEntry is backed in memory. This is not necessarily its
|
||||||
// canonical address, but the address for which the payload has been synced
|
// canonical address, but the address for which the payload has been synced
|
||||||
// to memory. The caller guarantees that the payload has been synced.
|
// to memory. The caller guarantees that the payload has been synced.
|
||||||
|
|
|
@ -62,7 +62,7 @@ struct AdjustedFrame {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is used for emitting code to inline callee-side frame creation and
|
* This is used for emitting code to inline callee-side frame creation and
|
||||||
* should jit code equivalent to JSStackFrame::initCallFrameCallerHalf.
|
* should jit code equivalent to StackFrame::initCallFrameCallerHalf.
|
||||||
*
|
*
|
||||||
* Once finished, JSFrameReg is advanced to be the new fp.
|
* Once finished, JSFrameReg is advanced to be the new fp.
|
||||||
*/
|
*/
|
||||||
|
@ -105,23 +105,23 @@ class InlineFrameAssembler {
|
||||||
|
|
||||||
DataLabelPtr assemble(void *ncode)
|
DataLabelPtr assemble(void *ncode)
|
||||||
{
|
{
|
||||||
JS_ASSERT((flags & ~JSFRAME_CONSTRUCTING) == 0);
|
JS_ASSERT((flags & ~StackFrame::CONSTRUCTING) == 0);
|
||||||
|
|
||||||
/* Generate JSStackFrame::initCallFrameCallerHalf. */
|
/* Generate StackFrame::initCallFrameCallerHalf. */
|
||||||
|
|
||||||
DataLabelPtr ncodePatch;
|
DataLabelPtr ncodePatch;
|
||||||
if (frameSize.isStatic()) {
|
if (frameSize.isStatic()) {
|
||||||
uint32 frameDepth = frameSize.staticLocalSlots();
|
uint32 frameDepth = frameSize.staticLocalSlots();
|
||||||
AdjustedFrame newfp(sizeof(JSStackFrame) + frameDepth * sizeof(Value));
|
AdjustedFrame newfp(sizeof(StackFrame) + frameDepth * sizeof(Value));
|
||||||
|
|
||||||
Address flagsAddr = newfp.addrOf(JSStackFrame::offsetOfFlags());
|
Address flagsAddr = newfp.addrOf(StackFrame::offsetOfFlags());
|
||||||
masm.store32(Imm32(JSFRAME_FUNCTION | flags), flagsAddr);
|
masm.store32(Imm32(StackFrame::FUNCTION | flags), flagsAddr);
|
||||||
Address prevAddr = newfp.addrOf(JSStackFrame::offsetOfPrev());
|
Address prevAddr = newfp.addrOf(StackFrame::offsetOfPrev());
|
||||||
masm.storePtr(JSFrameReg, prevAddr);
|
masm.storePtr(JSFrameReg, prevAddr);
|
||||||
Address ncodeAddr = newfp.addrOf(JSStackFrame::offsetOfncode());
|
Address ncodeAddr = newfp.addrOf(StackFrame::offsetOfNcode());
|
||||||
ncodePatch = masm.storePtrWithPatch(ImmPtr(ncode), ncodeAddr);
|
ncodePatch = masm.storePtrWithPatch(ImmPtr(ncode), ncodeAddr);
|
||||||
|
|
||||||
masm.addPtr(Imm32(sizeof(JSStackFrame) + frameDepth * sizeof(Value)), JSFrameReg);
|
masm.addPtr(Imm32(sizeof(StackFrame) + frameDepth * sizeof(Value)), JSFrameReg);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* If the frame size is dynamic, then the fast path generated by
|
* If the frame size is dynamic, then the fast path generated by
|
||||||
|
@ -134,11 +134,11 @@ class InlineFrameAssembler {
|
||||||
RegisterID newfp = tempRegs.takeAnyReg();
|
RegisterID newfp = tempRegs.takeAnyReg();
|
||||||
masm.loadPtr(FrameAddress(offsetof(VMFrame, regs.sp)), newfp);
|
masm.loadPtr(FrameAddress(offsetof(VMFrame, regs.sp)), newfp);
|
||||||
|
|
||||||
Address flagsAddr(newfp, JSStackFrame::offsetOfFlags());
|
Address flagsAddr(newfp, StackFrame::offsetOfFlags());
|
||||||
masm.store32(Imm32(JSFRAME_FUNCTION | flags), flagsAddr);
|
masm.store32(Imm32(StackFrame::FUNCTION | flags), flagsAddr);
|
||||||
Address prevAddr(newfp, JSStackFrame::offsetOfPrev());
|
Address prevAddr(newfp, StackFrame::offsetOfPrev());
|
||||||
masm.storePtr(JSFrameReg, prevAddr);
|
masm.storePtr(JSFrameReg, prevAddr);
|
||||||
Address ncodeAddr(newfp, JSStackFrame::offsetOfncode());
|
Address ncodeAddr(newfp, StackFrame::offsetOfNcode());
|
||||||
ncodePatch = masm.storePtrWithPatch(ImmPtr(ncode), ncodeAddr);
|
ncodePatch = masm.storePtrWithPatch(ImmPtr(ncode), ncodeAddr);
|
||||||
|
|
||||||
masm.move(newfp, JSFrameReg);
|
masm.move(newfp, JSFrameReg);
|
||||||
|
|
|
@ -81,13 +81,13 @@ using ic::Repatcher;
|
||||||
static jsbytecode *
|
static jsbytecode *
|
||||||
FindExceptionHandler(JSContext *cx)
|
FindExceptionHandler(JSContext *cx)
|
||||||
{
|
{
|
||||||
JSStackFrame *fp = cx->fp();
|
StackFrame *fp = cx->fp();
|
||||||
JSScript *script = fp->script();
|
JSScript *script = fp->script();
|
||||||
|
|
||||||
top:
|
top:
|
||||||
if (cx->isExceptionPending() && JSScript::isValidOffset(script->trynotesOffset)) {
|
if (cx->isExceptionPending() && JSScript::isValidOffset(script->trynotesOffset)) {
|
||||||
// The PC is updated before every stub call, so we can use it here.
|
// The PC is updated before every stub call, so we can use it here.
|
||||||
unsigned offset = cx->regs->pc - script->main;
|
unsigned offset = cx->regs().pc - script->main;
|
||||||
|
|
||||||
JSTryNoteArray *tnarray = script->trynotes();
|
JSTryNoteArray *tnarray = script->trynotes();
|
||||||
for (unsigned i = 0; i < tnarray->length; ++i) {
|
for (unsigned i = 0; i < tnarray->length; ++i) {
|
||||||
|
@ -110,12 +110,12 @@ top:
|
||||||
// bytecode compiler cannot throw, so this is not possible.
|
// bytecode compiler cannot throw, so this is not possible.
|
||||||
if (offset - tn->start > tn->length)
|
if (offset - tn->start > tn->length)
|
||||||
continue;
|
continue;
|
||||||
if (tn->stackDepth > cx->regs->sp - fp->base())
|
if (tn->stackDepth > cx->regs().sp - fp->base())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
jsbytecode *pc = script->main + tn->start + tn->length;
|
jsbytecode *pc = script->main + tn->start + tn->length;
|
||||||
JSBool ok = js_UnwindScope(cx, tn->stackDepth, JS_TRUE);
|
JSBool ok = js_UnwindScope(cx, tn->stackDepth, JS_TRUE);
|
||||||
JS_ASSERT(cx->regs->sp == fp->base() + tn->stackDepth);
|
JS_ASSERT(cx->regs().sp == fp->base() + tn->stackDepth);
|
||||||
|
|
||||||
switch (tn->kind) {
|
switch (tn->kind) {
|
||||||
case JSTRY_CATCH:
|
case JSTRY_CATCH:
|
||||||
|
@ -139,9 +139,9 @@ top:
|
||||||
* Push (true, exception) pair for finally to indicate that
|
* Push (true, exception) pair for finally to indicate that
|
||||||
* [retsub] should rethrow the exception.
|
* [retsub] should rethrow the exception.
|
||||||
*/
|
*/
|
||||||
cx->regs->sp[0].setBoolean(true);
|
cx->regs().sp[0].setBoolean(true);
|
||||||
cx->regs->sp[1] = cx->getPendingException();
|
cx->regs().sp[1] = cx->getPendingException();
|
||||||
cx->regs->sp += 2;
|
cx->regs().sp += 2;
|
||||||
cx->clearPendingException();
|
cx->clearPendingException();
|
||||||
return pc;
|
return pc;
|
||||||
|
|
||||||
|
@ -157,8 +157,8 @@ top:
|
||||||
Value v = cx->getPendingException();
|
Value v = cx->getPendingException();
|
||||||
JS_ASSERT(js_GetOpcode(cx, fp->script(), pc) == JSOP_ENDITER);
|
JS_ASSERT(js_GetOpcode(cx, fp->script(), pc) == JSOP_ENDITER);
|
||||||
cx->clearPendingException();
|
cx->clearPendingException();
|
||||||
ok = !!js_CloseIterator(cx, &cx->regs->sp[-1].toObject());
|
ok = !!js_CloseIterator(cx, &cx->regs().sp[-1].toObject());
|
||||||
cx->regs->sp -= 1;
|
cx->regs().sp -= 1;
|
||||||
if (!ok)
|
if (!ok)
|
||||||
goto top;
|
goto top;
|
||||||
cx->setPendingException(v);
|
cx->setPendingException(v);
|
||||||
|
@ -176,16 +176,9 @@ top:
|
||||||
static void
|
static void
|
||||||
InlineReturn(VMFrame &f)
|
InlineReturn(VMFrame &f)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
|
||||||
JSStackFrame *fp = f.regs.fp;
|
|
||||||
|
|
||||||
JS_ASSERT(f.fp() != f.entryfp);
|
JS_ASSERT(f.fp() != f.entryfp);
|
||||||
|
JS_ASSERT(!js_IsActiveWithOrBlock(f.cx, &f.fp()->scopeChain(), 0));
|
||||||
JS_ASSERT(!js_IsActiveWithOrBlock(cx, &fp->scopeChain(), 0));
|
f.cx->stack.popInlineFrame();
|
||||||
|
|
||||||
Value *newsp = fp->actualArgs() - 1;
|
|
||||||
newsp[-1] = fp->returnValue();
|
|
||||||
cx->stack().popInlineFrame(cx, fp->prev(), newsp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
|
@ -193,7 +186,7 @@ stubs::SlowCall(VMFrame &f, uint32 argc)
|
||||||
{
|
{
|
||||||
Value *vp = f.regs.sp - (argc + 2);
|
Value *vp = f.regs.sp - (argc + 2);
|
||||||
|
|
||||||
if (!Invoke(f.cx, InvokeArgsAlreadyOnTheStack(vp, argc), 0))
|
if (!Invoke(f.cx, InvokeArgsAlreadyOnTheStack(argc, vp)))
|
||||||
THROW();
|
THROW();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,7 +196,7 @@ stubs::SlowNew(VMFrame &f, uint32 argc)
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
Value *vp = f.regs.sp - (argc + 2);
|
Value *vp = f.regs.sp - (argc + 2);
|
||||||
|
|
||||||
if (!InvokeConstructor(cx, InvokeArgsAlreadyOnTheStack(vp, argc)))
|
if (!InvokeConstructor(cx, InvokeArgsAlreadyOnTheStack(argc, vp)))
|
||||||
THROW();
|
THROW();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,11 +205,9 @@ stubs::SlowNew(VMFrame &f, uint32 argc)
|
||||||
* on fp->exec.fun.
|
* on fp->exec.fun.
|
||||||
*/
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
RemovePartialFrame(JSContext *cx, JSStackFrame *fp)
|
RemovePartialFrame(JSContext *cx, StackFrame *fp)
|
||||||
{
|
{
|
||||||
JSStackFrame *prev = fp->prev();
|
cx->stack.popInlineFrame();
|
||||||
Value *newsp = (Value *)fp;
|
|
||||||
cx->stack().popInlineFrame(cx, prev, newsp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -229,7 +220,8 @@ stubs::HitStackQuota(VMFrame &f)
|
||||||
/* Include space to push another frame. */
|
/* Include space to push another frame. */
|
||||||
uintN nvals = f.fp()->script()->nslots + VALUES_PER_STACK_FRAME;
|
uintN nvals = f.fp()->script()->nslots + VALUES_PER_STACK_FRAME;
|
||||||
JS_ASSERT(f.regs.sp == f.fp()->base());
|
JS_ASSERT(f.regs.sp == f.fp()->base());
|
||||||
if (f.cx->stack().bumpCommitAndLimit(f.entryfp, f.regs.sp, nvals, &f.stackLimit))
|
StackSpace &space = f.cx->stack.space();
|
||||||
|
if (space.bumpLimitWithinQuota(NULL, f.entryfp, f.regs.sp, nvals, &f.stackLimit))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Remove the current partially-constructed frame before throwing. */
|
/* Remove the current partially-constructed frame before throwing. */
|
||||||
|
@ -246,7 +238,7 @@ void * JS_FASTCALL
|
||||||
stubs::FixupArity(VMFrame &f, uint32 nactual)
|
stubs::FixupArity(VMFrame &f, uint32 nactual)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSStackFrame *oldfp = f.fp();
|
StackFrame *oldfp = f.fp();
|
||||||
|
|
||||||
JS_ASSERT(nactual != oldfp->numFormalArgs());
|
JS_ASSERT(nactual != oldfp->numFormalArgs());
|
||||||
|
|
||||||
|
@ -261,13 +253,12 @@ stubs::FixupArity(VMFrame &f, uint32 nactual)
|
||||||
void *ncode = oldfp->nativeReturnAddress();
|
void *ncode = oldfp->nativeReturnAddress();
|
||||||
|
|
||||||
/* Pop the inline frame. */
|
/* Pop the inline frame. */
|
||||||
f.fp() = oldfp->prev();
|
f.regs.popPartialFrame((Value *)oldfp);
|
||||||
f.regs.sp = (Value*) oldfp;
|
|
||||||
|
|
||||||
/* Reserve enough space for a callee frame. */
|
/* Reserve enough space for a callee frame. */
|
||||||
JSStackFrame *newfp = cx->stack().getInlineFrameWithinLimit(cx, (Value*) oldfp, nactual,
|
StackFrame *newfp = cx->stack.getInlineFrameWithinLimit(cx, (Value*) oldfp, nactual,
|
||||||
fun, fun->script(), &flags,
|
fun, fun->script(), &flags,
|
||||||
f.entryfp, &f.stackLimit);
|
f.entryfp, &f.stackLimit);
|
||||||
if (!newfp) {
|
if (!newfp) {
|
||||||
/*
|
/*
|
||||||
* The PC is not coherent with the current frame, so fix it up for
|
* The PC is not coherent with the current frame, so fix it up for
|
||||||
|
@ -295,7 +286,7 @@ stubs::CompileFunction(VMFrame &f, uint32 nactual)
|
||||||
* compile though because we could throw, so get a full, adjusted frame.
|
* compile though because we could throw, so get a full, adjusted frame.
|
||||||
*/
|
*/
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSStackFrame *fp = f.fp();
|
StackFrame *fp = f.fp();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since we can only use members set by initCallFrameCallerHalf,
|
* Since we can only use members set by initCallFrameCallerHalf,
|
||||||
|
@ -312,7 +303,7 @@ stubs::CompileFunction(VMFrame &f, uint32 nactual)
|
||||||
fp->initCallFrameEarlyPrologue(fun, nactual);
|
fp->initCallFrameEarlyPrologue(fun, nactual);
|
||||||
|
|
||||||
if (nactual != fp->numFormalArgs()) {
|
if (nactual != fp->numFormalArgs()) {
|
||||||
fp = (JSStackFrame *)FixupArity(f, nactual);
|
fp = (StackFrame *)FixupArity(f, nactual);
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -321,9 +312,7 @@ stubs::CompileFunction(VMFrame &f, uint32 nactual)
|
||||||
fp->initCallFrameLatePrologue();
|
fp->initCallFrameLatePrologue();
|
||||||
|
|
||||||
/* These would have been initialized by the prologue. */
|
/* These would have been initialized by the prologue. */
|
||||||
f.regs.fp = fp;
|
f.regs.prepareToRun(fp, script);
|
||||||
f.regs.sp = fp->base();
|
|
||||||
f.regs.pc = script->code;
|
|
||||||
|
|
||||||
if (fun->isHeavyweight() && !js::CreateFunCallObject(cx, fp))
|
if (fun->isHeavyweight() && !js::CreateFunCallObject(cx, fp))
|
||||||
THROWV(NULL);
|
THROWV(NULL);
|
||||||
|
@ -352,10 +341,9 @@ UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, bool *unjittable, uint
|
||||||
JSScript *newscript = newfun->script();
|
JSScript *newscript = newfun->script();
|
||||||
|
|
||||||
/* Get pointer to new frame/slots, prepare arguments. */
|
/* Get pointer to new frame/slots, prepare arguments. */
|
||||||
StackSpace &stack = cx->stack();
|
StackFrame *newfp = cx->stack.getInlineFrameWithinLimit(cx, f.regs.sp, argc,
|
||||||
JSStackFrame *newfp = stack.getInlineFrameWithinLimit(cx, f.regs.sp, argc,
|
newfun, newscript, &flags,
|
||||||
newfun, newscript, &flags,
|
f.entryfp, &f.stackLimit);
|
||||||
f.entryfp, &f.stackLimit);
|
|
||||||
if (JS_UNLIKELY(!newfp))
|
if (JS_UNLIKELY(!newfp))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -364,8 +352,8 @@ UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, bool *unjittable, uint
|
||||||
SetValueRangeToUndefined(newfp->slots(), newscript->nfixed);
|
SetValueRangeToUndefined(newfp->slots(), newscript->nfixed);
|
||||||
|
|
||||||
/* Officially push the frame. */
|
/* Officially push the frame. */
|
||||||
stack.pushInlineFrame(cx, newscript, newfp, &f.regs);
|
cx->stack.pushInlineFrame(newscript, newfp, f.regs);
|
||||||
JS_ASSERT(newfp == f.regs.fp);
|
JS_ASSERT(newfp == f.fp());
|
||||||
|
|
||||||
/* Scope with a call object parented by callee's parent. */
|
/* Scope with a call object parented by callee's parent. */
|
||||||
if (newfun->isHeavyweight() && !js::CreateFunCallObject(cx, newfp))
|
if (newfun->isHeavyweight() && !js::CreateFunCallObject(cx, newfp))
|
||||||
|
@ -414,10 +402,10 @@ stubs::UncachedNewHelper(VMFrame &f, uint32 argc, UncachedCallResult *ucr)
|
||||||
/* Try to do a fast inline call before the general Invoke path. */
|
/* Try to do a fast inline call before the general Invoke path. */
|
||||||
if (IsFunctionObject(*vp, &ucr->fun) && ucr->fun->isInterpretedConstructor()) {
|
if (IsFunctionObject(*vp, &ucr->fun) && ucr->fun->isInterpretedConstructor()) {
|
||||||
ucr->callee = &vp->toObject();
|
ucr->callee = &vp->toObject();
|
||||||
if (!UncachedInlineCall(f, JSFRAME_CONSTRUCTING, &ucr->codeAddr, &ucr->unjittable, argc))
|
if (!UncachedInlineCall(f, StackFrame::CONSTRUCTING, &ucr->codeAddr, &ucr->unjittable, argc))
|
||||||
THROW();
|
THROW();
|
||||||
} else {
|
} else {
|
||||||
if (!InvokeConstructor(cx, InvokeArgsAlreadyOnTheStack(vp, argc)))
|
if (!InvokeConstructor(cx, InvokeArgsAlreadyOnTheStack(argc, vp)))
|
||||||
THROW();
|
THROW();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -435,13 +423,13 @@ stubs::Eval(VMFrame &f, uint32 argc)
|
||||||
{
|
{
|
||||||
Value *vp = f.regs.sp - (argc + 2);
|
Value *vp = f.regs.sp - (argc + 2);
|
||||||
|
|
||||||
if (!IsBuiltinEvalForScope(&f.regs.fp->scopeChain(), *vp)) {
|
if (!IsBuiltinEvalForScope(&f.fp()->scopeChain(), *vp)) {
|
||||||
if (!Invoke(f.cx, InvokeArgsAlreadyOnTheStack(vp, argc), 0))
|
if (!Invoke(f.cx, InvokeArgsAlreadyOnTheStack(argc, vp)))
|
||||||
THROW();
|
THROW();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_ASSERT(f.regs.fp == f.cx->fp());
|
JS_ASSERT(f.fp() == f.cx->fp());
|
||||||
if (!DirectEval(f.cx, CallArgsFromVp(argc, vp)))
|
if (!DirectEval(f.cx, CallArgsFromVp(argc, vp)))
|
||||||
THROW();
|
THROW();
|
||||||
|
|
||||||
|
@ -473,7 +461,7 @@ stubs::UncachedCallHelper(VMFrame &f, uint32 argc, UncachedCallResult *ucr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Invoke(f.cx, InvokeArgsAlreadyOnTheStack(vp, argc), 0))
|
if (!Invoke(f.cx, InvokeArgsAlreadyOnTheStack(argc, vp)))
|
||||||
THROW();
|
THROW();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -483,7 +471,7 @@ void JS_FASTCALL
|
||||||
stubs::PutActivationObjects(VMFrame &f)
|
stubs::PutActivationObjects(VMFrame &f)
|
||||||
{
|
{
|
||||||
JS_ASSERT(f.fp()->hasCallObj() || f.fp()->hasArgsObj());
|
JS_ASSERT(f.fp()->hasCallObj() || f.fp()->hasArgsObj());
|
||||||
js::PutActivationObjects(f.cx, f.fp());
|
f.fp()->putActivationObjects();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void *
|
extern "C" void *
|
||||||
|
@ -508,13 +496,13 @@ js_InternalThrow(VMFrame &f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure sp is up to date.
|
// Make sure sp is up to date.
|
||||||
JS_ASSERT(cx->regs == &f.regs);
|
JS_ASSERT(&cx->regs() == &f.regs);
|
||||||
|
|
||||||
// Call the throw hook if necessary
|
// Call the throw hook if necessary
|
||||||
JSThrowHook handler = f.cx->debugHooks->throwHook;
|
JSThrowHook handler = f.cx->debugHooks->throwHook;
|
||||||
if (handler) {
|
if (handler) {
|
||||||
Value rval;
|
Value rval;
|
||||||
switch (handler(cx, cx->fp()->script(), cx->regs->pc, Jsvalify(&rval),
|
switch (handler(cx, cx->fp()->script(), cx->regs().pc, Jsvalify(&rval),
|
||||||
cx->debugHooks->throwHookData)) {
|
cx->debugHooks->throwHookData)) {
|
||||||
case JSTRAP_ERROR:
|
case JSTRAP_ERROR:
|
||||||
cx->clearPendingException();
|
cx->clearPendingException();
|
||||||
|
@ -555,16 +543,16 @@ js_InternalThrow(VMFrame &f)
|
||||||
if (f.entryfp == f.fp())
|
if (f.entryfp == f.fp())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
JS_ASSERT(f.regs.sp == cx->regs->sp);
|
JS_ASSERT(f.regs.sp == cx->regs().sp);
|
||||||
InlineReturn(f);
|
InlineReturn(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_ASSERT(f.regs.sp == cx->regs->sp);
|
JS_ASSERT(f.regs.sp == cx->regs().sp);
|
||||||
|
|
||||||
if (!pc)
|
if (!pc)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
JSStackFrame *fp = cx->fp();
|
StackFrame *fp = cx->fp();
|
||||||
JSScript *script = fp->script();
|
JSScript *script = fp->script();
|
||||||
return script->nativeCodeForPC(fp->isConstructing(), pc);
|
return script->nativeCodeForPC(fp->isConstructing(), pc);
|
||||||
}
|
}
|
||||||
|
@ -581,7 +569,7 @@ void JS_FASTCALL
|
||||||
stubs::CreateThis(VMFrame &f, JSObject *proto)
|
stubs::CreateThis(VMFrame &f, JSObject *proto)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSStackFrame *fp = f.fp();
|
StackFrame *fp = f.fp();
|
||||||
JSObject *callee = &fp->callee();
|
JSObject *callee = &fp->callee();
|
||||||
JSObject *obj = js_CreateThisForFunctionWithProto(cx, callee, proto);
|
JSObject *obj = js_CreateThisForFunctionWithProto(cx, callee, proto);
|
||||||
if (!obj)
|
if (!obj)
|
||||||
|
@ -610,7 +598,7 @@ stubs::ScriptDebugEpilogue(VMFrame &f)
|
||||||
* handler in the process.
|
* handler in the process.
|
||||||
*/
|
*/
|
||||||
static inline bool
|
static inline bool
|
||||||
HandleErrorInExcessFrame(VMFrame &f, JSStackFrame *stopFp, bool searchedTopmostFrame = true)
|
HandleErrorInExcessFrame(VMFrame &f, StackFrame *stopFp, bool searchedTopmostFrame = true)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
|
|
||||||
|
@ -621,7 +609,7 @@ HandleErrorInExcessFrame(VMFrame &f, JSStackFrame *stopFp, bool searchedTopmostF
|
||||||
*
|
*
|
||||||
* Note that this also guarantees ScriptEpilogue() has been called.
|
* Note that this also guarantees ScriptEpilogue() has been called.
|
||||||
*/
|
*/
|
||||||
JSStackFrame *fp = cx->fp();
|
StackFrame *fp = cx->fp();
|
||||||
if (searchedTopmostFrame) {
|
if (searchedTopmostFrame) {
|
||||||
/*
|
/*
|
||||||
* This is a special case meaning that fp->finishedInInterpreter() is
|
* This is a special case meaning that fp->finishedInInterpreter() is
|
||||||
|
@ -647,7 +635,7 @@ HandleErrorInExcessFrame(VMFrame &f, JSStackFrame *stopFp, bool searchedTopmostF
|
||||||
|
|
||||||
/* Clear imacros. */
|
/* Clear imacros. */
|
||||||
if (fp->hasImacropc()) {
|
if (fp->hasImacropc()) {
|
||||||
cx->regs->pc = fp->imacropc();
|
cx->regs().pc = fp->imacropc();
|
||||||
fp->clearImacropc();
|
fp->clearImacropc();
|
||||||
}
|
}
|
||||||
JS_ASSERT(!fp->hasImacropc());
|
JS_ASSERT(!fp->hasImacropc());
|
||||||
|
@ -656,7 +644,7 @@ HandleErrorInExcessFrame(VMFrame &f, JSStackFrame *stopFp, bool searchedTopmostF
|
||||||
if (cx->isExceptionPending()) {
|
if (cx->isExceptionPending()) {
|
||||||
jsbytecode *pc = FindExceptionHandler(cx);
|
jsbytecode *pc = FindExceptionHandler(cx);
|
||||||
if (pc) {
|
if (pc) {
|
||||||
cx->regs->pc = pc;
|
cx->regs().pc = pc;
|
||||||
returnOK = true;
|
returnOK = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -672,7 +660,7 @@ HandleErrorInExcessFrame(VMFrame &f, JSStackFrame *stopFp, bool searchedTopmostF
|
||||||
InlineReturn(f);
|
InlineReturn(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_ASSERT(&f.regs == cx->regs);
|
JS_ASSERT(&f.regs == &cx->regs());
|
||||||
JS_ASSERT_IF(!returnOK, cx->fp() == stopFp);
|
JS_ASSERT_IF(!returnOK, cx->fp() == stopFp);
|
||||||
|
|
||||||
return returnOK;
|
return returnOK;
|
||||||
|
@ -682,12 +670,12 @@ HandleErrorInExcessFrame(VMFrame &f, JSStackFrame *stopFp, bool searchedTopmostF
|
||||||
static inline void *
|
static inline void *
|
||||||
AtSafePoint(JSContext *cx)
|
AtSafePoint(JSContext *cx)
|
||||||
{
|
{
|
||||||
JSStackFrame *fp = cx->fp();
|
StackFrame *fp = cx->fp();
|
||||||
if (fp->hasImacropc())
|
if (fp->hasImacropc())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
JSScript *script = fp->script();
|
JSScript *script = fp->script();
|
||||||
return script->maybeNativeCodeForPC(fp->isConstructing(), cx->regs->pc);
|
return script->maybeNativeCodeForPC(fp->isConstructing(), cx->regs().pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -698,13 +686,13 @@ static inline JSBool
|
||||||
PartialInterpret(VMFrame &f)
|
PartialInterpret(VMFrame &f)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSStackFrame *fp = cx->fp();
|
StackFrame *fp = cx->fp();
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
JSScript *script = fp->script();
|
JSScript *script = fp->script();
|
||||||
JS_ASSERT(!fp->finishedInInterpreter());
|
JS_ASSERT(!fp->finishedInInterpreter());
|
||||||
JS_ASSERT(fp->hasImacropc() ||
|
JS_ASSERT(fp->hasImacropc() ||
|
||||||
!script->maybeNativeCodeForPC(fp->isConstructing(), cx->regs->pc));
|
!script->maybeNativeCodeForPC(fp->isConstructing(), cx->regs().pc));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
JSBool ok = JS_TRUE;
|
JSBool ok = JS_TRUE;
|
||||||
|
@ -726,7 +714,7 @@ JS_STATIC_ASSERT(JSOP_NOP == 0);
|
||||||
static inline bool
|
static inline bool
|
||||||
FrameIsFinished(JSContext *cx)
|
FrameIsFinished(JSContext *cx)
|
||||||
{
|
{
|
||||||
JSOp op = JSOp(*cx->regs->pc);
|
JSOp op = JSOp(*cx->regs().pc);
|
||||||
return (op == JSOP_RETURN ||
|
return (op == JSOP_RETURN ||
|
||||||
op == JSOP_RETRVAL ||
|
op == JSOP_RETRVAL ||
|
||||||
op == JSOP_STOP)
|
op == JSOP_STOP)
|
||||||
|
@ -739,12 +727,12 @@ FrameIsFinished(JSContext *cx)
|
||||||
static inline void
|
static inline void
|
||||||
AdvanceReturnPC(JSContext *cx)
|
AdvanceReturnPC(JSContext *cx)
|
||||||
{
|
{
|
||||||
JS_ASSERT(*cx->regs->pc == JSOP_CALL ||
|
JS_ASSERT(*cx->regs().pc == JSOP_CALL ||
|
||||||
*cx->regs->pc == JSOP_NEW ||
|
*cx->regs().pc == JSOP_NEW ||
|
||||||
*cx->regs->pc == JSOP_EVAL ||
|
*cx->regs().pc == JSOP_EVAL ||
|
||||||
*cx->regs->pc == JSOP_FUNCALL ||
|
*cx->regs().pc == JSOP_FUNCALL ||
|
||||||
*cx->regs->pc == JSOP_FUNAPPLY);
|
*cx->regs().pc == JSOP_FUNAPPLY);
|
||||||
cx->regs->pc += JSOP_CALL_LENGTH;
|
cx->regs().pc += JSOP_CALL_LENGTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -756,7 +744,7 @@ AdvanceReturnPC(JSContext *cx)
|
||||||
* (and faster) to finish frames in C++ even if at a safe point here.
|
* (and faster) to finish frames in C++ even if at a safe point here.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
HandleFinishedFrame(VMFrame &f, JSStackFrame *entryFrame)
|
HandleFinishedFrame(VMFrame &f, StackFrame *entryFrame)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
|
|
||||||
|
@ -791,7 +779,7 @@ HandleFinishedFrame(VMFrame &f, JSStackFrame *entryFrame)
|
||||||
*/
|
*/
|
||||||
bool returnOK = true;
|
bool returnOK = true;
|
||||||
if (!cx->fp()->finishedInInterpreter()) {
|
if (!cx->fp()->finishedInInterpreter()) {
|
||||||
if (JSOp(*cx->regs->pc) == JSOP_RETURN)
|
if (JSOp(*cx->regs().pc) == JSOP_RETURN)
|
||||||
cx->fp()->setReturnValue(f.regs.sp[-1]);
|
cx->fp()->setReturnValue(f.regs.sp[-1]);
|
||||||
|
|
||||||
returnOK = ScriptEpilogue(cx, cx->fp(), true);
|
returnOK = ScriptEpilogue(cx, cx->fp(), true);
|
||||||
|
@ -821,10 +809,10 @@ HandleFinishedFrame(VMFrame &f, JSStackFrame *entryFrame)
|
||||||
* pushed by a call, that has method JIT'd code.
|
* pushed by a call, that has method JIT'd code.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
EvaluateExcessFrame(VMFrame &f, JSStackFrame *entryFrame)
|
EvaluateExcessFrame(VMFrame &f, StackFrame *entryFrame)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSStackFrame *fp = cx->fp();
|
StackFrame *fp = cx->fp();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A "finished" frame is when the interpreter rested on a STOP,
|
* A "finished" frame is when the interpreter rested on a STOP,
|
||||||
|
@ -851,7 +839,7 @@ EvaluateExcessFrame(VMFrame &f, JSStackFrame *entryFrame)
|
||||||
* always leave f.regs.fp == entryFrame.
|
* always leave f.regs.fp == entryFrame.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
FinishExcessFrames(VMFrame &f, JSStackFrame *entryFrame)
|
FinishExcessFrames(VMFrame &f, StackFrame *entryFrame)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
|
|
||||||
|
@ -940,7 +928,7 @@ RunTracer(VMFrame &f)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSStackFrame *entryFrame = f.fp();
|
StackFrame *entryFrame = f.fp();
|
||||||
TracePointAction tpa;
|
TracePointAction tpa;
|
||||||
|
|
||||||
/* :TODO: nuke PIC? */
|
/* :TODO: nuke PIC? */
|
||||||
|
@ -989,7 +977,6 @@ RunTracer(VMFrame &f)
|
||||||
// error failures correctly.
|
// error failures correctly.
|
||||||
JS_ASSERT_IF(cx->isExceptionPending(), tpa == TPA_Error);
|
JS_ASSERT_IF(cx->isExceptionPending(), tpa == TPA_Error);
|
||||||
|
|
||||||
f.fp() = cx->fp();
|
|
||||||
JS_ASSERT(f.fp() == cx->fp());
|
JS_ASSERT(f.fp() == cx->fp());
|
||||||
switch (tpa) {
|
switch (tpa) {
|
||||||
case TPA_Nothing:
|
case TPA_Nothing:
|
||||||
|
|
|
@ -63,7 +63,7 @@ struct Registers {
|
||||||
static const RegisterID ScratchReg = JSC::X86Registers::r11;
|
static const RegisterID ScratchReg = JSC::X86Registers::r11;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Register that homes the current JSStackFrame.
|
// Register that homes the current StackFrame.
|
||||||
#if defined(JS_CPU_X86) || defined(JS_CPU_X64)
|
#if defined(JS_CPU_X86) || defined(JS_CPU_X64)
|
||||||
static const RegisterID JSFrameReg = JSC::X86Registers::ebx;
|
static const RegisterID JSFrameReg = JSC::X86Registers::ebx;
|
||||||
#elif defined(JS_CPU_ARM)
|
#elif defined(JS_CPU_ARM)
|
||||||
|
|
|
@ -57,7 +57,7 @@ static const size_t CALLS_BEFORE_COMPILE = 16;
|
||||||
static const size_t BACKEDGES_BEFORE_COMPILE = 16;
|
static const size_t BACKEDGES_BEFORE_COMPILE = 16;
|
||||||
|
|
||||||
static inline CompileStatus
|
static inline CompileStatus
|
||||||
CanMethodJIT(JSContext *cx, JSScript *script, JSStackFrame *fp, CompileRequest request)
|
CanMethodJIT(JSContext *cx, JSScript *script, StackFrame *fp, CompileRequest request)
|
||||||
{
|
{
|
||||||
if (!cx->methodJitEnabled)
|
if (!cx->methodJitEnabled)
|
||||||
return Compile_Abort;
|
return Compile_Abort;
|
||||||
|
@ -81,7 +81,7 @@ CanMethodJIT(JSContext *cx, JSScript *script, JSStackFrame *fp, CompileRequest r
|
||||||
* methodjit. If so, we compile the given function.
|
* methodjit. If so, we compile the given function.
|
||||||
*/
|
*/
|
||||||
static inline CompileStatus
|
static inline CompileStatus
|
||||||
CanMethodJITAtBranch(JSContext *cx, JSScript *script, JSStackFrame *fp, jsbytecode *pc)
|
CanMethodJITAtBranch(JSContext *cx, JSScript *script, StackFrame *fp, jsbytecode *pc)
|
||||||
{
|
{
|
||||||
if (!cx->methodJitEnabled)
|
if (!cx->methodJitEnabled)
|
||||||
return Compile_Abort;
|
return Compile_Abort;
|
||||||
|
|
|
@ -62,20 +62,20 @@ js::mjit::CompilerAllocPolicy::CompilerAllocPolicy(JSContext *cx, Compiler &comp
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
JSStackFrame::methodjitStaticAsserts()
|
StackFrame::methodjitStaticAsserts()
|
||||||
{
|
{
|
||||||
/* Static assert for x86 trampolines in MethodJIT.cpp. */
|
/* Static assert for x86 trampolines in MethodJIT.cpp. */
|
||||||
#if defined(JS_CPU_X86)
|
#if defined(JS_CPU_X86)
|
||||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, rval_) == 0x18);
|
JS_STATIC_ASSERT(offsetof(StackFrame, rval_) == 0x18);
|
||||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, rval_) + 4 == 0x1C);
|
JS_STATIC_ASSERT(offsetof(StackFrame, rval_) + 4 == 0x1C);
|
||||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode_) == 0x14);
|
JS_STATIC_ASSERT(offsetof(StackFrame, ncode_) == 0x14);
|
||||||
/* ARM uses decimal literals. */
|
/* ARM uses decimal literals. */
|
||||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, rval_) == 24);
|
JS_STATIC_ASSERT(offsetof(StackFrame, rval_) == 24);
|
||||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, rval_) + 4 == 28);
|
JS_STATIC_ASSERT(offsetof(StackFrame, rval_) + 4 == 28);
|
||||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode_) == 20);
|
JS_STATIC_ASSERT(offsetof(StackFrame, ncode_) == 20);
|
||||||
#elif defined(JS_CPU_X64)
|
#elif defined(JS_CPU_X64)
|
||||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, rval_) == 0x30);
|
JS_STATIC_ASSERT(offsetof(StackFrame, rval_) == 0x30);
|
||||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode_) == 0x28);
|
JS_STATIC_ASSERT(offsetof(StackFrame, ncode_) == 0x28);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ extern "C" void JS_FASTCALL
|
||||||
PushActiveVMFrame(VMFrame &f)
|
PushActiveVMFrame(VMFrame &f)
|
||||||
{
|
{
|
||||||
f.entryfp->script()->compartment->jaegerCompartment->pushActiveFrame(&f);
|
f.entryfp->script()->compartment->jaegerCompartment->pushActiveFrame(&f);
|
||||||
f.regs.fp->setNativeReturnAddress(JS_FUNC_TO_DATA_PTR(void*, JaegerTrampolineReturn));
|
f.regs.fp()->setNativeReturnAddress(JS_FUNC_TO_DATA_PTR(void*, JaegerTrampolineReturn));
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void JS_FASTCALL
|
extern "C" void JS_FASTCALL
|
||||||
|
@ -131,7 +131,8 @@ PopActiveVMFrame(VMFrame &f)
|
||||||
extern "C" void JS_FASTCALL
|
extern "C" void JS_FASTCALL
|
||||||
SetVMFrameRegs(VMFrame &f)
|
SetVMFrameRegs(VMFrame &f)
|
||||||
{
|
{
|
||||||
f.cx->setCurrentRegs(&f.regs);
|
/* Restored on exit from EnterMethodJIT. */
|
||||||
|
f.cx->stack.repointRegs(&f.regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__APPLE__) || (defined(XP_WIN) && !defined(JS_CPU_X64)) || defined(XP_OS2)
|
#if defined(__APPLE__) || (defined(XP_WIN) && !defined(JS_CPU_X64)) || defined(XP_OS2)
|
||||||
|
@ -140,7 +141,7 @@ SetVMFrameRegs(VMFrame &f)
|
||||||
# define SYMBOL_STRING(name) #name
|
# define SYMBOL_STRING(name) #name
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
JS_STATIC_ASSERT(offsetof(JSFrameRegs, sp) == 0);
|
JS_STATIC_ASSERT(offsetof(FrameRegs, sp) == 0);
|
||||||
|
|
||||||
#if defined(__linux__) && defined(JS_CPU_X64)
|
#if defined(__linux__) && defined(JS_CPU_X64)
|
||||||
# define SYMBOL_STRING_RELOC(name) #name "@plt"
|
# define SYMBOL_STRING_RELOC(name) #name "@plt"
|
||||||
|
@ -179,7 +180,7 @@ JS_STATIC_ASSERT(sizeof(VMFrame) % 16 == 0);
|
||||||
* *** DANGER ***
|
* *** DANGER ***
|
||||||
*/
|
*/
|
||||||
JS_STATIC_ASSERT(offsetof(VMFrame, savedRBX) == 0x58);
|
JS_STATIC_ASSERT(offsetof(VMFrame, savedRBX) == 0x58);
|
||||||
JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == 0x38);
|
JS_STATIC_ASSERT(VMFrame::offsetOfFp == 0x38);
|
||||||
|
|
||||||
JS_STATIC_ASSERT(JSVAL_TAG_MASK == 0xFFFF800000000000LL);
|
JS_STATIC_ASSERT(JSVAL_TAG_MASK == 0xFFFF800000000000LL);
|
||||||
JS_STATIC_ASSERT(JSVAL_PAYLOAD_MASK == 0x00007FFFFFFFFFFFLL);
|
JS_STATIC_ASSERT(JSVAL_PAYLOAD_MASK == 0x00007FFFFFFFFFFFLL);
|
||||||
|
@ -284,7 +285,7 @@ SYMBOL_STRING(JaegerThrowpoline) ":" "\n"
|
||||||
* *** DANGER ***
|
* *** DANGER ***
|
||||||
*/
|
*/
|
||||||
JS_STATIC_ASSERT(offsetof(VMFrame, savedEBX) == 0x2c);
|
JS_STATIC_ASSERT(offsetof(VMFrame, savedEBX) == 0x2c);
|
||||||
JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == 0x1C);
|
JS_STATIC_ASSERT((VMFrame::offsetOfFp) == 0x1C);
|
||||||
|
|
||||||
asm (
|
asm (
|
||||||
".text\n"
|
".text\n"
|
||||||
|
@ -370,7 +371,7 @@ JS_STATIC_ASSERT(offsetof(VMFrame, savedLR) == (4*19));
|
||||||
JS_STATIC_ASSERT(offsetof(VMFrame, entryfp) == (4*10));
|
JS_STATIC_ASSERT(offsetof(VMFrame, entryfp) == (4*10));
|
||||||
JS_STATIC_ASSERT(offsetof(VMFrame, stackLimit) == (4*9));
|
JS_STATIC_ASSERT(offsetof(VMFrame, stackLimit) == (4*9));
|
||||||
JS_STATIC_ASSERT(offsetof(VMFrame, cx) == (4*8));
|
JS_STATIC_ASSERT(offsetof(VMFrame, cx) == (4*8));
|
||||||
JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == (4*7));
|
JS_STATIC_ASSERT(VMFrame::offsetOfFp == (4*7));
|
||||||
JS_STATIC_ASSERT(offsetof(VMFrame, unused) == (4*4));
|
JS_STATIC_ASSERT(offsetof(VMFrame, unused) == (4*4));
|
||||||
JS_STATIC_ASSERT(offsetof(VMFrame, previous) == (4*3));
|
JS_STATIC_ASSERT(offsetof(VMFrame, previous) == (4*3));
|
||||||
|
|
||||||
|
@ -520,11 +521,11 @@ SYMBOL_STRING(JaegerStubVeneer) ":" "\n"
|
||||||
* *** DANGER ***
|
* *** DANGER ***
|
||||||
*/
|
*/
|
||||||
JS_STATIC_ASSERT(offsetof(VMFrame, savedEBX) == 0x2c);
|
JS_STATIC_ASSERT(offsetof(VMFrame, savedEBX) == 0x2c);
|
||||||
JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == 0x1C);
|
JS_STATIC_ASSERT(VMFrame::offsetOfFp == 0x1C);
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
__declspec(naked) JSBool JaegerTrampoline(JSContext *cx, JSStackFrame *fp, void *code,
|
__declspec(naked) JSBool JaegerTrampoline(JSContext *cx, StackFrame *fp, void *code,
|
||||||
Value *stackLimit)
|
Value *stackLimit)
|
||||||
{
|
{
|
||||||
__asm {
|
__asm {
|
||||||
|
@ -615,7 +616,7 @@ extern "C" {
|
||||||
* *** DANGER ***
|
* *** DANGER ***
|
||||||
*/
|
*/
|
||||||
JS_STATIC_ASSERT(offsetof(VMFrame, savedRBX) == 0x58);
|
JS_STATIC_ASSERT(offsetof(VMFrame, savedRBX) == 0x58);
|
||||||
JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == 0x38);
|
JS_STATIC_ASSERT(VMFrame::offsetOfFp == 0x38);
|
||||||
JS_STATIC_ASSERT(JSVAL_TAG_MASK == 0xFFFF800000000000LL);
|
JS_STATIC_ASSERT(JSVAL_TAG_MASK == 0xFFFF800000000000LL);
|
||||||
JS_STATIC_ASSERT(JSVAL_PAYLOAD_MASK == 0x00007FFFFFFFFFFFLL);
|
JS_STATIC_ASSERT(JSVAL_PAYLOAD_MASK == 0x00007FFFFFFFFFFFLL);
|
||||||
|
|
||||||
|
@ -660,10 +661,10 @@ JaegerCompartment::Finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JSBool
|
extern "C" JSBool
|
||||||
JaegerTrampoline(JSContext *cx, JSStackFrame *fp, void *code, Value *stackLimit);
|
JaegerTrampoline(JSContext *cx, StackFrame *fp, void *code, Value *stackLimit);
|
||||||
|
|
||||||
JSBool
|
JSBool
|
||||||
mjit::EnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code, Value *stackLimit)
|
mjit::EnterMethodJIT(JSContext *cx, StackFrame *fp, void *code, Value *stackLimit)
|
||||||
{
|
{
|
||||||
#ifdef JS_METHODJIT_SPEW
|
#ifdef JS_METHODJIT_SPEW
|
||||||
Profiler prof;
|
Profiler prof;
|
||||||
|
@ -674,8 +675,8 @@ mjit::EnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code, Value *stackLi
|
||||||
prof.start();
|
prof.start();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
JS_ASSERT(cx->regs->fp == fp);
|
JS_ASSERT(cx->fp() == fp);
|
||||||
JSFrameRegs *oldRegs = cx->regs;
|
FrameRegs &oldRegs = cx->regs();
|
||||||
|
|
||||||
JSBool ok;
|
JSBool ok;
|
||||||
{
|
{
|
||||||
|
@ -684,7 +685,8 @@ mjit::EnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code, Value *stackLi
|
||||||
ok = JaegerTrampoline(cx, fp, code, stackLimit);
|
ok = JaegerTrampoline(cx, fp, code, stackLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
cx->setCurrentRegs(oldRegs);
|
/* Undo repointRegs in SetVMFrameRegs. */
|
||||||
|
cx->stack.repointRegs(&oldRegs);
|
||||||
JS_ASSERT(fp == cx->fp());
|
JS_ASSERT(fp == cx->fp());
|
||||||
|
|
||||||
/* The trampoline wrote the return value but did not set the HAS_RVAL flag. */
|
/* The trampoline wrote the return value but did not set the HAS_RVAL flag. */
|
||||||
|
@ -702,11 +704,11 @@ mjit::EnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code, Value *stackLi
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline JSBool
|
static inline JSBool
|
||||||
CheckStackAndEnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code)
|
CheckStackAndEnterMethodJIT(JSContext *cx, StackFrame *fp, void *code)
|
||||||
{
|
{
|
||||||
JS_CHECK_RECURSION(cx, return false);
|
JS_CHECK_RECURSION(cx, return false);
|
||||||
|
|
||||||
Value *stackLimit = cx->stack().getStackLimit(cx);
|
Value *stackLimit = cx->stack.space().getStackLimit(cx);
|
||||||
if (!stackLimit)
|
if (!stackLimit)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -716,7 +718,7 @@ CheckStackAndEnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code)
|
||||||
JSBool
|
JSBool
|
||||||
mjit::JaegerShot(JSContext *cx)
|
mjit::JaegerShot(JSContext *cx)
|
||||||
{
|
{
|
||||||
JSStackFrame *fp = cx->fp();
|
StackFrame *fp = cx->fp();
|
||||||
JSScript *script = fp->script();
|
JSScript *script = fp->script();
|
||||||
JITScript *jit = script->getJIT(fp->isConstructing());
|
JITScript *jit = script->getJIT(fp->isConstructing());
|
||||||
|
|
||||||
|
@ -725,7 +727,7 @@ mjit::JaegerShot(JSContext *cx)
|
||||||
AbortRecording(cx, "attempt to enter method JIT while recording");
|
AbortRecording(cx, "attempt to enter method JIT while recording");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
JS_ASSERT(cx->regs->pc == script->code);
|
JS_ASSERT(cx->regs().pc == script->code);
|
||||||
|
|
||||||
return CheckStackAndEnterMethodJIT(cx, cx->fp(), jit->invokeEntry);
|
return CheckStackAndEnterMethodJIT(cx, cx->fp(), jit->invokeEntry);
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,10 +107,10 @@ struct VMFrame
|
||||||
|
|
||||||
VMFrame *previous;
|
VMFrame *previous;
|
||||||
void *unused;
|
void *unused;
|
||||||
JSFrameRegs regs;
|
FrameRegs regs;
|
||||||
JSContext *cx;
|
JSContext *cx;
|
||||||
Value *stackLimit;
|
Value *stackLimit;
|
||||||
JSStackFrame *entryfp;
|
StackFrame *entryfp;
|
||||||
|
|
||||||
#if defined(JS_CPU_X86)
|
#if defined(JS_CPU_X86)
|
||||||
void *savedEBX;
|
void *savedEBX;
|
||||||
|
@ -178,8 +178,13 @@ struct VMFrame
|
||||||
|
|
||||||
JSRuntime *runtime() { return cx->runtime; }
|
JSRuntime *runtime() { return cx->runtime; }
|
||||||
|
|
||||||
JSStackFrame *&fp() { return regs.fp; }
|
StackFrame *fp() { return regs.fp(); }
|
||||||
mjit::JITScript *jit() { return fp()->jit(); }
|
mjit::JITScript *jit() { return fp()->jit(); }
|
||||||
|
|
||||||
|
static const size_t offsetOfFp = 5 * sizeof(void *) + FrameRegs::offsetOfFp;
|
||||||
|
static void staticAssert() {
|
||||||
|
JS_STATIC_ASSERT(offsetOfFp == offsetof(VMFrame, regs) + FrameRegs::offsetOfFp);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef JS_CPU_ARM
|
#ifdef JS_CPU_ARM
|
||||||
|
@ -425,7 +430,7 @@ struct JITScript {
|
||||||
* Execute the given mjit code. This is a low-level call and callers must
|
* Execute the given mjit code. This is a low-level call and callers must
|
||||||
* provide the same guarantees as JaegerShot/CheckStackAndEnterMethodJIT.
|
* provide the same guarantees as JaegerShot/CheckStackAndEnterMethodJIT.
|
||||||
*/
|
*/
|
||||||
JSBool EnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code, Value *stackLimit);
|
JSBool EnterMethodJIT(JSContext *cx, StackFrame *fp, void *code, Value *stackLimit);
|
||||||
|
|
||||||
/* Execute a method that has been JIT compiled. */
|
/* Execute a method that has been JIT compiled. */
|
||||||
JSBool JaegerShot(JSContext *cx);
|
JSBool JaegerShot(JSContext *cx);
|
||||||
|
@ -445,7 +450,7 @@ void JS_FASTCALL
|
||||||
ProfileStubCall(VMFrame &f);
|
ProfileStubCall(VMFrame &f);
|
||||||
|
|
||||||
CompileStatus JS_NEVER_INLINE
|
CompileStatus JS_NEVER_INLINE
|
||||||
TryCompile(JSContext *cx, JSStackFrame *fp);
|
TryCompile(JSContext *cx, StackFrame *fp);
|
||||||
|
|
||||||
void
|
void
|
||||||
ReleaseScriptCode(JSContext *cx, JSScript *script);
|
ReleaseScriptCode(JSContext *cx, JSScript *script);
|
||||||
|
|
|
@ -652,7 +652,7 @@ class CallCompiler : public BaseCompiler
|
||||||
Jump hasCode = masm.branchPtr(Assembler::Above, t0, ImmPtr(JS_UNJITTABLE_SCRIPT));
|
Jump hasCode = masm.branchPtr(Assembler::Above, t0, ImmPtr(JS_UNJITTABLE_SCRIPT));
|
||||||
|
|
||||||
/* Try and compile. On success we get back the nmap pointer. */
|
/* Try and compile. On success we get back the nmap pointer. */
|
||||||
masm.storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp)));
|
masm.storePtr(JSFrameReg, FrameAddress(VMFrame::offsetOfFp));
|
||||||
void *compilePtr = JS_FUNC_TO_DATA_PTR(void *, stubs::CompileFunction);
|
void *compilePtr = JS_FUNC_TO_DATA_PTR(void *, stubs::CompileFunction);
|
||||||
if (ic.frameSize.isStatic()) {
|
if (ic.frameSize.isStatic()) {
|
||||||
masm.move(Imm32(ic.frameSize.staticArgc()), Registers::ArgReg1);
|
masm.move(Imm32(ic.frameSize.staticArgc()), Registers::ArgReg1);
|
||||||
|
@ -661,7 +661,7 @@ class CallCompiler : public BaseCompiler
|
||||||
masm.load32(FrameAddress(offsetof(VMFrame, u.call.dynamicArgc)), Registers::ArgReg1);
|
masm.load32(FrameAddress(offsetof(VMFrame, u.call.dynamicArgc)), Registers::ArgReg1);
|
||||||
masm.fallibleVMCall(compilePtr, script->code, -1);
|
masm.fallibleVMCall(compilePtr, script->code, -1);
|
||||||
}
|
}
|
||||||
masm.loadPtr(FrameAddress(offsetof(VMFrame, regs.fp)), JSFrameReg);
|
masm.loadPtr(FrameAddress(VMFrame::offsetOfFp), JSFrameReg);
|
||||||
|
|
||||||
Jump notCompiled = masm.branchTestPtr(Assembler::Zero, Registers::ReturnReg,
|
Jump notCompiled = masm.branchTestPtr(Assembler::Zero, Registers::ReturnReg,
|
||||||
Registers::ReturnReg);
|
Registers::ReturnReg);
|
||||||
|
@ -777,7 +777,7 @@ class CallCompiler : public BaseCompiler
|
||||||
JITScript *jit = f.jit();
|
JITScript *jit = f.jit();
|
||||||
|
|
||||||
/* Snapshot the frameDepth before SplatApplyArgs modifies it. */
|
/* Snapshot the frameDepth before SplatApplyArgs modifies it. */
|
||||||
uintN initialFrameDepth = f.regs.sp - f.regs.fp->slots();
|
uintN initialFrameDepth = f.regs.sp - f.regs.fp()->slots();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SplatApplyArgs has not been called, so we call it here before
|
* SplatApplyArgs has not been called, so we call it here before
|
||||||
|
@ -785,7 +785,7 @@ class CallCompiler : public BaseCompiler
|
||||||
*/
|
*/
|
||||||
Value *vp;
|
Value *vp;
|
||||||
if (ic.frameSize.isStatic()) {
|
if (ic.frameSize.isStatic()) {
|
||||||
JS_ASSERT(f.regs.sp - f.regs.fp->slots() == (int)ic.frameSize.staticLocalSlots());
|
JS_ASSERT(f.regs.sp - f.regs.fp()->slots() == (int)ic.frameSize.staticLocalSlots());
|
||||||
vp = f.regs.sp - (2 + ic.frameSize.staticArgc());
|
vp = f.regs.sp - (2 + ic.frameSize.staticArgc());
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(*f.regs.pc == JSOP_FUNAPPLY && GET_ARGC(f.regs.pc) == 2);
|
JS_ASSERT(*f.regs.pc == JSOP_FUNAPPLY && GET_ARGC(f.regs.pc) == 2);
|
||||||
|
@ -839,18 +839,18 @@ class CallCompiler : public BaseCompiler
|
||||||
RegisterID t0 = tempRegs.takeAnyReg();
|
RegisterID t0 = tempRegs.takeAnyReg();
|
||||||
|
|
||||||
/* Store pc. */
|
/* Store pc. */
|
||||||
masm.storePtr(ImmPtr(cx->regs->pc),
|
masm.storePtr(ImmPtr(cx->regs().pc),
|
||||||
FrameAddress(offsetof(VMFrame, regs.pc)));
|
FrameAddress(offsetof(VMFrame, regs.pc)));
|
||||||
|
|
||||||
/* Store sp (if not already set by ic::SplatApplyArgs). */
|
/* Store sp (if not already set by ic::SplatApplyArgs). */
|
||||||
if (ic.frameSize.isStatic()) {
|
if (ic.frameSize.isStatic()) {
|
||||||
uint32 spOffset = sizeof(JSStackFrame) + initialFrameDepth * sizeof(Value);
|
uint32 spOffset = sizeof(StackFrame) + initialFrameDepth * sizeof(Value);
|
||||||
masm.addPtr(Imm32(spOffset), JSFrameReg, t0);
|
masm.addPtr(Imm32(spOffset), JSFrameReg, t0);
|
||||||
masm.storePtr(t0, FrameAddress(offsetof(VMFrame, regs.sp)));
|
masm.storePtr(t0, FrameAddress(offsetof(VMFrame, regs.sp)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Store fp. */
|
/* Store fp. */
|
||||||
masm.storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp)));
|
masm.storePtr(JSFrameReg, FrameAddress(VMFrame::offsetOfFp));
|
||||||
|
|
||||||
/* Grab cx. */
|
/* Grab cx. */
|
||||||
#ifdef JS_CPU_X86
|
#ifdef JS_CPU_X86
|
||||||
|
@ -868,7 +868,7 @@ class CallCompiler : public BaseCompiler
|
||||||
#endif
|
#endif
|
||||||
MaybeRegisterID argcReg;
|
MaybeRegisterID argcReg;
|
||||||
if (ic.frameSize.isStatic()) {
|
if (ic.frameSize.isStatic()) {
|
||||||
uint32 vpOffset = sizeof(JSStackFrame) + (vp - f.regs.fp->slots()) * sizeof(Value);
|
uint32 vpOffset = sizeof(StackFrame) + (vp - f.regs.fp()->slots()) * sizeof(Value);
|
||||||
masm.addPtr(Imm32(vpOffset), JSFrameReg, vpReg);
|
masm.addPtr(Imm32(vpOffset), JSFrameReg, vpReg);
|
||||||
} else {
|
} else {
|
||||||
argcReg = tempRegs.takeAnyReg();
|
argcReg = tempRegs.takeAnyReg();
|
||||||
|
@ -972,7 +972,7 @@ class CallCompiler : public BaseCompiler
|
||||||
JSObject *callee = ucr.callee;
|
JSObject *callee = ucr.callee;
|
||||||
JS_ASSERT(callee);
|
JS_ASSERT(callee);
|
||||||
|
|
||||||
uint32 flags = callingNew ? JSFRAME_CONSTRUCTING : 0;
|
uint32 flags = callingNew ? StackFrame::CONSTRUCTING : 0;
|
||||||
|
|
||||||
if (!ic.hit) {
|
if (!ic.hit) {
|
||||||
ic.hit = true;
|
ic.hit = true;
|
||||||
|
@ -1036,7 +1036,6 @@ ic::NativeNew(VMFrame &f, CallICInfo *ic)
|
||||||
}
|
}
|
||||||
|
|
||||||
static const unsigned MANY_ARGS = 1024;
|
static const unsigned MANY_ARGS = 1024;
|
||||||
static const unsigned MIN_SPACE = 500;
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
BumpStackFull(VMFrame &f, uintN inc)
|
BumpStackFull(VMFrame &f, uintN inc)
|
||||||
|
@ -1045,12 +1044,8 @@ BumpStackFull(VMFrame &f, uintN inc)
|
||||||
if (inc < MANY_ARGS) {
|
if (inc < MANY_ARGS) {
|
||||||
if (f.regs.sp + inc < f.stackLimit)
|
if (f.regs.sp + inc < f.stackLimit)
|
||||||
return true;
|
return true;
|
||||||
StackSpace &stack = f.cx->stack();
|
StackSpace &space = f.cx->stack.space();
|
||||||
if (!stack.bumpCommitAndLimit(f.entryfp, f.regs.sp, inc, &f.stackLimit)) {
|
return space.bumpLimitWithinQuota(f.cx, f.entryfp, f.regs.sp, inc, &f.stackLimit);
|
||||||
js_ReportOverRecursed(f.cx);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1065,20 +1060,8 @@ BumpStackFull(VMFrame &f, uintN inc)
|
||||||
* However, since each apply call must consume at least MANY_ARGS slots,
|
* However, since each apply call must consume at least MANY_ARGS slots,
|
||||||
* this sequence will quickly reach the end of the stack and OOM.
|
* this sequence will quickly reach the end of the stack and OOM.
|
||||||
*/
|
*/
|
||||||
|
StackSpace &space = f.cx->stack.space();
|
||||||
uintN incWithSpace = inc + MIN_SPACE;
|
return space.bumpLimit(f.cx, f.entryfp, f.regs.sp, inc, &f.stackLimit);
|
||||||
Value *bumpedWithSpace = f.regs.sp + incWithSpace;
|
|
||||||
if (bumpedWithSpace < f.stackLimit)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
StackSpace &stack = f.cx->stack();
|
|
||||||
if (stack.bumpCommitAndLimit(f.entryfp, f.regs.sp, incWithSpace, &f.stackLimit))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (!stack.ensureSpace(f.cx, f.regs.sp, incWithSpace))
|
|
||||||
return false;
|
|
||||||
f.stackLimit = bumpedWithSpace;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static JS_ALWAYS_INLINE bool
|
static JS_ALWAYS_INLINE bool
|
||||||
|
@ -1117,7 +1100,7 @@ ic::SplatApplyArgs(VMFrame &f)
|
||||||
Value *vp = f.regs.sp - 3;
|
Value *vp = f.regs.sp - 3;
|
||||||
JS_ASSERT(JS_CALLEE(cx, vp).toObject().getFunctionPrivate()->u.n.native == js_fun_apply);
|
JS_ASSERT(JS_CALLEE(cx, vp).toObject().getFunctionPrivate()->u.n.native == js_fun_apply);
|
||||||
|
|
||||||
JSStackFrame *fp = f.regs.fp;
|
StackFrame *fp = f.regs.fp();
|
||||||
if (!fp->hasOverriddenArgs()) {
|
if (!fp->hasOverriddenArgs()) {
|
||||||
uintN n;
|
uintN n;
|
||||||
if (!fp->hasArgsObj()) {
|
if (!fp->hasArgsObj()) {
|
||||||
|
|
|
@ -404,8 +404,8 @@ class SetPropCompiler : public PICStubCompiler
|
||||||
|
|
||||||
{
|
{
|
||||||
Address addr(pic.shapeReg, shape->setterOp() == SetCallArg
|
Address addr(pic.shapeReg, shape->setterOp() == SetCallArg
|
||||||
? JSStackFrame::offsetOfFormalArg(fun, slot)
|
? StackFrame::offsetOfFormalArg(fun, slot)
|
||||||
: JSStackFrame::offsetOfFixed(slot));
|
: StackFrame::offsetOfFixed(slot));
|
||||||
masm.storeValue(pic.u.vr, addr);
|
masm.storeValue(pic.u.vr, addr);
|
||||||
skipOver = masm.jump();
|
skipOver = masm.jump();
|
||||||
}
|
}
|
||||||
|
@ -907,7 +907,7 @@ class GetPropCompiler : public PICStubCompiler
|
||||||
* up in the fast path, or put this offset in PICInfo?
|
* up in the fast path, or put this offset in PICInfo?
|
||||||
*/
|
*/
|
||||||
uint32 thisvOffset = uint32(f.regs.sp - f.fp()->slots()) - 1;
|
uint32 thisvOffset = uint32(f.regs.sp - f.fp()->slots()) - 1;
|
||||||
Address thisv(JSFrameReg, sizeof(JSStackFrame) + thisvOffset * sizeof(Value));
|
Address thisv(JSFrameReg, sizeof(StackFrame) + thisvOffset * sizeof(Value));
|
||||||
masm.storeValueFromComponents(ImmType(JSVAL_TYPE_STRING),
|
masm.storeValueFromComponents(ImmType(JSVAL_TYPE_STRING),
|
||||||
pic.objReg, thisv);
|
pic.objReg, thisv);
|
||||||
|
|
||||||
|
@ -1247,7 +1247,7 @@ class ScopeNameCompiler : public PICStubCompiler
|
||||||
|
|
||||||
/* For GETXPROP, the object is already in objReg. */
|
/* For GETXPROP, the object is already in objReg. */
|
||||||
if (pic.kind == ic::PICInfo::NAME)
|
if (pic.kind == ic::PICInfo::NAME)
|
||||||
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfScopeChain()), pic.objReg);
|
masm.loadPtr(Address(JSFrameReg, StackFrame::offsetOfScopeChain()), pic.objReg);
|
||||||
|
|
||||||
JS_ASSERT(obj == getprop.holder);
|
JS_ASSERT(obj == getprop.holder);
|
||||||
JS_ASSERT(getprop.holder == scopeChain->getGlobal());
|
JS_ASSERT(getprop.holder == scopeChain->getGlobal());
|
||||||
|
@ -1315,7 +1315,7 @@ class ScopeNameCompiler : public PICStubCompiler
|
||||||
|
|
||||||
/* For GETXPROP, the object is already in objReg. */
|
/* For GETXPROP, the object is already in objReg. */
|
||||||
if (pic.kind == ic::PICInfo::NAME)
|
if (pic.kind == ic::PICInfo::NAME)
|
||||||
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfScopeChain()), pic.objReg);
|
masm.loadPtr(Address(JSFrameReg, StackFrame::offsetOfScopeChain()), pic.objReg);
|
||||||
|
|
||||||
JS_ASSERT(obj == getprop.holder);
|
JS_ASSERT(obj == getprop.holder);
|
||||||
JS_ASSERT(getprop.holder != scopeChain->getGlobal());
|
JS_ASSERT(getprop.holder != scopeChain->getGlobal());
|
||||||
|
@ -1352,8 +1352,8 @@ class ScopeNameCompiler : public PICStubCompiler
|
||||||
|
|
||||||
/* Not-escaped case. */
|
/* Not-escaped case. */
|
||||||
{
|
{
|
||||||
Address addr(pic.shapeReg, kind == ARG ? JSStackFrame::offsetOfFormalArg(fun, slot)
|
Address addr(pic.shapeReg, kind == ARG ? StackFrame::offsetOfFormalArg(fun, slot)
|
||||||
: JSStackFrame::offsetOfFixed(slot));
|
: StackFrame::offsetOfFixed(slot));
|
||||||
masm.loadPayload(addr, pic.objReg);
|
masm.loadPayload(addr, pic.objReg);
|
||||||
masm.loadTypeTag(addr, pic.shapeReg);
|
masm.loadTypeTag(addr, pic.shapeReg);
|
||||||
skipOver = masm.jump();
|
skipOver = masm.jump();
|
||||||
|
@ -1459,7 +1459,7 @@ class ScopeNameCompiler : public PICStubCompiler
|
||||||
/* Kludge to allow (typeof foo == "undefined") tests. */
|
/* Kludge to allow (typeof foo == "undefined") tests. */
|
||||||
disable("property not found");
|
disable("property not found");
|
||||||
if (pic.kind == ic::PICInfo::NAME) {
|
if (pic.kind == ic::PICInfo::NAME) {
|
||||||
JSOp op2 = js_GetOpcode(cx, script, cx->regs->pc + JSOP_NAME_LENGTH);
|
JSOp op2 = js_GetOpcode(cx, script, cx->regs().pc + JSOP_NAME_LENGTH);
|
||||||
if (op2 == JSOP_TYPEOF) {
|
if (op2 == JSOP_TYPEOF) {
|
||||||
vp->setUndefined();
|
vp->setUndefined();
|
||||||
return true;
|
return true;
|
||||||
|
@ -1531,7 +1531,7 @@ class BindNameCompiler : public PICStubCompiler
|
||||||
BindNameLabels &labels = pic.bindNameLabels();
|
BindNameLabels &labels = pic.bindNameLabels();
|
||||||
|
|
||||||
/* Guard on the shape of the scope chain. */
|
/* Guard on the shape of the scope chain. */
|
||||||
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfScopeChain()), pic.objReg);
|
masm.loadPtr(Address(JSFrameReg, StackFrame::offsetOfScopeChain()), pic.objReg);
|
||||||
masm.loadShape(pic.objReg, pic.shapeReg);
|
masm.loadShape(pic.objReg, pic.shapeReg);
|
||||||
Jump firstShape = masm.branch32(Assembler::NotEqual, pic.shapeReg,
|
Jump firstShape = masm.branch32(Assembler::NotEqual, pic.shapeReg,
|
||||||
Imm32(scopeChain->shape()));
|
Imm32(scopeChain->shape()));
|
||||||
|
@ -1751,7 +1751,7 @@ void JS_FASTCALL
|
||||||
ic::CallProp(VMFrame &f, ic::PICInfo *pic)
|
ic::CallProp(VMFrame &f, ic::PICInfo *pic)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSFrameRegs ®s = f.regs;
|
FrameRegs ®s = f.regs;
|
||||||
|
|
||||||
JSScript *script = f.fp()->script();
|
JSScript *script = f.fp()->script();
|
||||||
|
|
||||||
|
@ -1850,7 +1850,7 @@ ic::CallProp(VMFrame &f, ic::PICInfo *pic)
|
||||||
}
|
}
|
||||||
|
|
||||||
#if JS_HAS_NO_SUCH_METHOD
|
#if JS_HAS_NO_SUCH_METHOD
|
||||||
if (JS_UNLIKELY(rval.isUndefined()) && regs.sp[-1].isObject()) {
|
if (JS_UNLIKELY(rval.isPrimitive()) && regs.sp[-1].isObject()) {
|
||||||
regs.sp[-2].setString(pic->atom);
|
regs.sp[-2].setString(pic->atom);
|
||||||
if (!js_OnUnknownMethod(cx, regs.sp - 2))
|
if (!js_OnUnknownMethod(cx, regs.sp - 2))
|
||||||
THROW();
|
THROW();
|
||||||
|
@ -2102,8 +2102,8 @@ GetElementIC::attachGetProp(JSContext *cx, JSObject *obj, const Value &v, jsid i
|
||||||
|
|
||||||
if (op == JSOP_CALLELEM) {
|
if (op == JSOP_CALLELEM) {
|
||||||
// Emit a write of |obj| to the top of the stack, before we lose it.
|
// Emit a write of |obj| to the top of the stack, before we lose it.
|
||||||
Value *thisVp = &cx->regs->sp[-1];
|
Value *thisVp = &cx->regs().sp[-1];
|
||||||
Address thisSlot(JSFrameReg, JSStackFrame::offsetOfFixed(thisVp - cx->fp()->slots()));
|
Address thisSlot(JSFrameReg, StackFrame::offsetOfFixed(thisVp - cx->fp()->slots()));
|
||||||
masm.storeValueFromComponents(ImmType(JSVAL_TYPE_OBJECT), objReg, thisSlot);
|
masm.storeValueFromComponents(ImmType(JSVAL_TYPE_OBJECT), objReg, thisSlot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2369,7 +2369,7 @@ ic::CallElement(VMFrame &f, ic::GetElementIC *ic)
|
||||||
THROW();
|
THROW();
|
||||||
|
|
||||||
#if JS_HAS_NO_SUCH_METHOD
|
#if JS_HAS_NO_SUCH_METHOD
|
||||||
if (JS_UNLIKELY(f.regs.sp[-2].isUndefined()) && thisv.isObject()) {
|
if (JS_UNLIKELY(f.regs.sp[-2].isPrimitive()) && thisv.isObject()) {
|
||||||
f.regs.sp[-2] = f.regs.sp[-1];
|
f.regs.sp[-2] = f.regs.sp[-1];
|
||||||
f.regs.sp[-1].setObject(*thisObj);
|
f.regs.sp[-1].setObject(*thisObj);
|
||||||
if (!js_OnUnknownMethod(cx, f.regs.sp - 2))
|
if (!js_OnUnknownMethod(cx, f.regs.sp - 2))
|
||||||
|
|
|
@ -88,7 +88,7 @@ struct StateRemat {
|
||||||
// representation in a struct or union. This prevents bloating the IC
|
// representation in a struct or union. This prevents bloating the IC
|
||||||
// structs by an extra 8 bytes in some cases. 16 bits are needed to encode
|
// structs by an extra 8 bytes in some cases. 16 bits are needed to encode
|
||||||
// the largest local:
|
// the largest local:
|
||||||
// ((UINT16_LIMIT - 1) * sizeof(Value) + sizeof(JSStackFrame),
|
// ((UINT16_LIMIT - 1) * sizeof(Value) + sizeof(StackFrame),
|
||||||
// And an extra bit for the sign on arguments.
|
// And an extra bit for the sign on arguments.
|
||||||
#define MIN_STATE_REMAT_BITS 21
|
#define MIN_STATE_REMAT_BITS 21
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ struct StateRemat {
|
||||||
bool inRegister() const { return offset_ >= 0 &&
|
bool inRegister() const { return offset_ >= 0 &&
|
||||||
offset_ <= int32(JSC::MacroAssembler::TotalRegisters); }
|
offset_ <= int32(JSC::MacroAssembler::TotalRegisters); }
|
||||||
bool inMemory() const {
|
bool inMemory() const {
|
||||||
return offset_ >= int32(sizeof(JSStackFrame)) ||
|
return offset_ >= int32(sizeof(StackFrame)) ||
|
||||||
offset_ < 0;
|
offset_ < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -123,8 +123,8 @@ Recompiler::recompile()
|
||||||
Vector<PatchableAddress> normalPatches(cx);
|
Vector<PatchableAddress> normalPatches(cx);
|
||||||
Vector<PatchableAddress> ctorPatches(cx);
|
Vector<PatchableAddress> ctorPatches(cx);
|
||||||
|
|
||||||
JSStackFrame *firstCtorFrame = NULL;
|
StackFrame *firstCtorFrame = NULL;
|
||||||
JSStackFrame *firstNormalFrame = NULL;
|
StackFrame *firstNormalFrame = NULL;
|
||||||
|
|
||||||
// Find all JIT'd stack frames to account for return addresses that will
|
// Find all JIT'd stack frames to account for return addresses that will
|
||||||
// need to be patched after recompilation.
|
// need to be patched after recompilation.
|
||||||
|
@ -133,8 +133,8 @@ Recompiler::recompile()
|
||||||
f = f->previous) {
|
f = f->previous) {
|
||||||
|
|
||||||
// Scan all frames owned by this VMFrame.
|
// Scan all frames owned by this VMFrame.
|
||||||
JSStackFrame *end = f->entryfp->prev();
|
StackFrame *end = f->entryfp->prev();
|
||||||
for (JSStackFrame *fp = f->fp(); fp != end; fp = fp->prev()) {
|
for (StackFrame *fp = f->fp(); fp != end; fp = fp->prev()) {
|
||||||
// Remember the latest frame for each type of JIT'd code, so the
|
// Remember the latest frame for each type of JIT'd code, so the
|
||||||
// compiler will have a frame to re-JIT from.
|
// compiler will have a frame to re-JIT from.
|
||||||
if (!firstCtorFrame && fp->script() == script && fp->isConstructing())
|
if (!firstCtorFrame && fp->script() == script && fp->isConstructing())
|
||||||
|
@ -198,7 +198,7 @@ Recompiler::saveTraps(JITScript *jit, Vector<CallSite> *sites)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Recompiler::recompile(JSStackFrame *fp, Vector<PatchableAddress> &patches,
|
Recompiler::recompile(StackFrame *fp, Vector<PatchableAddress> &patches,
|
||||||
Vector<CallSite> &sites)
|
Vector<CallSite> &sites)
|
||||||
{
|
{
|
||||||
/* If we get this far, the script is live, and we better be safe to re-jit. */
|
/* If we get this far, the script is live, and we better be safe to re-jit. */
|
||||||
|
|
|
@ -98,7 +98,7 @@ private:
|
||||||
|
|
||||||
PatchableAddress findPatch(JITScript *jit, void **location);
|
PatchableAddress findPatch(JITScript *jit, void **location);
|
||||||
void applyPatch(Compiler& c, PatchableAddress& toPatch);
|
void applyPatch(Compiler& c, PatchableAddress& toPatch);
|
||||||
bool recompile(JSStackFrame *fp, Vector<PatchableAddress> &patches,
|
bool recompile(StackFrame *fp, Vector<PatchableAddress> &patches,
|
||||||
Vector<CallSite> &sites);
|
Vector<CallSite> &sites);
|
||||||
bool saveTraps(JITScript *jit, Vector<CallSite> *sites);
|
bool saveTraps(JITScript *jit, Vector<CallSite> *sites);
|
||||||
};
|
};
|
||||||
|
|
|
@ -411,7 +411,7 @@ void JS_FASTCALL
|
||||||
stubs::GetElem(VMFrame &f)
|
stubs::GetElem(VMFrame &f)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSFrameRegs ®s = f.regs;
|
FrameRegs ®s = f.regs;
|
||||||
|
|
||||||
Value &lref = regs.sp[-2];
|
Value &lref = regs.sp[-2];
|
||||||
Value &rref = regs.sp[-1];
|
Value &rref = regs.sp[-1];
|
||||||
|
@ -451,7 +451,7 @@ stubs::GetElem(VMFrame &f)
|
||||||
if (arg < obj->getArgsInitialLength()) {
|
if (arg < obj->getArgsInitialLength()) {
|
||||||
copyFrom = obj->addressOfArgsElement(arg);
|
copyFrom = obj->addressOfArgsElement(arg);
|
||||||
if (!copyFrom->isMagic()) {
|
if (!copyFrom->isMagic()) {
|
||||||
if (JSStackFrame *afp = (JSStackFrame *) obj->getPrivate())
|
if (StackFrame *afp = (StackFrame *) obj->getPrivate())
|
||||||
copyFrom = &afp->canonicalActualArg(arg);
|
copyFrom = &afp->canonicalActualArg(arg);
|
||||||
goto end_getelem;
|
goto end_getelem;
|
||||||
}
|
}
|
||||||
|
@ -496,7 +496,7 @@ void JS_FASTCALL
|
||||||
stubs::CallElem(VMFrame &f)
|
stubs::CallElem(VMFrame &f)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSFrameRegs ®s = f.regs;
|
FrameRegs ®s = f.regs;
|
||||||
|
|
||||||
/* Find the object on which to look for |this|'s properties. */
|
/* Find the object on which to look for |this|'s properties. */
|
||||||
Value thisv = regs.sp[-2];
|
Value thisv = regs.sp[-2];
|
||||||
|
@ -514,7 +514,7 @@ stubs::CallElem(VMFrame &f)
|
||||||
THROW();
|
THROW();
|
||||||
|
|
||||||
#if JS_HAS_NO_SUCH_METHOD
|
#if JS_HAS_NO_SUCH_METHOD
|
||||||
if (JS_UNLIKELY(regs.sp[-2].isUndefined()) && thisv.isObject()) {
|
if (JS_UNLIKELY(regs.sp[-2].isPrimitive()) && thisv.isObject()) {
|
||||||
regs.sp[-2] = regs.sp[-1];
|
regs.sp[-2] = regs.sp[-1];
|
||||||
regs.sp[-1].setObject(*thisObj);
|
regs.sp[-1].setObject(*thisObj);
|
||||||
if (!js_OnUnknownMethod(cx, regs.sp - 2))
|
if (!js_OnUnknownMethod(cx, regs.sp - 2))
|
||||||
|
@ -531,7 +531,7 @@ void JS_FASTCALL
|
||||||
stubs::SetElem(VMFrame &f)
|
stubs::SetElem(VMFrame &f)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSFrameRegs ®s = f.regs;
|
FrameRegs ®s = f.regs;
|
||||||
|
|
||||||
Value &objval = regs.sp[-3];
|
Value &objval = regs.sp[-3];
|
||||||
Value &idval = regs.sp[-2];
|
Value &idval = regs.sp[-2];
|
||||||
|
@ -691,7 +691,7 @@ stubs::DefFun(VMFrame &f, JSFunction *fun)
|
||||||
JSObject *obj2;
|
JSObject *obj2;
|
||||||
|
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSStackFrame *fp = f.fp();
|
StackFrame *fp = f.fp();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A top-level function defined in Global or Eval code (see ECMA-262
|
* A top-level function defined in Global or Eval code (see ECMA-262
|
||||||
|
@ -744,7 +744,7 @@ stubs::DefFun(VMFrame &f, JSFunction *fun)
|
||||||
* current scope chain even for the case of function expression statements
|
* current scope chain even for the case of function expression statements
|
||||||
* and functions defined by eval inside let or with blocks.
|
* and functions defined by eval inside let or with blocks.
|
||||||
*/
|
*/
|
||||||
JSObject *parent = &fp->varobj(cx);
|
JSObject *parent = &cx->stack.currentVarObj();
|
||||||
|
|
||||||
/* ES5 10.5 (NB: with subsequent errata). */
|
/* ES5 10.5 (NB: with subsequent errata). */
|
||||||
jsid id = ATOM_TO_JSID(fun->atom);
|
jsid id = ATOM_TO_JSID(fun->atom);
|
||||||
|
@ -811,7 +811,7 @@ template void JS_FASTCALL stubs::DefFun<false>(VMFrame &f, JSFunction *fun);
|
||||||
#define RELATIONAL(OP) \
|
#define RELATIONAL(OP) \
|
||||||
JS_BEGIN_MACRO \
|
JS_BEGIN_MACRO \
|
||||||
JSContext *cx = f.cx; \
|
JSContext *cx = f.cx; \
|
||||||
JSFrameRegs ®s = f.regs; \
|
FrameRegs ®s = f.regs; \
|
||||||
Value rval = regs.sp[-1]; \
|
Value rval = regs.sp[-1]; \
|
||||||
Value lval = regs.sp[-2]; \
|
Value lval = regs.sp[-2]; \
|
||||||
bool cond; \
|
bool cond; \
|
||||||
|
@ -879,7 +879,7 @@ static inline bool
|
||||||
StubEqualityOp(VMFrame &f)
|
StubEqualityOp(VMFrame &f)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSFrameRegs ®s = f.regs;
|
FrameRegs ®s = f.regs;
|
||||||
|
|
||||||
Value rval = regs.sp[-1];
|
Value rval = regs.sp[-1];
|
||||||
Value lval = regs.sp[-2];
|
Value lval = regs.sp[-2];
|
||||||
|
@ -1006,7 +1006,7 @@ void JS_FASTCALL
|
||||||
stubs::Add(VMFrame &f)
|
stubs::Add(VMFrame &f)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSFrameRegs ®s = f.regs;
|
FrameRegs ®s = f.regs;
|
||||||
Value rval = regs.sp[-1];
|
Value rval = regs.sp[-1];
|
||||||
Value lval = regs.sp[-2];
|
Value lval = regs.sp[-2];
|
||||||
|
|
||||||
|
@ -1078,7 +1078,7 @@ void JS_FASTCALL
|
||||||
stubs::Sub(VMFrame &f)
|
stubs::Sub(VMFrame &f)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSFrameRegs ®s = f.regs;
|
FrameRegs ®s = f.regs;
|
||||||
double d1, d2;
|
double d1, d2;
|
||||||
if (!ValueToNumber(cx, regs.sp[-2], &d1) ||
|
if (!ValueToNumber(cx, regs.sp[-2], &d1) ||
|
||||||
!ValueToNumber(cx, regs.sp[-1], &d2)) {
|
!ValueToNumber(cx, regs.sp[-1], &d2)) {
|
||||||
|
@ -1092,7 +1092,7 @@ void JS_FASTCALL
|
||||||
stubs::Mul(VMFrame &f)
|
stubs::Mul(VMFrame &f)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSFrameRegs ®s = f.regs;
|
FrameRegs ®s = f.regs;
|
||||||
double d1, d2;
|
double d1, d2;
|
||||||
if (!ValueToNumber(cx, regs.sp[-2], &d1) ||
|
if (!ValueToNumber(cx, regs.sp[-2], &d1) ||
|
||||||
!ValueToNumber(cx, regs.sp[-1], &d2)) {
|
!ValueToNumber(cx, regs.sp[-1], &d2)) {
|
||||||
|
@ -1107,7 +1107,7 @@ stubs::Div(VMFrame &f)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSRuntime *rt = cx->runtime;
|
JSRuntime *rt = cx->runtime;
|
||||||
JSFrameRegs ®s = f.regs;
|
FrameRegs ®s = f.regs;
|
||||||
|
|
||||||
double d1, d2;
|
double d1, d2;
|
||||||
if (!ValueToNumber(cx, regs.sp[-2], &d1) ||
|
if (!ValueToNumber(cx, regs.sp[-2], &d1) ||
|
||||||
|
@ -1139,7 +1139,7 @@ void JS_FASTCALL
|
||||||
stubs::Mod(VMFrame &f)
|
stubs::Mod(VMFrame &f)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSFrameRegs ®s = f.regs;
|
FrameRegs ®s = f.regs;
|
||||||
|
|
||||||
Value &lref = regs.sp[-2];
|
Value &lref = regs.sp[-2];
|
||||||
Value &rref = regs.sp[-1];
|
Value &rref = regs.sp[-1];
|
||||||
|
@ -1202,7 +1202,7 @@ void JS_FASTCALL
|
||||||
stubs::Trap(VMFrame &f, uint32 trapTypes)
|
stubs::Trap(VMFrame &f, uint32 trapTypes)
|
||||||
{
|
{
|
||||||
Value rval;
|
Value rval;
|
||||||
jsbytecode *pc = f.cx->regs->pc;
|
jsbytecode *pc = f.cx->regs().pc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Trap may be called for a single-step interrupt trap and/or a
|
* Trap may be called for a single-step interrupt trap and/or a
|
||||||
|
@ -1296,7 +1296,7 @@ void JS_FASTCALL
|
||||||
stubs::InitElem(VMFrame &f, uint32 last)
|
stubs::InitElem(VMFrame &f, uint32 last)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSFrameRegs ®s = f.regs;
|
FrameRegs ®s = f.regs;
|
||||||
|
|
||||||
/* Pop the element's value into rval. */
|
/* Pop the element's value into rval. */
|
||||||
JS_ASSERT(regs.sp - f.fp()->base() >= 3);
|
JS_ASSERT(regs.sp - f.fp()->base() >= 3);
|
||||||
|
@ -1836,7 +1836,7 @@ static bool JS_FASTCALL
|
||||||
InlineGetProp(VMFrame &f)
|
InlineGetProp(VMFrame &f)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSFrameRegs ®s = f.regs;
|
FrameRegs ®s = f.regs;
|
||||||
|
|
||||||
Value *vp = &f.regs.sp[-1];
|
Value *vp = &f.regs.sp[-1];
|
||||||
JSObject *obj = ValueToObject(f.cx, vp);
|
JSObject *obj = ValueToObject(f.cx, vp);
|
||||||
|
@ -1913,7 +1913,7 @@ void JS_FASTCALL
|
||||||
stubs::CallProp(VMFrame &f, JSAtom *origAtom)
|
stubs::CallProp(VMFrame &f, JSAtom *origAtom)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSFrameRegs ®s = f.regs;
|
FrameRegs ®s = f.regs;
|
||||||
|
|
||||||
Value lval;
|
Value lval;
|
||||||
lval = regs.sp[-1];
|
lval = regs.sp[-1];
|
||||||
|
@ -1994,7 +1994,7 @@ stubs::CallProp(VMFrame &f, JSAtom *origAtom)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if JS_HAS_NO_SUCH_METHOD
|
#if JS_HAS_NO_SUCH_METHOD
|
||||||
if (JS_UNLIKELY(rval.isUndefined()) && regs.sp[-1].isObject()) {
|
if (JS_UNLIKELY(rval.isPrimitive()) && regs.sp[-1].isObject()) {
|
||||||
regs.sp[-2].setString(origAtom);
|
regs.sp[-2].setString(origAtom);
|
||||||
if (!js_OnUnknownMethod(cx, regs.sp - 2))
|
if (!js_OnUnknownMethod(cx, regs.sp - 2))
|
||||||
THROW();
|
THROW();
|
||||||
|
@ -2005,7 +2005,7 @@ stubs::CallProp(VMFrame &f, JSAtom *origAtom)
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
stubs::Length(VMFrame &f)
|
stubs::Length(VMFrame &f)
|
||||||
{
|
{
|
||||||
JSFrameRegs ®s = f.regs;
|
FrameRegs ®s = f.regs;
|
||||||
Value *vp = ®s.sp[-1];
|
Value *vp = ®s.sp[-1];
|
||||||
|
|
||||||
if (vp->isString()) {
|
if (vp->isString()) {
|
||||||
|
@ -2042,7 +2042,7 @@ InitPropOrMethod(VMFrame &f, JSAtom *atom, JSOp op)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSRuntime *rt = cx->runtime;
|
JSRuntime *rt = cx->runtime;
|
||||||
JSFrameRegs ®s = f.regs;
|
FrameRegs ®s = f.regs;
|
||||||
|
|
||||||
/* Load the property's initial value into rval. */
|
/* Load the property's initial value into rval. */
|
||||||
JS_ASSERT(regs.sp - f.fp()->base() >= 2);
|
JS_ASSERT(regs.sp - f.fp()->base() >= 2);
|
||||||
|
@ -2224,7 +2224,7 @@ JSBool JS_FASTCALL
|
||||||
stubs::InstanceOf(VMFrame &f)
|
stubs::InstanceOf(VMFrame &f)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSFrameRegs ®s = f.regs;
|
FrameRegs ®s = f.regs;
|
||||||
|
|
||||||
const Value &rref = regs.sp[-1];
|
const Value &rref = regs.sp[-1];
|
||||||
if (rref.isPrimitive()) {
|
if (rref.isPrimitive()) {
|
||||||
|
@ -2263,7 +2263,7 @@ stubs::ArgCnt(VMFrame &f)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSRuntime *rt = cx->runtime;
|
JSRuntime *rt = cx->runtime;
|
||||||
JSStackFrame *fp = f.fp();
|
StackFrame *fp = f.fp();
|
||||||
|
|
||||||
jsid id = ATOM_TO_JSID(rt->atomState.lengthAtom);
|
jsid id = ATOM_TO_JSID(rt->atomState.lengthAtom);
|
||||||
f.regs.sp++;
|
f.regs.sp++;
|
||||||
|
@ -2274,9 +2274,9 @@ stubs::ArgCnt(VMFrame &f)
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
stubs::EnterBlock(VMFrame &f, JSObject *obj)
|
stubs::EnterBlock(VMFrame &f, JSObject *obj)
|
||||||
{
|
{
|
||||||
JSFrameRegs ®s = f.regs;
|
FrameRegs ®s = f.regs;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
JSStackFrame *fp = f.fp();
|
StackFrame *fp = f.fp();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
JS_ASSERT(obj->isStaticBlock());
|
JS_ASSERT(obj->isStaticBlock());
|
||||||
|
@ -2316,7 +2316,7 @@ void JS_FASTCALL
|
||||||
stubs::LeaveBlock(VMFrame &f, JSObject *blockChain)
|
stubs::LeaveBlock(VMFrame &f, JSObject *blockChain)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSStackFrame *fp = f.fp();
|
StackFrame *fp = f.fp();
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
JS_ASSERT(blockChain->isStaticBlock());
|
JS_ASSERT(blockChain->isStaticBlock());
|
||||||
|
@ -2552,9 +2552,9 @@ void JS_FASTCALL
|
||||||
stubs::DefVarOrConst(VMFrame &f, JSAtom *atom)
|
stubs::DefVarOrConst(VMFrame &f, JSAtom *atom)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSStackFrame *fp = f.fp();
|
StackFrame *fp = f.fp();
|
||||||
|
|
||||||
JSObject *obj = &fp->varobj(cx);
|
JSObject *obj = &cx->stack.currentVarObj();
|
||||||
JS_ASSERT(!obj->getOps()->defineProperty);
|
JS_ASSERT(!obj->getOps()->defineProperty);
|
||||||
uintN attrs = JSPROP_ENUMERATE;
|
uintN attrs = JSPROP_ENUMERATE;
|
||||||
if (!fp->isEvalFrame())
|
if (!fp->isEvalFrame())
|
||||||
|
@ -2598,9 +2598,8 @@ void JS_FASTCALL
|
||||||
stubs::SetConst(VMFrame &f, JSAtom *atom)
|
stubs::SetConst(VMFrame &f, JSAtom *atom)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSStackFrame *fp = f.fp();
|
|
||||||
|
|
||||||
JSObject *obj = &fp->varobj(cx);
|
JSObject *obj = &cx->stack.currentVarObj();
|
||||||
const Value &ref = f.regs.sp[-1];
|
const Value &ref = f.regs.sp[-1];
|
||||||
if (!obj->defineProperty(cx, ATOM_TO_JSID(atom), ref,
|
if (!obj->defineProperty(cx, ATOM_TO_JSID(atom), ref,
|
||||||
PropertyStub, StrictPropertyStub,
|
PropertyStub, StrictPropertyStub,
|
||||||
|
|
|
@ -118,20 +118,20 @@ TrampolineCompiler::generateForceReturn(Assembler &masm)
|
||||||
{
|
{
|
||||||
/* if (hasArgsObj() || hasCallObj()) stubs::PutActivationObjects() */
|
/* if (hasArgsObj() || hasCallObj()) stubs::PutActivationObjects() */
|
||||||
Jump noActObjs = masm.branchTest32(Assembler::Zero, FrameFlagsAddress(),
|
Jump noActObjs = masm.branchTest32(Assembler::Zero, FrameFlagsAddress(),
|
||||||
Imm32(JSFRAME_HAS_CALL_OBJ | JSFRAME_HAS_ARGS_OBJ));
|
Imm32(StackFrame::HAS_CALL_OBJ | StackFrame::HAS_ARGS_OBJ));
|
||||||
masm.fallibleVMCall(JS_FUNC_TO_DATA_PTR(void *, stubs::PutActivationObjects), NULL, 0);
|
masm.fallibleVMCall(JS_FUNC_TO_DATA_PTR(void *, stubs::PutActivationObjects), NULL, 0);
|
||||||
noActObjs.linkTo(masm.label(), &masm);
|
noActObjs.linkTo(masm.label(), &masm);
|
||||||
|
|
||||||
/* Store any known return value */
|
/* Store any known return value */
|
||||||
masm.loadValueAsComponents(UndefinedValue(), JSReturnReg_Type, JSReturnReg_Data);
|
masm.loadValueAsComponents(UndefinedValue(), JSReturnReg_Type, JSReturnReg_Data);
|
||||||
Jump rvalClear = masm.branchTest32(Assembler::Zero,
|
Jump rvalClear = masm.branchTest32(Assembler::Zero,
|
||||||
FrameFlagsAddress(), Imm32(JSFRAME_HAS_RVAL));
|
FrameFlagsAddress(), Imm32(StackFrame::HAS_RVAL));
|
||||||
Address rvalAddress(JSFrameReg, JSStackFrame::offsetOfReturnValue());
|
Address rvalAddress(JSFrameReg, StackFrame::offsetOfReturnValue());
|
||||||
masm.loadValueAsComponents(rvalAddress, JSReturnReg_Type, JSReturnReg_Data);
|
masm.loadValueAsComponents(rvalAddress, JSReturnReg_Type, JSReturnReg_Data);
|
||||||
rvalClear.linkTo(masm.label(), &masm);
|
rvalClear.linkTo(masm.label(), &masm);
|
||||||
|
|
||||||
/* Return to the caller */
|
/* Return to the caller */
|
||||||
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfncode()), Registers::ReturnReg);
|
masm.loadPtr(Address(JSFrameReg, StackFrame::offsetOfNcode()), Registers::ReturnReg);
|
||||||
masm.jump(Registers::ReturnReg);
|
masm.jump(Registers::ReturnReg);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ extern PopActiveVMFrame:PROC
|
||||||
|
|
||||||
.CODE
|
.CODE
|
||||||
|
|
||||||
; JSBool JaegerTrampoline(JSContext *cx, JSStackFrame *fp, void *code,
|
; JSBool JaegerTrampoline(JSContext *cx, StackFrame *fp, void *code,
|
||||||
; Value *stackLimit, void *safePoint);
|
; Value *stackLimit, void *safePoint);
|
||||||
JaegerTrampoline PROC FRAME
|
JaegerTrampoline PROC FRAME
|
||||||
push rbp
|
push rbp
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
.text
|
.text
|
||||||
.intel_syntax noprefix
|
.intel_syntax noprefix
|
||||||
|
|
||||||
# JSBool JaegerTrampoline(JSContext *cx, JSStackFrame *fp, void *code,
|
# JSBool JaegerTrampoline(JSContext *cx, StackFrame *fp, void *code,
|
||||||
# Value *stackLimit, void *safePoint)#
|
# Value *stackLimit, void *safePoint)#
|
||||||
.globl JaegerTrampoline
|
.globl JaegerTrampoline
|
||||||
.def JaegerTrampoline
|
.def JaegerTrampoline
|
||||||
|
|
|
@ -37,8 +37,8 @@
|
||||||
|
|
||||||
.text
|
.text
|
||||||
|
|
||||||
/ JSBool JaegerTrampoline(JSContext *cx, JSStackFrame *fp, void *code,
|
/ JSBool JaegerTrampoline(JSContext *cx, StackFrame *fp, void *code,
|
||||||
/ JSFrameRegs *regs, uintptr_t inlineCallCount)
|
/ FrameRegs *regs, uintptr_t inlineCallCount)
|
||||||
.global JaegerTrampoline
|
.global JaegerTrampoline
|
||||||
.type JaegerTrampoline, @function
|
.type JaegerTrampoline, @function
|
||||||
JaegerTrampoline:
|
JaegerTrampoline:
|
||||||
|
|
|
@ -37,8 +37,8 @@
|
||||||
|
|
||||||
.text
|
.text
|
||||||
|
|
||||||
/ JSBool JaegerTrampoline(JSContext *cx, JSStackFrame *fp, void *code,
|
/ JSBool JaegerTrampoline(JSContext *cx, StackFrame *fp, void *code,
|
||||||
/ JSFrameRegs *regs, uintptr_t inlineCallCount)
|
/ FrameRegs *regs, uintptr_t inlineCallCount)
|
||||||
.global JaegerTrampoline
|
.global JaegerTrampoline
|
||||||
.type JaegerTrampoline, @function
|
.type JaegerTrampoline, @function
|
||||||
JaegerTrampoline:
|
JaegerTrampoline:
|
||||||
|
|
|
@ -1800,7 +1800,7 @@ GetTrapArgs(JSContext *cx, uintN argc, jsval *argv, JSScript **scriptp,
|
||||||
uintN intarg;
|
uintN intarg;
|
||||||
JSScript *script;
|
JSScript *script;
|
||||||
|
|
||||||
*scriptp = JS_GetScriptedCaller(cx, NULL)->script();
|
*scriptp = JS_GetFrameScript(cx, JS_GetScriptedCaller(cx, NULL));
|
||||||
*ip = 0;
|
*ip = 0;
|
||||||
if (argc != 0) {
|
if (argc != 0) {
|
||||||
v = argv[0];
|
v = argv[0];
|
||||||
|
@ -1823,11 +1823,12 @@ GetTrapArgs(JSContext *cx, uintN argc, jsval *argv, JSScript **scriptp,
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSTrapStatus
|
static JSTrapStatus
|
||||||
TrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval,
|
TrapHandler(JSContext *cx, JSScript *, jsbytecode *pc, jsval *rval,
|
||||||
jsval closure)
|
jsval closure)
|
||||||
{
|
{
|
||||||
JSString *str = JSVAL_TO_STRING(closure);
|
JSString *str = JSVAL_TO_STRING(closure);
|
||||||
JSStackFrame *caller = JS_GetScriptedCaller(cx, NULL);
|
JSStackFrame *caller = JS_GetScriptedCaller(cx, NULL);
|
||||||
|
JSScript *script = JS_GetFrameScript(cx, caller);
|
||||||
|
|
||||||
size_t length;
|
size_t length;
|
||||||
const jschar *chars = JS_GetStringCharsAndLength(cx, str, &length);
|
const jschar *chars = JS_GetStringCharsAndLength(cx, str, &length);
|
||||||
|
@ -1835,8 +1836,8 @@ TrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval,
|
||||||
return JSTRAP_ERROR;
|
return JSTRAP_ERROR;
|
||||||
|
|
||||||
if (!JS_EvaluateUCInStackFrame(cx, caller, chars, length,
|
if (!JS_EvaluateUCInStackFrame(cx, caller, chars, length,
|
||||||
caller->script()->filename,
|
script->filename,
|
||||||
caller->script()->lineno,
|
script->lineno,
|
||||||
rval)) {
|
rval)) {
|
||||||
return JSTRAP_ERROR;
|
return JSTRAP_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -1938,7 +1939,7 @@ LineToPC(JSContext *cx, uintN argc, jsval *vp)
|
||||||
JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_LINE2PC_USAGE);
|
JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_LINE2PC_USAGE);
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
script = JS_GetScriptedCaller(cx, NULL)->script();
|
script = JS_GetFrameScript(cx, JS_GetScriptedCaller(cx, NULL));
|
||||||
if (!GetTrapArgs(cx, argc, JS_ARGV(cx, vp), &script, &i))
|
if (!GetTrapArgs(cx, argc, JS_ARGV(cx, vp), &script, &i))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
lineno = (i == 0) ? script->lineno : (uintN)i;
|
lineno = (i == 0) ? script->lineno : (uintN)i;
|
||||||
|
@ -3218,7 +3219,8 @@ ResolveClass(JSContext *cx, JSObject *obj, jsid id, JSBool *resolved)
|
||||||
|
|
||||||
if (!*resolved) {
|
if (!*resolved) {
|
||||||
if (JSID_IS_ATOM(id, CLASS_ATOM(cx, Reflect))) {
|
if (JSID_IS_ATOM(id, CLASS_ATOM(cx, Reflect))) {
|
||||||
if (!js_InitReflectClass(cx, obj))
|
if (!IsStandardClassResolved(obj, &js_ReflectClass) &&
|
||||||
|
!js_InitReflectClass(cx, obj))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
*resolved = JS_TRUE;
|
*resolved = JS_TRUE;
|
||||||
}
|
}
|
||||||
|
@ -3573,6 +3575,8 @@ EvalInContext(JSContext *cx, uintN argc, jsval *vp)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
JSStackFrame *fp = JS_GetScriptedCaller(cx, NULL);
|
JSStackFrame *fp = JS_GetScriptedCaller(cx, NULL);
|
||||||
|
JSScript *script = JS_GetFrameScript(cx, fp);
|
||||||
|
jsbytecode *pc = JS_GetFramePC(cx, fp);
|
||||||
{
|
{
|
||||||
JSAutoEnterCompartment ac;
|
JSAutoEnterCompartment ac;
|
||||||
uintN flags;
|
uintN flags;
|
||||||
|
@ -3591,8 +3595,8 @@ EvalInContext(JSContext *cx, uintN argc, jsval *vp)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!JS_EvaluateUCScript(cx, sobj, src, srclen,
|
if (!JS_EvaluateUCScript(cx, sobj, src, srclen,
|
||||||
fp->script()->filename,
|
script->filename,
|
||||||
JS_PCToLineNumber(cx, fp->script(), fp->pc(cx)),
|
JS_PCToLineNumber(cx, script, pc),
|
||||||
vp)) {
|
vp)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -3618,7 +3622,7 @@ EvalInFrame(JSContext *cx, uintN argc, jsval *vp)
|
||||||
? !!(JSVAL_TO_BOOLEAN(argv[2]))
|
? !!(JSVAL_TO_BOOLEAN(argv[2]))
|
||||||
: false;
|
: false;
|
||||||
|
|
||||||
JS_ASSERT(cx->hasfp());
|
JS_ASSERT(cx->running());
|
||||||
|
|
||||||
FrameRegsIter fi(cx);
|
FrameRegsIter fi(cx);
|
||||||
for (uint32 i = 0; i < upCount; ++i, ++fi) {
|
for (uint32 i = 0; i < upCount; ++i, ++fi) {
|
||||||
|
@ -3626,8 +3630,8 @@ EvalInFrame(JSContext *cx, uintN argc, jsval *vp)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSStackFrame *const fp = fi.fp();
|
StackFrame *const fp = fi.fp();
|
||||||
if (!JS_IsScriptFrame(cx, fp)) {
|
if (!fp->isScriptFrame()) {
|
||||||
JS_ReportError(cx, "cannot eval in non-script frame");
|
JS_ReportError(cx, "cannot eval in non-script frame");
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
@ -3641,7 +3645,7 @@ EvalInFrame(JSContext *cx, uintN argc, jsval *vp)
|
||||||
if (!chars)
|
if (!chars)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
JSBool ok = JS_EvaluateUCInStackFrame(cx, fp, chars, length,
|
JSBool ok = JS_EvaluateUCInStackFrame(cx, Jsvalify(fp), chars, length,
|
||||||
fp->script()->filename,
|
fp->script()->filename,
|
||||||
JS_PCToLineNumber(cx, fp->script(),
|
JS_PCToLineNumber(cx, fp->script(),
|
||||||
fi.pc()),
|
fi.pc()),
|
||||||
|
@ -4463,7 +4467,6 @@ Snarf(JSContext *cx, uintN argc, jsval *vp)
|
||||||
{
|
{
|
||||||
JSString *str;
|
JSString *str;
|
||||||
const char *pathname;
|
const char *pathname;
|
||||||
JSStackFrame *fp;
|
|
||||||
|
|
||||||
if (!argc)
|
if (!argc)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
@ -4476,10 +4479,11 @@ Snarf(JSContext *cx, uintN argc, jsval *vp)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
/* Get the currently executing script's name. */
|
/* Get the currently executing script's name. */
|
||||||
fp = JS_GetScriptedCaller(cx, NULL);
|
JSStackFrame *fp = JS_GetScriptedCaller(cx, NULL);
|
||||||
JS_ASSERT(fp && fp->script()->filename);
|
JSScript *script = JS_GetFrameScript(cx, fp);
|
||||||
|
JS_ASSERT(fp && script->filename);
|
||||||
#ifdef XP_UNIX
|
#ifdef XP_UNIX
|
||||||
pathname = MakeAbsolutePathname(cx, fp->script()->filename, filename.ptr());
|
pathname = MakeAbsolutePathname(cx, script->filename, filename.ptr());
|
||||||
if (!pathname)
|
if (!pathname)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
#else
|
#else
|
||||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче