зеркало из https://github.com/mozilla/pjs.git
Merge from mozilla-central
This commit is contained in:
Коммит
0d8887fa87
|
@ -5393,7 +5393,7 @@ nsContentUtils::CanAccessNativeAnon()
|
|||
// Some code is running, we can't make the assumption, as above, but we
|
||||
// can't use a native frame, so clear fp.
|
||||
fp = nsnull;
|
||||
} else if (!fp->script) {
|
||||
} else if (!fp->hasScript()) {
|
||||
fp = nsnull;
|
||||
}
|
||||
|
||||
|
@ -5408,8 +5408,8 @@ nsContentUtils::CanAccessNativeAnon()
|
|||
// if they've been cloned into less privileged contexts.
|
||||
static const char prefix[] = "chrome://global/";
|
||||
const char *filename;
|
||||
if (fp && fp->script &&
|
||||
(filename = fp->script->filename) &&
|
||||
if (fp && fp->hasScript() &&
|
||||
(filename = fp->getScript()->filename) &&
|
||||
!strncmp(filename, prefix, NS_ARRAY_LENGTH(prefix) - 1)) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
|
|
@ -4892,8 +4892,8 @@ nsDOMClassInfo::ShutDown()
|
|||
// Window helper
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCommonWindowSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
|
||||
JSObject *globalObj, JSObject **parentObj)
|
||||
nsInnerWindowSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
|
||||
JSObject *globalObj, JSObject **parentObj)
|
||||
{
|
||||
// Normally ::PreCreate() is used to give XPConnect the parent
|
||||
// object for the object that's being wrapped, this parent object is
|
||||
|
@ -4911,25 +4911,30 @@ nsCommonWindowSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
|
|||
NS_ASSERTION(sgo, "nativeObj not a global object!");
|
||||
|
||||
nsGlobalWindow *win = nsGlobalWindow::FromSupports(nativeObj);
|
||||
|
||||
if (win->IsOuterWindow()) {
|
||||
win->EnsureInnerWindow();
|
||||
JSObject *winObj = win->FastGetGlobalJSObject();
|
||||
if (!winObj) {
|
||||
NS_ASSERTION(win->GetOuterWindowInternal()->IsCreatingInnerWindow(),
|
||||
"should have a JS object by this point");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (sgo) {
|
||||
*parentObj = sgo->GetGlobalJSObject();
|
||||
*parentObj = winObj;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (*parentObj) {
|
||||
return win->IsChromeWindow() ? NS_OK : NS_SUCCESS_NEEDS_XOW;
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
nsOuterWindowSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
|
||||
JSObject *globalObj, JSObject **parentObj)
|
||||
{
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(nativeObj));
|
||||
NS_ASSERTION(sgo, "nativeObj not a global object!");
|
||||
|
||||
nsGlobalWindow *win = nsGlobalWindow::FromSupports(nativeObj);
|
||||
if (!win->EnsureInnerWindow()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// We're most likely being called when the global object is
|
||||
// created, at that point we won't get a nsIScriptContext but we
|
||||
// know we're called on the correct context so we return globalObj
|
||||
|
||||
*parentObj = globalObj;
|
||||
|
||||
*parentObj = win->GetCurrentInnerWindowInternal()->FastGetGlobalJSObject();
|
||||
return win->IsChromeWindow() ? NS_OK : NS_SUCCESS_NEEDS_XOW;
|
||||
}
|
||||
|
||||
|
@ -6662,33 +6667,33 @@ nsCommonWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
|||
my_cx = (JSContext *)my_context->GetNativeContext();
|
||||
}
|
||||
|
||||
JSBool ok;
|
||||
jsval exn;
|
||||
{
|
||||
JSBool ok = JS_TRUE;
|
||||
jsval exn = JSVAL_VOID;
|
||||
if (win->IsInnerWindow()) {
|
||||
JSAutoRequest transfer(my_cx);
|
||||
|
||||
JSObject *realObj;
|
||||
wrapper->GetJSObject(&realObj);
|
||||
|
||||
|
||||
// Don't resolve standard classes on XPCNativeWrapper etc, only
|
||||
// resolve them if we're resolving on the real global object.
|
||||
ok = obj == realObj ?
|
||||
::JS_ResolveStandardClass(my_cx, obj, id, &did_resolve) :
|
||||
JS_TRUE;
|
||||
|
||||
|
||||
if (!ok) {
|
||||
// Trust the JS engine (or the script security manager) to set
|
||||
// the exception in the JS engine.
|
||||
|
||||
|
||||
if (!JS_GetPendingException(my_cx, &exn)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
|
||||
// Return NS_OK to avoid stomping over the exception that was passed
|
||||
// down from the ResolveStandardClass call.
|
||||
// Note that the order of the JS_ClearPendingException and
|
||||
// JS_SetPendingException is important in the case that my_cx == cx.
|
||||
|
||||
|
||||
JS_ClearPendingException(my_cx);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -514,8 +514,6 @@ protected:
|
|||
PRBool *did_resolve);
|
||||
|
||||
public:
|
||||
NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
|
||||
JSObject *globalObj, JSObject **parentObj);
|
||||
#ifdef DEBUG
|
||||
NS_IMETHOD PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj)
|
||||
|
@ -578,6 +576,8 @@ protected:
|
|||
static PRBool sResolving;
|
||||
|
||||
public:
|
||||
NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
|
||||
JSObject *globalObj, JSObject **parentObj);
|
||||
NS_IMETHOD AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj, jsid id, jsval *vp, PRBool *_retval);
|
||||
NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
|
@ -607,6 +607,8 @@ protected:
|
|||
}
|
||||
|
||||
public:
|
||||
NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
|
||||
JSObject *globalObj, JSObject **parentObj);
|
||||
// We WANT_ADDPROPERTY, but are content to inherit it from nsEventReceiverSH.
|
||||
NS_IMETHOD OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
|
||||
JSObject * obj, JSObject * *_retval);
|
||||
|
|
|
@ -1514,7 +1514,8 @@ public:
|
|||
WindowStateHolder(nsGlobalWindow *aWindow,
|
||||
nsIXPConnectJSObjectHolder *aHolder,
|
||||
nsNavigator *aNavigator,
|
||||
nsIXPConnectJSObjectHolder *aOuterProto);
|
||||
nsIXPConnectJSObjectHolder *aOuterProto,
|
||||
nsIXPConnectJSObjectHolder *aOuterRealProto);
|
||||
|
||||
nsGlobalWindow* GetInnerWindow() { return mInnerWindow; }
|
||||
nsIXPConnectJSObjectHolder *GetInnerWindowHolder()
|
||||
|
@ -1522,6 +1523,7 @@ public:
|
|||
|
||||
nsNavigator* GetNavigator() { return mNavigator; }
|
||||
nsIXPConnectJSObjectHolder* GetOuterProto() { return mOuterProto; }
|
||||
nsIXPConnectJSObjectHolder* GetOuterRealProto() { return mOuterRealProto; }
|
||||
|
||||
void DidRestoreWindow()
|
||||
{
|
||||
|
@ -1530,6 +1532,7 @@ public:
|
|||
mInnerWindowHolder = nsnull;
|
||||
mNavigator = nsnull;
|
||||
mOuterProto = nsnull;
|
||||
mOuterRealProto = nsnull;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -1541,6 +1544,7 @@ protected:
|
|||
nsCOMPtr<nsIXPConnectJSObjectHolder> mInnerWindowHolder;
|
||||
nsRefPtr<nsNavigator> mNavigator;
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> mOuterProto;
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> mOuterRealProto;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(WindowStateHolder, WINDOWSTATEHOLDER_IID)
|
||||
|
@ -1548,10 +1552,12 @@ NS_DEFINE_STATIC_IID_ACCESSOR(WindowStateHolder, WINDOWSTATEHOLDER_IID)
|
|||
WindowStateHolder::WindowStateHolder(nsGlobalWindow *aWindow,
|
||||
nsIXPConnectJSObjectHolder *aHolder,
|
||||
nsNavigator *aNavigator,
|
||||
nsIXPConnectJSObjectHolder *aOuterProto)
|
||||
nsIXPConnectJSObjectHolder *aOuterProto,
|
||||
nsIXPConnectJSObjectHolder *aOuterRealProto)
|
||||
: mInnerWindow(aWindow),
|
||||
mNavigator(aNavigator),
|
||||
mOuterProto(aOuterProto)
|
||||
mOuterProto(aOuterProto),
|
||||
mOuterRealProto(aOuterRealProto)
|
||||
{
|
||||
NS_PRECONDITION(aWindow, "null window");
|
||||
NS_PRECONDITION(aWindow->IsInnerWindow(), "Saving an outer window");
|
||||
|
@ -1611,9 +1617,6 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
|||
if (IsFrozen()) {
|
||||
// This outer is now getting its first inner, thaw the outer now
|
||||
// that it's ready and is getting an inner window.
|
||||
mContext->CreateOuterObject(this, aDocument->NodePrincipal());
|
||||
mContext->DidInitializeContext();
|
||||
mJSObject = (JSObject *)mContext->GetNativeGlobal();
|
||||
|
||||
Thaw();
|
||||
}
|
||||
|
@ -1727,12 +1730,20 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
|||
|
||||
JSAutoRequest ar(cx);
|
||||
|
||||
nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
|
||||
NS_ASSERTION(!aState || wsh, "What kind of weird state are you giving me here?");
|
||||
|
||||
// Make sure to clear scope on the outer window *before* we
|
||||
// initialize the new inner window. If we don't, things
|
||||
// (Object.prototype etc) could leak from the old outer to the new
|
||||
// inner scope.
|
||||
mContext->ClearScope(mJSObject, PR_FALSE);
|
||||
|
||||
// This code should not be called during shutdown any more (now that
|
||||
// we don't ever call SetNewDocument(nsnull), so no need to null
|
||||
// check xpc here.
|
||||
nsIXPConnect *xpc = nsContentUtils::XPConnect();
|
||||
nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
|
||||
if (reUseInnerWindow) {
|
||||
// We're reusing the current inner window.
|
||||
NS_ASSERTION(!currentInner->IsFrozen(),
|
||||
|
@ -1744,9 +1755,6 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
|||
}
|
||||
} else {
|
||||
if (aState) {
|
||||
nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
|
||||
NS_ASSERTION(wsh, "What kind of weird state are you giving me here?");
|
||||
|
||||
newInnerWindow = wsh->GetInnerWindow();
|
||||
mInnerWindowHolder = wsh->GetInnerWindowHolder();
|
||||
|
||||
|
@ -1820,7 +1828,6 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
|||
getter_AddRefs(holder));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) && newGlobal && holder,
|
||||
"Failed to get script global and holder");
|
||||
newInnerWindow->mJSObject = (JSObject *)newGlobal;
|
||||
|
||||
mCreatingInnerWindow = PR_FALSE;
|
||||
Thaw();
|
||||
|
@ -1874,6 +1881,45 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
|||
}
|
||||
|
||||
mInnerWindow = newInnerWindow;
|
||||
|
||||
if (!mJSObject) {
|
||||
mContext->CreateOuterObject(this, newInnerWindow);
|
||||
mContext->DidInitializeContext();
|
||||
mJSObject = (JSObject *)mContext->GetNativeGlobal();
|
||||
} else {
|
||||
// XXX New global object and brain transplant!
|
||||
rv = xpc->GetWrappedNativeOfJSObject(cx, mJSObject,
|
||||
getter_AddRefs(wrapper));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Restore our object's prototype to its original value so we're sure to
|
||||
// update it under ReparentWrappedNativeIfFound.
|
||||
JSObject *proto;
|
||||
wrapper->GetJSObjectPrototype(&proto);
|
||||
if (!JS_SetPrototype(cx, mJSObject, proto)) {
|
||||
NS_ERROR("Can't set prototype");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
|
||||
xpc->ReparentWrappedNativeIfFound(cx, currentInner->mJSObject,
|
||||
newInnerWindow->mJSObject,
|
||||
ToSupports(this),
|
||||
getter_AddRefs(holder));
|
||||
|
||||
if (aState) {
|
||||
if (nsIXPConnectJSObjectHolder *holder = wsh->GetOuterRealProto()) {
|
||||
holder->GetJSObject(&proto);
|
||||
} else {
|
||||
proto = nsnull;
|
||||
}
|
||||
|
||||
if (!JS_SetPrototype(cx, mJSObject, proto)) {
|
||||
NS_ERROR("can't set prototype");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!aState && !reUseInnerWindow) {
|
||||
|
@ -1926,42 +1972,6 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
|||
html_doc);
|
||||
}
|
||||
|
||||
// This code should not be called during shutdown any more (now that
|
||||
// we don't ever call SetNewDocument(nsnull), so no need to null
|
||||
// check xpc here.
|
||||
nsIXPConnect *xpc = nsContentUtils::XPConnect();
|
||||
|
||||
nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
|
||||
if (aState) {
|
||||
// Restoring from session history.
|
||||
|
||||
nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
|
||||
NS_ASSERTION(wsh, "What kind of weird state are you giving me here?");
|
||||
|
||||
// Restore the prototype for the Window/ChromeWindow class in
|
||||
// the outer window scope.
|
||||
nsCOMPtr<nsIClassInfo> ci =
|
||||
do_QueryInterface((nsIScriptGlobalObject *)this);
|
||||
|
||||
rv = xpc->RestoreWrappedNativePrototype(cx, mJSObject, ci,
|
||||
wsh->GetOuterProto());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Refresh the outer window's prototype to what it was when the
|
||||
// window state was saved. This will make the outer window
|
||||
// object (and wrapper) pick up the prototype it had when the
|
||||
// window state was saved. This means Object.prototype etc from
|
||||
// the old inner will again be on the outer window's prototype
|
||||
// chain.
|
||||
|
||||
rv = xpc->GetWrappedNativeOfJSObject(cx, mJSObject,
|
||||
getter_AddRefs(wrapper));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = wrapper->RefreshPrototype();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
if (aDocument) {
|
||||
aDocument->SetScriptGlobalObject(newInnerWindow);
|
||||
}
|
||||
|
@ -9107,21 +9117,39 @@ nsGlobalWindow::SaveWindowState(nsISupports **aState)
|
|||
// to the page.
|
||||
inner->Freeze();
|
||||
|
||||
// Remember the outer window's XPConnect prototype.
|
||||
// Remember the outer window's prototype.
|
||||
JSContext *cx = (JSContext *)mContext->GetNativeContext();
|
||||
JSAutoRequest req(cx);
|
||||
|
||||
nsIXPConnect *xpc = nsContentUtils::XPConnect();
|
||||
|
||||
nsCOMPtr<nsIClassInfo> ci =
|
||||
do_QueryInterface((nsIScriptGlobalObject *)this);
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> proto;
|
||||
nsresult rv = nsContentUtils::XPConnect()->
|
||||
GetWrappedNativePrototype((JSContext *)mContext->GetNativeContext(),
|
||||
mJSObject, ci, getter_AddRefs(proto));
|
||||
nsresult rv = xpc->GetWrappedNativePrototype(cx, mJSObject, ci,
|
||||
getter_AddRefs(proto));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
JSObject *realProto = JS_GetPrototype(cx, mJSObject);
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> realProtoHolder;
|
||||
if (realProto) {
|
||||
rv = xpc->HoldObject(cx, realProto, getter_AddRefs(realProtoHolder));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> state = new WindowStateHolder(inner,
|
||||
mInnerWindowHolder,
|
||||
mNavigator,
|
||||
proto);
|
||||
proto,
|
||||
realProtoHolder);
|
||||
NS_ENSURE_TRUE(state, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
JSObject *wnProto;
|
||||
proto->GetJSObject(&wnProto);
|
||||
if (!JS_SetPrototype(cx, mJSObject, wnProto)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_PAGE_CACHE
|
||||
printf("saving window state, state = %p\n", (void*)state);
|
||||
#endif
|
||||
|
|
|
@ -383,6 +383,11 @@ public:
|
|||
// Make sure this matches the casts we do in QueryInterface().
|
||||
return (nsGlobalWindow *)(nsIScriptGlobalObject *)supports;
|
||||
}
|
||||
static nsISupports *ToSupports(nsGlobalWindow *win)
|
||||
{
|
||||
// Make sure this matches the casts we do in QueryInterface().
|
||||
return (nsISupports *)(nsIScriptGlobalObject *)win;
|
||||
}
|
||||
static nsGlobalWindow *FromWrapper(nsIXPConnectWrappedNative *wrapper)
|
||||
{
|
||||
return FromSupports(wrapper->Native());
|
||||
|
|
|
@ -344,11 +344,11 @@ public:
|
|||
* @param aGlobalObject The script global object to use as our global.
|
||||
*/
|
||||
virtual nsresult CreateOuterObject(nsIScriptGlobalObject *aGlobalObject,
|
||||
nsIPrincipal *aPrincipal) = 0;
|
||||
nsIScriptGlobalObject *aCurrentInner) = 0;
|
||||
|
||||
/**
|
||||
* Prepares this context for use with the current inner window for the
|
||||
* context's global object. This must be called after InitOuterWindow.
|
||||
* context's global object. This must be called after CreateOuterObject.
|
||||
*/
|
||||
virtual nsresult InitOuterWindow() = 0;
|
||||
|
||||
|
|
|
@ -1222,7 +1222,7 @@ nsJSContext::DOMOperationCallback(JSContext *cx)
|
|||
cx->debugHooks->
|
||||
debuggerHandlerData)) {
|
||||
case JSTRAP_RETURN:
|
||||
fp->rval = js::Valueify(rval);
|
||||
fp->setReturnValue(js::Valueify(rval));
|
||||
return JS_TRUE;
|
||||
case JSTRAP_ERROR:
|
||||
cx->throwing = JS_FALSE;
|
||||
|
@ -2582,7 +2582,7 @@ nsJSContext::ConnectToInner(nsIScriptGlobalObject *aNewInner, void *aOuterGlobal
|
|||
{
|
||||
NS_ENSURE_ARG(aNewInner);
|
||||
JSObject *newInnerJSObject = (JSObject *)aNewInner->GetScriptGlobal(JAVASCRIPT);
|
||||
JSObject *myobject = (JSObject *)aOuterGlobal;
|
||||
JSObject *outerGlobal = (JSObject *)aOuterGlobal;
|
||||
|
||||
// Make the inner and outer window both share the same
|
||||
// prototype. The prototype we share is the outer window's
|
||||
|
@ -2603,12 +2603,18 @@ nsJSContext::ConnectToInner(nsIScriptGlobalObject *aNewInner, void *aOuterGlobal
|
|||
// Object.prototype. This way the outer also gets the benefits
|
||||
// of the global scope polluter, and the inner window's
|
||||
// Object.prototype.
|
||||
JSObject *proto = ::JS_GetPrototype(mContext, myobject);
|
||||
JSObject *innerProto = ::JS_GetPrototype(mContext, newInnerJSObject);
|
||||
JSObject *innerProtoProto = ::JS_GetPrototype(mContext, innerProto);
|
||||
JSObject *proto = JS_GetPrototype(mContext, outerGlobal);
|
||||
JSObject *innerProto = JS_GetPrototype(mContext, newInnerJSObject);
|
||||
JSObject *innerProtoProto = JS_GetPrototype(mContext, innerProto);
|
||||
|
||||
::JS_SetPrototype(mContext, newInnerJSObject, proto);
|
||||
::JS_SetPrototype(mContext, proto, innerProtoProto);
|
||||
JS_SetPrototype(mContext, newInnerJSObject, proto);
|
||||
JS_SetPrototype(mContext, proto, innerProtoProto);
|
||||
|
||||
// Now that we're connecting the outer global to the inner one,
|
||||
// we must have transplanted it. The JS engine tries to maintain
|
||||
// the global object's compartment as its default compartment,
|
||||
// so update that now since it might have changed.
|
||||
JS_SetGlobalObject(mContext, outerGlobal);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -2648,11 +2654,8 @@ nsJSContext::InitContext()
|
|||
|
||||
nsresult
|
||||
nsJSContext::CreateOuterObject(nsIScriptGlobalObject *aGlobalObject,
|
||||
nsIPrincipal *aPrincipal)
|
||||
nsIScriptGlobalObject *aCurrentInner)
|
||||
{
|
||||
NS_PRECONDITION(!JS_GetGlobalObject(mContext),
|
||||
"Outer window already initialized");
|
||||
|
||||
nsCOMPtr<nsIDOMChromeWindow> chromeWindow(do_QueryInterface(aGlobalObject));
|
||||
PRUint32 flags = 0;
|
||||
|
||||
|
@ -2666,18 +2669,21 @@ nsJSContext::CreateOuterObject(nsIScriptGlobalObject *aGlobalObject,
|
|||
// need to preserve the <!-- script hiding hack from JS-in-HTML daze
|
||||
// (introduced in 1995 for graceful script degradation in Netscape 1,
|
||||
// Mosaic, and other pre-JS browsers).
|
||||
::JS_SetOptions(mContext, ::JS_GetOptions(mContext) | JSOPTION_XML);
|
||||
JS_SetOptions(mContext, JS_GetOptions(mContext) | JSOPTION_XML);
|
||||
}
|
||||
|
||||
nsIXPConnect *xpc = nsContentUtils::XPConnect();
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
|
||||
nsresult rv =
|
||||
xpc->InitClassesWithNewWrappedGlobal(mContext, aGlobalObject,
|
||||
NS_GET_IID(nsISupports),
|
||||
aPrincipal, EmptyCString(),
|
||||
flags, getter_AddRefs(holder));
|
||||
nsresult rv = xpc->WrapNative(mContext, aCurrentInner->GetGlobalJSObject(),
|
||||
aGlobalObject, NS_GET_IID(nsISupports),
|
||||
getter_AddRefs(holder));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Force our context's global object to be the outer.
|
||||
JSObject *globalObj;
|
||||
holder->GetJSObject(&globalObj);
|
||||
JS_SetGlobalObject(mContext, globalObj);
|
||||
|
||||
// Hold a strong reference to the wrapper for the global to avoid
|
||||
// rooting and unrooting the global object every time its AddRef()
|
||||
// or Release() methods are called
|
||||
|
@ -2696,14 +2702,9 @@ nsJSContext::InitOuterWindow()
|
|||
// properties will be forwarded to the inner window.
|
||||
JS_ClearScope(mContext, global);
|
||||
|
||||
// Now that the inner and outer windows are connected, tell XPConnect to
|
||||
// re-initialize the prototypes on the outer window's scope.
|
||||
nsIXPConnect *xpc = nsContentUtils::XPConnect();
|
||||
nsresult rv = xpc->InitClassesForOuterObject(mContext, global);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
nsCOMPtr<nsIClassInfo> ci(do_QueryInterface(sgo));
|
||||
|
||||
if (ci) {
|
||||
jsval v;
|
||||
|
||||
|
|
|
@ -142,7 +142,7 @@ public:
|
|||
void *aOuterGlobal);
|
||||
virtual nsresult InitContext();
|
||||
virtual nsresult CreateOuterObject(nsIScriptGlobalObject *aGlobalObject,
|
||||
nsIPrincipal *aPrincipal);
|
||||
nsIScriptGlobalObject *aCurrentInner);
|
||||
virtual nsresult InitOuterWindow();
|
||||
virtual PRBool IsContextInitialized();
|
||||
virtual void FinalizeContext();
|
||||
|
|
|
@ -75,11 +75,11 @@ function run_test() {
|
|||
do_check_eq(x, '{"bar":{"bar":42,"schmoo":[]},"qux":42,"quux":42}');
|
||||
|
||||
var x = JSON.stringify(foo, null, " ");
|
||||
do_check_eq(x, '{\n "bar":{\n "bar":42,\n "schmoo":[]\n },\n "qux":42,\n "quux":42\n}');
|
||||
do_check_eq(x, '{\n "bar": {\n "bar": 42,\n "schmoo": []\n },\n "qux": 42,\n "quux": 42\n}');
|
||||
|
||||
foo = {bar:{bar:{}}}
|
||||
var x = JSON.stringify(foo, null, " ");
|
||||
do_check_eq(x, '{\n "bar":{\n "bar":{}\n }\n}');
|
||||
do_check_eq(x, '{\n "bar": {\n "bar": {}\n }\n}');
|
||||
|
||||
var x = JSON.stringify({x:1,arr:[1]}, function (k,v) { return typeof v === 'number' ? 3 : v; });
|
||||
do_check_eq(x, '{"x":3,"arr":[3]}');
|
||||
|
|
|
@ -59,6 +59,8 @@ _TEST_FILES = \
|
|||
test_clipboard_events.html \
|
||||
test_focusrings.xul \
|
||||
test_nodesFromRect.html \
|
||||
test_frameElementWrapping.html \
|
||||
file_frameElementWrapping.html \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_TEST_FILES)
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
<html>
|
||||
<script>
|
||||
function check(elt, expectXOW, message) {
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
var utils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||
.getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
var result = ((utils.getClassName(elt) === 'XPCCrossOriginWrapper') === expectXOW)
|
||||
? "PASS"
|
||||
: "FAIL";
|
||||
|
||||
parent.postMessage(result + ',' + message, '*');
|
||||
}
|
||||
|
||||
try {
|
||||
// true if same origin, throws otherwise
|
||||
var sameOrigin = parent.location.href !== '';
|
||||
} catch (e) {
|
||||
sameOrigin = false;
|
||||
}
|
||||
|
||||
check(frameElement, !sameOrigin,
|
||||
sameOrigin
|
||||
? 'no wrapper needed if same origin'
|
||||
: 'wrapper needed if not same origin');
|
||||
</script>
|
||||
</html>
|
|
@ -0,0 +1,38 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for location object behaviors</title>
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<iframe id="ifr" src="file_frameElementWrapping.html"></iframe>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var count = 0;
|
||||
|
||||
function runTest(result, message) {
|
||||
ok(result === 'PASS', message);
|
||||
|
||||
if (++count === 2)
|
||||
SimpleTest.finish();
|
||||
else
|
||||
$('ifr').contentWindow.location = 'http://example.org/tests/dom/tests/mochitest/general/file_frameElementWrapping.html';
|
||||
}
|
||||
|
||||
window.addEventListener("message",
|
||||
function(event) { runTest.apply(null, event.data.split(',')) },
|
||||
false);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -160,6 +160,7 @@ CPPSRCS = \
|
|||
jsprf.cpp \
|
||||
jspropertycache.cpp \
|
||||
jspropertytree.cpp \
|
||||
jsreflect.cpp \
|
||||
jsregexp.cpp \
|
||||
jsscan.cpp \
|
||||
jsscope.cpp \
|
||||
|
@ -223,6 +224,7 @@ INSTALLED_HEADERS = \
|
|||
jsproto.tbl \
|
||||
jsprvtd.h \
|
||||
jspubtd.h \
|
||||
jsreflect.h \
|
||||
jsregexp.h \
|
||||
jsscan.h \
|
||||
jsscope.h \
|
||||
|
@ -341,9 +343,6 @@ CPPSRCS += Assertions.cpp \
|
|||
|
||||
ifeq (86, $(findstring 86,$(TARGET_CPU)))
|
||||
ifeq (x86_64, $(TARGET_CPU))
|
||||
ifeq ($(OS_ARCH),WINNT)
|
||||
ASFILES += TrampolineMasmX64.asm
|
||||
endif
|
||||
#CPPSRCS += only_on_x86_64.cpp
|
||||
else
|
||||
#CPPSRCS += only_on_x86.cpp
|
||||
|
@ -639,7 +638,7 @@ endif
|
|||
ifeq ($(OS_ARCH),IRIX)
|
||||
ifndef GNU_CC
|
||||
_COMPILE_CFLAGS = $(patsubst -O%,-O1,$(COMPILE_CFLAGS))
|
||||
jsapi.o jsxdrapi.o jsarena.o jsarray.o jsatom.o jsemit.o jsfun.o jsinterp.o jsregexp.o jsparse.o jsopcode.o jsscript.o: %.o: %.cpp Makefile.in
|
||||
jsapi.o jsxdrapi.o jsarena.o jsarray.o jsatom.o jsemit.o jsfun.o jsinterp.o jsreflect.o jsregexp.o jsparse.o jsopcode.o jsscript.o: %.o: %.cpp Makefile.in
|
||||
$(REPORT_BUILD)
|
||||
@$(MAKE_DEPS_AUTO_CXX)
|
||||
$(CXX) -o $@ -c $(_COMPILE_CFLAGS) $<
|
||||
|
|
|
@ -330,3 +330,7 @@ MSG_DEF(JSMSG_CSP_BLOCKED_FUNCTION, 247, 0, JSEXN_ERR, "call to Function() blo
|
|||
MSG_DEF(JSMSG_BAD_GET_SET_FIELD, 248, 1, JSEXN_TYPEERR, "property descriptor's {0} field is neither undefined nor a function")
|
||||
MSG_DEF(JSMSG_BAD_PROXY_FIX, 249, 0, JSEXN_TYPEERR, "proxy was fixed while executing the handler")
|
||||
MSG_DEF(JSMSG_INVALID_EVAL_SCOPE_ARG, 250, 0, JSEXN_EVALERR, "invalid eval scope argument")
|
||||
MSG_DEF(JSMSG_ACCESSOR_WRONG_ARGS, 251, 3, JSEXN_SYNTAXERR, "{0} functions must have {1} argument{2}")
|
||||
MSG_DEF(JSMSG_THROW_TYPE_ERROR, 252, 0, JSEXN_TYPEERR, "'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them")
|
||||
MSG_DEF(JSMSG_BAD_TOISOSTRING_PROP, 253, 0, JSEXN_TYPEERR, "toISOString property is not callable")
|
||||
MSG_DEF(JSMSG_BAD_PARSE_NODE, 254, 0, JSEXN_INTERNALERR, "bad parse node")
|
||||
|
|
|
@ -85,6 +85,8 @@ BEGIN_TEST(testContexts_bug563735)
|
|||
JSBool ok;
|
||||
{
|
||||
JSAutoRequest req(cx2);
|
||||
JSAutoCrossCompartmentCall crossCall;
|
||||
CHECK(crossCall.enter(cx2, global));
|
||||
jsval v = JSVAL_NULL;
|
||||
ok = JS_SetProperty(cx2, global, "x", &v);
|
||||
}
|
||||
|
|
|
@ -113,8 +113,9 @@ public:
|
|||
JSObject *global;
|
||||
bool knownFail;
|
||||
JSAPITestString msgs;
|
||||
JSCrossCompartmentCall *call;
|
||||
|
||||
JSAPITest() : rt(NULL), cx(NULL), global(NULL), knownFail(false) {
|
||||
JSAPITest() : rt(NULL), cx(NULL), global(NULL), knownFail(false), call(NULL) {
|
||||
next = list;
|
||||
list = this;
|
||||
}
|
||||
|
@ -130,10 +131,17 @@ public:
|
|||
return false;
|
||||
JS_BeginRequest(cx);
|
||||
global = createGlobal();
|
||||
return global != NULL;
|
||||
if (!global)
|
||||
return false;
|
||||
call = JS_EnterCrossCompartmentCall(cx, global);
|
||||
return call != NULL;
|
||||
}
|
||||
|
||||
virtual void uninit() {
|
||||
if (call) {
|
||||
JS_LeaveCrossCompartmentCall(call);
|
||||
call = NULL;
|
||||
}
|
||||
if (cx) {
|
||||
JS_EndRequest(cx);
|
||||
JS_DestroyContext(cx);
|
||||
|
@ -273,7 +281,7 @@ protected:
|
|||
|
||||
virtual JSObject * createGlobal() {
|
||||
/* Create the global object. */
|
||||
JSObject *global = JS_NewGlobalObject(cx, getGlobalClass());
|
||||
JSObject *global = JS_NewCompartmentAndGlobalObject(cx, getGlobalClass(), NULL);
|
||||
if (!global)
|
||||
return NULL;
|
||||
|
||||
|
|
|
@ -1823,7 +1823,7 @@ JS_GetGlobalForScopeChain(JSContext *cx)
|
|||
VOUCH_DOES_NOT_REQUIRE_STACK();
|
||||
|
||||
if (cx->fp)
|
||||
return cx->fp->scopeChain->getGlobal();
|
||||
return cx->fp->getScopeChain()->getGlobal();
|
||||
|
||||
JSObject *scope = cx->globalObject;
|
||||
if (!scope) {
|
||||
|
@ -1974,12 +1974,6 @@ JS_RemoveGCThingRoot(JSContext *cx, void **rp)
|
|||
return js_RemoveRoot(cx->runtime, (void *)rp);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_ClearNewbornRoots(JSContext *cx)
|
||||
{
|
||||
JS_CLEAR_WEAK_ROOTS(&cx->weakRoots);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
|
@ -4303,7 +4297,7 @@ js_generic_native_method_dispatcher(JSContext *cx, JSObject *obj,
|
|||
*/
|
||||
if (!ComputeThisFromArgv(cx, argv))
|
||||
return JS_FALSE;
|
||||
js_GetTopStackFrame(cx)->thisv = argv[-1];
|
||||
js_GetTopStackFrame(cx)->setThisValue(argv[-1]);
|
||||
JS_ASSERT(cx->fp->argv == argv);
|
||||
|
||||
/* Clear the last parameter in case too few arguments were passed. */
|
||||
|
@ -4398,7 +4392,6 @@ inline static void
|
|||
LAST_FRAME_CHECKS(JSContext *cx, bool result)
|
||||
{
|
||||
if (!JS_IsRunning(cx)) {
|
||||
cx->weakRoots.lastInternalResult = NULL;
|
||||
LAST_FRAME_EXCEPTION_CHECK(cx, result);
|
||||
}
|
||||
}
|
||||
|
@ -4623,18 +4616,18 @@ JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
|
|||
argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0);
|
||||
if (!argAtom) {
|
||||
fun = NULL;
|
||||
goto out;
|
||||
goto out2;
|
||||
}
|
||||
if (!js_AddLocal(cx, fun, argAtom, JSLOCAL_ARG)) {
|
||||
fun = NULL;
|
||||
goto out;
|
||||
goto out2;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Compiler::compileFunctionBody(cx, fun, principals,
|
||||
chars, length, filename, lineno)) {
|
||||
fun = NULL;
|
||||
goto out;
|
||||
goto out2;
|
||||
}
|
||||
|
||||
if (obj && funAtom &&
|
||||
|
@ -4653,9 +4646,6 @@ JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
|
|||
JS_BASIC_STATS_ACCUM(&cx->runtime->hostenvScopeDepthStats, depth);
|
||||
}
|
||||
#endif
|
||||
|
||||
out:
|
||||
cx->weakRoots.finalizableNewborns[FINALIZE_FUNCTION] = fun;
|
||||
}
|
||||
|
||||
out2:
|
||||
|
|
|
@ -1179,10 +1179,8 @@ js_RemoveRoot(JSRuntime *rt, void *rp);
|
|||
*/
|
||||
#define JS_TYPED_ROOTING_API
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_ClearNewbornRoots(JSContext *cx);
|
||||
|
||||
/* Obsolete rooting APIs. */
|
||||
#define JS_ClearNewbornRoots(cx) ((void) 0)
|
||||
#define JS_EnterLocalRootScope(cx) (JS_TRUE)
|
||||
#define JS_LeaveLocalRootScope(cx) ((void) 0)
|
||||
#define JS_LeaveLocalRootScopeWithResult(cx, rval) ((void) 0)
|
||||
|
@ -1664,6 +1662,12 @@ struct JSClass {
|
|||
#define JSCLASS_MARK_IS_TRACE (1<<(JSCLASS_HIGH_FLAGS_SHIFT+3))
|
||||
#define JSCLASS_INTERNAL_FLAG2 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+4))
|
||||
|
||||
/* Additional global reserved slots, beyond those for standard prototypes. */
|
||||
#define JSRESERVED_GLOBAL_SLOTS_COUNT 3
|
||||
#define JSRESERVED_GLOBAL_COMPARTMENT (JSProto_LIMIT * 3)
|
||||
#define JSRESERVED_GLOBAL_THIS (JSRESERVED_GLOBAL_COMPARTMENT + 1)
|
||||
#define JSRESERVED_GLOBAL_THROWTYPEERROR (JSRESERVED_GLOBAL_THIS + 1)
|
||||
|
||||
/*
|
||||
* ECMA-262 requires that most constructors used internally create objects
|
||||
* with "the original Foo.prototype value" as their [[Prototype]] (__proto__)
|
||||
|
@ -1675,11 +1679,9 @@ struct JSClass {
|
|||
* with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was
|
||||
* prevously allowed, but is now an ES5 violation and thus unsupported.
|
||||
*/
|
||||
#define JSCLASS_GLOBAL_FLAGS \
|
||||
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSProto_LIMIT * 3 + 2))
|
||||
|
||||
#define JSRESERVED_GLOBAL_COMPARTMENT (JSProto_LIMIT * 3)
|
||||
#define JSRESERVED_GLOBAL_THIS (JSRESERVED_GLOBAL_COMPARTMENT + 1)
|
||||
#define JSCLASS_GLOBAL_FLAGS \
|
||||
(JSCLASS_IS_GLOBAL | \
|
||||
JSCLASS_HAS_RESERVED_SLOTS(JSProto_LIMIT * 3 + JSRESERVED_GLOBAL_SLOTS_COUNT))
|
||||
|
||||
/* Fast access to the original value of each standard class's prototype. */
|
||||
#define JSCLASS_CACHED_PROTO_SHIFT (JSCLASS_HIGH_FLAGS_SHIFT + 8)
|
||||
|
|
|
@ -231,7 +231,7 @@ js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
|
|||
}
|
||||
|
||||
if (obj->isArguments() && !obj->isArgsLengthOverridden()) {
|
||||
*lengthp = obj->getArgsLength();
|
||||
*lengthp = obj->getArgsInitialLength();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3050,12 +3050,7 @@ js_NewArrayObject(JSContext *cx, jsuint length, const Value *vector)
|
|||
*/
|
||||
JS_ASSERT(obj->getProto());
|
||||
|
||||
if (!InitArrayObject(cx, obj, length, vector))
|
||||
obj = NULL;
|
||||
|
||||
/* Set/clear newborn root, in case we lost it. */
|
||||
cx->weakRoots.finalizableNewborns[FINALIZE_OBJECT] = obj;
|
||||
return obj;
|
||||
return InitArrayObject(cx, obj, length, vector) ? obj : NULL;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/* AST_ERROR = -1 */
|
||||
|
||||
ASTDEF(AST_PROGRAM, "Program")
|
||||
|
||||
ASTDEF(AST_IDENTIFIER, "Identifier")
|
||||
ASTDEF(AST_LITERAL, "Literal")
|
||||
ASTDEF(AST_PROPERTY, "Property")
|
||||
|
||||
ASTDEF(AST_FUNC_DECL, "FunctionDeclaration")
|
||||
ASTDEF(AST_VAR_DECL, "VariableDeclaration")
|
||||
ASTDEF(AST_VAR_DTOR, "VariableDeclarator")
|
||||
|
||||
ASTDEF(AST_LIST_EXPR, "SequenceExpression")
|
||||
ASTDEF(AST_COND_EXPR, "ConditionalExpression")
|
||||
ASTDEF(AST_UNARY_EXPR, "UnaryExpression")
|
||||
ASTDEF(AST_BINARY_EXPR, "BinaryExpression")
|
||||
ASTDEF(AST_ASSIGN_EXPR, "AssignmentExpression")
|
||||
ASTDEF(AST_LOGICAL_EXPR, "LogicalExpression")
|
||||
ASTDEF(AST_UPDATE_EXPR, "UpdateExpression")
|
||||
ASTDEF(AST_NEW_EXPR, "NewExpression")
|
||||
ASTDEF(AST_CALL_EXPR, "CallExpression")
|
||||
ASTDEF(AST_MEMBER_EXPR, "MemberExpression")
|
||||
ASTDEF(AST_FUNC_EXPR, "FunctionExpression")
|
||||
ASTDEF(AST_ARRAY_EXPR, "ArrayExpression")
|
||||
ASTDEF(AST_OBJECT_EXPR, "ObjectExpression")
|
||||
ASTDEF(AST_THIS_EXPR, "ThisExpression")
|
||||
ASTDEF(AST_GRAPH_EXPR, "GraphExpression")
|
||||
ASTDEF(AST_GRAPH_IDX_EXPR, "GraphIndexExpression")
|
||||
ASTDEF(AST_COMP_EXPR, "ComprehensionExpression")
|
||||
ASTDEF(AST_GENERATOR_EXPR, "GeneratorExpression")
|
||||
ASTDEF(AST_YIELD_EXPR, "YieldExpression")
|
||||
|
||||
ASTDEF(AST_EMPTY_STMT, "EmptyStatement")
|
||||
ASTDEF(AST_BLOCK_STMT, "BlockStatement")
|
||||
ASTDEF(AST_EXPR_STMT, "ExpressionStatement")
|
||||
ASTDEF(AST_LAB_STMT, "LabeledStatement")
|
||||
ASTDEF(AST_IF_STMT, "IfStatement")
|
||||
ASTDEF(AST_SWITCH_STMT, "SwitchStatement")
|
||||
ASTDEF(AST_WHILE_STMT, "WhileStatement")
|
||||
ASTDEF(AST_DO_STMT, "DoWhileStatement")
|
||||
ASTDEF(AST_FOR_STMT, "ForStatement")
|
||||
ASTDEF(AST_FOR_IN_STMT, "ForInStatement")
|
||||
ASTDEF(AST_BREAK_STMT, "BreakStatement")
|
||||
ASTDEF(AST_CONTINUE_STMT, "ContinueStatement")
|
||||
ASTDEF(AST_WITH_STMT, "WithStatement")
|
||||
ASTDEF(AST_RETURN_STMT, "ReturnStatement")
|
||||
ASTDEF(AST_TRY_STMT, "TryStatement")
|
||||
ASTDEF(AST_THROW_STMT, "ThrowStatement")
|
||||
ASTDEF(AST_DEBUGGER_STMT, "DebuggerStatement")
|
||||
|
||||
ASTDEF(AST_CASE, "SwitchCase")
|
||||
ASTDEF(AST_CATCH, "CatchClause")
|
||||
ASTDEF(AST_COMP_BLOCK, "ComprehensionBlock")
|
||||
|
||||
ASTDEF(AST_ARRAY_PATT, "ArrayPattern")
|
||||
ASTDEF(AST_OBJECT_PATT, "ObjectPattern")
|
||||
|
||||
ASTDEF(AST_XMLANYNAME, "XMLAnyName")
|
||||
ASTDEF(AST_XMLATTR_SEL, "XMLAttributeSelector")
|
||||
ASTDEF(AST_XMLESCAPE, "XMLEscape")
|
||||
ASTDEF(AST_XMLFILTER, "XMLFilterExpression")
|
||||
ASTDEF(AST_XMLDEFAULT, "XMLDefaultDeclaration")
|
||||
ASTDEF(AST_XMLQUAL, "XMLQualifiedIdentifier")
|
||||
ASTDEF(AST_XMLELEM, "XMLElement")
|
||||
ASTDEF(AST_XMLTEXT, "XMLText")
|
||||
ASTDEF(AST_XMLLIST, "XMLList")
|
||||
ASTDEF(AST_XMLSTART, "XMLStartTag")
|
||||
ASTDEF(AST_XMLEND, "XMLEndTag")
|
||||
ASTDEF(AST_XMLPOINT, "XMLPointTag")
|
||||
ASTDEF(AST_XMLNAME, "XMLName")
|
||||
ASTDEF(AST_XMLATTR, "XMLAttribute")
|
||||
ASTDEF(AST_XMLCDATA, "XMLCdata")
|
||||
ASTDEF(AST_XMLCOMMENT, "XMLComment")
|
||||
ASTDEF(AST_XMLPI, "XMLProcessingInstruction")
|
||||
|
||||
/* AST_LIMIT = last + 1 */
|
|
@ -148,6 +148,7 @@ const char *const js_common_atom_names[] = {
|
|||
js_ignoreCase_str, /* ignoreCaseAtom */
|
||||
js_index_str, /* indexAtom */
|
||||
js_input_str, /* inputAtom */
|
||||
"toISOString", /* toISOStringAtom */
|
||||
js_iterator_str, /* iteratorAtom */
|
||||
js_join_str, /* joinAtom */
|
||||
js_lastIndex_str, /* lastIndexAtom */
|
||||
|
@ -553,7 +554,6 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
|
|||
|
||||
JS_ASSERT(key->isAtomized());
|
||||
JSAtom *atom = STRING_TO_ATOM(key);
|
||||
cx->weakRoots.lastAtom = atom;
|
||||
JS_UNLOCK(cx, &state->lock);
|
||||
return atom;
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
|
||||
#define STRING_TO_ATOM(str) (JS_ASSERT(str->isAtomized()), \
|
||||
(JSAtom *)str)
|
||||
#define ATOM_TO_STRING(atom) ((JSString *)atom)
|
||||
#define ATOM_TO_STRING(atom) ((JSString *)(atom))
|
||||
#define ATOM_TO_JSVAL(atom) STRING_TO_JSVAL(ATOM_TO_STRING(atom))
|
||||
|
||||
/* Engine-internal extensions of jsid */
|
||||
|
@ -340,6 +340,7 @@ struct JSAtomState
|
|||
JSAtom *ignoreCaseAtom;
|
||||
JSAtom *indexAtom;
|
||||
JSAtom *inputAtom;
|
||||
JSAtom *toISOStringAtom;
|
||||
JSAtom *iteratorAtom;
|
||||
JSAtom *joinAtom;
|
||||
JSAtom *lastIndexAtom;
|
||||
|
|
|
@ -62,7 +62,7 @@ js_ValueToAtom(JSContext *cx, const js::Value &v, JSAtom **atomp)
|
|||
if (v.isString()) {
|
||||
str = v.toString();
|
||||
if (str->isAtomized()) {
|
||||
cx->weakRoots.lastAtom = *atomp = STRING_TO_ATOM(str);
|
||||
*atomp = STRING_TO_ATOM(str);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -343,15 +343,15 @@ js_PopInterpFrame(JSContext* cx, TracerState* state)
|
|||
* some things we just don't want to handle. In those cases, the trace will
|
||||
* MISMATCH_EXIT.
|
||||
*/
|
||||
if (fp->hookData)
|
||||
if (fp->hasHookData())
|
||||
return JS_FALSE;
|
||||
if (cx->version != fp->callerVersion)
|
||||
if (cx->version != fp->getCallerVersion())
|
||||
return JS_FALSE;
|
||||
if (fp->flags & JSFRAME_CONSTRUCTING)
|
||||
return JS_FALSE;
|
||||
if (fp->imacpc)
|
||||
if (fp->hasIMacroPC())
|
||||
return JS_FALSE;
|
||||
if (fp->blockChain)
|
||||
if (fp->hasBlockChain())
|
||||
return JS_FALSE;
|
||||
|
||||
fp->putActivationObjects(cx);
|
||||
|
|
|
@ -345,7 +345,7 @@ JS_REQUIRES_STACK void
|
|||
StackSpace::pushSynthesizedSlowNativeFrame(JSContext *cx, StackSegment *seg, JSStackFrame *fp,
|
||||
JSFrameRegs ®s)
|
||||
{
|
||||
JS_ASSERT(!fp->script && FUN_SLOW_NATIVE(fp->fun));
|
||||
JS_ASSERT(!fp->hasScript() && FUN_SLOW_NATIVE(fp->getFunction()));
|
||||
fp->down = cx->fp;
|
||||
seg->setPreviousInMemory(currentSegment);
|
||||
currentSegment = seg;
|
||||
|
@ -359,7 +359,7 @@ StackSpace::popSynthesizedSlowNativeFrame(JSContext *cx)
|
|||
JS_ASSERT(isCurrentAndActive(cx));
|
||||
JS_ASSERT(cx->hasActiveSegment());
|
||||
JS_ASSERT(currentSegment->getInitialFrame() == cx->fp);
|
||||
JS_ASSERT(!cx->fp->script && FUN_SLOW_NATIVE(cx->fp->fun));
|
||||
JS_ASSERT(!cx->fp->hasScript() && FUN_SLOW_NATIVE(cx->fp->getFunction()));
|
||||
cx->popSegmentAndFrame();
|
||||
currentSegment = currentSegment->getPreviousInMemory();
|
||||
}
|
||||
|
@ -1312,7 +1312,7 @@ PopulateReportBlame(JSContext *cx, JSErrorReport *report)
|
|||
*/
|
||||
for (JSStackFrame *fp = js_GetTopStackFrame(cx); fp; fp = fp->down) {
|
||||
if (fp->pc(cx)) {
|
||||
report->filename = fp->script->filename;
|
||||
report->filename = fp->getScript()->filename;
|
||||
report->lineno = js_FramePCToLineNumber(cx, fp);
|
||||
break;
|
||||
}
|
||||
|
@ -1406,7 +1406,7 @@ checkReportFlags(JSContext *cx, uintN *flags)
|
|||
* the nearest scripted frame is strict, see bug 536306.
|
||||
*/
|
||||
JSStackFrame *fp = js_GetScriptedCaller(cx, NULL);
|
||||
if (fp && fp->script->strictModeCode)
|
||||
if (fp && fp->getScript()->strictModeCode)
|
||||
*flags &= ~JSREPORT_WARNING;
|
||||
else if (JS_HAS_STRICT_OPTION(cx))
|
||||
*flags |= JSREPORT_WARNING;
|
||||
|
@ -1870,7 +1870,7 @@ js_GetScriptedCaller(JSContext *cx, JSStackFrame *fp)
|
|||
if (!fp)
|
||||
fp = js_GetTopStackFrame(cx);
|
||||
while (fp) {
|
||||
if (fp->script)
|
||||
if (fp->hasScript())
|
||||
return fp;
|
||||
fp = fp->down;
|
||||
}
|
||||
|
@ -1893,7 +1893,7 @@ js_GetCurrentBytecodePC(JSContext* cx)
|
|||
pc = cx->regs ? cx->regs->pc : NULL;
|
||||
if (!pc)
|
||||
return NULL;
|
||||
imacpc = cx->fp->imacpc;
|
||||
imacpc = cx->fp->maybeIMacroPC();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1909,7 +1909,9 @@ js_CurrentPCIsInImacro(JSContext *cx)
|
|||
{
|
||||
#ifdef JS_TRACER
|
||||
VOUCH_DOES_NOT_REQUIRE_STACK();
|
||||
return (JS_ON_TRACE(cx) ? cx->bailExit->imacpc : cx->fp->imacpc) != NULL;
|
||||
if (JS_ON_TRACE(cx))
|
||||
return cx->bailExit->imacpc != NULL;
|
||||
return cx->fp->hasIMacroPC();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
|
@ -1925,6 +1927,8 @@ DSTOffsetCache::purge()
|
|||
*/
|
||||
offsetMilliseconds = 0;
|
||||
rangeStartSeconds = rangeEndSeconds = INT64_MIN;
|
||||
oldOffsetMilliseconds = 0;
|
||||
oldRangeStartSeconds = oldRangeEndSeconds = INT64_MIN;
|
||||
|
||||
#ifdef JS_METER_DST_OFFSET_CACHING
|
||||
totalCalculations = 0;
|
||||
|
|
|
@ -1921,9 +1921,6 @@ struct JSContext
|
|||
/* Top-level object and pointer to top stack frame's scope chain. */
|
||||
JSObject *globalObject;
|
||||
|
||||
/* Storage to root recently allocated GC things and script result. */
|
||||
JSWeakRoots weakRoots;
|
||||
|
||||
/* Regular expression class statics. */
|
||||
js::RegExpStatics regExpStatics;
|
||||
|
||||
|
@ -2014,8 +2011,8 @@ struct JSContext
|
|||
JSStackFrame *findFrameAtLevel(uintN targetLevel) {
|
||||
JSStackFrame *fp = this->fp;
|
||||
while (true) {
|
||||
JS_ASSERT(fp && fp->script);
|
||||
if (fp->script->staticLevel == targetLevel)
|
||||
JS_ASSERT(fp && fp->hasScript());
|
||||
if (fp->getScript()->staticLevel == targetLevel)
|
||||
break;
|
||||
fp = fp->down;
|
||||
}
|
||||
|
@ -2299,14 +2296,14 @@ JS_ALWAYS_INLINE JSObject *
|
|||
JSStackFrame::varobj(js::StackSegment *seg) const
|
||||
{
|
||||
JS_ASSERT(seg->contains(this));
|
||||
return fun ? maybeCallObj() : seg->getInitialVarObj();
|
||||
return hasFunction() ? maybeCallObj() : seg->getInitialVarObj();
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE JSObject *
|
||||
JSStackFrame::varobj(JSContext *cx) const
|
||||
{
|
||||
JS_ASSERT(cx->activeSegment()->contains(this));
|
||||
return fun ? maybeCallObj() : cx->activeSegment()->getInitialVarObj();
|
||||
return hasFunction() ? maybeCallObj() : cx->activeSegment()->getInitialVarObj();
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE jsbytecode *
|
||||
|
@ -2348,15 +2345,16 @@ class AutoCheckRequestDepth {
|
|||
static inline uintN
|
||||
FramePCOffset(JSContext *cx, JSStackFrame* fp)
|
||||
{
|
||||
return uintN((fp->imacpc ? fp->imacpc : fp->pc(cx)) - fp->script->code);
|
||||
jsbytecode *pc = fp->hasIMacroPC() ? fp->getIMacroPC() : fp->pc(cx);
|
||||
return uintN(pc - fp->getScript()->code);
|
||||
}
|
||||
|
||||
static inline JSAtom **
|
||||
FrameAtomBase(JSContext *cx, JSStackFrame *fp)
|
||||
{
|
||||
return fp->imacpc
|
||||
return fp->hasIMacroPC()
|
||||
? COMMON_ATOMS_START(&cx->runtime->atomState)
|
||||
: fp->script->atomMap.vector;
|
||||
: fp->getScript()->atomMap.vector;
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
@ -2410,20 +2408,19 @@ class AutoGCRooter {
|
|||
enum {
|
||||
JSVAL = -1, /* js::AutoValueRooter */
|
||||
SPROP = -2, /* js::AutoScopePropertyRooter */
|
||||
WEAKROOTS = -3, /* js::AutoSaveWeakRoots */
|
||||
PARSER = -4, /* js::Parser */
|
||||
SCRIPT = -5, /* js::AutoScriptRooter */
|
||||
ENUMERATOR = -6, /* js::AutoEnumStateRooter */
|
||||
IDARRAY = -7, /* js::AutoIdArray */
|
||||
DESCRIPTORS = -8, /* js::AutoPropDescArrayRooter */
|
||||
NAMESPACES = -9, /* js::AutoNamespaceArray */
|
||||
XML = -10, /* js::AutoXMLRooter */
|
||||
OBJECT = -11, /* js::AutoObjectRooter */
|
||||
ID = -12, /* js::AutoIdRooter */
|
||||
VALVECTOR = -13, /* js::AutoValueVector */
|
||||
DESCRIPTOR = -14, /* js::AutoPropertyDescriptorRooter */
|
||||
STRING = -15, /* js::AutoStringRooter */
|
||||
IDVECTOR = -16 /* js::AutoIdVector */
|
||||
PARSER = -3, /* js::Parser */
|
||||
SCRIPT = -4, /* js::AutoScriptRooter */
|
||||
ENUMERATOR = -5, /* js::AutoEnumStateRooter */
|
||||
IDARRAY = -6, /* js::AutoIdArray */
|
||||
DESCRIPTORS = -7, /* js::AutoPropDescArrayRooter */
|
||||
NAMESPACES = -8, /* js::AutoNamespaceArray */
|
||||
XML = -9, /* js::AutoXMLRooter */
|
||||
OBJECT = -10, /* js::AutoObjectRooter */
|
||||
ID = -11, /* js::AutoIdRooter */
|
||||
VALVECTOR = -12, /* js::AutoValueVector */
|
||||
DESCRIPTOR = -13, /* js::AutoPropertyDescriptorRooter */
|
||||
STRING = -14, /* js::AutoStringRooter */
|
||||
IDVECTOR = -15 /* js::AutoIdVector */
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -2432,28 +2429,6 @@ class AutoGCRooter {
|
|||
void operator=(AutoGCRooter &ida);
|
||||
};
|
||||
|
||||
class AutoPreserveWeakRoots : private AutoGCRooter
|
||||
{
|
||||
public:
|
||||
explicit AutoPreserveWeakRoots(JSContext *cx
|
||||
JS_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: AutoGCRooter(cx, WEAKROOTS), savedRoots(cx->weakRoots)
|
||||
{
|
||||
JS_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
|
||||
~AutoPreserveWeakRoots()
|
||||
{
|
||||
context->weakRoots = savedRoots;
|
||||
}
|
||||
|
||||
friend void AutoGCRooter::trace(JSTracer *trc);
|
||||
|
||||
private:
|
||||
JSWeakRoots savedRoots;
|
||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
/* FIXME(bug 332648): Move this into a public header. */
|
||||
class AutoValueRooter : private AutoGCRooter
|
||||
{
|
||||
|
|
|
@ -313,6 +313,7 @@ StackSpace::popInlineFrame(JSContext *cx, JSStackFrame *up, JSStackFrame *down)
|
|||
JS_ASSERT(cx->hasActiveSegment());
|
||||
JS_ASSERT(cx->fp == up && up->down == down);
|
||||
JS_ASSERT(up->savedPC == JSStackFrame::sInvalidPC);
|
||||
JS_ASSERT(!up->hasIMacroPC());
|
||||
|
||||
JSFrameRegs *regs = cx->regs;
|
||||
regs->pc = down->savedPC;
|
||||
|
@ -342,9 +343,9 @@ FrameRegsIter::contiguousDownFrameSP(JSStackFrame *up)
|
|||
Value *sp = up->argv + up->argc;
|
||||
#ifdef DEBUG
|
||||
JS_ASSERT(sp <= up->argEnd());
|
||||
JS_ASSERT(sp >= (up->down->script ? up->down->base() : up->down->slots()));
|
||||
if (up->fun) {
|
||||
uint16 nargs = up->fun->nargs;
|
||||
JS_ASSERT(sp >= (up->down->hasScript() ? up->down->base() : up->down->slots()));
|
||||
if (up->hasFunction()) {
|
||||
uint16 nargs = up->getFunction()->nargs;
|
||||
uintN argc = up->argc;
|
||||
uintN missing = argc < nargs ? nargs - argc : 0;
|
||||
JS_ASSERT(sp == up->argEnd() - missing);
|
||||
|
|
|
@ -189,8 +189,23 @@ TimeWithinDay(jsdouble t)
|
|||
return result;
|
||||
}
|
||||
|
||||
#define DaysInYear(y) ((y) % 4 == 0 && ((y) % 100 || ((y) % 400 == 0)) \
|
||||
? 366 : 365)
|
||||
static inline bool
|
||||
IsLeapYear(jsint year)
|
||||
{
|
||||
return year % 4 == 0 && (year % 100 || (year % 400 == 0));
|
||||
}
|
||||
|
||||
static inline jsint
|
||||
DaysInYear(jsint year)
|
||||
{
|
||||
return IsLeapYear(year) ? 366 : 365;
|
||||
}
|
||||
|
||||
static inline jsint
|
||||
DaysInFebruary(jsint year)
|
||||
{
|
||||
return IsLeapYear(year) ? 29 : 28;
|
||||
}
|
||||
|
||||
/* math here has to be f.p, because we need
|
||||
* floor((1968 - 1969) / 4) == -1
|
||||
|
@ -205,6 +220,11 @@ YearFromTime(jsdouble t)
|
|||
jsint y = (jsint) floor(t /(msPerDay*365.2425)) + 1970;
|
||||
jsdouble t2 = (jsdouble) TimeFromYear(y);
|
||||
|
||||
/*
|
||||
* Adjust the year if the approximation was wrong. Since the year was
|
||||
* computed using the average number of ms per year, it will usually
|
||||
* be wrong for dates within several hours of a year transition.
|
||||
*/
|
||||
if (t2 > t) {
|
||||
y--;
|
||||
} else {
|
||||
|
@ -214,8 +234,6 @@ YearFromTime(jsdouble t)
|
|||
return y;
|
||||
}
|
||||
|
||||
#define InLeapYear(t) (JSBool) (DaysInYear(YearFromTime(t)) == 366)
|
||||
|
||||
#define DayWithinYear(t, year) ((intN) (Day(t) - DayFromYear(year)))
|
||||
|
||||
/*
|
||||
|
@ -232,7 +250,7 @@ static jsdouble firstDayOfMonth[2][13] = {
|
|||
static intN
|
||||
DaysInMonth(jsint year, jsint month)
|
||||
{
|
||||
JSBool leap = (DaysInYear(year) == 366);
|
||||
JSBool leap = IsLeapYear(year);
|
||||
intN result = intN(DayFromMonth(month, leap) - DayFromMonth(month-1, leap));
|
||||
return result;
|
||||
}
|
||||
|
@ -246,8 +264,7 @@ MonthFromTime(jsdouble t)
|
|||
|
||||
if (d < (step = 31))
|
||||
return 0;
|
||||
step += (InLeapYear(t) ? 29 : 28);
|
||||
if (d < step)
|
||||
if (d < (step += DaysInFebruary(year)))
|
||||
return 1;
|
||||
if (d < (step += 31))
|
||||
return 2;
|
||||
|
@ -280,8 +297,7 @@ DateFromTime(jsdouble t)
|
|||
if (d <= (next = 30))
|
||||
return d + 1;
|
||||
step = next;
|
||||
next += (InLeapYear(t) ? 29 : 28);
|
||||
if (d <= next)
|
||||
if (d <= (next += DaysInFebruary(year)))
|
||||
return d - step;
|
||||
step = next;
|
||||
if (d <= (next += 31))
|
||||
|
@ -341,7 +357,7 @@ MakeDay(jsdouble year, jsdouble month, jsdouble date)
|
|||
if (month < 0)
|
||||
month += 12;
|
||||
|
||||
leap = (DaysInYear((jsint) year) == 366);
|
||||
leap = IsLeapYear((jsint) year);
|
||||
|
||||
yearday = floor(TimeFromYear(year) / msPerDay);
|
||||
monthday = DayFromMonth(month, leap);
|
||||
|
@ -376,16 +392,13 @@ static jsint
|
|||
EquivalentYearForDST(jsint year)
|
||||
{
|
||||
jsint day;
|
||||
JSBool isLeapYear;
|
||||
|
||||
day = (jsint) DayFromYear(year) + 4;
|
||||
day = day % 7;
|
||||
if (day < 0)
|
||||
day += 7;
|
||||
|
||||
isLeapYear = (DaysInYear(year) == 366);
|
||||
|
||||
return yearStartingWith[isLeapYear][day];
|
||||
return yearStartingWith[IsLeapYear(year)][day];
|
||||
}
|
||||
|
||||
/* LocalTZA gets set by js_InitDateClass() */
|
||||
|
@ -483,7 +496,7 @@ msFromTime(jsdouble t)
|
|||
|
||||
Class js_DateClass = {
|
||||
js_Date_str,
|
||||
JSCLASS_HAS_RESERVED_SLOTS(JSObject::DATE_FIXED_RESERVED_SLOTS) |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(JSObject::DATE_CLASS_RESERVED_SLOTS) |
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_Date) |
|
||||
JSCLASS_FAST_CONSTRUCTOR,
|
||||
PropertyStub, /* addProperty */
|
||||
|
@ -1204,54 +1217,189 @@ GetUTCTime(JSContext *cx, JSObject *obj, Value *vp, jsdouble *dp)
|
|||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
SetDateToNaN(JSContext *cx, JSObject *obj, Value *vp = NULL)
|
||||
{
|
||||
JS_ASSERT(obj->getClass() == &js_DateClass);
|
||||
|
||||
obj->setDateLocalTime(cx->runtime->NaNValue);
|
||||
obj->setDateUTCTime(cx->runtime->NaNValue);
|
||||
if (vp)
|
||||
vp->setDouble(js_NaN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set UTC time to a given time and invalidate cached local time.
|
||||
*/
|
||||
static JSBool
|
||||
SetUTCTime(JSContext *cx, JSObject *obj, jsdouble t, Value *vp = NULL)
|
||||
{
|
||||
JS_ASSERT(obj->getClass() == &js_DateClass);
|
||||
JS_ASSERT(obj->isDate());
|
||||
|
||||
size_t slotCap = JS_MIN(obj->numSlots(), JSObject::DATE_CLASS_RESERVED_SLOTS);
|
||||
for (size_t ind = JSObject::JSSLOT_DATE_COMPONENTS_START; ind < slotCap; ind++)
|
||||
obj->getSlotRef(ind).setUndefined();
|
||||
|
||||
obj->setDateLocalTime(cx->runtime->NaNValue);
|
||||
obj->setDateUTCTime(DoubleValue(t));
|
||||
if (vp)
|
||||
vp->setDouble(t);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
SetDateToNaN(JSContext *cx, JSObject *obj, Value *vp = NULL)
|
||||
{
|
||||
jsdouble NaN = cx->runtime->NaNValue.getDoubleRef();
|
||||
SetUTCTime(cx, obj, NaN, vp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the local time, cache it if necessary. If UTC time is not finite
|
||||
* (e.g., NaN), the local time slot is set to the UTC time without conversion.
|
||||
* Cache the local time, year, month, and so forth of the object.
|
||||
* If UTC time is not finite (e.g., NaN), the local time
|
||||
* slots will be set to the UTC time without conversion.
|
||||
*/
|
||||
static JSBool
|
||||
GetAndCacheLocalTime(JSContext *cx, JSObject *obj, Value *vp, jsdouble *dp)
|
||||
static bool
|
||||
FillLocalTimes(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(obj->isDate());
|
||||
|
||||
jsdouble utcTime = obj->getDateUTCTime().toNumber();
|
||||
|
||||
/* Make sure there are slots to store the cached information. */
|
||||
if (obj->numSlots() < JSObject::DATE_CLASS_RESERVED_SLOTS) {
|
||||
if (!obj->growSlots(cx, JSObject::DATE_CLASS_RESERVED_SLOTS))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!JSDOUBLE_IS_FINITE(utcTime)) {
|
||||
for (size_t ind = JSObject::JSSLOT_DATE_COMPONENTS_START;
|
||||
ind < JSObject::DATE_CLASS_RESERVED_SLOTS;
|
||||
ind++) {
|
||||
obj->setSlot(ind, DoubleValue(utcTime));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
jsdouble localTime = LocalTime(utcTime, cx);
|
||||
|
||||
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_TIME, DoubleValue(localTime));
|
||||
|
||||
jsint year = (jsint) floor(localTime /(msPerDay*365.2425)) + 1970;
|
||||
jsdouble yearStartTime = (jsdouble) TimeFromYear(year);
|
||||
|
||||
/* Adjust the year in case the approximation was wrong, as in YearFromTime. */
|
||||
jsint yearDays;
|
||||
if (yearStartTime > localTime) {
|
||||
year--;
|
||||
yearStartTime -= (msPerDay * DaysInYear(year));
|
||||
yearDays = DaysInYear(year);
|
||||
} else {
|
||||
yearDays = DaysInYear(year);
|
||||
jsdouble nextStart = yearStartTime + (msPerDay * yearDays);
|
||||
if (nextStart <= localTime) {
|
||||
year++;
|
||||
yearStartTime = nextStart;
|
||||
yearDays = DaysInYear(year);
|
||||
}
|
||||
}
|
||||
|
||||
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR, Int32Value(year));
|
||||
|
||||
uint64 yearTime = uint64(localTime - yearStartTime);
|
||||
jsint yearSeconds = uint32(yearTime / 1000);
|
||||
|
||||
jsint day = yearSeconds / jsint(SecondsPerDay);
|
||||
|
||||
jsint step = -1, next = 30;
|
||||
jsint month;
|
||||
|
||||
do {
|
||||
if (day <= next) {
|
||||
month = 0;
|
||||
break;
|
||||
}
|
||||
step = next;
|
||||
next += ((yearDays == 366) ? 29 : 28);
|
||||
if (day <= next) {
|
||||
month = 1;
|
||||
break;
|
||||
}
|
||||
step = next;
|
||||
if (day <= (next += 31)) {
|
||||
month = 2;
|
||||
break;
|
||||
}
|
||||
step = next;
|
||||
if (day <= (next += 30)) {
|
||||
month = 3;
|
||||
break;
|
||||
}
|
||||
step = next;
|
||||
if (day <= (next += 31)) {
|
||||
month = 4;
|
||||
break;
|
||||
}
|
||||
step = next;
|
||||
if (day <= (next += 30)) {
|
||||
month = 5;
|
||||
break;
|
||||
}
|
||||
step = next;
|
||||
if (day <= (next += 31)) {
|
||||
month = 6;
|
||||
break;
|
||||
}
|
||||
step = next;
|
||||
if (day <= (next += 31)) {
|
||||
month = 7;
|
||||
break;
|
||||
}
|
||||
step = next;
|
||||
if (day <= (next += 30)) {
|
||||
month = 8;
|
||||
break;
|
||||
}
|
||||
step = next;
|
||||
if (day <= (next += 31)) {
|
||||
month = 9;
|
||||
break;
|
||||
}
|
||||
step = next;
|
||||
if (day <= (next += 30)) {
|
||||
month = 10;
|
||||
break;
|
||||
}
|
||||
step = next;
|
||||
month = 11;
|
||||
} while (0);
|
||||
|
||||
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_MONTH, Int32Value(month));
|
||||
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_DATE, Int32Value(day - step));
|
||||
|
||||
jsint weekday = WeekDay(localTime);
|
||||
|
||||
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_DAY, Int32Value(weekday));
|
||||
|
||||
jsint seconds = yearSeconds % 60;
|
||||
|
||||
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_SECONDS, Int32Value(seconds));
|
||||
|
||||
jsint minutes = (yearSeconds / 60) % 60;
|
||||
|
||||
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_MINUTES, Int32Value(minutes));
|
||||
|
||||
jsint hours = (yearSeconds / (60 * 60)) % 24;
|
||||
|
||||
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_HOURS, Int32Value(hours));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Cache the local times in obj, if necessary. */
|
||||
static inline JSBool
|
||||
GetAndCacheLocalTime(JSContext *cx, JSObject *obj, Value *vp, jsdouble *time = NULL)
|
||||
{
|
||||
if (!obj || !InstanceOf(cx, obj, &js_DateClass, vp ? vp + 2 : NULL))
|
||||
return false;
|
||||
|
||||
jsdouble result = obj->getDateLocalTime().toNumber();
|
||||
if (JSDOUBLE_IS_NaN(result)) {
|
||||
result = obj->getDateUTCTime().toDouble();
|
||||
|
||||
/* if result is NaN, it couldn't be finite. */
|
||||
if (JSDOUBLE_IS_FINITE(result))
|
||||
result = LocalTime(result, cx);
|
||||
|
||||
obj->setDateLocalTime(DoubleValue(result));
|
||||
/* If the local time is undefined, we need to fill in the cached values. */
|
||||
if (obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_TIME).isUndefined()) {
|
||||
if (!FillLocalTimes(cx, obj))
|
||||
return false;
|
||||
}
|
||||
|
||||
*dp = result;
|
||||
if (time)
|
||||
*time = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_TIME).toDouble();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1269,36 +1417,34 @@ date_getTime(JSContext *cx, uintN argc, Value *vp)
|
|||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
GetYear(JSContext *cx, JSBool fullyear, Value *vp)
|
||||
{
|
||||
jsdouble result;
|
||||
|
||||
if (!GetAndCacheLocalTime(cx, ComputeThisFromVp(cx, vp), vp, &result))
|
||||
return JS_FALSE;
|
||||
|
||||
if (JSDOUBLE_IS_FINITE(result)) {
|
||||
result = YearFromTime(result);
|
||||
|
||||
/* Follow ECMA-262 to the letter, contrary to IE JScript. */
|
||||
if (!fullyear)
|
||||
result -= 1900;
|
||||
}
|
||||
|
||||
vp->setNumber(result);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
date_getYear(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
return GetYear(cx, JS_FALSE, vp);
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
if (!GetAndCacheLocalTime(cx, obj, vp))
|
||||
return JS_FALSE;
|
||||
|
||||
Value yearVal = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR);
|
||||
if (yearVal.isInt32()) {
|
||||
/* Follow ECMA-262 to the letter, contrary to IE JScript. */
|
||||
jsint year = yearVal.toInt32() - 1900;
|
||||
vp->setInt32(year);
|
||||
} else {
|
||||
*vp = yearVal;
|
||||
}
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
date_getFullYear(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
return GetYear(cx, JS_TRUE, vp);
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
if (!GetAndCacheLocalTime(cx, obj, vp))
|
||||
return JS_FALSE;
|
||||
|
||||
*vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
|
@ -1319,15 +1465,11 @@ date_getUTCFullYear(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
date_getMonth(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
jsdouble result;
|
||||
|
||||
if (!GetAndCacheLocalTime(cx, ComputeThisFromVp(cx, vp), vp, &result))
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
if (!GetAndCacheLocalTime(cx, obj, vp))
|
||||
return JS_FALSE;
|
||||
|
||||
if (JSDOUBLE_IS_FINITE(result))
|
||||
result = MonthFromTime(result);
|
||||
|
||||
vp->setNumber(result);
|
||||
*vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MONTH);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
|
@ -1349,15 +1491,11 @@ date_getUTCMonth(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
date_getDate(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
jsdouble result;
|
||||
|
||||
if (!GetAndCacheLocalTime(cx, ComputeThisFromVp(cx, vp), vp, &result))
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
if (!GetAndCacheLocalTime(cx, obj, vp))
|
||||
return JS_FALSE;
|
||||
|
||||
if (JSDOUBLE_IS_FINITE(result))
|
||||
result = DateFromTime(result);
|
||||
|
||||
vp->setNumber(result);
|
||||
*vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DATE);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
|
@ -1379,15 +1517,11 @@ date_getUTCDate(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
date_getDay(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
jsdouble result;
|
||||
|
||||
if (!GetAndCacheLocalTime(cx, ComputeThisFromVp(cx, vp), vp, &result))
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
if (!GetAndCacheLocalTime(cx, obj, vp))
|
||||
return JS_FALSE;
|
||||
|
||||
if (JSDOUBLE_IS_FINITE(result))
|
||||
result = WeekDay(result);
|
||||
|
||||
vp->setNumber(result);
|
||||
*vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DAY);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
|
@ -1409,15 +1543,11 @@ date_getUTCDay(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
date_getHours(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
jsdouble result;
|
||||
|
||||
if (!GetAndCacheLocalTime(cx, ComputeThisFromVp(cx, vp), vp, &result))
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
if (!GetAndCacheLocalTime(cx, obj, vp))
|
||||
return JS_FALSE;
|
||||
|
||||
if (JSDOUBLE_IS_FINITE(result))
|
||||
result = HourFromTime(result);
|
||||
|
||||
vp->setNumber(result);
|
||||
*vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_HOURS);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
|
@ -1439,15 +1569,11 @@ date_getUTCHours(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
date_getMinutes(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
jsdouble result;
|
||||
|
||||
if (!GetAndCacheLocalTime(cx, ComputeThisFromVp(cx, vp), vp, &result))
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
if (!GetAndCacheLocalTime(cx, obj, vp))
|
||||
return JS_FALSE;
|
||||
|
||||
if (JSDOUBLE_IS_FINITE(result))
|
||||
result = MinFromTime(result);
|
||||
|
||||
vp->setNumber(result);
|
||||
*vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MINUTES);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
|
@ -1471,15 +1597,11 @@ date_getUTCMinutes(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
date_getUTCSeconds(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
jsdouble result;
|
||||
|
||||
if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &result))
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
if (!GetAndCacheLocalTime(cx, obj, vp))
|
||||
return JS_FALSE;
|
||||
|
||||
if (JSDOUBLE_IS_FINITE(result))
|
||||
result = SecFromTime(result);
|
||||
|
||||
vp->setNumber(result);
|
||||
*vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_SECONDS);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
|
@ -1898,6 +2020,57 @@ date_toISOString(JSContext *cx, uintN argc, Value *vp)
|
|||
return date_utc_format(cx, vp, print_iso_string);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/* ES5 15.9.5.44. */
|
||||
JSBool
|
||||
date_toJSON(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
/* Step 1. */
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
/* Step 2. */
|
||||
Value &tv = vp[0];
|
||||
if (!DefaultValue(cx, obj, JSTYPE_NUMBER, &tv))
|
||||
return false;
|
||||
|
||||
/* Step 3. */
|
||||
if (tv.isDouble() && !JSDOUBLE_IS_FINITE(tv.toDouble())) {
|
||||
vp->setNull();
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Step 4. */
|
||||
Value &toISO = vp[0];
|
||||
if (!obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.toISOStringAtom), &toISO))
|
||||
return false;
|
||||
|
||||
/* Step 5. */
|
||||
if (!js_IsCallable(toISO)) {
|
||||
JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_TOISOSTRING_PROP);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Step 6. */
|
||||
LeaveTrace(cx);
|
||||
InvokeArgsGuard args;
|
||||
if (!cx->stack().pushInvokeArgs(cx, 0, args))
|
||||
return false;
|
||||
|
||||
args.callee() = toISO;
|
||||
args.thisv().setObject(*obj);
|
||||
|
||||
if (!Invoke(cx, args, 0))
|
||||
return false;
|
||||
*vp = args.rval();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* for Date.toLocaleString; interface to PRMJTime date struct.
|
||||
*/
|
||||
static void
|
||||
|
@ -2293,7 +2466,7 @@ static JSFunctionSpec date_methods[] = {
|
|||
JS_FN("toDateString", date_toDateString, 0,0),
|
||||
JS_FN("toTimeString", date_toTimeString, 0,0),
|
||||
JS_FN("toISOString", date_toISOString, 0,0),
|
||||
JS_FN(js_toJSON_str, date_toISOString, 0,0),
|
||||
JS_FN(js_toJSON_str, date_toJSON, 1,0),
|
||||
#if JS_HAS_TOSOURCE
|
||||
JS_FN(js_toSource_str, date_toSource, 0,0),
|
||||
#endif
|
||||
|
|
|
@ -682,10 +682,10 @@ js_watch_set(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
|||
JSStackFrame *fp = frame.getFrame();
|
||||
PodZero(fp);
|
||||
MakeValueRangeGCSafe(fp->slots(), nfixed);
|
||||
fp->script = script;
|
||||
fp->fun = fun;
|
||||
fp->setScript(script);
|
||||
fp->setFunction(fun);
|
||||
fp->argv = vp + 2;
|
||||
fp->scopeChain = closure->getParent();
|
||||
fp->setScopeChain(closure->getParent());
|
||||
fp->setArgsObj(NULL);
|
||||
|
||||
/* Initialize regs. */
|
||||
|
@ -1100,7 +1100,7 @@ JS_FrameIterator(JSContext *cx, JSStackFrame **iteratorp)
|
|||
JS_PUBLIC_API(JSScript *)
|
||||
JS_GetFrameScript(JSContext *cx, JSStackFrame *fp)
|
||||
{
|
||||
return fp->script;
|
||||
return fp->maybeScript();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(jsbytecode *)
|
||||
|
@ -1120,16 +1120,16 @@ JS_StackFramePrincipals(JSContext *cx, JSStackFrame *fp)
|
|||
{
|
||||
JSSecurityCallbacks *callbacks;
|
||||
|
||||
if (fp->fun) {
|
||||
if (fp->hasFunction()) {
|
||||
callbacks = JS_GetSecurityCallbacks(cx);
|
||||
if (callbacks && callbacks->findObjectPrincipals) {
|
||||
if (FUN_OBJECT(fp->fun) != fp->callee())
|
||||
if (FUN_OBJECT(fp->getFunction()) != fp->callee())
|
||||
return callbacks->findObjectPrincipals(cx, fp->callee());
|
||||
/* FALL THROUGH */
|
||||
}
|
||||
}
|
||||
if (fp->script)
|
||||
return fp->script->principals;
|
||||
if (fp->hasScript())
|
||||
return fp->getScript()->principals;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1162,7 +1162,7 @@ JS_EvalFramePrincipals(JSContext *cx, JSStackFrame *fp, JSStackFrame *caller)
|
|||
JS_PUBLIC_API(void *)
|
||||
JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp)
|
||||
{
|
||||
if (fp->annotation && fp->script) {
|
||||
if (fp->hasAnnotation() && fp->hasScript()) {
|
||||
JSPrincipals *principals = JS_StackFramePrincipals(cx, fp);
|
||||
|
||||
if (principals && principals->globalPrivilegesEnabled(cx, principals)) {
|
||||
|
@ -1170,7 +1170,7 @@ JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp)
|
|||
* Give out an annotation only if privileges have not been revoked
|
||||
* or disabled globally.
|
||||
*/
|
||||
return fp->annotation;
|
||||
return fp->getAnnotation();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1180,7 +1180,7 @@ JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp)
|
|||
JS_PUBLIC_API(void)
|
||||
JS_SetFrameAnnotation(JSContext *cx, JSStackFrame *fp, void *annotation)
|
||||
{
|
||||
fp->annotation = annotation;
|
||||
fp->setAnnotation(annotation);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void *)
|
||||
|
@ -1197,14 +1197,14 @@ JS_GetFramePrincipalArray(JSContext *cx, JSStackFrame *fp)
|
|||
JS_PUBLIC_API(JSBool)
|
||||
JS_IsNativeFrame(JSContext *cx, JSStackFrame *fp)
|
||||
{
|
||||
return !fp->script;
|
||||
return !fp->hasScript();
|
||||
}
|
||||
|
||||
/* this is deprecated, use JS_GetFrameScopeChain instead */
|
||||
JS_PUBLIC_API(JSObject *)
|
||||
JS_GetFrameObject(JSContext *cx, JSStackFrame *fp)
|
||||
{
|
||||
return fp->scopeChain;
|
||||
return fp->maybeScopeChain();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSObject *)
|
||||
|
@ -1222,7 +1222,7 @@ JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fp)
|
|||
{
|
||||
JS_ASSERT(cx->stack().contains(fp));
|
||||
|
||||
if (! fp->fun)
|
||||
if (!fp->hasFunction())
|
||||
return NULL;
|
||||
|
||||
/* Force creation of argument object if not yet created */
|
||||
|
@ -1247,17 +1247,17 @@ JS_GetFrameThis(JSContext *cx, JSStackFrame *fp)
|
|||
JS_PUBLIC_API(JSFunction *)
|
||||
JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp)
|
||||
{
|
||||
return fp->fun;
|
||||
return fp->maybeFunction();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSObject *)
|
||||
JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fp)
|
||||
{
|
||||
if (!fp->fun)
|
||||
if (!fp->hasFunction())
|
||||
return NULL;
|
||||
|
||||
JS_ASSERT(fp->callee()->isFunction());
|
||||
JS_ASSERT(fp->callee()->getPrivate() == fp->fun);
|
||||
JS_ASSERT(fp->callee()->getPrivate() == fp->getFunction());
|
||||
return fp->callee();
|
||||
}
|
||||
|
||||
|
@ -1293,13 +1293,13 @@ JS_IsDebuggerFrame(JSContext *cx, JSStackFrame *fp)
|
|||
JS_PUBLIC_API(jsval)
|
||||
JS_GetFrameReturnValue(JSContext *cx, JSStackFrame *fp)
|
||||
{
|
||||
return Jsvalify(fp->rval);
|
||||
return Jsvalify(fp->getReturnValue());
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_SetFrameReturnValue(JSContext *cx, JSStackFrame *fp, jsval rval)
|
||||
{
|
||||
fp->rval = Valueify(rval);
|
||||
fp->setReturnValue(Valueify(rval));
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
@ -1562,9 +1562,9 @@ SetupFakeFrame(JSContext *cx, ExecuteFrameGuard &frame, JSFrameRegs ®s, JSObj
|
|||
|
||||
JSStackFrame *fp = frame.getFrame();
|
||||
PodZero(fp);
|
||||
fp->fun = fun;
|
||||
fp->setFunction(fun);
|
||||
fp->argv = vp + 2;
|
||||
fp->scopeChain = scopeobj->getGlobal();
|
||||
fp->setScopeChain(scopeobj->getGlobal());
|
||||
|
||||
regs.pc = NULL;
|
||||
regs.sp = fp->slots();
|
||||
|
@ -1796,8 +1796,8 @@ JS_GetTopScriptFilenameFlags(JSContext *cx, JSStackFrame *fp)
|
|||
if (!fp)
|
||||
fp = js_GetTopStackFrame(cx);
|
||||
while (fp) {
|
||||
if (fp->script)
|
||||
return JS_GetScriptFilenameFlags(fp->script);
|
||||
if (fp->hasScript())
|
||||
return JS_GetScriptFilenameFlags(fp->getScript());
|
||||
fp = fp->down;
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -64,7 +64,9 @@ jsdtrace_fun_classname(const JSFunction *fun)
|
|||
static char *
|
||||
jsdtrace_filename(JSStackFrame *fp)
|
||||
{
|
||||
return (fp && fp->script && fp->script->filename) ? (char *)fp->script->filename : dempty;
|
||||
return (fp && fp->hasScript() && fp->getScript()->filename)
|
||||
? (char *)fp->getScript()->filename
|
||||
: dempty;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
@ -1874,7 +1874,7 @@ static bool
|
|||
MakeUpvarForEval(JSParseNode *pn, JSCodeGenerator *cg)
|
||||
{
|
||||
JSContext *cx = cg->parser->context;
|
||||
JSFunction *fun = cg->parser->callerFrame->fun;
|
||||
JSFunction *fun = cg->parser->callerFrame->getFunction();
|
||||
uintN upvarLevel = fun->u.i.script->staticLevel;
|
||||
|
||||
JSFunctionBox *funbox = cg->funbox;
|
||||
|
@ -2059,8 +2059,8 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
if (cg->flags & TCF_IN_FOR_INIT)
|
||||
return JS_TRUE;
|
||||
|
||||
JS_ASSERT(caller->script);
|
||||
if (!caller->fun)
|
||||
JS_ASSERT(caller->hasScript());
|
||||
if (!caller->hasFunction())
|
||||
return JS_TRUE;
|
||||
|
||||
/*
|
||||
|
@ -2089,7 +2089,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
* defeats the display optimization to static link searching used
|
||||
* by JSOP_{GET,CALL}UPVAR.
|
||||
*/
|
||||
JSFunction *fun = cg->parser->callerFrame->fun;
|
||||
JSFunction *fun = cg->parser->callerFrame->getFunction();
|
||||
JS_ASSERT(cg->staticLevel >= fun->u.i.script->staticLevel);
|
||||
unsigned skip = cg->staticLevel - fun->u.i.script->staticLevel;
|
||||
if (cg->skipSpansGenerator(skip))
|
||||
|
@ -2159,7 +2159,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
JSStackFrame *caller = cg->parser->callerFrame;
|
||||
#endif
|
||||
JS_ASSERT(caller);
|
||||
JS_ASSERT(caller->script);
|
||||
JS_ASSERT(caller->hasScript());
|
||||
|
||||
JSTreeContext *tc = cg;
|
||||
while (tc->staticLevel != level)
|
||||
|
@ -2168,7 +2168,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
|
||||
JSCodeGenerator *evalcg = (JSCodeGenerator *) tc;
|
||||
JS_ASSERT(evalcg->compileAndGo());
|
||||
JS_ASSERT(caller->fun && cg->parser->callerVarObj == evalcg->scopeChain);
|
||||
JS_ASSERT(caller->hasFunction() && cg->parser->callerVarObj == evalcg->scopeChain);
|
||||
|
||||
/*
|
||||
* Don't generate upvars on the left side of a for loop. See
|
||||
|
@ -2821,7 +2821,9 @@ EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
|
|||
return JS_FALSE;
|
||||
if (left->pn_op == JSOP_ARGUMENTS &&
|
||||
JSDOUBLE_IS_INT32(next->pn_dval, &slot) &&
|
||||
(jsuint)slot < JS_BIT(16)) {
|
||||
jsuint(slot) < JS_BIT(16) &&
|
||||
(!cg->inStrictMode() ||
|
||||
(!cg->mutatesParameter() && !cg->callsEval()))) {
|
||||
/*
|
||||
* arguments[i]() requires arguments object as "this".
|
||||
* Check that we never generates list for that usage.
|
||||
|
@ -2895,7 +2897,9 @@ EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
|
|||
return JS_FALSE;
|
||||
if (left->pn_op == JSOP_ARGUMENTS &&
|
||||
JSDOUBLE_IS_INT32(right->pn_dval, &slot) &&
|
||||
(jsuint)slot < JS_BIT(16)) {
|
||||
jsuint(slot) < JS_BIT(16) &&
|
||||
(!cg->inStrictMode() ||
|
||||
(!cg->mutatesParameter() && !cg->callsEval()))) {
|
||||
left->pn_offset = right->pn_offset = top;
|
||||
EMIT_UINT16_IMM_OP(JSOP_ARGSUB, (jsatomid)slot);
|
||||
return JS_TRUE;
|
||||
|
@ -3547,6 +3551,13 @@ js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (cg->needsEagerArguments()) {
|
||||
CG_SWITCH_TO_PROLOG(cg);
|
||||
if (js_Emit1(cx, cg, JSOP_ARGUMENTS) < 0 || js_Emit1(cx, cg, JSOP_POP) < 0)
|
||||
return false;
|
||||
CG_SWITCH_TO_MAIN(cg);
|
||||
}
|
||||
|
||||
if (cg->flags & TCF_FUN_UNBRAND_THIS) {
|
||||
if (js_Emit1(cx, cg, JSOP_UNBRANDTHIS) < 0)
|
||||
return false;
|
||||
|
|
|
@ -240,6 +240,12 @@ struct JSStmtInfo {
|
|||
*/
|
||||
#define TCF_FUN_ENTRAINS_SCOPES 0x400000
|
||||
|
||||
/* The function calls 'eval'. */
|
||||
#define TCF_FUN_CALLS_EVAL 0x800000
|
||||
|
||||
/* The function mutates a positional (non-destructuring) parameter. */
|
||||
#define TCF_FUN_MUTATES_PARAMETER 0x1000000
|
||||
|
||||
/*
|
||||
* Flags to check for return; vs. return expr; in a function.
|
||||
*/
|
||||
|
@ -255,6 +261,8 @@ struct JSStmtInfo {
|
|||
TCF_FUN_IS_GENERATOR | \
|
||||
TCF_FUN_USES_OWN_NAME | \
|
||||
TCF_HAS_SHARPS | \
|
||||
TCF_FUN_CALLS_EVAL | \
|
||||
TCF_FUN_MUTATES_PARAMETER | \
|
||||
TCF_STRICT_MODE_CODE)
|
||||
|
||||
struct JSTreeContext { /* tree context for semantic checks */
|
||||
|
@ -324,6 +332,10 @@ struct JSTreeContext { /* tree context for semantic checks */
|
|||
/* Test whether we're in a statement of given type. */
|
||||
bool inStatement(JSStmtType type);
|
||||
|
||||
bool inStrictMode() const {
|
||||
return flags & TCF_STRICT_MODE_CODE;
|
||||
}
|
||||
|
||||
inline bool needStrictChecks();
|
||||
|
||||
/*
|
||||
|
@ -338,9 +350,43 @@ struct JSTreeContext { /* tree context for semantic checks */
|
|||
// this context is itself a generator.
|
||||
bool skipSpansGenerator(unsigned skip);
|
||||
|
||||
bool compileAndGo() { return !!(flags & TCF_COMPILE_N_GO); }
|
||||
bool inFunction() { return !!(flags & TCF_IN_FUNCTION); }
|
||||
bool compiling() { return !!(flags & TCF_COMPILING); }
|
||||
bool compileAndGo() const { return flags & TCF_COMPILE_N_GO; }
|
||||
bool inFunction() const { return flags & TCF_IN_FUNCTION; }
|
||||
bool compiling() const { return flags & TCF_COMPILING; }
|
||||
|
||||
bool usesArguments() const {
|
||||
return flags & TCF_FUN_USES_ARGUMENTS;
|
||||
}
|
||||
|
||||
void noteCallsEval() {
|
||||
flags |= TCF_FUN_CALLS_EVAL;
|
||||
}
|
||||
|
||||
bool callsEval() const {
|
||||
JS_ASSERT(inFunction());
|
||||
return flags & TCF_FUN_CALLS_EVAL;
|
||||
}
|
||||
|
||||
void noteParameterMutation() {
|
||||
JS_ASSERT(inFunction());
|
||||
flags |= TCF_FUN_MUTATES_PARAMETER;
|
||||
}
|
||||
|
||||
bool mutatesParameter() const {
|
||||
JS_ASSERT(inFunction());
|
||||
return flags & TCF_FUN_MUTATES_PARAMETER;
|
||||
}
|
||||
|
||||
void noteArgumentsUse() {
|
||||
JS_ASSERT(inFunction());
|
||||
flags |= TCF_FUN_USES_ARGUMENTS;
|
||||
if (funbox)
|
||||
funbox->node->pn_dflags |= PND_FUNARG;
|
||||
}
|
||||
|
||||
bool needsEagerArguments() const {
|
||||
return inStrictMode() && ((usesArguments() && mutatesParameter()) || callsEval());
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -348,8 +394,7 @@ struct JSTreeContext { /* tree context for semantic checks */
|
|||
* JSOPTION_STRICT warnings or strict mode errors.
|
||||
*/
|
||||
inline bool JSTreeContext::needStrictChecks() {
|
||||
return JS_HAS_STRICT_OPTION(parser->context) ||
|
||||
(flags & TCF_STRICT_MODE_CODE);
|
||||
return JS_HAS_STRICT_OPTION(parser->context) || inStrictMode();
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -293,7 +293,7 @@ InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
|
|||
stackDepth = 0;
|
||||
valueCount = 0;
|
||||
for (fp = js_GetTopStackFrame(cx); fp; fp = fp->down) {
|
||||
if (fp->fun && fp->argv) {
|
||||
if (fp->hasFunction() && fp->argv) {
|
||||
Value v = NullValue();
|
||||
if (checkAccess &&
|
||||
!checkAccess(cx, fp->callee(), callerid, JSACC_READ, &v)) {
|
||||
|
@ -334,12 +334,12 @@ InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
|
|||
values = GetStackTraceValueBuffer(priv);
|
||||
elem = priv->stackElems;
|
||||
for (fp = js_GetTopStackFrame(cx); fp != fpstop; fp = fp->down) {
|
||||
if (!fp->fun) {
|
||||
if (!fp->hasFunction()) {
|
||||
elem->funName = NULL;
|
||||
elem->argc = 0;
|
||||
} else {
|
||||
elem->funName = fp->fun->atom
|
||||
? ATOM_TO_STRING(fp->fun->atom)
|
||||
elem->funName = fp->getFunction()->atom
|
||||
? ATOM_TO_STRING(fp->getFunction()->atom)
|
||||
: cx->runtime->emptyString;
|
||||
elem->argc = fp->argc;
|
||||
memcpy(values, fp->argv, fp->argc * sizeof(jsval));
|
||||
|
@ -347,8 +347,8 @@ InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
|
|||
}
|
||||
elem->ulineno = 0;
|
||||
elem->filename = NULL;
|
||||
if (fp->script) {
|
||||
elem->filename = fp->script->filename;
|
||||
if (fp->hasScript()) {
|
||||
elem->filename = fp->getScript()->filename;
|
||||
if (fp->pc(cx))
|
||||
elem->ulineno = js_FramePCToLineNumber(cx, fp);
|
||||
}
|
||||
|
@ -749,7 +749,7 @@ Exception(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval)
|
|||
} else {
|
||||
fp = js_GetScriptedCaller(cx, NULL);
|
||||
if (fp) {
|
||||
filename = FilenameToString(cx, fp->script->filename);
|
||||
filename = FilenameToString(cx, fp->getScript()->filename);
|
||||
if (!filename)
|
||||
return JS_FALSE;
|
||||
} else {
|
||||
|
|
472
js/src/jsfun.cpp
472
js/src/jsfun.cpp
|
@ -82,11 +82,18 @@
|
|||
|
||||
#include "jsatominlines.h"
|
||||
#include "jscntxtinlines.h"
|
||||
#include "jsfuninlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
#include "jscntxtinlines.h"
|
||||
|
||||
using namespace js;
|
||||
|
||||
inline JSObject *
|
||||
JSObject::getThrowTypeError() const
|
||||
{
|
||||
return &getGlobal()->getReservedSlot(JSRESERVED_GLOBAL_THROWTYPEERROR).toObject();
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_GetArgsValue(JSContext *cx, JSStackFrame *fp, Value *vp)
|
||||
{
|
||||
|
@ -173,22 +180,25 @@ NewArguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject *callee)
|
|||
return NULL;
|
||||
|
||||
/* Init immediately to avoid GC seeing a half-init'ed object. */
|
||||
argsobj->init(&js_ArgumentsClass, proto, parent, PrivateValue(NULL));
|
||||
argsobj->setArgsCallee(ObjectOrNullValue(callee));
|
||||
bool strict = callee->getFunctionPrivate()->inStrictMode();
|
||||
argsobj->init(strict ? &StrictArgumentsClass : &js_ArgumentsClass, proto, parent,
|
||||
PrivateValue(NULL));
|
||||
argsobj->setArgsLength(argc);
|
||||
|
||||
argsobj->setArgsCallee(ObjectValue(*callee));
|
||||
argsobj->map = cx->runtime->emptyArgumentsScope->hold();
|
||||
|
||||
/* This must come after argsobj->map has been set. */
|
||||
if (!js_EnsureReservedSlots(cx, argsobj, argc))
|
||||
return NULL;
|
||||
|
||||
return argsobj;
|
||||
}
|
||||
|
||||
static void
|
||||
PutArguments(JSContext *cx, JSObject *argsobj, Value *args)
|
||||
{
|
||||
uint32 argc = argsobj->getArgsLength();
|
||||
JS_ASSERT(argsobj->isNormalArguments());
|
||||
uint32 argc = argsobj->getArgsInitialLength();
|
||||
for (uint32 i = 0; i != argc; ++i) {
|
||||
if (!argsobj->getArgsElement(i).isMagic(JS_ARGS_HOLE))
|
||||
argsobj->setArgsElement(i, args[i]);
|
||||
|
@ -202,8 +212,8 @@ js_GetArgsObject(JSContext *cx, JSStackFrame *fp)
|
|||
* We must be in a function activation; the function must be lightweight
|
||||
* or else fp must have a variable object.
|
||||
*/
|
||||
JS_ASSERT(fp->fun);
|
||||
JS_ASSERT_IF(fp->fun->flags & JSFUN_HEAVYWEIGHT,
|
||||
JS_ASSERT(fp->hasFunction());
|
||||
JS_ASSERT_IF(fp->getFunction()->flags & JSFUN_HEAVYWEIGHT,
|
||||
fp->varobj(cx->containingSegment(fp)));
|
||||
|
||||
/* Skip eval and debugger frames. */
|
||||
|
@ -215,13 +225,27 @@ js_GetArgsObject(JSContext *cx, JSStackFrame *fp)
|
|||
return fp->getArgsObj();
|
||||
|
||||
/* Compute the arguments object's parent slot from fp's scope chain. */
|
||||
JSObject *global = fp->scopeChain->getGlobal();
|
||||
JSObject *global = fp->getScopeChain()->getGlobal();
|
||||
JSObject *argsobj = NewArguments(cx, global, fp->argc, &fp->argv[-2].toObject());
|
||||
if (!argsobj)
|
||||
return argsobj;
|
||||
|
||||
/* Link the new object to fp so it can get actual argument values. */
|
||||
argsobj->setPrivate(fp);
|
||||
/*
|
||||
* Strict mode functions have arguments which copy the initial parameter
|
||||
* values. It is the caller's responsibility to get the arguments object
|
||||
* before any parameters are modified! (The emitter ensures this by
|
||||
* synthesizing an arguments access at the start of any strict mode
|
||||
* function which contains an assignment to a parameter or which calls
|
||||
* eval.) Non-strict mode arguments use the frame pointer to retrieve
|
||||
* up-to-date parameter values.
|
||||
*/
|
||||
if (argsobj->isStrictArguments()) {
|
||||
JS_ASSERT_IF(fp->argc > 0, argsobj->dslots[-1].toPrivateUint32() >= fp->argc);
|
||||
memcpy(argsobj->dslots, fp->argv, fp->argc * sizeof(Value));
|
||||
} else {
|
||||
argsobj->setPrivate(fp);
|
||||
}
|
||||
|
||||
fp->setArgsObj(argsobj);
|
||||
return argsobj;
|
||||
}
|
||||
|
@ -230,9 +254,13 @@ void
|
|||
js_PutArgsObject(JSContext *cx, JSStackFrame *fp)
|
||||
{
|
||||
JSObject *argsobj = fp->getArgsObj();
|
||||
JS_ASSERT(argsobj->getPrivate() == fp);
|
||||
PutArguments(cx, argsobj, fp->argv);
|
||||
argsobj->setPrivate(NULL);
|
||||
if (argsobj->isNormalArguments()) {
|
||||
JS_ASSERT(argsobj->getPrivate() == fp);
|
||||
PutArguments(cx, argsobj, fp->argv);
|
||||
argsobj->setPrivate(NULL);
|
||||
} else {
|
||||
JS_ASSERT(!argsobj->getPrivate());
|
||||
}
|
||||
fp->setArgsObj(NULL);
|
||||
}
|
||||
|
||||
|
@ -247,7 +275,17 @@ js_Arguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject *callee)
|
|||
JSObject *argsobj = NewArguments(cx, parent, argc, callee);
|
||||
if (!argsobj)
|
||||
return NULL;
|
||||
argsobj->setPrivate(JS_ARGUMENT_OBJECT_ON_TRACE);
|
||||
|
||||
if (callee->getFunctionPrivate()->inStrictMode()) {
|
||||
/*
|
||||
* Strict mode callers must copy arguments into the created arguments
|
||||
* object.
|
||||
*/
|
||||
JS_ASSERT(!argsobj->getPrivate());
|
||||
} else {
|
||||
argsobj->setPrivate(JS_ARGUMENT_OBJECT_ON_TRACE);
|
||||
}
|
||||
|
||||
return argsobj;
|
||||
}
|
||||
#endif
|
||||
|
@ -259,6 +297,7 @@ JS_DEFINE_CALLINFO_4(extern, OBJECT, js_Arguments, CONTEXT, OBJECT, UINT32, OBJE
|
|||
JSBool JS_FASTCALL
|
||||
js_PutArguments(JSContext *cx, JSObject *argsobj, Value *args)
|
||||
{
|
||||
JS_ASSERT(argsobj->isNormalArguments());
|
||||
JS_ASSERT(argsobj->getPrivate() == JS_ARGUMENT_OBJECT_ON_TRACE);
|
||||
PutArguments(cx, argsobj, args);
|
||||
argsobj->setPrivate(NULL);
|
||||
|
@ -275,7 +314,7 @@ args_delProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
|||
|
||||
if (JSID_IS_INT(id)) {
|
||||
uintN arg = uintN(JSID_TO_INT(id));
|
||||
if (arg < obj->getArgsLength())
|
||||
if (arg < obj->getArgsInitialLength())
|
||||
obj->setArgsElement(arg, MagicValue(JS_ARGS_HOLE));
|
||||
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
|
||||
obj->setArgsLengthOverridden();
|
||||
|
@ -471,7 +510,7 @@ ArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
|||
* prototype to point to another Arguments object with a bigger argc.
|
||||
*/
|
||||
uintN arg = uintN(JSID_TO_INT(id));
|
||||
if (arg < obj->getArgsLength()) {
|
||||
if (arg < obj->getArgsInitialLength()) {
|
||||
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
|
||||
if (fp) {
|
||||
*vp = fp->argv[arg];
|
||||
|
@ -483,7 +522,7 @@ ArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
|||
}
|
||||
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
|
||||
if (!obj->isArgsLengthOverridden())
|
||||
vp->setInt32(obj->getArgsLength());
|
||||
vp->setInt32(obj->getArgsInitialLength());
|
||||
} else {
|
||||
JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom));
|
||||
const Value &v = obj->getArgsCallee();
|
||||
|
@ -526,7 +565,7 @@ ArgSetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
|||
|
||||
if (JSID_IS_INT(id)) {
|
||||
uintN arg = uintN(JSID_TO_INT(id));
|
||||
if (arg < obj->getArgsLength()) {
|
||||
if (arg < obj->getArgsInitialLength()) {
|
||||
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
|
||||
if (fp) {
|
||||
fp->argv[arg] = *vp;
|
||||
|
@ -540,8 +579,8 @@ ArgSetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
|||
|
||||
/*
|
||||
* For simplicity we use delete/set to replace the property with one
|
||||
* backed by the default Object getter and setter. Note the we rely on
|
||||
* args_delete to clear the corresponding reserved slot so the GC can
|
||||
* backed by the default Object getter and setter. Note that we rely on
|
||||
* args_delProperty to clear the corresponding reserved slot so the GC can
|
||||
* collect its value.
|
||||
*/
|
||||
AutoValueRooter tvr(cx);
|
||||
|
@ -553,13 +592,15 @@ static JSBool
|
|||
args_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
||||
JSObject **objp)
|
||||
{
|
||||
JS_ASSERT(obj->isArguments());
|
||||
JS_ASSERT(obj->isNormalArguments());
|
||||
|
||||
*objp = NULL;
|
||||
bool valid = false;
|
||||
uintN attrs = JSPROP_SHARED;
|
||||
if (JSID_IS_INT(id)) {
|
||||
uint32 arg = uint32(JSID_TO_INT(id));
|
||||
if (arg < obj->getArgsLength() && !obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE))
|
||||
attrs = JSPROP_ENUMERATE | JSPROP_SHARED;
|
||||
if (arg < obj->getArgsInitialLength() && !obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE))
|
||||
valid = true;
|
||||
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
|
||||
if (!obj->isArgsLengthOverridden())
|
||||
|
@ -570,12 +611,8 @@ args_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
|||
}
|
||||
|
||||
if (valid) {
|
||||
/*
|
||||
* XXX ECMA specs DontEnum even for indexed properties, contrary to
|
||||
* other array-like objects.
|
||||
*/
|
||||
Value tmp = UndefinedValue();
|
||||
if (!js_DefineProperty(cx, obj, id, &tmp, ArgGetter, ArgSetter, JSPROP_SHARED))
|
||||
if (!js_DefineProperty(cx, obj, id, &tmp, ArgGetter, ArgSetter, attrs))
|
||||
return JS_FALSE;
|
||||
*objp = obj;
|
||||
}
|
||||
|
@ -585,13 +622,13 @@ args_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
|||
static JSBool
|
||||
args_enumerate(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(obj->isArguments());
|
||||
JS_ASSERT(obj->isNormalArguments());
|
||||
|
||||
/*
|
||||
* Trigger reflection in args_resolve using a series of js_LookupProperty
|
||||
* calls.
|
||||
*/
|
||||
int argc = int(obj->getArgsLength());
|
||||
int argc = int(obj->getArgsInitialLength());
|
||||
for (int i = -2; i != argc; i++) {
|
||||
jsid id = (i == -2)
|
||||
? ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)
|
||||
|
@ -611,6 +648,154 @@ args_enumerate(JSContext *cx, JSObject *obj)
|
|||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
JSBool
|
||||
StrictArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
{
|
||||
LeaveTrace(cx);
|
||||
|
||||
if (!InstanceOf(cx, obj, &StrictArgumentsClass, NULL))
|
||||
return true;
|
||||
|
||||
if (JSID_IS_INT(id)) {
|
||||
/*
|
||||
* arg can exceed the number of arguments if a script changed the
|
||||
* prototype to point to another Arguments object with a bigger argc.
|
||||
*/
|
||||
uintN arg = uintN(JSID_TO_INT(id));
|
||||
if (arg < obj->getArgsInitialLength()) {
|
||||
const Value &v = obj->getArgsElement(arg);
|
||||
if (!v.isMagic(JS_ARGS_HOLE))
|
||||
*vp = v;
|
||||
}
|
||||
} else {
|
||||
JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom));
|
||||
if (!obj->isArgsLengthOverridden())
|
||||
vp->setInt32(obj->getArgsInitialLength());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
StrictArgSetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
{
|
||||
if (!InstanceOf(cx, obj, &StrictArgumentsClass, NULL))
|
||||
return true;
|
||||
|
||||
if (JSID_IS_INT(id)) {
|
||||
uintN arg = uintN(JSID_TO_INT(id));
|
||||
if (arg < obj->getArgsInitialLength()) {
|
||||
obj->setArgsElement(arg, *vp);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom));
|
||||
}
|
||||
|
||||
/*
|
||||
* For simplicity we use delete/set to replace the property with one
|
||||
* backed by the default Object getter and setter. Note that we rely on
|
||||
* args_delProperty to clear the corresponding reserved slot so the GC can
|
||||
* collect its value.
|
||||
*/
|
||||
AutoValueRooter tvr(cx);
|
||||
return js_DeleteProperty(cx, obj, id, tvr.addr()) &&
|
||||
js_SetProperty(cx, obj, id, vp);
|
||||
}
|
||||
|
||||
JSBool
|
||||
strictargs_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp)
|
||||
{
|
||||
JS_ASSERT(obj->isStrictArguments());
|
||||
|
||||
*objp = NULL;
|
||||
bool valid = false;
|
||||
uintN attrs = JSPROP_SHARED;
|
||||
if (JSID_IS_INT(id)) {
|
||||
uint32 arg = uint32(JSID_TO_INT(id));
|
||||
attrs = JSPROP_SHARED | JSPROP_ENUMERATE;
|
||||
if (arg < obj->getArgsInitialLength() && !obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE))
|
||||
valid = true;
|
||||
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
|
||||
if (!obj->isArgsLengthOverridden())
|
||||
valid = true;
|
||||
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)) {
|
||||
Value tmp = UndefinedValue();
|
||||
PropertyOp throwTypeError = CastAsPropertyOp(obj->getThrowTypeError());
|
||||
uintN attrs = JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED;
|
||||
if (!js_DefineProperty(cx, obj, id, &tmp, throwTypeError, throwTypeError, attrs))
|
||||
return false;
|
||||
|
||||
*objp = obj;
|
||||
return true;
|
||||
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.callerAtom)) {
|
||||
/*
|
||||
* Strict mode arguments objects have an immutable poison-pill caller
|
||||
* property that throws a TypeError on getting or setting.
|
||||
*/
|
||||
PropertyOp throwTypeError = CastAsPropertyOp(obj->getThrowTypeError());
|
||||
Value tmp = UndefinedValue();
|
||||
if (!js_DefineProperty(cx, obj, id, &tmp, throwTypeError, throwTypeError,
|
||||
JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*objp = obj;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
Value tmp = UndefinedValue();
|
||||
if (!js_DefineProperty(cx, obj, id, &tmp, StrictArgGetter, StrictArgSetter, attrs))
|
||||
return false;
|
||||
*objp = obj;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
strictargs_enumerate(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(obj->isStrictArguments());
|
||||
|
||||
/*
|
||||
* Trigger reflection in strictargs_resolve using a series of
|
||||
* js_LookupProperty calls. Beware deleted properties!
|
||||
*/
|
||||
JSObject *pobj;
|
||||
JSProperty *prop;
|
||||
|
||||
// length
|
||||
if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), &pobj, &prop))
|
||||
return false;
|
||||
if (prop)
|
||||
pobj->dropProperty(cx, prop);
|
||||
|
||||
// callee
|
||||
if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.calleeAtom), &pobj, &prop))
|
||||
return false;
|
||||
if (prop)
|
||||
pobj->dropProperty(cx, prop);
|
||||
|
||||
// caller
|
||||
if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.callerAtom), &pobj, &prop))
|
||||
return false;
|
||||
if (prop)
|
||||
pobj->dropProperty(cx, prop);
|
||||
|
||||
for (uint32 i = 0, argc = obj->getArgsInitialLength(); i < argc; i++) {
|
||||
if (!js_LookupProperty(cx, obj, INT_TO_JSID(i), &pobj, &prop))
|
||||
return false;
|
||||
if (prop)
|
||||
pobj->dropProperty(cx, prop);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#if JS_HAS_GENERATORS
|
||||
/*
|
||||
* If a generator's arguments or call object escapes, and the generator frame
|
||||
|
@ -641,11 +826,14 @@ args_or_call_trace(JSTracer *trc, JSObject *obj)
|
|||
#endif
|
||||
|
||||
/*
|
||||
* The Arguments class is not initialized via JS_InitClass, because arguments
|
||||
* The Arguments classes aren't initialized via JS_InitClass, because arguments
|
||||
* objects have the initial value of Object.prototype as their [[Prototype]].
|
||||
* However, Object.prototype.toString.call(arguments) === "[object Arguments]"
|
||||
* per ES5 (although not ES3), so its class name is "Arguments" rather than
|
||||
* per ES5 (although not ES3), so the class name is "Arguments" rather than
|
||||
* "Object".
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* The JSClass functions below collaborate to lazily reflect and synchronize
|
||||
* actual argument values, argument count, and callee function object stored
|
||||
|
@ -674,6 +862,37 @@ Class js_ArgumentsClass = {
|
|||
JS_CLASS_TRACE(args_or_call_trace)
|
||||
};
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
* Strict mode arguments is significantly less magical than non-strict mode
|
||||
* arguments, so it is represented by a different class while sharing some
|
||||
* functionality.
|
||||
*/
|
||||
Class StrictArgumentsClass = {
|
||||
"Arguments",
|
||||
JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(JSObject::ARGS_FIXED_RESERVED_SLOTS) |
|
||||
JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
|
||||
PropertyStub, /* addProperty */
|
||||
args_delProperty,
|
||||
PropertyStub, /* getProperty */
|
||||
PropertyStub, /* setProperty */
|
||||
strictargs_enumerate,
|
||||
reinterpret_cast<JSResolveOp>(strictargs_resolve),
|
||||
ConvertStub,
|
||||
NULL, /* finalize */
|
||||
NULL, /* reserved0 */
|
||||
NULL, /* checkAccess */
|
||||
NULL, /* call */
|
||||
NULL, /* construct */
|
||||
NULL, /* xdrObject */
|
||||
NULL, /* hasInstance */
|
||||
JS_CLASS_TRACE(args_or_call_trace)
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
const uint32 JSSLOT_CALLEE = JSSLOT_PRIVATE + 1;
|
||||
const uint32 JSSLOT_CALL_ARGUMENTS = JSSLOT_PRIVATE + 2;
|
||||
const uint32 CALL_CLASS_FIXED_RESERVED_SLOTS = 2;
|
||||
|
@ -763,7 +982,7 @@ NewDeclEnvObject(JSContext *cx, JSStackFrame *fp)
|
|||
return NULL;
|
||||
|
||||
/* Init immediately to avoid GC seeing a half-init'ed object. */
|
||||
envobj->init(&js_DeclEnvClass, NULL, fp->scopeChain, PrivateValue(fp));
|
||||
envobj->init(&js_DeclEnvClass, NULL, fp->maybeScopeChain(), PrivateValue(fp));
|
||||
envobj->map = cx->runtime->emptyDeclEnvScope->hold();
|
||||
return envobj;
|
||||
}
|
||||
|
@ -772,17 +991,17 @@ JSObject *
|
|||
js_GetCallObject(JSContext *cx, JSStackFrame *fp)
|
||||
{
|
||||
/* Create a call object for fp only if it lacks one. */
|
||||
JS_ASSERT(fp->fun);
|
||||
JS_ASSERT(fp->hasFunction());
|
||||
if (fp->hasCallObj())
|
||||
return fp->getCallObj();
|
||||
|
||||
#ifdef DEBUG
|
||||
/* A call object should be a frame's outermost scope chain element. */
|
||||
Class *classp = fp->scopeChain->getClass();
|
||||
Class *classp = fp->getScopeChain()->getClass();
|
||||
if (classp == &js_WithClass || classp == &js_BlockClass)
|
||||
JS_ASSERT(fp->scopeChain->getPrivate() != js_FloatingFrameIfGenerator(cx, fp));
|
||||
JS_ASSERT(fp->getScopeChain()->getPrivate() != js_FloatingFrameIfGenerator(cx, fp));
|
||||
else if (classp == &js_CallClass)
|
||||
JS_ASSERT(fp->scopeChain->getPrivate() != fp);
|
||||
JS_ASSERT(fp->getScopeChain()->getPrivate() != fp);
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -791,16 +1010,17 @@ js_GetCallObject(JSContext *cx, JSStackFrame *fp)
|
|||
* expression Call's parent points to an environment object holding
|
||||
* function's name.
|
||||
*/
|
||||
JSAtom *lambdaName = (fp->fun->flags & JSFUN_LAMBDA) ? fp->fun->atom : NULL;
|
||||
JSAtom *lambdaName =
|
||||
(fp->getFunction()->flags & JSFUN_LAMBDA) ? fp->getFunction()->atom : NULL;
|
||||
if (lambdaName) {
|
||||
JSObject *envobj = NewDeclEnvObject(cx, fp);
|
||||
if (!envobj)
|
||||
return NULL;
|
||||
|
||||
/* Root envobj before js_DefineNativeProperty (-> JSClass.addProperty). */
|
||||
fp->scopeChain = envobj;
|
||||
fp->setScopeChain(envobj);
|
||||
JS_ASSERT(fp->argv);
|
||||
if (!js_DefineNativeProperty(cx, fp->scopeChain, ATOM_TO_JSID(lambdaName),
|
||||
if (!js_DefineNativeProperty(cx, fp->getScopeChain(), ATOM_TO_JSID(lambdaName),
|
||||
fp->calleeValue(),
|
||||
CalleeGetter, NULL,
|
||||
JSPROP_PERMANENT | JSPROP_READONLY,
|
||||
|
@ -809,13 +1029,13 @@ js_GetCallObject(JSContext *cx, JSStackFrame *fp)
|
|||
}
|
||||
}
|
||||
|
||||
JSObject *callobj = NewCallObject(cx, fp->fun, fp->scopeChain);
|
||||
JSObject *callobj = NewCallObject(cx, fp->getFunction(), fp->getScopeChain());
|
||||
if (!callobj)
|
||||
return NULL;
|
||||
|
||||
callobj->setPrivate(fp);
|
||||
JS_ASSERT(fp->argv);
|
||||
JS_ASSERT(fp->fun == GET_FUNCTION_PRIVATE(cx, fp->callee()));
|
||||
JS_ASSERT(fp->getFunction() == GET_FUNCTION_PRIVATE(cx, fp->callee()));
|
||||
callobj->setSlot(JSSLOT_CALLEE, fp->calleeValue());
|
||||
fp->setCallObj(callobj);
|
||||
|
||||
|
@ -823,7 +1043,7 @@ js_GetCallObject(JSContext *cx, JSStackFrame *fp)
|
|||
* Push callobj on the top of the scope chain, and make it the
|
||||
* variables object.
|
||||
*/
|
||||
fp->scopeChain = callobj;
|
||||
fp->setScopeChain(callobj);
|
||||
return callobj;
|
||||
}
|
||||
|
||||
|
@ -873,7 +1093,7 @@ js_PutCallObject(JSContext *cx, JSStackFrame *fp)
|
|||
js_PutArgsObject(cx, fp);
|
||||
}
|
||||
|
||||
JSFunction *fun = fp->fun;
|
||||
JSFunction *fun = fp->getFunction();
|
||||
JS_ASSERT(fun == js_GetCallObjectFunction(callobj));
|
||||
uintN n = fun->countArgsAndVars();
|
||||
|
||||
|
@ -1265,11 +1485,13 @@ JS_PUBLIC_DATA(Class) js_CallClass = {
|
|||
bool
|
||||
JSStackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
|
||||
{
|
||||
if (!fun) {
|
||||
if (!hasFunction()) {
|
||||
*vp = argv ? argv[-2] : UndefinedValue();
|
||||
return true;
|
||||
}
|
||||
|
||||
JSFunction *fun = getFunction();
|
||||
|
||||
/*
|
||||
* See the equivalent condition in args_getProperty for ARGS_CALLEE, but
|
||||
* note that here we do not want to throw, since this escape can happen via
|
||||
|
@ -1292,11 +1514,11 @@ JSStackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
|
|||
* through the frame's |this| object's method read barrier for the method
|
||||
* atom by which it was uniquely associated with a property.
|
||||
*/
|
||||
if (thisv.isObject()) {
|
||||
if (getThisValue().isObject()) {
|
||||
JS_ASSERT(GET_FUNCTION_PRIVATE(cx, funobj) == fun);
|
||||
|
||||
if (fun == funobj && fun->methodAtom()) {
|
||||
JSObject *thisp = &thisv.toObject();
|
||||
JSObject *thisp = &getThisValue().toObject();
|
||||
JS_ASSERT(thisp->canHaveMethodBarrier());
|
||||
|
||||
JSScope *scope = thisp->scope();
|
||||
|
@ -1382,8 +1604,9 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
|||
* Function.prototype object (we use JSPROP_PERMANENT with JSPROP_SHARED
|
||||
* to make it appear so).
|
||||
*
|
||||
* This code couples tightly to the attributes for lazy_function_props[]
|
||||
* initializers above, and to js_SetProperty and js_HasOwnProperty.
|
||||
* This code couples tightly to the attributes for lazyFunctionDataProps[]
|
||||
* and poisonPillProps[] initializers below, and to js_SetProperty and
|
||||
* js_HasOwnProperty.
|
||||
*
|
||||
* It's important to allow delegating objects, even though they inherit
|
||||
* this getter (fun_getProperty), to override arguments, arity, caller,
|
||||
|
@ -1408,7 +1631,7 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
|||
/* Find fun's top-most activation record. */
|
||||
JSStackFrame *fp;
|
||||
for (fp = js_GetTopStackFrame(cx);
|
||||
fp && (fp->fun != fun || (fp->flags & JSFRAME_SPECIAL));
|
||||
fp && (fp->maybeFunction() != fun || (fp->flags & JSFRAME_SPECIAL));
|
||||
fp = fp->down) {
|
||||
continue;
|
||||
}
|
||||
|
@ -1455,7 +1678,7 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
|||
|
||||
default:
|
||||
/* XXX fun[0] and fun.arguments[0] are equivalent. */
|
||||
if (fp && fp->fun && (uintN)slot < fp->fun->nargs)
|
||||
if (fp && fp->hasFunction() && (uintN)slot < fp->getFunction()->nargs)
|
||||
*vp = fp->argv[slot];
|
||||
break;
|
||||
}
|
||||
|
@ -1463,20 +1686,34 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
struct LazyFunctionProp {
|
||||
namespace {
|
||||
|
||||
struct LazyFunctionDataProp {
|
||||
uint16 atomOffset;
|
||||
int8 tinyid;
|
||||
uint8 attrs;
|
||||
};
|
||||
|
||||
/* NB: no sentinel at the end -- use JS_ARRAY_LENGTH to bound loops. */
|
||||
static LazyFunctionProp lazy_function_props[] = {
|
||||
{ATOM_OFFSET(arguments), FUN_ARGUMENTS, JSPROP_PERMANENT},
|
||||
struct PoisonPillProp {
|
||||
uint16 atomOffset;
|
||||
int8 tinyid;
|
||||
};
|
||||
|
||||
/* NB: no sentinels at ends -- use JS_ARRAY_LENGTH to bound loops. */
|
||||
|
||||
const LazyFunctionDataProp lazyFunctionDataProps[] = {
|
||||
{ATOM_OFFSET(arity), FUN_ARITY, JSPROP_PERMANENT},
|
||||
{ATOM_OFFSET(caller), FUN_CALLER, JSPROP_PERMANENT},
|
||||
{ATOM_OFFSET(name), FUN_NAME, JSPROP_PERMANENT},
|
||||
};
|
||||
|
||||
/* Properties censored into [[ThrowTypeError]] in strict mode. */
|
||||
const PoisonPillProp poisonPillProps[] = {
|
||||
{ATOM_OFFSET(arguments), FUN_ARGUMENTS },
|
||||
{ATOM_OFFSET(caller), FUN_CALLER },
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static JSBool
|
||||
fun_enumerate(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
|
@ -1490,13 +1727,20 @@ fun_enumerate(JSContext *cx, JSObject *obj)
|
|||
if (!JS_LookupPropertyById(cx, obj, id, &v))
|
||||
return false;
|
||||
|
||||
for (uintN i = 0; i < JS_ARRAY_LENGTH(lazy_function_props); i++) {
|
||||
LazyFunctionProp &lfp = lazy_function_props[i];
|
||||
for (uintN i = 0; i < JS_ARRAY_LENGTH(lazyFunctionDataProps); i++) {
|
||||
const LazyFunctionDataProp &lfp = lazyFunctionDataProps[i];
|
||||
id = ATOM_TO_JSID(OFFSET_TO_ATOM(cx->runtime, lfp.atomOffset));
|
||||
if (!JS_LookupPropertyById(cx, obj, id, &v))
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uintN i = 0; i < JS_ARRAY_LENGTH(poisonPillProps); i++) {
|
||||
const PoisonPillProp &p = poisonPillProps[i];
|
||||
id = ATOM_TO_JSID(OFFSET_TO_ATOM(cx->runtime, p.atomOffset));
|
||||
if (!JS_LookupPropertyById(cx, obj, id, &v))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1572,8 +1816,8 @@ fun_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
|||
return JS_TRUE;
|
||||
}
|
||||
|
||||
for (uintN i = 0; i < JS_ARRAY_LENGTH(lazy_function_props); i++) {
|
||||
LazyFunctionProp *lfp = &lazy_function_props[i];
|
||||
for (uintN i = 0; i < JS_ARRAY_LENGTH(lazyFunctionDataProps); i++) {
|
||||
const LazyFunctionDataProp *lfp = &lazyFunctionDataProps[i];
|
||||
|
||||
atom = OFFSET_TO_ATOM(cx->runtime, lfp->atomOffset);
|
||||
if (id == ATOM_TO_JSID(atom)) {
|
||||
|
@ -1591,6 +1835,37 @@ fun_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
|||
}
|
||||
}
|
||||
|
||||
for (uintN i = 0; i < JS_ARRAY_LENGTH(poisonPillProps); i++) {
|
||||
const PoisonPillProp &p = poisonPillProps[i];
|
||||
|
||||
atom = OFFSET_TO_ATOM(cx->runtime, p.atomOffset);
|
||||
if (id == ATOM_TO_JSID(atom)) {
|
||||
JS_ASSERT(!IsInternalFunctionObject(obj));
|
||||
|
||||
PropertyOp getter, setter;
|
||||
uintN attrs = JSPROP_PERMANENT;
|
||||
if (fun->inStrictMode()) {
|
||||
JSObject *throwTypeError = obj->getThrowTypeError();
|
||||
|
||||
getter = CastAsPropertyOp(throwTypeError);
|
||||
setter = CastAsPropertyOp(throwTypeError);
|
||||
attrs |= JSPROP_GETTER | JSPROP_SETTER;
|
||||
} else {
|
||||
getter = fun_getProperty;
|
||||
setter = PropertyStub;
|
||||
}
|
||||
|
||||
if (!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), UndefinedValue(),
|
||||
getter, setter,
|
||||
attrs, JSScopeProperty::HAS_SHORTID,
|
||||
p.tinyid, NULL)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
*objp = obj;
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
|
@ -2070,7 +2345,7 @@ js_fun_apply(JSContext *cx, uintN argc, Value *vp)
|
|||
if (aobj->isArray()) {
|
||||
length = aobj->getArrayLength();
|
||||
} else if (aobj->isArguments() && !aobj->isArgsLengthOverridden()) {
|
||||
length = aobj->getArgsLength();
|
||||
length = aobj->getArgsInitialLength();
|
||||
} else {
|
||||
Value &lenval = vp[0];
|
||||
if (!aobj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), &lenval))
|
||||
|
@ -2210,7 +2485,8 @@ Function(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval)
|
|||
* Function indirectly from a script.
|
||||
*/
|
||||
fp = js_GetTopStackFrame(cx);
|
||||
JS_ASSERT(!fp->script && fp->fun && fp->fun->u.n.native == Function);
|
||||
JS_ASSERT(!fp->hasScript() && fp->hasFunction() &&
|
||||
fp->getFunction()->u.n.native == Function);
|
||||
caller = js_GetScriptedCaller(cx, fp);
|
||||
if (caller) {
|
||||
principals = JS_EvalFramePrincipals(cx, fp, caller);
|
||||
|
@ -2389,20 +2665,43 @@ Function(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval)
|
|||
filename, lineno);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
JSBool
|
||||
ThrowTypeError(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
|
||||
JSMSG_THROW_TYPE_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
JSObject *
|
||||
js_InitFunctionClass(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
JSObject *proto;
|
||||
JSFunction *fun;
|
||||
|
||||
proto = js_InitClass(cx, obj, NULL, &js_FunctionClass, Function, 1,
|
||||
NULL, function_methods, NULL, NULL);
|
||||
JSObject *proto = js_InitClass(cx, obj, NULL, &js_FunctionClass, Function, 1,
|
||||
NULL, function_methods, NULL, NULL);
|
||||
if (!proto)
|
||||
return NULL;
|
||||
fun = js_NewFunction(cx, proto, NULL, 0, JSFUN_INTERPRETED, obj, NULL);
|
||||
|
||||
JSFunction *fun = js_NewFunction(cx, proto, NULL, 0, JSFUN_INTERPRETED, obj, NULL);
|
||||
if (!fun)
|
||||
return NULL;
|
||||
fun->u.i.script = JSScript::emptyScript();
|
||||
|
||||
if (obj->getClass()->flags & JSCLASS_IS_GLOBAL) {
|
||||
/* ES5 13.2.3: Construct the unique [[ThrowTypeError]] function object. */
|
||||
JSObject *throwTypeError =
|
||||
js_NewFunction(cx, NULL, reinterpret_cast<Native>(ThrowTypeError), 0,
|
||||
JSFUN_FAST_NATIVE, obj, NULL);
|
||||
if (!throwTypeError)
|
||||
return NULL;
|
||||
|
||||
JS_ALWAYS_TRUE(js_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_THROWTYPEERROR,
|
||||
ObjectValue(*throwTypeError)));
|
||||
}
|
||||
|
||||
return proto;
|
||||
}
|
||||
|
||||
|
@ -2544,8 +2843,8 @@ js_NewFlatClosure(JSContext *cx, JSFunction *fun)
|
|||
JSObject *
|
||||
js_NewDebuggableFlatClosure(JSContext *cx, JSFunction *fun)
|
||||
{
|
||||
JS_ASSERT(cx->fp->fun->flags & JSFUN_HEAVYWEIGHT);
|
||||
JS_ASSERT(!cx->fp->fun->optimizedClosure());
|
||||
JS_ASSERT(cx->fp->getFunction()->flags & JSFUN_HEAVYWEIGHT);
|
||||
JS_ASSERT(!cx->fp->getFunction()->optimizedClosure());
|
||||
JS_ASSERT(FUN_FLAT_CLOSURE(fun));
|
||||
|
||||
return WrapEscapingClosure(cx, cx->fp, fun);
|
||||
|
@ -2599,34 +2898,13 @@ js_ValueToFunction(JSContext *cx, const Value *vp, uintN flags)
|
|||
JSObject *
|
||||
js_ValueToFunctionObject(JSContext *cx, Value *vp, uintN flags)
|
||||
{
|
||||
JSFunction *fun;
|
||||
JSStackFrame *caller;
|
||||
JSPrincipals *principals;
|
||||
|
||||
JSObject *funobj;
|
||||
if (IsFunctionObject(*vp, &funobj))
|
||||
return funobj;
|
||||
|
||||
fun = js_ValueToFunction(cx, vp, flags);
|
||||
if (!fun)
|
||||
return NULL;
|
||||
vp->setObject(*fun);
|
||||
|
||||
caller = js_GetScriptedCaller(cx, NULL);
|
||||
if (caller) {
|
||||
principals = JS_StackFramePrincipals(cx, caller);
|
||||
} else {
|
||||
/* No scripted caller, don't allow access. */
|
||||
principals = NULL;
|
||||
}
|
||||
|
||||
if (!js_CheckPrincipalsAccess(cx, FUN_OBJECT(fun), principals,
|
||||
fun->atom
|
||||
? fun->atom
|
||||
: cx->runtime->atomState.anonymousAtom)) {
|
||||
if (!IsFunctionObject(*vp, &funobj)) {
|
||||
js_ReportIsNotFunction(cx, vp, flags);
|
||||
return NULL;
|
||||
}
|
||||
return FUN_OBJECT(fun);
|
||||
|
||||
return funobj;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
|
@ -2637,7 +2915,9 @@ js_ValueToCallableObject(JSContext *cx, Value *vp, uintN flags)
|
|||
if (callable->isCallable())
|
||||
return callable;
|
||||
}
|
||||
return js_ValueToFunctionObject(cx, vp, flags);
|
||||
|
||||
js_ReportIsNotFunction(cx, vp, flags);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2665,7 +2945,7 @@ js_ReportIsNotFunction(JSContext *cx, const Value *vp, uintN flags)
|
|||
++i;
|
||||
|
||||
if (!i.done()) {
|
||||
uintN depth = js_ReconstructStackDepth(cx, i.fp()->script, i.pc());
|
||||
uintN depth = js_ReconstructStackDepth(cx, i.fp()->getScript(), i.pc());
|
||||
Value *simsp = i.fp()->base() + depth;
|
||||
JS_ASSERT(simsp <= i.sp());
|
||||
if (i.fp()->base() <= vp && vp < simsp)
|
||||
|
@ -3113,6 +3393,8 @@ js_FreezeLocalNames(JSContext *cx, JSFunction *fun)
|
|||
JSAtom *
|
||||
JSFunction::findDuplicateFormal() const
|
||||
{
|
||||
JS_ASSERT(isInterpreted());
|
||||
|
||||
if (nargs <= 1)
|
||||
return NULL;
|
||||
|
||||
|
|
|
@ -184,6 +184,8 @@ struct JSFunction : public JSObject
|
|||
bool isHeavyweight() const { return JSFUN_HEAVYWEIGHT_TEST(flags); }
|
||||
unsigned minArgs() const { return FUN_MINARGS(this); }
|
||||
|
||||
inline bool inStrictMode() const;
|
||||
|
||||
uintN countVars() const {
|
||||
JS_ASSERT(FUN_INTERPRETED(this));
|
||||
return u.i.nvars;
|
||||
|
@ -278,8 +280,9 @@ JS_STATIC_ASSERT(sizeof(JSFunction) % JS_GCTHING_ALIGN == 0);
|
|||
#endif
|
||||
|
||||
/*
|
||||
* NB: the Arguments class is an uninitialized internal class that masquerades
|
||||
* (according to Object.prototype.toString.call(argsobj)) as "Object".
|
||||
* NB: the Arguments classes are uninitialized internal classes that masquerade
|
||||
* (according to Object.prototype.toString.call(arguments)) as "Arguments",
|
||||
* while having Object.getPrototypeOf(arguments) === Object.prototype.
|
||||
*
|
||||
* WARNING (to alert embedders reading this private .h file): arguments objects
|
||||
* are *not* thread-safe and should not be used concurrently -- they should be
|
||||
|
@ -291,11 +294,26 @@ JS_STATIC_ASSERT(sizeof(JSFunction) % JS_GCTHING_ALIGN == 0);
|
|||
* single-threaded objects and GC heaps.
|
||||
*/
|
||||
extern js::Class js_ArgumentsClass;
|
||||
namespace js {
|
||||
extern Class StrictArgumentsClass;
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSObject::isNormalArguments() const
|
||||
{
|
||||
return getClass() == &js_ArgumentsClass;
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSObject::isStrictArguments() const
|
||||
{
|
||||
return getClass() == &js::StrictArgumentsClass;
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSObject::isArguments() const
|
||||
{
|
||||
return getClass() == &js_ArgumentsClass;
|
||||
return isNormalArguments() || isStrictArguments();
|
||||
}
|
||||
|
||||
#define JS_ARGUMENT_OBJECT_ON_TRACE ((void *)0xa126)
|
||||
|
@ -349,6 +367,10 @@ IsFunctionObject(const js::Value &v, JSObject **funobj)
|
|||
(JS_ASSERT((funobj)->isFunction()), \
|
||||
(JSFunction *) (funobj)->getPrivate())
|
||||
|
||||
extern JSFunction *
|
||||
js_NewFunction(JSContext *cx, JSObject *funobj, js::Native native, uintN nargs,
|
||||
uintN flags, JSObject *parent, JSAtom *atom);
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
|
@ -364,6 +386,9 @@ IsInternalFunctionObject(JSObject *funobj)
|
|||
return funobj == fun && (fun->flags & JSFUN_LAMBDA) && !funobj->getParent();
|
||||
}
|
||||
|
||||
extern JSString *
|
||||
fun_toStringHelper(JSContext *cx, JSObject *obj, uintN indent);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
extern JSObject *
|
||||
|
@ -372,10 +397,6 @@ js_InitFunctionClass(JSContext *cx, JSObject *obj);
|
|||
extern JSObject *
|
||||
js_InitArgumentsClass(JSContext *cx, JSObject *obj);
|
||||
|
||||
extern JSFunction *
|
||||
js_NewFunction(JSContext *cx, JSObject *funobj, js::Native native, uintN nargs,
|
||||
uintN flags, JSObject *parent, JSAtom *atom);
|
||||
|
||||
extern void
|
||||
js_TraceFunction(JSTracer *trc, JSFunction *fun);
|
||||
|
||||
|
@ -467,6 +488,16 @@ js_GetArgsValue(JSContext *cx, JSStackFrame *fp, js::Value *vp);
|
|||
extern JSBool
|
||||
js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, js::Value *vp);
|
||||
|
||||
/*
|
||||
* Get the arguments object for the given frame. If the frame is strict mode
|
||||
* code, its current arguments will be copied into the arguments object.
|
||||
*
|
||||
* NB: Callers *must* get the arguments object before any parameters are
|
||||
* mutated when the frame is strict mode code! The emitter ensures this
|
||||
* occurs for strict mode functions containing syntax which might mutate a
|
||||
* named parameter by synthesizing an arguments access at the start of the
|
||||
* function.
|
||||
*/
|
||||
extern JSObject *
|
||||
js_GetArgsObject(JSContext *cx, JSStackFrame *fp);
|
||||
|
||||
|
@ -489,9 +520,8 @@ js_IsNamedLambda(JSFunction *fun) { return (fun->flags & JSFUN_LAMBDA) && fun->a
|
|||
const uint32 JS_ARGS_LENGTH_MAX = JS_BIT(19) - 1024;
|
||||
|
||||
/*
|
||||
* JSSLOT_ARGS_LENGTH stores ((argc << 1) | overwritten_flag) as int jsval.
|
||||
* Thus (JS_ARGS_LENGTH_MAX << 1) | 1 must fit JSVAL_INT_MAX. To assert that
|
||||
* we check first that the shift does not overflow uint32.
|
||||
* JSSLOT_ARGS_LENGTH stores ((argc << 1) | overwritten_flag) as an Int32
|
||||
* Value. Thus (JS_ARGS_LENGTH_MAX << 1) | 1 must be less than JSVAL_INT_MAX.
|
||||
*/
|
||||
JS_STATIC_ASSERT(JS_ARGS_LENGTH_MAX <= JS_BIT(30));
|
||||
JS_STATIC_ASSERT(((JS_ARGS_LENGTH_MAX << 1) | 1) <= JSVAL_INT_MAX);
|
||||
|
@ -555,11 +585,4 @@ js_fun_apply(JSContext *cx, uintN argc, js::Value *vp);
|
|||
extern JSBool
|
||||
js_fun_call(JSContext *cx, uintN argc, js::Value *vp);
|
||||
|
||||
|
||||
namespace js {
|
||||
|
||||
extern JSString *
|
||||
fun_toStringHelper(JSContext *cx, JSObject *obj, uintN indent);
|
||||
|
||||
}
|
||||
#endif /* jsfun_h___ */
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=99:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is SpiderMonkey.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef jsfuninlines_h___
|
||||
#define jsfuninlines_h___
|
||||
|
||||
#include "jsfun.h"
|
||||
#include "jsscript.h"
|
||||
|
||||
inline bool
|
||||
JSFunction::inStrictMode() const
|
||||
{
|
||||
return isInterpreted() && u.i.script->strictModeCode;
|
||||
}
|
||||
|
||||
#endif /* jsfuninlines_h___ */
|
|
@ -1334,6 +1334,8 @@ js_DumpGCStats(JSRuntime *rt, FILE *fp)
|
|||
fprintf(fp, "\nTOTAL STATS:\n");
|
||||
fprintf(fp, " bytes allocated: %lu\n", UL(rt->gcBytes));
|
||||
fprintf(fp, " total GC arenas: %lu\n", UL(sumArenas));
|
||||
fprintf(fp, " max allocated arenas: %lu\n", ULSTAT(maxnallarenas));
|
||||
fprintf(fp, " max allocated chunks: %lu\n", ULSTAT(maxnchunks));
|
||||
fprintf(fp, " total GC things: %lu\n", UL(sumThings));
|
||||
fprintf(fp, " max total GC things: %lu\n", UL(sumMaxThings));
|
||||
fprintf(fp, " GC cell utilization: %.1f%%\n",
|
||||
|
@ -1345,25 +1347,14 @@ js_DumpGCStats(JSRuntime *rt, FILE *fp)
|
|||
fprintf(fp, " alloc without locks: %lu (%.1f%%)\n",
|
||||
UL(sumLocalAlloc), PERCENT(sumLocalAlloc, sumAlloc));
|
||||
fprintf(fp, " allocation failures: %lu\n", UL(sumFail));
|
||||
fprintf(fp, " things born locked: %lu\n", ULSTAT(lockborn));
|
||||
fprintf(fp, " valid lock calls: %lu\n", ULSTAT(lock));
|
||||
fprintf(fp, " valid unlock calls: %lu\n", ULSTAT(unlock));
|
||||
fprintf(fp, " mark recursion depth: %lu\n", ULSTAT(depth));
|
||||
fprintf(fp, " maximum mark recursion: %lu\n", ULSTAT(maxdepth));
|
||||
fprintf(fp, " mark C recursion depth: %lu\n", ULSTAT(cdepth));
|
||||
fprintf(fp, " maximum mark C recursion: %lu\n", ULSTAT(maxcdepth));
|
||||
fprintf(fp, " delayed tracing calls: %lu\n", ULSTAT(unmarked));
|
||||
#ifdef DEBUG
|
||||
fprintf(fp, " max trace later count: %lu\n", ULSTAT(maxunmarked));
|
||||
#endif
|
||||
fprintf(fp, "potentially useful GC calls: %lu\n", ULSTAT(poke));
|
||||
fprintf(fp, " thing arenas freed so far: %lu\n", ULSTAT(afree));
|
||||
fprintf(fp, " stack segments scanned: %lu\n", ULSTAT(stackseg));
|
||||
fprintf(fp, "stack segment slots scanned: %lu\n", ULSTAT(segslots));
|
||||
fprintf(fp, "reachable closeable objects: %lu\n", ULSTAT(nclose));
|
||||
fprintf(fp, " max reachable closeable: %lu\n", ULSTAT(maxnclose));
|
||||
fprintf(fp, " scheduled close hooks: %lu\n", ULSTAT(closelater));
|
||||
fprintf(fp, " max scheduled close hooks: %lu\n", ULSTAT(maxcloselater));
|
||||
rt->gcStats.conservative.dump(fp);
|
||||
|
||||
#undef UL
|
||||
|
@ -1605,7 +1596,6 @@ LastDitchGC(JSContext *cx)
|
|||
JS_ASSERT(!JS_ON_TRACE(cx));
|
||||
|
||||
/* The last ditch GC preserves weak roots and all atoms. */
|
||||
AutoPreserveWeakRoots save(cx);
|
||||
AutoKeepAtoms keep(cx->runtime);
|
||||
|
||||
/*
|
||||
|
@ -1629,10 +1619,8 @@ RefillFinalizableFreeList(JSContext *cx, unsigned thingKind)
|
|||
{
|
||||
AutoLockGC lock(rt);
|
||||
JS_ASSERT(!rt->gcRunning);
|
||||
if (rt->gcRunning) {
|
||||
METER(rt->gcStats.finalfail++);
|
||||
if (rt->gcRunning)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool canGC = !JS_ON_TRACE(cx) && !JS_THREAD_DATA(cx)->waiveGCQuota;
|
||||
bool doGC = canGC && IsGCThresholdReached(rt);
|
||||
|
@ -1721,7 +1709,6 @@ js_NewFinalizableGCThing(JSContext *cx, unsigned thingKind)
|
|||
JSGCThing *thing = *freeListp;
|
||||
if (thing) {
|
||||
*freeListp = thing->link;
|
||||
cx->weakRoots.finalizableNewborns[thingKind] = thing;
|
||||
CheckGCFreeListLink(thing);
|
||||
METER(cx->runtime->gcStats.arenaStats[thingKind].localalloc++);
|
||||
return thing;
|
||||
|
@ -1742,8 +1729,6 @@ js_NewFinalizableGCThing(JSContext *cx, unsigned thingKind)
|
|||
|
||||
CheckGCFreeListLink(thing);
|
||||
|
||||
cx->weakRoots.finalizableNewborns[thingKind] = thing;
|
||||
|
||||
return thing;
|
||||
}
|
||||
|
||||
|
@ -2254,48 +2239,14 @@ js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp)
|
|||
JS_CALL_OBJECT_TRACER(trc, fp->getCallObj(), "call");
|
||||
if (fp->hasArgsObj())
|
||||
JS_CALL_OBJECT_TRACER(trc, fp->getArgsObj(), "arguments");
|
||||
if (fp->script)
|
||||
js_TraceScript(trc, fp->script);
|
||||
if (fp->hasScript())
|
||||
js_TraceScript(trc, fp->getScript());
|
||||
|
||||
/* Allow for primitive this parameter due to JSFUN_THISP_* flags. */
|
||||
MarkValue(trc, fp->thisv, "this");
|
||||
MarkValue(trc, fp->rval, "rval");
|
||||
if (fp->scopeChain)
|
||||
JS_CALL_OBJECT_TRACER(trc, fp->scopeChain, "scope chain");
|
||||
}
|
||||
|
||||
void
|
||||
JSWeakRoots::mark(JSTracer *trc)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
const char * const newbornNames[] = {
|
||||
"newborn_object", /* FINALIZE_OBJECT */
|
||||
"newborn_function", /* FINALIZE_FUNCTION */
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
"newborn_xml", /* FINALIZE_XML */
|
||||
#endif
|
||||
"newborn_short_string", /* FINALIZE_SHORT_STRING */
|
||||
"newborn_string", /* FINALIZE_STRING */
|
||||
"newborn_external_string0", /* FINALIZE_EXTERNAL_STRING0 */
|
||||
"newborn_external_string1", /* FINALIZE_EXTERNAL_STRING1 */
|
||||
"newborn_external_string2", /* FINALIZE_EXTERNAL_STRING2 */
|
||||
"newborn_external_string3", /* FINALIZE_EXTERNAL_STRING3 */
|
||||
"newborn_external_string4", /* FINALIZE_EXTERNAL_STRING4 */
|
||||
"newborn_external_string5", /* FINALIZE_EXTERNAL_STRING5 */
|
||||
"newborn_external_string6", /* FINALIZE_EXTERNAL_STRING6 */
|
||||
"newborn_external_string7", /* FINALIZE_EXTERNAL_STRING7 */
|
||||
};
|
||||
#endif
|
||||
for (size_t i = 0; i != JS_ARRAY_LENGTH(finalizableNewborns); ++i) {
|
||||
void *newborn = finalizableNewborns[i];
|
||||
if (newborn) {
|
||||
JS_CALL_TRACER(trc, newborn, GetFinalizableTraceKind(i),
|
||||
newbornNames[i]);
|
||||
}
|
||||
}
|
||||
if (lastAtom)
|
||||
MarkString(trc, ATOM_TO_STRING(lastAtom), "lastAtom");
|
||||
MarkGCThing(trc, lastInternalResult, "lastInternalResult");
|
||||
MarkValue(trc, fp->getThisValue(), "this");
|
||||
MarkValue(trc, fp->getReturnValue(), "rval");
|
||||
if (fp->hasScopeChain())
|
||||
JS_CALL_OBJECT_TRACER(trc, fp->getScopeChain(), "scope chain");
|
||||
}
|
||||
|
||||
inline void
|
||||
|
@ -2310,10 +2261,6 @@ AutoGCRooter::trace(JSTracer *trc)
|
|||
static_cast<AutoScopePropertyRooter *>(this)->sprop->trace(trc);
|
||||
return;
|
||||
|
||||
case WEAKROOTS:
|
||||
static_cast<AutoPreserveWeakRoots *>(this)->savedRoots.mark(trc);
|
||||
return;
|
||||
|
||||
case PARSER:
|
||||
static_cast<Parser *>(this)->trace(trc);
|
||||
return;
|
||||
|
@ -2410,7 +2357,6 @@ js_TraceContext(JSTracer *trc, JSContext *acx)
|
|||
/* Mark other roots-by-definition in acx. */
|
||||
if (acx->globalObject && !JS_HAS_OPTION(acx, JSOPTION_UNROOTED_GLOBAL))
|
||||
JS_CALL_OBJECT_TRACER(trc, acx->globalObject, "global object");
|
||||
acx->weakRoots.mark(trc);
|
||||
if (acx->throwing) {
|
||||
MarkValue(trc, acx->exception, "exception");
|
||||
} else {
|
||||
|
@ -3039,8 +2985,6 @@ PreGCCleanup(JSContext *cx, JSGCInvocationKind gckind)
|
|||
while (JSContext *acx = js_ContextIterator(rt, JS_TRUE, &iter))
|
||||
acx->purge();
|
||||
}
|
||||
|
||||
JS_CLEAR_WEAK_ROOTS(&cx->weakRoots);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -347,21 +347,6 @@ struct JSGCFreeLists {
|
|||
extern void
|
||||
js_DestroyScriptsToGC(JSContext *cx, JSThreadData *data);
|
||||
|
||||
struct JSWeakRoots {
|
||||
/* Most recently created things by type, members of the GC's root set. */
|
||||
void *finalizableNewborns[FINALIZE_LIMIT];
|
||||
|
||||
/* Atom root for the last-looked-up atom on this context. */
|
||||
JSAtom *lastAtom;
|
||||
|
||||
/* Root for the result of the most recent js_InternalInvoke call. */
|
||||
void *lastInternalResult;
|
||||
|
||||
void mark(JSTracer *trc);
|
||||
};
|
||||
|
||||
#define JS_CLEAR_WEAK_ROOTS(wr) (memset((wr), 0, sizeof(JSWeakRoots)))
|
||||
|
||||
namespace js {
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
|
@ -556,14 +541,8 @@ struct JSGCArenaStats {
|
|||
};
|
||||
|
||||
struct JSGCStats {
|
||||
uint32 finalfail; /* finalizer calls allocator failures */
|
||||
uint32 lockborn; /* things born locked */
|
||||
uint32 lock; /* valid lock calls */
|
||||
uint32 unlock; /* valid unlock calls */
|
||||
uint32 depth; /* mark tail recursion depth */
|
||||
uint32 maxdepth; /* maximum mark tail recursion depth */
|
||||
uint32 cdepth; /* mark recursion depth of C functions */
|
||||
uint32 maxcdepth; /* maximum mark recursion depth of C functions */
|
||||
uint32 unmarked; /* number of times marking of GC thing's children were
|
||||
delayed due to a low C stack */
|
||||
#ifdef DEBUG
|
||||
|
@ -572,12 +551,6 @@ struct JSGCStats {
|
|||
#endif
|
||||
uint32 poke; /* number of potentially useful GC calls */
|
||||
uint32 afree; /* thing arenas freed so far */
|
||||
uint32 stackseg; /* total extraordinary stack segments scanned */
|
||||
uint32 segslots; /* total stack segment value slots scanned */
|
||||
uint32 nclose; /* number of objects with close hooks */
|
||||
uint32 maxnclose; /* max number of objects with close hooks */
|
||||
uint32 closelater; /* number of close hooks scheduled to run */
|
||||
uint32 maxcloselater; /* max number of close hooks scheduled to run */
|
||||
uint32 nallarenas; /* number of all allocated arenas */
|
||||
uint32 maxnallarenas; /* maximum number of all allocated arenas */
|
||||
uint32 nchunks; /* number of allocated chunks */
|
||||
|
|
|
@ -103,18 +103,18 @@ jsbytecode *const JSStackFrame::sInvalidPC = (jsbytecode *)0xbeef;
|
|||
JSObject *
|
||||
js_GetScopeChain(JSContext *cx, JSStackFrame *fp)
|
||||
{
|
||||
JSObject *sharedBlock = fp->blockChain;
|
||||
JSObject *sharedBlock = fp->maybeBlockChain();
|
||||
|
||||
if (!sharedBlock) {
|
||||
/*
|
||||
* Don't force a call object for a lightweight function call, but do
|
||||
* insist that there is a call object for a heavyweight function call.
|
||||
*/
|
||||
JS_ASSERT(!fp->fun ||
|
||||
!(fp->fun->flags & JSFUN_HEAVYWEIGHT) ||
|
||||
JS_ASSERT(!fp->hasFunction() ||
|
||||
!(fp->getFunction()->flags & JSFUN_HEAVYWEIGHT) ||
|
||||
fp->hasCallObj());
|
||||
JS_ASSERT(fp->scopeChain);
|
||||
return fp->scopeChain;
|
||||
JS_ASSERT(fp->hasScopeChain());
|
||||
return fp->getScopeChain();
|
||||
}
|
||||
|
||||
/* We don't handle cloning blocks on trace. */
|
||||
|
@ -128,9 +128,9 @@ js_GetScopeChain(JSContext *cx, JSStackFrame *fp)
|
|||
* Also, identify the innermost compiler-allocated block we needn't clone.
|
||||
*/
|
||||
JSObject *limitBlock, *limitClone;
|
||||
if (fp->fun && !fp->hasCallObj()) {
|
||||
JS_ASSERT_IF(fp->scopeChain->getClass() == &js_BlockClass,
|
||||
fp->scopeChain->getPrivate() != js_FloatingFrameIfGenerator(cx, fp));
|
||||
if (fp->hasFunction() && !fp->hasCallObj()) {
|
||||
JS_ASSERT_IF(fp->getScopeChain()->getClass() == &js_BlockClass,
|
||||
fp->getScopeChain()->getPrivate() != js_FloatingFrameIfGenerator(cx, fp));
|
||||
if (!js_GetCallObject(cx, fp))
|
||||
return NULL;
|
||||
|
||||
|
@ -143,7 +143,7 @@ js_GetScopeChain(JSContext *cx, JSStackFrame *fp)
|
|||
* prototype should appear on blockChain; we'll clone blockChain up
|
||||
* to, but not including, that prototype.
|
||||
*/
|
||||
limitClone = fp->scopeChain;
|
||||
limitClone = fp->getScopeChain();
|
||||
while (limitClone->getClass() == &js_WithClass)
|
||||
limitClone = limitClone->getParent();
|
||||
JS_ASSERT(limitClone);
|
||||
|
@ -170,7 +170,7 @@ js_GetScopeChain(JSContext *cx, JSStackFrame *fp)
|
|||
|
||||
/* If the innermost block has already been cloned, we are done. */
|
||||
if (limitBlock == sharedBlock)
|
||||
return fp->scopeChain;
|
||||
return fp->getScopeChain();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -206,7 +206,7 @@ js_GetScopeChain(JSContext *cx, JSStackFrame *fp)
|
|||
newChild->setParent(clone);
|
||||
newChild = clone;
|
||||
}
|
||||
newChild->setParent(fp->scopeChain);
|
||||
newChild->setParent(fp->getScopeChain());
|
||||
|
||||
|
||||
/*
|
||||
|
@ -219,7 +219,7 @@ js_GetScopeChain(JSContext *cx, JSStackFrame *fp)
|
|||
sharedBlock);
|
||||
|
||||
/* Place our newly cloned blocks at the head of the scope chain. */
|
||||
fp->scopeChain = innermostNewChild;
|
||||
fp->setScopeChain(innermostNewChild);
|
||||
return innermostNewChild;
|
||||
}
|
||||
|
||||
|
@ -498,19 +498,23 @@ InvokeCommon(JSContext *cx, JSFunction *fun, JSScript *script, T native,
|
|||
SetValueRangeToUndefined(fp->slots(), nvars);
|
||||
|
||||
/* Initialize frame. */
|
||||
fp->thisv = args.thisv();
|
||||
fp->setThisValue(args.thisv());
|
||||
fp->setCallObj(NULL);
|
||||
fp->setArgsObj(NULL);
|
||||
fp->script = script;
|
||||
fp->fun = fun;
|
||||
fp->setScript(script);
|
||||
fp->setFunction(fun);
|
||||
fp->argc = args.argc();
|
||||
fp->argv = args.argv();
|
||||
fp->rval = (flags & JSINVOKE_CONSTRUCT) ? fp->thisv : UndefinedValue();
|
||||
fp->annotation = NULL;
|
||||
fp->scopeChain = NULL;
|
||||
fp->blockChain = NULL;
|
||||
fp->imacpc = NULL;
|
||||
fp->setAnnotation(NULL);
|
||||
fp->setScopeChain(NULL);
|
||||
fp->setBlockChain(NULL);
|
||||
fp->flags = flags;
|
||||
JS_ASSERT(!fp->hasIMacroPC());
|
||||
|
||||
if (flags & JSINVOKE_CONSTRUCT)
|
||||
fp->setReturnValue(fp->getThisValue());
|
||||
else
|
||||
fp->clearReturnValue();
|
||||
|
||||
/* Initialize regs. */
|
||||
JSFrameRegs ®s = frame.getRegs();
|
||||
|
@ -530,14 +534,14 @@ InvokeCommon(JSContext *cx, JSFunction *fun, JSScript *script, T native,
|
|||
if (native) {
|
||||
/* Slow natives and call ops expect the caller's scopeChain as their scopeChain. */
|
||||
if (JSStackFrame *down = fp->down)
|
||||
fp->scopeChain = down->scopeChain;
|
||||
fp->setScopeChain(down->maybeScopeChain());
|
||||
|
||||
/* Ensure that we have a scope chain. */
|
||||
if (!fp->scopeChain)
|
||||
fp->scopeChain = parent;
|
||||
if (!fp->hasScopeChain())
|
||||
fp->setScopeChain(parent);
|
||||
} else {
|
||||
/* Use parent scope so js_GetCallObject can find the right "Call". */
|
||||
fp->scopeChain = parent;
|
||||
fp->setScopeChain(parent);
|
||||
if (fun->isHeavyweight() && !js_GetCallObject(cx, fp))
|
||||
return false;
|
||||
}
|
||||
|
@ -557,8 +561,9 @@ InvokeCommon(JSContext *cx, JSFunction *fun, JSScript *script, T native,
|
|||
JSBool alreadyThrowing = cx->throwing;
|
||||
#endif
|
||||
|
||||
JSObject *thisp = fp->thisv.toObjectOrNull();
|
||||
ok = callJSNative(cx, native, thisp, fp->argc, fp->argv, &fp->rval);
|
||||
JSObject *thisp = fp->getThisValue().toObjectOrNull();
|
||||
ok = callJSNative(cx, native, thisp, fp->argc, fp->argv,
|
||||
fp->addressReturnValue());
|
||||
|
||||
JS_ASSERT(cx->fp == fp);
|
||||
JS_RUNTIME_METER(cx->runtime, nativeCalls);
|
||||
|
@ -572,7 +577,7 @@ InvokeCommon(JSContext *cx, JSFunction *fun, JSScript *script, T native,
|
|||
ok = Interpret(cx);
|
||||
}
|
||||
|
||||
DTrace::exitJSFun(cx, fp, fun, fp->rval);
|
||||
DTrace::exitJSFun(cx, fp, fun, fp->getReturnValue());
|
||||
|
||||
if (hookData) {
|
||||
hook = cx->debugHooks->callHook;
|
||||
|
@ -581,7 +586,7 @@ InvokeCommon(JSContext *cx, JSFunction *fun, JSScript *script, T native,
|
|||
}
|
||||
|
||||
fp->putActivationObjects(cx);
|
||||
args.rval() = fp->rval;
|
||||
args.rval() = fp->getReturnValue();
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
@ -604,7 +609,7 @@ DoSlowCall(JSContext *cx, uintN argc, Value *vp)
|
|||
JSObject *obj = fp->getThisObject(cx);
|
||||
if (!obj)
|
||||
return false;
|
||||
JS_ASSERT(ObjectValue(*obj) == fp->thisv);
|
||||
JS_ASSERT(ObjectValue(*obj) == fp->getThisValue());
|
||||
|
||||
JSObject *callee = &JS_CALLEE(cx, vp).toObject();
|
||||
Class *clasp = callee->getClass();
|
||||
|
@ -734,15 +739,7 @@ InternalInvoke(JSContext *cx, const Value &thisv, const Value &fval, uintN flags
|
|||
if (!Invoke(cx, args, flags))
|
||||
return JS_FALSE;
|
||||
|
||||
/*
|
||||
* Store *rval in the lastInternalResult pigeon-hole GC root, solely
|
||||
* so users of js_InternalInvoke and its direct and indirect
|
||||
* (js_ValueToString for example) callers do not need to manage roots
|
||||
* for local, temporary references to such results.
|
||||
*/
|
||||
*rval = args.rval();
|
||||
if (rval->isMarkable())
|
||||
cx->weakRoots.lastInternalResult = rval->asGCThing();
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
@ -796,11 +793,11 @@ Execute(JSContext *cx, JSObject *chain, JSScript *script,
|
|||
if (script->hasSharps) {
|
||||
JS_ASSERT(script->nfixed >= SHARP_NSLOTS);
|
||||
Value *sharps = &fp->slots()[script->nfixed - SHARP_NSLOTS];
|
||||
if (down && down->script && down->script->hasSharps) {
|
||||
JS_ASSERT(down->script->nfixed >= SHARP_NSLOTS);
|
||||
int base = (down->fun && !(down->flags & JSFRAME_SPECIAL))
|
||||
? down->fun->sharpSlotBase(cx)
|
||||
: down->script->nfixed - SHARP_NSLOTS;
|
||||
if (down && down->hasScript() && down->getScript()->hasSharps) {
|
||||
JS_ASSERT(down->getFixedCount() >= SHARP_NSLOTS);
|
||||
int base = (down->hasFunction() && !(down->flags & JSFRAME_SPECIAL))
|
||||
? down->getFunction()->sharpSlotBase(cx)
|
||||
: down->getFixedCount() - SHARP_NSLOTS;
|
||||
if (base < 0)
|
||||
return false;
|
||||
sharps[0] = down->slots()[base];
|
||||
|
@ -818,13 +815,13 @@ Execute(JSContext *cx, JSObject *chain, JSScript *script,
|
|||
/* Propagate arg state for eval and the debugger API. */
|
||||
fp->setCallObj(down->maybeCallObj());
|
||||
fp->setArgsObj(NULL);
|
||||
fp->fun = (script->staticLevel > 0) ? down->fun : NULL;
|
||||
fp->thisv = down->thisv;
|
||||
fp->setFunction((script->staticLevel > 0) ? down->maybeFunction() : NULL);
|
||||
fp->setThisValue(down->getThisValue());
|
||||
fp->flags = flags | (down->flags & JSFRAME_COMPUTED_THIS);
|
||||
fp->argc = down->argc;
|
||||
fp->argv = down->argv;
|
||||
fp->annotation = down->annotation;
|
||||
fp->scopeChain = chain;
|
||||
fp->setAnnotation(down->maybeAnnotation());
|
||||
fp->setScopeChain(chain);
|
||||
|
||||
/*
|
||||
* We want to call |down->varobj()|, but this requires knowing the
|
||||
|
@ -839,18 +836,18 @@ Execute(JSContext *cx, JSObject *chain, JSScript *script,
|
|||
} else {
|
||||
fp->setCallObj(NULL);
|
||||
fp->setArgsObj(NULL);
|
||||
fp->fun = NULL;
|
||||
fp->thisv.setUndefined(); /* Make GC-safe until initialized below. */
|
||||
fp->setFunction(NULL);
|
||||
fp->setThisValue(UndefinedValue()); /* Make GC-safe until initialized below. */
|
||||
fp->flags = flags | JSFRAME_COMPUTED_THIS;
|
||||
fp->argc = 0;
|
||||
fp->argv = NULL;
|
||||
fp->annotation = NULL;
|
||||
fp->setAnnotation(NULL);
|
||||
|
||||
JSObject *innerizedChain = chain;
|
||||
OBJ_TO_INNER_OBJECT(cx, innerizedChain);
|
||||
if (!innerizedChain)
|
||||
return false;
|
||||
fp->scopeChain = innerizedChain;
|
||||
fp->setScopeChain(innerizedChain);
|
||||
|
||||
initialVarObj = (cx->options & JSOPTION_VAROBJFIX)
|
||||
? chain->getGlobal()
|
||||
|
@ -858,10 +855,10 @@ Execute(JSContext *cx, JSObject *chain, JSScript *script,
|
|||
}
|
||||
JS_ASSERT(!initialVarObj->getOps()->defineProperty);
|
||||
|
||||
fp->script = script;
|
||||
fp->imacpc = NULL;
|
||||
fp->rval.setUndefined();
|
||||
fp->blockChain = NULL;
|
||||
JS_ASSERT(!fp->hasIMacroPC());
|
||||
fp->setScript(script);
|
||||
fp->clearReturnValue();
|
||||
fp->setBlockChain(NULL);
|
||||
|
||||
/* Initialize regs. */
|
||||
regs.pc = script->code;
|
||||
|
@ -875,7 +872,7 @@ Execute(JSContext *cx, JSObject *chain, JSScript *script,
|
|||
JSObject *thisp = chain->thisObject(cx);
|
||||
if (!thisp)
|
||||
return false;
|
||||
fp->thisv.setObject(*thisp);
|
||||
fp->setThisValue(ObjectValue(*thisp));
|
||||
}
|
||||
|
||||
void *hookData = NULL;
|
||||
|
@ -885,7 +882,7 @@ Execute(JSContext *cx, JSObject *chain, JSScript *script,
|
|||
AutoPreserveEnumerators preserve(cx);
|
||||
JSBool ok = Interpret(cx);
|
||||
if (result)
|
||||
*result = fp->rval;
|
||||
*result = fp->getReturnValue();
|
||||
|
||||
if (hookData) {
|
||||
if (JSInterpreterHook hook = cx->debugHooks->executeHook)
|
||||
|
@ -1245,7 +1242,7 @@ js_EnterWith(JSContext *cx, jsint stackIndex)
|
|||
if (!withobj)
|
||||
return JS_FALSE;
|
||||
|
||||
fp->scopeChain = withobj;
|
||||
fp->setScopeChain(withobj);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
|
@ -1254,11 +1251,11 @@ js_LeaveWith(JSContext *cx)
|
|||
{
|
||||
JSObject *withobj;
|
||||
|
||||
withobj = cx->fp->scopeChain;
|
||||
withobj = cx->fp->getScopeChain();
|
||||
JS_ASSERT(withobj->getClass() == &js_WithClass);
|
||||
JS_ASSERT(withobj->getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp));
|
||||
JS_ASSERT(OBJ_BLOCK_DEPTH(cx, withobj) >= 0);
|
||||
cx->fp->scopeChain = withobj->getParent();
|
||||
cx->fp->setScopeChain(withobj->getParent());
|
||||
withobj->setPrivate(NULL);
|
||||
}
|
||||
|
||||
|
@ -1290,15 +1287,15 @@ js_UnwindScope(JSContext *cx, jsint stackDepth, JSBool normalUnwind)
|
|||
JS_ASSERT(cx->fp->base() + stackDepth <= cx->regs->sp);
|
||||
|
||||
JSStackFrame *fp = cx->fp;
|
||||
for (obj = fp->blockChain; obj; obj = obj->getParent()) {
|
||||
for (obj = fp->maybeBlockChain(); obj; obj = obj->getParent()) {
|
||||
JS_ASSERT(obj->getClass() == &js_BlockClass);
|
||||
if (OBJ_BLOCK_DEPTH(cx, obj) < stackDepth)
|
||||
break;
|
||||
}
|
||||
fp->blockChain = obj;
|
||||
fp->setBlockChain(obj);
|
||||
|
||||
for (;;) {
|
||||
obj = fp->scopeChain;
|
||||
obj = fp->getScopeChain();
|
||||
clasp = js_IsActiveWithOrBlock(cx, obj, stackDepth);
|
||||
if (!clasp)
|
||||
break;
|
||||
|
@ -1347,16 +1344,16 @@ js::GetUpvar(JSContext *cx, uintN closureLevel, UpvarCookie cookie)
|
|||
uintN slot = cookie.slot();
|
||||
Value *vp;
|
||||
|
||||
if (!fp->fun || (fp->flags & JSFRAME_EVAL)) {
|
||||
vp = fp->slots() + fp->script->nfixed;
|
||||
} else if (slot < fp->fun->nargs) {
|
||||
if (!fp->hasFunction() || (fp->flags & JSFRAME_EVAL)) {
|
||||
vp = fp->slots() + fp->getFixedCount();
|
||||
} else if (slot < fp->getArgumentCount()) {
|
||||
vp = fp->argv;
|
||||
} else if (slot == UpvarCookie::CALLEE_SLOT) {
|
||||
vp = &fp->argv[-2];
|
||||
slot = 0;
|
||||
} else {
|
||||
slot -= fp->fun->nargs;
|
||||
JS_ASSERT(slot < fp->script->nslots);
|
||||
slot -= fp->getArgumentCount();
|
||||
JS_ASSERT(slot < fp->getSlotCount());
|
||||
vp = fp->slots();
|
||||
}
|
||||
|
||||
|
@ -1384,10 +1381,10 @@ js_TraceOpcode(JSContext *cx)
|
|||
* Operations in prologues don't produce interesting values, and
|
||||
* js_DecompileValueGenerator isn't set up to handle them anyway.
|
||||
*/
|
||||
if (cx->tracePrevPc && regs->pc >= fp->script->main) {
|
||||
if (cx->tracePrevPc && regs->pc >= fp->getScript()->main) {
|
||||
JSOp tracePrevOp = JSOp(*cx->tracePrevPc);
|
||||
ndefs = js_GetStackDefs(cx, &js_CodeSpec[tracePrevOp], tracePrevOp,
|
||||
fp->script, cx->tracePrevPc);
|
||||
fp->getScript(), cx->tracePrevPc);
|
||||
|
||||
/*
|
||||
* If there aren't that many elements on the stack, then we have
|
||||
|
@ -1424,9 +1421,10 @@ js_TraceOpcode(JSContext *cx)
|
|||
}
|
||||
|
||||
fprintf(tracefp, "%4u: ",
|
||||
js_PCToLineNumber(cx, fp->script, fp->imacpc ? fp->imacpc : regs->pc));
|
||||
js_Disassemble1(cx, fp->script, regs->pc,
|
||||
regs->pc - fp->script->code,
|
||||
js_PCToLineNumber(cx, fp->getScript(),
|
||||
fp->hasIMacroPC() ? fp->getIMacroPC() : regs->pc));
|
||||
js_Disassemble1(cx, fp->getScript(), regs->pc,
|
||||
regs->pc - fp->getScript()->code,
|
||||
JS_FALSE, tracefp);
|
||||
op = (JSOp) *regs->pc;
|
||||
nuses = js_GetStackUses(&js_CodeSpec[op], op, regs->pc);
|
||||
|
@ -1767,6 +1765,7 @@ namespace reprmeter {
|
|||
#define PUSH_OBJECT_OR_NULL(obj) regs.sp++->setObject(obj)
|
||||
#define PUSH_HOLE() regs.sp++->setMagic(JS_ARRAY_HOLE)
|
||||
#define POP_COPY_TO(v) v = *--regs.sp
|
||||
#define POP_RETURN_VALUE() fp->setReturnValue(*--regs.sp)
|
||||
|
||||
#define POP_BOOLEAN(cx, vp, b) \
|
||||
JS_BEGIN_MACRO \
|
||||
|
@ -2180,7 +2179,7 @@ Interpret(JSContext *cx)
|
|||
|
||||
/* Set registerized frame pointer and derived script pointer. */
|
||||
JSStackFrame *fp = cx->fp;
|
||||
JSScript *script = fp->script;
|
||||
JSScript *script = fp->getScript();
|
||||
JS_ASSERT(!script->isEmpty());
|
||||
JS_ASSERT(script->length > 1);
|
||||
|
||||
|
@ -2198,7 +2197,7 @@ Interpret(JSContext *cx)
|
|||
|
||||
#define LOAD_ATOM(PCOFF, atom) \
|
||||
JS_BEGIN_MACRO \
|
||||
JS_ASSERT(fp->imacpc \
|
||||
JS_ASSERT(fp->hasIMacroPC() \
|
||||
? atoms == COMMON_ATOMS_START(&rt->atomState) && \
|
||||
GET_INDEX(regs.pc + PCOFF) < js_common_atom_count \
|
||||
: (size_t)(atoms - script->atomMap.vector) < \
|
||||
|
@ -2241,7 +2240,7 @@ Interpret(JSContext *cx)
|
|||
#define RESTORE_INTERP_VARS() \
|
||||
JS_BEGIN_MACRO \
|
||||
fp = cx->fp; \
|
||||
script = fp->script; \
|
||||
script = fp->getScript(); \
|
||||
atoms = FrameAtomBase(cx, fp); \
|
||||
currentVersion = (JSVersion) script->version; \
|
||||
JS_ASSERT(cx->regs == ®s); \
|
||||
|
@ -2442,7 +2441,7 @@ Interpret(JSContext *cx)
|
|||
case JSTRAP_CONTINUE:
|
||||
break;
|
||||
case JSTRAP_RETURN:
|
||||
fp->rval = rval;
|
||||
fp->setReturnValue(rval);
|
||||
interpReturnOK = JS_TRUE;
|
||||
goto forced_return;
|
||||
case JSTRAP_THROW:
|
||||
|
@ -2525,11 +2524,11 @@ BEGIN_CASE(JSOP_POPN)
|
|||
regs.sp -= GET_UINT16(regs.pc);
|
||||
#ifdef DEBUG
|
||||
JS_ASSERT(fp->base() <= regs.sp);
|
||||
JSObject *obj = fp->blockChain;
|
||||
JSObject *obj = fp->maybeBlockChain();
|
||||
JS_ASSERT_IF(obj,
|
||||
OBJ_BLOCK_DEPTH(cx, obj) + OBJ_BLOCK_COUNT(cx, obj)
|
||||
<= (size_t) (regs.sp - fp->base()));
|
||||
for (obj = fp->scopeChain; obj; obj = obj->getParent()) {
|
||||
for (obj = fp->maybeScopeChain(); obj; obj = obj->getParent()) {
|
||||
Class *clasp = obj->getClass();
|
||||
if (clasp != &js_BlockClass && clasp != &js_WithClass)
|
||||
continue;
|
||||
|
@ -2548,7 +2547,7 @@ END_CASE(JSOP_POPN)
|
|||
BEGIN_CASE(JSOP_SETRVAL)
|
||||
BEGIN_CASE(JSOP_POPV)
|
||||
ASSERT_NOT_THROWING(cx);
|
||||
POP_COPY_TO(fp->rval);
|
||||
POP_RETURN_VALUE();
|
||||
END_CASE(JSOP_POPV)
|
||||
|
||||
BEGIN_CASE(JSOP_ENTERWITH)
|
||||
|
@ -2564,20 +2563,20 @@ BEGIN_CASE(JSOP_ENTERWITH)
|
|||
* We set sp[-1] to the current "with" object to help asserting the
|
||||
* enter/leave balance in [leavewith].
|
||||
*/
|
||||
regs.sp[-1].setObject(*fp->scopeChain);
|
||||
regs.sp[-1].setObject(*fp->getScopeChain());
|
||||
END_CASE(JSOP_ENTERWITH)
|
||||
|
||||
BEGIN_CASE(JSOP_LEAVEWITH)
|
||||
JS_ASSERT(®s.sp[-1].toObject() == fp->scopeChain);
|
||||
JS_ASSERT(®s.sp[-1].toObject() == fp->getScopeChain());
|
||||
regs.sp--;
|
||||
js_LeaveWith(cx);
|
||||
END_CASE(JSOP_LEAVEWITH)
|
||||
|
||||
BEGIN_CASE(JSOP_RETURN)
|
||||
POP_COPY_TO(fp->rval);
|
||||
POP_RETURN_VALUE();
|
||||
/* FALL THROUGH */
|
||||
|
||||
BEGIN_CASE(JSOP_RETRVAL) /* fp->rval already set */
|
||||
BEGIN_CASE(JSOP_RETRVAL) /* fp return value already set */
|
||||
BEGIN_CASE(JSOP_STOP)
|
||||
{
|
||||
/*
|
||||
|
@ -2587,35 +2586,35 @@ BEGIN_CASE(JSOP_STOP)
|
|||
ASSERT_NOT_THROWING(cx);
|
||||
CHECK_BRANCH();
|
||||
|
||||
if (fp->imacpc) {
|
||||
if (fp->hasIMacroPC()) {
|
||||
/*
|
||||
* If we are at the end of an imacro, return to its caller in the
|
||||
* current frame.
|
||||
*/
|
||||
JS_ASSERT(op == JSOP_STOP);
|
||||
JS_ASSERT((uintN)(regs.sp - fp->slots()) <= script->nslots);
|
||||
regs.pc = fp->imacpc + js_CodeSpec[*fp->imacpc].length;
|
||||
fp->imacpc = NULL;
|
||||
jsbytecode *imacpc = fp->getIMacroPC();
|
||||
regs.pc = imacpc + js_CodeSpec[*imacpc].length;
|
||||
fp->clearIMacroPC();
|
||||
atoms = script->atomMap.vector;
|
||||
op = JSOp(*regs.pc);
|
||||
DO_OP();
|
||||
}
|
||||
|
||||
JS_ASSERT(regs.sp == fp->base());
|
||||
if ((fp->flags & JSFRAME_CONSTRUCTING) && fp->rval.isPrimitive())
|
||||
fp->rval = fp->thisv;
|
||||
if ((fp->flags & JSFRAME_CONSTRUCTING) && fp->getReturnValue().isPrimitive())
|
||||
fp->setReturnValue(fp->getThisValue());
|
||||
|
||||
interpReturnOK = true;
|
||||
if (inlineCallCount)
|
||||
inline_return:
|
||||
{
|
||||
JS_ASSERT(!fp->blockChain);
|
||||
JS_ASSERT(!js_IsActiveWithOrBlock(cx, fp->scopeChain, 0));
|
||||
JS_ASSERT(!fp->hasBlockChain());
|
||||
JS_ASSERT(!js_IsActiveWithOrBlock(cx, fp->getScopeChain(), 0));
|
||||
|
||||
void *hookData = fp->hookData;
|
||||
if (JS_UNLIKELY(hookData != NULL)) {
|
||||
if (JS_UNLIKELY(fp->hasHookData())) {
|
||||
if (JSInterpreterHook hook = cx->debugHooks->callHook) {
|
||||
hook(cx, fp, JS_FALSE, &interpReturnOK, hookData);
|
||||
hook(cx, fp, JS_FALSE, &interpReturnOK, fp->getHookData());
|
||||
CHECK_INTERRUPT_HANDLER();
|
||||
}
|
||||
}
|
||||
|
@ -2628,11 +2627,11 @@ BEGIN_CASE(JSOP_STOP)
|
|||
*/
|
||||
fp->putActivationObjects(cx);
|
||||
|
||||
DTrace::exitJSFun(cx, fp, fp->fun, fp->rval);
|
||||
DTrace::exitJSFun(cx, fp, fp->getFunction(), fp->getReturnValue());
|
||||
|
||||
/* Restore context version only if callee hasn't set version. */
|
||||
if (JS_LIKELY(cx->version == currentVersion)) {
|
||||
currentVersion = fp->callerVersion;
|
||||
currentVersion = fp->getCallerVersion();
|
||||
if (currentVersion != cx->version)
|
||||
js_SetVersion(cx, currentVersion);
|
||||
}
|
||||
|
@ -2642,13 +2641,13 @@ BEGIN_CASE(JSOP_STOP)
|
|||
* passed in via |this|, and instrument this constructor invocation.
|
||||
*/
|
||||
if (fp->flags & JSFRAME_CONSTRUCTING) {
|
||||
if (fp->rval.isPrimitive())
|
||||
fp->rval = fp->thisv;
|
||||
if (fp->getReturnValue().isPrimitive())
|
||||
fp->setReturnValue(fp->getThisValue());
|
||||
JS_RUNTIME_METER(cx->runtime, constructs);
|
||||
}
|
||||
|
||||
JSStackFrame *down = fp->down;
|
||||
bool recursive = fp->script == down->script;
|
||||
bool recursive = fp->getScript() == down->getScript();
|
||||
Value *newsp = fp->argv - 1;
|
||||
|
||||
/* Pop the frame. */
|
||||
|
@ -2656,11 +2655,11 @@ BEGIN_CASE(JSOP_STOP)
|
|||
|
||||
/* Propagate return value before fp is lost. */
|
||||
regs.sp = newsp;
|
||||
regs.sp[-1] = fp->rval;
|
||||
regs.sp[-1] = fp->getReturnValue();
|
||||
|
||||
/* Sync interpreter registers. */
|
||||
fp = cx->fp;
|
||||
script = fp->script;
|
||||
script = fp->getScript();
|
||||
atoms = FrameAtomBase(cx, fp);
|
||||
|
||||
/* Resume execution in the calling frame. */
|
||||
|
@ -2910,7 +2909,7 @@ BEGIN_CASE(JSOP_FORARG)
|
|||
{
|
||||
JS_ASSERT(regs.sp - 1 >= fp->base());
|
||||
uintN slot = GET_ARGNO(regs.pc);
|
||||
JS_ASSERT(slot < fp->fun->nargs);
|
||||
JS_ASSERT(slot < fp->getArgumentCount());
|
||||
JS_ASSERT(regs.sp[-1].isObject());
|
||||
if (!IteratorNext(cx, ®s.sp[-1].toObject(), &fp->argv[slot]))
|
||||
goto error;
|
||||
|
@ -2921,7 +2920,7 @@ BEGIN_CASE(JSOP_FORLOCAL)
|
|||
{
|
||||
JS_ASSERT(regs.sp - 1 >= fp->base());
|
||||
uintN slot = GET_SLOTNO(regs.pc);
|
||||
JS_ASSERT(slot < fp->script->nslots);
|
||||
JS_ASSERT(slot < fp->getSlotCount());
|
||||
JS_ASSERT(regs.sp[-1].isObject());
|
||||
if (!IteratorNext(cx, ®s.sp[-1].toObject(), &fp->slots()[slot]))
|
||||
goto error;
|
||||
|
@ -3136,7 +3135,7 @@ BEGIN_CASE(JSOP_BINDNAME)
|
|||
* the rhs. We desire such resolve hook equivalence between the two
|
||||
* forms.
|
||||
*/
|
||||
obj = fp->scopeChain;
|
||||
obj = fp->getScopeChain();
|
||||
if (!obj->getParent())
|
||||
break;
|
||||
|
||||
|
@ -3150,7 +3149,7 @@ BEGIN_CASE(JSOP_BINDNAME)
|
|||
}
|
||||
|
||||
jsid id = ATOM_TO_JSID(atom);
|
||||
obj = js_FindIdentifierBase(cx, fp->scopeChain, id);
|
||||
obj = js_FindIdentifierBase(cx, fp->getScopeChain(), id);
|
||||
if (!obj)
|
||||
goto error;
|
||||
} while (0);
|
||||
|
@ -3159,8 +3158,8 @@ BEGIN_CASE(JSOP_BINDNAME)
|
|||
END_CASE(JSOP_BINDNAME)
|
||||
|
||||
BEGIN_CASE(JSOP_IMACOP)
|
||||
JS_ASSERT(JS_UPTRDIFF(fp->imacpc, script->code) < script->length);
|
||||
op = JSOp(*fp->imacpc);
|
||||
JS_ASSERT(JS_UPTRDIFF(fp->getIMacroPC(), script->code) < script->length);
|
||||
op = JSOp(*fp->getIMacroPC());
|
||||
DO_OP();
|
||||
|
||||
#define BITWISE_OP(OP) \
|
||||
|
@ -3705,7 +3704,7 @@ BEGIN_CASE(JSOP_DECNAME)
|
|||
BEGIN_CASE(JSOP_NAMEINC)
|
||||
BEGIN_CASE(JSOP_NAMEDEC)
|
||||
{
|
||||
obj = fp->scopeChain;
|
||||
obj = fp->getScopeChain();
|
||||
|
||||
JSObject *obj2;
|
||||
PropertyCacheEntry *entry;
|
||||
|
@ -3815,7 +3814,7 @@ BEGIN_CASE(JSOP_ARGINC)
|
|||
// If we initialize in the declaration, MSVC complains that the labels skip init.
|
||||
uint32 slot;
|
||||
slot = GET_ARGNO(regs.pc);
|
||||
JS_ASSERT(slot < fp->fun->nargs);
|
||||
JS_ASSERT(slot < fp->getArgumentCount());
|
||||
METER_SLOT_OP(op, slot);
|
||||
vp = fp->argv + slot;
|
||||
goto do_int_fast_incop;
|
||||
|
@ -3836,7 +3835,7 @@ BEGIN_CASE(JSOP_LOCALINC)
|
|||
*/
|
||||
do_local_incop:
|
||||
slot = GET_SLOTNO(regs.pc);
|
||||
JS_ASSERT(slot < fp->script->nslots);
|
||||
JS_ASSERT(slot < fp->getSlotCount());
|
||||
vp = fp->slots() + slot;
|
||||
METER_SLOT_OP(op, slot);
|
||||
vp = fp->slots() + slot;
|
||||
|
@ -3917,7 +3916,7 @@ BEGIN_CASE(JSOP_GVARINC)
|
|||
BEGIN_CASE(JSOP_THIS)
|
||||
if (!fp->getThisObject(cx))
|
||||
goto error;
|
||||
PUSH_COPY(fp->thisv);
|
||||
PUSH_COPY(fp->getThisValue());
|
||||
END_CASE(JSOP_THIS)
|
||||
|
||||
BEGIN_CASE(JSOP_UNBRANDTHIS)
|
||||
|
@ -3947,7 +3946,7 @@ BEGIN_CASE(JSOP_GETARGPROP)
|
|||
{
|
||||
i = ARGNO_LEN;
|
||||
uint32 slot = GET_ARGNO(regs.pc);
|
||||
JS_ASSERT(slot < fp->fun->nargs);
|
||||
JS_ASSERT(slot < fp->getArgumentCount());
|
||||
PUSH_COPY(fp->argv[slot]);
|
||||
goto do_getprop_body;
|
||||
}
|
||||
|
@ -3998,7 +3997,7 @@ BEGIN_CASE(JSOP_GETXPROP)
|
|||
JS_ASSERT(entry->vword.isSprop());
|
||||
JSScopeProperty *sprop = entry->vword.toSprop();
|
||||
NATIVE_GET(cx, obj, obj2, sprop,
|
||||
fp->imacpc ? JSGET_NO_METHOD_BARRIER : JSGET_METHOD_BARRIER,
|
||||
fp->hasIMacroPC() ? JSGET_NO_METHOD_BARRIER : JSGET_METHOD_BARRIER,
|
||||
&rval);
|
||||
}
|
||||
break;
|
||||
|
@ -4007,7 +4006,7 @@ BEGIN_CASE(JSOP_GETXPROP)
|
|||
jsid id = ATOM_TO_JSID(atom);
|
||||
if (JS_LIKELY(!aobj->getOps()->getProperty)
|
||||
? !js_GetPropertyHelper(cx, obj, id,
|
||||
(fp->imacpc ||
|
||||
(fp->hasIMacroPC() ||
|
||||
regs.pc[JSOP_GETPROP_LENGTH + i] == JSOP_IFEQ)
|
||||
? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER
|
||||
: JSGET_CACHE_RESULT | JSGET_METHOD_BARRIER,
|
||||
|
@ -4033,7 +4032,7 @@ BEGIN_CASE(JSOP_LENGTH)
|
|||
jsuint length = obj->getArrayLength();
|
||||
regs.sp[-1].setNumber(length);
|
||||
} else if (obj->isArguments() && !obj->isArgsLengthOverridden()) {
|
||||
uint32 length = obj->getArgsLength();
|
||||
uint32 length = obj->getArgsInitialLength();
|
||||
JS_ASSERT(length < INT32_MAX);
|
||||
regs.sp[-1].setInt32(int32_t(length));
|
||||
} else {
|
||||
|
@ -4401,7 +4400,7 @@ BEGIN_CASE(JSOP_GETELEM)
|
|||
} else if (obj->isArguments()) {
|
||||
uint32 arg = uint32(i);
|
||||
|
||||
if (arg < obj->getArgsLength()) {
|
||||
if (arg < obj->getArgsInitialLength()) {
|
||||
JSStackFrame *afp = (JSStackFrame *) obj->getPrivate();
|
||||
if (afp) {
|
||||
copyFrom = &afp->argv[arg];
|
||||
|
@ -4611,25 +4610,25 @@ BEGIN_CASE(JSOP_APPLY)
|
|||
/* Initialize stack frame. */
|
||||
newfp->setCallObj(NULL);
|
||||
newfp->setArgsObj(NULL);
|
||||
newfp->script = newscript;
|
||||
newfp->fun = fun;
|
||||
newfp->setScript(newscript);
|
||||
newfp->setFunction(fun);
|
||||
newfp->argc = argc;
|
||||
newfp->argv = vp + 2;
|
||||
newfp->rval.setUndefined();
|
||||
newfp->annotation = NULL;
|
||||
newfp->scopeChain = obj->getParent();
|
||||
newfp->clearReturnValue();
|
||||
newfp->setAnnotation(NULL);
|
||||
newfp->setScopeChain(obj->getParent());
|
||||
newfp->flags = flags;
|
||||
newfp->blockChain = NULL;
|
||||
newfp->setBlockChain(NULL);
|
||||
JS_ASSERT(!JSFUN_BOUND_METHOD_TEST(fun->flags));
|
||||
newfp->thisv = vp[1];
|
||||
newfp->imacpc = NULL;
|
||||
newfp->setThisValue(vp[1]);
|
||||
JS_ASSERT(!newfp->hasIMacroPC());
|
||||
|
||||
/* Push void to initialize local variables. */
|
||||
Value *newsp = newfp->base();
|
||||
SetValueRangeToUndefined(newfp->slots(), newsp);
|
||||
|
||||
/* Switch version if currentVersion wasn't overridden. */
|
||||
newfp->callerVersion = (JSVersion) cx->version;
|
||||
newfp->setCallerVersion((JSVersion) cx->version);
|
||||
if (JS_LIKELY(cx->version == currentVersion)) {
|
||||
currentVersion = (JSVersion) newscript->version;
|
||||
if (JS_UNLIKELY(currentVersion != cx->version))
|
||||
|
@ -4655,11 +4654,11 @@ BEGIN_CASE(JSOP_APPLY)
|
|||
|
||||
/* Call the debugger hook if present. */
|
||||
if (JSInterpreterHook hook = cx->debugHooks->callHook) {
|
||||
fp->hookData = hook(cx, fp, JS_TRUE, 0,
|
||||
cx->debugHooks->callHookData);
|
||||
fp->setHookData(hook(cx, fp, JS_TRUE, 0,
|
||||
cx->debugHooks->callHookData));
|
||||
CHECK_INTERRUPT_HANDLER();
|
||||
} else {
|
||||
fp->hookData = NULL;
|
||||
fp->setHookData(NULL);
|
||||
}
|
||||
|
||||
inlineCallCount++;
|
||||
|
@ -4679,7 +4678,7 @@ BEGIN_CASE(JSOP_APPLY)
|
|||
if (status == ARECORD_ERROR)
|
||||
goto error;
|
||||
}
|
||||
} else if (fp->script == fp->down->script &&
|
||||
} else if (fp->getScript() == fp->down->getScript() &&
|
||||
*fp->down->savedPC == JSOP_CALL &&
|
||||
*regs.pc == JSOP_TRACE) {
|
||||
MONITOR_BRANCH(Record_EnterFrame);
|
||||
|
@ -4734,7 +4733,7 @@ END_CASE(JSOP_SETCALL)
|
|||
BEGIN_CASE(JSOP_NAME)
|
||||
BEGIN_CASE(JSOP_CALLNAME)
|
||||
{
|
||||
JSObject *obj = fp->scopeChain;
|
||||
JSObject *obj = fp->getScopeChain();
|
||||
|
||||
JSScopeProperty *sprop;
|
||||
Value rval;
|
||||
|
@ -4837,7 +4836,7 @@ END_CASE(JSOP_RESETBASE)
|
|||
|
||||
BEGIN_CASE(JSOP_DOUBLE)
|
||||
{
|
||||
JS_ASSERT(!fp->imacpc);
|
||||
JS_ASSERT(!fp->hasIMacroPC());
|
||||
JS_ASSERT(size_t(atoms - script->atomMap.vector) <= script->atomMap.length);
|
||||
double dbl;
|
||||
LOAD_DOUBLE(0, dbl);
|
||||
|
@ -4874,7 +4873,7 @@ BEGIN_CASE(JSOP_REGEXP)
|
|||
*/
|
||||
jsatomid index = GET_FULL_INDEX(0);
|
||||
JSObject *proto;
|
||||
if (!js_GetClassPrototype(cx, fp->scopeChain, JSProto_RegExp, &proto))
|
||||
if (!js_GetClassPrototype(cx, fp->getScopeChain(), JSProto_RegExp, &proto))
|
||||
goto error;
|
||||
JS_ASSERT(proto);
|
||||
JSObject *obj = js_CloneRegExpObject(cx, script->getRegExp(index), proto);
|
||||
|
@ -4995,7 +4994,7 @@ BEGIN_CASE(JSOP_LOOKUPSWITCH)
|
|||
* JSOP_LOOKUPSWITCH and JSOP_LOOKUPSWITCHX are never used if any atom
|
||||
* index in it would exceed 64K limit.
|
||||
*/
|
||||
JS_ASSERT(!fp->imacpc);
|
||||
JS_ASSERT(!fp->hasIMacroPC());
|
||||
JS_ASSERT(atoms == script->atomMap.vector);
|
||||
jsbytecode *pc2 = regs.pc;
|
||||
|
||||
|
@ -5062,7 +5061,7 @@ BEGIN_CASE(JSOP_TRAP)
|
|||
case JSTRAP_ERROR:
|
||||
goto error;
|
||||
case JSTRAP_RETURN:
|
||||
fp->rval = rval;
|
||||
fp->setReturnValue(rval);
|
||||
interpReturnOK = JS_TRUE;
|
||||
goto forced_return;
|
||||
case JSTRAP_THROW:
|
||||
|
@ -5113,7 +5112,7 @@ BEGIN_CASE(JSOP_GETARG)
|
|||
BEGIN_CASE(JSOP_CALLARG)
|
||||
{
|
||||
uint32 slot = GET_ARGNO(regs.pc);
|
||||
JS_ASSERT(slot < fp->fun->nargs);
|
||||
JS_ASSERT(slot < fp->getArgumentCount());
|
||||
METER_SLOT_OP(op, slot);
|
||||
PUSH_COPY(fp->argv[slot]);
|
||||
if (op == JSOP_CALLARG)
|
||||
|
@ -5124,7 +5123,7 @@ END_CASE(JSOP_GETARG)
|
|||
BEGIN_CASE(JSOP_SETARG)
|
||||
{
|
||||
uint32 slot = GET_ARGNO(regs.pc);
|
||||
JS_ASSERT(slot < fp->fun->nargs);
|
||||
JS_ASSERT(slot < fp->getArgumentCount());
|
||||
METER_SLOT_OP(op, slot);
|
||||
fp->argv[slot] = regs.sp[-1];
|
||||
}
|
||||
|
@ -5174,7 +5173,7 @@ END_CASE(JSOP_GETUPVAR)
|
|||
BEGIN_CASE(JSOP_GETUPVAR_DBG)
|
||||
BEGIN_CASE(JSOP_CALLUPVAR_DBG)
|
||||
{
|
||||
JSFunction *fun = fp->fun;
|
||||
JSFunction *fun = fp->getFunction();
|
||||
JS_ASSERT(FUN_KIND(fun) == JSFUN_INTERPRETED);
|
||||
JS_ASSERT(fun->u.i.wrapper);
|
||||
|
||||
|
@ -5351,7 +5350,7 @@ BEGIN_CASE(JSOP_DEFVAR)
|
|||
* and has stub getter and setter, into a "fast global" accessed
|
||||
* by the JSOP_*GVAR opcodes.
|
||||
*/
|
||||
if (!fp->fun &&
|
||||
if (!fp->hasFunction() &&
|
||||
index < GlobalVarCount(fp) &&
|
||||
obj2 == obj &&
|
||||
obj->isNative()) {
|
||||
|
@ -5393,7 +5392,7 @@ BEGIN_CASE(JSOP_DEFFUN)
|
|||
* FIXME: bug 476950, although debugger users may also demand some kind
|
||||
* of scope link for debugger-assisted eval-in-frame.
|
||||
*/
|
||||
obj2 = fp->scopeChain;
|
||||
obj2 = fp->getScopeChain();
|
||||
} else {
|
||||
JS_ASSERT(!FUN_FLAT_CLOSURE(fun));
|
||||
|
||||
|
@ -5401,8 +5400,8 @@ BEGIN_CASE(JSOP_DEFFUN)
|
|||
* Inline js_GetScopeChain a bit to optimize for the case of a
|
||||
* top-level function.
|
||||
*/
|
||||
if (!fp->blockChain) {
|
||||
obj2 = fp->scopeChain;
|
||||
if (!fp->hasBlockChain()) {
|
||||
obj2 = fp->getScopeChain();
|
||||
} else {
|
||||
obj2 = js_GetScopeChain(cx, fp);
|
||||
if (!obj2)
|
||||
|
@ -5431,7 +5430,7 @@ BEGIN_CASE(JSOP_DEFFUN)
|
|||
* fp->scopeChain code below the parent->defineProperty call.
|
||||
*/
|
||||
MUST_FLOW_THROUGH("restore_scope");
|
||||
fp->scopeChain = obj;
|
||||
fp->setScopeChain(obj);
|
||||
|
||||
Value rval = ObjectValue(*obj);
|
||||
|
||||
|
@ -5501,7 +5500,7 @@ BEGIN_CASE(JSOP_DEFFUN)
|
|||
|
||||
restore_scope:
|
||||
/* Restore fp->scopeChain now that obj is defined in fp->callobj. */
|
||||
fp->scopeChain = obj2;
|
||||
fp->setScopeChain(obj2);
|
||||
if (!ok)
|
||||
goto error;
|
||||
}
|
||||
|
@ -5556,7 +5555,7 @@ BEGIN_CASE(JSOP_DEFLOCALFUN)
|
|||
JSObject *obj = FUN_OBJECT(fun);
|
||||
|
||||
if (FUN_NULL_CLOSURE(fun)) {
|
||||
obj = CloneFunctionObject(cx, fun, fp->scopeChain);
|
||||
obj = CloneFunctionObject(cx, fun, fp->getScopeChain());
|
||||
if (!obj)
|
||||
goto error;
|
||||
} else {
|
||||
|
@ -5623,7 +5622,7 @@ BEGIN_CASE(JSOP_LAMBDA)
|
|||
do {
|
||||
JSObject *parent;
|
||||
if (FUN_NULL_CLOSURE(fun)) {
|
||||
parent = fp->scopeChain;
|
||||
parent = fp->getScopeChain();
|
||||
|
||||
if (obj->getParent() == parent) {
|
||||
jsbytecode *pc2 = regs.pc + JSOP_LAMBDA_LENGTH;
|
||||
|
@ -5940,11 +5939,9 @@ END_CASE(JSOP_NEWINIT)
|
|||
|
||||
BEGIN_CASE(JSOP_ENDINIT)
|
||||
{
|
||||
/* Re-set the newborn root to the top of this object tree. */
|
||||
/* FIXME remove JSOP_ENDINIT bug 588522 */
|
||||
JS_ASSERT(regs.sp - fp->base() >= 1);
|
||||
const Value &lref = regs.sp[-1];
|
||||
JS_ASSERT(lref.isObject());
|
||||
cx->weakRoots.finalizableNewborns[FINALIZE_OBJECT] = &lref.toObject();
|
||||
JS_ASSERT(regs.sp[-1].isObject());
|
||||
}
|
||||
END_CASE(JSOP_ENDINIT)
|
||||
|
||||
|
@ -6021,9 +6018,7 @@ BEGIN_CASE(JSOP_INITMETHOD)
|
|||
LOAD_ATOM(0, atom);
|
||||
jsid id = ATOM_TO_JSID(atom);
|
||||
|
||||
/* Set the property named by obj[id] to rval. */
|
||||
if (!CheckRedeclaration(cx, obj, id, JSPROP_INITIALIZER, NULL, NULL))
|
||||
goto error;
|
||||
/* No need to check for duplicate property; the compiler already did. */
|
||||
|
||||
uintN defineHow = (op == JSOP_INITMETHOD)
|
||||
? JSDNP_CACHE_RESULT | JSDNP_SET_METHOD
|
||||
|
@ -6057,12 +6052,7 @@ BEGIN_CASE(JSOP_INITELEM)
|
|||
jsid id;
|
||||
FETCH_ELEMENT_ID(obj, -2, id);
|
||||
|
||||
/*
|
||||
* Check for property redeclaration strict warning (we may be in an object
|
||||
* initialiser, not an array initialiser).
|
||||
*/
|
||||
if (!CheckRedeclaration(cx, obj, id, JSPROP_INITIALIZER, NULL, NULL))
|
||||
goto error;
|
||||
/* No need to check for duplicate property; the compiler already did. */
|
||||
|
||||
/*
|
||||
* If rref is a hole, do not call JSObject::defineProperty. In this case,
|
||||
|
@ -6090,7 +6080,7 @@ END_CASE(JSOP_INITELEM)
|
|||
BEGIN_CASE(JSOP_DEFSHARP)
|
||||
{
|
||||
uint32 slot = GET_UINT16(regs.pc);
|
||||
JS_ASSERT(slot + 1 < fp->script->nfixed);
|
||||
JS_ASSERT(slot + 1 < fp->getFixedCount());
|
||||
const Value &lref = fp->slots()[slot];
|
||||
JSObject *obj;
|
||||
if (lref.isObject()) {
|
||||
|
@ -6120,7 +6110,7 @@ END_CASE(JSOP_DEFSHARP)
|
|||
BEGIN_CASE(JSOP_USESHARP)
|
||||
{
|
||||
uint32 slot = GET_UINT16(regs.pc);
|
||||
JS_ASSERT(slot + 1 < fp->script->nfixed);
|
||||
JS_ASSERT(slot + 1 < fp->getFixedCount());
|
||||
const Value &lref = fp->slots()[slot];
|
||||
jsint i = (jsint) GET_UINT16(regs.pc + UINT16_LEN);
|
||||
Value rval;
|
||||
|
@ -6147,7 +6137,7 @@ END_CASE(JSOP_USESHARP)
|
|||
BEGIN_CASE(JSOP_SHARPINIT)
|
||||
{
|
||||
uint32 slot = GET_UINT16(regs.pc);
|
||||
JS_ASSERT(slot + 1 < fp->script->nfixed);
|
||||
JS_ASSERT(slot + 1 < fp->getFixedCount());
|
||||
Value *vp = &fp->slots()[slot];
|
||||
Value rval = vp[1];
|
||||
|
||||
|
@ -6309,7 +6299,7 @@ BEGIN_CASE(JSOP_DEBUGGER)
|
|||
case JSTRAP_CONTINUE:
|
||||
break;
|
||||
case JSTRAP_RETURN:
|
||||
fp->rval = rval;
|
||||
fp->setReturnValue(rval);
|
||||
interpReturnOK = JS_TRUE;
|
||||
goto forced_return;
|
||||
case JSTRAP_THROW:
|
||||
|
@ -6625,7 +6615,7 @@ BEGIN_CASE(JSOP_ENTERBLOCK)
|
|||
regs.sp = vp;
|
||||
|
||||
#ifdef DEBUG
|
||||
JS_ASSERT(fp->blockChain == obj->getParent());
|
||||
JS_ASSERT(fp->maybeBlockChain() == obj->getParent());
|
||||
|
||||
/*
|
||||
* The young end of fp->scopeChain may omit blocks if we haven't closed
|
||||
|
@ -6634,7 +6624,7 @@ BEGIN_CASE(JSOP_ENTERBLOCK)
|
|||
* anything else we should have popped off fp->scopeChain when we left its
|
||||
* static scope.
|
||||
*/
|
||||
JSObject *obj2 = fp->scopeChain;
|
||||
JSObject *obj2 = fp->getScopeChain();
|
||||
Class *clasp;
|
||||
while ((clasp = obj2->getClass()) == &js_WithClass)
|
||||
obj2 = obj2->getParent();
|
||||
|
@ -6648,7 +6638,7 @@ BEGIN_CASE(JSOP_ENTERBLOCK)
|
|||
}
|
||||
#endif
|
||||
|
||||
fp->blockChain = obj;
|
||||
fp->setBlockChain(obj);
|
||||
}
|
||||
END_CASE(JSOP_ENTERBLOCK)
|
||||
|
||||
|
@ -6656,8 +6646,8 @@ BEGIN_CASE(JSOP_LEAVEBLOCKEXPR)
|
|||
BEGIN_CASE(JSOP_LEAVEBLOCK)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
JS_ASSERT(fp->blockChain->getClass() == &js_BlockClass);
|
||||
uintN blockDepth = OBJ_BLOCK_DEPTH(cx, fp->blockChain);
|
||||
JS_ASSERT(fp->getBlockChain()->getClass() == &js_BlockClass);
|
||||
uintN blockDepth = OBJ_BLOCK_DEPTH(cx, fp->getBlockChain());
|
||||
|
||||
JS_ASSERT(blockDepth <= StackDepth(script));
|
||||
#endif
|
||||
|
@ -6666,15 +6656,15 @@ BEGIN_CASE(JSOP_LEAVEBLOCK)
|
|||
* cloned onto fp->scopeChain, clear its private data, move its locals from
|
||||
* the stack into the clone, and pop it off the chain.
|
||||
*/
|
||||
JSObject *obj = fp->scopeChain;
|
||||
if (obj->getProto() == fp->blockChain) {
|
||||
JSObject *obj = fp->getScopeChain();
|
||||
if (obj->getProto() == fp->getBlockChain()) {
|
||||
JS_ASSERT(obj->getClass() == &js_BlockClass);
|
||||
if (!js_PutBlockObject(cx, JS_TRUE))
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Pop the block chain, too. */
|
||||
fp->blockChain = fp->blockChain->getParent();
|
||||
fp->setBlockChain(fp->getBlockChain()->getParent());
|
||||
|
||||
/* Move the result of the expression to the new topmost stack slot. */
|
||||
Value *vp = NULL; /* silence GCC warnings */
|
||||
|
@ -6699,7 +6689,7 @@ BEGIN_CASE(JSOP_GENERATOR)
|
|||
if (!obj)
|
||||
goto error;
|
||||
JS_ASSERT(!fp->hasCallObj() && !fp->hasArgsObj());
|
||||
fp->rval.setObject(*obj);
|
||||
fp->setReturnValue(ObjectValue(*obj));
|
||||
interpReturnOK = true;
|
||||
if (inlineCallCount != 0)
|
||||
goto inline_return;
|
||||
|
@ -6713,7 +6703,7 @@ BEGIN_CASE(JSOP_YIELD)
|
|||
JSDVG_SEARCH_STACK, fp->argv[-2], NULL);
|
||||
goto error;
|
||||
}
|
||||
fp->rval = regs.sp[-1];
|
||||
fp->setReturnValue(regs.sp[-1]);
|
||||
fp->flags |= JSFRAME_YIELDING;
|
||||
regs.pc += JSOP_YIELD_LENGTH;
|
||||
interpReturnOK = JS_TRUE;
|
||||
|
@ -6805,15 +6795,16 @@ END_CASE(JSOP_ARRAYPUSH)
|
|||
error:
|
||||
JS_ASSERT(cx->regs == ®s);
|
||||
#ifdef JS_TRACER
|
||||
if (fp->imacpc && cx->throwing) {
|
||||
if (fp->hasIMacroPC() && cx->throwing) {
|
||||
// Handle other exceptions as if they came from the imacro-calling pc.
|
||||
regs.pc = fp->imacpc;
|
||||
fp->imacpc = NULL;
|
||||
regs.pc = fp->getIMacroPC();
|
||||
fp->clearIMacroPC();
|
||||
atoms = script->atomMap.vector;
|
||||
}
|
||||
#endif
|
||||
|
||||
JS_ASSERT((size_t)((fp->imacpc ? fp->imacpc : regs.pc) - script->code) < script->length);
|
||||
JS_ASSERT(size_t((fp->hasIMacroPC() ? fp->getIMacroPC() : regs.pc) - script->code) <
|
||||
script->length);
|
||||
|
||||
#ifdef JS_TRACER
|
||||
/*
|
||||
|
@ -6844,7 +6835,7 @@ END_CASE(JSOP_ARRAYPUSH)
|
|||
goto error;
|
||||
case JSTRAP_RETURN:
|
||||
cx->throwing = JS_FALSE;
|
||||
fp->rval = rval;
|
||||
fp->setReturnValue(rval);
|
||||
interpReturnOK = JS_TRUE;
|
||||
goto forced_return;
|
||||
case JSTRAP_THROW:
|
||||
|
@ -6909,7 +6900,7 @@ END_CASE(JSOP_ARRAYPUSH)
|
|||
|
||||
switch (tn->kind) {
|
||||
case JSTRY_CATCH:
|
||||
JS_ASSERT(js_GetOpcode(cx, fp->script, regs.pc) == JSOP_ENTERBLOCK);
|
||||
JS_ASSERT(js_GetOpcode(cx, fp->getScript(), regs.pc) == JSOP_ENTERBLOCK);
|
||||
|
||||
#if JS_HAS_GENERATORS
|
||||
/* Catch cannot intercept the closing of a generator. */
|
||||
|
@ -6938,7 +6929,7 @@ END_CASE(JSOP_ARRAYPUSH)
|
|||
|
||||
case JSTRY_ITER: {
|
||||
/* This is similar to JSOP_ENDITER in the interpreter loop. */
|
||||
JS_ASSERT(js_GetOpcode(cx, fp->script, regs.pc) == JSOP_ENDITER);
|
||||
JS_ASSERT(js_GetOpcode(cx, fp->getScript(), regs.pc) == JSOP_ENDITER);
|
||||
AutoValueRooter tvr(cx, cx->exception);
|
||||
cx->throwing = false;
|
||||
ok = js_CloseIterator(cx, ®s.sp[-1].toObject());
|
||||
|
@ -6962,7 +6953,7 @@ END_CASE(JSOP_ARRAYPUSH)
|
|||
cx->exception.isMagic(JS_GENERATOR_CLOSING))) {
|
||||
cx->throwing = JS_FALSE;
|
||||
interpReturnOK = JS_TRUE;
|
||||
fp->rval.setUndefined();
|
||||
fp->clearReturnValue();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -7007,8 +6998,8 @@ END_CASE(JSOP_ARRAYPUSH)
|
|||
AbortRecording(cx, "recording out of Interpret");
|
||||
#endif
|
||||
|
||||
JS_ASSERT_IF(!fp->isGenerator(), !fp->blockChain);
|
||||
JS_ASSERT_IF(!fp->isGenerator(), !js_IsActiveWithOrBlock(cx, fp->scopeChain, 0));
|
||||
JS_ASSERT_IF(!fp->isGenerator(), !fp->hasBlockChain());
|
||||
JS_ASSERT_IF(!fp->isGenerator(), !js_IsActiveWithOrBlock(cx, fp->getScopeChain(), 0));
|
||||
|
||||
/* Undo the remaining effects committed on entry to Interpret. */
|
||||
if (cx->version == currentVersion && currentVersion != originalVersion)
|
||||
|
|
|
@ -69,6 +69,7 @@ enum JSFrameFlags {
|
|||
JSFRAME_GENERATOR = 0x80, /* frame belongs to generator-iterator */
|
||||
JSFRAME_OVERRIDE_ARGS = 0x100, /* overridden arguments local variable */
|
||||
JSFRAME_DUMMY = 0x200, /* frame is a dummy frame */
|
||||
JSFRAME_IN_IMACRO = 0x400, /* frame has imacpc value available */
|
||||
|
||||
JSFRAME_SPECIAL = JSFRAME_DEBUGGER | JSFRAME_EVAL
|
||||
};
|
||||
|
@ -86,16 +87,20 @@ struct JSStackFrame
|
|||
private:
|
||||
JSObject *callobj; /* lazily created Call object */
|
||||
JSObject *argsobj; /* lazily created arguments object */
|
||||
JSObject *scopeChain; /* current scope chain */
|
||||
JSObject *blockChain; /* current static block */
|
||||
jsbytecode *imacpc; /* null or interpreter macro call pc */
|
||||
void *annotation; /* used by Java security */
|
||||
void *hookData; /* debugger call hook data */
|
||||
JSVersion callerVersion; /* dynamic version of calling script */
|
||||
JSScript *script; /* script being interpreted */
|
||||
JSFunction *fun; /* function being called or null */
|
||||
js::Value thisv; /* "this" pointer if in method */
|
||||
js::Value rval; /* function return value */
|
||||
|
||||
public:
|
||||
jsbytecode *imacpc; /* null or interpreter macro call pc */
|
||||
JSScript *script; /* script being interpreted */
|
||||
js::Value thisv; /* "this" pointer if in method */
|
||||
JSFunction *fun; /* function being called or null */
|
||||
uintN argc; /* actual argument count */
|
||||
js::Value *argv; /* base of argument stack slots */
|
||||
void *annotation; /* used by Java security */
|
||||
js::Value rval; /* function return value */
|
||||
|
||||
/* Maintained by StackSpace operations */
|
||||
JSStackFrame *down; /* previous frame, part of
|
||||
|
@ -105,52 +110,9 @@ struct JSStackFrame
|
|||
static jsbytecode *const sInvalidPC;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We can't determine in advance which local variables can live on
|
||||
* the stack and be freed when their dynamic scope ends, and which
|
||||
* will be closed over and need to live in the heap. So we place
|
||||
* variables on the stack initially, note when they are closed
|
||||
* over, and copy those that are out to the heap when we leave
|
||||
* their dynamic scope.
|
||||
*
|
||||
* The bytecode compiler produces a tree of block objects
|
||||
* accompanying each JSScript representing those lexical blocks in
|
||||
* the script that have let-bound variables associated with them.
|
||||
* These block objects are never modified, and never become part
|
||||
* of any function's scope chain. Their parent slots point to the
|
||||
* innermost block that encloses them, or are NULL in the
|
||||
* outermost blocks within a function or in eval or global code.
|
||||
*
|
||||
* When we are in the static scope of such a block, blockChain
|
||||
* points to its compiler-allocated block object; otherwise, it is
|
||||
* NULL.
|
||||
*
|
||||
* scopeChain is the current scope chain, including 'call' and
|
||||
* 'block' objects for those function calls and lexical blocks
|
||||
* whose static scope we are currently executing in, and 'with'
|
||||
* objects for with statements; the chain is typically terminated
|
||||
* by a global object. However, as an optimization, the young end
|
||||
* of the chain omits block objects we have not yet cloned. To
|
||||
* create a closure, we clone the missing blocks from blockChain
|
||||
* (which is always current), place them at the head of
|
||||
* scopeChain, and use that for the closure's scope chain. If we
|
||||
* never close over a lexical block, we never place a mutable
|
||||
* clone of it on scopeChain.
|
||||
*
|
||||
* This lazy cloning is implemented in js_GetScopeChain, which is
|
||||
* also used in some other cases --- entering 'with' blocks, for
|
||||
* example.
|
||||
*/
|
||||
JSObject *scopeChain;
|
||||
JSObject *blockChain;
|
||||
uint32 flags; /* frame flags -- see below */
|
||||
|
||||
uint32 flags; /* frame flags -- see below */
|
||||
|
||||
/* Members only needed for inline calls. */
|
||||
void *hookData; /* debugger call hook data */
|
||||
JSVersion callerVersion; /* dynamic version of calling script */
|
||||
|
||||
void *padding;
|
||||
void *padding;
|
||||
|
||||
/* Get the frame's current bytecode, assuming |this| is in |cx|. */
|
||||
jsbytecode *pc(JSContext *cx) const;
|
||||
|
@ -164,7 +126,7 @@ struct JSStackFrame
|
|||
}
|
||||
|
||||
js::Value *base() const {
|
||||
return slots() + script->nfixed;
|
||||
return slots() + getScript()->nfixed;
|
||||
}
|
||||
|
||||
/* Call object accessors */
|
||||
|
@ -217,6 +179,250 @@ struct JSStackFrame
|
|||
return offsetof(JSStackFrame, argsobj);
|
||||
}
|
||||
|
||||
/*
|
||||
* We can't determine in advance which local variables can live on
|
||||
* the stack and be freed when their dynamic scope ends, and which
|
||||
* will be closed over and need to live in the heap. So we place
|
||||
* variables on the stack initially, note when they are closed
|
||||
* over, and copy those that are out to the heap when we leave
|
||||
* their dynamic scope.
|
||||
*
|
||||
* The bytecode compiler produces a tree of block objects
|
||||
* accompanying each JSScript representing those lexical blocks in
|
||||
* the script that have let-bound variables associated with them.
|
||||
* These block objects are never modified, and never become part
|
||||
* of any function's scope chain. Their parent slots point to the
|
||||
* innermost block that encloses them, or are NULL in the
|
||||
* outermost blocks within a function or in eval or global code.
|
||||
*
|
||||
* When we are in the static scope of such a block, blockChain
|
||||
* points to its compiler-allocated block object; otherwise, it is
|
||||
* NULL.
|
||||
*
|
||||
* scopeChain is the current scope chain, including 'call' and
|
||||
* 'block' objects for those function calls and lexical blocks
|
||||
* whose static scope we are currently executing in, and 'with'
|
||||
* objects for with statements; the chain is typically terminated
|
||||
* by a global object. However, as an optimization, the young end
|
||||
* of the chain omits block objects we have not yet cloned. To
|
||||
* create a closure, we clone the missing blocks from blockChain
|
||||
* (which is always current), place them at the head of
|
||||
* scopeChain, and use that for the closure's scope chain. If we
|
||||
* never close over a lexical block, we never place a mutable
|
||||
* clone of it on scopeChain.
|
||||
*
|
||||
* This lazy cloning is implemented in js_GetScopeChain, which is
|
||||
* also used in some other cases --- entering 'with' blocks, for
|
||||
* example.
|
||||
*/
|
||||
|
||||
/* Scope chain accessors */
|
||||
|
||||
bool hasScopeChain() const {
|
||||
return scopeChain != NULL;
|
||||
}
|
||||
|
||||
JSObject* getScopeChain() const {
|
||||
JS_ASSERT(hasScopeChain());
|
||||
return scopeChain;
|
||||
}
|
||||
|
||||
JSObject* maybeScopeChain() const {
|
||||
return scopeChain;
|
||||
}
|
||||
|
||||
void setScopeChain(JSObject *obj) {
|
||||
scopeChain = obj;
|
||||
}
|
||||
|
||||
JSObject** addressScopeChain() {
|
||||
return &scopeChain;
|
||||
}
|
||||
|
||||
static size_t offsetScopeChain() {
|
||||
return offsetof(JSStackFrame, scopeChain);
|
||||
}
|
||||
|
||||
/* Block chain accessors */
|
||||
|
||||
bool hasBlockChain() const {
|
||||
return blockChain != NULL;
|
||||
}
|
||||
|
||||
JSObject* getBlockChain() const {
|
||||
JS_ASSERT(hasBlockChain());
|
||||
return blockChain;
|
||||
}
|
||||
|
||||
JSObject* maybeBlockChain() const {
|
||||
return blockChain;
|
||||
}
|
||||
|
||||
void setBlockChain(JSObject *obj) {
|
||||
blockChain = obj;
|
||||
}
|
||||
|
||||
/* IMacroPC accessors. */
|
||||
|
||||
bool hasIMacroPC() const { return flags & JSFRAME_IN_IMACRO; }
|
||||
|
||||
/*
|
||||
* @pre hasIMacroPC
|
||||
* @return The PC at which an imacro started executing (guaranteed non-null. The PC of the
|
||||
* executing imacro must be in regs.pc, so the displaced
|
||||
* original value is stored here.
|
||||
*/
|
||||
jsbytecode *getIMacroPC() const {
|
||||
JS_ASSERT(flags & JSFRAME_IN_IMACRO);
|
||||
return imacpc;
|
||||
}
|
||||
|
||||
/* @return The imacro pc if hasIMacroPC; otherwise, NULL. */
|
||||
jsbytecode *maybeIMacroPC() const { return hasIMacroPC() ? getIMacroPC() : NULL; }
|
||||
|
||||
void clearIMacroPC() { flags &= ~JSFRAME_IN_IMACRO; }
|
||||
|
||||
void setIMacroPC(jsbytecode *newIMacPC) {
|
||||
JS_ASSERT(newIMacPC);
|
||||
JS_ASSERT(!(flags & JSFRAME_IN_IMACRO));
|
||||
imacpc = newIMacPC;
|
||||
flags |= JSFRAME_IN_IMACRO;
|
||||
}
|
||||
|
||||
/* Annotation accessors */
|
||||
|
||||
bool hasAnnotation() const {
|
||||
return annotation != NULL;
|
||||
}
|
||||
|
||||
void* getAnnotation() const {
|
||||
JS_ASSERT(hasAnnotation());
|
||||
return annotation;
|
||||
}
|
||||
|
||||
void* maybeAnnotation() const {
|
||||
return annotation;
|
||||
}
|
||||
|
||||
void setAnnotation(void *annot) {
|
||||
annotation = annot;
|
||||
}
|
||||
|
||||
/* Debugger hook data accessors */
|
||||
|
||||
bool hasHookData() const {
|
||||
return hookData != NULL;
|
||||
}
|
||||
|
||||
void* getHookData() const {
|
||||
JS_ASSERT(hasHookData());
|
||||
return hookData;
|
||||
}
|
||||
|
||||
void* maybeHookData() const {
|
||||
return hookData;
|
||||
}
|
||||
|
||||
void setHookData(void *data) {
|
||||
hookData = data;
|
||||
}
|
||||
|
||||
/* Version accessors */
|
||||
|
||||
JSVersion getCallerVersion() const {
|
||||
return callerVersion;
|
||||
}
|
||||
|
||||
void setCallerVersion(JSVersion version) {
|
||||
callerVersion = version;
|
||||
}
|
||||
|
||||
/* Script accessors */
|
||||
|
||||
bool hasScript() const {
|
||||
return script != NULL;
|
||||
}
|
||||
|
||||
JSScript* getScript() const {
|
||||
JS_ASSERT(hasScript());
|
||||
return script;
|
||||
}
|
||||
|
||||
JSScript* maybeScript() const {
|
||||
return script;
|
||||
}
|
||||
|
||||
size_t getFixedCount() const {
|
||||
return getScript()->nfixed;
|
||||
}
|
||||
|
||||
size_t getSlotCount() const {
|
||||
return getScript()->nslots;
|
||||
}
|
||||
|
||||
void setScript(JSScript *s) {
|
||||
script = s;
|
||||
}
|
||||
|
||||
static size_t offsetScript() {
|
||||
return offsetof(JSStackFrame, script);
|
||||
}
|
||||
|
||||
/* Function accessors */
|
||||
|
||||
bool hasFunction() const {
|
||||
return fun != NULL;
|
||||
}
|
||||
|
||||
JSFunction* getFunction() const {
|
||||
JS_ASSERT(hasFunction());
|
||||
return fun;
|
||||
}
|
||||
|
||||
JSFunction* maybeFunction() const {
|
||||
return fun;
|
||||
}
|
||||
|
||||
size_t getArgumentCount() const {
|
||||
return getFunction()->nargs;
|
||||
}
|
||||
|
||||
void setFunction(JSFunction *f) {
|
||||
fun = f;
|
||||
}
|
||||
|
||||
/* This-value accessors */
|
||||
|
||||
const js::Value& getThisValue() {
|
||||
return thisv;
|
||||
}
|
||||
|
||||
void setThisValue(const js::Value &v) {
|
||||
thisv = v;
|
||||
}
|
||||
|
||||
/* Return-value accessors */
|
||||
|
||||
const js::Value& getReturnValue() {
|
||||
return rval;
|
||||
}
|
||||
|
||||
void setReturnValue(const js::Value &v) {
|
||||
rval = v;
|
||||
}
|
||||
|
||||
void clearReturnValue() {
|
||||
rval.setUndefined();
|
||||
}
|
||||
|
||||
js::Value* addressReturnValue() {
|
||||
return &rval;
|
||||
}
|
||||
|
||||
static size_t offsetReturnValue() {
|
||||
return offsetof(JSStackFrame, rval);
|
||||
}
|
||||
|
||||
/* Other accessors */
|
||||
|
||||
void putActivationObjects(JSContext *cx) {
|
||||
|
@ -279,6 +485,9 @@ struct JSStackFrame
|
|||
}
|
||||
|
||||
bool isDummyFrame() const { return !!(flags & JSFRAME_DUMMY); }
|
||||
|
||||
/* Contains static assertions for member alignment, don't call. */
|
||||
inline void staticAsserts();
|
||||
};
|
||||
|
||||
namespace js {
|
||||
|
@ -286,16 +495,20 @@ namespace js {
|
|||
JS_STATIC_ASSERT(sizeof(JSStackFrame) % sizeof(Value) == 0);
|
||||
static const size_t VALUES_PER_STACK_FRAME = sizeof(JSStackFrame) / sizeof(Value);
|
||||
|
||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, rval) % sizeof(Value) == 0);
|
||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, thisv) % sizeof(Value) == 0);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
inline void
|
||||
JSStackFrame::staticAsserts()
|
||||
{
|
||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, rval) % sizeof(js::Value) == 0);
|
||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, thisv) % sizeof(js::Value) == 0);
|
||||
}
|
||||
|
||||
static JS_INLINE uintN
|
||||
GlobalVarCount(JSStackFrame *fp)
|
||||
{
|
||||
JS_ASSERT(!fp->fun);
|
||||
return fp->script->nfixed;
|
||||
JS_ASSERT(!fp->hasFunction());
|
||||
return fp->getScript()->nfixed;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -571,7 +784,7 @@ JSStackFrame::getThisObject(JSContext *cx)
|
|||
return &thisv.toObject();
|
||||
if (!js::ComputeThisFromArgv(cx, argv))
|
||||
return NULL;
|
||||
thisv = argv[-1];
|
||||
setThisValue(argv[-1]);
|
||||
flags |= JSFRAME_COMPUTED_THIS;
|
||||
return &thisv.toObject();
|
||||
}
|
||||
|
|
|
@ -1096,7 +1096,7 @@ js_NewGenerator(JSContext *cx)
|
|||
/* Load and compute stack slot counts. */
|
||||
JSStackFrame *fp = cx->fp;
|
||||
uintN argc = fp->argc;
|
||||
uintN nargs = JS_MAX(argc, fp->fun->nargs);
|
||||
uintN nargs = JS_MAX(argc, fp->getArgumentCount());
|
||||
uintN vplen = 2 + nargs;
|
||||
|
||||
/* Compute JSGenerator size. */
|
||||
|
@ -1104,7 +1104,7 @@ js_NewGenerator(JSContext *cx)
|
|||
(-1 + /* one Value included in JSGenerator */
|
||||
vplen +
|
||||
VALUES_PER_STACK_FRAME +
|
||||
fp->script->nslots) * sizeof(Value);
|
||||
fp->getSlotCount()) * sizeof(Value);
|
||||
|
||||
JSGenerator *gen = (JSGenerator *) cx->malloc(nbytes);
|
||||
if (!gen)
|
||||
|
@ -1119,14 +1119,13 @@ js_NewGenerator(JSContext *cx)
|
|||
gen->obj = obj;
|
||||
gen->state = JSGEN_NEWBORN;
|
||||
gen->savedRegs.pc = cx->regs->pc;
|
||||
JS_ASSERT(cx->regs->sp == fp->slots() + fp->script->nfixed);
|
||||
gen->savedRegs.sp = slots + fp->script->nfixed;
|
||||
JS_ASSERT(cx->regs->sp == fp->slots() + fp->getFixedCount());
|
||||
gen->savedRegs.sp = slots + fp->getFixedCount();
|
||||
gen->vplen = vplen;
|
||||
gen->enumerators = NULL;
|
||||
gen->liveFrame = newfp;
|
||||
|
||||
/* Copy generator's stack frame copy in from |cx->fp|. */
|
||||
newfp->imacpc = NULL;
|
||||
newfp->setCallObj(fp->maybeCallObj());
|
||||
if (fp->hasCallObj()) { /* Steal call object. */
|
||||
fp->getCallObj()->setPrivate(newfp);
|
||||
|
@ -1137,21 +1136,22 @@ js_NewGenerator(JSContext *cx)
|
|||
fp->getArgsObj()->setPrivate(newfp);
|
||||
fp->setArgsObj(NULL);
|
||||
}
|
||||
newfp->script = fp->script;
|
||||
newfp->fun = fp->fun;
|
||||
newfp->thisv = fp->thisv;
|
||||
newfp->setScript(fp->getScript());
|
||||
newfp->setFunction(fp->getFunction());
|
||||
newfp->setThisValue(fp->getThisValue());
|
||||
newfp->argc = fp->argc;
|
||||
newfp->argv = vp + 2;
|
||||
newfp->rval = fp->rval;
|
||||
newfp->annotation = NULL;
|
||||
newfp->scopeChain = fp->scopeChain;
|
||||
JS_ASSERT(!fp->blockChain);
|
||||
newfp->blockChain = NULL;
|
||||
newfp->setReturnValue(fp->getReturnValue());
|
||||
newfp->setAnnotation(NULL);
|
||||
newfp->setScopeChain(fp->maybeScopeChain());
|
||||
JS_ASSERT(!fp->hasBlockChain());
|
||||
newfp->setBlockChain(NULL);
|
||||
newfp->flags = fp->flags | JSFRAME_GENERATOR | JSFRAME_FLOATING_GENERATOR;
|
||||
JS_ASSERT(!newfp->hasIMacroPC());
|
||||
|
||||
/* Copy in arguments and slots. */
|
||||
memcpy(vp, fp->argv - 2, vplen * sizeof(Value));
|
||||
memcpy(slots, fp->slots(), fp->script->nfixed * sizeof(Value));
|
||||
memcpy(slots, fp->slots(), fp->getFixedCount() * sizeof(Value));
|
||||
|
||||
obj->setPrivate(gen);
|
||||
return obj;
|
||||
|
@ -1184,7 +1184,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
|
|||
if (gen->state == JSGEN_RUNNING || gen->state == JSGEN_CLOSING) {
|
||||
js_ReportValueError(cx, JSMSG_NESTING_GENERATOR,
|
||||
JSDVG_SEARCH_STACK, ObjectOrNullValue(obj),
|
||||
JS_GetFunctionId(gen->getFloatingFrame()->fun));
|
||||
JS_GetFunctionId(gen->getFloatingFrame()->getFunction()));
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
|
@ -1223,7 +1223,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
|
|||
{
|
||||
Value *genVp = gen->floatingStack;
|
||||
uintN vplen = gen->vplen;
|
||||
uintN nfixed = genfp->script->nslots;
|
||||
uintN nfixed = genfp->getSlotCount();
|
||||
|
||||
/*
|
||||
* Get a pointer to new frame/slots. This memory is not "claimed", so
|
||||
|
@ -1247,7 +1247,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
|
|||
fp->flags &= ~JSFRAME_FLOATING_GENERATOR;
|
||||
fp->argv = vp + 2;
|
||||
gen->savedRegs.sp = fp->slots() + (gen->savedRegs.sp - genfp->slots());
|
||||
JS_ASSERT(uintN(gen->savedRegs.sp - fp->slots()) <= fp->script->nslots);
|
||||
JS_ASSERT(uintN(gen->savedRegs.sp - fp->slots()) <= fp->getSlotCount());
|
||||
|
||||
#ifdef DEBUG
|
||||
JSObject *callobjBefore = fp->maybeCallObj();
|
||||
|
@ -1292,13 +1292,13 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
|
|||
JS_ASSERT_IF(callobjBefore, callobjBefore == fp->maybeCallObj());
|
||||
|
||||
/* Copy and rebase stack frame/args/slots. Restore "floating" flag. */
|
||||
JS_ASSERT(uintN(gen->savedRegs.sp - fp->slots()) <= fp->script->nslots);
|
||||
JS_ASSERT(uintN(gen->savedRegs.sp - fp->slots()) <= fp->getSlotCount());
|
||||
uintN usedAfter = gen->savedRegs.sp - vp;
|
||||
memcpy(genVp, vp, usedAfter * sizeof(Value));
|
||||
genfp->flags |= JSFRAME_FLOATING_GENERATOR;
|
||||
genfp->argv = genVp + 2;
|
||||
gen->savedRegs.sp = genfp->slots() + (gen->savedRegs.sp - fp->slots());
|
||||
JS_ASSERT(uintN(gen->savedRegs.sp - genfp->slots()) <= genfp->script->nslots);
|
||||
JS_ASSERT(uintN(gen->savedRegs.sp - genfp->slots()) <= genfp->getSlotCount());
|
||||
}
|
||||
|
||||
if (gen->getFloatingFrame()->flags & JSFRAME_YIELDING) {
|
||||
|
@ -1312,7 +1312,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
|
|||
return JS_TRUE;
|
||||
}
|
||||
|
||||
genfp->rval.setUndefined();
|
||||
genfp->clearReturnValue();
|
||||
gen->state = JSGEN_CLOSED;
|
||||
if (ok) {
|
||||
/* Returned, explicitly or by falling off the end. */
|
||||
|
@ -1401,7 +1401,7 @@ generator_op(JSContext *cx, JSGeneratorOp op, Value *vp, uintN argc)
|
|||
bool undef = ((op == JSGENOP_SEND || op == JSGENOP_THROW) && argc != 0);
|
||||
if (!SendToGenerator(cx, op, obj, gen, undef ? vp[2] : UndefinedValue()))
|
||||
return JS_FALSE;
|
||||
*vp = gen->getFloatingFrame()->rval;
|
||||
*vp = gen->getFloatingFrame()->getReturnValue();
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
|
|
|
@ -951,7 +951,7 @@ js_ComputeFilename(JSContext *cx, JSStackFrame *caller,
|
|||
#endif
|
||||
|
||||
JS_ASSERT(principals || !(callbacks && callbacks->findObjectPrincipals));
|
||||
flags = JS_GetScriptFilenameFlags(caller->script);
|
||||
flags = JS_GetScriptFilenameFlags(caller->getScript());
|
||||
if ((flags & JSFILENAME_PROTECTED) &&
|
||||
principals &&
|
||||
strcmp(principals->codebase, "[System Principal]")) {
|
||||
|
@ -960,13 +960,13 @@ js_ComputeFilename(JSContext *cx, JSStackFrame *caller,
|
|||
}
|
||||
|
||||
jsbytecode *pc = caller->pc(cx);
|
||||
if (pc && js_GetOpcode(cx, caller->script, pc) == JSOP_EVAL) {
|
||||
JS_ASSERT(js_GetOpcode(cx, caller->script, pc + JSOP_EVAL_LENGTH) == JSOP_LINENO);
|
||||
if (pc && js_GetOpcode(cx, caller->getScript(), pc) == JSOP_EVAL) {
|
||||
JS_ASSERT(js_GetOpcode(cx, caller->getScript(), pc + JSOP_EVAL_LENGTH) == JSOP_LINENO);
|
||||
*linenop = GET_UINT16(pc + JSOP_EVAL_LENGTH);
|
||||
} else {
|
||||
*linenop = js_FramePCToLineNumber(cx, caller);
|
||||
}
|
||||
return caller->script->filename;
|
||||
return caller->getScript()->filename;
|
||||
}
|
||||
|
||||
#ifndef EVAL_CACHE_CHAIN_LIMIT
|
||||
|
@ -1024,10 +1024,13 @@ obj_eval(JSContext *cx, uintN argc, Value *vp)
|
|||
return JS_FALSE;
|
||||
obj = obj->wrappedObject(cx);
|
||||
|
||||
OBJ_TO_INNER_OBJECT(cx, obj);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
|
||||
/*
|
||||
* Ban all indirect uses of eval (global.foo = eval; global.foo(...)) and
|
||||
* calls that attempt to use a non-global object as the "with" object in
|
||||
* the former indirect case.
|
||||
* Ban indirect uses of eval (nonglobal.eval = eval; nonglobal.eval(....))
|
||||
* that attempt to use a non-global object as the scope object.
|
||||
*/
|
||||
{
|
||||
JSObject *parent = obj->getParent();
|
||||
|
@ -1053,18 +1056,18 @@ obj_eval(JSContext *cx, uintN argc, Value *vp)
|
|||
* when evaluating the code string. Warn when such uses are seen so that
|
||||
* authors will know that support for eval(s, o) has been removed.
|
||||
*/
|
||||
if (argc > 1 && !caller->script->warnedAboutTwoArgumentEval) {
|
||||
if (argc > 1 && !caller->getScript()->warnedAboutTwoArgumentEval) {
|
||||
static const char TWO_ARGUMENT_WARNING[] =
|
||||
"Support for eval(code, scopeObject) has been removed. "
|
||||
"Use |with (scopeObject) eval(code);| instead.";
|
||||
if (!JS_ReportWarning(cx, TWO_ARGUMENT_WARNING))
|
||||
return JS_FALSE;
|
||||
caller->script->warnedAboutTwoArgumentEval = true;
|
||||
caller->getScript()->warnedAboutTwoArgumentEval = true;
|
||||
}
|
||||
|
||||
/* From here on, control must exit through label out with ok set. */
|
||||
MUST_FLOW_THROUGH("out");
|
||||
uintN staticLevel = caller->script->staticLevel + 1;
|
||||
uintN staticLevel = caller->getScript()->staticLevel + 1;
|
||||
|
||||
/*
|
||||
* Bring fp->scopeChain up to date. We're either going to use
|
||||
|
@ -1086,10 +1089,6 @@ obj_eval(JSContext *cx, uintN argc, Value *vp)
|
|||
/* Pretend that we're top level. */
|
||||
staticLevel = 0;
|
||||
|
||||
OBJ_TO_INNER_OBJECT(cx, obj);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
|
||||
if (!js_CheckPrincipalsAccess(cx, obj,
|
||||
JS_StackFramePrincipals(cx, caller),
|
||||
cx->runtime->atomState.evalAtom)) {
|
||||
|
@ -1141,7 +1140,7 @@ obj_eval(JSContext *cx, uintN argc, Value *vp)
|
|||
* calls to eval from global code are not cached.
|
||||
*/
|
||||
JSScript **bucket = EvalCacheHash(cx, str);
|
||||
if (!indirectCall && caller->fun) {
|
||||
if (!indirectCall && caller->hasFunction()) {
|
||||
uintN count = 0;
|
||||
JSScript **scriptp = bucket;
|
||||
|
||||
|
@ -1159,7 +1158,7 @@ obj_eval(JSContext *cx, uintN argc, Value *vp)
|
|||
*/
|
||||
JSFunction *fun = script->getFunction(0);
|
||||
|
||||
if (fun == caller->fun) {
|
||||
if (fun == caller->getFunction()) {
|
||||
/*
|
||||
* Get the source string passed for safekeeping in the
|
||||
* atom map by the prior eval to Compiler::compileScript.
|
||||
|
@ -2694,10 +2693,10 @@ Detecting(JSContext *cx, jsbytecode *pc)
|
|||
JSOp op;
|
||||
JSAtom *atom;
|
||||
|
||||
script = cx->fp->script;
|
||||
script = cx->fp->getScript();
|
||||
endpc = script->code + script->length;
|
||||
for (;; pc += js_CodeSpec[op].length) {
|
||||
JS_ASSERT_IF(!cx->fp->imacpc, script->code <= pc && pc < endpc);
|
||||
JS_ASSERT_IF(!cx->fp->hasIMacroPC(), script->code <= pc && pc < endpc);
|
||||
|
||||
/* General case: a branch or equality op follows the access. */
|
||||
op = js_GetOpcode(cx, script, pc);
|
||||
|
@ -2767,7 +2766,7 @@ js_InferFlags(JSContext *cx, uintN defaultFlags)
|
|||
JSStackFrame *const fp = js_GetTopStackFrame(cx);
|
||||
if (!fp || !(pc = cx->regs->pc))
|
||||
return defaultFlags;
|
||||
cs = &js_CodeSpec[js_GetOpcode(cx, fp->script, pc)];
|
||||
cs = &js_CodeSpec[js_GetOpcode(cx, fp->getScript(), pc)];
|
||||
format = cs->format;
|
||||
if (JOF_MODE(format) != JOF_NAME)
|
||||
flags |= JSRESOLVE_QUALIFIED;
|
||||
|
@ -2776,7 +2775,7 @@ js_InferFlags(JSContext *cx, uintN defaultFlags)
|
|||
flags |= JSRESOLVE_ASSIGNING;
|
||||
} else if (cs->length >= 0) {
|
||||
pc += cs->length;
|
||||
if (pc < cx->fp->script->code + cx->fp->script->length && Detecting(cx, pc))
|
||||
if (pc < cx->fp->getScript()->code + cx->fp->getScript()->length && Detecting(cx, pc))
|
||||
flags |= JSRESOLVE_DETECTING;
|
||||
}
|
||||
if (format & JOF_DECLARING)
|
||||
|
@ -2953,7 +2952,7 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
|
|||
JS_STATIC_ASSERT(JS_INITIAL_NSLOTS == JSSLOT_BLOCK_DEPTH + 2);
|
||||
|
||||
JSStackFrame *const fp = cx->fp;
|
||||
JSObject *obj = fp->scopeChain;
|
||||
JSObject *obj = fp->getScopeChain();
|
||||
JS_ASSERT(obj->getClass() == &js_BlockClass);
|
||||
JS_ASSERT(obj->getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp));
|
||||
JS_ASSERT(OBJ_IS_CLONED_BLOCK(obj));
|
||||
|
@ -2978,7 +2977,7 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
|
|||
/* See comments in CheckDestructuring from jsparse.cpp. */
|
||||
JS_ASSERT(count >= 1);
|
||||
|
||||
depth += fp->script->nfixed;
|
||||
depth += fp->getFixedCount();
|
||||
obj->fslots[JSSLOT_BLOCK_DEPTH + 1] = fp->slots()[depth];
|
||||
if (normalUnwind && count > 1) {
|
||||
--count;
|
||||
|
@ -2987,7 +2986,7 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
|
|||
|
||||
/* We must clear the private slot even with errors. */
|
||||
obj->setPrivate(NULL);
|
||||
fp->scopeChain = obj->getParent();
|
||||
fp->setScopeChain(obj->getParent());
|
||||
return normalUnwind;
|
||||
}
|
||||
|
||||
|
@ -3007,8 +3006,8 @@ block_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
|||
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
|
||||
if (fp) {
|
||||
fp = js_LiveFrameIfGenerator(fp);
|
||||
index += fp->script->nfixed + OBJ_BLOCK_DEPTH(cx, obj);
|
||||
JS_ASSERT(index < fp->script->nslots);
|
||||
index += fp->getFixedCount() + OBJ_BLOCK_DEPTH(cx, obj);
|
||||
JS_ASSERT(index < fp->getSlotCount());
|
||||
*vp = fp->slots()[index];
|
||||
return true;
|
||||
}
|
||||
|
@ -3033,8 +3032,8 @@ block_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
|||
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
|
||||
if (fp) {
|
||||
fp = js_LiveFrameIfGenerator(fp);
|
||||
index += fp->script->nfixed + OBJ_BLOCK_DEPTH(cx, obj);
|
||||
JS_ASSERT(index < fp->script->nslots);
|
||||
index += fp->getFixedCount() + OBJ_BLOCK_DEPTH(cx, obj);
|
||||
JS_ASSERT(index < fp->getSlotCount());
|
||||
fp->slots()[index] = *vp;
|
||||
return true;
|
||||
}
|
||||
|
@ -3736,7 +3735,7 @@ js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey protoKey,
|
|||
*/
|
||||
VOUCH_DOES_NOT_REQUIRE_STACK();
|
||||
if (!start && (fp = cx->fp) != NULL)
|
||||
start = fp->scopeChain;
|
||||
start = fp->maybeScopeChain();
|
||||
|
||||
if (start) {
|
||||
/* Find the topmost object in the scope chain. */
|
||||
|
@ -4455,7 +4454,7 @@ js_FindPropertyHelper(JSContext *cx, jsid id, JSBool cacheResult,
|
|||
JSProperty *prop;
|
||||
|
||||
JS_ASSERT_IF(cacheResult, !JS_ON_TRACE(cx));
|
||||
scopeChain = js_GetTopStackFrame(cx)->scopeChain;
|
||||
scopeChain = js_GetTopStackFrame(cx)->getScopeChain();
|
||||
|
||||
/* Scan entries on the scope chain that we can cache across. */
|
||||
entry = JS_NO_PROP_CACHE_FILL;
|
||||
|
@ -4776,7 +4775,7 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN getHow,
|
|||
op = (JSOp) *pc;
|
||||
if (op == JSOP_TRAP) {
|
||||
JS_ASSERT_NOT_ON_TRACE(cx);
|
||||
op = JS_GetTrapOpcode(cx, cx->fp->script, pc);
|
||||
op = JS_GetTrapOpcode(cx, cx->fp->getScript(), pc);
|
||||
}
|
||||
if (op == JSOP_GETXPROP) {
|
||||
flags = JSREPORT_ERROR;
|
||||
|
@ -4868,7 +4867,7 @@ js_CheckUndeclaredVarAssignment(JSContext *cx, JSString *propname)
|
|||
return true;
|
||||
|
||||
/* If neither cx nor the code is strict, then no check is needed. */
|
||||
if (!(fp->script && fp->script->strictModeCode) &&
|
||||
if (!(fp->hasScript() && fp->getScript()->strictModeCode) &&
|
||||
!JS_HAS_STRICT_OPTION(cx)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -5265,8 +5264,8 @@ js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval)
|
|||
if (fun != funobj) {
|
||||
for (JSStackFrame *fp = cx->fp; fp; fp = fp->down) {
|
||||
if (fp->callee() == fun &&
|
||||
fp->thisv.isObject() &&
|
||||
&fp->thisv.toObject() == obj) {
|
||||
fp->getThisValue().isObject() &&
|
||||
&fp->getThisValue().toObject() == obj) {
|
||||
fp->setCalleeObject(*funobj);
|
||||
}
|
||||
}
|
||||
|
@ -5561,7 +5560,7 @@ js_GetClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey,
|
|||
if (protoKey != JSProto_Null) {
|
||||
if (!scope) {
|
||||
if (cx->fp)
|
||||
scope = cx->fp->scopeChain;
|
||||
scope = cx->fp->maybeScopeChain();
|
||||
if (!scope) {
|
||||
scope = cx->globalObject;
|
||||
if (!scope) {
|
||||
|
@ -6047,9 +6046,9 @@ JSObject::wrappedObject(JSContext *cx) const
|
|||
}
|
||||
|
||||
JSObject *
|
||||
JSObject::getGlobal()
|
||||
JSObject::getGlobal() const
|
||||
{
|
||||
JSObject *obj = this;
|
||||
JSObject *obj = const_cast<JSObject *>(this);
|
||||
while (JSObject *parent = obj->getParent())
|
||||
obj = parent;
|
||||
return obj;
|
||||
|
@ -6370,17 +6369,19 @@ js_DumpStackFrame(JSContext *cx, JSStackFrame *start)
|
|||
}
|
||||
fputc('\n', stderr);
|
||||
|
||||
if (fp->script)
|
||||
fprintf(stderr, "file %s line %u\n", fp->script->filename, (unsigned) fp->script->lineno);
|
||||
if (fp->hasScript()) {
|
||||
fprintf(stderr, "file %s line %u\n",
|
||||
fp->getScript()->filename, (unsigned) fp->getScript()->lineno);
|
||||
}
|
||||
|
||||
if (jsbytecode *pc = i.pc()) {
|
||||
if (!fp->script) {
|
||||
if (!fp->hasScript()) {
|
||||
fprintf(stderr, "*** pc && !script, skipping frame\n\n");
|
||||
continue;
|
||||
}
|
||||
if (fp->imacpc) {
|
||||
if (fp->hasIMacroPC()) {
|
||||
fprintf(stderr, " pc in imacro at %p\n called from ", pc);
|
||||
pc = fp->imacpc;
|
||||
pc = fp->getIMacroPC();
|
||||
} else {
|
||||
fprintf(stderr, " ");
|
||||
}
|
||||
|
@ -6400,9 +6401,9 @@ js_DumpStackFrame(JSContext *cx, JSStackFrame *start)
|
|||
fprintf(stderr, " argv: %p (argc: %u)\n", (void *) fp->argv, (unsigned) fp->argc);
|
||||
MaybeDumpObject("callobj", fp->maybeCallObj());
|
||||
MaybeDumpObject("argsobj", fp->maybeArgsObj());
|
||||
MaybeDumpValue("this", fp->thisv);
|
||||
MaybeDumpValue("this", fp->getThisValue());
|
||||
fprintf(stderr, " rval: ");
|
||||
dumpValue(fp->rval);
|
||||
dumpValue(fp->getReturnValue());
|
||||
fputc('\n', stderr);
|
||||
|
||||
fprintf(stderr, " flags:");
|
||||
|
@ -6426,10 +6427,10 @@ js_DumpStackFrame(JSContext *cx, JSStackFrame *start)
|
|||
fprintf(stderr, " overridden_args");
|
||||
fputc('\n', stderr);
|
||||
|
||||
if (fp->scopeChain)
|
||||
fprintf(stderr, " scopeChain: (JSObject *) %p\n", (void *) fp->scopeChain);
|
||||
if (fp->blockChain)
|
||||
fprintf(stderr, " blockChain: (JSObject *) %p\n", (void *) fp->blockChain);
|
||||
if (fp->hasScopeChain())
|
||||
fprintf(stderr, " scopeChain: (JSObject *) %p\n", (void *) fp->getScopeChain());
|
||||
if (fp->hasBlockChain())
|
||||
fprintf(stderr, " blockChain: (JSObject *) %p\n", (void *) fp->getBlockChain());
|
||||
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
|
|
|
@ -418,7 +418,7 @@ struct JSObject {
|
|||
parent = newParent;
|
||||
}
|
||||
|
||||
JSObject *getGlobal();
|
||||
JSObject *getGlobal() const;
|
||||
|
||||
void *getPrivate() const {
|
||||
JS_ASSERT(getClass()->flags & JSCLASS_HAS_PRIVATE);
|
||||
|
@ -498,7 +498,10 @@ struct JSObject {
|
|||
* JSSLOT_PRIVATE - the corresponding frame until the frame exits.
|
||||
* JSSLOT_ARGS_LENGTH - the number of actual arguments and a flag
|
||||
* indicating whether arguments.length was
|
||||
* overwritten.
|
||||
* overwritten. This slot is not used to represent
|
||||
* arguments.length after that property has been
|
||||
* assigned, even if the new value is integral: it's
|
||||
* always the original length.
|
||||
* JSSLOT_ARGS_CALLEE - the arguments.callee value or JSVAL_HOLE if that
|
||||
* was overwritten.
|
||||
*
|
||||
|
@ -512,8 +515,21 @@ struct JSObject {
|
|||
/* Number of extra fixed slots besides JSSLOT_PRIVATE. */
|
||||
static const uint32 ARGS_FIXED_RESERVED_SLOTS = 2;
|
||||
|
||||
inline uint32 getArgsLength() const;
|
||||
/* Lower-order bit stolen from the length slot. */
|
||||
static const uint32 ARGS_LENGTH_OVERRIDDEN_BIT = 0x1;
|
||||
static const uint32 ARGS_PACKED_BITS_COUNT = 1;
|
||||
|
||||
/*
|
||||
* Set the initial length of the arguments, and mark it as not overridden.
|
||||
*/
|
||||
inline void setArgsLength(uint32 argc);
|
||||
|
||||
/*
|
||||
* Return the initial length of the arguments. This may differ from the
|
||||
* current value of arguments.length!
|
||||
*/
|
||||
inline uint32 getArgsInitialLength() const;
|
||||
|
||||
inline void setArgsLengthOverridden();
|
||||
inline bool isArgsLengthOverridden() const;
|
||||
|
||||
|
@ -528,16 +544,26 @@ struct JSObject {
|
|||
* Date-specific getters and setters.
|
||||
*/
|
||||
|
||||
private:
|
||||
// The second slot caches the local time; it's initialized to NaN.
|
||||
static const uint32 JSSLOT_DATE_UTC_TIME = JSSLOT_PRIVATE;
|
||||
static const uint32 JSSLOT_DATE_LOCAL_TIME = JSSLOT_PRIVATE + 1;
|
||||
|
||||
public:
|
||||
static const uint32 DATE_FIXED_RESERVED_SLOTS = 2;
|
||||
static const uint32 JSSLOT_DATE_UTC_TIME = JSSLOT_PRIVATE;
|
||||
|
||||
inline const js::Value &getDateLocalTime() const;
|
||||
inline void setDateLocalTime(const js::Value &pthis);
|
||||
/*
|
||||
* Cached slots holding local properties of the date.
|
||||
* These are undefined until the first actual lookup occurs
|
||||
* and are reset to undefined whenever the date's time is modified.
|
||||
*/
|
||||
static const uint32 JSSLOT_DATE_COMPONENTS_START = JSSLOT_PRIVATE + 1;
|
||||
|
||||
static const uint32 JSSLOT_DATE_LOCAL_TIME = JSSLOT_PRIVATE + 1;
|
||||
static const uint32 JSSLOT_DATE_LOCAL_YEAR = JSSLOT_PRIVATE + 2;
|
||||
static const uint32 JSSLOT_DATE_LOCAL_MONTH = JSSLOT_PRIVATE + 3;
|
||||
static const uint32 JSSLOT_DATE_LOCAL_DATE = JSSLOT_PRIVATE + 4;
|
||||
static const uint32 JSSLOT_DATE_LOCAL_DAY = JSSLOT_PRIVATE + 5;
|
||||
static const uint32 JSSLOT_DATE_LOCAL_HOURS = JSSLOT_PRIVATE + 6;
|
||||
static const uint32 JSSLOT_DATE_LOCAL_MINUTES = JSSLOT_PRIVATE + 7;
|
||||
static const uint32 JSSLOT_DATE_LOCAL_SECONDS = JSSLOT_PRIVATE + 8;
|
||||
|
||||
static const uint32 DATE_CLASS_RESERVED_SLOTS = 9;
|
||||
|
||||
inline const js::Value &getDateUTCTime() const;
|
||||
inline void setDateUTCTime(const js::Value &pthis);
|
||||
|
@ -558,6 +584,8 @@ struct JSObject {
|
|||
inline bool hasMethodObj(const JSObject& obj) const;
|
||||
inline void setMethodObj(JSObject& obj);
|
||||
|
||||
inline JSFunction *getFunctionPrivate() const;
|
||||
|
||||
/*
|
||||
* RegExp-specific getters and setters.
|
||||
*/
|
||||
|
@ -729,11 +757,15 @@ struct JSObject {
|
|||
|
||||
JS_FRIEND_API(JSCompartment *) getCompartment(JSContext *cx);
|
||||
|
||||
inline JSObject *getThrowTypeError() const;
|
||||
|
||||
void swap(JSObject *obj);
|
||||
|
||||
inline bool canHaveMethodBarrier() const;
|
||||
|
||||
inline bool isArguments() const;
|
||||
inline bool isNormalArguments() const;
|
||||
inline bool isStrictArguments() const;
|
||||
inline bool isArray() const;
|
||||
inline bool isDenseArray() const;
|
||||
inline bool isSlowArray() const;
|
||||
|
|
|
@ -220,15 +220,16 @@ JSObject::setArgsLength(uint32 argc)
|
|||
{
|
||||
JS_ASSERT(isArguments());
|
||||
JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX);
|
||||
fslots[JSSLOT_ARGS_LENGTH].setInt32(argc << 1);
|
||||
JS_ASSERT(UINT32_MAX > (uint64(argc) << ARGS_PACKED_BITS_COUNT));
|
||||
fslots[JSSLOT_ARGS_LENGTH].setInt32(argc << ARGS_PACKED_BITS_COUNT);
|
||||
JS_ASSERT(!isArgsLengthOverridden());
|
||||
}
|
||||
|
||||
inline uint32
|
||||
JSObject::getArgsLength() const
|
||||
JSObject::getArgsInitialLength() const
|
||||
{
|
||||
JS_ASSERT(isArguments());
|
||||
uint32 argc = uint32(fslots[JSSLOT_ARGS_LENGTH].toInt32()) >> 1;
|
||||
uint32 argc = uint32(fslots[JSSLOT_ARGS_LENGTH].toInt32()) >> ARGS_PACKED_BITS_COUNT;
|
||||
JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX);
|
||||
return argc;
|
||||
}
|
||||
|
@ -237,7 +238,7 @@ inline void
|
|||
JSObject::setArgsLengthOverridden()
|
||||
{
|
||||
JS_ASSERT(isArguments());
|
||||
fslots[JSSLOT_ARGS_LENGTH].getInt32Ref() |= 1;
|
||||
fslots[JSSLOT_ARGS_LENGTH].getInt32Ref() |= ARGS_LENGTH_OVERRIDDEN_BIT;
|
||||
}
|
||||
|
||||
inline bool
|
||||
|
@ -245,7 +246,7 @@ JSObject::isArgsLengthOverridden() const
|
|||
{
|
||||
JS_ASSERT(isArguments());
|
||||
const js::Value &v = fslots[JSSLOT_ARGS_LENGTH];
|
||||
return (v.toInt32() & 1) != 0;
|
||||
return v.toInt32() & ARGS_LENGTH_OVERRIDDEN_BIT;
|
||||
}
|
||||
|
||||
inline const js::Value &
|
||||
|
@ -286,20 +287,6 @@ JSObject::setArgsElement(uint32 i, const js::Value &v)
|
|||
dslots[i] = v;
|
||||
}
|
||||
|
||||
inline const js::Value &
|
||||
JSObject::getDateLocalTime() const
|
||||
{
|
||||
JS_ASSERT(isDate());
|
||||
return fslots[JSSLOT_DATE_LOCAL_TIME];
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setDateLocalTime(const js::Value &time)
|
||||
{
|
||||
JS_ASSERT(isDate());
|
||||
fslots[JSSLOT_DATE_LOCAL_TIME] = time;
|
||||
}
|
||||
|
||||
inline const js::Value &
|
||||
JSObject::getDateUTCTime() const
|
||||
{
|
||||
|
@ -327,6 +314,13 @@ JSObject::setMethodObj(JSObject& obj)
|
|||
fslots[JSSLOT_FUN_METHOD_OBJ].setObject(obj);
|
||||
}
|
||||
|
||||
inline JSFunction *
|
||||
JSObject::getFunctionPrivate() const
|
||||
{
|
||||
JS_ASSERT(isFunction());
|
||||
return reinterpret_cast<JSFunction *>(getPrivate());
|
||||
}
|
||||
|
||||
inline NativeIterator *
|
||||
JSObject::getNativeIterator() const
|
||||
{
|
||||
|
@ -611,7 +605,7 @@ NewBuiltinClassInstance(JSContext *cx, Class *clasp)
|
|||
if (!global)
|
||||
return NULL;
|
||||
} else {
|
||||
global = cx->fp->scopeChain->getGlobal();
|
||||
global = cx->fp->getScopeChain()->getGlobal();
|
||||
}
|
||||
JS_ASSERT(global->getClass()->flags & JSCLASS_IS_GLOBAL);
|
||||
|
||||
|
|
|
@ -240,16 +240,14 @@ public:
|
|||
if (gapValue.value().isString()) {
|
||||
if (!js_ValueToCharBuffer(cx, gapValue.value(), gap))
|
||||
return false;
|
||||
if (cb.length() > 10)
|
||||
cb.resize(10);
|
||||
}
|
||||
|
||||
if (gapValue.value().isNumber()) {
|
||||
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 && !cb.appendN(' ', uint32(d)))
|
||||
if (d >= 1 && !gap.appendN(' ', uint32(d)))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -346,23 +344,23 @@ JO(JSContext *cx, Value *vp, StringifyContext *scx)
|
|||
}
|
||||
|
||||
JSBool memberWritten = JS_FALSE;
|
||||
AutoIdArray ida(cx, JS_Enumerate(cx, &keySource->toObject()));
|
||||
if (!ida)
|
||||
AutoIdVector props(cx);
|
||||
if (!GetPropertyNames(cx, &keySource->toObject(), JSITER_OWNONLY, props))
|
||||
return JS_FALSE;
|
||||
|
||||
for (jsint i = 0, len = ida.length(); i < len; i++) {
|
||||
for (size_t i = 0, len = props.length(); i < len; i++) {
|
||||
outputValue.setUndefined();
|
||||
|
||||
if (!usingWhitelist) {
|
||||
if (!js_ValueToStringId(cx, IdToValue(ida[i]), &id))
|
||||
if (!js_ValueToStringId(cx, IdToValue(props[i]), &id))
|
||||
return JS_FALSE;
|
||||
} else {
|
||||
// skip non-index properties
|
||||
jsuint index = 0;
|
||||
if (!js_IdIsIndex(ida[i], &index))
|
||||
if (!js_IdIsIndex(props[i], &index))
|
||||
continue;
|
||||
|
||||
if (!scx->replacer->getProperty(cx, ida[i], &whitelistElement))
|
||||
if (!scx->replacer->getProperty(cx, props[i], &whitelistElement))
|
||||
return JS_FALSE;
|
||||
|
||||
if (!js_ValueToStringId(cx, whitelistElement, &id))
|
||||
|
@ -409,6 +407,7 @@ JO(JSContext *cx, Value *vp, StringifyContext *scx)
|
|||
s->getCharsAndLength(chars, length);
|
||||
if (!write_string(cx, scx->cb, chars, length) ||
|
||||
!scx->cb.append(':') ||
|
||||
!(scx->gap.empty() || scx->cb.append(' ')) ||
|
||||
!Str(cx, id, obj, scx, &outputValue, true)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
@ -618,12 +617,12 @@ Walk(JSContext *cx, jsid id, JSObject *holder, const Value &reviver, Value *vp)
|
|||
return false;
|
||||
}
|
||||
} else {
|
||||
AutoIdArray ida(cx, JS_Enumerate(cx, obj));
|
||||
if (!ida)
|
||||
AutoIdVector props(cx);
|
||||
if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, props))
|
||||
return false;
|
||||
|
||||
for (jsint i = 0, len = ida.length(); i < len; i++) {
|
||||
jsid idName = ida[i];
|
||||
for (size_t i = 0, len = props.length(); i < len; i++) {
|
||||
jsid idName = props[i];
|
||||
if (!Walk(cx, idName, obj, reviver, propValue.addr()))
|
||||
return false;
|
||||
if (propValue.value().isUndefined()) {
|
||||
|
|
|
@ -279,7 +279,7 @@ js_Disassemble(JSContext *cx, JSScript *script, JSBool lines, FILE *fp)
|
|||
JS_FRIEND_API(JSBool)
|
||||
js_DumpPC(JSContext *cx)
|
||||
{
|
||||
return js_DisassembleAtPC(cx, cx->fp->script, true, stdout, cx->regs->pc);
|
||||
return js_DisassembleAtPC(cx, cx->fp->getScript(), true, stdout, cx->regs->pc);
|
||||
}
|
||||
|
||||
JSBool
|
||||
|
@ -2873,8 +2873,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||
if (fp) {
|
||||
while (!(fp->flags & JSFRAME_EVAL))
|
||||
fp = fp->down;
|
||||
JS_ASSERT(fp->script == jp->script);
|
||||
JS_ASSERT(fp->down->fun == jp->fun);
|
||||
JS_ASSERT(fp->getScript() == jp->script);
|
||||
JS_ASSERT(fp->down->getFunction() == jp->fun);
|
||||
JS_ASSERT(FUN_INTERPRETED(jp->fun));
|
||||
JS_ASSERT(jp->script != jp->fun->u.i.script);
|
||||
JS_ASSERT(jp->script->upvarsOffset != 0);
|
||||
|
@ -5082,15 +5082,15 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v_in,
|
|||
|
||||
/* Get scripted caller */
|
||||
FrameRegsIter i(cx);
|
||||
while (!i.done() && !i.fp()->script)
|
||||
while (!i.done() && !i.fp()->hasScript())
|
||||
++i;
|
||||
|
||||
if (i.done() || !i.pc() || i.fp()->script->nslots == 0)
|
||||
if (i.done() || !i.pc() || i.fp()->getSlotCount() == 0)
|
||||
goto do_fallback;
|
||||
|
||||
fp = i.fp();
|
||||
script = fp->script;
|
||||
pc = fp->imacpc ? fp->imacpc : i.pc();
|
||||
script = fp->getScript();
|
||||
pc = fp->hasIMacroPC() ? fp->getIMacroPC() : i.pc();
|
||||
JS_ASSERT(pc >= script->main && pc < script->code + script->length);
|
||||
|
||||
if (spindex != JSDVG_IGNORE_STACK) {
|
||||
|
@ -5153,13 +5153,13 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v_in,
|
|||
|
||||
{
|
||||
jsbytecode* savepc = i.pc();
|
||||
jsbytecode* imacpc = fp->imacpc;
|
||||
if (imacpc) {
|
||||
jsbytecode* savedIMacroPC = fp->maybeIMacroPC();
|
||||
if (savedIMacroPC) {
|
||||
if (fp == cx->fp)
|
||||
cx->regs->pc = imacpc;
|
||||
cx->regs->pc = savedIMacroPC;
|
||||
else
|
||||
fp->savedPC = imacpc;
|
||||
fp->imacpc = NULL;
|
||||
fp->savedPC = savedIMacroPC;
|
||||
fp->clearIMacroPC();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -5167,17 +5167,17 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v_in,
|
|||
* value *inside* an imacro; this would confuse the decompiler.
|
||||
*/
|
||||
char *name;
|
||||
if (imacpc && size_t(pc - script->code) >= script->length)
|
||||
if (savedIMacroPC && size_t(pc - script->code) >= script->length)
|
||||
name = FAILED_EXPRESSION_DECOMPILER;
|
||||
else
|
||||
name = DecompileExpression(cx, script, fp->fun, pc);
|
||||
name = DecompileExpression(cx, script, fp->maybeFunction(), pc);
|
||||
|
||||
if (imacpc) {
|
||||
if (savedIMacroPC) {
|
||||
if (fp == cx->fp)
|
||||
cx->regs->pc = imacpc;
|
||||
cx->regs->pc = savedIMacroPC;
|
||||
else
|
||||
fp->savedPC = savepc;
|
||||
fp->imacpc = imacpc;
|
||||
fp->setIMacroPC(savedIMacroPC);
|
||||
}
|
||||
|
||||
if (name != FAILED_EXPRESSION_DECOMPILER)
|
||||
|
@ -5401,11 +5401,15 @@ SimulateImacroCFG(JSContext *cx, JSScript *script,
|
|||
uintN pcdepth, jsbytecode *pc, jsbytecode *target,
|
||||
jsbytecode **pcstack)
|
||||
{
|
||||
size_t nbytes = StackDepth(script) * sizeof *pcstack;
|
||||
jsbytecode** tmp_pcstack = (jsbytecode **) cx->malloc(nbytes);
|
||||
if (!tmp_pcstack)
|
||||
return -1;
|
||||
memcpy(tmp_pcstack, pcstack, nbytes);
|
||||
size_t nbytes = 0;
|
||||
jsbytecode** tmp_pcstack = NULL;
|
||||
if (pcstack) {
|
||||
nbytes = StackDepth(script) * sizeof *pcstack;
|
||||
tmp_pcstack = (jsbytecode **) cx->malloc(nbytes);
|
||||
if (!tmp_pcstack)
|
||||
return -1;
|
||||
memcpy(tmp_pcstack, pcstack, nbytes);
|
||||
}
|
||||
|
||||
ptrdiff_t oplen;
|
||||
for (; pc < target; pc += oplen) {
|
||||
|
@ -5441,12 +5445,15 @@ SimulateImacroCFG(JSContext *cx, JSScript *script,
|
|||
LOCAL_ASSERT(pc == target);
|
||||
|
||||
success:
|
||||
memcpy(pcstack, tmp_pcstack, nbytes);
|
||||
cx->free(tmp_pcstack);
|
||||
if (tmp_pcstack) {
|
||||
memcpy(pcstack, tmp_pcstack, nbytes);
|
||||
cx->free(tmp_pcstack);
|
||||
}
|
||||
return pcdepth;
|
||||
|
||||
failure:
|
||||
cx->free(tmp_pcstack);
|
||||
if (tmp_pcstack)
|
||||
cx->free(tmp_pcstack);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -5463,8 +5470,8 @@ ReconstructImacroPCStack(JSContext *cx, JSScript *script,
|
|||
* the state-of-the-world at the *start* of the imacro.
|
||||
*/
|
||||
JSStackFrame *fp = js_GetScriptedCaller(cx, NULL);
|
||||
JS_ASSERT(fp->imacpc);
|
||||
intN pcdepth = ReconstructPCStack(cx, script, fp->imacpc, pcstack);
|
||||
JS_ASSERT(fp->hasIMacroPC());
|
||||
intN pcdepth = ReconstructPCStack(cx, script, fp->getIMacroPC(), pcstack);
|
||||
if (pcdepth < 0)
|
||||
return pcdepth;
|
||||
return SimulateImacroCFG(cx, script, pcdepth, imacstart, target, pcstack);
|
||||
|
|
|
@ -771,8 +771,8 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *calle
|
|||
|
||||
/* If this is a direct call to eval, inherit the caller's strictness. */
|
||||
if (callerFrame &&
|
||||
callerFrame->script &&
|
||||
callerFrame->script->strictModeCode) {
|
||||
callerFrame->hasScript() &&
|
||||
callerFrame->getScript()->strictModeCode) {
|
||||
cg.flags |= TCF_STRICT_MODE_CODE;
|
||||
tokenStream.setStrictMode();
|
||||
}
|
||||
|
@ -795,13 +795,13 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *calle
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (callerFrame && callerFrame->fun) {
|
||||
if (callerFrame && callerFrame->hasFunction()) {
|
||||
/*
|
||||
* An eval script in a caller frame needs to have its enclosing
|
||||
* function captured in case it refers to an upvar, and someone
|
||||
* wishes to decompile it while it's running.
|
||||
*/
|
||||
funbox = parser.newObjectBox(FUN_OBJECT(callerFrame->fun));
|
||||
funbox = parser.newObjectBox(FUN_OBJECT(callerFrame->getFunction()));
|
||||
if (!funbox)
|
||||
goto out;
|
||||
funbox->emitLink = cg.objectList.lastbox;
|
||||
|
@ -1131,8 +1131,7 @@ CheckFinalReturn(JSContext *cx, JSTreeContext *tc, JSParseNode *pn)
|
|||
bool
|
||||
CheckStrictAssignment(JSContext *cx, JSTreeContext *tc, JSParseNode *lhs)
|
||||
{
|
||||
if (tc->needStrictChecks() &&
|
||||
lhs->pn_type == TOK_NAME) {
|
||||
if (tc->needStrictChecks() && lhs->pn_type == TOK_NAME) {
|
||||
JSAtom *atom = lhs->pn_atom;
|
||||
JSAtomState *atomState = &cx->runtime->atomState;
|
||||
if (atom == atomState->evalAtom || atom == atomState->argumentsAtom) {
|
||||
|
@ -1162,9 +1161,9 @@ CheckStrictBinding(JSContext *cx, JSTreeContext *tc, JSAtom *atom, JSParseNode *
|
|||
JSAtomState *atomState = &cx->runtime->atomState;
|
||||
if (atom == atomState->evalAtom || atom == atomState->argumentsAtom) {
|
||||
const char *name = js_AtomToPrintableString(cx, atom);
|
||||
if (name)
|
||||
ReportStrictModeError(cx, TS(tc->parser), tc, pn, JSMSG_BAD_BINDING, name);
|
||||
return false;
|
||||
if (!name)
|
||||
return false;
|
||||
return ReportStrictModeError(cx, TS(tc->parser), tc, pn, JSMSG_BAD_BINDING, name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -2532,29 +2531,163 @@ LeaveFunction(JSParseNode *fn, JSTreeContext *funtc, JSAtom *funAtom = NULL,
|
|||
funtc->lexdeps.clear();
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether any parameters have been assigned within this function.
|
||||
* In strict mode parameters do not alias arguments[i], and to make the
|
||||
* arguments object reflect initial parameter values prior to any mutation
|
||||
* we create it eagerly whenever parameters are (or might, in the case of
|
||||
* calls to eval) be assigned.
|
||||
*/
|
||||
if (funtc->inStrictMode() && funbox->object->getFunctionPrivate()->nargs > 0) {
|
||||
JSAtomListIterator iter(&funtc->decls);
|
||||
JSAtomListElement *ale;
|
||||
|
||||
while ((ale = iter()) != NULL) {
|
||||
JSDefinition *dn = ALE_DEFN(ale);
|
||||
if (dn->kind() == JSDefinition::ARG && dn->isAssigned()) {
|
||||
funbox->tcflags |= TCF_FUN_MUTATES_PARAMETER;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Parser::functionArguments(JSTreeContext &funtc, JSFunctionBox *funbox, JSFunction *fun,
|
||||
JSParseNode **listp)
|
||||
{
|
||||
if (tokenStream.getToken() != TOK_LP) {
|
||||
reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_PAREN_BEFORE_FORMAL);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!tokenStream.matchToken(TOK_RP)) {
|
||||
#if JS_HAS_DESTRUCTURING
|
||||
JSAtom *duplicatedArg = NULL;
|
||||
bool destructuringArg = false;
|
||||
JSParseNode *list = NULL;
|
||||
#endif
|
||||
do {
|
||||
switch (TokenKind tt = tokenStream.getToken()) {
|
||||
#if JS_HAS_DESTRUCTURING
|
||||
case TOK_LB:
|
||||
case TOK_LC:
|
||||
{
|
||||
/* See comment below in the TOK_NAME case. */
|
||||
if (duplicatedArg)
|
||||
goto report_dup_and_destructuring;
|
||||
destructuringArg = true;
|
||||
|
||||
/*
|
||||
* A destructuring formal parameter turns into one or more
|
||||
* local variables initialized from properties of a single
|
||||
* anonymous positional parameter, so here we must tweak our
|
||||
* binder and its data.
|
||||
*/
|
||||
BindData data;
|
||||
data.pn = NULL;
|
||||
data.op = JSOP_DEFVAR;
|
||||
data.binder = BindDestructuringArg;
|
||||
JSParseNode *lhs = destructuringExpr(&data, tt);
|
||||
if (!lhs)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Adjust fun->nargs to count the single anonymous positional
|
||||
* parameter that is to be destructured.
|
||||
*/
|
||||
jsint slot = fun->nargs;
|
||||
if (!js_AddLocal(context, fun, NULL, JSLOCAL_ARG))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Synthesize a destructuring assignment from the single
|
||||
* anonymous positional parameter into the destructuring
|
||||
* left-hand-side expression and accumulate it in list.
|
||||
*/
|
||||
JSParseNode *rhs = NameNode::create(context->runtime->atomState.emptyAtom, &funtc);
|
||||
if (!rhs)
|
||||
return false;
|
||||
rhs->pn_type = TOK_NAME;
|
||||
rhs->pn_op = JSOP_GETARG;
|
||||
rhs->pn_cookie.set(funtc.staticLevel, uint16(slot));
|
||||
rhs->pn_dflags |= PND_BOUND;
|
||||
|
||||
JSParseNode *item = JSParseNode::newBinaryOrAppend(TOK_ASSIGN, JSOP_NOP, lhs, rhs, &funtc);
|
||||
if (!item)
|
||||
return false;
|
||||
if (!list) {
|
||||
list = ListNode::create(&funtc);
|
||||
if (!list)
|
||||
return false;
|
||||
list->pn_type = TOK_COMMA;
|
||||
list->makeEmpty();
|
||||
*listp = list;
|
||||
}
|
||||
list->append(item);
|
||||
break;
|
||||
}
|
||||
#endif /* JS_HAS_DESTRUCTURING */
|
||||
|
||||
case TOK_NAME:
|
||||
{
|
||||
JSAtom *atom = tokenStream.currentToken().t_atom;
|
||||
if (!DefineArg(funbox->node, atom, fun->nargs, &funtc))
|
||||
return false;
|
||||
#ifdef JS_HAS_DESTRUCTURING
|
||||
/*
|
||||
* ECMA-262 requires us to support duplicate parameter names, but if the
|
||||
* parameter list includes destructuring, we consider the code to have
|
||||
* opted in to higher standards, and forbid duplicates. We may see a
|
||||
* destructuring parameter later, so always note duplicates now.
|
||||
*
|
||||
* Duplicates are warned about (strict option) or cause errors (strict
|
||||
* mode code), but we do those tests in one place below, after having
|
||||
* parsed the body.
|
||||
*/
|
||||
if (js_LookupLocal(context, fun, atom, NULL) != JSLOCAL_NONE) {
|
||||
duplicatedArg = atom;
|
||||
if (destructuringArg)
|
||||
goto report_dup_and_destructuring;
|
||||
}
|
||||
#endif
|
||||
if (!js_AddLocal(context, fun, atom, JSLOCAL_ARG))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_MISSING_FORMAL);
|
||||
/* FALL THROUGH */
|
||||
case TOK_ERROR:
|
||||
return false;
|
||||
|
||||
#if JS_HAS_DESTRUCTURING
|
||||
report_dup_and_destructuring:
|
||||
JSDefinition *dn = ALE_DEFN(funtc.decls.lookup(duplicatedArg));
|
||||
reportErrorNumber(dn, JSREPORT_ERROR, JSMSG_DESTRUCT_DUP_ARG);
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
} while (tokenStream.matchToken(TOK_COMMA));
|
||||
|
||||
if (tokenStream.getToken() != TOK_RP) {
|
||||
reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_PAREN_AFTER_FORMAL);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JSParseNode *
|
||||
Parser::functionDef(uintN lambda, bool namePermitted)
|
||||
Parser::functionDef(JSAtom *funAtom, FunctionType type, uintN lambda)
|
||||
{
|
||||
JSParseNode *pn, *body, *result;
|
||||
TokenKind tt;
|
||||
JSAtomListElement *ale;
|
||||
#if JS_HAS_DESTRUCTURING
|
||||
JSParseNode *item, *list = NULL;
|
||||
bool destructuringArg = false;
|
||||
JSAtom *duplicatedArg = NULL;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Save the current op for later so we can tag the created function as a
|
||||
* getter/setter if necessary.
|
||||
*/
|
||||
JSOp op = tokenStream.currentToken().t_op;
|
||||
|
||||
/* Make a TOK_FUNCTION node. */
|
||||
pn = FunctionNode::create(tc);
|
||||
tokenStream.mungeCurrentToken(TOK_FUNCTION, JSOP_NOP);
|
||||
JSParseNode *pn = FunctionNode::create(tc);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn->pn_body = NULL;
|
||||
|
@ -2571,28 +2704,12 @@ Parser::functionDef(uintN lambda, bool namePermitted)
|
|||
bool topLevel = tc->atTopLevel();
|
||||
pn->pn_dflags = (lambda || !topLevel) ? PND_FUNARG : 0;
|
||||
|
||||
/* Scan the optional function name into funAtom. */
|
||||
JSAtom *funAtom = NULL;
|
||||
if (namePermitted) {
|
||||
tt = tokenStream.getToken(TSF_KEYWORD_IS_NAME);
|
||||
if (tt == TOK_NAME) {
|
||||
funAtom = tokenStream.currentToken().t_atom;
|
||||
} else {
|
||||
if (lambda == 0 && (context->options & JSOPTION_ANONFUNFIX)) {
|
||||
reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
tokenStream.ungetToken();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Record names for function statements in tc->decls so we know when to
|
||||
* avoid optimizing variable references that might name a function.
|
||||
*/
|
||||
if (lambda == 0 && funAtom) {
|
||||
ale = tc->decls.lookup(funAtom);
|
||||
if (ale) {
|
||||
if (JSAtomListElement *ale = tc->decls.lookup(funAtom)) {
|
||||
JSDefinition *dn = ALE_DEFN(ale);
|
||||
JSDefinition::Kind dn_kind = dn->kind();
|
||||
|
||||
|
@ -2702,124 +2819,24 @@ Parser::functionDef(uintN lambda, bool namePermitted)
|
|||
|
||||
JSFunction *fun = (JSFunction *) funbox->object;
|
||||
|
||||
if (op != JSOP_NOP)
|
||||
fun->flags |= (op == JSOP_GETTER) ? JSPROP_GETTER : JSPROP_SETTER;
|
||||
|
||||
/* Now parse formal argument list and compute fun->nargs. */
|
||||
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_FORMAL);
|
||||
if (!tokenStream.matchToken(TOK_RP)) {
|
||||
do {
|
||||
tt = tokenStream.getToken();
|
||||
switch (tt) {
|
||||
#if JS_HAS_DESTRUCTURING
|
||||
case TOK_LB:
|
||||
case TOK_LC:
|
||||
{
|
||||
BindData data;
|
||||
JSParseNode *lhs, *rhs;
|
||||
jsint slot;
|
||||
JSParseNode *prolog = NULL;
|
||||
if (!functionArguments(funtc, funbox, fun, &prolog))
|
||||
return NULL;
|
||||
|
||||
/* See comment below in the TOK_NAME case. */
|
||||
if (duplicatedArg)
|
||||
goto report_dup_and_destructuring;
|
||||
destructuringArg = true;
|
||||
|
||||
/*
|
||||
* A destructuring formal parameter turns into one or more
|
||||
* local variables initialized from properties of a single
|
||||
* anonymous positional parameter, so here we must tweak our
|
||||
* binder and its data.
|
||||
*/
|
||||
data.pn = NULL;
|
||||
data.op = JSOP_DEFVAR;
|
||||
data.binder = BindDestructuringArg;
|
||||
lhs = destructuringExpr(&data, tt);
|
||||
if (!lhs)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Adjust fun->nargs to count the single anonymous positional
|
||||
* parameter that is to be destructured.
|
||||
*/
|
||||
slot = fun->nargs;
|
||||
if (!js_AddLocal(context, fun, NULL, JSLOCAL_ARG))
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Synthesize a destructuring assignment from the single
|
||||
* anonymous positional parameter into the destructuring
|
||||
* left-hand-side expression and accumulate it in list.
|
||||
*/
|
||||
rhs = NameNode::create(context->runtime->atomState.emptyAtom, &funtc);
|
||||
if (!rhs)
|
||||
return NULL;
|
||||
rhs->pn_type = TOK_NAME;
|
||||
rhs->pn_op = JSOP_GETARG;
|
||||
rhs->pn_cookie.set(funtc.staticLevel, uint16(slot));
|
||||
rhs->pn_dflags |= PND_BOUND;
|
||||
|
||||
item = JSParseNode::newBinaryOrAppend(TOK_ASSIGN, JSOP_NOP, lhs, rhs, &funtc);
|
||||
if (!item)
|
||||
return NULL;
|
||||
if (!list) {
|
||||
list = ListNode::create(&funtc);
|
||||
if (!list)
|
||||
return NULL;
|
||||
list->pn_type = TOK_COMMA;
|
||||
list->makeEmpty();
|
||||
}
|
||||
list->append(item);
|
||||
break;
|
||||
}
|
||||
#endif /* JS_HAS_DESTRUCTURING */
|
||||
|
||||
case TOK_NAME:
|
||||
{
|
||||
JSAtom *atom = tokenStream.currentToken().t_atom;
|
||||
if (!DefineArg(pn, atom, fun->nargs, &funtc))
|
||||
return NULL;
|
||||
#ifdef JS_HAS_DESTRUCTURING
|
||||
/*
|
||||
* ECMA-262 requires us to support duplicate parameter names, but if the
|
||||
* parameter list includes destructuring, we consider the code to have
|
||||
* opted in to higher standards, and forbid duplicates. We may see a
|
||||
* destructuring parameter later, so always note duplicates now.
|
||||
*
|
||||
* Duplicates are warned about (strict option) or cause errors (strict
|
||||
* mode code), but we do those tests in one place below, after having
|
||||
* parsed the body.
|
||||
*/
|
||||
if (js_LookupLocal(context, fun, atom, NULL) != JSLOCAL_NONE) {
|
||||
duplicatedArg = atom;
|
||||
if (destructuringArg)
|
||||
goto report_dup_and_destructuring;
|
||||
}
|
||||
#endif
|
||||
if (!js_AddLocal(context, fun, atom, JSLOCAL_ARG))
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_MISSING_FORMAL);
|
||||
/* FALL THROUGH */
|
||||
case TOK_ERROR:
|
||||
return NULL;
|
||||
|
||||
#if JS_HAS_DESTRUCTURING
|
||||
report_dup_and_destructuring:
|
||||
JSDefinition *dn = ALE_DEFN(funtc.decls.lookup(duplicatedArg));
|
||||
reportErrorNumber(dn, JSREPORT_ERROR, JSMSG_DESTRUCT_DUP_ARG);
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
} while (tokenStream.matchToken(TOK_COMMA));
|
||||
|
||||
MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FORMAL);
|
||||
if (type == GETTER && fun->nargs > 0) {
|
||||
reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_ACCESSOR_WRONG_ARGS,
|
||||
"getter", "no", "s");
|
||||
return NULL;
|
||||
}
|
||||
if (type == SETTER && fun->nargs != 1) {
|
||||
reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_ACCESSOR_WRONG_ARGS,
|
||||
"setter", "one", "");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if JS_HAS_EXPR_CLOSURES
|
||||
tt = tokenStream.getToken(TSF_OPERAND);
|
||||
TokenKind tt = tokenStream.getToken(TSF_OPERAND);
|
||||
if (tt != TOK_LC) {
|
||||
tokenStream.ungetToken();
|
||||
fun->flags |= JSFUN_EXPR_CLOSURE;
|
||||
|
@ -2828,7 +2845,7 @@ Parser::functionDef(uintN lambda, bool namePermitted)
|
|||
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_BODY);
|
||||
#endif
|
||||
|
||||
body = functionBody();
|
||||
JSParseNode *body = functionBody();
|
||||
if (!body)
|
||||
return NULL;
|
||||
|
||||
|
@ -2848,15 +2865,32 @@ Parser::functionDef(uintN lambda, bool namePermitted)
|
|||
#endif
|
||||
pn->pn_pos.end = tokenStream.currentToken().pos.end;
|
||||
|
||||
/*
|
||||
* Strict mode functions' arguments objects copy initial parameter values.
|
||||
* We create arguments objects lazily -- but that doesn't work for strict
|
||||
* mode functions where a parameter might be modified and arguments might
|
||||
* be accessed. For such functions we synthesize an access to arguments to
|
||||
* initialize it with the original parameter values.
|
||||
*/
|
||||
if (funtc.inStrictMode()) {
|
||||
/*
|
||||
* Fruit of the poisonous tree: eval forces eager arguments
|
||||
* creation in (strict mode) parent functions.
|
||||
*/
|
||||
if (outertc->inFunction() && outertc->inStrictMode()) {
|
||||
if (funtc.callsEval())
|
||||
outertc->noteCallsEval();
|
||||
}
|
||||
}
|
||||
|
||||
#if JS_HAS_DESTRUCTURING
|
||||
/*
|
||||
* If there were destructuring formal parameters, prepend the initializing
|
||||
* comma expression that we synthesized to body. If the body is a lexical
|
||||
* scope node, we must make a special TOK_SEQ node, to prepend the formal
|
||||
* parameter destructuring code without bracing the decompilation of the
|
||||
* function body's lexical scope.
|
||||
* comma expression that we synthesized to body. If the body is a return
|
||||
* node, we must make a special TOK_SEQ node, to prepend the destructuring
|
||||
* code without bracing the decompilation of the function body.
|
||||
*/
|
||||
if (list) {
|
||||
if (prolog) {
|
||||
if (body->pn_arity != PN_LIST) {
|
||||
JSParseNode *block;
|
||||
|
||||
|
@ -2870,13 +2904,13 @@ Parser::functionDef(uintN lambda, bool namePermitted)
|
|||
body = block;
|
||||
}
|
||||
|
||||
item = UnaryNode::create(outertc);
|
||||
JSParseNode *item = UnaryNode::create(outertc);
|
||||
if (!item)
|
||||
return NULL;
|
||||
|
||||
item->pn_type = TOK_SEMI;
|
||||
item->pn_pos.begin = item->pn_pos.end = body->pn_pos.begin;
|
||||
item->pn_kid = list;
|
||||
item->pn_kid = prolog;
|
||||
item->pn_next = body->pn_head;
|
||||
body->pn_head = item;
|
||||
if (body->pn_tail == &body->pn_head)
|
||||
|
@ -2905,7 +2939,8 @@ Parser::functionDef(uintN lambda, bool namePermitted)
|
|||
outertc->flags |= TCF_FUN_HEAVYWEIGHT;
|
||||
}
|
||||
|
||||
result = pn;
|
||||
JSParseNode *result = pn;
|
||||
JSOp op = JSOP_NOP;
|
||||
if (lambda != 0) {
|
||||
/*
|
||||
* ECMA ed. 3 standard: function expression, possibly anonymous.
|
||||
|
@ -2934,8 +2969,6 @@ Parser::functionDef(uintN lambda, bool namePermitted)
|
|||
* sub-statement.
|
||||
*/
|
||||
op = JSOP_DEFFUN;
|
||||
} else {
|
||||
op = JSOP_NOP;
|
||||
}
|
||||
|
||||
funbox->kids = funtc.functionList;
|
||||
|
@ -2955,7 +2988,7 @@ Parser::functionDef(uintN lambda, bool namePermitted)
|
|||
return NULL;
|
||||
|
||||
/* If the surrounding function is not strict code, reset the lexer. */
|
||||
if (!(outertc->flags & TCF_STRICT_MODE_CODE))
|
||||
if (!outertc->inStrictMode())
|
||||
tokenStream.setStrictMode(false);
|
||||
|
||||
return result;
|
||||
|
@ -2964,13 +2997,29 @@ Parser::functionDef(uintN lambda, bool namePermitted)
|
|||
JSParseNode *
|
||||
Parser::functionStmt()
|
||||
{
|
||||
return functionDef(0, true);
|
||||
JSAtom *name = NULL;
|
||||
if (tokenStream.getToken(TSF_KEYWORD_IS_NAME) == TOK_NAME) {
|
||||
name = tokenStream.currentToken().t_atom;
|
||||
} else {
|
||||
if (context->options & JSOPTION_ANONFUNFIX) {
|
||||
/* Extension: accept unnamed function expressions as statements. */
|
||||
reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
tokenStream.ungetToken();
|
||||
}
|
||||
return functionDef(name, GENERAL, 0);
|
||||
}
|
||||
|
||||
JSParseNode *
|
||||
Parser::functionExpr()
|
||||
{
|
||||
return functionDef(JSFUN_LAMBDA, true);
|
||||
JSAtom *name = NULL;
|
||||
if (tokenStream.getToken(TSF_KEYWORD_IS_NAME) == TOK_NAME)
|
||||
name = tokenStream.currentToken().t_atom;
|
||||
else
|
||||
tokenStream.ungetToken();
|
||||
return functionDef(name, GENERAL, JSFUN_LAMBDA);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3514,7 +3563,8 @@ NoteLValue(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, uintN dflag = PND_
|
|||
|
||||
pn->pn_dflags |= dflag;
|
||||
|
||||
if (pn->pn_atom == cx->runtime->atomState.argumentsAtom)
|
||||
JSAtom *lname = pn->pn_atom;
|
||||
if (lname == cx->runtime->atomState.argumentsAtom)
|
||||
tc->flags |= TCF_FUN_HEAVYWEIGHT;
|
||||
}
|
||||
|
||||
|
@ -5629,15 +5679,6 @@ Parser::statement()
|
|||
return MatchOrInsertSemicolon(context, &tokenStream) ? pn : NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
NoteArgumentsUse(JSTreeContext *tc)
|
||||
{
|
||||
JS_ASSERT(tc->inFunction());
|
||||
tc->flags |= TCF_FUN_USES_ARGUMENTS;
|
||||
if (tc->funbox)
|
||||
tc->funbox->node->pn_dflags |= PND_FUNARG;
|
||||
}
|
||||
|
||||
JSParseNode *
|
||||
Parser::variables(bool inLetHead)
|
||||
{
|
||||
|
@ -5803,7 +5844,7 @@ Parser::variables(bool inLetHead)
|
|||
|
||||
if (tc->inFunction() &&
|
||||
atom == context->runtime->atomState.argumentsAtom) {
|
||||
NoteArgumentsUse(tc);
|
||||
tc->noteArgumentsUse();
|
||||
if (!let)
|
||||
tc->flags |= TCF_FUN_HEAVYWEIGHT;
|
||||
}
|
||||
|
@ -7005,6 +7046,7 @@ Parser::memberExpr(JSBool allowCallSyntax)
|
|||
if (pn->pn_atom == context->runtime->atomState.evalAtom) {
|
||||
/* Select JSOP_EVAL and flag tc as heavyweight. */
|
||||
pn2->pn_op = JSOP_EVAL;
|
||||
tc->noteCallsEval();
|
||||
tc->flags |= TCF_FUN_HEAVYWEIGHT;
|
||||
}
|
||||
} else if (pn->pn_op == JSOP_GETPROP) {
|
||||
|
@ -7838,10 +7880,9 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot)
|
|||
* ARRAYPUSH node after we parse the rest of the comprehension.
|
||||
*/
|
||||
pnexp = pn->last();
|
||||
JS_ASSERT(pn->pn_count == 1 || pn->pn_count == 2);
|
||||
pn->pn_tail = (--pn->pn_count == 1)
|
||||
? &pn->pn_head->pn_next
|
||||
: &pn->pn_head;
|
||||
JS_ASSERT(pn->pn_count == 1);
|
||||
pn->pn_count = 0;
|
||||
pn->pn_tail = &pn->pn_head;
|
||||
*pn->pn_tail = NULL;
|
||||
|
||||
pntop = comprehensionTail(pnexp, pn->pn_blockid,
|
||||
|
@ -7936,9 +7977,8 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot)
|
|||
goto property_name;
|
||||
}
|
||||
|
||||
/* We have to fake a 'function' token here. */
|
||||
tokenStream.mungeCurrentToken(TOK_FUNCTION, JSOP_NOP);
|
||||
pn2 = functionDef(JSFUN_LAMBDA, false);
|
||||
/* NB: Getter function in { get x(){} } is unnamed. */
|
||||
pn2 = functionDef(NULL, op == JSOP_SETTER ? SETTER : GETTER, JSFUN_LAMBDA);
|
||||
pn2 = JSParseNode::newBinaryOrAppend(TOK_COLON, op, pn3, pn2, tc);
|
||||
goto skip;
|
||||
}
|
||||
|
@ -8154,7 +8194,7 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot)
|
|||
* a reference of the form foo.arguments, which ancient code may
|
||||
* still use instead of arguments (more hate).
|
||||
*/
|
||||
NoteArgumentsUse(tc);
|
||||
tc->noteArgumentsUse();
|
||||
|
||||
/*
|
||||
* Bind early to JSOP_ARGUMENTS to relieve later code from having
|
||||
|
|
|
@ -69,7 +69,10 @@ JS_BEGIN_EXTERN_C
|
|||
* pn_body: TOK_UPVARS if the function's source body
|
||||
* depends on outer names, else TOK_ARGSBODY
|
||||
* if formal parameters, else TOK_LC node for
|
||||
* function body statements
|
||||
* function body statements, else TOK_RETURN
|
||||
* for expression closure, else TOK_SEQ for
|
||||
* expression closure with destructured
|
||||
* formal parameters
|
||||
* pn_cookie: static level and var index for function
|
||||
* pn_dflags: PND_* definition/use flags (see below)
|
||||
* pn_blockid: block id number
|
||||
|
@ -84,7 +87,10 @@ JS_BEGIN_EXTERN_C
|
|||
*
|
||||
* <Statements>
|
||||
* TOK_LC list pn_head: list of pn_count statements
|
||||
* TOK_IF ternary pn_kid1: cond, pn_kid2: then, pn_kid3: else or null
|
||||
* TOK_IF ternary pn_kid1: cond, pn_kid2: then, pn_kid3: else or null.
|
||||
* In body of a comprehension or desugared generator
|
||||
* expression, pn_kid2 is TOK_YIELD, TOK_ARRAYPUSH,
|
||||
* or (if the push was optimized away) empty TOK_LC.
|
||||
* TOK_SWITCH binary pn_left: discriminant
|
||||
* pn_right: list of TOK_CASE nodes, with at most one
|
||||
* TOK_DEFAULT node, or if there are let bindings
|
||||
|
@ -128,7 +134,7 @@ JS_BEGIN_EXTERN_C
|
|||
* pn_expr: initializer or null
|
||||
* each assignment node has
|
||||
* pn_left: TOK_NAME with pn_used true and
|
||||
* pn_lexdef (NOT pn_expr) set
|
||||
* pn_lexdef (NOT pn_expr) set
|
||||
* pn_right: initializer
|
||||
* TOK_RETURN unary pn_kid: return expr or null
|
||||
* TOK_SEMI unary pn_kid: expr or null statement
|
||||
|
@ -207,6 +213,9 @@ JS_BEGIN_EXTERN_C
|
|||
* TOK_PRIMARY nullary pn_op: JSOp bytecode
|
||||
*
|
||||
* <E4X node descriptions>
|
||||
* TOK_DEFAULT name pn_atom: default XML namespace string literal
|
||||
* TOK_FILTER binary pn_left: container expr, pn_right: filter expr
|
||||
* TOK_DBLDOT binary pn_left: container expr, pn_right: selector expr
|
||||
* TOK_ANYNAME nullary pn_op: JSOP_ANYNAME
|
||||
* pn_atom: cx->runtime->atomState.starAtom
|
||||
* TOK_AT unary pn_op: JSOP_TOATTRNAME; pn_kid attribute id/expr
|
||||
|
@ -220,11 +229,13 @@ JS_BEGIN_EXTERN_C
|
|||
* pn_head: start tag, content1, ... contentN, end tag
|
||||
* pn_count: 2 + N where N is number of content nodes
|
||||
* N may be > x.length() if {expr} embedded
|
||||
* After constant folding, these contents may be
|
||||
* concatenated into string nodes.
|
||||
* TOK_XMLLIST list XML list node
|
||||
* pn_head: content1, ... contentN
|
||||
* TOK_XMLSTAGO, list XML start, end, and point tag contents
|
||||
* TOK_XMLETAGC, pn_head: tag name or {expr}, ... XML attrs ...
|
||||
* TOK_XMLPTAGO
|
||||
* TOK_XMLETAGO, pn_head: tag name or {expr}, ... XML attrs ...
|
||||
* TOK_XMLPTAGC
|
||||
* TOK_XMLNAME nullary pn_atom: XML name, with no {expr} embedded
|
||||
* TOK_XMLNAME list pn_head: tag name or {expr}, ... name or {expr}
|
||||
* TOK_XMLATTR, nullary pn_atom: attribute value string; pn_op: JSOP_STRING
|
||||
|
@ -267,10 +278,10 @@ JS_BEGIN_EXTERN_C
|
|||
* TOK_LEXICALSCOPE name pn_op: JSOP_LEAVEBLOCK or JSOP_LEAVEBLOCKEXPR
|
||||
* pn_objbox: block object in JSObjectBox holder
|
||||
* pn_expr: block body
|
||||
* TOK_ARRAYCOMP list pn_head: list of pn_count (1 or 2) elements
|
||||
* if pn_count is 2, first element is #n=[...]
|
||||
* last element is block enclosing for loop(s)
|
||||
* and optionally if-guarded TOK_ARRAYPUSH
|
||||
* TOK_ARRAYCOMP list pn_count: 1
|
||||
* pn_head: list of 1 element, which is block
|
||||
* enclosing for loop(s) and optionally
|
||||
* if-guarded TOK_ARRAYPUSH
|
||||
* TOK_ARRAYPUSH unary pn_op: JSOP_ARRAYCOMP
|
||||
* pn_kid: array comprehension expression
|
||||
*/
|
||||
|
@ -458,9 +469,9 @@ public:
|
|||
#define PNX_DESTRUCT 0x200 /* destructuring special cases:
|
||||
1. shorthand syntax used, at present
|
||||
object destructuring ({x,y}) only;
|
||||
2. the first child of function body
|
||||
is code evaluating destructuring
|
||||
arguments */
|
||||
2. code evaluating destructuring
|
||||
arguments occurs before function
|
||||
body */
|
||||
#define PNX_HOLEY 0x400 /* array initialiser has holes */
|
||||
|
||||
uintN frameLevel() const {
|
||||
|
@ -532,6 +543,35 @@ public:
|
|||
pn_pos.begin.index + str->length() + 2 == pn_pos.end.index);
|
||||
}
|
||||
|
||||
#ifdef JS_HAS_GENERATOR_EXPRS
|
||||
/*
|
||||
* True if this node is a desugared generator expression.
|
||||
*/
|
||||
bool isGeneratorExpr() const {
|
||||
if (PN_TYPE(this) == js::TOK_LP) {
|
||||
JSParseNode *callee = this->pn_head;
|
||||
if (PN_TYPE(callee) == js::TOK_FUNCTION) {
|
||||
JSParseNode *body = (PN_TYPE(callee->pn_body) == js::TOK_UPVARS)
|
||||
? callee->pn_body->pn_tree
|
||||
: callee->pn_body;
|
||||
if (PN_TYPE(body) == js::TOK_LEXICALSCOPE)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
JSParseNode *generatorExpr() const {
|
||||
JS_ASSERT(isGeneratorExpr());
|
||||
JSParseNode *callee = this->pn_head;
|
||||
JSParseNode *body = PN_TYPE(callee->pn_body) == js::TOK_UPVARS
|
||||
? callee->pn_body->pn_tree
|
||||
: callee->pn_body;
|
||||
JS_ASSERT(PN_TYPE(body) == js::TOK_LEXICALSCOPE);
|
||||
return body->pn_expr;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Compute a pointer to the last element in a singly-linked list. NB: list
|
||||
* must be non-empty for correct PN_LAST usage -- this is asserted!
|
||||
|
@ -939,7 +979,7 @@ struct Parser : private js::AutoGCRooter
|
|||
{
|
||||
js::PodArrayZero(tempFreeList);
|
||||
setPrincipals(prin);
|
||||
JS_ASSERT_IF(cfp, cfp->script);
|
||||
JS_ASSERT_IF(cfp, cfp->hasScript());
|
||||
}
|
||||
|
||||
~Parser();
|
||||
|
@ -959,6 +999,11 @@ struct Parser : private js::AutoGCRooter
|
|||
|
||||
void setPrincipals(JSPrincipals *prin);
|
||||
|
||||
const char *getFilename()
|
||||
{
|
||||
return tokenStream.getFilename();
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a top-level JS script.
|
||||
*/
|
||||
|
@ -1033,8 +1078,13 @@ private:
|
|||
* Additional JS parsers.
|
||||
*/
|
||||
bool recognizeDirectivePrologue(JSParseNode *pn);
|
||||
|
||||
enum FunctionType { GETTER, SETTER, GENERAL };
|
||||
bool functionArguments(JSTreeContext &funtc, JSFunctionBox *funbox, JSFunction *fun,
|
||||
JSParseNode **list);
|
||||
JSParseNode *functionBody();
|
||||
JSParseNode *functionDef(uintN lambda, bool namePermitted);
|
||||
JSParseNode *functionDef(JSAtom *name, FunctionType type, uintN lambda);
|
||||
|
||||
JSParseNode *condition();
|
||||
JSParseNode *comprehensionTail(JSParseNode *kid, uintN blockid,
|
||||
js::TokenKind type = js::TOK_SEMI, JSOp op = JSOP_NOP);
|
||||
|
|
|
@ -128,7 +128,7 @@ PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, uintN protoI
|
|||
* opcode format flags.
|
||||
*/
|
||||
pc = cx->regs->pc;
|
||||
op = js_GetOpcode(cx, cx->fp->script, pc);
|
||||
op = js_GetOpcode(cx, cx->fp->getScript(), pc);
|
||||
cs = &js_CodeSpec[op];
|
||||
kshape = 0;
|
||||
|
||||
|
@ -317,7 +317,7 @@ GetAtomFromBytecode(JSContext *cx, jsbytecode *pc, JSOp op, const JSCodeSpec &cs
|
|||
|
||||
ptrdiff_t pcoff = (JOF_TYPE(cs.format) == JOF_SLOTATOM) ? SLOTNO_LEN : 0;
|
||||
JSAtom *atom;
|
||||
GET_ATOM_FROM_BYTECODE(cx->fp->script, pc, pcoff, atom);
|
||||
GET_ATOM_FROM_BYTECODE(cx->fp->getScript(), pc, pcoff, atom);
|
||||
return atom;
|
||||
}
|
||||
|
||||
|
@ -329,10 +329,11 @@ PropertyCache::fullTest(JSContext *cx, jsbytecode *pc, JSObject **objp, JSObject
|
|||
uint32 vcap;
|
||||
|
||||
JS_ASSERT(this == &JS_PROPERTY_CACHE(cx));
|
||||
JS_ASSERT(uintN((cx->fp->imacpc ? cx->fp->imacpc : pc) - cx->fp->script->code)
|
||||
< cx->fp->script->length);
|
||||
JS_ASSERT(
|
||||
uintN((cx->fp->hasIMacroPC() ? cx->fp->getIMacroPC() : pc) - cx->fp->getScript()->code)
|
||||
< cx->fp->getScript()->length);
|
||||
|
||||
JSOp op = js_GetOpcode(cx, cx->fp->script, pc);
|
||||
JSOp op = js_GetOpcode(cx, cx->fp->getScript(), pc);
|
||||
const JSCodeSpec &cs = js_CodeSpec[op];
|
||||
|
||||
obj = *objp;
|
||||
|
|
|
@ -103,6 +103,8 @@ JS_PROTO(Float32Array, 34, js_InitTypedArrayClasses)
|
|||
JS_PROTO(Float64Array, 35, js_InitTypedArrayClasses)
|
||||
JS_PROTO(Uint8ClampedArray, 36, js_InitTypedArrayClasses)
|
||||
JS_PROTO(Proxy, 37, js_InitProxyClass)
|
||||
JS_PROTO(Reflect, 38, js_InitReflectClass)
|
||||
JS_PROTO(ASTNode, 39, js_InitReflectClass)
|
||||
|
||||
#undef XML_INIT
|
||||
#undef NAMESPACE_INIT
|
||||
|
|
|
@ -103,7 +103,6 @@ typedef struct JSThread JSThread;
|
|||
typedef struct JSThreadData JSThreadData;
|
||||
typedef struct JSTreeContext JSTreeContext;
|
||||
typedef struct JSTryNote JSTryNote;
|
||||
typedef struct JSWeakRoots JSWeakRoots;
|
||||
|
||||
/* Friend "Advanced API" typedefs. */
|
||||
typedef struct JSAtom JSAtom;
|
||||
|
|
|
@ -186,7 +186,7 @@ TraceRecorder::downSnapshot(FrameInfo* downFrame)
|
|||
exit->numStackSlotsBelowCurrentFrame = cx->fp->down->argv ?
|
||||
nativeStackOffset(&cx->fp->argv[-2]) / sizeof(double) : 0;
|
||||
exit->exitType = UNSTABLE_LOOP_EXIT;
|
||||
exit->block = cx->fp->down->blockChain;
|
||||
exit->block = cx->fp->down->maybeBlockChain();
|
||||
exit->pc = downFrame->pc + JSOP_CALL_LENGTH;
|
||||
exit->imacpc = NULL;
|
||||
exit->sp_adj = ((downPostSlots + 1) * sizeof(double)) - tree->nativeStackBase;
|
||||
|
@ -213,7 +213,7 @@ JS_REQUIRES_STACK AbortableRecordingStatus
|
|||
TraceRecorder::upRecursion()
|
||||
{
|
||||
JS_ASSERT((JSOp)*cx->fp->down->savedPC == JSOP_CALL);
|
||||
JS_ASSERT(js_CodeSpec[js_GetOpcode(cx, cx->fp->down->script,
|
||||
JS_ASSERT(js_CodeSpec[js_GetOpcode(cx, cx->fp->down->getScript(),
|
||||
cx->fp->down->savedPC)].length == JSOP_CALL_LENGTH);
|
||||
|
||||
JS_ASSERT(callDepth == 0);
|
||||
|
@ -390,7 +390,7 @@ JS_REQUIRES_STACK AbortableRecordingStatus
|
|||
TraceRecorder::slurpDownFrames(jsbytecode* return_pc)
|
||||
{
|
||||
/* Missing - no go */
|
||||
if (cx->fp->argc != cx->fp->fun->nargs)
|
||||
if (cx->fp->argc != cx->fp->getArgumentCount())
|
||||
RETURN_STOP_A("argc != nargs");
|
||||
|
||||
LIns* argv_ins;
|
||||
|
@ -432,9 +432,9 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc)
|
|||
guard(true,
|
||||
lir->ins2(LIR_eqp,
|
||||
addName(lir->insLoad(LIR_ldp, fp_ins,
|
||||
offsetof(JSStackFrame, script), ACCSET_OTHER),
|
||||
JSStackFrame::offsetScript(), ACCSET_OTHER),
|
||||
"script"),
|
||||
INS_CONSTPTR(cx->fp->down->script)),
|
||||
INS_CONSTPTR(cx->fp->down->getScript())),
|
||||
RECURSIVE_LOOP_EXIT);
|
||||
}
|
||||
|
||||
|
@ -591,19 +591,19 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc)
|
|||
/* this */
|
||||
slurpSlot(argv_ins, -1 * ptrdiff_t(sizeof(Value)), &fp->argv[-1], &info);
|
||||
/* args[0..n] */
|
||||
for (unsigned i = 0; i < JS_MAX(fp->argc, fp->fun->nargs); i++)
|
||||
for (unsigned i = 0; i < JS_MAX(fp->argc, fp->getArgumentCount()); i++)
|
||||
slurpSlot(argv_ins, i * sizeof(Value), &fp->argv[i], &info);
|
||||
/* argsobj */
|
||||
slurpFrameObjPtrSlot(fp_ins, JSStackFrame::offsetArgsObj(), fp->addressArgsObj(), &info);
|
||||
/* scopeChain */
|
||||
slurpFrameObjPtrSlot(fp_ins, offsetof(JSStackFrame, scopeChain), &fp->scopeChain, &info);
|
||||
slurpFrameObjPtrSlot(fp_ins, JSStackFrame::offsetScopeChain(), fp->addressScopeChain(), &info);
|
||||
/* vars */
|
||||
LIns* slots_ins = addName(lir->ins2(LIR_addp, fp_ins, INS_CONSTWORD(sizeof(JSStackFrame))),
|
||||
"slots");
|
||||
for (unsigned i = 0; i < fp->script->nfixed; i++)
|
||||
for (unsigned i = 0; i < fp->getFixedCount(); i++)
|
||||
slurpSlot(slots_ins, i * sizeof(Value), &fp->slots()[i], &info);
|
||||
/* stack vals */
|
||||
unsigned nfixed = fp->script->nfixed;
|
||||
unsigned nfixed = fp->getFixedCount();
|
||||
Value* stack = fp->base();
|
||||
LIns* stack_ins = addName(lir->ins2(LIR_addp,
|
||||
slots_ins,
|
||||
|
@ -614,7 +614,7 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc)
|
|||
if (anchor && anchor->exitType == RECURSIVE_SLURP_FAIL_EXIT)
|
||||
limit--;
|
||||
else
|
||||
limit -= fp->fun->nargs + 2;
|
||||
limit -= fp->getArgumentCount() + 2;
|
||||
for (size_t i = 0; i < limit; i++)
|
||||
slurpSlot(stack_ins, i * sizeof(Value), &stack[i], &info);
|
||||
|
||||
|
@ -673,14 +673,15 @@ JS_REQUIRES_STACK AbortableRecordingStatus
|
|||
TraceRecorder::downRecursion()
|
||||
{
|
||||
JSStackFrame* fp = cx->fp;
|
||||
if ((jsbytecode*)fragment->ip < fp->script->code ||
|
||||
(jsbytecode*)fragment->ip >= fp->script->code + fp->script->length) {
|
||||
JSScript *script = fp->getScript();
|
||||
if ((jsbytecode*)fragment->ip < script->code ||
|
||||
(jsbytecode*)fragment->ip >= script->code + script->length) {
|
||||
RETURN_STOP_A("inner recursive call must compile first");
|
||||
}
|
||||
|
||||
/* Adjust the stack by the budget the down-frame needs. */
|
||||
int slots = NativeStackSlots(cx, 1) - NativeStackSlots(cx, 0);
|
||||
JS_ASSERT(unsigned(slots) == NativeStackSlots(cx, 1) - fp->argc - 2 - fp->script->nfixed - 2);
|
||||
JS_ASSERT(unsigned(slots) == NativeStackSlots(cx, 1) - fp->argc - 2 - fp->getFixedCount() - 2);
|
||||
|
||||
/* Guard that there is enough stack space. */
|
||||
JS_ASSERT(tree->maxNativeStackSlots >= tree->nativeStackBase / sizeof(double));
|
||||
|
@ -722,11 +723,11 @@ TraceRecorder::downRecursion()
|
|||
* tree pc.
|
||||
*/
|
||||
VMSideExit* exit;
|
||||
if ((jsbytecode*)fragment->root->ip == fp->script->code)
|
||||
if ((jsbytecode*)fragment->root->ip == script->code)
|
||||
exit = snapshot(UNSTABLE_LOOP_EXIT);
|
||||
else
|
||||
exit = snapshot(RECURSIVE_UNLINKED_EXIT);
|
||||
exit->recursive_pc = fp->script->code;
|
||||
exit->recursive_pc = script->code;
|
||||
debug_only_print0(LC_TMTracer, "Compiling down-recursive function call.\n");
|
||||
JS_ASSERT(tree->recursion != Recursion_Disallowed);
|
||||
tree->recursion = Recursion_Detected;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,138 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=99 ft=cpp:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
|
||||
* June 12, 2009.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Corporation.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dave Herman <dherman@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
* JS reflection package.
|
||||
*/
|
||||
#ifndef jsreflect_h___
|
||||
#define jsreflect_h___
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "jspubtd.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
enum ASTType {
|
||||
AST_ERROR = -1,
|
||||
#define ASTDEF(ast, str) ast,
|
||||
#include "jsast.tbl"
|
||||
#undef ASTDEF
|
||||
AST_LIMIT
|
||||
};
|
||||
|
||||
enum AssignmentOperator {
|
||||
AOP_ERR = -1,
|
||||
|
||||
/* assign */
|
||||
AOP_ASSIGN = 0,
|
||||
/* operator-assign */
|
||||
AOP_PLUS, AOP_MINUS, AOP_STAR, AOP_DIV, AOP_MOD,
|
||||
/* shift-assign */
|
||||
AOP_LSH, AOP_RSH, AOP_URSH,
|
||||
/* binary */
|
||||
AOP_BITOR, AOP_BITXOR, AOP_BITAND,
|
||||
|
||||
AOP_LIMIT
|
||||
};
|
||||
|
||||
enum BinaryOperator {
|
||||
BINOP_ERR = -1,
|
||||
|
||||
/* eq */
|
||||
BINOP_EQ = 0, BINOP_NE, BINOP_STRICTEQ, BINOP_STRICTNE,
|
||||
/* rel */
|
||||
BINOP_LT, BINOP_LE, BINOP_GT, BINOP_GE,
|
||||
/* shift */
|
||||
BINOP_LSH, BINOP_RSH, BINOP_URSH,
|
||||
/* arithmetic */
|
||||
BINOP_PLUS, BINOP_MINUS, BINOP_STAR, BINOP_DIV, BINOP_MOD,
|
||||
/* binary */
|
||||
BINOP_BITOR, BINOP_BITXOR, BINOP_BITAND,
|
||||
/* misc */
|
||||
BINOP_IN, BINOP_INSTANCEOF,
|
||||
/* xml */
|
||||
BINOP_DBLDOT,
|
||||
|
||||
BINOP_LIMIT
|
||||
};
|
||||
|
||||
enum UnaryOperator {
|
||||
UNOP_ERR = -1,
|
||||
|
||||
UNOP_DELETE = 0,
|
||||
UNOP_NEG,
|
||||
UNOP_POS,
|
||||
UNOP_NOT,
|
||||
UNOP_BITNOT,
|
||||
UNOP_TYPEOF,
|
||||
UNOP_VOID,
|
||||
|
||||
UNOP_LIMIT
|
||||
};
|
||||
|
||||
enum VarDeclKind {
|
||||
VARDECL_ERR = -1,
|
||||
VARDECL_VAR = 0,
|
||||
VARDECL_CONST,
|
||||
VARDECL_LET,
|
||||
VARDECL_LIMIT
|
||||
};
|
||||
|
||||
enum PropKind {
|
||||
PROP_ERR = -1,
|
||||
PROP_INIT = 0,
|
||||
PROP_GETTER,
|
||||
PROP_SETTER,
|
||||
PROP_LIMIT
|
||||
};
|
||||
|
||||
extern char const *aopNames[];
|
||||
extern char const *binopNames[];
|
||||
extern char const *unopNames[];
|
||||
extern char const *nodeTypeNames[];
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
extern js::Class js_ReflectClass;
|
||||
|
||||
extern JSObject *
|
||||
js_InitReflectClass(JSContext *cx, JSObject *obj);
|
||||
|
||||
|
||||
#endif /* jsreflect_h___ */
|
|
@ -176,7 +176,7 @@ js_IsIdentifier(JSString *str)
|
|||
|
||||
/* Initialize members that aren't initialized in |init|. */
|
||||
TokenStream::TokenStream(JSContext *cx)
|
||||
: cx(cx), tokens(), cursor(), lookahead(), ungetpos(), ungetbuf(), flags(),
|
||||
: cx(cx), tokens(), cursor(), lookahead(), flags(),
|
||||
linepos(), lineposNext(), file(), listenerTSData(), tokenbuf(cx)
|
||||
{}
|
||||
|
||||
|
@ -192,8 +192,8 @@ TokenStream::init(const jschar *base, size_t length, FILE *fp, const char *fn, u
|
|||
JS_ASSERT_IF(fp, !base);
|
||||
JS_ASSERT_IF(!base, length == 0);
|
||||
size_t nb = fp
|
||||
? 2 * LINE_LIMIT * sizeof(jschar)
|
||||
: LINE_LIMIT * sizeof(jschar);
|
||||
? (UNGET_LIMIT + 2 * LINE_LIMIT) * sizeof(jschar) /* see below */
|
||||
: (UNGET_LIMIT + 1 * LINE_LIMIT) * sizeof(jschar);
|
||||
JS_ARENA_ALLOCATE_CAST(buf, jschar *, &cx->tempPool, nb);
|
||||
if (!buf) {
|
||||
js_ReportOutOfScriptQuota(cx);
|
||||
|
@ -204,18 +204,38 @@ TokenStream::init(const jschar *base, size_t length, FILE *fp, const char *fn, u
|
|||
/* Initialize members. */
|
||||
filename = fn;
|
||||
lineno = ln;
|
||||
linebuf.base = linebuf.limit = linebuf.ptr = buf;
|
||||
/*
|
||||
* Split 'buf' into 3 (ungetbuf, linebuf, userbuf) or 2 (ungetbuf, linebuf).
|
||||
* ungetbuf is empty and fills backwards. linebuf is empty and fills forwards.
|
||||
*/
|
||||
ungetbuf.base = buf;
|
||||
ungetbuf.limit = ungetbuf.ptr = buf + UNGET_LIMIT;
|
||||
linebuf.base = linebuf.limit = linebuf.ptr = buf + UNGET_LIMIT;
|
||||
if (fp) {
|
||||
file = fp;
|
||||
userbuf.base = buf + LINE_LIMIT;
|
||||
userbuf.base = buf + UNGET_LIMIT + LINE_LIMIT;
|
||||
userbuf.ptr = userbuf.limit = userbuf.base + LINE_LIMIT;
|
||||
} else {
|
||||
userbuf.base = (jschar *)base;
|
||||
userbuf.limit = (jschar *)base + length;
|
||||
userbuf.ptr = (jschar *)base;
|
||||
}
|
||||
currbuf = &linebuf;
|
||||
listener = cx->debugHooks->sourceHandler;
|
||||
listenerData = cx->debugHooks->sourceHandlerData;
|
||||
/* See getCharFillLinebuf() for an explanation of maybeEOL[]. */
|
||||
memset(maybeEOL, 0, sizeof(maybeEOL));
|
||||
maybeEOL['\n'] = true;
|
||||
maybeEOL['\r'] = true;
|
||||
maybeEOL[LINE_SEPARATOR & 0xff] = true;
|
||||
maybeEOL[PARA_SEPARATOR & 0xff] = true;
|
||||
/* See getTokenInternal() for an explanation of maybeStrSpecial[]. */
|
||||
memset(maybeStrSpecial, 0, sizeof(maybeStrSpecial));
|
||||
maybeStrSpecial['"'] = true;
|
||||
maybeStrSpecial['\''] = true;
|
||||
maybeStrSpecial['\n'] = true;
|
||||
maybeStrSpecial['\\'] = true;
|
||||
maybeStrSpecial[EOF & 0xff] = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -352,11 +372,21 @@ TokenStream::getCharFillLinebuf()
|
|||
i++;
|
||||
|
||||
/*
|
||||
* Normalize the copied jschar if it was a newline. Try to
|
||||
* prevent multiple tests on most characters by first
|
||||
* filtering out characters that aren't 000x or 202x.
|
||||
* Normalize the copied jschar if it was a newline. We need to detect
|
||||
* any of these four characters: '\n' (0x000a), '\r' (0x000d),
|
||||
* LINE_SEPARATOR (0x2028), PARA_SEPARATOR (0x2029). Testing for each
|
||||
* one in turn is slow, so we use a single probabilistic check, and if
|
||||
* that succeeds, test for them individually.
|
||||
*
|
||||
* We use the bottom 8 bits to index into a lookup table, succeeding
|
||||
* when d&0xff is 0xa, 0xd, 0x28 or 0x29. Among ASCII chars (which
|
||||
* are by the far the most common) this gives false positives for '('
|
||||
* (0x0028) and ')' (0x0029). We could avoid those by incorporating
|
||||
* the 13th bit of d into the lookup, but that requires extra shifting
|
||||
* and masking and isn't worthwhile. See TokenStream::init() for the
|
||||
* initialization of the relevant entries in the table.
|
||||
*/
|
||||
if ((d & 0xDFD0) == 0) {
|
||||
if (maybeEOL[d & 0xff]) {
|
||||
if (d == '\n') {
|
||||
break;
|
||||
}
|
||||
|
@ -399,15 +429,20 @@ TokenStream::getCharFillLinebuf()
|
|||
* This gets the next char, normalizing all EOL sequences to '\n' as it goes.
|
||||
*/
|
||||
int32
|
||||
TokenStream::getChar()
|
||||
TokenStream::getCharSlowCase()
|
||||
{
|
||||
int32 c;
|
||||
if (ungetpos != 0) {
|
||||
c = ungetbuf[--ungetpos];
|
||||
} else if (linebuf.ptr == linebuf.limit) {
|
||||
c = getCharFillLinebuf();
|
||||
if (currbuf->ptr == currbuf->limit - 1) {
|
||||
/* Last char of currbuf. Switch to linebuf if we're in ungetbuf. */
|
||||
c = *currbuf->ptr++;
|
||||
if (currbuf == &ungetbuf)
|
||||
currbuf = &linebuf;
|
||||
|
||||
} else {
|
||||
c = *linebuf.ptr++;
|
||||
/* One past the last char of currbuf; can only happen for linebuf. */
|
||||
JS_ASSERT(currbuf->ptr == currbuf->limit);
|
||||
JS_ASSERT(currbuf == &linebuf);
|
||||
c = getCharFillLinebuf();
|
||||
}
|
||||
if (c == '\n')
|
||||
lineno++;
|
||||
|
@ -419,10 +454,14 @@ TokenStream::ungetChar(int32 c)
|
|||
{
|
||||
if (c == EOF)
|
||||
return;
|
||||
JS_ASSERT(ungetpos < JS_ARRAY_LENGTH(ungetbuf));
|
||||
if (c == '\n')
|
||||
JS_ASSERT(ungetbuf.ptr >= ungetbuf.base);
|
||||
if (c == '\n') {
|
||||
/* We can only unget one '\n', and it must be the first ungotten char. */
|
||||
JS_ASSERT(ungetbuf.ptr == ungetbuf.limit);
|
||||
lineno--;
|
||||
ungetbuf[ungetpos++] = (jschar)c;
|
||||
}
|
||||
*(--ungetbuf.ptr) = (jschar)c;
|
||||
currbuf = &ungetbuf;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -816,7 +855,7 @@ TokenStream::newToken(ptrdiff_t adjust)
|
|||
cursor = (cursor + 1) & ntokensMask;
|
||||
Token *tp = &tokens[cursor];
|
||||
tp->ptr = linebuf.ptr + adjust;
|
||||
tp->pos.begin.index = linepos + (tp->ptr - linebuf.base) - ungetpos;
|
||||
tp->pos.begin.index = linepos + (tp->ptr - linebuf.base) - (ungetbuf.limit - ungetbuf.ptr);
|
||||
tp->pos.begin.lineno = tp->pos.end.lineno = lineno;
|
||||
return tp;
|
||||
}
|
||||
|
@ -1184,72 +1223,81 @@ TokenStream::getTokenInternal()
|
|||
if (c == '"' || c == '\'') {
|
||||
qc = c;
|
||||
tokenbuf.clear();
|
||||
while ((c = getChar()) != qc) {
|
||||
if (c == '\n' || c == EOF) {
|
||||
ungetChar(c);
|
||||
ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR,
|
||||
JSMSG_UNTERMINATED_STRING);
|
||||
goto error;
|
||||
}
|
||||
if (c == '\\') {
|
||||
switch (c = getChar()) {
|
||||
case 'b': c = '\b'; break;
|
||||
case 'f': c = '\f'; break;
|
||||
case 'n': c = '\n'; break;
|
||||
case 'r': c = '\r'; break;
|
||||
case 't': c = '\t'; break;
|
||||
case 'v': c = '\v'; break;
|
||||
|
||||
default:
|
||||
if ('0' <= c && c < '8') {
|
||||
int32 val = JS7_UNDEC(c);
|
||||
|
||||
c = peekChar();
|
||||
/* Strict mode code allows only \0, then a non-digit. */
|
||||
if (val != 0 || JS7_ISDEC(c)) {
|
||||
if (!ReportStrictModeError(cx, this, NULL, NULL,
|
||||
JSMSG_DEPRECATED_OCTAL)) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if ('0' <= c && c < '8') {
|
||||
val = 8 * val + JS7_UNDEC(c);
|
||||
getChar();
|
||||
c = peekChar();
|
||||
if ('0' <= c && c < '8') {
|
||||
int32 save = val;
|
||||
val = 8 * val + JS7_UNDEC(c);
|
||||
if (val <= 0377)
|
||||
getChar();
|
||||
else
|
||||
val = save;
|
||||
}
|
||||
}
|
||||
|
||||
c = (jschar)val;
|
||||
} else if (c == 'u') {
|
||||
jschar cp[4];
|
||||
if (peekChars(4, cp) &&
|
||||
JS7_ISHEX(cp[0]) && JS7_ISHEX(cp[1]) &&
|
||||
JS7_ISHEX(cp[2]) && JS7_ISHEX(cp[3])) {
|
||||
c = (((((JS7_UNHEX(cp[0]) << 4)
|
||||
+ JS7_UNHEX(cp[1])) << 4)
|
||||
+ JS7_UNHEX(cp[2])) << 4)
|
||||
+ JS7_UNHEX(cp[3]);
|
||||
skipChars(4);
|
||||
}
|
||||
} else if (c == 'x') {
|
||||
jschar cp[2];
|
||||
if (peekChars(2, cp) &&
|
||||
JS7_ISHEX(cp[0]) && JS7_ISHEX(cp[1])) {
|
||||
c = (JS7_UNHEX(cp[0]) << 4) + JS7_UNHEX(cp[1]);
|
||||
skipChars(2);
|
||||
}
|
||||
} else if (c == '\n') {
|
||||
/* ECMA follows C by removing escaped newlines. */
|
||||
continue;
|
||||
}
|
||||
while (true) {
|
||||
c = getChar();
|
||||
/*
|
||||
* We need to detect any of these four chars: " or ', \n, \\,
|
||||
* EOF. We use maybeStrSpecial[] in a manner similar to
|
||||
* maybeEOL[], see above.
|
||||
*/
|
||||
if (maybeStrSpecial[c & 0xff]) {
|
||||
if (c == qc) {
|
||||
break;
|
||||
} else if (c == '\\') {
|
||||
switch (c = getChar()) {
|
||||
case 'b': c = '\b'; break;
|
||||
case 'f': c = '\f'; break;
|
||||
case 'n': c = '\n'; break;
|
||||
case 'r': c = '\r'; break;
|
||||
case 't': c = '\t'; break;
|
||||
case 'v': c = '\v'; break;
|
||||
|
||||
default:
|
||||
if ('0' <= c && c < '8') {
|
||||
int32 val = JS7_UNDEC(c);
|
||||
|
||||
c = peekChar();
|
||||
/* Strict mode code allows only \0, then a non-digit. */
|
||||
if (val != 0 || JS7_ISDEC(c)) {
|
||||
if (!ReportStrictModeError(cx, this, NULL, NULL,
|
||||
JSMSG_DEPRECATED_OCTAL)) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if ('0' <= c && c < '8') {
|
||||
val = 8 * val + JS7_UNDEC(c);
|
||||
getChar();
|
||||
c = peekChar();
|
||||
if ('0' <= c && c < '8') {
|
||||
int32 save = val;
|
||||
val = 8 * val + JS7_UNDEC(c);
|
||||
if (val <= 0377)
|
||||
getChar();
|
||||
else
|
||||
val = save;
|
||||
}
|
||||
}
|
||||
|
||||
c = (jschar)val;
|
||||
} else if (c == 'u') {
|
||||
jschar cp[4];
|
||||
if (peekChars(4, cp) &&
|
||||
JS7_ISHEX(cp[0]) && JS7_ISHEX(cp[1]) &&
|
||||
JS7_ISHEX(cp[2]) && JS7_ISHEX(cp[3])) {
|
||||
c = (((((JS7_UNHEX(cp[0]) << 4)
|
||||
+ JS7_UNHEX(cp[1])) << 4)
|
||||
+ JS7_UNHEX(cp[2])) << 4)
|
||||
+ JS7_UNHEX(cp[3]);
|
||||
skipChars(4);
|
||||
}
|
||||
} else if (c == 'x') {
|
||||
jschar cp[2];
|
||||
if (peekChars(2, cp) &&
|
||||
JS7_ISHEX(cp[0]) && JS7_ISHEX(cp[1])) {
|
||||
c = (JS7_UNHEX(cp[0]) << 4) + JS7_UNHEX(cp[1]);
|
||||
skipChars(2);
|
||||
}
|
||||
} else if (c == '\n') {
|
||||
/* ECMA follows C by removing escaped newlines. */
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (c == '\n' || c == EOF) {
|
||||
ungetChar(c);
|
||||
ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR,
|
||||
JSMSG_UNTERMINATED_STRING);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (!tokenbuf.append(c))
|
||||
|
@ -1800,7 +1848,7 @@ TokenStream::getTokenInternal()
|
|||
|
||||
eol_out:
|
||||
JS_ASSERT(tt < TOK_LIMIT);
|
||||
tp->pos.end.index = linepos + (linebuf.ptr - linebuf.base) - ungetpos;
|
||||
tp->pos.end.index = linepos + (linebuf.ptr - linebuf.base) - (ungetbuf.limit - ungetbuf.ptr);
|
||||
tp->type = tt;
|
||||
return tt;
|
||||
|
||||
|
|
|
@ -292,8 +292,10 @@ enum TokenStreamFlags
|
|||
#define t_atom2 u.p.atom2
|
||||
#define t_dval u.dval
|
||||
|
||||
const size_t LINE_LIMIT = 1024; /* logical line buffer size limit
|
||||
-- physical line length is unlimited */
|
||||
static const size_t LINE_LIMIT = 1024; /* logical line buffer size limit
|
||||
-- physical line length is unlimited */
|
||||
static const size_t UNGET_LIMIT = 6; /* maximum number of chars to unget at once
|
||||
-- for \uXXXX lookahead */
|
||||
|
||||
class TokenStream
|
||||
{
|
||||
|
@ -449,7 +451,21 @@ class TokenStream
|
|||
TokenKind getTokenInternal(); /* doesn't check for pushback or error flag. */
|
||||
int fillUserbuf();
|
||||
int32 getCharFillLinebuf();
|
||||
int32 getChar();
|
||||
|
||||
/* This gets the next char, normalizing all EOL sequences to '\n' as it goes. */
|
||||
JS_ALWAYS_INLINE int32 getChar() {
|
||||
int32 c;
|
||||
if (currbuf->ptr < currbuf->limit - 1) {
|
||||
/* Not yet the last char of currbuf, so it can't be a newline. Just get it. */
|
||||
c = *currbuf->ptr++;
|
||||
JS_ASSERT(c != '\n');
|
||||
} else {
|
||||
c = getCharSlowCase();
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int32 getCharSlowCase();
|
||||
void ungetChar(int32 c);
|
||||
Token *newToken(ptrdiff_t adjust);
|
||||
int32 getUnicodeEscape();
|
||||
|
@ -480,19 +496,21 @@ class TokenStream
|
|||
uintN cursor; /* index of last parsed token */
|
||||
uintN lookahead; /* count of lookahead tokens */
|
||||
uintN lineno; /* current line number */
|
||||
uintN ungetpos; /* next free char slot in ungetbuf */
|
||||
jschar ungetbuf[6]; /* at most 6, for \uXXXX lookahead */
|
||||
uintN flags; /* flags -- see above */
|
||||
uint32 linepos; /* linebuf offset in physical line */
|
||||
uint32 lineposNext; /* the next value of linepos */
|
||||
TokenBuf linebuf; /* line buffer for diagnostics */
|
||||
TokenBuf userbuf; /* user input buffer if !file */
|
||||
TokenBuf ungetbuf; /* buffer for ungetChar */
|
||||
TokenBuf *currbuf; /* the buffer getChar is currently using */
|
||||
const char *filename; /* input filename or null */
|
||||
FILE *file; /* stdio stream if reading from file */
|
||||
JSSourceHandler listener; /* callback for source; eg debugger */
|
||||
void *listenerData; /* listener 'this' data */
|
||||
void *listenerTSData;/* listener data for this TokenStream */
|
||||
JSCharBuffer tokenbuf; /* current token string buffer */
|
||||
bool maybeEOL[256]; /* probabilistic EOL lookup table */
|
||||
bool maybeStrSpecial[256];/* speeds up string scanning */
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
|
|
@ -1000,13 +1000,25 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
|
|||
{
|
||||
/*
|
||||
* We can probably use the immutable empty script singleton, just
|
||||
* one hard case (nupvars != 0) may stand in our way.
|
||||
* two hard cases (nupvars != 0, strict mode code) may stand in our
|
||||
* way.
|
||||
*/
|
||||
JSScript *empty = JSScript::emptyScript();
|
||||
|
||||
if (cg->flags & TCF_IN_FUNCTION) {
|
||||
fun = cg->fun;
|
||||
JS_ASSERT(FUN_INTERPRETED(fun) && !FUN_SCRIPT(fun));
|
||||
JS_ASSERT(fun->isInterpreted() && !FUN_SCRIPT(fun));
|
||||
if (cg->flags & TCF_STRICT_MODE_CODE) {
|
||||
/*
|
||||
* We can't use a script singleton for empty strict mode
|
||||
* functions because they have poison-pill caller and
|
||||
* arguments properties:
|
||||
*
|
||||
* function strict() { "use strict"; }
|
||||
* strict.caller; // calls [[ThrowTypeError]] function
|
||||
*/
|
||||
goto skip_empty;
|
||||
}
|
||||
if (fun->u.i.nupvars != 0) {
|
||||
/*
|
||||
* FIXME: upvar uses that were all optimized away may leave
|
||||
|
@ -1356,7 +1368,8 @@ js_GetSrcNoteCached(JSContext *cx, JSScript *script, jsbytecode *pc)
|
|||
uintN
|
||||
js_FramePCToLineNumber(JSContext *cx, JSStackFrame *fp)
|
||||
{
|
||||
return js_PCToLineNumber(cx, fp->script, fp->imacpc ? fp->imacpc : fp->pc(cx));
|
||||
return js_PCToLineNumber(cx, fp->getScript(),
|
||||
fp->hasIMacroPC() ? fp->getIMacroPC() : fp->pc(cx));
|
||||
}
|
||||
|
||||
uintN
|
||||
|
|
|
@ -495,7 +495,7 @@ struct JSString {
|
|||
}
|
||||
|
||||
#ifdef __SUNPRO_CC
|
||||
#pragma align 8 (__1cIJSStringPunitStringTable_, __1cIJSStringOintStringTable_)
|
||||
#pragma align 8 (__1cIJSStringPunitStringTable_, __1cIJSStringSlength2StringTable_, __1cIJSStringShundredStringTable_)
|
||||
#endif
|
||||
|
||||
static const SmallChar INVALID_SMALL_CHAR = -1;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1159,7 +1159,7 @@ class TraceRecorder
|
|||
JS_REQUIRES_STACK nanojit::LIns* makeNumberInt32(nanojit::LIns* f);
|
||||
JS_REQUIRES_STACK nanojit::LIns* stringify(const Value& v);
|
||||
|
||||
JS_REQUIRES_STACK nanojit::LIns* newArguments(nanojit::LIns* callee_ins);
|
||||
JS_REQUIRES_STACK nanojit::LIns* newArguments(nanojit::LIns* callee_ins, bool strict);
|
||||
|
||||
JS_REQUIRES_STACK bool canCallImacro() const;
|
||||
JS_REQUIRES_STACK RecordingStatus callImacro(jsbytecode* imacro);
|
||||
|
|
|
@ -261,6 +261,7 @@ typedef enum JSWhyMagic
|
|||
JS_FAST_CONSTRUCTOR, /* 'this' value for fast natives invoked with 'new' */
|
||||
JS_NO_CONSTANT, /* compiler sentinel value */
|
||||
JS_THIS_POISON, /* used in debug builds to catch tracing errors */
|
||||
JS_SERIALIZE_NO_NODE, /* an empty subnode in the AST serializer */
|
||||
JS_GENERIC_MAGIC /* for local use */
|
||||
} JSWhyMagic;
|
||||
|
||||
|
|
|
@ -381,7 +381,7 @@ JSCompartment::wrap(JSContext *cx, Value *vp)
|
|||
* we parent all wrappers to the global object in their home compartment.
|
||||
* This loses us some transparency, and is generally very cheesy.
|
||||
*/
|
||||
JSObject *global = cx->fp ? cx->fp->scopeChain->getGlobal() : cx->globalObject;
|
||||
JSObject *global = cx->fp ? cx->fp->getScopeChain()->getGlobal() : cx->globalObject;
|
||||
wrapper->setParent(global);
|
||||
return true;
|
||||
}
|
||||
|
@ -489,7 +489,7 @@ SetupFakeFrame(JSContext *cx, ExecuteFrameGuard &frame, JSFrameRegs ®s, JSObj
|
|||
JSStackFrame *fp = frame.getFrame();
|
||||
PodZero(fp); // fp->fun and fp->script are both NULL
|
||||
fp->argv = vp + 2;
|
||||
fp->scopeChain = obj->getGlobal();
|
||||
fp->setScopeChain(obj->getGlobal());
|
||||
fp->flags = JSFRAME_DUMMY;
|
||||
|
||||
regs.pc = NULL;
|
||||
|
|
|
@ -1716,14 +1716,14 @@ ParseXMLSource(JSContext *cx, JSString *src)
|
|||
xml = NULL;
|
||||
FrameRegsIter i(cx);
|
||||
for (; !i.done() && !i.pc(); ++i)
|
||||
JS_ASSERT(!i.fp()->script);
|
||||
JS_ASSERT(!i.fp()->hasScript());
|
||||
filename = NULL;
|
||||
lineno = 1;
|
||||
if (!i.done()) {
|
||||
JSStackFrame *fp = i.fp();
|
||||
op = (JSOp) *i.pc();
|
||||
if (op == JSOP_TOXML || op == JSOP_TOXMLLIST) {
|
||||
filename = fp->script->filename;
|
||||
filename = fp->getScript()->filename;
|
||||
lineno = js_FramePCToLineNumber(cx, fp);
|
||||
for (endp = srcp + srclen; srcp < endp; srcp++) {
|
||||
if (*srcp == '\n')
|
||||
|
@ -1735,7 +1735,7 @@ ParseXMLSource(JSContext *cx, JSString *src)
|
|||
{
|
||||
Parser parser(cx);
|
||||
if (parser.init(chars, length, NULL, filename, lineno)) {
|
||||
JSObject *scopeChain = js_GetTopStackFrame(cx)->scopeChain;
|
||||
JSObject *scopeChain = js_GetTopStackFrame(cx)->getScopeChain();
|
||||
JSParseNode *pn = parser.parseXMLText(scopeChain, false);
|
||||
uintN flags;
|
||||
if (pn && GetXMLSettingFlags(cx, &flags)) {
|
||||
|
@ -7227,7 +7227,7 @@ js_GetDefaultXMLNamespace(JSContext *cx, jsval *vp)
|
|||
fp = js_GetTopStackFrame(cx);
|
||||
|
||||
obj = NULL;
|
||||
for (tmp = fp->scopeChain; tmp; tmp = tmp->getParent()) {
|
||||
for (tmp = fp->getScopeChain(); tmp; tmp = tmp->getParent()) {
|
||||
Class *clasp = tmp->getClass();
|
||||
if (clasp == &js_BlockClass || clasp == &js_WithClass)
|
||||
continue;
|
||||
|
@ -7440,7 +7440,7 @@ js_FindXMLProperty(JSContext *cx, const Value &nameval, JSObject **objp, jsid *i
|
|||
if (!IsFunctionQName(cx, qn, &funid))
|
||||
return JS_FALSE;
|
||||
|
||||
obj = js_GetTopStackFrame(cx)->scopeChain;
|
||||
obj = js_GetTopStackFrame(cx)->getScopeChain();
|
||||
do {
|
||||
/* Skip any With object that can wrap XML. */
|
||||
target = obj;
|
||||
|
|
|
@ -98,16 +98,12 @@ extern int gettimeofday(struct timeval *tv);
|
|||
#define PRMJ_YEAR_SECONDS (PRMJ_DAY_SECONDS * PRMJ_YEAR_DAYS)
|
||||
#define PRMJ_MAX_UNIX_TIMET 2145859200L /*time_t value equiv. to 12/31/2037 */
|
||||
|
||||
/* function prototypes */
|
||||
static void PRMJ_basetime(JSInt64 tsecs, PRMJTime *prtm);
|
||||
/*
|
||||
* get the difference in seconds between this time zone and UTC (GMT)
|
||||
*/
|
||||
JSInt32
|
||||
PRMJ_LocalGMTDifference()
|
||||
{
|
||||
struct tm ltime;
|
||||
|
||||
#if defined(XP_WIN) && !defined(WINCE)
|
||||
/* Windows does not follow POSIX. Updates to the
|
||||
* TZ environment variable are not reflected
|
||||
|
@ -116,11 +112,31 @@ PRMJ_LocalGMTDifference()
|
|||
*/
|
||||
_tzset();
|
||||
#endif
|
||||
/* get the difference between this time zone and GMT */
|
||||
memset((char *)<ime,0,sizeof(ltime));
|
||||
ltime.tm_mday = 2;
|
||||
ltime.tm_year = 70;
|
||||
return (JSInt32)mktime(<ime) - (24L * 3600L);
|
||||
|
||||
/*
|
||||
* Get the difference between this time zone and GMT, by checking the local
|
||||
* time at the epoch.
|
||||
*/
|
||||
time_t local = 0;
|
||||
struct tm tm;
|
||||
#ifndef HAVE_LOCALTIME_R
|
||||
struct tm *ptm = localtime(&local);
|
||||
if (!ptm)
|
||||
return 0;
|
||||
tm = *ptm;
|
||||
#else
|
||||
localtime_r(&local, &tm);
|
||||
#endif
|
||||
|
||||
JSInt32 time = (tm.tm_hour * 3600)
|
||||
+ (tm.tm_min * 60)
|
||||
+ tm.tm_sec;
|
||||
time = (24 * 3600) - time;
|
||||
|
||||
if (time >= (12 * 3600))
|
||||
time -= (24 * 3600);
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
/* Constants for GMT offset from 1970 */
|
||||
|
@ -130,34 +146,6 @@ PRMJ_LocalGMTDifference()
|
|||
#define G2037GMTMICROHI 0x00e45fab /* micro secs to 2037 high */
|
||||
#define G2037GMTMICROLOW 0x7a238000 /* micro secs to 2037 low */
|
||||
|
||||
/* Convert from base time to extended time */
|
||||
static JSInt64
|
||||
PRMJ_ToExtendedTime(JSInt32 base_time)
|
||||
{
|
||||
JSInt64 exttime;
|
||||
JSInt64 g1970GMTMicroSeconds;
|
||||
JSInt64 low;
|
||||
JSInt32 diff;
|
||||
JSInt64 tmp;
|
||||
JSInt64 tmp1;
|
||||
|
||||
diff = PRMJ_LocalGMTDifference();
|
||||
JSLL_UI2L(tmp, PRMJ_USEC_PER_SEC);
|
||||
JSLL_I2L(tmp1,diff);
|
||||
JSLL_MUL(tmp,tmp,tmp1);
|
||||
|
||||
JSLL_UI2L(g1970GMTMicroSeconds,G1970GMTMICROHI);
|
||||
JSLL_UI2L(low,G1970GMTMICROLOW);
|
||||
JSLL_SHL(g1970GMTMicroSeconds,g1970GMTMicroSeconds,16);
|
||||
JSLL_SHL(g1970GMTMicroSeconds,g1970GMTMicroSeconds,16);
|
||||
JSLL_ADD(g1970GMTMicroSeconds,g1970GMTMicroSeconds,low);
|
||||
|
||||
JSLL_I2L(exttime,base_time);
|
||||
JSLL_ADD(exttime,exttime,g1970GMTMicroSeconds);
|
||||
JSLL_SUB(exttime,exttime,tmp);
|
||||
return exttime;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SYSTEMTIMETOFILETIME
|
||||
|
||||
static const JSInt64 win2un = JSLL_INIT(0x19DB1DE, 0xD53E8000);
|
||||
|
@ -681,178 +669,6 @@ PRMJ_FormatTime(char *buf, int buflen, const char *fmt, PRMJTime *prtm)
|
|||
return result;
|
||||
}
|
||||
|
||||
/* table for number of days in a month */
|
||||
static int mtab[] = {
|
||||
/* jan, feb,mar,apr,may,jun */
|
||||
31,28,31,30,31,30,
|
||||
/* july,aug,sep,oct,nov,dec */
|
||||
31,31,30,31,30,31
|
||||
};
|
||||
|
||||
/*
|
||||
* basic time calculation functionality for localtime and gmtime
|
||||
* setups up prtm argument with correct values based upon input number
|
||||
* of seconds.
|
||||
*/
|
||||
static void
|
||||
PRMJ_basetime(JSInt64 tsecs, PRMJTime *prtm)
|
||||
{
|
||||
/* convert tsecs back to year,month,day,hour,secs */
|
||||
JSInt32 year = 0;
|
||||
JSInt32 month = 0;
|
||||
JSInt32 yday = 0;
|
||||
JSInt32 mday = 0;
|
||||
JSInt32 wday = 6; /* start on a Sunday */
|
||||
JSInt32 days = 0;
|
||||
JSInt32 seconds = 0;
|
||||
JSInt32 minutes = 0;
|
||||
JSInt32 hours = 0;
|
||||
JSInt32 isleap = 0;
|
||||
|
||||
/* Temporaries used for various computations */
|
||||
JSInt64 result;
|
||||
JSInt64 result1;
|
||||
JSInt64 result2;
|
||||
|
||||
JSInt64 base;
|
||||
|
||||
/* Some variables for intermediate result storage to make computing isleap
|
||||
easier/faster */
|
||||
JSInt32 fourCenturyBlocks;
|
||||
JSInt32 centuriesLeft;
|
||||
JSInt32 fourYearBlocksLeft;
|
||||
JSInt32 yearsLeft;
|
||||
|
||||
/* Since leap years work by 400/100/4 year intervals, precompute the length
|
||||
of those in seconds if they start at the beginning of year 1. */
|
||||
JSInt64 fourYears;
|
||||
JSInt64 century;
|
||||
JSInt64 fourCenturies;
|
||||
|
||||
JSLL_UI2L(result, PRMJ_DAY_SECONDS);
|
||||
|
||||
JSLL_I2L(fourYears, PRMJ_FOUR_YEARS_DAYS);
|
||||
JSLL_MUL(fourYears, fourYears, result);
|
||||
|
||||
JSLL_I2L(century, PRMJ_CENTURY_DAYS);
|
||||
JSLL_MUL(century, century, result);
|
||||
|
||||
JSLL_I2L(fourCenturies, PRMJ_FOUR_CENTURIES_DAYS);
|
||||
JSLL_MUL(fourCenturies, fourCenturies, result);
|
||||
|
||||
/* get the base time via UTC */
|
||||
base = PRMJ_ToExtendedTime(0);
|
||||
JSLL_UI2L(result, PRMJ_USEC_PER_SEC);
|
||||
JSLL_DIV(base,base,result);
|
||||
JSLL_ADD(tsecs,tsecs,base);
|
||||
|
||||
/* Compute our |year|, |isleap|, and part of |days|. When this part is
|
||||
done, |year| should hold the year our date falls in (number of whole
|
||||
years elapsed before our date), isleap should hold 1 if the year the
|
||||
date falls in is a leap year and 0 otherwise. */
|
||||
|
||||
/* First do year 0; it's special and nonleap. */
|
||||
JSLL_UI2L(result, PRMJ_YEAR_SECONDS);
|
||||
if (!JSLL_CMP(tsecs,<,result)) {
|
||||
days = PRMJ_YEAR_DAYS;
|
||||
year = 1;
|
||||
JSLL_SUB(tsecs, tsecs, result);
|
||||
}
|
||||
|
||||
/* Now use those constants we computed above */
|
||||
JSLL_UDIVMOD(&result1, &result2, tsecs, fourCenturies);
|
||||
JSLL_L2I(fourCenturyBlocks, result1);
|
||||
year += fourCenturyBlocks * 400;
|
||||
days += fourCenturyBlocks * PRMJ_FOUR_CENTURIES_DAYS;
|
||||
tsecs = result2;
|
||||
|
||||
JSLL_UDIVMOD(&result1, &result2, tsecs, century);
|
||||
JSLL_L2I(centuriesLeft, result1);
|
||||
year += centuriesLeft * 100;
|
||||
days += centuriesLeft * PRMJ_CENTURY_DAYS;
|
||||
tsecs = result2;
|
||||
|
||||
JSLL_UDIVMOD(&result1, &result2, tsecs, fourYears);
|
||||
JSLL_L2I(fourYearBlocksLeft, result1);
|
||||
year += fourYearBlocksLeft * 4;
|
||||
days += fourYearBlocksLeft * PRMJ_FOUR_YEARS_DAYS;
|
||||
tsecs = result2;
|
||||
|
||||
/* Recall that |result| holds PRMJ_YEAR_SECONDS */
|
||||
JSLL_UDIVMOD(&result1, &result2, tsecs, result);
|
||||
JSLL_L2I(yearsLeft, result1);
|
||||
year += yearsLeft;
|
||||
days += yearsLeft * PRMJ_YEAR_DAYS;
|
||||
tsecs = result2;
|
||||
|
||||
/* now compute isleap. Note that we don't have to use %, since we've
|
||||
already computed those remainders. Also note that they're all offset by
|
||||
1 because of the 1 for year 0. */
|
||||
isleap =
|
||||
(yearsLeft == 3) && (fourYearBlocksLeft != 24 || centuriesLeft == 3);
|
||||
JS_ASSERT(isleap ==
|
||||
((year % 4 == 0) && (year % 100 != 0 || year % 400 == 0)));
|
||||
|
||||
JSLL_UI2L(result1,PRMJ_DAY_SECONDS);
|
||||
|
||||
JSLL_DIV(result,tsecs,result1);
|
||||
JSLL_L2I(mday,result);
|
||||
|
||||
/* let's find the month */
|
||||
while(((month == 1 && isleap) ?
|
||||
(mday >= mtab[month] + 1) :
|
||||
(mday >= mtab[month]))){
|
||||
yday += mtab[month];
|
||||
days += mtab[month];
|
||||
|
||||
mday -= mtab[month];
|
||||
|
||||
/* it's a Feb, check if this is a leap year */
|
||||
if(month == 1 && isleap != 0){
|
||||
yday++;
|
||||
days++;
|
||||
mday--;
|
||||
}
|
||||
month++;
|
||||
}
|
||||
|
||||
/* now adjust tsecs */
|
||||
JSLL_MUL(result,result,result1);
|
||||
JSLL_SUB(tsecs,tsecs,result);
|
||||
|
||||
mday++; /* day of month always start with 1 */
|
||||
days += mday;
|
||||
wday = (days + wday) % 7;
|
||||
|
||||
yday += mday;
|
||||
|
||||
/* get the hours */
|
||||
JSLL_UI2L(result1,PRMJ_HOUR_SECONDS);
|
||||
JSLL_DIV(result,tsecs,result1);
|
||||
JSLL_L2I(hours,result);
|
||||
JSLL_MUL(result,result,result1);
|
||||
JSLL_SUB(tsecs,tsecs,result);
|
||||
|
||||
/* get minutes */
|
||||
JSLL_UI2L(result1,60);
|
||||
JSLL_DIV(result,tsecs,result1);
|
||||
JSLL_L2I(minutes,result);
|
||||
JSLL_MUL(result,result,result1);
|
||||
JSLL_SUB(tsecs,tsecs,result);
|
||||
|
||||
JSLL_L2I(seconds,tsecs);
|
||||
|
||||
prtm->tm_usec = 0L;
|
||||
prtm->tm_sec = (JSInt8)seconds;
|
||||
prtm->tm_min = (JSInt8)minutes;
|
||||
prtm->tm_hour = (JSInt8)hours;
|
||||
prtm->tm_mday = (JSInt8)mday;
|
||||
prtm->tm_mon = (JSInt8)month;
|
||||
prtm->tm_wday = (JSInt8)wday;
|
||||
prtm->tm_year = (JSInt16)year;
|
||||
prtm->tm_yday = (JSInt16)yday;
|
||||
}
|
||||
|
||||
JSInt64
|
||||
DSTOffsetCache::computeDSTOffsetMilliseconds(int64 localTimeSeconds)
|
||||
{
|
||||
|
@ -869,9 +685,7 @@ DSTOffsetCache::computeDSTOffsetMilliseconds(int64 localTimeSeconds)
|
|||
#endif
|
||||
|
||||
time_t local = static_cast<time_t>(localTimeSeconds);
|
||||
PRMJTime prtm;
|
||||
struct tm tm;
|
||||
PRMJ_basetime(localTimeSeconds, &prtm);
|
||||
#ifndef HAVE_LOCALTIME_R
|
||||
struct tm *ptm = localtime(&local);
|
||||
if (!ptm)
|
||||
|
@ -881,8 +695,13 @@ DSTOffsetCache::computeDSTOffsetMilliseconds(int64 localTimeSeconds)
|
|||
localtime_r(&local, &tm); /* get dst information */
|
||||
#endif
|
||||
|
||||
JSInt32 diff = ((tm.tm_hour - prtm.tm_hour) * SECONDS_PER_HOUR) +
|
||||
((tm.tm_min - prtm.tm_min) * SECONDS_PER_MINUTE);
|
||||
JSInt32 base = PRMJ_LocalGMTDifference();
|
||||
|
||||
int32 dayoff = int32((localTimeSeconds - base) % (SECONDS_PER_HOUR * 24));
|
||||
int32 tmoff = tm.tm_sec + (tm.tm_min * SECONDS_PER_MINUTE) +
|
||||
(tm.tm_hour * SECONDS_PER_HOUR);
|
||||
|
||||
JSInt32 diff = tmoff - dayoff;
|
||||
|
||||
if (diff < 0)
|
||||
diff += SECONDS_PER_DAY;
|
||||
|
@ -911,12 +730,23 @@ DSTOffsetCache::getDSTOffsetMilliseconds(JSInt64 localTimeMilliseconds, JSContex
|
|||
* values, must result in a cache miss.
|
||||
*/
|
||||
|
||||
if (rangeStartSeconds <= localTimeSeconds) {
|
||||
if (localTimeSeconds <= rangeEndSeconds) {
|
||||
noteCacheHit();
|
||||
return offsetMilliseconds;
|
||||
}
|
||||
if (rangeStartSeconds <= localTimeSeconds &&
|
||||
localTimeSeconds <= rangeEndSeconds) {
|
||||
noteCacheHit();
|
||||
return offsetMilliseconds;
|
||||
}
|
||||
|
||||
if (oldRangeStartSeconds <= localTimeSeconds &&
|
||||
localTimeSeconds <= oldRangeEndSeconds) {
|
||||
noteCacheHit();
|
||||
return oldOffsetMilliseconds;
|
||||
}
|
||||
|
||||
oldOffsetMilliseconds = offsetMilliseconds;
|
||||
oldRangeStartSeconds = rangeStartSeconds;
|
||||
oldRangeEndSeconds = rangeEndSeconds;
|
||||
|
||||
if (rangeStartSeconds <= localTimeSeconds) {
|
||||
JSInt64 newEndSeconds = JS_MIN(rangeEndSeconds + RANGE_EXPANSION_AMOUNT, MAX_UNIX_TIMET);
|
||||
if (newEndSeconds >= localTimeSeconds) {
|
||||
JSInt64 endOffsetMilliseconds = computeDSTOffsetMilliseconds(newEndSeconds);
|
||||
|
|
|
@ -112,6 +112,9 @@ class DSTOffsetCache {
|
|||
JSInt64 offsetMilliseconds;
|
||||
JSInt64 rangeStartSeconds, rangeEndSeconds;
|
||||
|
||||
JSInt64 oldOffsetMilliseconds;
|
||||
JSInt64 oldRangeStartSeconds, oldRangeEndSeconds;
|
||||
|
||||
#ifdef JS_METER_DST_OFFSET_CACHING
|
||||
size_t totalCalculations;
|
||||
size_t hit;
|
||||
|
|
|
@ -71,6 +71,7 @@
|
|||
#include "jsnum.h"
|
||||
#include "jsobj.h"
|
||||
#include "jsparse.h"
|
||||
#include "jsreflect.h"
|
||||
#include "jsscope.h"
|
||||
#include "jsscript.h"
|
||||
#include "jstracer.h"
|
||||
|
@ -1428,7 +1429,7 @@ ValueToScript(JSContext *cx, jsval v)
|
|||
script = (JSScript *) JS_GetPrivate(cx, obj);
|
||||
} else if (clasp == Jsvalify(&js_GeneratorClass)) {
|
||||
JSGenerator *gen = (JSGenerator *) JS_GetPrivate(cx, obj);
|
||||
fun = gen->getFloatingFrame()->fun;
|
||||
fun = gen->getFloatingFrame()->getFunction();
|
||||
script = FUN_SCRIPT(fun);
|
||||
}
|
||||
}
|
||||
|
@ -1455,7 +1456,7 @@ GetTrapArgs(JSContext *cx, uintN argc, jsval *argv, JSScript **scriptp,
|
|||
uintN intarg;
|
||||
JSScript *script;
|
||||
|
||||
*scriptp = JS_GetScriptedCaller(cx, NULL)->script;
|
||||
*scriptp = JS_GetScriptedCaller(cx, NULL)->getScript();
|
||||
*ip = 0;
|
||||
if (argc != 0) {
|
||||
v = argv[0];
|
||||
|
@ -1485,7 +1486,8 @@ TrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval,
|
|||
JSStackFrame *caller = JS_GetScriptedCaller(cx, NULL);
|
||||
if (!JS_EvaluateUCInStackFrame(cx, caller,
|
||||
JS_GetStringChars(str), JS_GetStringLength(str),
|
||||
caller->script->filename, caller->script->lineno,
|
||||
caller->getScript()->filename,
|
||||
caller->getScript()->lineno,
|
||||
rval)) {
|
||||
return JSTRAP_ERROR;
|
||||
}
|
||||
|
@ -1539,7 +1541,7 @@ LineToPC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||
JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_LINE2PC_USAGE);
|
||||
return JS_FALSE;
|
||||
}
|
||||
script = JS_GetScriptedCaller(cx, NULL)->script;
|
||||
script = JS_GetScriptedCaller(cx, NULL)->getScript();
|
||||
if (!GetTrapArgs(cx, argc, argv, &script, &i))
|
||||
return JS_FALSE;
|
||||
lineno = (i == 0) ? script->lineno : (uintN)i;
|
||||
|
@ -2705,6 +2707,23 @@ split_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
|
|||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
ResolveClass(JSContext *cx, JSObject *obj, jsid id, JSBool *resolved)
|
||||
{
|
||||
if (!JS_ResolveStandardClass(cx, obj, id, resolved))
|
||||
return JS_FALSE;
|
||||
|
||||
if (!*resolved) {
|
||||
if (JSID_IS_ATOM(id, CLASS_ATOM(cx, Reflect))) {
|
||||
if (!js_InitReflectClass(cx, obj))
|
||||
return JS_FALSE;
|
||||
*resolved = JS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
split_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp)
|
||||
{
|
||||
|
@ -2735,7 +2754,7 @@ split_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **obj
|
|||
if (!(flags & JSRESOLVE_ASSIGNING)) {
|
||||
JSBool resolved;
|
||||
|
||||
if (!JS_ResolveStandardClass(cx, obj, id, &resolved))
|
||||
if (!ResolveClass(cx, obj, id, &resolved))
|
||||
return JS_FALSE;
|
||||
|
||||
if (resolved) {
|
||||
|
@ -2961,7 +2980,7 @@ sandbox_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
|||
|
||||
JS_ValueToBoolean(cx, v, &b);
|
||||
if (b && (flags & JSRESOLVE_ASSIGNING) == 0) {
|
||||
if (!JS_ResolveStandardClass(cx, obj, id, &resolved))
|
||||
if (!ResolveClass(cx, obj, id, &resolved))
|
||||
return JS_FALSE;
|
||||
if (resolved) {
|
||||
*objp = obj;
|
||||
|
@ -3067,8 +3086,8 @@ EvalInContext(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|||
return false;
|
||||
}
|
||||
if (!JS_EvaluateUCScript(cx, sobj, src, srclen,
|
||||
fp->script->filename,
|
||||
JS_PCToLineNumber(cx, fp->script, fp->pc(cx)),
|
||||
fp->getScript()->filename,
|
||||
JS_PCToLineNumber(cx, fp->getScript(), fp->pc(cx)),
|
||||
rval)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -3103,7 +3122,7 @@ EvalInFrame(JSContext *cx, uintN argc, jsval *vp)
|
|||
}
|
||||
|
||||
JSStackFrame *const fp = fi.fp();
|
||||
if (!fp->script) {
|
||||
if (!fp->hasScript()) {
|
||||
JS_ReportError(cx, "cannot eval in non-script frame");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
@ -3113,8 +3132,8 @@ EvalInFrame(JSContext *cx, uintN argc, jsval *vp)
|
|||
oldfp = JS_SaveFrameChain(cx);
|
||||
|
||||
JSBool ok = JS_EvaluateUCInStackFrame(cx, fp, str->chars(), str->length(),
|
||||
fp->script->filename,
|
||||
JS_PCToLineNumber(cx, fp->script,
|
||||
fp->getScript()->filename,
|
||||
JS_PCToLineNumber(cx, fp->getScript(),
|
||||
fi.pc()),
|
||||
vp);
|
||||
|
||||
|
@ -3836,9 +3855,9 @@ Snarf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||
|
||||
/* Get the currently executing script's name. */
|
||||
fp = JS_GetScriptedCaller(cx, NULL);
|
||||
JS_ASSERT(fp && fp->script->filename);
|
||||
JS_ASSERT(fp && fp->getScript()->filename);
|
||||
#ifdef XP_UNIX
|
||||
pathname = MakeAbsolutePathname(cx, fp->script->filename, filename);
|
||||
pathname = MakeAbsolutePathname(cx, fp->getScript()->filename, filename);
|
||||
if (!pathname)
|
||||
return JS_FALSE;
|
||||
#else
|
||||
|
@ -4710,7 +4729,7 @@ global_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
|||
#ifdef LAZY_STANDARD_CLASSES
|
||||
JSBool resolved;
|
||||
|
||||
if (!JS_ResolveStandardClass(cx, obj, id, &resolved))
|
||||
if (!ResolveClass(cx, obj, id, &resolved))
|
||||
return JS_FALSE;
|
||||
if (resolved) {
|
||||
*objp = obj;
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
url-prefix ../../jsreftest.html?test=ecma_5/Date/
|
||||
script 15.9.4.2.js
|
||||
script toJSON-01.js
|
||||
|
|
|
@ -0,0 +1,242 @@
|
|||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
var gTestfile = 'toJSON-01.js';
|
||||
//-----------------------------------------------------------------------------
|
||||
var BUGNUMBER = 584811;
|
||||
var summary = "Date.prototype.toJSON isn't to spec";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
/**************
|
||||
* BEGIN TEST *
|
||||
**************/
|
||||
|
||||
var called;
|
||||
|
||||
var dateToJSON = Date.prototype.toJSON;
|
||||
assertEq(Date.prototype.hasOwnProperty("toJSON"), true);
|
||||
assertEq(typeof dateToJSON, "function");
|
||||
|
||||
// brief test to exercise this outside of isolation, just for sanity
|
||||
var invalidDate = new Date();
|
||||
invalidDate.setTime(NaN);
|
||||
assertEq(JSON.stringify({ p: invalidDate }), '{"p":null}');
|
||||
|
||||
|
||||
/* 15.9.5.44 Date.prototype.toJSON ( key ) */
|
||||
assertEq(dateToJSON.length, 1);
|
||||
|
||||
/*
|
||||
* 1. Let O be the result of calling ToObject, giving it the this value as its
|
||||
* argument.
|
||||
*/
|
||||
function strictThis() { "use strict"; return this; }
|
||||
if (strictThis.call(null) === null)
|
||||
{
|
||||
try
|
||||
{
|
||||
dateToJSON.call(null);
|
||||
throw new Error("should have thrown a TypeError");
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true,
|
||||
"ToObject throws TypeError for null/undefined");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
dateToJSON.call(undefined);
|
||||
throw new Error("should have thrown a TypeError");
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true,
|
||||
"ToObject throws TypeError for null/undefined");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 2. Let tv be ToPrimitive(O, hint Number).
|
||||
* ...expands to:
|
||||
* 1. Let valueOf be the result of calling the [[Get]] internal method of object O with argument "valueOf".
|
||||
* 2. If IsCallable(valueOf) is true then,
|
||||
* a. Let val be the result of calling the [[Call]] internal method of valueOf, with O as the this value and
|
||||
* an empty argument list.
|
||||
* b. If val is a primitive value, return val.
|
||||
* 3. Let toString be the result of calling the [[Get]] internal method of object O with argument "toString".
|
||||
* 4. If IsCallable(toString) is true then,
|
||||
* a. Let str be the result of calling the [[Call]] internal method of toString, with O as the this value and
|
||||
* an empty argument list.
|
||||
* b. If str is a primitive value, return str.
|
||||
* 5. Throw a TypeError exception.
|
||||
*/
|
||||
try
|
||||
{
|
||||
var r = dateToJSON.call({ get valueOf() { throw 17; } });
|
||||
throw new Error("didn't throw, returned: " + r);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e, 17, "bad exception: " + e);
|
||||
}
|
||||
|
||||
called = false;
|
||||
assertEq(dateToJSON.call({ valueOf: null,
|
||||
toString: function() { called = true; return 12; },
|
||||
toISOString: function() { return "ohai"; } }),
|
||||
"ohai");
|
||||
assertEq(called, true);
|
||||
|
||||
called = false;
|
||||
assertEq(dateToJSON.call({ valueOf: function() { called = true; return 42; },
|
||||
toISOString: function() { return null; } }),
|
||||
null);
|
||||
assertEq(called, true);
|
||||
|
||||
try
|
||||
{
|
||||
called = false;
|
||||
dateToJSON.call({ valueOf: function() { called = true; return {}; },
|
||||
get toString() { throw 42; } });
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(called, true);
|
||||
assertEq(e, 42, "bad exception: " + e);
|
||||
}
|
||||
|
||||
called = false;
|
||||
assertEq(dateToJSON.call({ valueOf: function() { called = true; return {}; },
|
||||
get toString() { return function() { return 8675309; }; },
|
||||
toISOString: function() { return true; } }),
|
||||
true);
|
||||
assertEq(called, true);
|
||||
|
||||
var asserted = false;
|
||||
called = false;
|
||||
assertEq(dateToJSON.call({ valueOf: function() { called = true; return {}; },
|
||||
get toString()
|
||||
{
|
||||
assertEq(called, true);
|
||||
asserted = true;
|
||||
return function() { return 8675309; };
|
||||
},
|
||||
toISOString: function() { return NaN; } }),
|
||||
NaN);
|
||||
assertEq(asserted, true);
|
||||
|
||||
try
|
||||
{
|
||||
var r = dateToJSON.call({ valueOf: null, toString: null,
|
||||
get toISOString()
|
||||
{
|
||||
throw new Error("shouldn't have been gotten");
|
||||
} });
|
||||
throw new Error("didn't throw, returned: " + r);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true, "bad exception: " + e);
|
||||
}
|
||||
|
||||
|
||||
/* 3. If tv is a Number and is not finite, return null. */
|
||||
assertEq(dateToJSON.call({ valueOf: function() { return Infinity; } }), null);
|
||||
assertEq(dateToJSON.call({ valueOf: function() { return -Infinity; } }), null);
|
||||
assertEq(dateToJSON.call({ valueOf: function() { return NaN; } }), null);
|
||||
|
||||
assertEq(dateToJSON.call({ valueOf: function() { return Infinity; },
|
||||
toISOString: function() { return {}; } }), null);
|
||||
assertEq(dateToJSON.call({ valueOf: function() { return -Infinity; },
|
||||
toISOString: function() { return []; } }), null);
|
||||
assertEq(dateToJSON.call({ valueOf: function() { return NaN; },
|
||||
toISOString: function() { return undefined; } }), null);
|
||||
|
||||
|
||||
/*
|
||||
* 4. Let toISO be the result of calling the [[Get]] internal method of O with
|
||||
* argument "toISOString".
|
||||
*/
|
||||
try
|
||||
{
|
||||
var r = dateToJSON.call({ get toISOString() { throw 42; } });
|
||||
throw new Error("didn't throw, returned: " + r);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e, 42, "bad exception: " + e);
|
||||
}
|
||||
|
||||
|
||||
/* 5. If IsCallable(toISO) is false, throw a TypeError exception. */
|
||||
try
|
||||
{
|
||||
var r = dateToJSON.call({ toISOString: null });
|
||||
throw new Error("didn't throw, returned: " + r);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true, "bad exception: " + e);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var r = dateToJSON.call({ toISOString: undefined });
|
||||
throw new Error("didn't throw, returned: " + r);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true, "bad exception: " + e);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var r = dateToJSON.call({ toISOString: "oogabooga" });
|
||||
throw new Error("didn't throw, returned: " + r);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true, "bad exception: " + e);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var r = dateToJSON.call({ toISOString: Math.PI });
|
||||
throw new Error("didn't throw, returned: " + r);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true, "bad exception: " + e);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 6. Return the result of calling the [[Call]] internal method of toISO with O
|
||||
* as the this value and an empty argument list.
|
||||
*/
|
||||
var o =
|
||||
{
|
||||
toISOString: function(a)
|
||||
{
|
||||
called = true;
|
||||
assertEq(this, o);
|
||||
assertEq(a, undefined);
|
||||
assertEq(arguments.length, 0);
|
||||
return obj;
|
||||
}
|
||||
};
|
||||
var obj = {};
|
||||
called = false;
|
||||
assertEq(dateToJSON.call(o), obj, "should have gotten obj back");
|
||||
assertEq(called, true);
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
print("All tests passed!");
|
|
@ -18,8 +18,8 @@ assertEq("get" in Object.getOwnPropertyDescriptor(o, "a b c"), true);
|
|||
o = eval('({ get "a b c"() { return 17; } })');
|
||||
assertEq("get" in Object.getOwnPropertyDescriptor(o, "a b c"), true);
|
||||
|
||||
var f = eval("(function literalInside() { return { set 'c d e'() { } }; })");
|
||||
f = function literalInside() { return { set 'c d e'() { } }; };
|
||||
var f = eval("(function literalInside() { return { set 'c d e'(q) { } }; })");
|
||||
f = function literalInside() { return { set 'c d e'(q) { } }; };
|
||||
|
||||
function checkO()
|
||||
{
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
url-prefix ../../jsreftest.html?test=ecma_5/Expressions/
|
||||
script 11.1.5-01.js
|
||||
script named-accessor-function.js
|
||||
script object-literal-accessor-arguments.js
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
var gTestfile = 'object-literal-accessor-arguments.js';
|
||||
//-----------------------------------------------------------------------------
|
||||
var BUGNUMBER = 536472;
|
||||
var summary =
|
||||
'ES5: { get x(v) { } } and { set x(v, v2) { } } should be syntax errors';
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function expectSyntaxError(s)
|
||||
{
|
||||
try
|
||||
{
|
||||
eval(s);
|
||||
throw new Error("no error thrown");
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof SyntaxError, true,
|
||||
"expected syntax error parsing '" + s + "', got: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
expectSyntaxError("({ get x(a) { } })");
|
||||
expectSyntaxError("({ get x(a, a) { } })");
|
||||
expectSyntaxError("({ get x(a, b) { } })");
|
||||
expectSyntaxError("({ get x(a, a, b) { } })");
|
||||
expectSyntaxError("({ get x(a, b, c) { } })");
|
||||
|
||||
expectSyntaxError("({ set x() { } })");
|
||||
expectSyntaxError("({ set x(a, a) { } })");
|
||||
expectSyntaxError("({ set x(a, b) { } })");
|
||||
expectSyntaxError("({ set x(a, a, b) { } })");
|
||||
expectSyntaxError("({ set x(a, b, c) { } })");
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
reportCompare(true, true);
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
var gTestfile = 'arguments-caller-callee.js';
|
||||
var BUGNUMBER = 514563;
|
||||
var summary = "arguments.caller and arguments.callee are poison pills in ES5";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
/**************
|
||||
* BEGIN TEST *
|
||||
**************/
|
||||
|
||||
// behavior
|
||||
|
||||
function expectTypeError(fun)
|
||||
{
|
||||
try
|
||||
{
|
||||
fun();
|
||||
throw new Error("didn't throw");
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true,
|
||||
"expected TypeError calling function" +
|
||||
("name" in fun ? " " + fun.name : "") + ", instead got: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
function bar() { "use strict"; return arguments; }
|
||||
expectTypeError(function barCaller() { bar().caller; });
|
||||
expectTypeError(function barCallee() { bar().callee; });
|
||||
|
||||
function baz() { return arguments; }
|
||||
assertEq(baz().callee, baz);
|
||||
|
||||
|
||||
// accessor identity
|
||||
|
||||
function strictMode() { "use strict"; return arguments; }
|
||||
var canonicalTTE = Object.getOwnPropertyDescriptor(strictMode(), "caller").get;
|
||||
|
||||
var args = strictMode();
|
||||
|
||||
var argsCaller = Object.getOwnPropertyDescriptor(args, "caller");
|
||||
assertEq("get" in argsCaller, true);
|
||||
assertEq("set" in argsCaller, true);
|
||||
assertEq(argsCaller.get, canonicalTTE);
|
||||
assertEq(argsCaller.set, canonicalTTE);
|
||||
|
||||
var argsCallee = Object.getOwnPropertyDescriptor(args, "callee");
|
||||
assertEq("get" in argsCallee, true);
|
||||
assertEq("set" in argsCallee, true);
|
||||
assertEq(argsCallee.get, canonicalTTE);
|
||||
assertEq(argsCallee.set, canonicalTTE);
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
print("All tests passed!");
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
var gTestfile = 'arguments-property-attributes.js';
|
||||
var BUGNUMBER = 516255;
|
||||
var summary = "Attributes for properties of arguments objects";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
/**************
|
||||
* BEGIN TEST *
|
||||
**************/
|
||||
|
||||
// normal
|
||||
|
||||
function args() { return arguments; }
|
||||
var a = args(0, 1);
|
||||
|
||||
var argProps = Object.getOwnPropertyNames(a).sort();
|
||||
assertEq(argProps.indexOf("callee") >= 0, true);
|
||||
assertEq(argProps.indexOf("0") >= 0, true);
|
||||
assertEq(argProps.indexOf("1") >= 0, true);
|
||||
assertEq(argProps.indexOf("length") >= 0, true);
|
||||
|
||||
var calleeDesc = Object.getOwnPropertyDescriptor(a, "callee");
|
||||
assertEq(calleeDesc.value, args);
|
||||
assertEq(calleeDesc.writable, true);
|
||||
assertEq(calleeDesc.enumerable, false);
|
||||
assertEq(calleeDesc.configurable, true);
|
||||
|
||||
var zeroDesc = Object.getOwnPropertyDescriptor(a, "0");
|
||||
assertEq(zeroDesc.value, 0);
|
||||
assertEq(zeroDesc.writable, true);
|
||||
assertEq(zeroDesc.enumerable, true);
|
||||
assertEq(zeroDesc.configurable, true);
|
||||
|
||||
var oneDesc = Object.getOwnPropertyDescriptor(a, "1");
|
||||
assertEq(oneDesc.value, 1);
|
||||
assertEq(oneDesc.writable, true);
|
||||
assertEq(oneDesc.enumerable, true);
|
||||
assertEq(oneDesc.configurable, true);
|
||||
|
||||
var lengthDesc = Object.getOwnPropertyDescriptor(a, "length");
|
||||
assertEq(lengthDesc.value, 2);
|
||||
assertEq(lengthDesc.writable, true);
|
||||
assertEq(lengthDesc.enumerable, false);
|
||||
assertEq(lengthDesc.configurable, true);
|
||||
|
||||
|
||||
// strict
|
||||
|
||||
function strictArgs() { "use strict"; return arguments; }
|
||||
var sa = strictArgs(0, 1);
|
||||
|
||||
var strictArgProps = Object.getOwnPropertyNames(sa).sort();
|
||||
assertEq(strictArgProps.indexOf("callee") >= 0, true);
|
||||
assertEq(strictArgProps.indexOf("caller") >= 0, true);
|
||||
assertEq(strictArgProps.indexOf("0") >= 0, true);
|
||||
assertEq(strictArgProps.indexOf("1") >= 0, true);
|
||||
assertEq(strictArgProps.indexOf("length") >= 0, true);
|
||||
|
||||
var strictCalleeDesc = Object.getOwnPropertyDescriptor(sa, "callee");
|
||||
assertEq(typeof strictCalleeDesc.get, "function");
|
||||
assertEq(typeof strictCalleeDesc.set, "function");
|
||||
assertEq(strictCalleeDesc.get, strictCalleeDesc.set);
|
||||
assertEq(strictCalleeDesc.enumerable, false);
|
||||
assertEq(strictCalleeDesc.configurable, false);
|
||||
|
||||
var strictCallerDesc = Object.getOwnPropertyDescriptor(sa, "caller");
|
||||
assertEq(typeof strictCallerDesc.get, "function");
|
||||
assertEq(typeof strictCallerDesc.set, "function");
|
||||
assertEq(strictCallerDesc.get, strictCallerDesc.set);
|
||||
assertEq(strictCallerDesc.enumerable, false);
|
||||
assertEq(strictCallerDesc.configurable, false);
|
||||
|
||||
var strictZeroDesc = Object.getOwnPropertyDescriptor(sa, "0");
|
||||
assertEq(strictZeroDesc.value, 0);
|
||||
assertEq(strictZeroDesc.writable, true);
|
||||
assertEq(strictZeroDesc.enumerable, true);
|
||||
assertEq(strictZeroDesc.configurable, true);
|
||||
|
||||
var strictOneDesc = Object.getOwnPropertyDescriptor(sa, "1");
|
||||
assertEq(strictOneDesc.value, 1);
|
||||
assertEq(strictOneDesc.writable, true);
|
||||
assertEq(strictOneDesc.enumerable, true);
|
||||
assertEq(strictOneDesc.configurable, true);
|
||||
|
||||
var strictLengthDesc = Object.getOwnPropertyDescriptor(sa, "length");
|
||||
assertEq(strictLengthDesc.value, 2);
|
||||
assertEq(strictLengthDesc.writable, true);
|
||||
assertEq(strictLengthDesc.enumerable, false);
|
||||
assertEq(strictLengthDesc.configurable, true);
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
print("All tests passed!");
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
var gTestfile = 'function-caller.js';
|
||||
var BUGNUMBER = 514581;
|
||||
var summary = "Function.prototype.caller should throw a TypeError for " +
|
||||
"strict-mode functions";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
/**************
|
||||
* BEGIN TEST *
|
||||
**************/
|
||||
|
||||
// behavior
|
||||
|
||||
function expectTypeError(fun)
|
||||
{
|
||||
try
|
||||
{
|
||||
fun();
|
||||
throw new Error("didn't throw");
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true,
|
||||
"expected TypeError calling function" +
|
||||
("name" in fun ? " " + fun.name : "") + ", instead got: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
function bar() { "use strict"; }
|
||||
expectTypeError(function barCaller() { bar.caller; });
|
||||
|
||||
function baz() { "use strict"; return 17; }
|
||||
expectTypeError(function bazCaller() { baz.caller; });
|
||||
|
||||
|
||||
// accessor identity
|
||||
|
||||
function strictMode() { "use strict"; return 42; }
|
||||
var canonicalTTE = Object.getOwnPropertyDescriptor(strictMode, "caller").get;
|
||||
|
||||
var barCaller = Object.getOwnPropertyDescriptor(bar, "caller");
|
||||
assertEq("get" in barCaller, true);
|
||||
assertEq("set" in barCaller, true);
|
||||
assertEq(barCaller.get, canonicalTTE);
|
||||
assertEq(barCaller.set, canonicalTTE);
|
||||
|
||||
var barArguments = Object.getOwnPropertyDescriptor(bar, "arguments");
|
||||
assertEq("get" in barArguments, true);
|
||||
assertEq("set" in barArguments, true);
|
||||
assertEq(barArguments.get, canonicalTTE);
|
||||
assertEq(barArguments.set, canonicalTTE);
|
||||
|
||||
var bazCaller = Object.getOwnPropertyDescriptor(baz, "caller");
|
||||
assertEq("get" in bazCaller, true);
|
||||
assertEq("set" in bazCaller, true);
|
||||
assertEq(bazCaller.get, canonicalTTE);
|
||||
assertEq(bazCaller.set, canonicalTTE);
|
||||
|
||||
var bazArguments = Object.getOwnPropertyDescriptor(baz, "arguments");
|
||||
assertEq("get" in bazArguments, true);
|
||||
assertEq("set" in bazArguments, true);
|
||||
assertEq(bazArguments.get, canonicalTTE);
|
||||
assertEq(bazArguments.set, canonicalTTE);
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
print("All tests passed!");
|
|
@ -1,2 +1,6 @@
|
|||
url-prefix ../../jsreftest.html?test=ecma_5/Function/
|
||||
script 15.3.4.3-01.js
|
||||
script arguments-caller-callee.js
|
||||
script function-caller.js
|
||||
script strict-arguments.js
|
||||
script arguments-property-attributes.js
|
||||
|
|
|
@ -0,0 +1,382 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
var gTestfile = 'strict-arguments.js';
|
||||
var BUGNUMBER = 516255;
|
||||
var summary =
|
||||
"ES5 strict mode: arguments objects of strict mode functions must copy " +
|
||||
"argument values";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
/**************
|
||||
* BEGIN TEST *
|
||||
**************/
|
||||
|
||||
function arrayEvery(arr, fun)
|
||||
{
|
||||
return Array.prototype.every.call(arr, fun);
|
||||
}
|
||||
|
||||
function arraysEqual(a1, a2)
|
||||
{
|
||||
return a1.length === a2.length &&
|
||||
arrayEvery(a1, function(v, i) { return v === a2[i]; });
|
||||
}
|
||||
|
||||
|
||||
/************************
|
||||
* NON-STRICT ARGUMENTS *
|
||||
************************/
|
||||
|
||||
var obj = {};
|
||||
|
||||
function noargs() { return arguments; }
|
||||
|
||||
assertEq(arraysEqual(noargs(), []), true);
|
||||
assertEq(arraysEqual(noargs(1), [1]), true);
|
||||
assertEq(arraysEqual(noargs(2, obj, 8), [2, obj, 8]), true);
|
||||
|
||||
function args(a) { return arguments; }
|
||||
|
||||
assertEq(arraysEqual(args(), []), true);
|
||||
assertEq(arraysEqual(args(1), [1]), true);
|
||||
assertEq(arraysEqual(args(1, obj), [1, obj]), true);
|
||||
assertEq(arraysEqual(args("foopy"), ["foopy"]), true);
|
||||
|
||||
function assign(a)
|
||||
{
|
||||
a = 17;
|
||||
return arguments;
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(assign(1), [17]), true);
|
||||
|
||||
function getLaterAssign(a)
|
||||
{
|
||||
var o = arguments;
|
||||
a = 17;
|
||||
return o;
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(getLaterAssign(1), [17]), true);
|
||||
|
||||
function assignElementGetParameter(a)
|
||||
{
|
||||
arguments[0] = 17;
|
||||
return a;
|
||||
}
|
||||
|
||||
assertEq(assignElementGetParameter(42), 17);
|
||||
|
||||
function assignParameterGetElement(a)
|
||||
{
|
||||
a = 17;
|
||||
return arguments[0];
|
||||
}
|
||||
|
||||
assertEq(assignParameterGetElement(42), 17);
|
||||
|
||||
|
||||
/********************
|
||||
* STRICT ARGUMENTS *
|
||||
********************/
|
||||
|
||||
function strictNoargs()
|
||||
{
|
||||
"use strict";
|
||||
return arguments;
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(strictNoargs(), []), true);
|
||||
assertEq(arraysEqual(strictNoargs(1), [1]), true);
|
||||
assertEq(arraysEqual(strictNoargs(1, obj), [1, obj]), true);
|
||||
|
||||
function strictArgs(a)
|
||||
{
|
||||
"use strict";
|
||||
return arguments;
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(strictArgs(), []), true);
|
||||
assertEq(arraysEqual(strictArgs(1), [1]), true);
|
||||
assertEq(arraysEqual(strictArgs(1, obj), [1, obj]), true);
|
||||
|
||||
function strictAssign(a)
|
||||
{
|
||||
"use strict";
|
||||
a = 17;
|
||||
return arguments;
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(strictAssign(), []), true);
|
||||
assertEq(arraysEqual(strictAssign(1), [1]), true);
|
||||
assertEq(arraysEqual(strictAssign(1, obj), [1, obj]), true);
|
||||
|
||||
var upper;
|
||||
function strictAssignAfter(a)
|
||||
{
|
||||
"use strict";
|
||||
upper = arguments;
|
||||
a = 42;
|
||||
return upper;
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(strictAssignAfter(), []), true);
|
||||
assertEq(arraysEqual(strictAssignAfter(17), [17]), true);
|
||||
assertEq(arraysEqual(strictAssignAfter(obj), [obj]), true);
|
||||
|
||||
function strictMaybeAssignOuterParam(p)
|
||||
{
|
||||
"use strict";
|
||||
function inner() { p = 17; }
|
||||
return arguments;
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(strictMaybeAssignOuterParam(), []), true);
|
||||
assertEq(arraysEqual(strictMaybeAssignOuterParam(42), [42]), true);
|
||||
assertEq(arraysEqual(strictMaybeAssignOuterParam(obj), [obj]), true);
|
||||
|
||||
function strictAssignOuterParam(p)
|
||||
{
|
||||
"use strict";
|
||||
function inner() { p = 17; }
|
||||
inner();
|
||||
return arguments;
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(strictAssignOuterParam(), []), true);
|
||||
assertEq(arraysEqual(strictAssignOuterParam(17), [17]), true);
|
||||
assertEq(arraysEqual(strictAssignOuterParam(obj), [obj]), true);
|
||||
|
||||
function strictAssignOuterParamPSYCH(p)
|
||||
{
|
||||
"use strict";
|
||||
function inner(p) { p = 17; }
|
||||
inner();
|
||||
return arguments;
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(strictAssignOuterParamPSYCH(), []), true);
|
||||
assertEq(arraysEqual(strictAssignOuterParamPSYCH(17), [17]), true);
|
||||
assertEq(arraysEqual(strictAssignOuterParamPSYCH(obj), [obj]), true);
|
||||
|
||||
function strictEval(code, p)
|
||||
{
|
||||
"use strict";
|
||||
eval(code);
|
||||
return arguments;
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(strictEval("1", 2), ["1", 2]), true);
|
||||
assertEq(arraysEqual(strictEval("arguments"), ["arguments"]), true);
|
||||
assertEq(arraysEqual(strictEval("p = 2"), ["p = 2"]), true);
|
||||
assertEq(arraysEqual(strictEval("p = 2", 17), ["p = 2", 17]), true);
|
||||
assertEq(arraysEqual(strictEval("arguments[0] = 17"), [17]), true);
|
||||
assertEq(arraysEqual(strictEval("arguments[0] = 17", 42), [17, 42]), true);
|
||||
|
||||
function strictMaybeNestedEval(code, p)
|
||||
{
|
||||
"use strict";
|
||||
function inner() { eval(code); }
|
||||
return arguments;
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(strictMaybeNestedEval("1", 2), ["1", 2]), true);
|
||||
assertEq(arraysEqual(strictMaybeNestedEval("arguments"), ["arguments"]), true);
|
||||
assertEq(arraysEqual(strictMaybeNestedEval("p = 2"), ["p = 2"]), true);
|
||||
assertEq(arraysEqual(strictMaybeNestedEval("p = 2", 17), ["p = 2", 17]), true);
|
||||
|
||||
function strictNestedEval(code, p)
|
||||
{
|
||||
"use strict";
|
||||
function inner() { eval(code); }
|
||||
inner();
|
||||
return arguments;
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(strictNestedEval("1", 2), ["1", 2]), true);
|
||||
assertEq(arraysEqual(strictNestedEval("arguments"), ["arguments"]), true);
|
||||
assertEq(arraysEqual(strictNestedEval("p = 2"), ["p = 2"]), true);
|
||||
assertEq(arraysEqual(strictNestedEval("p = 2", 17), ["p = 2", 17]), true);
|
||||
assertEq(arraysEqual(strictNestedEval("arguments[0] = 17"), ["arguments[0] = 17"]), true);
|
||||
assertEq(arraysEqual(strictNestedEval("arguments[0] = 17", 42), ["arguments[0] = 17", 42]), true);
|
||||
|
||||
function strictAssignArguments(a)
|
||||
{
|
||||
"use strict";
|
||||
arguments[0] = 42;
|
||||
return a;
|
||||
}
|
||||
|
||||
assertEq(strictAssignArguments(), undefined);
|
||||
assertEq(strictAssignArguments(obj), obj);
|
||||
assertEq(strictAssignArguments(17), 17);
|
||||
|
||||
function strictAssignParameterGetElement(a)
|
||||
{
|
||||
"use strict";
|
||||
a = 17;
|
||||
return arguments[0];
|
||||
}
|
||||
|
||||
assertEq(strictAssignParameterGetElement(42), 42);
|
||||
|
||||
function strictNestedAssignShadowVar(p)
|
||||
{
|
||||
"use strict";
|
||||
function inner()
|
||||
{
|
||||
var p = 12;
|
||||
function innermost() { p = 1776; return 12; }
|
||||
return innermost();
|
||||
}
|
||||
return arguments;
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(strictNestedAssignShadowVar(), []), true);
|
||||
assertEq(arraysEqual(strictNestedAssignShadowVar(99), [99]), true);
|
||||
assertEq(arraysEqual(strictNestedAssignShadowVar(""), [""]), true);
|
||||
assertEq(arraysEqual(strictNestedAssignShadowVar(obj), [obj]), true);
|
||||
|
||||
function strictNestedAssignShadowCatch(p)
|
||||
{
|
||||
"use strict";
|
||||
function inner()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (p)
|
||||
{
|
||||
var f = function innermost() { p = 1776; return 12; };
|
||||
f();
|
||||
}
|
||||
}
|
||||
return arguments;
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(strictNestedAssignShadowCatch(), []), true);
|
||||
assertEq(arraysEqual(strictNestedAssignShadowCatch(99), [99]), true);
|
||||
assertEq(arraysEqual(strictNestedAssignShadowCatch(""), [""]), true);
|
||||
assertEq(arraysEqual(strictNestedAssignShadowCatch(obj), [obj]), true);
|
||||
|
||||
function strictNestedAssignShadowCatchCall(p)
|
||||
{
|
||||
"use strict";
|
||||
function inner()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (p)
|
||||
{
|
||||
var f = function innermost() { p = 1776; return 12; };
|
||||
f();
|
||||
}
|
||||
}
|
||||
inner();
|
||||
return arguments;
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(strictNestedAssignShadowCatchCall(), []), true);
|
||||
assertEq(arraysEqual(strictNestedAssignShadowCatchCall(99), [99]), true);
|
||||
assertEq(arraysEqual(strictNestedAssignShadowCatchCall(""), [""]), true);
|
||||
assertEq(arraysEqual(strictNestedAssignShadowCatchCall(obj), [obj]), true);
|
||||
|
||||
function strictNestedAssignShadowFunction(p)
|
||||
{
|
||||
"use strict";
|
||||
function inner()
|
||||
{
|
||||
function p() { }
|
||||
p = 1776;
|
||||
}
|
||||
return arguments;
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(strictNestedAssignShadowFunction(), []), true);
|
||||
assertEq(arraysEqual(strictNestedAssignShadowFunction(99), [99]), true);
|
||||
assertEq(arraysEqual(strictNestedAssignShadowFunction(""), [""]), true);
|
||||
assertEq(arraysEqual(strictNestedAssignShadowFunction(obj), [obj]), true);
|
||||
|
||||
function strictNestedAssignShadowFunctionCall(p)
|
||||
{
|
||||
"use strict";
|
||||
function inner()
|
||||
{
|
||||
function p() { }
|
||||
p = 1776;
|
||||
}
|
||||
return arguments;
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(strictNestedAssignShadowFunctionCall(), []), true);
|
||||
assertEq(arraysEqual(strictNestedAssignShadowFunctionCall(99), [99]), true);
|
||||
assertEq(arraysEqual(strictNestedAssignShadowFunctionCall(""), [""]), true);
|
||||
assertEq(arraysEqual(strictNestedAssignShadowFunctionCall(obj), [obj]), true);
|
||||
|
||||
function strictNestedShadowAndMaybeEval(code, p)
|
||||
{
|
||||
"use strict";
|
||||
function inner(p) { eval(code); }
|
||||
return arguments;
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(strictNestedShadowAndMaybeEval("1", 2), ["1", 2]), true);
|
||||
assertEq(arraysEqual(strictNestedShadowAndMaybeEval("arguments"), ["arguments"]), true);
|
||||
assertEq(arraysEqual(strictNestedShadowAndMaybeEval("p = 2"), ["p = 2"]), true);
|
||||
assertEq(arraysEqual(strictNestedShadowAndMaybeEval("p = 2", 17), ["p = 2", 17]), true);
|
||||
assertEq(arraysEqual(strictNestedShadowAndMaybeEval("arguments[0] = 17"), ["arguments[0] = 17"]), true);
|
||||
assertEq(arraysEqual(strictNestedShadowAndMaybeEval("arguments[0] = 17", 42), ["arguments[0] = 17", 42]), true);
|
||||
|
||||
function strictNestedShadowAndEval(code, p)
|
||||
{
|
||||
"use strict";
|
||||
function inner(p) { eval(code); }
|
||||
return arguments;
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(strictNestedShadowAndEval("1", 2), ["1", 2]), true);
|
||||
assertEq(arraysEqual(strictNestedShadowAndEval("arguments"), ["arguments"]), true);
|
||||
assertEq(arraysEqual(strictNestedShadowAndEval("p = 2"), ["p = 2"]), true);
|
||||
assertEq(arraysEqual(strictNestedShadowAndEval("p = 2", 17), ["p = 2", 17]), true);
|
||||
assertEq(arraysEqual(strictNestedShadowAndEval("arguments[0] = 17"), ["arguments[0] = 17"]), true);
|
||||
assertEq(arraysEqual(strictNestedShadowAndEval("arguments[0] = 17", 42), ["arguments[0] = 17", 42]), true);
|
||||
|
||||
function strictEvalContainsMutation(code)
|
||||
{
|
||||
"use strict";
|
||||
return eval(code);
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(strictEvalContainsMutation("code = 17; arguments"), ["code = 17; arguments"]), true);
|
||||
assertEq(arraysEqual(strictEvalContainsMutation("arguments[0] = 17; arguments"), [17]), true);
|
||||
assertEq(strictEvalContainsMutation("arguments[0] = 17; code"), "arguments[0] = 17; code");
|
||||
|
||||
function strictNestedAssignShadowFunctionName(p)
|
||||
{
|
||||
"use strict";
|
||||
function inner()
|
||||
{
|
||||
function p() { p = 1776; }
|
||||
p();
|
||||
}
|
||||
inner();
|
||||
return arguments;
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(strictNestedAssignShadowFunctionName(), []), true);
|
||||
assertEq(arraysEqual(strictNestedAssignShadowFunctionName(99), [99]), true);
|
||||
assertEq(arraysEqual(strictNestedAssignShadowFunctionName(""), [""]), true);
|
||||
assertEq(arraysEqual(strictNestedAssignShadowFunctionName(obj), [obj]), true);
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
print("All tests passed!");
|
|
@ -1,2 +1,3 @@
|
|||
url-prefix ../../jsreftest.html?test=ecma_5/JSON/
|
||||
script cyclic-stringify.js
|
||||
script stringify-gap.js
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
var gTestfile = 'stringify-gap.js';
|
||||
//-----------------------------------------------------------------------------
|
||||
var BUGNUMBER = 584909;
|
||||
var summary =
|
||||
"JSON.stringify(_1, _2, numberGreaterThanOne) produces wrong output";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
/**************
|
||||
* BEGIN TEST *
|
||||
**************/
|
||||
|
||||
var LF = "\n";
|
||||
var GAP = " ";
|
||||
|
||||
var obj = { a: { b: [1, 2], c: { d: 3, e: 4 }, f: [], g: {}, h: [5], i: { j: 6 } } };
|
||||
|
||||
var expected =
|
||||
'{\n' +
|
||||
' "a": {\n' +
|
||||
' "b": [\n' +
|
||||
' 1,\n' +
|
||||
' 2\n' +
|
||||
' ],\n' +
|
||||
' "c": {\n' +
|
||||
' "d": 3,\n' +
|
||||
' "e": 4\n' +
|
||||
' },\n' +
|
||||
' "f": [],\n' +
|
||||
' "g": {},\n' +
|
||||
' "h": [\n' +
|
||||
' 5\n' +
|
||||
' ],\n' +
|
||||
' "i": {\n' +
|
||||
' "j": 6\n' +
|
||||
' }\n' +
|
||||
' }\n' +
|
||||
'}';
|
||||
|
||||
assertEq(JSON.stringify(obj, null, 3), expected);
|
||||
assertEq(JSON.stringify(obj, null, " "), expected);
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
print("All tests passed!");
|
|
@ -156,7 +156,7 @@ expectDescriptor(pd, expected);
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
o = { get y() { return 17; }, set y() { } };
|
||||
o = { get y() { return 17; }, set y(z) { } };
|
||||
|
||||
pd = Object.getOwnPropertyDescriptor(o, "y");
|
||||
expected =
|
||||
|
|
|
@ -103,32 +103,32 @@ assertEq(testLenientAndStrict('({x:1, get x() {}})',
|
|||
parseRaisesException(SyntaxError)),
|
||||
true);
|
||||
|
||||
assertEq(testLenientAndStrict('({set x() {}, x:1})',
|
||||
assertEq(testLenientAndStrict('({set x(q) {}, x:1})',
|
||||
parsesSuccessfully,
|
||||
parseRaisesException(SyntaxError)),
|
||||
true);
|
||||
|
||||
assertEq(testLenientAndStrict('({x:1, set x() {}})',
|
||||
assertEq(testLenientAndStrict('({x:1, set x(q) {}})',
|
||||
parsesSuccessfully,
|
||||
parseRaisesException(SyntaxError)),
|
||||
true);
|
||||
|
||||
assertEq(testLenientAndStrict('({get x() {}, set x() {}})',
|
||||
assertEq(testLenientAndStrict('({get x() {}, set x(q) {}})',
|
||||
parsesSuccessfully,
|
||||
parsesSuccessfully),
|
||||
true);
|
||||
|
||||
assertEq(testLenientAndStrict('({set x() {}, get x() {}})',
|
||||
assertEq(testLenientAndStrict('({set x(q) {}, get x() {}})',
|
||||
parsesSuccessfully,
|
||||
parsesSuccessfully),
|
||||
true);
|
||||
|
||||
assertEq(testLenientAndStrict('({get x() {}, set x() {}, x:1})',
|
||||
assertEq(testLenientAndStrict('({get x() {}, set x(q) {}, x:1})',
|
||||
parsesSuccessfully,
|
||||
parseRaisesException(SyntaxError)),
|
||||
true);
|
||||
|
||||
assertEq(testLenientAndStrict('({set x() {}, get x() {}, x:1})',
|
||||
assertEq(testLenientAndStrict('({set x(q) {}, get x() {}, x:1})',
|
||||
parsesSuccessfully,
|
||||
parseRaisesException(SyntaxError)),
|
||||
true);
|
||||
|
@ -138,7 +138,7 @@ assertEq(testLenientAndStrict('({get x() {}, get x() {}})',
|
|||
parseRaisesException(SyntaxError)),
|
||||
true);
|
||||
|
||||
assertEq(testLenientAndStrict('({get x() {}, set x() {}, y:1})',
|
||||
assertEq(testLenientAndStrict('({get x() {}, set x(q) {}, y:1})',
|
||||
parsesSuccessfully,
|
||||
parsesSuccessfully),
|
||||
true);
|
||||
|
|
|
@ -82,27 +82,6 @@ assertEq(testLenientAndStrict('Function("x","y","\'use strict\'")',
|
|||
true);
|
||||
|
||||
|
||||
/*
|
||||
* The parameter lists of getters and setters in object literals
|
||||
* should not contain duplicate identifiers.
|
||||
*/
|
||||
assertEq(testLenientAndStrict('({get x(y,y) {}})',
|
||||
parsesSuccessfully,
|
||||
parseRaisesException(SyntaxError)),
|
||||
true);
|
||||
assertEq(testLenientAndStrict('({get x(y,y) { "use strict"; }})',
|
||||
parseRaisesException(SyntaxError),
|
||||
parseRaisesException(SyntaxError)),
|
||||
true);
|
||||
assertEq(testLenientAndStrict('({set x(y,y) {}})',
|
||||
parsesSuccessfully,
|
||||
parseRaisesException(SyntaxError)),
|
||||
true);
|
||||
assertEq(testLenientAndStrict('({set x(y,y) { "use strict"; }})',
|
||||
parseRaisesException(SyntaxError),
|
||||
parseRaisesException(SyntaxError)),
|
||||
true);
|
||||
|
||||
/*
|
||||
* The parameter lists of function expressions should not contain
|
||||
* duplicate identifiers.
|
||||
|
@ -210,30 +189,6 @@ assertEq(testLenientAndStrict('(function eval() 2)',
|
|||
parsesSuccessfully,
|
||||
parseRaisesException(SyntaxError)),
|
||||
true);
|
||||
assertEq(testLenientAndStrict('({get x(eval){}})',
|
||||
parsesSuccessfully,
|
||||
parseRaisesException(SyntaxError)),
|
||||
true);
|
||||
assertEq(testLenientAndStrict('({get x([eval]){}})',
|
||||
parsesSuccessfully,
|
||||
parseRaisesException(SyntaxError)),
|
||||
true);
|
||||
assertEq(testLenientAndStrict('({get x({x:eval}){}})',
|
||||
parsesSuccessfully,
|
||||
parseRaisesException(SyntaxError)),
|
||||
true);
|
||||
assertEq(testLenientAndStrict('({get x(eval){"use strict";}})',
|
||||
parseRaisesException(SyntaxError),
|
||||
parseRaisesException(SyntaxError)),
|
||||
true);
|
||||
assertEq(testLenientAndStrict('({get x([eval]){"use strict";}})',
|
||||
parseRaisesException(SyntaxError),
|
||||
parseRaisesException(SyntaxError)),
|
||||
true);
|
||||
assertEq(testLenientAndStrict('({get x({x:eval}){"use strict";}})',
|
||||
parseRaisesException(SyntaxError),
|
||||
parseRaisesException(SyntaxError)),
|
||||
true);
|
||||
assertEq(testLenientAndStrict('({set x(eval){}})',
|
||||
parsesSuccessfully,
|
||||
parseRaisesException(SyntaxError)),
|
||||
|
@ -338,30 +293,6 @@ assertEq(testLenientAndStrict('(function arguments() 2)',
|
|||
parsesSuccessfully,
|
||||
parseRaisesException(SyntaxError)),
|
||||
true);
|
||||
assertEq(testLenientAndStrict('({get x(arguments){}})',
|
||||
parsesSuccessfully,
|
||||
parseRaisesException(SyntaxError)),
|
||||
true);
|
||||
assertEq(testLenientAndStrict('({get x([arguments]){}})',
|
||||
parsesSuccessfully,
|
||||
parseRaisesException(SyntaxError)),
|
||||
true);
|
||||
assertEq(testLenientAndStrict('({get x({x:arguments}){}})',
|
||||
parsesSuccessfully,
|
||||
parseRaisesException(SyntaxError)),
|
||||
true);
|
||||
assertEq(testLenientAndStrict('({get x(arguments){"use strict";}})',
|
||||
parseRaisesException(SyntaxError),
|
||||
parseRaisesException(SyntaxError)),
|
||||
true);
|
||||
assertEq(testLenientAndStrict('({get x([arguments]){"use strict";}})',
|
||||
parseRaisesException(SyntaxError),
|
||||
parseRaisesException(SyntaxError)),
|
||||
true);
|
||||
assertEq(testLenientAndStrict('({get x({x:arguments}){"use strict";}})',
|
||||
parseRaisesException(SyntaxError),
|
||||
parseRaisesException(SyntaxError)),
|
||||
true);
|
||||
assertEq(testLenientAndStrict('({set x(arguments){}})',
|
||||
parsesSuccessfully,
|
||||
parseRaisesException(SyntaxError)),
|
||||
|
|
|
@ -52,14 +52,14 @@ function test()
|
|||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
var f = function() { return { set this() { } }; } ;
|
||||
expect = 'function() { return { set this() { } }; }';
|
||||
var f = function() { return { set this(v) { } }; } ;
|
||||
expect = 'function() { return { set this(v) { } }; }';
|
||||
actual = f + '';
|
||||
|
||||
compareSource(expect, actual, summary);
|
||||
|
||||
expect = "({ set ''() {} })";
|
||||
actual = uneval({ set ''() {} });
|
||||
expect = "({ set ''(v) {} })";
|
||||
actual = uneval({ set ''(v) {} });
|
||||
compareSource(expect, actual, expect);
|
||||
exitFunc ('test');
|
||||
}
|
||||
|
|
|
@ -63,8 +63,8 @@ function test()
|
|||
|
||||
try
|
||||
{
|
||||
expect = 'TypeError: redeclaration of property a';
|
||||
var o = {a:4, a:5};
|
||||
expect = 'SyntaxError: property name a appears more than once in object literal';
|
||||
eval('({a:4, a:5})');
|
||||
// syntax warning, need to eval to catch
|
||||
actual = 'No warning';
|
||||
}
|
||||
|
@ -80,8 +80,8 @@ function test()
|
|||
|
||||
try
|
||||
{
|
||||
expect = 'TypeError: redeclaration of property 1';
|
||||
var o1 = {1:1, 1:2};
|
||||
expect = 'SyntaxError: property name 1 appears more than once in object literal';
|
||||
eval('({1:1, 1:2})');
|
||||
// syntax warning, need to eval to catch
|
||||
actual = 'No warning';
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ function test()
|
|||
try
|
||||
{
|
||||
expect = 'undefined';
|
||||
var a = { set x() {} };
|
||||
var a = { set x(v) {} };
|
||||
actual = a.x + '';
|
||||
}
|
||||
catch(ex)
|
||||
|
|
|
@ -55,7 +55,7 @@ function test()
|
|||
try
|
||||
{
|
||||
expect = 'undefined';
|
||||
var a = { set x() {} };
|
||||
var a = { set x(v) {} };
|
||||
for (var i = 0; i < 92169 - 3; ++i) a[i] = 1;
|
||||
actual = a.x + '';
|
||||
actual = a.x + '';
|
||||
|
|
|
@ -55,7 +55,7 @@ function test()
|
|||
try
|
||||
{
|
||||
expect = actual = 'No Crash';
|
||||
var a = { set x() {} };
|
||||
var a = { set x(v) {} };
|
||||
for (var i = 0; i < 0x4bf20 - 3; ++i) a[i] = 1;
|
||||
a.x;
|
||||
a.x.x;
|
||||
|
|
|
@ -55,7 +55,7 @@ function test()
|
|||
try
|
||||
{
|
||||
expect = actual = 'No Crash';
|
||||
var a = { set x() {} };
|
||||
var a = { set x(v) {} };
|
||||
for (var i = 0; i < 0x10050c - 3; ++i) a[i] = 1;
|
||||
a.x;
|
||||
typeof a.x;
|
||||
|
|
|
@ -64,7 +64,7 @@ function test()
|
|||
reportCompare(expect, actual, summary + ': 2');
|
||||
|
||||
// Assertion failure: JOF_OPTYPE(op) == JOF_ATOM, at ../jsemit.cpp:5916
|
||||
({ set z(){}, set y()--x, set w()--w });
|
||||
({ set z(v){}, set y(v)--x, set w(v)--w });
|
||||
reportCompare(expect, actual, summary + ': 3');
|
||||
|
||||
exitFunc ('test');
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
var gTestfile = 'destructure-accessor.js';
|
||||
//-----------------------------------------------------------------------------
|
||||
var BUGNUMBER = 536472;
|
||||
var summary =
|
||||
'ES5: { get x(v) { } } and { set x(v, v2) { } } should be syntax errors';
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function expectOk(s)
|
||||
{
|
||||
try
|
||||
{
|
||||
eval(s);
|
||||
return;
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(true, false,
|
||||
"expected no error parsing '" + "', got : " + e);
|
||||
}
|
||||
}
|
||||
|
||||
function expectSyntaxError(s)
|
||||
{
|
||||
try
|
||||
{
|
||||
eval(s);
|
||||
throw new Error("no error thrown");
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof SyntaxError, true,
|
||||
"expected syntax error parsing '" + s + "', got: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
expectSyntaxError("({ get x([]) { } })");
|
||||
expectSyntaxError("({ get x({}) { } })");
|
||||
expectSyntaxError("({ get x(a, []) { } })");
|
||||
expectSyntaxError("({ get x(a, {}) { } })");
|
||||
expectSyntaxError("({ get x([], a) { } })");
|
||||
expectSyntaxError("({ get x({}, a) { } })");
|
||||
expectSyntaxError("({ get x([], a, []) { } })");
|
||||
expectSyntaxError("({ get x([], a, {}) { } })");
|
||||
expectSyntaxError("({ get x({}, a, []) { } })");
|
||||
expectSyntaxError("({ get x({}, a, {}) { } })");
|
||||
|
||||
expectOk("({ get x() { } })");
|
||||
|
||||
|
||||
expectSyntaxError("({ set x() { } })");
|
||||
expectSyntaxError("({ set x(a, []) { } })");
|
||||
expectSyntaxError("({ set x(a, b, c) { } })");
|
||||
|
||||
expectOk("({ set x([]) { } })");
|
||||
expectOk("({ set x({}) { } })");
|
||||
expectOk("({ set x([a]) { } })");
|
||||
expectOk("({ set x([a, b]) { } })");
|
||||
expectOk("({ set x([a,]) { } })");
|
||||
expectOk("({ set x([a, b,]) { } })");
|
||||
expectOk("({ set x([, b]) { } })");
|
||||
expectOk("({ set x([, b,]) { } })");
|
||||
expectOk("({ set x([, b, c]) { } })");
|
||||
expectOk("({ set x([, b, c,]) { } })");
|
||||
expectOk("({ set x({ a: a }) { } })");
|
||||
expectOk("({ set x({ a: a, b: b }) { } })");
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
reportCompare(true, true);
|
|
@ -12,3 +12,5 @@ script scripted-proxies.js
|
|||
script array-length-protochange.js
|
||||
script parseInt-octal.js
|
||||
script proxy-enumerateOwn-duplicates.js
|
||||
skip-if(!xulRuntime.shell) script reflect-parse.js
|
||||
script destructure-accessor.js
|
||||
|
|
|
@ -0,0 +1,703 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
var { Pattern, MatchError } = Match;
|
||||
|
||||
var _ = Pattern.ANY;
|
||||
|
||||
function program(elts) Pattern({ type: "Program", body: elts })
|
||||
function exprStmt(expr) Pattern({ type: "ExpressionStatement", expression: expr })
|
||||
function throwStmt(expr) Pattern({ type: "ThrowStatement", argument: expr })
|
||||
function returnStmt(expr) Pattern({ type: "ReturnStatement", argument: expr })
|
||||
function yieldExpr(expr) Pattern({ type: "YieldExpression", argument: expr })
|
||||
function lit(val) Pattern({ type: "Literal", value: val })
|
||||
var thisExpr = Pattern({ type: "ThisExpression" });
|
||||
function funDecl(id, params, body) Pattern({ type: "FunctionDeclaration",
|
||||
id: id,
|
||||
params: params,
|
||||
body: body,
|
||||
generator: false })
|
||||
function genFunDecl(id, params, body) Pattern({ type: "FunctionDeclaration",
|
||||
id: id,
|
||||
params: params,
|
||||
body: body,
|
||||
generator: true })
|
||||
function varDecl(decls) Pattern({ type: "VariableDeclaration", declarations: decls, kind: "var" })
|
||||
function letDecl(decls) Pattern({ type: "VariableDeclaration", declarations: decls, kind: "let" })
|
||||
function constDecl(decls) Pattern({ type: "VariableDeclaration", declarations: decls, kind: "const" })
|
||||
function blockStmt(body) Pattern({ type: "BlockStatement", body: body })
|
||||
function ident(name) Pattern({ type: "Identifier", name: name })
|
||||
function dotExpr(obj, id) Pattern({ type: "MemberExpression", computed: false, object: obj, property: id })
|
||||
function memExpr(obj, id) Pattern({ type: "MemberExpression", computed: true, object: obj, property: id })
|
||||
function forStmt(init, test, update, body) Pattern({ type: "ForStatement", init: init, test: test, update: update, body: body })
|
||||
function forInStmt(lhs, rhs, body) Pattern({ type: "ForInStatement", left: lhs, right: rhs, body: body, each: false })
|
||||
function forEachInStmt(lhs, rhs, body) Pattern({ type: "ForInStatement", left: lhs, right: rhs, body: body, each: true })
|
||||
function breakStmt(lab) Pattern({ type: "BreakStatement", label: lab })
|
||||
function continueStmt(lab) Pattern({ type: "ContinueStatement", label: lab })
|
||||
function blockStmt(stmts) Pattern({ type: "BlockStatement", body: stmts })
|
||||
var emptyStmt = Pattern({ type: "EmptyStatement" })
|
||||
function ifStmt(test, cons, alt) Pattern({ type: "IfStatement", test: test, alternate: alt, consequent: cons })
|
||||
function labStmt(lab, stmt) Pattern({ type: "LabeledStatement", label: lab, body: stmt })
|
||||
function withStmt(obj, stmt) Pattern({ type: "WithStatement", object: obj, body: stmt })
|
||||
function whileStmt(test, stmt) Pattern({ type: "WhileStatement", test: test, body: stmt })
|
||||
function doStmt(stmt, test) Pattern({ type: "DoWhileStatement", test: test, body: stmt })
|
||||
function switchStmt(disc, cases) Pattern({ type: "SwitchStatement", discriminant: disc, cases: cases })
|
||||
function caseClause(test, stmts) Pattern({ type: "SwitchCase", test: test, consequent: stmts })
|
||||
function defaultClause(stmts) Pattern({ type: "SwitchCase", test: null, consequent: stmts })
|
||||
function catchClause(id, guard, body) Pattern({ type: "CatchClause", param: id, guard: guard, body: body })
|
||||
function tryStmt(body, catches, fin) Pattern({ type: "TryStatement", block: body, handler: catches, finalizer: fin })
|
||||
function funExpr(id, args, body, gen) Pattern({ type: "FunctionExpression",
|
||||
id: id,
|
||||
params: args,
|
||||
body: body,
|
||||
generator: false })
|
||||
function genFunExpr(id, args, body) Pattern({ type: "FunctionExpression",
|
||||
id: id,
|
||||
params: args,
|
||||
body: body,
|
||||
generator: true })
|
||||
|
||||
function unExpr(op, arg) Pattern({ type: "UnaryExpression", operator: op, argument: arg })
|
||||
function binExpr(op, left, right) Pattern({ type: "BinaryExpression", operator: op, left: left, right: right })
|
||||
function aExpr(op, left, right) Pattern({ type: "AssignmentExpression", operator: op, left: left, right: right })
|
||||
function updExpr(op, arg, prefix) Pattern({ type: "UpdateExpression", operator: op, argument: arg, prefix: prefix })
|
||||
function logExpr(op, left, right) Pattern({ type: "LogicalExpression", operator: op, left: left, right: right })
|
||||
|
||||
function condExpr(test, cons, alt) Pattern({ type: "ConditionalExpression", test: test, consequent: cons, alternate: alt })
|
||||
function seqExpr(exprs) Pattern({ type: "SequenceExpression", expressions: exprs })
|
||||
function newExpr(callee, args) Pattern({ type: "NewExpression", callee: callee, arguments: args })
|
||||
function callExpr(callee, args) Pattern({ type: "CallExpression", callee: callee, arguments: args })
|
||||
function arrExpr(elts) Pattern({ type: "ArrayExpression", elements: elts })
|
||||
function objExpr(elts) Pattern({ type: "ObjectExpression", properties: elts })
|
||||
function compExpr(body, blocks, filter) Pattern({ type: "ComprehensionExpression", body: body, blocks: blocks, filter: filter })
|
||||
function genExpr(body, blocks, filter) Pattern({ type: "GeneratorExpression", body: body, blocks: blocks, filter: filter })
|
||||
function graphExpr(idx, body) Pattern({ type: "GraphExpression", index: idx, expression: body })
|
||||
function idxExpr(idx) Pattern({ type: "GraphIndexExpression", index: idx })
|
||||
|
||||
function compBlock(left, right) Pattern({ type: "ComprehensionBlock", left: left, right: right, each: false })
|
||||
function compEachBlock(left, right) Pattern({ type: "ComprehensionBlock", left: left, right: right, each: true })
|
||||
|
||||
function arrPatt(elts) Pattern({ type: "ArrayPattern", elements: elts })
|
||||
function objPatt(elts) Pattern({ type: "ObjectPattern", properties: elts })
|
||||
|
||||
function localSrc(src) "(function(){ " + src + " })"
|
||||
function localPatt(patt) program([exprStmt(funExpr(null, [], blockStmt([patt])))])
|
||||
function blockSrc(src) "(function(){ { " + src + " } })"
|
||||
function blockPatt(patt) program([exprStmt(funExpr(null, [], blockStmt([blockStmt([patt])])))])
|
||||
|
||||
var xmlAnyName = Pattern({ type: "XMLAnyName" });
|
||||
|
||||
function xmlQualId(left, right, computed) Pattern({ type: "XMLQualifiedIdentifier", left: left, right: right, computed: computed })
|
||||
function xmlAttrSel(id) Pattern({ type: "XMLAttributeSelector", attribute: id })
|
||||
function xmlFilter(left, right) Pattern({ type: "XMLFilterExpression", left: left, right: right })
|
||||
function xmlPointTag(contents) Pattern({ type: "XMLPointTag", contents: contents })
|
||||
function xmlStartTag(contents) Pattern({ type: "XMLStartTag", contents: contents })
|
||||
function xmlEndTag(contents) Pattern({ type: "XMLEndTag", contents: contents })
|
||||
function xmlEscape(expr) Pattern({ type: "XMLEscape", expression: expr })
|
||||
function xmlElt(contents) Pattern({ type: "XMLElement", contents: contents })
|
||||
function xmlAttr(value) Pattern({ type: "XMLAttribute", value: value })
|
||||
function xmlText(text) Pattern({ type: "XMLText", text: text })
|
||||
function xmlPI(target, contents) Pattern({ type: "XMLProcessingInstruction", target: target, contents: contents })
|
||||
|
||||
function assertBlockStmt(src, patt) {
|
||||
blockPatt(patt).assert(Reflect.parse(blockSrc(src)));
|
||||
}
|
||||
|
||||
function assertBlockExpr(src, patt) {
|
||||
assertBlockStmt(src, exprStmt(patt));
|
||||
}
|
||||
|
||||
function assertBlockDecl(src, patt) {
|
||||
blockPatt(patt).assert(Reflect.parse(blockSrc(src)));
|
||||
}
|
||||
|
||||
function assertLocalStmt(src, patt) {
|
||||
localPatt(patt).assert(Reflect.parse(localSrc(src)));
|
||||
}
|
||||
|
||||
function assertLocalExpr(src, patt) {
|
||||
assertLocalStmt(src, exprStmt(patt));
|
||||
}
|
||||
|
||||
function assertLocalDecl(src, patt) {
|
||||
localPatt(patt).assert(Reflect.parse(localSrc(src)));
|
||||
}
|
||||
|
||||
function assertGlobalStmt(src, patt) {
|
||||
program([patt]).assert(Reflect.parse(src));
|
||||
}
|
||||
|
||||
function assertGlobalExpr(src, patt) {
|
||||
assertStmt(src, exprStmt(patt));
|
||||
}
|
||||
|
||||
function assertGlobalDecl(src, patt) {
|
||||
program([patt]).assert(Reflect.parse(src));
|
||||
}
|
||||
|
||||
function assertStmt(src, patt) {
|
||||
assertLocalStmt(src, patt);
|
||||
assertGlobalStmt(src, patt);
|
||||
assertBlockStmt(src, patt);
|
||||
}
|
||||
|
||||
function assertExpr(src, patt) {
|
||||
assertLocalExpr(src, patt);
|
||||
assertGlobalExpr(src, patt);
|
||||
assertBlockExpr(src, patt);
|
||||
}
|
||||
|
||||
function assertDecl(src, patt) {
|
||||
assertLocalDecl(src, patt);
|
||||
assertGlobalDecl(src, patt);
|
||||
assertBlockDecl(src, patt);
|
||||
}
|
||||
|
||||
// general tests
|
||||
|
||||
// NB: These are useful but for now trace-test doesn't do I/O reliably.
|
||||
|
||||
//program(_).assert(Reflect.parse(snarf('data/flapjax.txt')));
|
||||
//program(_).assert(Reflect.parse(snarf('data/jquery-1.4.2.txt')));
|
||||
//program(_).assert(Reflect.parse(snarf('data/prototype.js')));
|
||||
//program(_).assert(Reflect.parse(snarf('data/dojo.js.uncompressed.js')));
|
||||
//program(_).assert(Reflect.parse(snarf('data/mootools-1.2.4-core-nc.js')));
|
||||
|
||||
|
||||
// declarations
|
||||
|
||||
assertDecl("var x = 1, y = 2, z = 3",
|
||||
varDecl([{ id: ident("x"), init: lit(1) },
|
||||
{ id: ident("y"), init: lit(2) },
|
||||
{ id: ident("z"), init: lit(3) }]));
|
||||
assertDecl("var x, y, z",
|
||||
varDecl([{ id: ident("x"), init: null },
|
||||
{ id: ident("y"), init: null },
|
||||
{ id: ident("z"), init: null }]));
|
||||
assertDecl("function foo() { }",
|
||||
funDecl(ident("foo"), [], blockStmt([])));
|
||||
assertDecl("function foo() { return 42 }",
|
||||
funDecl(ident("foo"), [], blockStmt([returnStmt(lit(42))])));
|
||||
|
||||
|
||||
// expressions
|
||||
|
||||
assertExpr("true", lit(true));
|
||||
assertExpr("false", lit(false));
|
||||
assertExpr("42", lit(42));
|
||||
assertExpr("(/asdf/)", lit(/asdf/));
|
||||
assertExpr("this", thisExpr);
|
||||
assertExpr("foo", ident("foo"));
|
||||
assertExpr("foo.bar", dotExpr(ident("foo"), ident("bar")));
|
||||
assertExpr("foo[bar]", memExpr(ident("foo"), ident("bar")));
|
||||
assertExpr("(function(){})", funExpr(null, [], blockStmt([])));
|
||||
assertExpr("(function f() {})", funExpr(ident("f"), [], blockStmt([])));
|
||||
assertExpr("(function f(x,y,z) {})", funExpr(ident("f"), [ident("x"),ident("y"),ident("z")], blockStmt([])));
|
||||
assertExpr("(++x)", updExpr("++", ident("x"), true));
|
||||
assertExpr("(x++)", updExpr("++", ident("x"), false));
|
||||
assertExpr("(+x)", unExpr("+", ident("x")));
|
||||
assertExpr("(-x)", unExpr("-", ident("x")));
|
||||
assertExpr("(!x)", unExpr("!", ident("x")));
|
||||
assertExpr("(~x)", unExpr("~", ident("x")));
|
||||
assertExpr("(delete x)", unExpr("delete", ident("x")));
|
||||
assertExpr("(typeof x)", unExpr("typeof", ident("x")));
|
||||
assertExpr("(void x)", unExpr("void", ident("x")));
|
||||
assertExpr("(x == y)", binExpr("==", ident("x"), ident("y")));
|
||||
assertExpr("(x != y)", binExpr("!=", ident("x"), ident("y")));
|
||||
assertExpr("(x === y)", binExpr("===", ident("x"), ident("y")));
|
||||
assertExpr("(x !== y)", binExpr("!==", ident("x"), ident("y")));
|
||||
assertExpr("(x < y)", binExpr("<", ident("x"), ident("y")));
|
||||
assertExpr("(x <= y)", binExpr("<=", ident("x"), ident("y")));
|
||||
assertExpr("(x > y)", binExpr(">", ident("x"), ident("y")));
|
||||
assertExpr("(x >= y)", binExpr(">=", ident("x"), ident("y")));
|
||||
assertExpr("(x << y)", binExpr("<<", ident("x"), ident("y")));
|
||||
assertExpr("(x >> y)", binExpr(">>", ident("x"), ident("y")));
|
||||
assertExpr("(x >>> y)", binExpr(">>>", ident("x"), ident("y")));
|
||||
assertExpr("(x + y)", binExpr("+", ident("x"), ident("y")));
|
||||
assertExpr("(w + x + y + z)", binExpr("+", ident("w"), binExpr("+", ident("x", binExpr("+", ident("y"), ident("z"))))))
|
||||
assertExpr("(x - y)", binExpr("-", ident("x"), ident("y")));
|
||||
assertExpr("(x * y)", binExpr("*", ident("x"), ident("y")));
|
||||
assertExpr("(x / y)", binExpr("/", ident("x"), ident("y")));
|
||||
assertExpr("(x % y)", binExpr("%", ident("x"), ident("y")));
|
||||
assertExpr("(x | y)", binExpr("|", ident("x"), ident("y")));
|
||||
assertExpr("(x ^ y)", binExpr("^", ident("x"), ident("y")));
|
||||
assertExpr("(x & y)", binExpr("&", ident("x"), ident("y")));
|
||||
assertExpr("(x in y)", binExpr("in", ident("x"), ident("y")));
|
||||
assertExpr("(x instanceof y)", binExpr("instanceof", ident("x"), ident("y")));
|
||||
assertExpr("(x = y)", aExpr("=", ident("x"), ident("y")));
|
||||
assertExpr("(x += y)", aExpr("+=", ident("x"), ident("y")));
|
||||
assertExpr("(x -= y)", aExpr("-=", ident("x"), ident("y")));
|
||||
assertExpr("(x *= y)", aExpr("*=", ident("x"), ident("y")));
|
||||
assertExpr("(x /= y)", aExpr("/=", ident("x"), ident("y")));
|
||||
assertExpr("(x %= y)", aExpr("%=", ident("x"), ident("y")));
|
||||
assertExpr("(x <<= y)", aExpr("<<=", ident("x"), ident("y")));
|
||||
assertExpr("(x >>= y)", aExpr(">>=", ident("x"), ident("y")));
|
||||
assertExpr("(x >>>= y)", aExpr(">>>=", ident("x"), ident("y")));
|
||||
assertExpr("(x |= y)", aExpr("|=", ident("x"), ident("y")));
|
||||
assertExpr("(x ^= y)", aExpr("^=", ident("x"), ident("y")));
|
||||
assertExpr("(x &= y)", aExpr("&=", ident("x"), ident("y")));
|
||||
assertExpr("(x || y)", logExpr("||", ident("x"), ident("y")));
|
||||
assertExpr("(x && y)", logExpr("&&", ident("x"), ident("y")));
|
||||
assertExpr("(w || x || y || z)", logExpr("||", ident("w"), logExpr("||", ident("x", logExpr("||", ident("y"), ident("z"))))))
|
||||
assertExpr("(x ? y : z)", condExpr(ident("x"), ident("y"), ident("z")));
|
||||
assertExpr("(x,y)", seqExpr([ident("x"),ident("y")]))
|
||||
assertExpr("(x,y,z)", seqExpr([ident("x"),ident("y"),ident("z")]))
|
||||
assertExpr("(a,b,c,d,e,f,g)", seqExpr([ident("a"),ident("b"),ident("c"),ident("d"),ident("e"),ident("f"),ident("g")]));
|
||||
assertExpr("(new Object)", newExpr(ident("Object"), []));
|
||||
assertExpr("(new Object())", newExpr(ident("Object"), []));
|
||||
assertExpr("(new Object(42))", newExpr(ident("Object"), [lit(42)]));
|
||||
assertExpr("(new Object(1,2,3))", newExpr(ident("Object"), [lit(1),lit(2),lit(3)]));
|
||||
assertExpr("(String())", callExpr(ident("String"), []));
|
||||
assertExpr("(String(42))", callExpr(ident("String"), [lit(42)]));
|
||||
assertExpr("(String(1,2,3))", callExpr(ident("String"), [lit(1),lit(2),lit(3)]));
|
||||
assertExpr("[]", arrExpr([]));
|
||||
assertExpr("[1]", arrExpr([lit(1)]));
|
||||
assertExpr("[1,2]", arrExpr([lit(1),lit(2)]));
|
||||
assertExpr("[1,2,3]", arrExpr([lit(1),lit(2),lit(3)]));
|
||||
assertExpr("[1,,2,3]", arrExpr([lit(1),null,lit(2),lit(3)]));
|
||||
assertExpr("[1,,,2,3]", arrExpr([lit(1),null,null,lit(2),lit(3)]));
|
||||
assertExpr("[1,,,2,,3]", arrExpr([lit(1),null,null,lit(2),null,lit(3)]));
|
||||
assertExpr("[1,,,2,,,3]", arrExpr([lit(1),null,null,lit(2),null,null,lit(3)]));
|
||||
assertExpr("[,1,2,3]", arrExpr([null,lit(1),lit(2),lit(3)]));
|
||||
assertExpr("[,,1,2,3]", arrExpr([null,null,lit(1),lit(2),lit(3)]));
|
||||
assertExpr("[,,,1,2,3]", arrExpr([null,null,null,lit(1),lit(2),lit(3)]));
|
||||
assertExpr("[,,,1,2,3,]", arrExpr([null,null,null,lit(1),lit(2),lit(3)]));
|
||||
assertExpr("[,,,1,2,3,,]", arrExpr([null,null,null,lit(1),lit(2),lit(3),null]));
|
||||
assertExpr("[,,,1,2,3,,,]", arrExpr([null,null,null,lit(1),lit(2),lit(3),null,null]));
|
||||
assertExpr("[,,,,,]", arrExpr([null,null,null,null,null]));
|
||||
assertExpr("({})", objExpr([]));
|
||||
assertExpr("({x:1})", objExpr([{ key: ident("x"), value: lit(1) }]));
|
||||
assertExpr("({x:1, y:2})", objExpr([{ key: ident("x"), value: lit(1) },
|
||||
{ key: ident("y"), value: lit(2) } ]));
|
||||
assertExpr("({x:1, y:2, z:3})", objExpr([{ key: ident("x"), value: lit(1) },
|
||||
{ key: ident("y"), value: lit(2) },
|
||||
{ key: ident("z"), value: lit(3) } ]));
|
||||
assertExpr("({x:1, 'y':2, z:3})", objExpr([{ key: ident("x"), value: lit(1) },
|
||||
{ key: lit("y"), value: lit(2) },
|
||||
{ key: ident("z"), value: lit(3) } ]));
|
||||
assertExpr("({'x':1, 'y':2, z:3})", objExpr([{ key: lit("x"), value: lit(1) },
|
||||
{ key: lit("y"), value: lit(2) },
|
||||
{ key: ident("z"), value: lit(3) } ]));
|
||||
assertExpr("({'x':1, 'y':2, 3:3})", objExpr([{ key: lit("x"), value: lit(1) },
|
||||
{ key: lit("y"), value: lit(2) },
|
||||
{ key: lit(3), value: lit(3) } ]));
|
||||
|
||||
// statements
|
||||
|
||||
assertStmt("throw 42", throwStmt(lit(42)));
|
||||
assertStmt("for (;;) break", forStmt(null, null, null, breakStmt(null)));
|
||||
assertStmt("for (x; y; z) break", forStmt(ident("x"), ident("y"), ident("z"), breakStmt(null)));
|
||||
assertStmt("for (var x; y; z) break", forStmt(varDecl([{ id: ident("x"), init: null }]), ident("y"), ident("z")));
|
||||
assertStmt("for (var x = 42; y; z) break", forStmt(varDecl([{ id: ident("x"), init: lit(42) }]), ident("y"), ident("z")));
|
||||
assertStmt("for (x; ; z) break", forStmt(ident("x"), null, ident("z"), breakStmt(null)));
|
||||
assertStmt("for (var x; ; z) break", forStmt(varDecl([{ id: ident("x"), init: null }]), null, ident("z")));
|
||||
assertStmt("for (var x = 42; ; z) break", forStmt(varDecl([{ id: ident("x"), init: lit(42) }]), null, ident("z")));
|
||||
assertStmt("for (x; y; ) break", forStmt(ident("x"), ident("y"), null, breakStmt(null)));
|
||||
assertStmt("for (var x; y; ) break", forStmt(varDecl([{ id: ident("x"), init: null }]), ident("y"), null, breakStmt(null)));
|
||||
assertStmt("for (var x = 42; y; ) break", forStmt(varDecl([{ id: ident("x"), init: lit(42) }]), ident("y"), null, breakStmt(null)));
|
||||
assertStmt("for (var x in y) break", forInStmt(varDecl([{ id: ident("x"), init: null }]), ident("y"), breakStmt(null)));
|
||||
assertStmt("for (x in y) break", forInStmt(ident("x"), ident("y"), breakStmt(null)));
|
||||
assertStmt("{ }", blockStmt([]));
|
||||
assertStmt("{ throw 1; throw 2; throw 3; }", blockStmt([ throwStmt(lit(1)), throwStmt(lit(2)), throwStmt(lit(3))]));
|
||||
assertStmt(";", emptyStmt);
|
||||
assertStmt("if (foo) throw 42;", ifStmt(ident("foo"), throwStmt(lit(42)), null));
|
||||
assertStmt("if (foo) throw 42; else true;", ifStmt(ident("foo"), throwStmt(lit(42)), exprStmt(lit(true))));
|
||||
assertStmt("if (foo) { throw 1; throw 2; throw 3; }",
|
||||
ifStmt(ident("foo"),
|
||||
blockStmt([throwStmt(lit(1)), throwStmt(lit(2)), throwStmt(lit(3))]),
|
||||
null));
|
||||
assertStmt("if (foo) { throw 1; throw 2; throw 3; } else true;",
|
||||
ifStmt(ident("foo"),
|
||||
blockStmt([throwStmt(lit(1)), throwStmt(lit(2)), throwStmt(lit(3))]),
|
||||
exprStmt(lit(true))));
|
||||
assertStmt("foo: for(;;) break foo;", labStmt(ident("foo"), forStmt(null, null, null, breakStmt(ident("foo")))));
|
||||
assertStmt("foo: for(;;) continue foo;", labStmt(ident("foo"), forStmt(null, null, null, continueStmt(ident("foo")))));
|
||||
assertStmt("with (obj) { }", withStmt(ident("obj"), blockStmt([])));
|
||||
assertStmt("with (obj) { obj; }", withStmt(ident("obj"), blockStmt([exprStmt(ident("obj"))])));
|
||||
assertStmt("while (foo) { }", whileStmt(ident("foo"), blockStmt([])));
|
||||
assertStmt("while (foo) { foo; }", whileStmt(ident("foo"), blockStmt([exprStmt(ident("foo"))])));
|
||||
assertStmt("do { } while (foo);", doStmt(blockStmt([]), ident("foo")));
|
||||
assertStmt("do { foo; } while (foo)", doStmt(blockStmt([exprStmt(ident("foo"))]), ident("foo")));
|
||||
assertStmt("switch (foo) { case 1: 1; break; case 2: 2; break; default: 3; }",
|
||||
switchStmt(ident("foo"),
|
||||
[ caseClause(lit(1), [ exprStmt(lit(1)), breakStmt(null) ]),
|
||||
caseClause(lit(2), [ exprStmt(lit(2)), breakStmt(null) ]),
|
||||
defaultClause([ exprStmt(lit(3)) ]) ]));
|
||||
assertStmt("switch (foo) { case 1: 1; break; case 2: 2; break; default: 3; case 42: 42; }",
|
||||
switchStmt(ident("foo"),
|
||||
[ caseClause(lit(1), [ exprStmt(lit(1)), breakStmt(null) ]),
|
||||
caseClause(lit(2), [ exprStmt(lit(2)), breakStmt(null) ]),
|
||||
defaultClause([ exprStmt(lit(3)) ]),
|
||||
caseClause(lit(42), [ exprStmt(lit(42)) ]) ]));
|
||||
assertStmt("try { } catch (e) { }",
|
||||
tryStmt(blockStmt([]),
|
||||
catchClause(ident("e"), null, blockStmt([])),
|
||||
null));
|
||||
assertStmt("try { } catch (e) { } finally { }",
|
||||
tryStmt(blockStmt([]),
|
||||
catchClause(ident("e"), null, blockStmt([])),
|
||||
blockStmt([])));
|
||||
assertStmt("try { } finally { }",
|
||||
tryStmt(blockStmt([]),
|
||||
null,
|
||||
blockStmt([])));
|
||||
assertStmt("try { } catch (e if foo) { } catch (e if bar) { } finally { }",
|
||||
tryStmt(blockStmt([]),
|
||||
[ catchClause(ident("e"), ident("foo"), blockStmt([])),
|
||||
catchClause(ident("e"), ident("bar"), blockStmt([])) ],
|
||||
blockStmt([])));
|
||||
assertStmt("try { } catch (e if foo) { } catch (e if bar) { } catch (e) { } finally { }",
|
||||
tryStmt(blockStmt([]),
|
||||
[ catchClause(ident("e"), ident("foo"), blockStmt([])),
|
||||
catchClause(ident("e"), ident("bar"), blockStmt([])),
|
||||
catchClause(ident("e"), null, blockStmt([])) ],
|
||||
blockStmt([])));
|
||||
|
||||
assertDecl("var {x:y} = foo;", varDecl([{ id: objPatt([{ key: ident("x"), value: ident("y") }]),
|
||||
init: ident("foo") }]));
|
||||
|
||||
// global let is var
|
||||
assertGlobalDecl("let {x:y} = foo;", varDecl([{ id: objPatt([{ key: ident("x"), value: ident("y") }]),
|
||||
init: ident("foo") }]));
|
||||
// function-global let is var
|
||||
assertLocalDecl("let {x:y} = foo;", varDecl([{ id: objPatt([{ key: ident("x"), value: ident("y") }]),
|
||||
init: ident("foo") }]));
|
||||
// block-local let is let
|
||||
assertBlockDecl("let {x:y} = foo;", letDecl([{ id: objPatt([{ key: ident("x"), value: ident("y") }]),
|
||||
init: ident("foo") }]));
|
||||
|
||||
assertDecl("const {x:y} = foo;", constDecl([{ id: objPatt([{ key: ident("x"), value: ident("y") }]),
|
||||
init: ident("foo") }]));
|
||||
|
||||
|
||||
// various combinations of identifiers and destructuring patterns:
|
||||
function makePatternCombinations(id, destr)
|
||||
[
|
||||
[ id(1) ],
|
||||
[ id(1), id(2) ],
|
||||
[ id(1), id(2), id(3) ],
|
||||
[ id(1), id(2), id(3), id(4) ],
|
||||
[ id(1), id(2), id(3), id(4), id(5) ],
|
||||
|
||||
[ destr(1) ],
|
||||
[ destr(1), destr(2) ],
|
||||
[ destr(1), destr(2), destr(3) ],
|
||||
[ destr(1), destr(2), destr(3), destr(4) ],
|
||||
[ destr(1), destr(2), destr(3), destr(4), destr(5) ],
|
||||
|
||||
[ destr(1), id(2) ],
|
||||
|
||||
[ destr(1), id(2), id(3) ],
|
||||
[ destr(1), id(2), id(3), id(4) ],
|
||||
[ destr(1), id(2), id(3), id(4), id(5) ],
|
||||
[ destr(1), id(2), id(3), id(4), destr(5) ],
|
||||
[ destr(1), id(2), id(3), destr(4) ],
|
||||
[ destr(1), id(2), id(3), destr(4), id(5) ],
|
||||
[ destr(1), id(2), id(3), destr(4), destr(5) ],
|
||||
|
||||
[ destr(1), id(2), destr(3) ],
|
||||
[ destr(1), id(2), destr(3), id(4) ],
|
||||
[ destr(1), id(2), destr(3), id(4), id(5) ],
|
||||
[ destr(1), id(2), destr(3), id(4), destr(5) ],
|
||||
[ destr(1), id(2), destr(3), destr(4) ],
|
||||
[ destr(1), id(2), destr(3), destr(4), id(5) ],
|
||||
[ destr(1), id(2), destr(3), destr(4), destr(5) ],
|
||||
|
||||
[ id(1), destr(2) ],
|
||||
|
||||
[ id(1), destr(2), id(3) ],
|
||||
[ id(1), destr(2), id(3), id(4) ],
|
||||
[ id(1), destr(2), id(3), id(4), id(5) ],
|
||||
[ id(1), destr(2), id(3), id(4), destr(5) ],
|
||||
[ id(1), destr(2), id(3), destr(4) ],
|
||||
[ id(1), destr(2), id(3), destr(4), id(5) ],
|
||||
[ id(1), destr(2), id(3), destr(4), destr(5) ],
|
||||
|
||||
[ id(1), destr(2), destr(3) ],
|
||||
[ id(1), destr(2), destr(3), id(4) ],
|
||||
[ id(1), destr(2), destr(3), id(4), id(5) ],
|
||||
[ id(1), destr(2), destr(3), id(4), destr(5) ],
|
||||
[ id(1), destr(2), destr(3), destr(4) ],
|
||||
[ id(1), destr(2), destr(3), destr(4), id(5) ],
|
||||
[ id(1), destr(2), destr(3), destr(4), destr(5) ]
|
||||
]
|
||||
|
||||
// destructuring function parameters
|
||||
|
||||
function testParamPatternCombinations(makePattSrc, makePattPatt) {
|
||||
var pattSrcs = makePatternCombinations(function(n) ("x" + n), makePattSrc);
|
||||
var pattPatts = makePatternCombinations(function(n) (ident("x" + n)), makePattPatt);
|
||||
|
||||
for (var i = 0; i < pattSrcs.length; i++) {
|
||||
function makeSrc(body) ("(function(" + pattSrcs[i].join(",") + ") " + body + ")")
|
||||
function makePatt(body) (funExpr(null, pattPatts[i], body))
|
||||
|
||||
// no upvars, block body
|
||||
assertExpr(makeSrc("{ }", makePatt(blockStmt([]))));
|
||||
// upvars, block body
|
||||
assertExpr(makeSrc("{ return [x1,x2,x3,x4,x5]; }"),
|
||||
makePatt(blockStmt([returnStmt(arrExpr([ident("x1"), ident("x2"), ident("x3"), ident("x4"), ident("x5")]))])));
|
||||
// no upvars, expression body
|
||||
assertExpr(makeSrc("(0)"), makePatt(lit(0)));
|
||||
// upvars, expression body
|
||||
assertExpr(makeSrc("[x1,x2,x3,x4,x5]"),
|
||||
makePatt(arrExpr([ident("x1"), ident("x2"), ident("x3"), ident("x4"), ident("x5")])));
|
||||
}
|
||||
}
|
||||
|
||||
testParamPatternCombinations(function(n) ("{a" + n + ":x" + n + "," + "b" + n + ":y" + n + "," + "c" + n + ":z" + n + "}"),
|
||||
function(n) (objPatt([{ key: ident("a" + n), value: ident("x" + n) },
|
||||
{ key: ident("b" + n), value: ident("y" + n) },
|
||||
{ key: ident("c" + n), value: ident("z" + n) }])));
|
||||
|
||||
testParamPatternCombinations(function(n) ("[x" + n + "," + "y" + n + "," + "z" + n + "]"),
|
||||
function(n) (arrPatt([ident("x" + n), ident("y" + n), ident("z" + n)])));
|
||||
|
||||
|
||||
// destructuring variable declarations
|
||||
|
||||
function testVarPatternCombinations(makePattSrc, makePattPatt) {
|
||||
var pattSrcs = makePatternCombinations(function(n) ("x" + n), makePattSrc);
|
||||
var pattPatts = makePatternCombinations(function(n) ({ id: ident("x" + n), init: null }), makePattPatt);
|
||||
|
||||
for (var i = 0; i < pattSrcs.length; i++) {
|
||||
// variable declarations in blocks
|
||||
assertDecl("var " + pattSrcs[i].join(",") + ";", varDecl(pattPatts[i]));
|
||||
|
||||
assertGlobalDecl("let " + pattSrcs[i].join(",") + ";", varDecl(pattPatts[i]));
|
||||
assertLocalDecl("let " + pattSrcs[i].join(",") + ";", varDecl(pattPatts[i]));
|
||||
assertBlockDecl("let " + pattSrcs[i].join(",") + ";", letDecl(pattPatts[i]));
|
||||
|
||||
assertDecl("const " + pattSrcs[i].join(",") + ";", constDecl(pattPatts[i]));
|
||||
|
||||
// variable declarations in for-loop heads
|
||||
assertStmt("for (var " + pattSrcs[i].join(",") + "; foo; bar);",
|
||||
forStmt(varDecl(pattPatts[i]), ident("foo"), ident("bar"), emptyStmt));
|
||||
assertStmt("for (let " + pattSrcs[i].join(",") + "; foo; bar);",
|
||||
forStmt(letDecl(pattPatts[i]), ident("foo"), ident("bar"), emptyStmt));
|
||||
assertStmt("for (const " + pattSrcs[i].join(",") + "; foo; bar);",
|
||||
forStmt(constDecl(pattPatts[i]), ident("foo"), ident("bar"), emptyStmt));
|
||||
}
|
||||
}
|
||||
|
||||
testVarPatternCombinations(function (n) ("{a" + n + ":x" + n + "," + "b" + n + ":y" + n + "," + "c" + n + ":z" + n + "} = 0"),
|
||||
function (n) ({ id: objPatt([{ key: ident("a" + n), value: ident("x" + n) },
|
||||
{ key: ident("b" + n), value: ident("y" + n) },
|
||||
{ key: ident("c" + n), value: ident("z" + n) }]),
|
||||
init: lit(0) }));
|
||||
|
||||
testVarPatternCombinations(function(n) ("[x" + n + "," + "y" + n + "," + "z" + n + "] = 0"),
|
||||
function(n) ({ id: arrPatt([ident("x" + n), ident("y" + n), ident("z" + n)]),
|
||||
init: lit(0) }));
|
||||
|
||||
// destructuring assignment
|
||||
|
||||
function testAssignmentCombinations(makePattSrc, makePattPatt) {
|
||||
var pattSrcs = makePatternCombinations(function(n) ("x" + n + " = 0"), makePattSrc);
|
||||
var pattPatts = makePatternCombinations(function(n) (aExpr("=", ident("x" + n), lit(0))), makePattPatt);
|
||||
|
||||
for (var i = 0; i < pattSrcs.length; i++) {
|
||||
var src = pattSrcs[i].join(",");
|
||||
var patt = pattPatts[i].length === 1 ? pattPatts[i][0] : seqExpr(pattPatts[i]);
|
||||
|
||||
// assignment expression statement
|
||||
assertExpr("(" + src + ")", patt);
|
||||
|
||||
// for-loop head assignment
|
||||
assertStmt("for (" + src + "; foo; bar);",
|
||||
forStmt(patt, ident("foo"), ident("bar"), emptyStmt));
|
||||
}
|
||||
}
|
||||
|
||||
testAssignmentCombinations(function (n) ("{a" + n + ":x" + n + "," + "b" + n + ":y" + n + "," + "c" + n + ":z" + n + "} = 0"),
|
||||
function (n) (aExpr("=",
|
||||
objPatt([{ key: ident("a" + n), value: ident("x" + n) },
|
||||
{ key: ident("b" + n), value: ident("y" + n) },
|
||||
{ key: ident("c" + n), value: ident("z" + n) }]),
|
||||
lit(0))));
|
||||
|
||||
|
||||
// destructuring in for-in and for-each-in loop heads
|
||||
|
||||
var axbycz = objPatt([{ key: ident("a"), value: ident("x") },
|
||||
{ key: ident("b"), value: ident("y") },
|
||||
{ key: ident("c"), value: ident("z") }]);
|
||||
var xyz = arrPatt([ident("x"), ident("y"), ident("z")]);
|
||||
|
||||
assertStmt("for (var {a:x,b:y,c:z} in foo);", forInStmt(varDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt));
|
||||
assertStmt("for (let {a:x,b:y,c:z} in foo);", forInStmt(letDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt));
|
||||
assertStmt("for ({a:x,b:y,c:z} in foo);", forInStmt(axbycz, ident("foo"), emptyStmt));
|
||||
assertStmt("for (var [x,y,z] in foo);", forInStmt(varDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt));
|
||||
assertStmt("for (let [x,y,z] in foo);", forInStmt(letDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt));
|
||||
assertStmt("for ([x,y,z] in foo);", forInStmt(xyz, ident("foo"), emptyStmt));
|
||||
assertStmt("for each (var {a:x,b:y,c:z} in foo);", forEachInStmt(varDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt));
|
||||
assertStmt("for each (let {a:x,b:y,c:z} in foo);", forEachInStmt(letDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt));
|
||||
assertStmt("for each ({a:x,b:y,c:z} in foo);", forEachInStmt(axbycz, ident("foo"), emptyStmt));
|
||||
assertStmt("for each (var [x,y,z] in foo);", forEachInStmt(varDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt));
|
||||
assertStmt("for each (let [x,y,z] in foo);", forEachInStmt(letDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt));
|
||||
assertStmt("for each ([x,y,z] in foo);", forEachInStmt(xyz, ident("foo"), emptyStmt));
|
||||
|
||||
// expression closures
|
||||
|
||||
assertDecl("function inc(x) (x + 1)", funDecl(ident("inc"), [ident("x")], binExpr("+", ident("x"), lit(1))));
|
||||
assertExpr("(function(x) (x+1))", funExpr(null, [ident("x")], binExpr("+"), ident("x"), lit(1)));
|
||||
|
||||
// generators
|
||||
|
||||
assertDecl("function gen(x) { yield }", genFunDecl(ident("gen"), [ident("x")], blockStmt([exprStmt(yieldExpr(null))])));
|
||||
assertExpr("(function(x) { yield })", genFunExpr(null, [ident("x")], blockStmt([exprStmt(yieldExpr(null))])));
|
||||
assertDecl("function gen(x) { yield 42 }", genFunDecl(ident("gen"), [ident("x")], blockStmt([exprStmt(yieldExpr(lit(42)))])));
|
||||
assertExpr("(function(x) { yield 42 })", genFunExpr(null, [ident("x")], blockStmt([exprStmt(yieldExpr(lit(42)))])));
|
||||
|
||||
// getters and setters
|
||||
|
||||
assertExpr("({ get x() { return 42 } })",
|
||||
objExpr([ { key: ident("x"),
|
||||
value: funExpr(null, [], blockStmt([returnStmt(lit(42))])),
|
||||
kind: "get" } ]));
|
||||
assertExpr("({ set x(v) { return 42 } })",
|
||||
objExpr([ { key: ident("x"),
|
||||
value: funExpr(null, [ident("v")], blockStmt([returnStmt(lit(42))])),
|
||||
kind: "set" } ]));
|
||||
|
||||
// comprehensions
|
||||
|
||||
assertExpr("[ x for (x in foo)]",
|
||||
compExpr(ident("x"), [compBlock(ident("x"), ident("foo"))], null));
|
||||
assertExpr("[ [x,y] for (x in foo) for (y in bar)]",
|
||||
compExpr(arrExpr([ident("x"), ident("y")]), [compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar"))], null));
|
||||
assertExpr("[ [x,y,z] for (x in foo) for (y in bar) for (z in baz)]",
|
||||
compExpr(arrExpr([ident("x"), ident("y"), ident("z")]),
|
||||
[compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar")), compBlock(ident("z"), ident("baz"))],
|
||||
null));
|
||||
|
||||
assertExpr("[ x for (x in foo) if (p)]",
|
||||
compExpr(ident("x"), [compBlock(ident("x"), ident("foo"))], ident("p")));
|
||||
assertExpr("[ [x,y] for (x in foo) for (y in bar) if (p)]",
|
||||
compExpr(arrExpr([ident("x"), ident("y")]), [compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar"))], ident("p")));
|
||||
assertExpr("[ [x,y,z] for (x in foo) for (y in bar) for (z in baz) if (p) ]",
|
||||
compExpr(arrExpr([ident("x"), ident("y"), ident("z")]),
|
||||
[compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar")), compBlock(ident("z"), ident("baz"))],
|
||||
ident("p")));
|
||||
|
||||
assertExpr("[ x for each (x in foo)]",
|
||||
compExpr(ident("x"), [compEachBlock(ident("x"), ident("foo"))], null));
|
||||
assertExpr("[ [x,y] for each (x in foo) for each (y in bar)]",
|
||||
compExpr(arrExpr([ident("x"), ident("y")]), [compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar"))], null));
|
||||
assertExpr("[ [x,y,z] for each (x in foo) for each (y in bar) for each (z in baz)]",
|
||||
compExpr(arrExpr([ident("x"), ident("y"), ident("z")]),
|
||||
[compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar")), compEachBlock(ident("z"), ident("baz"))],
|
||||
null));
|
||||
|
||||
assertExpr("[ x for each (x in foo) if (p)]",
|
||||
compExpr(ident("x"), [compEachBlock(ident("x"), ident("foo"))], ident("p")));
|
||||
assertExpr("[ [x,y] for each (x in foo) for each (y in bar) if (p)]",
|
||||
compExpr(arrExpr([ident("x"), ident("y")]), [compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar"))], ident("p")));
|
||||
assertExpr("[ [x,y,z] for each (x in foo) for each (y in bar) for each (z in baz) if (p) ]",
|
||||
compExpr(arrExpr([ident("x"), ident("y"), ident("z")]),
|
||||
[compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar")), compEachBlock(ident("z"), ident("baz"))],
|
||||
ident("p")));
|
||||
|
||||
// generator expressions
|
||||
|
||||
assertExpr("( x for (x in foo))",
|
||||
genExpr(ident("x"), [compBlock(ident("x"), ident("foo"))], null));
|
||||
assertExpr("( [x,y] for (x in foo) for (y in bar))",
|
||||
genExpr(arrExpr([ident("x"), ident("y")]), [compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar"))], null));
|
||||
assertExpr("( [x,y,z] for (x in foo) for (y in bar) for (z in baz))",
|
||||
genExpr(arrExpr([ident("x"), ident("y"), ident("z")]),
|
||||
[compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar")), compBlock(ident("z"), ident("baz"))],
|
||||
null));
|
||||
|
||||
assertExpr("( x for (x in foo) if (p))",
|
||||
genExpr(ident("x"), [compBlock(ident("x"), ident("foo"))], ident("p")));
|
||||
assertExpr("( [x,y] for (x in foo) for (y in bar) if (p))",
|
||||
genExpr(arrExpr([ident("x"), ident("y")]), [compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar"))], ident("p")));
|
||||
assertExpr("( [x,y,z] for (x in foo) for (y in bar) for (z in baz) if (p) )",
|
||||
genExpr(arrExpr([ident("x"), ident("y"), ident("z")]),
|
||||
[compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar")), compBlock(ident("z"), ident("baz"))],
|
||||
ident("p")));
|
||||
|
||||
assertExpr("( x for each (x in foo))",
|
||||
genExpr(ident("x"), [compEachBlock(ident("x"), ident("foo"))], null));
|
||||
assertExpr("( [x,y] for each (x in foo) for each (y in bar))",
|
||||
genExpr(arrExpr([ident("x"), ident("y")]), [compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar"))], null));
|
||||
assertExpr("( [x,y,z] for each (x in foo) for each (y in bar) for each (z in baz))",
|
||||
genExpr(arrExpr([ident("x"), ident("y"), ident("z")]),
|
||||
[compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar")), compEachBlock(ident("z"), ident("baz"))],
|
||||
null));
|
||||
|
||||
assertExpr("( x for each (x in foo) if (p))",
|
||||
genExpr(ident("x"), [compEachBlock(ident("x"), ident("foo"))], ident("p")));
|
||||
assertExpr("( [x,y] for each (x in foo) for each (y in bar) if (p))",
|
||||
genExpr(arrExpr([ident("x"), ident("y")]), [compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar"))], ident("p")));
|
||||
assertExpr("( [x,y,z] for each (x in foo) for each (y in bar) for each (z in baz) if (p) )",
|
||||
genExpr(arrExpr([ident("x"), ident("y"), ident("z")]),
|
||||
[compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar")), compEachBlock(ident("z"), ident("baz"))],
|
||||
ident("p")));
|
||||
|
||||
// NOTE: it would be good to test generator expressions both with and without upvars, just like functions above.
|
||||
|
||||
|
||||
// sharp variables
|
||||
|
||||
assertExpr("#1={me:#1#}", graphExpr(1, objExpr([{ key: ident("me"), value: idxExpr(1) }])))
|
||||
|
||||
|
||||
// E4X
|
||||
|
||||
assertExpr("x..tagName", binExpr("..", ident("x"), lit("tagName")));
|
||||
assertExpr("x.*", memExpr(ident("x"), xmlAnyName));
|
||||
assertExpr("x[*]", memExpr(ident("x"), xmlAnyName));
|
||||
assertExpr("x::y", xmlQualId(ident("x"), ident("y"), false));
|
||||
assertExpr("x::[foo]", xmlQualId(ident("x"), ident("foo"), true));
|
||||
assertExpr("x::[foo()]", xmlQualId(ident("x"), callExpr(ident("foo"), []), true));
|
||||
assertExpr("*::*", xmlQualId(xmlAnyName, ident("*"), false));
|
||||
assertExpr("*::[foo]", xmlQualId(xmlAnyName, ident("foo"), true));
|
||||
assertExpr("*::[foo()]", xmlQualId(xmlAnyName, callExpr(ident("foo"), []), true));
|
||||
assertExpr("@foo", xmlAttrSel(ident("foo")));
|
||||
assertExpr("x.(p)", xmlFilter(ident("x"), ident("p")));
|
||||
assertExpr("<{foo}/>", xmlPointTag([xmlEscape(ident("foo"))]));
|
||||
assertExpr("<{foo}></{foo}>", xmlElt([xmlStartTag([xmlEscape(ident("foo"))]),
|
||||
xmlEndTag([xmlEscape(ident("foo"))])]));
|
||||
assertExpr("<{foo} {attr}='attr'/>", xmlPointTag([xmlEscape(ident("foo")),
|
||||
xmlEscape(ident("attr")),
|
||||
xmlAttr("attr")]));
|
||||
assertExpr("<{foo}>text</{foo}>", xmlElt([xmlStartTag([xmlEscape(ident("foo"))]),
|
||||
xmlText("text"),
|
||||
xmlEndTag([xmlEscape(ident("foo"))])]));
|
||||
assertExpr("<?xml?>", xmlPI("xml", ""));
|
||||
assertExpr("<?xml version='1.0'?>", xmlPI("xml", "version='1.0'"));
|
||||
|
||||
// NOTE: We appear to be unable to test XMLNAME, XMLCDATA, and XMLCOMMENT.
|
||||
|
||||
|
||||
// Source location information
|
||||
|
||||
|
||||
var withoutFileOrLine = Reflect.parse("42");
|
||||
var withFile = Reflect.parse("42", "foo.js");
|
||||
var withFileAndLine = Reflect.parse("42", "foo.js", 111);
|
||||
|
||||
Pattern({ source: null, start: { line: 1, column: 0 }, end: { line: 1, column: 2 } }).match(withoutFileOrLine.loc);
|
||||
Pattern({ source: "foo.js", start: { line: 1, column: 0 }, end: { line: 1, column: 2 } }).match(withFile.loc);
|
||||
Pattern({ source: "foo.js", start: { line: 111, column: 0 }, end: { line: 111, column: 2 } }).match(withFileAndLine.loc);
|
||||
|
||||
var withoutFileOrLine2 = Reflect.parse("foo +\nbar");
|
||||
var withFile2 = Reflect.parse("foo +\nbar", "foo.js");
|
||||
var withFileAndLine2 = Reflect.parse("foo +\nbar", "foo.js", 111);
|
||||
|
||||
Pattern({ source: null, start: { line: 1, column: 0 }, end: { line: 2, column: 3 } }).match(withoutFileOrLine2.loc);
|
||||
Pattern({ source: "foo.js", start: { line: 1, column: 0 }, end: { line: 2, column: 3 } }).match(withFile2.loc);
|
||||
Pattern({ source: "foo.js", start: { line: 111, column: 0 }, end: { line: 112, column: 3 } }).match(withFileAndLine2.loc);
|
||||
|
||||
var nested = Reflect.parse("(-b + sqrt(sqr(b) - 4 * a * c)) / (2 * a)", "quad.js");
|
||||
var fourAC = nested.body[0].expression.left.right.arguments[0].right;
|
||||
|
||||
Pattern({ source: "quad.js", start: { line: 1, column: 20 }, end: { line: 1, column: 29 } }).match(fourAC.loc);
|
||||
|
||||
|
||||
reportCompare(true, true);
|
|
@ -17,3 +17,156 @@ if (typeof version != 'undefined')
|
|||
version(185);
|
||||
}
|
||||
|
||||
// A little pattern-matching library.
|
||||
var Match =
|
||||
|
||||
(function() {
|
||||
|
||||
function Pattern(template) {
|
||||
// act like a constructor even as a function
|
||||
if (!(this instanceof Pattern))
|
||||
return new Pattern(template);
|
||||
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
Pattern.prototype = {
|
||||
match: function(act) {
|
||||
return match(act, this.template);
|
||||
},
|
||||
|
||||
matches: function(act) {
|
||||
try {
|
||||
return this.match(act);
|
||||
}
|
||||
catch (e if e instanceof MatchError) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
assert: function(act, message) {
|
||||
try {
|
||||
return this.match(act);
|
||||
}
|
||||
catch (e if e instanceof MatchError) {
|
||||
throw new Error((message || "failed match") + ": " + e.message);
|
||||
}
|
||||
},
|
||||
|
||||
toString: function() "[object Pattern]"
|
||||
};
|
||||
|
||||
Pattern.ANY = new Pattern;
|
||||
Pattern.ANY.template = Pattern.ANY;
|
||||
|
||||
var quote = uneval;
|
||||
|
||||
function MatchError(msg) {
|
||||
this.message = msg;
|
||||
}
|
||||
|
||||
MatchError.prototype = {
|
||||
toString: function() {
|
||||
return "match error: " + this.message;
|
||||
}
|
||||
};
|
||||
|
||||
function isAtom(x) {
|
||||
return (typeof x === "number") ||
|
||||
(typeof x === "string") ||
|
||||
(typeof x === "boolean") ||
|
||||
(x === null) ||
|
||||
(typeof x === "object" && x instanceof RegExp);
|
||||
}
|
||||
|
||||
function isObject(x) {
|
||||
return (x !== null) && (typeof x === "object");
|
||||
}
|
||||
|
||||
function isArrayLike(x) {
|
||||
return isObject(x) && ("length" in x);
|
||||
}
|
||||
|
||||
function matchAtom(act, exp) {
|
||||
if ((typeof exp) === "number" && isNaN(exp)) {
|
||||
if ((typeof act) !== "number" || !isNaN(act))
|
||||
throw new MatchError("expected NaN, got: " + quote(act));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (exp === null) {
|
||||
if (act !== null)
|
||||
throw new MatchError("expected null, got: " + quote(act));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (exp instanceof RegExp) {
|
||||
if (!(act instanceof RegExp) || exp.source !== act.source)
|
||||
throw new MatchError("expected " + quote(exp) + ", got: " + quote(act));
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (typeof exp) {
|
||||
case "string":
|
||||
if (act !== exp)
|
||||
throw new MatchError("expected " + exp.quote() + ", got " + quote(act));
|
||||
return true;
|
||||
case "boolean":
|
||||
case "number":
|
||||
if (exp !== act)
|
||||
throw new MatchError("expected " + exp + ", got " + quote(act));
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new Error("bad pattern: " + exp.toSource());
|
||||
}
|
||||
|
||||
function matchObject(act, exp) {
|
||||
if (!isObject(act))
|
||||
throw new MatchError("expected object, got " + quote(act));
|
||||
|
||||
for (var key in exp) {
|
||||
if (!(key in act))
|
||||
throw new MatchError("expected property " + key.quote() + " not found in " + quote(act));
|
||||
match(act[key], exp[key]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function matchArray(act, exp) {
|
||||
if (!isObject(act) || !("length" in act))
|
||||
throw new MatchError("expected array-like object, got " + quote(act));
|
||||
|
||||
var length = exp.length;
|
||||
for (var i = 0; i < length; i++) {
|
||||
if (i in exp) {
|
||||
if (!(i in act))
|
||||
throw new MatchError("expected array property " + i + " not found in " + quote(act));
|
||||
match(act[i], exp[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function match(act, exp) {
|
||||
if (exp === Pattern.ANY)
|
||||
return true;
|
||||
|
||||
if (exp instanceof Pattern)
|
||||
return exp.match(act);
|
||||
|
||||
if (isAtom(exp))
|
||||
return matchAtom(act, exp);
|
||||
|
||||
if (isArrayLike(exp))
|
||||
return matchArray(act, exp);
|
||||
|
||||
return matchObject(act, exp);
|
||||
}
|
||||
|
||||
return { Pattern: Pattern,
|
||||
MatchError: MatchError };
|
||||
|
||||
})();
|
||||
|
|
|
@ -28,4 +28,5 @@ script regress-577648-1.js
|
|||
script regress-577648-2.js
|
||||
script regress-583429.js
|
||||
script regress-584355.js
|
||||
script regress-588339.js
|
||||
script regress-yarr-regexp.js
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/licenses/publicdomain/
|
||||
// Contributor: Jesse Ruderman <jruderman@gmail.com>
|
||||
|
||||
try {
|
||||
var x = Proxy.create( {get:function(r,name){return {}[name]}} );
|
||||
x.watch('e', function(){});
|
||||
} catch (exc) {
|
||||
}
|
||||
|
||||
reportCompare(0, 0, 'ok');
|
|
@ -0,0 +1,5 @@
|
|||
(#3={})
|
||||
eval("#1={}")
|
||||
|
||||
/* Watch for crash. */
|
||||
reportCompare(0, 0, "");
|
|
@ -0,0 +1,24 @@
|
|||
// Library file for tests to load.
|
||||
|
||||
function SameValue(v1, v2)
|
||||
{
|
||||
if (v1 === 0 && v2 === 0)
|
||||
return 1 / v1 === 1 / v2;
|
||||
if (v1 !== v1 && v2 !== v2)
|
||||
return true;
|
||||
return v1 === v2;
|
||||
}
|
||||
|
||||
function arraysEqual(a1, a2)
|
||||
{
|
||||
var len1 = a1.length, len2 = a2.length;
|
||||
if (len1 !== len2)
|
||||
return false;
|
||||
for (var i = 0; i < len1; i++)
|
||||
{
|
||||
if (!SameValue(a1[i], a2[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
actual = '';
|
||||
expected = '5,';
|
||||
expected = '6,';
|
||||
|
||||
// tracing length
|
||||
|
||||
|
@ -14,7 +14,7 @@ function f() {
|
|||
}
|
||||
|
||||
for (var i = 0; i < 5; ++i) {
|
||||
f(10, 20, 30, 40, 50);
|
||||
f(10, 20, 30, 40, 50, 60);
|
||||
}
|
||||
appendToActual(g);
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
load(libdir + 'array-compare.js');
|
||||
|
||||
var obj = {};
|
||||
|
||||
function args(a) { return arguments; }
|
||||
|
||||
var a1, a2, a3, a4;
|
||||
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
a1 = args();
|
||||
a2 = args(1);
|
||||
a3 = args(1, obj);
|
||||
a4 = args("foopy");
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(a1, []), true);
|
||||
assertEq(arraysEqual(a2, [1]), true);
|
||||
assertEq(arraysEqual(a3, [1, obj]), true);
|
||||
assertEq(arraysEqual(a4, ["foopy"]), true);
|
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
function assignElementGetParameter(a)
|
||||
{
|
||||
arguments[0] = 17;
|
||||
return a;
|
||||
}
|
||||
|
||||
for (var i = 0; i < 5; i++)
|
||||
assertEq(assignElementGetParameter(42), 17);
|
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
function assignParameterGetElement(a)
|
||||
{
|
||||
a = 17;
|
||||
return arguments[0];
|
||||
}
|
||||
|
||||
for (var i = 0; i < 5; i++)
|
||||
assertEq(assignParameterGetElement(42), 17);
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче