mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-05 00:25:27 +00:00
[JAEGER] Merge for manual backout.
This commit is contained in:
commit
8ef207d8ff
@ -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);
|
||||
|
@ -1512,7 +1512,8 @@ public:
|
||||
WindowStateHolder(nsGlobalWindow *aWindow,
|
||||
nsIXPConnectJSObjectHolder *aHolder,
|
||||
nsNavigator *aNavigator,
|
||||
nsIXPConnectJSObjectHolder *aOuterProto);
|
||||
nsIXPConnectJSObjectHolder *aOuterProto,
|
||||
nsIXPConnectJSObjectHolder *aOuterRealProto);
|
||||
|
||||
nsGlobalWindow* GetInnerWindow() { return mInnerWindow; }
|
||||
nsIXPConnectJSObjectHolder *GetInnerWindowHolder()
|
||||
@ -1520,6 +1521,7 @@ public:
|
||||
|
||||
nsNavigator* GetNavigator() { return mNavigator; }
|
||||
nsIXPConnectJSObjectHolder* GetOuterProto() { return mOuterProto; }
|
||||
nsIXPConnectJSObjectHolder* GetOuterRealProto() { return mOuterRealProto; }
|
||||
|
||||
void DidRestoreWindow()
|
||||
{
|
||||
@ -1528,6 +1530,7 @@ public:
|
||||
mInnerWindowHolder = nsnull;
|
||||
mNavigator = nsnull;
|
||||
mOuterProto = nsnull;
|
||||
mOuterRealProto = nsnull;
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -1539,6 +1542,7 @@ protected:
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> mInnerWindowHolder;
|
||||
nsRefPtr<nsNavigator> mNavigator;
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> mOuterProto;
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> mOuterRealProto;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(WindowStateHolder, WINDOWSTATEHOLDER_IID)
|
||||
@ -1546,10 +1550,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");
|
||||
@ -1609,9 +1615,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();
|
||||
}
|
||||
@ -1725,12 +1728,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(),
|
||||
@ -1742,9 +1753,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();
|
||||
|
||||
@ -1818,7 +1826,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();
|
||||
@ -1872,6 +1879,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) {
|
||||
@ -1924,42 +1970,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);
|
||||
}
|
||||
@ -9073,21 +9083,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;
|
||||
|
||||
|
@ -2594,7 +2594,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
|
||||
@ -2615,12 +2615,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;
|
||||
}
|
||||
|
||||
@ -2660,11 +2666,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;
|
||||
|
||||
@ -2678,18 +2681,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
|
||||
@ -2708,14 +2714,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)
|
||||
|
26
dom/tests/mochitest/general/file_frameElementWrapping.html
Normal file
26
dom/tests/mochitest/general/file_frameElementWrapping.html
Normal file
@ -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>
|
38
dom/tests/mochitest/general/test_frameElementWrapping.html
Normal file
38
dom/tests/mochitest/general/test_frameElementWrapping.html
Normal file
@ -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>
|
@ -386,9 +386,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
|
||||
@ -875,17 +872,21 @@ endif
|
||||
###############################################
|
||||
# BEGIN kludges for the Nitro assembler
|
||||
#
|
||||
## FIXME figure out where INCLUDES is being reset, and move this
|
||||
## backwards to that point. Ideally, merge with the rest of the
|
||||
## Nitro assembler stuff, far above.
|
||||
ifdef ENABLE_METHODJIT
|
||||
INCLUDES += -I$(srcdir)/assembler -I$(srcdir)/yarr
|
||||
#
|
||||
|
||||
# Needed to "configure" it correctly. Unfortunately these
|
||||
# flags wind up being applied to all code in js/src, not just
|
||||
# the code in js/src/assembler.
|
||||
CXXFLAGS += -DENABLE_ASSEMBLER=1 -DUSE_SYSTEM_MALLOC=1 -DENABLE_JIT=1
|
||||
CXXFLAGS += -DUSE_SYSTEM_MALLOC=1
|
||||
|
||||
ifeq (android,$(TARGET_VENDOR))
|
||||
CXXFLAGS += -DWTF_PLATFORM_ANDROID=1
|
||||
else
|
||||
CXXFLAGS += -DENABLE_ASSEMBLER=1 -DENABLE_JIT=1
|
||||
endif
|
||||
|
||||
INCLUDES += -I$(srcdir)/assembler -I$(srcdir)/yarr
|
||||
|
||||
ifdef ENABLE_METHODJIT
|
||||
# Build a standalone test program that exercises the assembler
|
||||
# sources a bit.
|
||||
TESTMAIN_OBJS = \
|
||||
@ -901,6 +902,7 @@ TESTMAIN_OBJS = \
|
||||
TestMain$(HOST_BIN_SUFFIX): $(TESTMAIN_OBJS)
|
||||
$(CXX) -o TestMain$(HOST_BIN_SUFFIX) $(TESTMAIN_OBJS)
|
||||
endif
|
||||
|
||||
#
|
||||
# END kludges for the Nitro assembler
|
||||
###############################################
|
||||
|
@ -275,8 +275,8 @@ void ARMAssembler::dataTransfer32(bool isLoad, RegisterID srcDst, RegisterID bas
|
||||
add_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | (10 << 8));
|
||||
dtr_u(isLoad, srcDst, ARMRegisters::S0, (offset & 0xfff));
|
||||
} else {
|
||||
ARMWord reg = getImm(offset, ARMRegisters::S0);
|
||||
dtr_ur(isLoad, srcDst, base, reg);
|
||||
moveImm(offset, ARMRegisters::S0);
|
||||
dtr_ur(isLoad, srcDst, base, ARMRegisters::S0);
|
||||
}
|
||||
} else {
|
||||
offset = -offset;
|
||||
@ -286,8 +286,8 @@ void ARMAssembler::dataTransfer32(bool isLoad, RegisterID srcDst, RegisterID bas
|
||||
sub_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | (10 << 8));
|
||||
dtr_d(isLoad, srcDst, ARMRegisters::S0, (offset & 0xfff));
|
||||
} else {
|
||||
ARMWord reg = getImm(offset, ARMRegisters::S0);
|
||||
dtr_dr(isLoad, srcDst, base, reg);
|
||||
moveImm(offset, ARMRegisters::S0);
|
||||
dtr_dr(isLoad, srcDst, base, ARMRegisters::S0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -301,8 +301,8 @@ void ARMAssembler::dataTransfer8(bool isLoad, RegisterID srcDst, RegisterID base
|
||||
add_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | (10 << 8));
|
||||
dtrb_u(isLoad, srcDst, ARMRegisters::S0, (offset & 0xfff));
|
||||
} else {
|
||||
ARMWord reg = getImm(offset, ARMRegisters::S0);
|
||||
dtrb_ur(isLoad, srcDst, base, reg);
|
||||
moveImm(offset, ARMRegisters::S0);
|
||||
dtrb_ur(isLoad, srcDst, base, ARMRegisters::S0);
|
||||
}
|
||||
} else {
|
||||
offset = -offset;
|
||||
@ -312,8 +312,8 @@ void ARMAssembler::dataTransfer8(bool isLoad, RegisterID srcDst, RegisterID base
|
||||
sub_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | (10 << 8));
|
||||
dtrb_d(isLoad, srcDst, ARMRegisters::S0, (offset & 0xfff));
|
||||
} else {
|
||||
ARMWord reg = getImm(offset, ARMRegisters::S0);
|
||||
dtrb_dr(isLoad, srcDst, base, reg);
|
||||
moveImm(offset, ARMRegisters::S0);
|
||||
dtrb_dr(isLoad, srcDst, base, ARMRegisters::S0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -283,6 +283,16 @@ public:
|
||||
return dataLabel;
|
||||
}
|
||||
|
||||
DataLabel32 load64WithAddressOffsetPatch(Address address, RegisterID hi, RegisterID lo)
|
||||
{
|
||||
DataLabel32 dataLabel(this);
|
||||
m_assembler.ldr_un_imm(ARMRegisters::S0, 0);
|
||||
m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, address.base);
|
||||
m_assembler.dtr_u(true, lo, ARMRegisters::S0, 0);
|
||||
m_assembler.dtr_u(true, hi, ARMRegisters::S0, 4);
|
||||
return dataLabel;
|
||||
}
|
||||
|
||||
Label loadPtrWithPatchToLEA(Address address, RegisterID dest)
|
||||
{
|
||||
Label label(this);
|
||||
@ -312,6 +322,27 @@ public:
|
||||
return dataLabel;
|
||||
}
|
||||
|
||||
DataLabel32 store64WithAddressOffsetPatch(RegisterID hi, RegisterID lo, Address address)
|
||||
{
|
||||
DataLabel32 dataLabel(this);
|
||||
m_assembler.ldr_un_imm(ARMRegisters::S0, 0);
|
||||
m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, address.base);
|
||||
m_assembler.dtr_u(false, lo, ARMRegisters::S0, 0);
|
||||
m_assembler.dtr_u(false, hi, ARMRegisters::S0, 4);
|
||||
return dataLabel;
|
||||
}
|
||||
|
||||
DataLabel32 store64WithAddressOffsetPatch(Imm32 hi, RegisterID lo, Address address)
|
||||
{
|
||||
DataLabel32 dataLabel(this);
|
||||
m_assembler.ldr_un_imm(ARMRegisters::S0, 0);
|
||||
m_assembler.getImm(hi.m_value, ARMRegisters::S1);
|
||||
m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, address.base);
|
||||
m_assembler.dtr_u(false, lo, ARMRegisters::S0, 0);
|
||||
m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 4);
|
||||
return dataLabel;
|
||||
}
|
||||
|
||||
void store32(RegisterID src, ImplicitAddress address)
|
||||
{
|
||||
m_assembler.dataTransfer32(false, src, address.base, address.offset);
|
||||
@ -437,6 +468,13 @@ public:
|
||||
return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool));
|
||||
}
|
||||
|
||||
// As branch32, but allow the value ('right') to be patched.
|
||||
Jump branch32WithPatch(Condition cond, RegisterID left, Imm32 right, DataLabel32 &dataLabel)
|
||||
{
|
||||
dataLabel = moveWithPatch(right, ARMRegisters::S1);
|
||||
return branch32(cond, left, ARMRegisters::S1, true);
|
||||
}
|
||||
|
||||
Jump branch32(Condition cond, RegisterID left, Address right)
|
||||
{
|
||||
load32(right, ARMRegisters::S1);
|
||||
@ -822,6 +860,13 @@ public:
|
||||
return dataLabel;
|
||||
}
|
||||
|
||||
DataLabel32 moveWithPatch(Imm32 initialValue, RegisterID dest)
|
||||
{
|
||||
DataLabel32 dataLabel(this);
|
||||
m_assembler.ldr_un_imm(dest, initialValue.m_value);
|
||||
return dataLabel;
|
||||
}
|
||||
|
||||
Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
|
||||
{
|
||||
dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S1);
|
||||
@ -1116,8 +1161,8 @@ protected:
|
||||
m_assembler.add_r(ARMRegisters::S0, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8));
|
||||
m_assembler.dtr_u(true, ARMRegisters::S0, ARMRegisters::S0, offset & 0xfff);
|
||||
} else {
|
||||
ARMWord reg = m_assembler.getImm(offset, ARMRegisters::S0);
|
||||
m_assembler.dtr_ur(true, ARMRegisters::S0, base, reg);
|
||||
m_assembler.moveImm(offset, ARMRegisters::S0);
|
||||
m_assembler.dtr_ur(true, ARMRegisters::S0, base, ARMRegisters::S0);
|
||||
}
|
||||
} else {
|
||||
offset = -offset;
|
||||
@ -1127,8 +1172,8 @@ protected:
|
||||
m_assembler.sub_r(ARMRegisters::S0, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8));
|
||||
m_assembler.dtr_d(true, ARMRegisters::S0, ARMRegisters::S0, offset & 0xfff);
|
||||
} else {
|
||||
ARMWord reg = m_assembler.getImm(offset, ARMRegisters::S0);
|
||||
m_assembler.dtr_dr(true, ARMRegisters::S0, base, reg);
|
||||
m_assembler.moveImm(offset, ARMRegisters::S0);
|
||||
m_assembler.dtr_dr(true, ARMRegisters::S0, base, ARMRegisters::S0);
|
||||
}
|
||||
}
|
||||
m_assembler.blx(ARMRegisters::S0);
|
||||
|
@ -894,11 +894,11 @@ on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */
|
||||
#if !defined(ENABLE_YARR_JIT)
|
||||
|
||||
/* YARR supports ARM, x86 & x86-64, and has been tested on Mac and Windows. */
|
||||
#if WTF_CPU_X86 \
|
||||
#if (WTF_CPU_X86 \
|
||||
|| WTF_CPU_X86_64 \
|
||||
|| WTF_CPU_ARM_THUMB2 \
|
||||
|| WTF_CPU_ARM_TRADITIONAL \
|
||||
|| WTF_CPU_X86
|
||||
|| WTF_CPU_X86) && !WTF_PLATFORM_ANDROID
|
||||
#define ENABLE_YARR_JIT 1
|
||||
#else
|
||||
#define ENABLE_YARR_JIT 0
|
||||
@ -906,7 +906,7 @@ on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */
|
||||
|
||||
#endif /* !defined(ENABLE_YARR_JIT) */
|
||||
|
||||
#if ENABLE_JIT || ENABLE_YARR_JIT
|
||||
#if (ENABLE_JIT || ENABLE_YARR_JIT) && !WTF_PLATFORM_ANDROID
|
||||
#define ENABLE_ASSEMBLER 1
|
||||
#endif
|
||||
/* Setting this flag prevents the assembler from using RWX memory; this may improve
|
||||
|
@ -2594,6 +2594,7 @@ arm*-*)
|
||||
ENABLE_TRACEJIT=1
|
||||
NANOJIT_ARCH=ARM
|
||||
ENABLE_METHODJIT=1
|
||||
ENABLE_MONOIC=1
|
||||
AC_DEFINE(JS_CPU_ARM)
|
||||
AC_DEFINE(JS_NUNBOX32)
|
||||
;;
|
||||
|
@ -330,4 +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_NEED_DEBUG_MODE, 251, 0, JSEXN_ERR, "function can be called only in debug mode")
|
||||
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_NEED_DEBUG_MODE, 254, 0, JSEXN_ERR, "function can be called only in debug mode")
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -1687,6 +1687,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__)
|
||||
@ -1698,11 +1704,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;
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -340,6 +340,7 @@ struct JSAtomState
|
||||
JSAtom *ignoreCaseAtom;
|
||||
JSAtom *indexAtom;
|
||||
JSAtom *inputAtom;
|
||||
JSAtom *toISOStringAtom;
|
||||
JSAtom *iteratorAtom;
|
||||
JSAtom *joinAtom;
|
||||
JSAtom *lastIndexAtom;
|
||||
|
@ -1968,6 +1968,8 @@ DSTOffsetCache::purge()
|
||||
*/
|
||||
offsetMilliseconds = 0;
|
||||
rangeStartSeconds = rangeEndSeconds = INT64_MIN;
|
||||
oldOffsetMilliseconds = 0;
|
||||
oldRangeStartSeconds = oldRangeEndSeconds = INT64_MIN;
|
||||
|
||||
#ifdef JS_METER_DST_OFFSET_CACHING
|
||||
totalCalculations = 0;
|
||||
|
@ -205,6 +205,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 {
|
||||
@ -483,7 +488,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 +1209,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 +1409,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 +1457,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 +1483,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 +1509,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 +1535,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 +1561,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 +1589,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 +2012,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 +2458,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
|
||||
|
@ -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
|
||||
|
@ -2899,7 +2899,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.
|
||||
@ -2973,7 +2975,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;
|
||||
@ -3625,6 +3629,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;
|
||||
@ -3701,7 +3712,7 @@ MaybeEmitVarDecl(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp,
|
||||
}
|
||||
|
||||
if (JOF_OPTYPE(pn->pn_op) == JOF_LOCAL &&
|
||||
!(cg->flags & TCF_FUN_USES_EVAL) &&
|
||||
!(cg->flags & TCF_FUN_CALLS_EVAL) &&
|
||||
pn->pn_defn &&
|
||||
(((JSDefinition *)pn)->pn_dflags & PND_CLOSED))
|
||||
{
|
||||
@ -4536,7 +4547,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
JS_ASSERT(index < JS_BIT(20));
|
||||
pn->pn_index = index;
|
||||
op = FUN_FLAT_CLOSURE(fun) ? JSOP_DEFLOCALFUN_FC : JSOP_DEFLOCALFUN;
|
||||
if ((pn->pn_dflags & PND_CLOSED) && !(cg->flags & TCF_FUN_USES_EVAL)) {
|
||||
if ((pn->pn_dflags & PND_CLOSED) && !(cg->flags & TCF_FUN_CALLS_EVAL)) {
|
||||
CG_SWITCH_TO_PROLOG(cg);
|
||||
EMIT_UINT16_IMM_OP(JSOP_DEFUPVAR, pn->pn_cookie.asInteger());
|
||||
CG_SWITCH_TO_MAIN(cg);
|
||||
|
@ -240,15 +240,16 @@ struct JSStmtInfo {
|
||||
*/
|
||||
#define TCF_FUN_ENTRAINS_SCOPES 0x400000
|
||||
|
||||
/*
|
||||
* Function uses eval.
|
||||
*/
|
||||
#define TCF_FUN_USES_EVAL 0x800000
|
||||
/* The function calls 'eval'. */
|
||||
#define TCF_FUN_CALLS_EVAL 0x800000
|
||||
|
||||
/* The function mutates a positional (non-destructuring) parameter. */
|
||||
#define TCF_FUN_MUTATES_PARAMETER 0x1000000
|
||||
|
||||
/*
|
||||
* Compiling an eval() script.
|
||||
*/
|
||||
#define TCF_COMPILE_FOR_EVAL 0x1000000
|
||||
#define TCF_COMPILE_FOR_EVAL 0x2000000
|
||||
|
||||
/*
|
||||
* Flags to check for return; vs. return expr; in a function.
|
||||
@ -264,8 +265,9 @@ struct JSStmtInfo {
|
||||
TCF_FUN_HEAVYWEIGHT | \
|
||||
TCF_FUN_IS_GENERATOR | \
|
||||
TCF_FUN_USES_OWN_NAME | \
|
||||
TCF_FUN_USES_EVAL | \
|
||||
TCF_HAS_SHARPS | \
|
||||
TCF_FUN_CALLS_EVAL | \
|
||||
TCF_FUN_MUTATES_PARAMETER | \
|
||||
TCF_STRICT_MODE_CODE)
|
||||
|
||||
struct JSTreeContext { /* tree context for semantic checks */
|
||||
@ -337,6 +339,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();
|
||||
|
||||
/*
|
||||
@ -353,9 +359,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());
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
@ -363,8 +403,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();
|
||||
}
|
||||
|
||||
/*
|
||||
|
420
js/src/jsfun.cpp
420
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]);
|
||||
@ -220,8 +230,22 @@ js_GetArgsObject(JSContext *cx, JSStackFrame *fp)
|
||||
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();
|
||||
@ -478,7 +517,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];
|
||||
@ -490,7 +529,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();
|
||||
@ -533,7 +572,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;
|
||||
@ -547,8 +586,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);
|
||||
@ -560,13 +599,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())
|
||||
@ -577,12 +618,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;
|
||||
}
|
||||
@ -592,13 +629,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)
|
||||
@ -618,6 +655,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
|
||||
@ -648,11 +833,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
|
||||
@ -681,6 +869,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;
|
||||
@ -1392,8 +1611,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,
|
||||
@ -1473,20 +1693,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)
|
||||
{
|
||||
@ -1500,13 +1734,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;
|
||||
}
|
||||
|
||||
@ -1582,8 +1823,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)) {
|
||||
@ -1601,6 +1842,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;
|
||||
}
|
||||
|
||||
@ -2080,7 +2352,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))
|
||||
@ -2400,20 +2672,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;
|
||||
}
|
||||
|
||||
@ -2610,34 +2905,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 *
|
||||
@ -2648,7 +2922,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
|
||||
@ -3124,6 +3400,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___ */
|
||||
|
52
js/src/jsfuninlines.h
Normal file
52
js/src/jsfuninlines.h
Normal file
@ -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___ */
|
@ -1352,6 +1352,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",
|
||||
@ -1363,25 +1365,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
|
||||
@ -1647,10 +1638,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);
|
||||
|
@ -556,14 +556,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 +566,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 */
|
||||
|
@ -4147,7 +4147,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 {
|
||||
@ -4518,7 +4518,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];
|
||||
|
@ -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();
|
||||
@ -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)) {
|
||||
@ -6048,9 +6047,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;
|
||||
|
@ -421,7 +421,7 @@ struct JSObject {
|
||||
parent = newParent;
|
||||
}
|
||||
|
||||
JSObject *getGlobal();
|
||||
JSObject *getGlobal() const;
|
||||
|
||||
void *getPrivate() const {
|
||||
JS_ASSERT(getClass()->flags & JSCLASS_HAS_PRIVATE);
|
||||
@ -500,7 +500,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.
|
||||
*
|
||||
@ -514,8 +517,21 @@ struct JSObject {
|
||||
static const uint32 JSSLOT_ARGS_LENGTH = JSSLOT_PRIVATE + 1;
|
||||
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;
|
||||
|
||||
@ -530,16 +546,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);
|
||||
@ -560,6 +586,8 @@ struct JSObject {
|
||||
inline bool hasMethodObj(const JSObject& obj) const;
|
||||
inline void setMethodObj(JSObject& obj);
|
||||
|
||||
inline JSFunction *getFunctionPrivate() const;
|
||||
|
||||
/*
|
||||
* RegExp-specific getters and setters.
|
||||
*/
|
||||
@ -731,11 +759,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
|
||||
{
|
||||
|
@ -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()) {
|
||||
|
@ -5436,11 +5436,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) {
|
||||
@ -5476,12 +5480,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;
|
||||
}
|
||||
|
||||
|
@ -1191,8 +1191,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) {
|
||||
@ -1222,9 +1221,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;
|
||||
}
|
||||
@ -2529,7 +2528,7 @@ LeaveFunction(JSParseNode *fn, JSTreeContext *funtc, JSAtom *funAtom = NULL,
|
||||
* Make sure to deoptimize lexical dependencies that are polluted
|
||||
* by eval or with, to safely statically bind globals (see bug 561923).
|
||||
*/
|
||||
if ((funtc->flags & TCF_FUN_USES_EVAL) ||
|
||||
if ((funtc->flags & TCF_FUN_CALLS_EVAL) ||
|
||||
(outer_ale && tc->innermostWith &&
|
||||
ALE_DEFN(outer_ale)->pn_pos < tc->innermostWith->pn_pos)) {
|
||||
DeoptimizeUsesWithin(dn, fn->pn_pos);
|
||||
@ -2608,32 +2607,166 @@ 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;
|
||||
}
|
||||
|
||||
static bool
|
||||
DefineGlobal(JSParseNode *pn, JSCodeGenerator *cg, JSAtom *atom);
|
||||
|
||||
JSParseNode *
|
||||
Parser::functionDef(uintN lambda, bool namePermitted)
|
||||
bool
|
||||
Parser::functionArguments(JSTreeContext &funtc, JSFunctionBox *funbox, JSFunction *fun,
|
||||
JSParseNode **listp)
|
||||
{
|
||||
JSParseNode *pn, *body, *result;
|
||||
TokenKind tt;
|
||||
JSAtomListElement *ale;
|
||||
if (tokenStream.getToken() != TOK_LP) {
|
||||
reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_PAREN_BEFORE_FORMAL);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!tokenStream.matchToken(TOK_RP)) {
|
||||
#if JS_HAS_DESTRUCTURING
|
||||
JSParseNode *item, *list = NULL;
|
||||
bool destructuringArg = false;
|
||||
JSAtom *duplicatedArg = NULL;
|
||||
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;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
/*
|
||||
* 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(JSAtom *funAtom, FunctionType type, uintN lambda)
|
||||
{
|
||||
/* 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;
|
||||
@ -2650,28 +2783,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();
|
||||
|
||||
@ -2781,124 +2898,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;
|
||||
@ -2907,7 +2924,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;
|
||||
|
||||
@ -2927,6 +2944,24 @@ 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
|
||||
@ -2935,7 +2970,7 @@ Parser::functionDef(uintN lambda, bool namePermitted)
|
||||
* parameter destructuring code without bracing the decompilation of the
|
||||
* function body's lexical scope.
|
||||
*/
|
||||
if (list) {
|
||||
if (prolog) {
|
||||
if (body->pn_arity != PN_LIST) {
|
||||
JSParseNode *block;
|
||||
|
||||
@ -2949,13 +2984,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)
|
||||
@ -2984,7 +3019,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.
|
||||
@ -3013,8 +3049,6 @@ Parser::functionDef(uintN lambda, bool namePermitted)
|
||||
* sub-statement.
|
||||
*/
|
||||
op = JSOP_DEFFUN;
|
||||
} else {
|
||||
op = JSOP_NOP;
|
||||
}
|
||||
|
||||
funbox->kids = funtc.functionList;
|
||||
@ -3041,7 +3075,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;
|
||||
@ -3050,13 +3084,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);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3673,7 +3723,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;
|
||||
}
|
||||
|
||||
@ -5806,15 +5857,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)
|
||||
{
|
||||
@ -5982,7 +6024,7 @@ Parser::variables(bool inLetHead)
|
||||
|
||||
if (tc->inFunction() &&
|
||||
atom == context->runtime->atomState.argumentsAtom) {
|
||||
NoteArgumentsUse(tc);
|
||||
tc->noteArgumentsUse();
|
||||
if (!let)
|
||||
tc->flags |= TCF_FUN_HEAVYWEIGHT;
|
||||
}
|
||||
@ -7184,7 +7226,8 @@ 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->flags |= TCF_FUN_HEAVYWEIGHT | TCF_FUN_USES_EVAL;
|
||||
tc->noteCallsEval();
|
||||
tc->flags |= TCF_FUN_HEAVYWEIGHT;
|
||||
}
|
||||
} else if (pn->pn_op == JSOP_GETPROP) {
|
||||
if (pn->pn_atom == context->runtime->atomState.applyAtom ||
|
||||
@ -8115,9 +8158,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;
|
||||
}
|
||||
@ -8333,7 +8375,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
|
||||
|
@ -486,9 +486,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 {
|
||||
@ -1061,8 +1061,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);
|
||||
|
@ -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 */
|
||||
|
@ -1030,13 +1030,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
|
||||
@ -1118,7 +1130,7 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
|
||||
script->strictModeCode = true;
|
||||
if (cg->flags & TCF_COMPILE_N_GO)
|
||||
script->compileAndGo = true;
|
||||
if (cg->flags & TCF_FUN_USES_EVAL)
|
||||
if (cg->flags & TCF_FUN_CALLS_EVAL)
|
||||
script->usesEval = true;
|
||||
|
||||
if (cg->upvarList.count != 0) {
|
||||
|
@ -79,6 +79,7 @@
|
||||
|
||||
#include "jsatominlines.h"
|
||||
#include "jscntxtinlines.h"
|
||||
#include "jsfuninlines.h"
|
||||
#include "jspropertycacheinlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
#include "jsscopeinlines.h"
|
||||
@ -3453,8 +3454,10 @@ FlushNativeStackFrame(JSContext* cx, unsigned callDepth, const JSValueType* mp,
|
||||
for (; n != 0; fp = fp->down) {
|
||||
--n;
|
||||
if (fp->argv) {
|
||||
if (fp->hasArgsObj() && fp->getArgsObj()->getPrivate() == JS_ARGUMENT_OBJECT_ON_TRACE)
|
||||
if (fp->hasArgsObj() && fp->getArgsObj()->getPrivate() == JS_ARGUMENT_OBJECT_ON_TRACE) {
|
||||
JS_ASSERT(fp->getArgsObj()->isNormalArguments());
|
||||
fp->getArgsObj()->setPrivate(fp);
|
||||
}
|
||||
|
||||
JS_ASSERT(fp->argv[-1].isObjectOrNull());
|
||||
JS_ASSERT(fp->callee()->isFunction());
|
||||
@ -8748,13 +8751,22 @@ TraceRecorder::tableswitch()
|
||||
high = GET_JUMPX_OFFSET(pc);
|
||||
}
|
||||
|
||||
/*
|
||||
* If there are no cases, this is a no-op. The default case immediately
|
||||
* follows in the bytecode and is always taken, so we need no special
|
||||
* action to handle it.
|
||||
*/
|
||||
int count = high + 1 - low;
|
||||
if (count == 0)
|
||||
return ARECORD_CONTINUE;
|
||||
|
||||
/* Cap maximum table-switch size for modesty. */
|
||||
if ((high + 1 - low) > MAX_TABLE_SWITCH)
|
||||
if (count > MAX_TABLE_SWITCH)
|
||||
return InjectStatus(switchop());
|
||||
|
||||
/* Generate switch LIR. */
|
||||
SwitchInfo* si = new (traceAlloc()) SwitchInfo();
|
||||
si->count = high + 1 - low;
|
||||
si->count = count;
|
||||
si->table = 0;
|
||||
si->index = (uint32) -1;
|
||||
LIns* diff = lir->ins2(LIR_subi, v_ins, lir->insImmI(low));
|
||||
@ -10297,7 +10309,7 @@ TraceRecorder::clearCurrentFrameSlotsFromTracker(Tracker& which)
|
||||
JS_REQUIRES_STACK void
|
||||
TraceRecorder::putActivationObjects()
|
||||
{
|
||||
bool have_args = cx->fp->hasArgsObj() && cx->fp->argc;
|
||||
bool have_args = cx->fp->hasArgsObj() && !cx->fp->getArgsObj()->isStrictArguments() && cx->fp->argc > 0;
|
||||
bool have_call = cx->fp->hasFunction() &&
|
||||
JSFUN_HEAVYWEIGHT_TEST(cx->fp->getFunction()->flags) &&
|
||||
cx->fp->getFunction()->countArgsAndVars();
|
||||
@ -10660,7 +10672,7 @@ TraceRecorder::record_JSOP_IFNE()
|
||||
}
|
||||
|
||||
LIns*
|
||||
TraceRecorder::newArguments(LIns* callee_ins)
|
||||
TraceRecorder::newArguments(LIns* callee_ins, bool strict)
|
||||
{
|
||||
LIns* global_ins = INS_CONSTOBJ(globalObj);
|
||||
LIns* argc_ins = INS_CONST(cx->fp->argc);
|
||||
@ -10668,6 +10680,15 @@ TraceRecorder::newArguments(LIns* callee_ins)
|
||||
LIns* args[] = { callee_ins, argc_ins, global_ins, cx_ins };
|
||||
LIns* call_ins = lir->insCall(&js_Arguments_ci, args);
|
||||
guard(false, lir->insEqP_0(call_ins), OOM_EXIT);
|
||||
|
||||
if (strict) {
|
||||
JSStackFrame* fp = cx->fp;
|
||||
uintN argc = fp->argc;
|
||||
LIns* argsSlots_ins = NULL;
|
||||
for (uintN i = 0; i < argc; i++)
|
||||
stobj_set_dslot(call_ins, i, argsSlots_ins, fp->argv[i], get(&fp->argv[i]));
|
||||
}
|
||||
|
||||
return call_ins;
|
||||
}
|
||||
|
||||
@ -10680,12 +10701,15 @@ TraceRecorder::record_JSOP_ARGUMENTS()
|
||||
if (cx->fp->flags & JSFRAME_OVERRIDE_ARGS)
|
||||
RETURN_STOP_A("Can't trace |arguments| if |arguments| is assigned to");
|
||||
|
||||
JSStackFrame* const fp = cx->fp;
|
||||
|
||||
LIns* a_ins = getFrameObjPtr(cx->fp->addressArgsObj());
|
||||
LIns* args_ins;
|
||||
LIns* callee_ins = get(&cx->fp->argv[-2]);
|
||||
LIns* callee_ins = get(&fp->argv[-2]);
|
||||
bool strict = fp->getFunction()->inStrictMode();
|
||||
if (a_ins->isImmP()) {
|
||||
// |arguments| is set to 0 by EnterFrame on this trace, so call to create it.
|
||||
args_ins = newArguments(callee_ins);
|
||||
args_ins = newArguments(callee_ins, strict);
|
||||
} else {
|
||||
// Generate LIR to create arguments only if it has not already been created.
|
||||
|
||||
@ -10698,7 +10722,7 @@ TraceRecorder::record_JSOP_ARGUMENTS()
|
||||
LIns* label1 = lir->ins0(LIR_label);
|
||||
br1->setTarget(label1);
|
||||
|
||||
LIns* call_ins = newArguments(callee_ins);
|
||||
LIns* call_ins = newArguments(callee_ins, strict);
|
||||
lir->insStore(call_ins, mem_ins, 0, ACCSET_OTHER);
|
||||
|
||||
LIns* label2 = lir->ins0(LIR_label);
|
||||
@ -10708,7 +10732,7 @@ TraceRecorder::record_JSOP_ARGUMENTS()
|
||||
}
|
||||
|
||||
stack(0, args_ins);
|
||||
setFrameObjPtr(cx->fp->addressArgsObj(), args_ins);
|
||||
setFrameObjPtr(fp->addressArgsObj(), args_ins);
|
||||
return ARECORD_CONTINUE;
|
||||
}
|
||||
|
||||
@ -13361,7 +13385,7 @@ TraceRecorder::guardArguments(JSObject *obj, LIns* obj_ins, unsigned *depthp)
|
||||
return NULL;
|
||||
|
||||
VMSideExit *exit = snapshot(MISMATCH_EXIT);
|
||||
guardClass(obj_ins, &js_ArgumentsClass, exit, LOAD_CONST);
|
||||
guardClass(obj_ins, obj->getClass(), exit, LOAD_CONST);
|
||||
|
||||
LIns* args_ins = getFrameObjPtr(afp->addressArgsObj());
|
||||
LIns* cmp = lir->ins2(LIR_eqp, args_ins, obj_ins);
|
||||
@ -15272,10 +15296,10 @@ TraceRecorder::record_JSOP_ARGSUB()
|
||||
JS_REQUIRES_STACK LIns*
|
||||
TraceRecorder::guardArgsLengthNotAssigned(LIns* argsobj_ins)
|
||||
{
|
||||
// The following implements IsOverriddenArgsLength on trace.
|
||||
// The '2' bit is set if length was overridden.
|
||||
// The following implements JSObject::isArgsLengthOverridden on trace.
|
||||
// ARGS_LENGTH_OVERRIDDEN_BIT is set if length was overridden.
|
||||
LIns *len_ins = stobj_get_fslot_uint32(argsobj_ins, JSObject::JSSLOT_ARGS_LENGTH);
|
||||
LIns *ovr_ins = lir->ins2(LIR_andi, len_ins, INS_CONST(2));
|
||||
LIns *ovr_ins = lir->ins2(LIR_andi, len_ins, INS_CONST(JSObject::ARGS_LENGTH_OVERRIDDEN_BIT));
|
||||
guard(true, lir->insEqI_0(ovr_ins), snapshot(BRANCH_EXIT));
|
||||
return len_ins;
|
||||
}
|
||||
@ -15973,9 +15997,11 @@ TraceRecorder::record_JSOP_LENGTH()
|
||||
RETURN_STOP_A("can't trace JSOP_ARGCNT if arguments.length has been modified");
|
||||
LIns* slot_ins = guardArgsLengthNotAssigned(obj_ins);
|
||||
|
||||
// slot_ins is the value from the slot; right-shift by 2 bits to get
|
||||
// the length (see GetArgsLength in jsfun.cpp).
|
||||
LIns* v_ins = lir->ins1(LIR_i2d, lir->ins2ImmI(LIR_rshi, slot_ins, 1));
|
||||
// slot_ins is the value from the slot; right-shift to get the length
|
||||
// (see JSObject::getArgsInitialLength in jsfun.cpp).
|
||||
LIns* v_ins =
|
||||
lir->ins1(LIR_i2d, lir->ins2ImmI(LIR_rshi,
|
||||
slot_ins, JSObject::ARGS_PACKED_BITS_COUNT));
|
||||
set(&l, v_ins);
|
||||
return ARECORD_CONTINUE;
|
||||
}
|
||||
|
@ -1167,7 +1167,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);
|
||||
|
@ -2115,8 +2115,7 @@ mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck)
|
||||
pic.objRemat = frame.dataRematInfo(top);
|
||||
|
||||
/* Guard on shape. */
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, map)), shapeReg);
|
||||
masm.load32(Address(shapeReg, offsetof(JSObjectMap, shape)), shapeReg);
|
||||
masm.loadShape(objReg, shapeReg);
|
||||
pic.shapeGuard = masm.label();
|
||||
|
||||
DataLabel32 inlineShapeLabel;
|
||||
@ -2203,8 +2202,7 @@ mjit::Compiler::jsop_getelem_pic(FrameEntry *obj, FrameEntry *id, RegisterID obj
|
||||
pic.fastPathStart = masm.label();
|
||||
|
||||
/* Guard on shape. */
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, map)), shapeReg);
|
||||
masm.load32(Address(shapeReg, offsetof(JSObjectMap, shape)), shapeReg);
|
||||
masm.loadShape(objReg, shapeReg);
|
||||
pic.shapeGuard = masm.label();
|
||||
|
||||
DataLabel32 inlineShapeOffsetLabel;
|
||||
@ -2347,8 +2345,7 @@ mjit::Compiler::jsop_callprop_generic(JSAtom *atom)
|
||||
frame.freeReg(pic.typeReg);
|
||||
|
||||
/* Guard on shape. */
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, map)), shapeReg);
|
||||
masm.load32(Address(shapeReg, offsetof(JSObjectMap, shape)), shapeReg);
|
||||
masm.loadShape(objReg, shapeReg);
|
||||
pic.shapeGuard = masm.label();
|
||||
|
||||
DataLabel32 inlineShapeLabel;
|
||||
@ -2515,8 +2512,7 @@ mjit::Compiler::jsop_callprop_obj(JSAtom *atom)
|
||||
pic.objRemat = frame.dataRematInfo(top);
|
||||
|
||||
/* Guard on shape. */
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, map)), shapeReg);
|
||||
masm.load32(Address(shapeReg, offsetof(JSObjectMap, shape)), shapeReg);
|
||||
masm.loadShape(objReg, shapeReg);
|
||||
pic.shapeGuard = masm.label();
|
||||
|
||||
DataLabel32 inlineShapeLabel;
|
||||
@ -2688,8 +2684,7 @@ mjit::Compiler::jsop_setprop(JSAtom *atom)
|
||||
}
|
||||
|
||||
/* Guard on shape. */
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, map)), shapeReg);
|
||||
masm.load32(Address(shapeReg, offsetof(JSObjectMap, shape)), shapeReg);
|
||||
masm.loadShape(objReg, shapeReg);
|
||||
pic.shapeGuard = masm.label();
|
||||
DataLabel32 inlineShapeOffsetLabel;
|
||||
Jump j = masm.branch32WithPatch(Assembler::NotEqual, shapeReg,
|
||||
@ -3473,8 +3468,7 @@ mjit::Compiler::jsop_getgname(uint32 index)
|
||||
frame.pop();
|
||||
RegisterID reg = frame.allocReg();
|
||||
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, map)), reg);
|
||||
masm.load32(Address(reg, offsetof(JSObjectMap, shape)), reg);
|
||||
masm.loadShape(objReg, reg);
|
||||
shapeGuard = masm.branch32WithPatch(Assembler::NotEqual, reg,
|
||||
Imm32(int32(JSObjectMap::INVALID_SHAPE)), mic.shape);
|
||||
frame.freeReg(reg);
|
||||
@ -3510,8 +3504,13 @@ mjit::Compiler::jsop_getgname(uint32 index)
|
||||
|
||||
mic.load = masm.label();
|
||||
# if defined JS_NUNBOX32
|
||||
# if defined JS_CPU_ARM
|
||||
DataLabel32 offsetAddress = masm.load64WithAddressOffsetPatch(address, treg, dreg);
|
||||
JS_ASSERT(masm.differenceBetween(mic.load, offsetAddress) == 0);
|
||||
# else
|
||||
masm.loadPayload(address, dreg);
|
||||
masm.loadTypeTag(address, treg);
|
||||
# endif
|
||||
# elif defined JS_PUNBOX64
|
||||
Label inlineValueLoadLabel =
|
||||
masm.loadValueAsComponents(address, treg, dreg);
|
||||
@ -3569,8 +3568,7 @@ mjit::Compiler::jsop_setgname(uint32 index)
|
||||
frame.pinReg(objReg);
|
||||
RegisterID reg = frame.allocReg();
|
||||
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, map)), reg);
|
||||
masm.load32(Address(reg, offsetof(JSObjectMap, shape)), reg);
|
||||
masm.loadShape(objReg, reg);
|
||||
shapeGuard = masm.branch32WithPatch(Assembler::NotEqual, reg,
|
||||
Imm32(int32(JSObjectMap::INVALID_SHAPE)),
|
||||
mic.shape);
|
||||
@ -3608,11 +3606,27 @@ mjit::Compiler::jsop_setgname(uint32 index)
|
||||
v = fe->getValue();
|
||||
}
|
||||
|
||||
mic.load = masm.label();
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
|
||||
Address address(objReg, slot);
|
||||
|
||||
mic.load = masm.label();
|
||||
|
||||
#if defined JS_NUNBOX32
|
||||
# if defined JS_CPU_ARM
|
||||
DataLabel32 offsetAddress;
|
||||
if (mic.u.name.dataConst) {
|
||||
offsetAddress = masm.moveWithPatch(Imm32(address.offset), JSC::ARMRegisters::S0);
|
||||
masm.add32(address.base, JSC::ARMRegisters::S0);
|
||||
masm.storeValue(v, Address(JSC::ARMRegisters::S0, 0));
|
||||
} else {
|
||||
if (mic.u.name.typeConst) {
|
||||
offsetAddress = masm.store64WithAddressOffsetPatch(ImmType(typeTag), dataReg, address);
|
||||
} else {
|
||||
offsetAddress = masm.store64WithAddressOffsetPatch(typeReg, dataReg, address);
|
||||
}
|
||||
}
|
||||
JS_ASSERT(masm.differenceBetween(mic.load, offsetAddress) == 0);
|
||||
# else
|
||||
if (mic.u.name.dataConst) {
|
||||
masm.storeValue(v, address);
|
||||
} else {
|
||||
@ -3622,6 +3636,7 @@ mjit::Compiler::jsop_setgname(uint32 index)
|
||||
masm.storeTypeTag(typeReg, address);
|
||||
masm.storePayload(dataReg, address);
|
||||
}
|
||||
# endif
|
||||
#elif defined JS_PUNBOX64
|
||||
if (mic.u.name.dataConst) {
|
||||
/* Emits a single move. No code length variation. */
|
||||
@ -3739,10 +3754,9 @@ mjit::Compiler::jsop_instanceof()
|
||||
|
||||
/* Quick test to avoid wrapped objects. */
|
||||
masm.loadPtr(Address(obj, offsetof(JSObject, clasp)), temp);
|
||||
masm.load32(Address(temp, offsetof(Class, ext) +
|
||||
offsetof(ClassExtension, wrappedObject)),
|
||||
temp);
|
||||
j = masm.branchTest32(Assembler::NonZero, temp, temp);
|
||||
masm.loadPtr(Address(temp, offsetof(Class, ext) +
|
||||
offsetof(ClassExtension, wrappedObject)), temp);
|
||||
j = masm.branchTestPtr(Assembler::NonZero, temp, temp);
|
||||
stubcc.linkExit(j, Uses(3));
|
||||
|
||||
Address protoAddr(obj, offsetof(JSObject, proto));
|
||||
|
@ -130,14 +130,21 @@ struct Registers {
|
||||
(1 << JSC::ARMRegisters::r0)
|
||||
| (1 << JSC::ARMRegisters::r1)
|
||||
| (1 << JSC::ARMRegisters::r2);
|
||||
// r3 is reserved as a scratch register for the assembler.
|
||||
|
||||
static const uint32 SavedRegs =
|
||||
(1 << JSC::ARMRegisters::r4)
|
||||
| (1 << JSC::ARMRegisters::r5)
|
||||
| (1 << JSC::ARMRegisters::r6)
|
||||
| (1 << JSC::ARMRegisters::r7)
|
||||
// r8 is reserved as a scratch register for the assembler.
|
||||
| (1 << JSC::ARMRegisters::r9)
|
||||
| (1 << JSC::ARMRegisters::r10);
|
||||
// r11 is reserved for JSFrameReg.
|
||||
// r12 is IP, and is used for stub calls.
|
||||
// r13 is SP and must always point to VMFrame whilst in generated code.
|
||||
// r14 is LR and is used for return sequences.
|
||||
// r15 is PC (program counter).
|
||||
|
||||
static const uint32 SingleByteRegs = TempRegs | SavedRegs;
|
||||
#else
|
||||
|
@ -101,9 +101,13 @@ ic::GetGlobalName(VMFrame &f, uint32 index)
|
||||
slot -= JS_INITIAL_NSLOTS;
|
||||
slot *= sizeof(Value);
|
||||
JSC::RepatchBuffer loads(mic.load.executableAddress(), 32, false);
|
||||
#if defined JS_NUNBOX32
|
||||
#if defined JS_CPU_X86
|
||||
loads.repatch(mic.load.dataLabel32AtOffset(MICInfo::GET_DATA_OFFSET), slot);
|
||||
loads.repatch(mic.load.dataLabel32AtOffset(MICInfo::GET_TYPE_OFFSET), slot + 4);
|
||||
#elif defined JS_CPU_ARM
|
||||
// mic.load actually points to the LDR instruction which fetches the offset, but 'repatch'
|
||||
// knows how to dereference it to find the integer value.
|
||||
loads.repatch(mic.load.dataLabel32AtOffset(0), slot);
|
||||
#elif defined JS_PUNBOX64
|
||||
loads.repatch(mic.load.dataLabel32AtOffset(mic.patchValueOffset), slot);
|
||||
#endif
|
||||
@ -167,7 +171,7 @@ ic::SetGlobalName(VMFrame &f, uint32 index)
|
||||
slot *= sizeof(Value);
|
||||
|
||||
JSC::RepatchBuffer stores(mic.load.executableAddress(), 32, false);
|
||||
#if defined JS_NUNBOX32
|
||||
#if defined JS_CPU_X86
|
||||
stores.repatch(mic.load.dataLabel32AtOffset(MICInfo::SET_TYPE_OFFSET), slot + 4);
|
||||
|
||||
uint32 dataOffset;
|
||||
@ -177,6 +181,10 @@ ic::SetGlobalName(VMFrame &f, uint32 index)
|
||||
dataOffset = MICInfo::SET_DATA_TYPE_OFFSET;
|
||||
if (mic.u.name.dataWrite)
|
||||
stores.repatch(mic.load.dataLabel32AtOffset(dataOffset), slot);
|
||||
#elif defined JS_CPU_ARM
|
||||
// mic.load actually points to the LDR instruction which fetches the offset, but 'repatch'
|
||||
// knows how to dereference it to find the integer value.
|
||||
stores.repatch(mic.load.dataLabel32AtOffset(0), slot);
|
||||
#elif defined JS_PUNBOX64
|
||||
stores.repatch(mic.load.dataLabel32AtOffset(mic.patchValueOffset), slot);
|
||||
#endif
|
||||
|
@ -55,11 +55,12 @@ struct MICInfo {
|
||||
static const uint32 GET_DATA_OFFSET = 6;
|
||||
static const uint32 GET_TYPE_OFFSET = 12;
|
||||
|
||||
static const uint32 SET_TYPE_OFFSET = 9;
|
||||
static const uint32 SET_DATA_CONST_TYPE_OFFSET = 19;
|
||||
static const uint32 SET_DATA_TYPE_OFFSET = 15;
|
||||
#elif JS_CPU_X64
|
||||
/* No constants used, thanks to patchValueOffset. */
|
||||
static const uint32 SET_TYPE_OFFSET = 6;
|
||||
static const uint32 SET_DATA_CONST_TYPE_OFFSET = 16;
|
||||
static const uint32 SET_DATA_TYPE_OFFSET = 12;
|
||||
#elif JS_CPU_X64 || JS_CPU_ARM
|
||||
/* X64: No constants used, thanks to patchValueOffset. */
|
||||
/* ARM: No constants used as mic.load always points to an LDR that loads the offset. */
|
||||
#endif
|
||||
|
||||
enum Kind
|
||||
|
@ -153,7 +153,6 @@ class Assembler : public BaseAssembler
|
||||
|
||||
/*
|
||||
* Stores type first, then payload.
|
||||
* Returns label after type store. Useful for offset verification.
|
||||
*/
|
||||
void storeValue(const Value &v, Address address) {
|
||||
jsval_layout jv;
|
||||
|
@ -853,7 +853,7 @@ class GetPropCompiler : public PICStubCompiler
|
||||
|
||||
if (pic.objNeedsRemat()) {
|
||||
if (pic.objRemat() >= sizeof(JSStackFrame))
|
||||
masm.load32(Address(JSFrameReg, pic.objRemat()), pic.objReg);
|
||||
masm.loadPayload(Address(JSFrameReg, pic.objRemat()), pic.objReg);
|
||||
else
|
||||
masm.move(RegisterID(pic.objRemat()), pic.objReg);
|
||||
pic.u.get.objNeedsRemat = false;
|
||||
@ -1210,7 +1210,7 @@ class GetElemCompiler : public PICStubCompiler
|
||||
|
||||
if (pic.objNeedsRemat()) {
|
||||
if (pic.objRemat() >= sizeof(JSStackFrame))
|
||||
masm.load32(Address(JSFrameReg, pic.objRemat()), pic.objReg);
|
||||
masm.loadPayload(Address(JSFrameReg, pic.objRemat()), pic.objReg);
|
||||
else
|
||||
masm.move(RegisterID(pic.objRemat()), pic.objReg);
|
||||
pic.u.get.objNeedsRemat = false;
|
||||
@ -1218,7 +1218,7 @@ class GetElemCompiler : public PICStubCompiler
|
||||
|
||||
if (pic.idNeedsRemat()) {
|
||||
if (pic.idRemat() >= sizeof(JSStackFrame))
|
||||
masm.load32(Address(JSFrameReg, pic.idRemat()), pic.u.get.idReg);
|
||||
masm.loadPayload(Address(JSFrameReg, pic.idRemat()), pic.u.get.idReg);
|
||||
else
|
||||
masm.move(RegisterID(pic.idRemat()), pic.u.get.idReg);
|
||||
pic.u.get.idNeedsRemat = false;
|
||||
@ -1843,7 +1843,7 @@ ic::GetProp(VMFrame &f, uint32 index)
|
||||
cc.disable("error");
|
||||
THROW();
|
||||
}
|
||||
f.regs.sp[-1].setInt32(int32_t(obj->getArgsLength()));
|
||||
f.regs.sp[-1].setInt32(int32_t(obj->getArgsInitialLength()));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -525,7 +525,7 @@ stubs::GetElem(VMFrame &f)
|
||||
) {
|
||||
uint32 arg = uint32(rval.toInt32());
|
||||
|
||||
if (arg < obj->getArgsLength()) {
|
||||
if (arg < obj->getArgsInitialLength()) {
|
||||
JSStackFrame *afp = (JSStackFrame *) obj->getPrivate();
|
||||
if (afp) {
|
||||
copyFrom = &afp->argv[arg];
|
||||
@ -2159,7 +2159,7 @@ stubs::Length(VMFrame &f)
|
||||
regs.sp[-1].setNumber(length);
|
||||
return;
|
||||
} 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));
|
||||
return;
|
||||
|
@ -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;
|
||||
|
@ -1,2 +1,3 @@
|
||||
url-prefix ../../jsreftest.html?test=ecma_5/Date/
|
||||
script 15.9.4.2.js
|
||||
script toJSON-01.js
|
||||
|
242
js/src/tests/ecma_5/Date/toJSON-01.js
Normal file
242
js/src/tests/ecma_5/Date/toJSON-01.js
Normal file
@ -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);
|
66
js/src/tests/ecma_5/Function/arguments-caller-callee.js
Normal file
66
js/src/tests/ecma_5/Function/arguments-caller-callee.js
Normal file
@ -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!");
|
102
js/src/tests/ecma_5/Function/arguments-property-attributes.js
Normal file
102
js/src/tests/ecma_5/Function/arguments-property-attributes.js
Normal file
@ -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!");
|
76
js/src/tests/ecma_5/Function/function-caller.js
Normal file
76
js/src/tests/ecma_5/Function/function-caller.js
Normal file
@ -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
|
||||
|
382
js/src/tests/ecma_5/Function/strict-arguments.js
Normal file
382
js/src/tests/ecma_5/Function/strict-arguments.js
Normal file
@ -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
|
||||
|
52
js/src/tests/ecma_5/JSON/stringify-gap.js
Normal file
52
js/src/tests/ecma_5/JSON/stringify-gap.js
Normal file
@ -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');
|
||||
}
|
||||
|
@ -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');
|
||||
|
75
js/src/tests/js1_8_5/extensions/destructure-accessor.js
Normal file
75
js/src/tests/js1_8_5/extensions/destructure-accessor.js
Normal file
@ -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,4 @@ script scripted-proxies.js
|
||||
script array-length-protochange.js
|
||||
script parseInt-octal.js
|
||||
script proxy-enumerateOwn-duplicates.js
|
||||
script destructure-accessor.js
|
||||
|
24
js/src/trace-test/lib/array-compare.js
Normal file
24
js/src/trace-test/lib/array-compare.js
Normal file
@ -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);
|
||||
|
||||
|
24
js/src/trace-test/tests/arguments/nonstrict-args.js
Normal file
24
js/src/trace-test/tests/arguments/nonstrict-args.js
Normal file
@ -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);
|
17
js/src/trace-test/tests/arguments/nonstrict-assign.js
Normal file
17
js/src/trace-test/tests/arguments/nonstrict-assign.js
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
load(libdir + 'array-compare.js');
|
||||
|
||||
function assign(a)
|
||||
{
|
||||
a = 17;
|
||||
return arguments;
|
||||
}
|
||||
|
||||
var a1;
|
||||
for (var i = 0; i < 5; i++)
|
||||
a1 = assign(1);
|
||||
|
||||
assertEq(arraysEqual(a1, [17]), true);
|
18
js/src/trace-test/tests/arguments/nonstrict-later-assign.js
Normal file
18
js/src/trace-test/tests/arguments/nonstrict-later-assign.js
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
load(libdir + 'array-compare.js');
|
||||
|
||||
function getLaterAssign(a)
|
||||
{
|
||||
var o = arguments;
|
||||
a = 17;
|
||||
return o;
|
||||
}
|
||||
|
||||
var a1, a2;
|
||||
for (var i = 0; i < 5; i++)
|
||||
a1 = getLaterAssign(1);
|
||||
|
||||
assertEq(arraysEqual(a1, [17]), true);
|
21
js/src/trace-test/tests/arguments/nonstrict-noargs.js
Normal file
21
js/src/trace-test/tests/arguments/nonstrict-noargs.js
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
load(libdir + 'array-compare.js');
|
||||
|
||||
var obj = {};
|
||||
|
||||
function noargs() { return arguments; }
|
||||
|
||||
var a1, a2, a3;
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
a1 = noargs();
|
||||
a2 = noargs(1);
|
||||
a3 = noargs(2, obj, 8);
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(a1, []), true);
|
||||
assertEq(arraysEqual(a2, [1]), true);
|
||||
assertEq(arraysEqual(a3, [2, obj, 8]), true);
|
25
js/src/trace-test/tests/arguments/strict-args.js
Normal file
25
js/src/trace-test/tests/arguments/strict-args.js
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
load(libdir + 'array-compare.js');
|
||||
|
||||
var obj = {};
|
||||
|
||||
function strictArgs(a)
|
||||
{
|
||||
"use strict";
|
||||
return arguments;
|
||||
}
|
||||
|
||||
var a1, a2, a3;
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
a1 = strictArgs();
|
||||
a2 = strictArgs(1);
|
||||
a3 = strictArgs(1, obj);
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(a1, []), true);
|
||||
assertEq(arraysEqual(a2, [1]), true);
|
||||
assertEq(arraysEqual(a3, [1, obj]), true);
|
28
js/src/trace-test/tests/arguments/strict-assign-after.js
Normal file
28
js/src/trace-test/tests/arguments/strict-assign-after.js
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
load(libdir + 'array-compare.js');
|
||||
|
||||
var obj = {};
|
||||
|
||||
var upper;
|
||||
function strictAssignAfter(a)
|
||||
{
|
||||
"use strict";
|
||||
upper = arguments;
|
||||
a = 42;
|
||||
return upper;
|
||||
}
|
||||
|
||||
var a1, a2, a3;
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
a1 = strictAssignAfter();
|
||||
a2 = strictAssignAfter(17);
|
||||
a3 = strictAssignAfter(obj);
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(a1, []), true);
|
||||
assertEq(arraysEqual(a2, [17]), true);
|
||||
assertEq(arraysEqual(a3, [obj]), true);
|
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
load(libdir + 'array-compare.js');
|
||||
|
||||
var obj = {};
|
||||
|
||||
function strictAssignArgumentsElement(a)
|
||||
{
|
||||
"use strict";
|
||||
arguments[0] = 42;
|
||||
return a;
|
||||
}
|
||||
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
assertEq(strictAssignArgumentsElement(), undefined);
|
||||
assertEq(strictAssignArgumentsElement(obj), obj);
|
||||
assertEq(strictAssignArgumentsElement(17), 17);
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
load(libdir + 'array-compare.js');
|
||||
|
||||
var obj = {};
|
||||
|
||||
function strictAssignOuterParamPSYCH(p)
|
||||
{
|
||||
"use strict";
|
||||
function inner(p) { p = 17; }
|
||||
inner();
|
||||
return arguments;
|
||||
}
|
||||
|
||||
var a1, a2, a3;
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
a1 = strictAssignOuterParamPSYCH();
|
||||
a2 = strictAssignOuterParamPSYCH(17);
|
||||
a3 = strictAssignOuterParamPSYCH(obj);
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(a1, []), true);
|
||||
assertEq(arraysEqual(a2, [17]), true);
|
||||
assertEq(arraysEqual(a3, [obj]), true);
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
load(libdir + 'array-compare.js');
|
||||
|
||||
var obj = {};
|
||||
|
||||
function strictAssignOuterParam(p)
|
||||
{
|
||||
"use strict";
|
||||
function inner() { p = 17; }
|
||||
inner();
|
||||
return arguments;
|
||||
}
|
||||
|
||||
var a1, a2, a3;
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
a1 = strictAssignOuterParam();
|
||||
a2 = strictAssignOuterParam(42);
|
||||
a3 = strictAssignOuterParam(obj);
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(a1, []), true);
|
||||
assertEq(arraysEqual(a2, [42]), true);
|
||||
assertEq(arraysEqual(a3, [obj]), true);
|
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
function strictAssignParameterGetElement(a)
|
||||
{
|
||||
"use strict";
|
||||
a = 17;
|
||||
return arguments[0];
|
||||
}
|
||||
|
||||
for (var i = 0; i < 5; i++)
|
||||
assertEq(strictAssignParameterGetElement(42), 42);
|
26
js/src/trace-test/tests/arguments/strict-assign.js
Normal file
26
js/src/trace-test/tests/arguments/strict-assign.js
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
load(libdir + 'array-compare.js');
|
||||
|
||||
var obj = {};
|
||||
|
||||
function strictAssign(a)
|
||||
{
|
||||
"use strict";
|
||||
a = 17;
|
||||
return arguments;
|
||||
}
|
||||
|
||||
var a1, a2, a3;
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
a1 = strictAssign();
|
||||
a2 = strictAssign(1);
|
||||
a3 = strictAssign(1, obj);
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(a1, []), true);
|
||||
assertEq(arraysEqual(a2, [1]), true);
|
||||
assertEq(arraysEqual(a3, [1, obj]), true);
|
24
js/src/trace-test/tests/arguments/strict-eval-mutation.js
Normal file
24
js/src/trace-test/tests/arguments/strict-eval-mutation.js
Normal file
@ -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 strictEvalMutation(code)
|
||||
{
|
||||
"use strict";
|
||||
return eval(code);
|
||||
}
|
||||
|
||||
var a1, a2;
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
a1 = strictEvalMutation("code = 17; arguments");
|
||||
a2 = strictEvalMutation("arguments[0] = 17; arguments");
|
||||
assertEq(strictEvalMutation("arguments[0] = 17; code"), "arguments[0] = 17; code");
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(a1, ["code = 17; arguments"]), true);
|
||||
assertEq(arraysEqual(a2, [17]), true);
|
30
js/src/trace-test/tests/arguments/strict-eval.js
Normal file
30
js/src/trace-test/tests/arguments/strict-eval.js
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
load(libdir + 'array-compare.js');
|
||||
|
||||
function strictEval(code, p)
|
||||
{
|
||||
"use strict";
|
||||
eval(code);
|
||||
return arguments;
|
||||
}
|
||||
|
||||
var a1, a2, a3, a4, a5, a6;
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
a1 = strictEval("1", 2);
|
||||
a2 = strictEval("arguments");
|
||||
a3 = strictEval("p = 2");
|
||||
a4 = strictEval("p = 2", 17);
|
||||
a5 = strictEval("arguments[0] = 17");
|
||||
a6 = strictEval("arguments[0] = 17", 42);
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(a1, ["1", 2]), true);
|
||||
assertEq(arraysEqual(a2, ["arguments"]), true);
|
||||
assertEq(arraysEqual(a3, ["p = 2"]), true);
|
||||
assertEq(arraysEqual(a4, ["p = 2", 17]), true);
|
||||
assertEq(arraysEqual(a5, [17]), true);
|
||||
assertEq(arraysEqual(a6, [17, 42]), true);
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
load(libdir + 'array-compare.js');
|
||||
|
||||
var obj = {};
|
||||
|
||||
function strictMaybeAssignOuterParam(p)
|
||||
{
|
||||
"use strict";
|
||||
function inner() { p = 17; }
|
||||
return arguments;
|
||||
}
|
||||
|
||||
var a1, a2, a3;
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
a1 = strictMaybeAssignOuterParam();
|
||||
a2 = strictMaybeAssignOuterParam(17);
|
||||
a3 = strictMaybeAssignOuterParam(obj);
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(a1, []), true);
|
||||
assertEq(arraysEqual(a2, [17]), true);
|
||||
assertEq(arraysEqual(a3, [obj]), true);
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
load(libdir + 'array-compare.js');
|
||||
|
||||
function strictMaybeNestedEval(code, p)
|
||||
{
|
||||
"use strict";
|
||||
function inner() { eval(code); }
|
||||
return arguments;
|
||||
}
|
||||
|
||||
var a1, a2, a3, a4;
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
a1 = strictMaybeNestedEval("1", 2);
|
||||
a2 = strictMaybeNestedEval("arguments");
|
||||
a3 = strictMaybeNestedEval("p = 2");
|
||||
a4 = strictMaybeNestedEval("p = 2", 17);
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(a1, ["1", 2]), true);
|
||||
assertEq(arraysEqual(a2, ["arguments"]), true);
|
||||
assertEq(arraysEqual(a3, ["p = 2"]), true);
|
||||
assertEq(arraysEqual(a4, ["p = 2", 17]), true);
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
load(libdir + 'array-compare.js');
|
||||
|
||||
var obj = {};
|
||||
|
||||
function strictNestedAssignShadowFunctionCall(p)
|
||||
{
|
||||
"use strict";
|
||||
function inner()
|
||||
{
|
||||
function p() { }
|
||||
p = 1776;
|
||||
}
|
||||
inner();
|
||||
return arguments;
|
||||
}
|
||||
|
||||
var a1, a2, a3, a4;
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
a1 = strictNestedAssignShadowFunctionCall();
|
||||
a2 = strictNestedAssignShadowFunctionCall(99);
|
||||
a3 = strictNestedAssignShadowFunctionCall("");
|
||||
a4 = strictNestedAssignShadowFunctionCall(obj);
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(a1, []), true);
|
||||
assertEq(arraysEqual(a2, [99]), true);
|
||||
assertEq(arraysEqual(a3, [""]), true);
|
||||
assertEq(arraysEqual(a4, [obj]), true);
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
load(libdir + 'array-compare.js');
|
||||
|
||||
var obj = {};
|
||||
|
||||
function strictNestedAssignShadowFunctionName(p)
|
||||
{
|
||||
"use strict";
|
||||
function inner()
|
||||
{
|
||||
function p() { p = 1776; }
|
||||
p();
|
||||
}
|
||||
inner();
|
||||
return arguments;
|
||||
}
|
||||
|
||||
var a1, a2, a3, a4, a5;
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
a1 = strictNestedAssignShadowFunctionName();
|
||||
a2 = strictNestedAssignShadowFunctionName(99);
|
||||
a3 = strictNestedAssignShadowFunctionName("");
|
||||
a4 = strictNestedAssignShadowFunctionName(obj);
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(a1, []), true);
|
||||
assertEq(arraysEqual(a2, [99]), true);
|
||||
assertEq(arraysEqual(a3, [""]), true);
|
||||
assertEq(arraysEqual(a4, [obj]), true);
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
load(libdir + 'array-compare.js');
|
||||
|
||||
var obj = {};
|
||||
|
||||
function strictNestedAssignShadowFunction(p)
|
||||
{
|
||||
"use strict";
|
||||
function inner()
|
||||
{
|
||||
function p() { }
|
||||
p = 1776;
|
||||
}
|
||||
return arguments;
|
||||
}
|
||||
|
||||
var a1, a2, a3, a4;
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
a1 = strictNestedAssignShadowFunction();
|
||||
a2 = strictNestedAssignShadowFunction(99);
|
||||
a3 = strictNestedAssignShadowFunction("");
|
||||
a4 = strictNestedAssignShadowFunction(obj);
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(a1, []), true);
|
||||
assertEq(arraysEqual(a2, [99]), true);
|
||||
assertEq(arraysEqual(a3, [""]), true);
|
||||
assertEq(arraysEqual(a4, [obj]), true);
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
load(libdir + 'array-compare.js');
|
||||
|
||||
var obj = {};
|
||||
|
||||
function strictNestedAssignShadowCatchCall(p)
|
||||
{
|
||||
"use strict";
|
||||
function inner()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (p)
|
||||
{
|
||||
var f = function innermost() { p = 1776; return 12; };
|
||||
f();
|
||||
}
|
||||
}
|
||||
inner();
|
||||
return arguments;
|
||||
}
|
||||
|
||||
var a1, a2, a3, a4;
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
a1 = strictNestedAssignShadowCatchCall();
|
||||
a2 = strictNestedAssignShadowCatchCall(99);
|
||||
a3 = strictNestedAssignShadowCatchCall("");
|
||||
a4 = strictNestedAssignShadowCatchCall(obj);
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(a1, []), true);
|
||||
assertEq(arraysEqual(a2, [99]), true);
|
||||
assertEq(arraysEqual(a3, [""]), true);
|
||||
assertEq(arraysEqual(a4, [obj]), true);
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user