[JAEGER] Merge for manual backout.

This commit is contained in:
David Mandelin 2010-08-18 12:24:47 -07:00
commit 7b3b9d1f90
120 changed files with 3632 additions and 1194 deletions

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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

View File

@ -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());

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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]}');

View File

@ -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)

View 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>

View 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>

View File

@ -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
###############################################

View File

@ -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);
}
}
}

View File

@ -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);

View File

@ -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

View File

@ -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)
;;

View File

@ -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")

View File

@ -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);
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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 */

View File

@ -340,6 +340,7 @@ struct JSAtomState
JSAtom *ignoreCaseAtom;
JSAtom *indexAtom;
JSAtom *inputAtom;
JSAtom *toISOStringAtom;
JSAtom *iteratorAtom;
JSAtom *joinAtom;
JSAtom *lastIndexAtom;

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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();
}
/*

View File

@ -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;

View File

@ -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
View 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___ */

View File

@ -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);

View File

@ -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 */

View File

@ -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];

View File

@ -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;

View File

@ -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;

View File

@ -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
{

View File

@ -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()) {

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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 */

View File

@ -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) {

View File

@ -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;
}

View File

@ -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);

View File

@ -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));

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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 *)&ltime,0,sizeof(ltime));
ltime.tm_mday = 2;
ltime.tm_year = 70;
return (JSInt32)mktime(&ltime) - (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);

View File

@ -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;

View File

@ -1,2 +1,3 @@
url-prefix ../../jsreftest.html?test=ecma_5/Date/
script 15.9.4.2.js
script toJSON-01.js

View 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!");

View File

@ -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()
{

View File

@ -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

View File

@ -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);

View 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!");

View 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!");

View 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!");

View File

@ -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

View 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!");

View File

@ -1,2 +1,3 @@
url-prefix ../../jsreftest.html?test=ecma_5/JSON/
script cyclic-stringify.js
script stringify-gap.js

View 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!");

View File

@ -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 =

View File

@ -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);

View File

@ -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)),

View File

@ -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');
}

View File

@ -55,7 +55,7 @@ function test()
try
{
expect = 'undefined';
var a = { set x() {} };
var a = { set x(v) {} };
actual = a.x + '';
}
catch(ex)

View File

@ -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 + '';

View File

@ -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;

View File

@ -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;

View File

@ -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');

View 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);

View File

@ -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

View 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;
}

View File

@ -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);

View 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);

View File

@ -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);

View File

@ -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);

View 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);

View 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);

View 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);

View 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);

View 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);

View 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 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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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);

View 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);

View 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);

View 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);

View 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 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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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