зеркало из https://github.com/mozilla/pjs.git
Merge tracemonkey to mozilla-central. (a=blockers)
This commit is contained in:
Коммит
c228dde80b
|
@ -354,6 +354,7 @@ user_pref("browser.EULA.override", true);
|
|||
user_pref("javascript.options.tracejit.content", true);
|
||||
user_pref("javascript.options.methodjit.content", true);
|
||||
user_pref("javascript.options.jitprofiling.content", true);
|
||||
user_pref("javascript.options.methodjit_always", false);
|
||||
user_pref("gfx.color_management.force_srgb", true);
|
||||
user_pref("network.manage-offline-status", false);
|
||||
user_pref("test.mousescroll", true);
|
||||
|
|
|
@ -1015,10 +1015,11 @@ static const char js_zeal_option_str[] = JS_OPTIONS_DOT_STR "gczeal";
|
|||
#endif
|
||||
static const char js_tracejit_content_str[] = JS_OPTIONS_DOT_STR "tracejit.content";
|
||||
static const char js_tracejit_chrome_str[] = JS_OPTIONS_DOT_STR "tracejit.chrome";
|
||||
static const char js_methodjit_content_str[] = JS_OPTIONS_DOT_STR "methodjit.content";
|
||||
static const char js_methodjit_chrome_str[] = JS_OPTIONS_DOT_STR "methodjit.chrome";
|
||||
static const char js_profiling_content_str[] = JS_OPTIONS_DOT_STR "jitprofiling.content";
|
||||
static const char js_profiling_chrome_str[] = JS_OPTIONS_DOT_STR "jitprofiling.chrome";
|
||||
static const char js_methodjit_content_str[] = JS_OPTIONS_DOT_STR "methodjit.content";
|
||||
static const char js_methodjit_chrome_str[] = JS_OPTIONS_DOT_STR "methodjit.chrome";
|
||||
static const char js_profiling_content_str[] = JS_OPTIONS_DOT_STR "jitprofiling.content";
|
||||
static const char js_profiling_chrome_str[] = JS_OPTIONS_DOT_STR "jitprofiling.chrome";
|
||||
static const char js_methodjit_always_str[] = JS_OPTIONS_DOT_STR "methodjit_always";
|
||||
|
||||
int
|
||||
nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
|
||||
|
@ -1047,6 +1048,7 @@ nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
|
|||
PRBool useProfiling = nsContentUtils::GetBoolPref(chromeWindow ?
|
||||
js_profiling_chrome_str :
|
||||
js_profiling_content_str);
|
||||
PRBool useMethodJITAlways = nsContentUtils::GetBoolPref(js_methodjit_always_str);
|
||||
nsCOMPtr<nsIXULRuntime> xr = do_GetService(XULRUNTIME_SERVICE_CONTRACTID);
|
||||
if (xr) {
|
||||
PRBool safeMode = PR_FALSE;
|
||||
|
@ -1055,6 +1057,7 @@ nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
|
|||
useTraceJIT = PR_FALSE;
|
||||
useMethodJIT = PR_FALSE;
|
||||
useProfiling = PR_FALSE;
|
||||
useMethodJITAlways = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1073,6 +1076,11 @@ nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
|
|||
else
|
||||
newDefaultJSOptions &= ~JSOPTION_PROFILING;
|
||||
|
||||
if (useMethodJITAlways)
|
||||
newDefaultJSOptions |= JSOPTION_METHODJIT_ALWAYS;
|
||||
else
|
||||
newDefaultJSOptions &= ~JSOPTION_METHODJIT_ALWAYS;
|
||||
|
||||
#ifdef DEBUG
|
||||
// In debug builds, warnings are enabled in chrome context if
|
||||
// javascript.options.strict.debug is true
|
||||
|
|
|
@ -2580,7 +2580,12 @@ jsdService::ActivateDebugger (JSRuntime *rt)
|
|||
return rv;
|
||||
|
||||
xpc->InitClasses (cx, glob);
|
||||
|
||||
|
||||
/* Start watching for script creation/destruction and manage jsdScript
|
||||
* objects accordingly
|
||||
*/
|
||||
JSD_SetScriptHook (mCx, jsds_ScriptHookProc, NULL);
|
||||
|
||||
/* If any of these mFooHook objects are installed, do the required JSD
|
||||
* hookup now. See also, jsdService::SetFooHook().
|
||||
*/
|
||||
|
|
|
@ -54,7 +54,7 @@ class Test:
|
|||
|
||||
def copy(self):
|
||||
t = Test(self.path)
|
||||
t.jitflags = self.jitflags
|
||||
t.jitflags = self.jitflags[:]
|
||||
t.slow = self.slow
|
||||
t.allow_oom = self.allow_oom
|
||||
t.valgrind = self.valgrind
|
||||
|
@ -93,6 +93,8 @@ class Test:
|
|||
test.allow_oom = True
|
||||
elif name == 'valgrind':
|
||||
test.valgrind = options.valgrind
|
||||
elif name == 'mjitalways':
|
||||
test.jitflags.append('-a')
|
||||
else:
|
||||
print('warning: unrecognized |jit-test| attribute %s'%part)
|
||||
|
||||
|
@ -426,7 +428,7 @@ def main(argv):
|
|||
for test in test_list:
|
||||
for jitflags in jitflags_list:
|
||||
new_test = test.copy()
|
||||
new_test.jitflags = jitflags
|
||||
new_test.jitflags.extend(jitflags)
|
||||
job_list.append(new_test)
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
var N = HOTLOOP + 2;
|
||||
function f(b) {
|
||||
var a = [];
|
||||
for (var i = 0; i < N; i++)
|
||||
a[i] = {};
|
||||
a[N-1] = arguments;
|
||||
for (var i = 0; i < N; i++)
|
||||
a[i][0] = i;
|
||||
assertEq(b, N - 1);
|
||||
}
|
||||
f(null);
|
|
@ -0,0 +1,6 @@
|
|||
Object.defineProperty(Function.prototype, "prototype", {set:function(){}});
|
||||
var x;
|
||||
for (var i = 0; i < HOTLOOP + 2; i++)
|
||||
x = new Function.prototype;
|
||||
assertEq(toString.call(x), "[object Object]");
|
||||
assertEq(Object.getPrototypeOf(x), Object.prototype);
|
|
@ -0,0 +1,6 @@
|
|||
Function.prototype.prototype = function () {};
|
||||
var x;
|
||||
for (var i = 0; i < HOTLOOP + 2; i++)
|
||||
x = new Function.prototype;
|
||||
assertEq(toString.call(x), "[object Object]");
|
||||
assertEq(Object.getPrototypeOf(x), Function.prototype.prototype);
|
|
@ -0,0 +1,12 @@
|
|||
var a = [];
|
||||
function next() {
|
||||
var x = {};
|
||||
a.push(x);
|
||||
return x;
|
||||
}
|
||||
Object.defineProperty(Function.prototype, 'prototype', {get: next});
|
||||
var b = [];
|
||||
for (var i = 0; i < HOTLOOP + 2; i++)
|
||||
b[i] = new Function.prototype;
|
||||
for (var i = 0; i < HOTLOOP + 2; i++)
|
||||
assertEq(Object.getPrototypeOf(b[i]), a[i]);
|
|
@ -0,0 +1,10 @@
|
|||
Object.defineProperty(Function.prototype, 'prototype',
|
||||
{get: function () { if (i == HOTLOOP + 1) throw "X"; }});
|
||||
var x;
|
||||
try {
|
||||
for (var i = 0; i < HOTLOOP + 2; i++)
|
||||
x = new Function.prototype;
|
||||
} catch (exc) {
|
||||
assertEq(i, HOTLOOP + 1);
|
||||
assertEq(exc, "X");
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
function C(a, b) {
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
}
|
||||
var f = C.bind(null, 2);
|
||||
Object.defineProperty(f, "prototype", {get: function () { throw "FAIL"; }});
|
||||
var x;
|
||||
for (var i = 0; i < HOTLOOP + 2; i++)
|
||||
x = new f(i);
|
||||
assertEq(toString.call(x), "[object Object]");
|
||||
assertEq(Object.getPrototypeOf(x), C.prototype);
|
||||
assertEq(x.a, 2);
|
||||
assertEq(x.b, HOTLOOP + 1);
|
|
@ -0,0 +1,11 @@
|
|||
var a = [];
|
||||
var x, i;
|
||||
for (i = 0; i < HOTLOOP + 10; i++) {
|
||||
a[i] = function (b) { this.b = b; };
|
||||
if (i != HOTLOOP + 9)
|
||||
x = a[i].prototype;
|
||||
}
|
||||
for (i = 0; i < HOTLOOP + 10; i++)
|
||||
x = new a[i];
|
||||
assertEq(toString.call(x), "[object Object]");
|
||||
assertEq(Object.getPrototypeOf(x), a[HOTLOOP + 9].prototype);
|
|
@ -0,0 +1,9 @@
|
|||
var n = 0;
|
||||
var a = [];
|
||||
for (var i = 0; i < 20; i++)
|
||||
a[i] = {};
|
||||
a[18].watch("p", function () { n++; });
|
||||
delete a[18].p;
|
||||
for (var i = 0; i < 20; i++)
|
||||
a[i].p = 0;
|
||||
assertEq(n, 1);
|
|
@ -0,0 +1,13 @@
|
|||
// vim: set ts=4 sw=4 tw=99 et:
|
||||
x = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6 };
|
||||
|
||||
for (i in x)
|
||||
delete x.d;
|
||||
|
||||
x = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6 };
|
||||
y = [];
|
||||
for (i in x)
|
||||
y.push(i)
|
||||
|
||||
assertEq(y[3], "d");
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// vim: set ts=4 sw=4 tw=99 et:
|
||||
|
||||
var o1 = {p1: 1};
|
||||
var o2 = {p1: 1, p2: 2};
|
||||
|
||||
for(var x in o1) {
|
||||
for(var y in o2) {
|
||||
delete o2.p2;
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't fail cx->enumerators == obj assert, see bug comment #31 */
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
var BUGNUMBER = '';
|
||||
function printBugNumber (num)
|
||||
{
|
||||
return "foo";
|
||||
}
|
||||
function optionsClear() {
|
||||
var x = printBugNumber().split(',');
|
||||
}
|
||||
function optionsReset() {
|
||||
optionsClear();
|
||||
}
|
||||
var code = new Array();
|
||||
code.push("evaluate");
|
||||
var x0 = "\
|
||||
printBugNumber(BUGNUMBER);\n\
|
||||
function gen()\n\
|
||||
{\n\
|
||||
try {\n\
|
||||
yield 0;\n\
|
||||
} finally {\n\
|
||||
}\n\
|
||||
}\n\
|
||||
var iter1 = gen( iter1=\"NaN\", new gen(gen)) ;\n\
|
||||
gc();\n\
|
||||
";
|
||||
code.push(x0);
|
||||
code.push("evaluate");
|
||||
var files = new Array();
|
||||
while (true) {
|
||||
var file = code.shift();
|
||||
if (file == "evaluate") {
|
||||
loadFiles(files);
|
||||
} else if (file == undefined) {
|
||||
break;
|
||||
} else {
|
||||
files.push(file);
|
||||
}
|
||||
}
|
||||
function loadFiles(x) {
|
||||
for (i in x) {
|
||||
try {
|
||||
eval(x[i]);
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
optionsReset();
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
function f(a, b) {
|
||||
this.a = a;
|
||||
assertEq(b, 'x');
|
||||
}
|
||||
|
||||
for (var x = 0; x < RUNLOOP; ++x) {
|
||||
f.prototype = {};
|
||||
var obj = new f(x, 'x');
|
||||
assertEq(obj.a, x);
|
||||
assertEq(Object.getPrototypeOf(obj), f.prototype);
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
function f(a, b, c) {
|
||||
this.a = a;
|
||||
assertEq(b, 'x');
|
||||
assertEq(c, void 0);
|
||||
}
|
||||
|
||||
for (var x = 0; x < RUNLOOP; ++x) {
|
||||
f.prototype = {};
|
||||
var obj = new f(x, 'x'); // fewer than f.length arguments
|
||||
assertEq(obj.a, x);
|
||||
assertEq(Object.getPrototypeOf(obj), f.prototype);
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
function f(a) {
|
||||
this.a = a;
|
||||
assertEq(arguments[1], 'x');
|
||||
}
|
||||
|
||||
for (var x = 0; x < RUNLOOP; ++x) {
|
||||
f.prototype = {};
|
||||
var obj = new f(x, 'x'); // more than f.length arguments
|
||||
assertEq(obj.a, x);
|
||||
assertEq(Object.getPrototypeOf(obj), f.prototype);
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
// |jit-test| mjitalways
|
||||
setDebug(true);
|
||||
|
||||
function callee() {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// |jit-test| mjitalways
|
||||
setDebug(true);
|
||||
|
||||
function callee() {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// |jit-test| mjitalways
|
||||
setDebug(true);
|
||||
|
||||
function callee() {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// |jit-test| mjitalways
|
||||
setDebug(true);
|
||||
|
||||
this.__defineGetter__("someProperty", function () { evalInFrame(1, "var x = 'success'"); });
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// |jit-test| mjitalways
|
||||
setDebug(true);
|
||||
|
||||
this.__defineGetter__("someProperty", function () { evalInFrame(1, "var x = 'success'"); });
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// |jit-test| mjitalways
|
||||
setDebug(true);
|
||||
|
||||
this.__defineGetter__("someProperty", function () { evalInFrame(1, "x = 'success'"); });
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// |jit-test| mjitalways
|
||||
setDebug(true);
|
||||
|
||||
function nop(){}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// |jit-test| mjitalways
|
||||
setDebug(true);
|
||||
|
||||
function nop(){}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// |jit-test| mjitalways
|
||||
setDebug(true);
|
||||
|
||||
function nop(){}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
var o = {};
|
||||
for(var i=0; i<5; i++) {
|
||||
o.p = 2;
|
||||
o.watch("p", function() { });
|
||||
o.p = 2;
|
||||
delete o.p;
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
// |jit-test| mjitalways
|
||||
// vim: set ts=4 sw=4 tw=99 et:
|
||||
|
||||
function assertObjectsEqual(obj1, obj2) {
|
||||
|
|
|
@ -955,11 +955,14 @@ JS_StringToVersion(const char *string);
|
|||
|
||||
#define JSOPTION_METHODJIT JS_BIT(14) /* Whole-method JIT. */
|
||||
#define JSOPTION_PROFILING JS_BIT(15) /* Profiler to make tracer/methodjit choices. */
|
||||
#define JSOPTION_METHODJIT_ALWAYS \
|
||||
JS_BIT(16) /* Always whole-method JIT,
|
||||
don't tune at run-time. */
|
||||
|
||||
/* Options which reflect compile-time properties of scripts. */
|
||||
#define JSCOMPILEOPTION_MASK (JSOPTION_XML | JSOPTION_ANONFUNFIX)
|
||||
|
||||
#define JSRUNOPTION_MASK (JS_BITMASK(16) & ~JSCOMPILEOPTION_MASK)
|
||||
#define JSRUNOPTION_MASK (JS_BITMASK(17) & ~JSCOMPILEOPTION_MASK)
|
||||
#define JSALLOPTION_MASK (JSCOMPILEOPTION_MASK | JSRUNOPTION_MASK)
|
||||
|
||||
extern JS_PUBLIC_API(uint32)
|
||||
|
|
|
@ -188,8 +188,8 @@ struct ClosureVarInfo;
|
|||
#define _JS_CTYPE_THIS _JS_CTYPE(JSObject *, _JS_PTR,"T", "", INFALLIBLE)
|
||||
#define _JS_CTYPE_THIS_DOUBLE _JS_CTYPE(jsdouble, _JS_F64,"D", "", INFALLIBLE)
|
||||
#define _JS_CTYPE_THIS_STRING _JS_CTYPE(JSString *, _JS_PTR,"S", "", INFALLIBLE)
|
||||
#define _JS_CTYPE_CALLEE _JS_CTYPE(JSObject *, _JS_PTR,"f","", INFALLIBLE)
|
||||
#define _JS_CTYPE_CALLEE_PROTOTYPE _JS_CTYPE(JSObject *, _JS_PTR,"p","", INFALLIBLE)
|
||||
#define _JS_CTYPE_CALLEE _JS_CTYPE(JSObject *, _JS_PTR,"f", "", INFALLIBLE)
|
||||
#define _JS_CTYPE_CALLEE_PROTOTYPE _JS_CTYPE(JSObject *, _JS_PTR,"p", "", INFALLIBLE)
|
||||
#define _JS_CTYPE_FUNCTION _JS_CTYPE(JSFunction *, _JS_PTR, --, --, INFALLIBLE)
|
||||
#define _JS_CTYPE_PC _JS_CTYPE(jsbytecode *, _JS_PTR,"P", "", INFALLIBLE)
|
||||
#define _JS_CTYPE_VALUEPTR _JS_CTYPE(js::Value *, _JS_PTR, --, --, INFALLIBLE)
|
||||
|
@ -233,7 +233,8 @@ struct ClosureVarInfo;
|
|||
#define _JS_CTYPE_CVIPTR _JS_CTYPE(const ClosureVarInfo *, _JS_PTR, --, --, INFALLIBLE)
|
||||
#define _JS_CTYPE_FRAMEINFO _JS_CTYPE(FrameInfo *, _JS_PTR, --, --, INFALLIBLE)
|
||||
#define _JS_CTYPE_PICTABLE _JS_CTYPE(PICTable *, _JS_PTR, --, --, INFALLIBLE)
|
||||
|
||||
#define _JS_CTYPE_UINTN _JS_CTYPE(uintN, _JS_PTR, --, --, INFALLIBLE)
|
||||
|
||||
/*
|
||||
* The "VALUE" type is used to indicate that a native takes a js::Value
|
||||
* parameter by value. Unfortunately, for technical reasons, we can't simply
|
||||
|
|
|
@ -327,7 +327,11 @@ StackSpace::getCallFrame(JSContext *cx, Value *firstUnused, uintN nactual,
|
|||
uintN ncopy = 2 + nformal;
|
||||
if (JS_UNLIKELY(!check(*this, cx, firstUnused, ncopy + nvals)))
|
||||
return NULL;
|
||||
memcpy(firstUnused, firstUnused - (2 + nactual), ncopy * sizeof(Value));
|
||||
|
||||
Value *dst = firstUnused;
|
||||
Value *src = firstUnused - (2 + nactual);
|
||||
PodCopy(dst, src, ncopy);
|
||||
Debug_SetValueRangeToCrashOnTouch(src, ncopy);
|
||||
return reinterpret_cast<JSStackFrame *>(firstUnused + ncopy);
|
||||
}
|
||||
|
||||
|
|
|
@ -53,6 +53,10 @@
|
|||
|
||||
#include "jsgcinlines.h"
|
||||
|
||||
#if ENABLE_YARR_JIT
|
||||
#include "assembler/jit/ExecutableAllocator.h"
|
||||
#endif
|
||||
|
||||
using namespace js;
|
||||
using namespace js::gc;
|
||||
|
||||
|
@ -151,10 +155,12 @@ JSCompartment::init()
|
|||
return false;
|
||||
#endif
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
if (!(jaegerCompartment = js_new<mjit::JaegerCompartment>())) {
|
||||
if (!backEdgeTable.init())
|
||||
return false;
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
if (!(jaegerCompartment = js_new<mjit::JaegerCompartment>()))
|
||||
return false;
|
||||
}
|
||||
return jaegerCompartment->Initialize();
|
||||
#else
|
||||
return true;
|
||||
|
@ -174,7 +180,8 @@ JSCompartment::arenaListsAreEmpty()
|
|||
static bool
|
||||
IsCrossCompartmentWrapper(JSObject *wrapper)
|
||||
{
|
||||
return !!(JSWrapper::wrapperHandler(wrapper)->flags() & JSWrapper::CROSS_COMPARTMENT);
|
||||
return wrapper->isWrapper() &&
|
||||
!!(JSWrapper::wrapperHandler(wrapper)->flags() & JSWrapper::CROSS_COMPARTMENT);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -584,3 +591,25 @@ JSCompartment::allocMathCache(JSContext *cx)
|
|||
js_ReportOutOfMemory(cx);
|
||||
return mathCache;
|
||||
}
|
||||
|
||||
size_t
|
||||
JSCompartment::backEdgeCount(jsbytecode *pc) const
|
||||
{
|
||||
if (BackEdgeMap::Ptr p = backEdgeTable.lookup(pc))
|
||||
return p->value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
JSCompartment::incBackEdgeCount(jsbytecode *pc)
|
||||
{
|
||||
if (BackEdgeMap::AddPtr p = backEdgeTable.lookupForAdd(pc)) {
|
||||
p->value++;
|
||||
return p->value;
|
||||
} else {
|
||||
backEdgeTable.add(p, pc, 1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -482,6 +482,13 @@ struct JS_FRIEND_API(JSCompartment) {
|
|||
|
||||
bool marked;
|
||||
|
||||
typedef js::HashMap<jsbytecode*,
|
||||
size_t,
|
||||
js::DefaultHasher<jsbytecode*>,
|
||||
js::SystemAllocPolicy> BackEdgeMap;
|
||||
|
||||
BackEdgeMap backEdgeTable;
|
||||
|
||||
public:
|
||||
js::MathCache *getMathCache(JSContext *cx) {
|
||||
return mathCache ? mathCache : allocMathCache(cx);
|
||||
|
@ -489,6 +496,9 @@ struct JS_FRIEND_API(JSCompartment) {
|
|||
|
||||
bool isMarked() { return marked; }
|
||||
void clearMark() { marked = false; }
|
||||
|
||||
size_t backEdgeCount(jsbytecode *pc) const;
|
||||
size_t incBackEdgeCount(jsbytecode *pc);
|
||||
};
|
||||
|
||||
#define JS_SCRIPTS_TO_GC(cx) ((cx)->compartment->scriptsToGC)
|
||||
|
|
|
@ -565,7 +565,7 @@ JS_ClearInterrupt(JSRuntime *rt, JSInterruptHook *hoop, void **closurep)
|
|||
|
||||
struct JSWatchPoint {
|
||||
JSCList links;
|
||||
JSObject *object; /* weak link, see js_FinalizeObject */
|
||||
JSObject *object; /* weak link, see js_SweepWatchPoints */
|
||||
const Shape *shape;
|
||||
StrictPropertyOp setter;
|
||||
JSWatchPointHandler handler;
|
||||
|
@ -711,45 +711,110 @@ js_watch_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
|||
&wp->links != &rt->watchPointList;
|
||||
wp = (JSWatchPoint *)wp->links.next) {
|
||||
const Shape *shape = wp->shape;
|
||||
if (wp->object == obj && SHAPE_USERID(shape) == id &&
|
||||
!(wp->flags & JSWP_HELD)) {
|
||||
if (wp->object == obj && SHAPE_USERID(shape) == id && !(wp->flags & JSWP_HELD)) {
|
||||
wp->flags |= JSWP_HELD;
|
||||
DBG_UNLOCK(rt);
|
||||
|
||||
jsid propid = shape->id;
|
||||
shape = obj->nativeLookup(propid);
|
||||
JS_ASSERT(IsWatchedProperty(cx, shape));
|
||||
jsid userid = SHAPE_USERID(shape);
|
||||
|
||||
/* NB: wp is held, so we can safely dereference it still. */
|
||||
if (!wp->handler(cx, obj, propid,
|
||||
obj->containsSlot(shape->slot)
|
||||
? Jsvalify(obj->nativeGetSlot(shape->slot))
|
||||
: JSVAL_VOID,
|
||||
Jsvalify(vp), wp->closure)) {
|
||||
DBG_LOCK(rt);
|
||||
DropWatchPointAndUnlock(cx, wp, JSWP_HELD);
|
||||
return JS_FALSE;
|
||||
/* Determine the property's old value. */
|
||||
bool ok;
|
||||
uint32 slot = shape->slot;
|
||||
Value old = obj->containsSlot(slot) ? obj->nativeGetSlot(slot) : UndefinedValue();
|
||||
const Shape *needMethodSlotWrite = NULL;
|
||||
if (shape->isMethod()) {
|
||||
/*
|
||||
* We get here in two cases: (1) the existing watched property
|
||||
* is a method; or (2) the watched property was deleted and is
|
||||
* now in the middle of being re-added via JSOP_SETMETHOD. In
|
||||
* both cases we must trip the method read barrier in order to
|
||||
* avoid passing an uncloned function object to the handler.
|
||||
*
|
||||
* Case 2 is especially hairy. js_watch_set, uniquely, gets
|
||||
* called in the middle of creating a method property, after
|
||||
* shape is in obj but before the slot has been set. So in this
|
||||
* case we must finish initializing the half-finished method
|
||||
* property before triggering the method read barrier.
|
||||
*
|
||||
* Bonus weirdness: because this changes obj's shape,
|
||||
* js_NativeSet (which is our caller) will not write to the
|
||||
* slot, as it will appear the property was deleted and a new
|
||||
* property added. We must write the slot ourselves -- however
|
||||
* we must do it after calling the watchpoint handler. So set
|
||||
* needMethodSlotWrite here and use it to write to the slot
|
||||
* below, if the handler does not tinker with the property
|
||||
* further.
|
||||
*/
|
||||
JS_ASSERT(!wp->setter);
|
||||
Value method = ObjectValue(shape->methodObject());
|
||||
if (old.isUndefined())
|
||||
obj->nativeSetSlot(slot, method);
|
||||
ok = obj->methodReadBarrier(cx, *shape, &method);
|
||||
if (!ok)
|
||||
goto out;
|
||||
wp->shape = shape = needMethodSlotWrite = obj->nativeLookup(propid);
|
||||
JS_ASSERT(shape->isDataDescriptor());
|
||||
JS_ASSERT(!shape->isMethod());
|
||||
if (old.isUndefined())
|
||||
obj->nativeSetSlot(shape->slot, old);
|
||||
else
|
||||
old = method;
|
||||
}
|
||||
|
||||
/* Handler could have redefined the shape; see bug 624050. */
|
||||
shape = wp->shape;
|
||||
{
|
||||
Conditionally<AutoShapeRooter> tvr(needMethodSlotWrite, cx, needMethodSlotWrite);
|
||||
|
||||
/*
|
||||
* Pass the output of the handler to the setter. Security wrappers
|
||||
* prevent any funny business between watchpoints and setters.
|
||||
*/
|
||||
JSBool ok = !wp->setter ||
|
||||
(shape->hasSetterValue()
|
||||
/*
|
||||
* Call the handler. This invalidates shape, so re-lookup the shape.
|
||||
* NB: wp is held, so we can safely dereference it still.
|
||||
*/
|
||||
ok = wp->handler(cx, obj, propid, Jsvalify(old), Jsvalify(vp), wp->closure);
|
||||
if (!ok)
|
||||
goto out;
|
||||
shape = obj->nativeLookup(propid);
|
||||
JS_ASSERT_IF(!shape, !wp->setter);
|
||||
|
||||
if (!shape) {
|
||||
ok = true;
|
||||
} else if (wp->setter) {
|
||||
/*
|
||||
* Pass the output of the handler to the setter. Security wrappers
|
||||
* prevent any funny business between watchpoints and setters.
|
||||
*/
|
||||
ok = shape->hasSetterValue()
|
||||
? ExternalInvoke(cx, ObjectValue(*obj),
|
||||
ObjectValue(*CastAsObject(wp->setter)),
|
||||
1, vp, vp)
|
||||
: CallJSPropertyOpSetter(cx, wp->setter, obj, userid, strict, vp));
|
||||
: CallJSPropertyOpSetter(cx, wp->setter, obj, userid, strict, vp);
|
||||
} else if (shape == needMethodSlotWrite) {
|
||||
/* See comment above about needMethodSlotWrite. */
|
||||
obj->nativeSetSlot(shape->slot, *vp);
|
||||
ok = true;
|
||||
} else {
|
||||
/*
|
||||
* A property with the default setter might be either a method
|
||||
* or an ordinary function-valued data property subject to the
|
||||
* method write barrier.
|
||||
*
|
||||
* It is not the setter's job to call methodWriteBarrier,
|
||||
* but js_watch_set must do so, because the caller will be
|
||||
* fooled into not doing it: shape does *not* have the
|
||||
* default setter and therefore seems not to be a method.
|
||||
*/
|
||||
ok = obj->methodWriteBarrier(cx, *shape, *vp) != NULL;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
DBG_LOCK(rt);
|
||||
return DropWatchPointAndUnlock(cx, wp, JSWP_HELD) && ok;
|
||||
}
|
||||
}
|
||||
DBG_UNLOCK(rt);
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
|
@ -825,23 +890,23 @@ WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, StrictPropertyOp setter)
|
|||
return CastAsStrictPropertyOp(FUN_OBJECT(wrapper));
|
||||
}
|
||||
|
||||
static bool
|
||||
UpdateWatchpointShape(JSContext *cx, JSWatchPoint *wp, const js::Shape *newShape)
|
||||
static const Shape *
|
||||
UpdateWatchpointShape(JSContext *cx, JSWatchPoint *wp, const Shape *newShape)
|
||||
{
|
||||
JS_ASSERT_IF(wp->shape, wp->shape->id == newShape->id);
|
||||
JS_ASSERT(!IsWatchedProperty(cx, newShape));
|
||||
|
||||
/* Create a watching setter we can substitute for the new shape's setter. */
|
||||
js::StrictPropertyOp watchingSetter =
|
||||
StrictPropertyOp watchingSetter =
|
||||
WrapWatchedSetter(cx, newShape->id, newShape->attributes(), newShape->setter());
|
||||
if (!watchingSetter)
|
||||
return false;
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Save the shape's setter; we don't know whether js_ChangeNativePropertyAttrs will
|
||||
* return a new shape, or mutate this one.
|
||||
*/
|
||||
js::StrictPropertyOp originalSetter = newShape->setter();
|
||||
StrictPropertyOp originalSetter = newShape->setter();
|
||||
|
||||
/*
|
||||
* Drop the watching setter into the object, in place of newShape. Note that a single
|
||||
|
@ -849,21 +914,21 @@ UpdateWatchpointShape(JSContext *cx, JSWatchPoint *wp, const js::Shape *newShape
|
|||
* wrap all (JSPropertyOp, not JSObject *) setters with js_watch_set, so shapes that
|
||||
* differ only in their setter may all get wrapped to the same shape.
|
||||
*/
|
||||
const js::Shape *watchingShape =
|
||||
const Shape *watchingShape =
|
||||
js_ChangeNativePropertyAttrs(cx, wp->object, newShape, 0, newShape->attributes(),
|
||||
newShape->getter(), watchingSetter);
|
||||
if (!watchingShape)
|
||||
return false;
|
||||
return NULL;
|
||||
|
||||
/* Update the watchpoint with the new shape and its original setter. */
|
||||
wp->setter = originalSetter;
|
||||
wp->shape = watchingShape;
|
||||
|
||||
return true;
|
||||
return watchingShape;
|
||||
}
|
||||
|
||||
bool
|
||||
js_SlowPathUpdateWatchpointsForShape(JSContext *cx, JSObject *obj, const js::Shape *newShape)
|
||||
const Shape *
|
||||
js_SlowPathUpdateWatchpointsForShape(JSContext *cx, JSObject *obj, const Shape *newShape)
|
||||
{
|
||||
/*
|
||||
* The watchpoint code uses the normal property-modification functions to install its
|
||||
|
@ -873,11 +938,11 @@ js_SlowPathUpdateWatchpointsForShape(JSContext *cx, JSObject *obj, const js::Sha
|
|||
* proceed without interference.
|
||||
*/
|
||||
if (IsWatchedProperty(cx, newShape))
|
||||
return true;
|
||||
return newShape;
|
||||
|
||||
JSWatchPoint *wp = FindWatchPoint(cx->runtime, obj, newShape->id);
|
||||
if (!wp)
|
||||
return true;
|
||||
return newShape;
|
||||
|
||||
return UpdateWatchpointShape(cx, wp, newShape);
|
||||
}
|
||||
|
@ -1034,6 +1099,13 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsid id,
|
|||
JS_APPEND_LINK(&wp->links, &rt->watchPointList);
|
||||
++rt->debuggerMutations;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure that an object with watchpoints never has the same shape as an
|
||||
* object without them, even if the watched properties are deleted.
|
||||
*/
|
||||
obj->watchpointOwnShapeChange(cx);
|
||||
|
||||
wp->handler = handler;
|
||||
wp->closure = reinterpret_cast<JSObject*>(closure);
|
||||
DBG_UNLOCK(rt);
|
||||
|
|
|
@ -46,19 +46,19 @@
|
|||
|
||||
#if defined(JS_HAS_OBJ_WATCHPOINT) && defined(__cplusplus)
|
||||
|
||||
extern bool
|
||||
extern const js::Shape *
|
||||
js_SlowPathUpdateWatchpointsForShape(JSContext *cx, JSObject *obj, const js::Shape *newShape);
|
||||
|
||||
/*
|
||||
* Update any watchpoints on |obj| on |new_shape->id| to use |new_shape|. Property-manipulating
|
||||
* Update any watchpoints on |obj| on |newShape->id| to use |newShape|. Property-manipulating
|
||||
* functions must call this any time it takes on a new shape to represent a potentially
|
||||
* watched property, or when it mutates a shape's attributes/setter/getter.
|
||||
*/
|
||||
static inline bool
|
||||
static inline const js::Shape *
|
||||
js_UpdateWatchpointsForShape(JSContext *cx, JSObject *obj, const js::Shape *newShape)
|
||||
{
|
||||
if (JS_CLIST_IS_EMPTY(&cx->runtime->watchPointList))
|
||||
return true;
|
||||
return newShape;
|
||||
|
||||
return js_SlowPathUpdateWatchpointsForShape(cx, obj, newShape);
|
||||
}
|
||||
|
|
|
@ -554,10 +554,7 @@ ArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
|||
// sure any updates also get written back to the trace native stack.
|
||||
// For simplicity, we just leave trace, since this is presumably not
|
||||
// a common operation.
|
||||
if (JS_ON_TRACE(cx)) {
|
||||
DeepBail(cx);
|
||||
return false;
|
||||
}
|
||||
LeaveTrace(cx);
|
||||
#endif
|
||||
|
||||
if (!InstanceOf(cx, obj, &js_ArgumentsClass, NULL))
|
||||
|
@ -1707,6 +1704,46 @@ fun_enumerate(JSContext *cx, JSObject *obj)
|
|||
return true;
|
||||
}
|
||||
|
||||
static JSObject *
|
||||
ResolveInterpretedFunctionPrototype(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
JSFunction *fun = obj->getFunctionPrivate();
|
||||
JS_ASSERT(fun->isInterpreted());
|
||||
JS_ASSERT(!fun->isFunctionPrototype());
|
||||
|
||||
/*
|
||||
* Assert that fun is not a compiler-created function object, which
|
||||
* must never leak to script or embedding code and then be mutated.
|
||||
* Also assert that obj is not bound, per the ES5 15.3.4.5 ref above.
|
||||
*/
|
||||
JS_ASSERT(!IsInternalFunctionObject(obj));
|
||||
JS_ASSERT(!obj->isBoundFunction());
|
||||
|
||||
/*
|
||||
* Make the prototype object an instance of Object with the same parent
|
||||
* as the function object itself.
|
||||
*/
|
||||
JSObject *parent = obj->getParent();
|
||||
JSObject *proto;
|
||||
if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
|
||||
return NULL;
|
||||
proto = NewNativeClassInstance(cx, &js_ObjectClass, proto, parent);
|
||||
if (!proto)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* ECMA (15.3.5.2) says that a user-defined function's .prototype property
|
||||
* is non-configurable, non-enumerable, and (initially) writable. Hence
|
||||
* JSPROP_PERMANENT below. By contrast, the built-in constructors, such as
|
||||
* Object (15.2.3.1) and Function (15.3.3.1), have non-writable
|
||||
* .prototype properties. Those are eagerly defined, with attributes
|
||||
* JSPROP_PERMANENT | JSPROP_READONLY, in js_InitClass.
|
||||
*/
|
||||
if (!js_SetClassPrototype(cx, obj, proto, JSPROP_PERMANENT))
|
||||
return NULL;
|
||||
return proto;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
fun_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
||||
JSObject **objp)
|
||||
|
@ -1733,36 +1770,8 @@ fun_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
|||
if (fun->isNative() || fun->isFunctionPrototype())
|
||||
return true;
|
||||
|
||||
/*
|
||||
* Assert that fun is not a compiler-created function object, which
|
||||
* must never leak to script or embedding code and then be mutated.
|
||||
* Also assert that obj is not bound, per the ES5 15.3.4.5 ref above.
|
||||
*/
|
||||
JS_ASSERT(!IsInternalFunctionObject(obj));
|
||||
JS_ASSERT(!obj->isBoundFunction());
|
||||
|
||||
/*
|
||||
* Make the prototype object an instance of Object with the same parent
|
||||
* as the function object itself.
|
||||
*/
|
||||
JSObject *parent = obj->getParent();
|
||||
JSObject *proto;
|
||||
if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
|
||||
if (!ResolveInterpretedFunctionPrototype(cx, obj))
|
||||
return false;
|
||||
proto = NewNativeClassInstance(cx, &js_ObjectClass, proto, parent);
|
||||
if (!proto)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* ECMA (15.3.5.2) says that constructor.prototype is DontDelete for
|
||||
* user-defined functions, but DontEnum | ReadOnly | DontDelete for
|
||||
* native "system" constructors such as Object or Function. So lazily
|
||||
* set the former here in fun_resolve, but eagerly define the latter
|
||||
* in js_InitClass, with the right attributes.
|
||||
*/
|
||||
if (!js_SetClassPrototype(cx, obj, proto, JSPROP_PERMANENT))
|
||||
return false;
|
||||
|
||||
*objp = obj;
|
||||
return true;
|
||||
}
|
||||
|
@ -2633,6 +2642,28 @@ IsBuiltinFunctionConstructor(JSFunction *fun)
|
|||
return fun->maybeNative() == Function;
|
||||
}
|
||||
|
||||
const Shape *
|
||||
LookupInterpretedFunctionPrototype(JSContext *cx, JSObject *funobj)
|
||||
{
|
||||
JSFunction *fun = funobj->getFunctionPrivate();
|
||||
JS_ASSERT(fun->isInterpreted());
|
||||
JS_ASSERT(!fun->isFunctionPrototype());
|
||||
JS_ASSERT(!funobj->isBoundFunction());
|
||||
|
||||
jsid id = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
|
||||
const Shape *shape = funobj->nativeLookup(id);
|
||||
if (!shape) {
|
||||
if (!ResolveInterpretedFunctionPrototype(cx, funobj))
|
||||
return false;
|
||||
shape = funobj->nativeLookup(id);
|
||||
}
|
||||
JS_ASSERT(!shape->configurable());
|
||||
JS_ASSERT(shape->isDataDescriptor());
|
||||
JS_ASSERT(shape->hasSlot());
|
||||
JS_ASSERT(!shape->isMethod());
|
||||
return shape;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static JSBool
|
||||
|
|
|
@ -432,6 +432,21 @@ GetFunctionNameBytes(JSContext *cx, JSFunction *fun, JSAutoByteString *bytes)
|
|||
extern JS_FRIEND_API(bool)
|
||||
IsBuiltinFunctionConstructor(JSFunction *fun);
|
||||
|
||||
/*
|
||||
* Preconditions: funobj->isInterpreted() && !funobj->isFunctionPrototype() &&
|
||||
* !funobj->isBoundFunction(). This is sufficient to establish that funobj has
|
||||
* a non-configurable non-method .prototype data property, thought it might not
|
||||
* have been resolved yet, and its value could be anything.
|
||||
*
|
||||
* Return the shape of the .prototype property of funobj, resolving it if
|
||||
* needed. On error, return NULL.
|
||||
*
|
||||
* This is not safe to call on trace because it defines properties, which can
|
||||
* trigger lookups that could reenter.
|
||||
*/
|
||||
const Shape *
|
||||
LookupInterpretedFunctionPrototype(JSContext *cx, JSObject *funobj);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
extern JSString *
|
||||
|
|
|
@ -1850,7 +1850,7 @@ js_DestroyScriptsToGC(JSContext *cx, JSCompartment *comp)
|
|||
while ((script = *listp) != NULL) {
|
||||
*listp = script->u.nextToGC;
|
||||
script->u.nextToGC = NULL;
|
||||
js_DestroyScriptFromGC(cx, script);
|
||||
js_DestroyCachedScript(cx, script);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
#include "jslibmath.h"
|
||||
#include "jsvector.h"
|
||||
#include "methodjit/MethodJIT.h"
|
||||
#include "methodjit/MethodJIT-inl.h"
|
||||
#include "methodjit/Logging.h"
|
||||
|
||||
#include "jsatominlines.h"
|
||||
|
@ -505,7 +506,6 @@ BoxThisForVp(JSContext *cx, Value *vp)
|
|||
if (!vp[1].isObject())
|
||||
return !!js_PrimitiveToObject(cx, &vp[1]);
|
||||
|
||||
JS_ASSERT(IsSaneThisObject(vp[1].toObject()));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -638,7 +638,8 @@ RunScript(JSContext *cx, JSScript *script, JSStackFrame *fp)
|
|||
JS_ASSERT(fp->script() == script);
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
mjit::CompileStatus status = mjit::CanMethodJIT(cx, script, fp);
|
||||
mjit::CompileStatus status =
|
||||
mjit::CanMethodJIT(cx, script, fp, mjit::CompileRequest_Interpreter);
|
||||
if (status == mjit::Compile_Error)
|
||||
return JS_FALSE;
|
||||
|
||||
|
@ -741,10 +742,6 @@ InvokeSessionGuard::start(JSContext *cx, const Value &calleev, const Value &this
|
|||
#ifdef JS_TRACER
|
||||
if (TRACE_RECORDER(cx))
|
||||
AbortRecording(cx, "attempt to reenter VM while recording");
|
||||
#ifdef JS_METHODJIT
|
||||
if (TRACE_PROFILER(cx))
|
||||
AbortProfiling(cx);
|
||||
#endif
|
||||
LeaveTrace(cx);
|
||||
#endif
|
||||
|
||||
|
@ -781,7 +778,7 @@ InvokeSessionGuard::start(JSContext *cx, const Value &calleev, const Value &this
|
|||
|
||||
#ifdef JS_METHODJIT
|
||||
/* Hoist dynamic checks from RunScript. */
|
||||
mjit::CompileStatus status = mjit::CanMethodJIT(cx, script_, fp);
|
||||
mjit::CompileStatus status = mjit::CanMethodJIT(cx, script_, fp, mjit::CompileRequest_JIT);
|
||||
if (status == mjit::Compile_Error)
|
||||
return false;
|
||||
if (status != mjit::Compile_Okay)
|
||||
|
@ -843,7 +840,6 @@ ExternalInvoke(JSContext *cx, const Value &thisv, const Value &fval,
|
|||
JSObject *thisp = args.thisv().toObject().thisObject(cx);
|
||||
if (!thisp)
|
||||
return false;
|
||||
JS_ASSERT(IsSaneThisObject(*thisp));
|
||||
args.thisv().setObject(*thisp);
|
||||
}
|
||||
|
||||
|
@ -2331,6 +2327,35 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
|
|||
#define LOAD_DOUBLE(PCOFF, dbl) \
|
||||
(dbl = script->getConst(GET_FULL_INDEX(PCOFF)).toDouble())
|
||||
|
||||
bool methodJitFailed = false;
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
|
||||
#define MONITOR_BRANCH_METHODJIT() \
|
||||
JS_BEGIN_MACRO \
|
||||
mjit::CompileStatus status = \
|
||||
mjit::CanMethodJITAtBranch(cx, script, regs.fp, regs.pc); \
|
||||
if (status == mjit::Compile_Error) \
|
||||
goto error; \
|
||||
if (status == mjit::Compile_Okay) { \
|
||||
void *ncode = \
|
||||
script->nativeCodeForPC(regs.fp->isConstructing(), regs.pc); \
|
||||
interpReturnOK = mjit::JaegerShotAtSafePoint(cx, ncode); \
|
||||
if (inlineCallCount) \
|
||||
goto jit_return; \
|
||||
goto leave_on_safe_point; \
|
||||
} \
|
||||
if (status == mjit::Compile_Abort) { \
|
||||
methodJitFailed = true; \
|
||||
} \
|
||||
JS_END_MACRO
|
||||
|
||||
#else
|
||||
|
||||
#define MONITOR_BRANCH_METHODJIT() ((void) 0)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef JS_TRACER
|
||||
|
||||
#ifdef MOZ_TRACEVIS
|
||||
|
@ -2363,24 +2388,38 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
|
|||
#define MONITOR_BRANCH() \
|
||||
JS_BEGIN_MACRO \
|
||||
if (TRACING_ENABLED(cx)) { \
|
||||
MonitorResult r = MonitorLoopEdge(cx, inlineCallCount); \
|
||||
if (r == MONITOR_RECORDING) { \
|
||||
JS_ASSERT(TRACE_RECORDER(cx)); \
|
||||
JS_ASSERT(!TRACE_PROFILER(cx)); \
|
||||
MONITOR_BRANCH_TRACEVIS; \
|
||||
ENABLE_INTERRUPTS(); \
|
||||
CLEAR_LEAVE_ON_TRACE_POINT(); \
|
||||
if (!TRACE_RECORDER(cx) && \
|
||||
!TRACE_PROFILER(cx) && \
|
||||
interpMode == JSINTERP_NORMAL && \
|
||||
cx->methodJitEnabled && \
|
||||
!methodJitFailed) \
|
||||
{ \
|
||||
MONITOR_BRANCH_METHODJIT(); \
|
||||
} else { \
|
||||
MonitorResult r = MonitorLoopEdge(cx, inlineCallCount, interpMode); \
|
||||
if (r == MONITOR_RECORDING) { \
|
||||
JS_ASSERT(TRACE_RECORDER(cx)); \
|
||||
JS_ASSERT(!TRACE_PROFILER(cx)); \
|
||||
MONITOR_BRANCH_TRACEVIS; \
|
||||
ENABLE_INTERRUPTS(); \
|
||||
CLEAR_LEAVE_ON_TRACE_POINT(); \
|
||||
} \
|
||||
RESTORE_INTERP_VARS(); \
|
||||
JS_ASSERT_IF(cx->isExceptionPending(), r == MONITOR_ERROR); \
|
||||
if (r == MONITOR_ERROR) \
|
||||
goto error; \
|
||||
} \
|
||||
RESTORE_INTERP_VARS(); \
|
||||
JS_ASSERT_IF(cx->isExceptionPending(), r == MONITOR_ERROR); \
|
||||
if (r == MONITOR_ERROR) \
|
||||
goto error; \
|
||||
} else { \
|
||||
MONITOR_BRANCH_METHODJIT(); \
|
||||
} \
|
||||
JS_END_MACRO
|
||||
|
||||
#else /* !JS_TRACER */
|
||||
|
||||
#define MONITOR_BRANCH() ((void) 0)
|
||||
#define MONITOR_BRANCH() \
|
||||
JS_BEGIN_MACRO \
|
||||
MONITOR_BRANCH_METHODJIT(); \
|
||||
JS_END_MACRO
|
||||
|
||||
#endif /* !JS_TRACER */
|
||||
|
||||
|
@ -2511,10 +2550,6 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
|
|||
ENABLE_INTERRUPTS();
|
||||
} else if (TRACE_RECORDER(cx)) {
|
||||
AbortRecording(cx, "attempt to reenter interpreter while recording");
|
||||
#ifdef JS_METHODJIT
|
||||
} else if (TRACE_PROFILER(cx)) {
|
||||
AbortProfiling(cx);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (regs.fp->hasImacropc())
|
||||
|
@ -2637,7 +2672,8 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
|
|||
|
||||
#ifdef JS_TRACER
|
||||
#ifdef JS_METHODJIT
|
||||
if (LoopProfile *prof = TRACE_PROFILER(cx)) {
|
||||
if (TRACE_PROFILER(cx) && interpMode == JSINTERP_PROFILE) {
|
||||
LoopProfile *prof = TRACE_PROFILER(cx);
|
||||
JS_ASSERT(!TRACE_RECORDER(cx));
|
||||
LoopProfile::ProfileAction act = prof->profileOperation(cx, op);
|
||||
switch (act) {
|
||||
|
@ -4674,7 +4710,6 @@ BEGIN_CASE(JSOP_FUNCALL)
|
|||
newscript, &flags);
|
||||
if (JS_UNLIKELY(!newfp))
|
||||
goto error;
|
||||
JS_ASSERT_IF(!vp[1].isPrimitive(), IsSaneThisObject(vp[1].toObject()));
|
||||
|
||||
/* Initialize frame, locals. */
|
||||
newfp->initCallFrame(cx, *callee, newfun, argc, flags);
|
||||
|
@ -4702,7 +4737,10 @@ BEGIN_CASE(JSOP_FUNCALL)
|
|||
|
||||
#ifdef JS_METHODJIT
|
||||
/* Try to ensure methods are method JIT'd. */
|
||||
mjit::CompileStatus status = mjit::CanMethodJIT(cx, script, regs.fp);
|
||||
mjit::CompileRequest request = (interpMode == JSINTERP_NORMAL)
|
||||
? mjit::CompileRequest_Interpreter
|
||||
: mjit::CompileRequest_JIT;
|
||||
mjit::CompileStatus status = mjit::CanMethodJIT(cx, script, regs.fp, request);
|
||||
if (status == mjit::Compile_Error)
|
||||
goto error;
|
||||
if (!TRACE_RECORDER(cx) && !TRACE_PROFILER(cx) && status == mjit::Compile_Okay) {
|
||||
|
@ -6929,7 +6967,7 @@ END_CASE(JSOP_ARRAYPUSH)
|
|||
* This path is used when it's guaranteed the method can be finished
|
||||
* inside the JIT.
|
||||
*/
|
||||
#if defined(JS_TRACER) && defined(JS_METHODJIT)
|
||||
#if defined(JS_METHODJIT)
|
||||
leave_on_safe_point:
|
||||
#endif
|
||||
return interpReturnOK;
|
||||
|
|
|
@ -246,9 +246,12 @@ JSStackFrame::stealFrameAndSlots(js::Value *vp, JSStackFrame *otherfp,
|
|||
JS_ASSERT(othersp >= otherfp->slots());
|
||||
JS_ASSERT(othersp <= otherfp->base() + otherfp->numSlots());
|
||||
|
||||
size_t nbytes = (othersp - othervp) * sizeof(js::Value);
|
||||
memcpy(vp, othervp, nbytes);
|
||||
JS_ASSERT(vp == actualArgs() - 2);
|
||||
PodCopy(vp, othervp, othersp - othervp);
|
||||
JS_ASSERT(vp == this->actualArgs() - 2);
|
||||
|
||||
/* Catch bad-touching of non-canonical args (e.g., generator_trace). */
|
||||
if (otherfp->hasOverflowArgs())
|
||||
Debug_SetValueRangeToCrashOnTouch(othervp, othervp + 2 + otherfp->numFormalArgs());
|
||||
|
||||
/*
|
||||
* Repoint Call, Arguments, Block and With objects to the new live frame.
|
||||
|
@ -374,7 +377,6 @@ JSStackFrame::computeThis(JSContext *cx)
|
|||
}
|
||||
if (!js::BoxThisForVp(cx, &thisv - 1))
|
||||
return false;
|
||||
JS_ASSERT(IsSaneThisObject(thisv.toObject()));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -585,8 +587,8 @@ InvokeSessionGuard::invoke(JSContext *cx) const
|
|||
formals_[-2] = savedCallee_;
|
||||
formals_[-1] = savedThis_;
|
||||
|
||||
void *code;
|
||||
#ifdef JS_METHODJIT
|
||||
void *code;
|
||||
if (!optimized() || !(code = script_->getJIT(false /* !constructing */)->invokeEntry))
|
||||
#else
|
||||
if (!optimized())
|
||||
|
|
|
@ -590,7 +590,7 @@ GetIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp)
|
|||
JSObject *proto = obj->getProto();
|
||||
if (last) {
|
||||
NativeIterator *lastni = last->getNativeIterator();
|
||||
if (!(lastni->flags & JSITER_ACTIVE) &&
|
||||
if (!(lastni->flags & (JSITER_ACTIVE|JSITER_UNREUSABLE)) &&
|
||||
obj->isNative() &&
|
||||
obj->shape() == lastni->shapes_array[0] &&
|
||||
proto && proto->isNative() &&
|
||||
|
@ -627,7 +627,7 @@ GetIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp)
|
|||
JSObject *iterobj = cx->compartment->nativeIterCache.get(key);
|
||||
if (iterobj) {
|
||||
NativeIterator *ni = iterobj->getNativeIterator();
|
||||
if (!(ni->flags & JSITER_ACTIVE) &&
|
||||
if (!(ni->flags & (JSITER_ACTIVE|JSITER_UNREUSABLE)) &&
|
||||
ni->shapes_key == key &&
|
||||
ni->shapes_length == shapes.length() &&
|
||||
Compare(ni->shapes_array, shapes.begin(), ni->shapes_length)) {
|
||||
|
@ -882,6 +882,10 @@ SuppressDeletedPropertyHelper(JSContext *cx, JSObject *obj, IdPredicate predicat
|
|||
memmove(idp, idp + 1, (props_end - (idp + 1)) * sizeof(jsid));
|
||||
ni->props_end = ni->end() - 1;
|
||||
}
|
||||
|
||||
/* Don't reuse modified native iterators. */
|
||||
ni->flags |= JSITER_UNREUSABLE;
|
||||
|
||||
if (predicate.matchesAtMostOne())
|
||||
break;
|
||||
}
|
||||
|
@ -1080,9 +1084,17 @@ generator_trace(JSTracer *trc, JSObject *obj)
|
|||
|
||||
JSStackFrame *fp = gen->floatingFrame();
|
||||
JS_ASSERT(gen->liveFrame() == fp);
|
||||
MarkValueRange(trc, gen->floatingStack, fp->formalArgsEnd(), "generator slots");
|
||||
|
||||
/*
|
||||
* Currently, generators are not mjitted. Still, (overflow) args can be
|
||||
* pushed by the mjit and need to be conservatively marked. Technically, the
|
||||
* formal args and generator slots are safe for exact marking, but since the
|
||||
* plan is to eventually mjit generators, it makes sense to future-proof
|
||||
* this code and save someone an hour later.
|
||||
*/
|
||||
MarkStackRangeConservatively(trc, gen->floatingStack, fp->formalArgsEnd());
|
||||
js_TraceStackFrame(trc, fp);
|
||||
MarkValueRange(trc, fp->slots(), gen->regs.sp, "generator slots");
|
||||
MarkStackRangeConservatively(trc, fp->slots(), gen->regs.sp);
|
||||
}
|
||||
|
||||
Class js_GeneratorClass = {
|
||||
|
|
|
@ -63,7 +63,8 @@
|
|||
* For cacheable native iterators, whether the iterator is currently active.
|
||||
* Not serialized by XDR.
|
||||
*/
|
||||
#define JSITER_ACTIVE 0x1000
|
||||
#define JSITER_ACTIVE 0x1000
|
||||
#define JSITER_UNREUSABLE 0x2000
|
||||
|
||||
namespace js {
|
||||
|
||||
|
|
|
@ -1249,9 +1249,23 @@ EvalKernel(JSContext *cx, uintN argc, Value *vp, EvalType evalType, JSStackFrame
|
|||
|
||||
JSScript *script = NULL;
|
||||
JSScript **bucket = EvalCacheHash(cx, linearStr);
|
||||
if (evalType == DIRECT_EVAL && caller->isFunctionFrame() && !caller->isEvalFrame())
|
||||
if (evalType == DIRECT_EVAL && caller->isFunctionFrame() && !caller->isEvalFrame()) {
|
||||
script = EvalCacheLookup(cx, linearStr, caller, staticLevel, principals, scopeobj, bucket);
|
||||
|
||||
/*
|
||||
* Although the eval cache keeps a script alive from the perspective of
|
||||
* the JS engine, from a jsdbgapi user's perspective each eval()
|
||||
* creates and destroys a script. This hides implementation details and
|
||||
* allows jsdbgapi clients to avoid calling JS_GetScriptObject after a
|
||||
* script has been returned to the eval cache, which is invalid since
|
||||
* script->u.object aliases script->u.nextToGC.
|
||||
*/
|
||||
if (script) {
|
||||
js_CallNewScriptHook(cx, script, NULL);
|
||||
MUST_FLOW_THROUGH("destroy");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We can't have a callerFrame (down in js::Execute's terms) if we're in
|
||||
* global code (or if we're an indirect eval).
|
||||
|
@ -1280,6 +1294,9 @@ EvalKernel(JSContext *cx, uintN argc, Value *vp, EvalType evalType, JSStackFrame
|
|||
cx->runtime->atomState.evalAtom) &&
|
||||
Execute(cx, scopeobj, script, callerFrame, JSFRAME_EVAL, vp);
|
||||
|
||||
MUST_FLOW_LABEL(destroy);
|
||||
js_CallDestroyScriptHook(cx, script);
|
||||
|
||||
script->u.nextToGC = *bucket;
|
||||
*bucket = script;
|
||||
#ifdef CHECK_SCRIPT_OWNER
|
||||
|
@ -2979,59 +2996,37 @@ js_String_tn(JSContext* cx, JSObject* proto, JSString* str)
|
|||
JS_DEFINE_CALLINFO_3(extern, OBJECT, js_String_tn, CONTEXT, CALLEE_PROTOTYPE, STRING, 0,
|
||||
nanojit::ACCSET_STORE_ANY)
|
||||
|
||||
JSObject* FASTCALL
|
||||
js_CreateThisFromTrace(JSContext *cx, Class *clasp, JSObject *ctor)
|
||||
JSObject * FASTCALL
|
||||
js_CreateThisFromTrace(JSContext *cx, JSObject *ctor, uintN protoSlot)
|
||||
{
|
||||
JS_ASSERT(JS_ON_TRACE(cx));
|
||||
#ifdef DEBUG
|
||||
JS_ASSERT(ctor->isFunction());
|
||||
|
||||
if (!ctor->ensureClassReservedSlots(cx))
|
||||
return NULL;
|
||||
|
||||
jsid classPrototypeId = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
|
||||
const Shape *shape = ctor->nativeLookup(classPrototypeId);
|
||||
Value pval = shape ? ctor->getSlot(shape->slot) : MagicValue(JS_GENERIC_MAGIC);
|
||||
JS_ASSERT(ctor->getFunctionPrivate()->isInterpreted());
|
||||
jsid id = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
|
||||
const Shape *shape = ctor->nativeLookup(id);
|
||||
JS_ASSERT(shape->slot == protoSlot);
|
||||
JS_ASSERT(!shape->configurable());
|
||||
JS_ASSERT(!shape->isMethod());
|
||||
#endif
|
||||
|
||||
JSObject *parent = ctor->getParent();
|
||||
JSObject *proto;
|
||||
if (pval.isObject()) {
|
||||
/* An object in ctor.prototype, let's use it as the new instance's proto. */
|
||||
proto = &pval.toObject();
|
||||
const Value &protov = ctor->getSlotRef(protoSlot);
|
||||
if (protov.isObject()) {
|
||||
proto = &protov.toObject();
|
||||
} else {
|
||||
/* A hole or a primitive: either way, we need to get Object.prototype. */
|
||||
/*
|
||||
* GetInterpretedFunctionPrototype found that ctor.prototype is
|
||||
* primitive. Use Object.prototype for proto, per ES5 13.2.2 step 7.
|
||||
*/
|
||||
if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
|
||||
return NULL;
|
||||
|
||||
if (pval.isMagic(JS_GENERIC_MAGIC)) {
|
||||
/*
|
||||
* No ctor.prototype was set, so we inline-expand and optimize
|
||||
* fun_resolve's prototype creation code.
|
||||
*/
|
||||
proto = NewNativeClassInstance(cx, clasp, proto, parent);
|
||||
if (!proto)
|
||||
return NULL;
|
||||
JSFunction *fun = ctor->getFunctionPrivate();
|
||||
if (!fun->isNative() && !fun->isFunctionPrototype()) {
|
||||
if (!js_SetClassPrototype(cx, ctor, proto, JSPROP_ENUMERATE | JSPROP_PERMANENT))
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* A primitive value in .prototype means to use Object.prototype
|
||||
* for proto. See ES5 13.2.2 step 7.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: 561785 at least. Quasi-natives including XML objects prevent us
|
||||
* from easily or unconditionally calling NewNativeClassInstance here.
|
||||
*/
|
||||
gc::FinalizeKind kind = NewObjectGCKind(cx, clasp);
|
||||
return NewNonFunction<WithProto::Given>(cx, clasp, proto, parent, kind);
|
||||
gc::FinalizeKind kind = NewObjectGCKind(cx, &js_ObjectClass);
|
||||
return NewNativeClassInstance(cx, &js_ObjectClass, proto, parent, kind);
|
||||
}
|
||||
|
||||
JS_DEFINE_CALLINFO_3(extern, CONSTRUCTOR_RETRY, js_CreateThisFromTrace, CONTEXT, CLASS, OBJECT, 0,
|
||||
JS_DEFINE_CALLINFO_3(extern, CONSTRUCTOR_RETRY, js_CreateThisFromTrace, CONTEXT, OBJECT, UINTN, 0,
|
||||
nanojit::ACCSET_STORE_ANY)
|
||||
|
||||
#else /* !JS_TRACER */
|
||||
|
@ -6970,17 +6965,5 @@ js_DumpStackFrame(JSContext *cx, JSStackFrame *start)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool
|
||||
IsSaneThisObject(JSObject &obj)
|
||||
{
|
||||
Class *clasp = obj.getClass();
|
||||
return clasp != &js_CallClass &&
|
||||
clasp != &js_BlockClass &&
|
||||
clasp != &js_DeclEnvClass &&
|
||||
clasp != &js_WithClass;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* DEBUG */
|
||||
|
||||
|
|
|
@ -518,6 +518,7 @@ struct JSObject : js::gc::Cell {
|
|||
void protoShapeChange(JSContext *cx);
|
||||
void shadowingShapeChange(JSContext *cx, const js::Shape &shape);
|
||||
bool globalObjectOwnShapeChange(JSContext *cx);
|
||||
void watchpointOwnShapeChange(JSContext *cx) { generateOwnShape(cx); }
|
||||
|
||||
void extensibleShapeChange(JSContext *cx) {
|
||||
/* This will do for now. */
|
||||
|
@ -1893,7 +1894,6 @@ JS_FRIEND_API(void) js_DumpObject(JSObject *obj);
|
|||
JS_FRIEND_API(void) js_DumpValue(const js::Value &val);
|
||||
JS_FRIEND_API(void) js_DumpId(jsid id);
|
||||
JS_FRIEND_API(void) js_DumpStackFrame(JSContext *cx, JSStackFrame *start = NULL);
|
||||
bool IsSaneThisObject(JSObject &obj);
|
||||
#endif
|
||||
|
||||
extern uintN
|
||||
|
|
|
@ -151,6 +151,10 @@ JSObject::methodReadBarrier(JSContext *cx, const js::Shape &shape, js::Value *vp
|
|||
JS_ASSERT(nativeContains(shape));
|
||||
JS_ASSERT(shape.isMethod());
|
||||
JS_ASSERT(&shape.methodObject() == &vp->toObject());
|
||||
JS_ASSERT(shape.writable());
|
||||
JS_ASSERT(shape.slot != SHAPE_INVALID_SLOT);
|
||||
JS_ASSERT(shape.hasDefaultSetter() || shape.setterOp() == js_watch_set);
|
||||
JS_ASSERT(!isGlobal()); /* i.e. we are not changing the global shape */
|
||||
|
||||
JSObject *funobj = &vp->toObject();
|
||||
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
|
||||
|
@ -161,9 +165,19 @@ JSObject::methodReadBarrier(JSContext *cx, const js::Shape &shape, js::Value *vp
|
|||
return false;
|
||||
funobj->setMethodObj(*this);
|
||||
|
||||
/*
|
||||
* Replace the method property with an ordinary data property. This is
|
||||
* equivalent to this->setProperty(cx, shape.id, vp) except that any
|
||||
* watchpoint on the property is not triggered.
|
||||
*/
|
||||
uint32 slot = shape.slot;
|
||||
const js::Shape *newshape = methodShapeChange(cx, shape);
|
||||
if (!newshape)
|
||||
return NULL;
|
||||
JS_ASSERT(!newshape->isMethod());
|
||||
JS_ASSERT(newshape->slot == slot);
|
||||
vp->setObject(*funobj);
|
||||
if (!js_SetPropertyHelper(cx, this, shape.id, 0, vp, false))
|
||||
return false;
|
||||
nativeSetSlot(slot, *vp);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (cx->runtime->functionMeterFilename) {
|
||||
|
|
|
@ -139,7 +139,7 @@ JS_FRIEND_DATA(JSScopeStats) js_scope_stats = {0};
|
|||
|
||||
# define METER(x) JS_ATOMIC_INCREMENT(&js_scope_stats.x)
|
||||
#else
|
||||
# define METER(x) /* nothing */
|
||||
# define METER(x) ((void) 0)
|
||||
#endif
|
||||
|
||||
bool
|
||||
|
@ -768,10 +768,9 @@ JSObject::addProperty(JSContext *cx, jsid id,
|
|||
return NULL;
|
||||
|
||||
/* Update any watchpoints referring to this property. */
|
||||
if (!js_UpdateWatchpointsForShape(cx, this, shape)) {
|
||||
shape = js_UpdateWatchpointsForShape(cx, this, shape);
|
||||
if (!shape)
|
||||
METER(wrapWatchFails);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return shape;
|
||||
}
|
||||
|
@ -896,13 +895,14 @@ JSObject::putProperty(JSContext *cx, jsid id,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
const Shape *new_shape =
|
||||
const Shape *newShape =
|
||||
addPropertyInternal(cx, id, getter, setter, slot, attrs, flags, shortid, spp);
|
||||
if (!js_UpdateWatchpointsForShape(cx, this, new_shape)) {
|
||||
METER(wrapWatchFails);
|
||||
if (!newShape)
|
||||
return NULL;
|
||||
}
|
||||
return new_shape;
|
||||
newShape = js_UpdateWatchpointsForShape(cx, this, newShape);
|
||||
if (!newShape)
|
||||
METER(wrapWatchFails);
|
||||
return newShape;
|
||||
}
|
||||
|
||||
/* Property exists: search must have returned a valid *spp. */
|
||||
|
@ -1038,12 +1038,10 @@ JSObject::putProperty(JSContext *cx, jsid id,
|
|||
CHECK_SHAPE_CONSISTENCY(this);
|
||||
METER(puts);
|
||||
|
||||
if (!js_UpdateWatchpointsForShape(cx, this, shape)) {
|
||||
const Shape *newShape = js_UpdateWatchpointsForShape(cx, this, shape);
|
||||
if (!newShape)
|
||||
METER(wrapWatchFails);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return shape;
|
||||
return newShape;
|
||||
}
|
||||
|
||||
const Shape *
|
||||
|
@ -1109,11 +1107,12 @@ JSObject::changeProperty(JSContext *cx, const Shape *shape, uintN attrs, uintN m
|
|||
lastProp->shape = js_GenerateShape(cx);
|
||||
clearOwnShape();
|
||||
|
||||
if (!js_UpdateWatchpointsForShape(cx, this, shape)) {
|
||||
shape = js_UpdateWatchpointsForShape(cx, this, shape);
|
||||
if (!shape) {
|
||||
METER(wrapWatchFails);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JS_ASSERT(shape == mutableShape);
|
||||
newShape = mutableShape;
|
||||
} else if (shape == lastProp) {
|
||||
Shape child(shape->id, getter, setter, shape->slot, attrs, shape->flags, shape->shortid);
|
||||
|
|
|
@ -1561,7 +1561,7 @@ js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun)
|
|||
}
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
void
|
||||
js_CallDestroyScriptHook(JSContext *cx, JSScript *script)
|
||||
{
|
||||
JSDestroyScriptHook hook;
|
||||
|
@ -1569,6 +1569,7 @@ js_CallDestroyScriptHook(JSContext *cx, JSScript *script)
|
|||
hook = cx->debugHooks->destroyScriptHook;
|
||||
if (hook)
|
||||
hook(cx, script, cx->debugHooks->destroyScriptHookData);
|
||||
JS_ClearScriptTraps(cx, script);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1581,9 +1582,6 @@ DestroyScript(JSContext *cx, JSScript *script)
|
|||
JS_RUNTIME_UNMETER(cx->runtime, liveScripts);
|
||||
#endif
|
||||
|
||||
js_CallDestroyScriptHook(cx, script);
|
||||
JS_ClearScriptTraps(cx, script);
|
||||
|
||||
if (script->principals)
|
||||
JSPRINCIPALS_DROP(cx, script->principals);
|
||||
|
||||
|
@ -1646,11 +1644,20 @@ void
|
|||
js_DestroyScript(JSContext *cx, JSScript *script)
|
||||
{
|
||||
JS_ASSERT(!cx->runtime->gcRunning);
|
||||
js_CallDestroyScriptHook(cx, script);
|
||||
DestroyScript(cx, script);
|
||||
}
|
||||
|
||||
void
|
||||
js_DestroyScriptFromGC(JSContext *cx, JSScript *script)
|
||||
{
|
||||
JS_ASSERT(cx->runtime->gcRunning);
|
||||
js_CallDestroyScriptHook(cx, script);
|
||||
DestroyScript(cx, script);
|
||||
}
|
||||
|
||||
void
|
||||
js_DestroyCachedScript(JSContext *cx, JSScript *script)
|
||||
{
|
||||
JS_ASSERT(cx->runtime->gcRunning);
|
||||
DestroyScript(cx, script);
|
||||
|
|
|
@ -373,6 +373,8 @@ struct JSScript {
|
|||
private:
|
||||
uint16 version; /* JS version under which script was compiled */
|
||||
|
||||
size_t callCount_; /* Number of times the script has been called. */
|
||||
|
||||
public:
|
||||
uint16 nfixed; /* number of slots besides stack operands in
|
||||
slot array */
|
||||
|
@ -473,6 +475,9 @@ struct JSScript {
|
|||
return constructing ? jitCtor : jitNormal;
|
||||
}
|
||||
|
||||
size_t callCount() const { return callCount_; }
|
||||
size_t incCallCount() { return ++callCount_; }
|
||||
|
||||
JITScriptStatus getJITStatus(bool constructing) {
|
||||
void *addr = constructing ? jitArityCheckCtor : jitArityCheckNormal;
|
||||
if (addr == NULL)
|
||||
|
@ -649,7 +654,7 @@ js_SweepScriptFilenames(JSRuntime *rt);
|
|||
extern JS_FRIEND_API(void)
|
||||
js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun);
|
||||
|
||||
extern JS_FRIEND_API(void)
|
||||
extern void
|
||||
js_CallDestroyScriptHook(JSContext *cx, JSScript *script);
|
||||
|
||||
/*
|
||||
|
@ -659,13 +664,18 @@ js_CallDestroyScriptHook(JSContext *cx, JSScript *script);
|
|||
extern void
|
||||
js_DestroyScript(JSContext *cx, JSScript *script);
|
||||
|
||||
/*
|
||||
* If data is not null, it indicates that the script could been accessed only
|
||||
* from that thread.
|
||||
*/
|
||||
extern void
|
||||
js_DestroyScriptFromGC(JSContext *cx, JSScript *script);
|
||||
|
||||
/*
|
||||
* Script objects may be cached and reused, in which case their JSD-visible
|
||||
* lifetimes may be shorter than their actual lifetimes. Destroy one such
|
||||
* script for real as part of a GC pass. From JSD's point of view, the script
|
||||
* is already dead.
|
||||
*/
|
||||
extern void
|
||||
js_DestroyCachedScript(JSContext *cx, JSScript *script);
|
||||
|
||||
extern void
|
||||
js_TraceScript(JSTracer *trc, JSScript *script);
|
||||
|
||||
|
|
|
@ -381,6 +381,9 @@ class Conditionally {
|
|||
|
||||
template <class T1>
|
||||
Conditionally(bool b, const T1 &t1) { if (b) t.construct(t1); }
|
||||
|
||||
template <class T1, class T2>
|
||||
Conditionally(bool b, const T1 &t1, const T2 &t2) { if (b) t.construct(t1, t2); }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
|
|
|
@ -2314,6 +2314,11 @@ TraceRecorder::TraceRecorder(JSContext* cx, TraceMonitor *tm,
|
|||
JS_ASSERT(globalObj->hasOwnShape());
|
||||
JS_ASSERT(cx->regs->pc == (jsbytecode*)fragment->ip);
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
if (TRACE_PROFILER(cx))
|
||||
AbortProfiling(cx);
|
||||
#endif
|
||||
|
||||
JS_ASSERT(JS_THREAD_DATA(cx)->onTraceCompartment == NULL);
|
||||
JS_ASSERT(JS_THREAD_DATA(cx)->profilingCompartment == NULL);
|
||||
JS_ASSERT(JS_THREAD_DATA(cx)->recordingCompartment == NULL);
|
||||
|
@ -5628,7 +5633,6 @@ TraceRecorder::startRecorder(JSContext* cx, TraceMonitor *tm, VMSideExit* anchor
|
|||
JSScript* outerScript, jsbytecode* outerPC, uint32 outerArgc,
|
||||
bool speculate)
|
||||
{
|
||||
JS_ASSERT(!tm->profile);
|
||||
JS_ASSERT(!tm->needFlush);
|
||||
JS_ASSERT_IF(cx->fp()->hasImacropc(), f->root != f);
|
||||
|
||||
|
@ -6494,6 +6498,11 @@ TracerState::TracerState(JSContext* cx, TraceMonitor* tm, TreeFragment* f,
|
|||
prev = tm->tracerState;
|
||||
tm->tracerState = this;
|
||||
|
||||
#ifdef JS_METH
|
||||
if (TRACE_PROFILER(cx))
|
||||
AbortProfiling(cx);
|
||||
#endif
|
||||
|
||||
JS_ASSERT(JS_THREAD_DATA(cx)->onTraceCompartment == NULL);
|
||||
JS_ASSERT(JS_THREAD_DATA(cx)->recordingCompartment == NULL ||
|
||||
JS_THREAD_DATA(cx)->recordingCompartment == cx->compartment);
|
||||
|
@ -7086,8 +7095,6 @@ RecordLoopEdge(JSContext* cx, TraceMonitor* tm, uintN& inlineCallCount)
|
|||
TraceVisStateObj tvso(cx, S_MONITOR);
|
||||
#endif
|
||||
|
||||
JS_ASSERT(!tm->profile);
|
||||
|
||||
/* Is the recorder currently active? */
|
||||
if (tm->recorder) {
|
||||
tm->recorder->assertInsideLoop();
|
||||
|
@ -7296,6 +7303,8 @@ TraceRecorder::monitorRecording(JSOp op)
|
|||
{
|
||||
JS_ASSERT(!addPropShapeBefore);
|
||||
|
||||
JS_ASSERT(traceMonitor == &cx->compartment->traceMonitor);
|
||||
|
||||
TraceMonitor &localtm = *traceMonitor;
|
||||
debug_only_stmt( JSContext *localcx = cx; )
|
||||
assertInsideLoop();
|
||||
|
@ -10483,13 +10492,6 @@ TraceRecorder::record_EnterFrame()
|
|||
RETURN_STOP_A("recursion started inlining");
|
||||
}
|
||||
|
||||
if (fp->isConstructing()) {
|
||||
LIns* args[] = { callee_ins, w.nameImmpNonGC(&js_ObjectClass), cx_ins };
|
||||
LIns* tv_ins = w.call(&js_CreateThisFromTrace_ci, args);
|
||||
guard(false, w.eqp0(tv_ins), OOM_EXIT);
|
||||
set(&fp->thisValue(), tv_ins);
|
||||
}
|
||||
|
||||
return ARECORD_CONTINUE;
|
||||
}
|
||||
|
||||
|
@ -11440,7 +11442,8 @@ TraceRecorder::callNative(uintN argc, JSOp mode)
|
|||
|
||||
Value* vp = &stackval(0 - (2 + argc));
|
||||
JSObject* funobj = &vp[0].toObject();
|
||||
JSFunction* fun = GET_FUNCTION_PRIVATE(cx, funobj);
|
||||
JSFunction* fun = funobj->getFunctionPrivate();
|
||||
JS_ASSERT(fun->isNative());
|
||||
Native native = fun->u.n.native;
|
||||
|
||||
switch (argc) {
|
||||
|
@ -11616,39 +11619,24 @@ TraceRecorder::callNative(uintN argc, JSOp mode)
|
|||
clasp = &js_ObjectClass;
|
||||
JS_ASSERT(((jsuword) clasp & 3) == 0);
|
||||
|
||||
// Abort on |new Function|. js_CreateThis would allocate a regular-
|
||||
// sized JSObject, not a Function-sized one. (The Function ctor would
|
||||
// deep-bail anyway but let's not go there.)
|
||||
// Abort on |new Function|. (FIXME: This restriction might not
|
||||
// unnecessary now that the constructor creates the new function object
|
||||
// itself.)
|
||||
if (clasp == &js_FunctionClass)
|
||||
RETURN_STOP("new Function");
|
||||
|
||||
if (!clasp->isNative())
|
||||
RETURN_STOP("new with non-native ops");
|
||||
|
||||
if (fun->isConstructor()) {
|
||||
vp[1].setMagicWithObjectOrNullPayload(NULL);
|
||||
newobj_ins = w.immpMagicNull();
|
||||
// Don't trace |new Math.sin(0)|.
|
||||
if (!fun->isConstructor())
|
||||
RETURN_STOP("new with non-constructor native function");
|
||||
|
||||
/* Treat this as a regular call, the constructor will behave correctly. */
|
||||
mode = JSOP_CALL;
|
||||
} else {
|
||||
args[0] = w.immpObjGC(funobj);
|
||||
args[1] = w.immpNonGC(clasp);
|
||||
args[2] = cx_ins;
|
||||
newobj_ins = w.call(&js_CreateThisFromTrace_ci, args);
|
||||
guard(false, w.eqp0(newobj_ins), OOM_EXIT);
|
||||
vp[1].setMagicWithObjectOrNullPayload(NULL);
|
||||
newobj_ins = w.immpMagicNull();
|
||||
|
||||
/*
|
||||
* emitNativeCall may take a snapshot below. To avoid having a type
|
||||
* mismatch (e.g., where get(&vp[1]) is an object and vp[1] is
|
||||
* null), we make sure vp[1] is some object. The actual object
|
||||
* doesn't matter; JSOP_NEW and InvokeConstructor both overwrite
|
||||
* vp[1] without observing its value.
|
||||
*
|
||||
* N.B. tracing specializes for functions, so pick a non-function.
|
||||
*/
|
||||
vp[1].setObject(*globalObj);
|
||||
}
|
||||
/* Treat this as a regular call, the constructor will behave correctly. */
|
||||
mode = JSOP_CALL;
|
||||
this_ins = newobj_ins;
|
||||
} else {
|
||||
this_ins = get(&vp[1]);
|
||||
|
@ -13741,6 +13729,42 @@ TraceRecorder::guardArguments(JSObject *obj, LIns* obj_ins, unsigned *depthp)
|
|||
return afp;
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK RecordingStatus
|
||||
TraceRecorder::createThis(JSObject& ctor, LIns* ctor_ins, LIns** thisobj_insp)
|
||||
{
|
||||
JS_ASSERT(ctor.getFunctionPrivate()->isInterpreted());
|
||||
if (ctor.getFunctionPrivate()->isFunctionPrototype())
|
||||
RETURN_STOP("new Function.prototype");
|
||||
if (ctor.isBoundFunction())
|
||||
RETURN_STOP("new applied to bound function");
|
||||
|
||||
// Given the above conditions, ctor.prototype is a non-configurable data
|
||||
// property with a slot.
|
||||
jsid id = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
|
||||
const Shape *shape = LookupInterpretedFunctionPrototype(cx, &ctor);
|
||||
if (!shape)
|
||||
RETURN_ERROR("new f: error resolving f.prototype");
|
||||
|
||||
// At run time ctor might be a different instance of the same function. Its
|
||||
// .prototype property might not be resolved yet. Guard on the function
|
||||
// object's shape to make sure .prototype is there.
|
||||
//
|
||||
// However, if ctor_ins is constant, which is usual, we don't need to
|
||||
// guard: .prototype is non-configurable, and an object's non-configurable
|
||||
// data properties always stay in the same slot for the life of the object.
|
||||
if (!ctor_ins->isImmP())
|
||||
guardShape(ctor_ins, &ctor, ctor.shape(), "ctor_shape", snapshot(MISMATCH_EXIT));
|
||||
|
||||
// Pass the slot of ctor.prototype to js_CreateThisFromTrace. We can only
|
||||
// bake the slot into the trace, not the value, since .prototype is
|
||||
// writable.
|
||||
uintN protoSlot = shape->slot;
|
||||
LIns* args[] = { w.nameImmw(protoSlot), ctor_ins, cx_ins };
|
||||
*thisobj_insp = w.call(&js_CreateThisFromTrace_ci, args);
|
||||
guard(false, w.eqp0(*thisobj_insp), OOM_EXIT);
|
||||
return RECORD_CONTINUE;
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK RecordingStatus
|
||||
TraceRecorder::interpretedFunctionCall(Value& fval, JSFunction* fun, uintN argc, bool constructing)
|
||||
{
|
||||
|
@ -13752,14 +13776,10 @@ TraceRecorder::interpretedFunctionCall(Value& fval, JSFunction* fun, uintN argc,
|
|||
*/
|
||||
if (fun->script()->isEmpty()) {
|
||||
LIns* rval_ins;
|
||||
if (constructing) {
|
||||
LIns* args[] = { get(&fval), w.nameImmpNonGC(&js_ObjectClass), cx_ins };
|
||||
LIns* tv_ins = w.call(&js_CreateThisFromTrace_ci, args);
|
||||
guard(false, w.eqp0(tv_ins), OOM_EXIT);
|
||||
rval_ins = tv_ins;
|
||||
} else {
|
||||
if (constructing)
|
||||
CHECK_STATUS(createThis(fval.toObject(), get(&fval), &rval_ins));
|
||||
else
|
||||
rval_ins = w.immiUndefined();
|
||||
}
|
||||
stack(-2 - argc, rval_ins);
|
||||
return RECORD_CONTINUE;
|
||||
}
|
||||
|
@ -13769,6 +13789,12 @@ TraceRecorder::interpretedFunctionCall(Value& fval, JSFunction* fun, uintN argc,
|
|||
|
||||
JSStackFrame* const fp = cx->fp();
|
||||
|
||||
if (constructing) {
|
||||
LIns* thisobj_ins;
|
||||
CHECK_STATUS(createThis(fval.toObject(), get(&fval), &thisobj_ins));
|
||||
stack(-argc - 1, thisobj_ins);
|
||||
}
|
||||
|
||||
// Generate a type map for the outgoing frame and stash it in the LIR
|
||||
unsigned stackSlots = NativeStackSlots(cx, 0 /* callDepth */);
|
||||
FrameInfo* fi = (FrameInfo*)
|
||||
|
@ -17003,7 +17029,6 @@ LookupLoopProfile(TraceMonitor *tm, jsbytecode *pc)
|
|||
void
|
||||
LoopProfile::stopProfiling(JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(JS_THREAD_DATA(cx)->onTraceCompartment == NULL);
|
||||
JS_ASSERT(JS_THREAD_DATA(cx)->recordingCompartment == NULL);
|
||||
JS_THREAD_DATA(cx)->profilingCompartment = NULL;
|
||||
|
||||
|
@ -17022,10 +17047,14 @@ MonitorTracePoint(JSContext *cx, uintN& inlineCallCount, bool* blacklist,
|
|||
*blacklist = false;
|
||||
|
||||
/*
|
||||
* We may have re-entered Interpret while profiling. We don't profile
|
||||
* the nested invocation.
|
||||
* This is the only place where we check for re-entering the profiler.
|
||||
* The assumption is that MonitorTracePoint is the only place where we
|
||||
* start profiling. When we do so, we enter an interpreter frame with
|
||||
* JSINTERP_PROFILE mode. All other entry points to the profiler check
|
||||
* that the interpreter mode is JSINTERP_PROFILE. If it isn't, they
|
||||
* don't profile.
|
||||
*/
|
||||
if (tm->profile)
|
||||
if (TRACE_PROFILER(cx))
|
||||
return TPA_Nothing;
|
||||
|
||||
jsbytecode* pc = cx->regs->pc;
|
||||
|
@ -17055,7 +17084,6 @@ MonitorTracePoint(JSContext *cx, uintN& inlineCallCount, bool* blacklist,
|
|||
tm->profile = prof;
|
||||
|
||||
JS_ASSERT(JS_THREAD_DATA(cx)->profilingCompartment == NULL);
|
||||
JS_ASSERT(JS_THREAD_DATA(cx)->onTraceCompartment == NULL);
|
||||
JS_ASSERT(JS_THREAD_DATA(cx)->recordingCompartment == NULL);
|
||||
JS_THREAD_DATA(cx)->profilingCompartment = cx->compartment;
|
||||
|
||||
|
@ -17092,6 +17120,9 @@ LoopProfile::profileOperation(JSContext* cx, JSOp op)
|
|||
{
|
||||
TraceMonitor* tm = JS_TRACE_MONITOR_FROM_CONTEXT(cx);
|
||||
|
||||
JS_ASSERT(tm == traceMonitor);
|
||||
JS_ASSERT(&entryScript->compartment->traceMonitor == tm);
|
||||
|
||||
if (profiled) {
|
||||
stopProfiling(cx);
|
||||
return ProfComplete;
|
||||
|
@ -17448,10 +17479,10 @@ LoopProfile::decide(JSContext *cx)
|
|||
}
|
||||
|
||||
JS_REQUIRES_STACK MonitorResult
|
||||
MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount)
|
||||
MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount, JSInterpMode interpMode)
|
||||
{
|
||||
TraceMonitor *tm = JS_TRACE_MONITOR_FROM_CONTEXT(cx);
|
||||
if (tm->profile)
|
||||
if (interpMode == JSINTERP_PROFILE && tm->profile)
|
||||
return tm->profile->profileLoopEdge(cx, inlineCallCount);
|
||||
else
|
||||
return RecordLoopEdge(cx, tm, inlineCallCount);
|
||||
|
@ -17473,7 +17504,7 @@ AbortProfiling(JSContext *cx)
|
|||
#else /* JS_METHODJIT */
|
||||
|
||||
JS_REQUIRES_STACK MonitorResult
|
||||
MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount)
|
||||
MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount, JSInterpMode interpMode)
|
||||
{
|
||||
TraceMonitor *tm = JS_TRACE_MONITOR_FROM_CONTEXT(cx);
|
||||
return RecordLoopEdge(cx, tm, inlineCallCount);
|
||||
|
|
|
@ -1479,15 +1479,17 @@ class TraceRecorder
|
|||
VMSideExit* exit);
|
||||
JS_REQUIRES_STACK RecordingStatus guardPrototypeHasNoIndexedProperties(JSObject* obj,
|
||||
nanojit::LIns* obj_ins,
|
||||
VMSideExit *exit);
|
||||
VMSideExit* exit);
|
||||
JS_REQUIRES_STACK RecordingStatus guardNativeConversion(Value& v);
|
||||
JS_REQUIRES_STACK void clearReturningFrameFromNativeTracker();
|
||||
JS_REQUIRES_STACK void putActivationObjects();
|
||||
JS_REQUIRES_STACK RecordingStatus createThis(JSObject& ctor, nanojit::LIns* ctor_ins,
|
||||
nanojit::LIns** thisobj_insp);
|
||||
JS_REQUIRES_STACK RecordingStatus guardCallee(Value& callee);
|
||||
JS_REQUIRES_STACK JSStackFrame *guardArguments(JSObject *obj, nanojit::LIns* obj_ins,
|
||||
unsigned *depthp);
|
||||
JS_REQUIRES_STACK nanojit::LIns* guardArgsLengthNotAssigned(nanojit::LIns* argsobj_ins);
|
||||
JS_REQUIRES_STACK void guardNotHole(nanojit::LIns *argsobj_ins, nanojit::LIns *ids_ins);
|
||||
JS_REQUIRES_STACK void guardNotHole(nanojit::LIns* argsobj_ins, nanojit::LIns* ids_ins);
|
||||
JS_REQUIRES_STACK RecordingStatus getClassPrototype(JSObject* ctor,
|
||||
nanojit::LIns*& proto_ins);
|
||||
JS_REQUIRES_STACK RecordingStatus getClassPrototype(JSProtoKey key,
|
||||
|
@ -1690,10 +1692,7 @@ class TraceRecorder
|
|||
#define TRACE_2(x,a,b) TRACE_ARGS(x, (a, b))
|
||||
|
||||
extern JS_REQUIRES_STACK MonitorResult
|
||||
MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount);
|
||||
|
||||
extern JS_REQUIRES_STACK MonitorResult
|
||||
ProfileLoopEdge(JSContext* cx, uintN& inlineCallCount);
|
||||
MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount, JSInterpMode interpMode);
|
||||
|
||||
extern JS_REQUIRES_STACK TracePointAction
|
||||
RecordTracePoint(JSContext*, uintN& inlineCallCount, bool* blacklist);
|
||||
|
|
|
@ -768,7 +768,7 @@ class TypedArrayTemplate
|
|||
cx->destroy<ThisTypeArray>(tarray);
|
||||
return false;
|
||||
}
|
||||
} else if (argv[0].isObject()) {
|
||||
} else if (argc > 0 && argv[0].isObject()) {
|
||||
int32_t byteOffset = -1;
|
||||
int32_t length = -1;
|
||||
|
||||
|
@ -936,7 +936,7 @@ class TypedArrayTemplate
|
|||
}
|
||||
|
||||
// first arg must be either a typed array or a JS array
|
||||
if (!argv[0].isObject()) {
|
||||
if (argc == 0 || !argv[0].isObject()) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_TYPED_ARRAY_BAD_ARGS);
|
||||
return false;
|
||||
|
|
|
@ -1196,7 +1196,7 @@ SetValueRangeToUndefined(Value *beg, Value *end)
|
|||
static JS_ALWAYS_INLINE void
|
||||
SetValueRangeToUndefined(Value *vec, size_t len)
|
||||
{
|
||||
return SetValueRangeToUndefined(vec, vec + len);
|
||||
SetValueRangeToUndefined(vec, vec + len);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE void
|
||||
|
@ -1209,7 +1209,30 @@ SetValueRangeToNull(Value *beg, Value *end)
|
|||
static JS_ALWAYS_INLINE void
|
||||
SetValueRangeToNull(Value *vec, size_t len)
|
||||
{
|
||||
return SetValueRangeToNull(vec, vec + len);
|
||||
SetValueRangeToNull(vec, vec + len);
|
||||
}
|
||||
|
||||
/*
|
||||
* To really poison a set of values, using 'magic' or 'undefined' isn't good
|
||||
* enough since often these will just be ignored by buggy code (see bug 629974)
|
||||
* in debug builds and crash in release builds. Instead, we use a safe-for-crash
|
||||
* pointer.
|
||||
*/
|
||||
static JS_ALWAYS_INLINE void
|
||||
Debug_SetValueRangeToCrashOnTouch(Value *beg, Value *end)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
for (Value *v = beg; v != end; ++v)
|
||||
v->setObject(*reinterpret_cast<JSObject *>(0x42));
|
||||
#endif
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE void
|
||||
Debug_SetValueRangeToCrashOnTouch(Value *vec, size_t len)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
Debug_SetValueRangeToCrashOnTouch(vec, vec + len);
|
||||
#endif
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
|
|
@ -168,13 +168,13 @@ class LinkerHelper : public JSC::LinkBuffer
|
|||
if (!ep)
|
||||
return ep;
|
||||
|
||||
m_size = masm.size();
|
||||
m_code = executableCopy(masm, ep);
|
||||
if (!m_code) {
|
||||
ep->release();
|
||||
js_ReportOutOfMemory(cx);
|
||||
return NULL;
|
||||
}
|
||||
m_size = masm.size(); // must come after the call to executableCopy()
|
||||
return ep;
|
||||
}
|
||||
|
||||
|
|
|
@ -645,7 +645,8 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
|
|||
#ifdef JS_TRACER
|
||||
jitTraceICs[i].loopCounterStart = GetHotloop(cx);
|
||||
#endif
|
||||
jitTraceICs[i].loopCounter = jitTraceICs[i].loopCounterStart;
|
||||
jitTraceICs[i].loopCounter = jitTraceICs[i].loopCounterStart
|
||||
- cx->compartment->backEdgeCount(traceICs[i].jumpTarget);
|
||||
|
||||
stubCode.patch(traceICs[i].addrLabel, &jitTraceICs[i]);
|
||||
}
|
||||
|
@ -4032,7 +4033,8 @@ mjit::Compiler::iter(uintN flags)
|
|||
/* Test for active iterator. */
|
||||
Address flagsAddr(nireg, offsetof(NativeIterator, flags));
|
||||
masm.load32(flagsAddr, T1);
|
||||
Jump activeIterator = masm.branchTest32(Assembler::NonZero, T1, Imm32(JSITER_ACTIVE));
|
||||
Jump activeIterator = masm.branchTest32(Assembler::NonZero, T1,
|
||||
Imm32(JSITER_ACTIVE|JSITER_UNREUSABLE));
|
||||
stubcc.linkExit(activeIterator, Uses(1));
|
||||
|
||||
/* Compare shape of object with iterator. */
|
||||
|
@ -4224,9 +4226,8 @@ mjit::Compiler::iterEnd()
|
|||
Address flagAddr(T1, offsetof(NativeIterator, flags));
|
||||
masm.loadPtr(flagAddr, T2);
|
||||
|
||||
/* Test for (flags == ENUMERATE | ACTIVE). */
|
||||
Jump notEnumerate = masm.branch32(Assembler::NotEqual, T2,
|
||||
Imm32(JSITER_ENUMERATE | JSITER_ACTIVE));
|
||||
/* Test for a normal enumerate iterator. */
|
||||
Jump notEnumerate = masm.branchTest32(Assembler::Zero, T2, Imm32(JSITER_ENUMERATE));
|
||||
stubcc.linkExit(notEnumerate, Uses(1));
|
||||
|
||||
/* Clear active bit. */
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
#include "jscntxtinlines.h"
|
||||
#include "jsatominlines.h"
|
||||
#include "StubCalls-inl.h"
|
||||
#include "MethodJIT-inl.h"
|
||||
|
||||
#include "jsautooplen.h"
|
||||
|
||||
|
@ -170,12 +171,7 @@ top:
|
|||
}
|
||||
|
||||
/*
|
||||
* Clean up a frame and return. popFrame indicates whether to additionally pop
|
||||
* the frame and store the return value on the caller's stack. The frame will
|
||||
* normally be popped by the caller on return from a call into JIT code,
|
||||
* so must be popped here when that caller code will not execute. This can be
|
||||
* either because of a call into an un-JITable script, or because the call is
|
||||
* throwing an exception.
|
||||
* Clean up a frame and return.
|
||||
*/
|
||||
static void
|
||||
InlineReturn(VMFrame &f)
|
||||
|
@ -311,8 +307,7 @@ stubs::CompileFunction(VMFrame &f, uint32 nactual)
|
|||
|
||||
/*
|
||||
* FixupArity/RemovePartialFrame expect to be called after the early
|
||||
* prologue. Pass the existing value for ncode, it has already been set
|
||||
* by the jit code calling into this stub.
|
||||
* prologue.
|
||||
*/
|
||||
fp->initCallFrameEarlyPrologue(fun, nactual);
|
||||
|
||||
|
@ -333,7 +328,7 @@ stubs::CompileFunction(VMFrame &f, uint32 nactual)
|
|||
if (fun->isHeavyweight() && !js_GetCallObject(cx, fp))
|
||||
THROWV(NULL);
|
||||
|
||||
CompileStatus status = CanMethodJIT(cx, script, fp);
|
||||
CompileStatus status = CanMethodJIT(cx, script, fp, CompileRequest_JIT);
|
||||
if (status == Compile_Okay)
|
||||
return script->getJIT(fp->isConstructing())->invokeEntry;
|
||||
|
||||
|
@ -348,7 +343,7 @@ stubs::CompileFunction(VMFrame &f, uint32 nactual)
|
|||
}
|
||||
|
||||
static inline bool
|
||||
UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, uint32 argc)
|
||||
UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, bool *unjittable, uint32 argc)
|
||||
{
|
||||
JSContext *cx = f.cx;
|
||||
Value *vp = f.regs.sp - (argc + 2);
|
||||
|
@ -363,8 +358,6 @@ UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, uint32 argc)
|
|||
f.entryfp, &f.stackLimit);
|
||||
if (JS_UNLIKELY(!newfp))
|
||||
return false;
|
||||
JS_ASSERT_IF(!vp[1].isPrimitive() && !(flags & JSFRAME_CONSTRUCTING),
|
||||
IsSaneThisObject(vp[1].toObject()));
|
||||
|
||||
/* Initialize frame, locals. */
|
||||
newfp->initCallFrame(cx, callee, newfun, argc, flags);
|
||||
|
@ -380,11 +373,14 @@ UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, uint32 argc)
|
|||
|
||||
/* Try to compile if not already compiled. */
|
||||
if (newscript->getJITStatus(newfp->isConstructing()) == JITScript_None) {
|
||||
if (mjit::TryCompile(cx, newfp) == Compile_Error) {
|
||||
CompileStatus status = CanMethodJIT(cx, newscript, newfp, CompileRequest_Interpreter);
|
||||
if (status == Compile_Error) {
|
||||
/* A runtime exception was thrown, get out. */
|
||||
InlineReturn(f);
|
||||
return false;
|
||||
}
|
||||
if (status == Compile_Abort)
|
||||
*unjittable = true;
|
||||
}
|
||||
|
||||
/* If newscript was successfully compiled, run it. */
|
||||
|
@ -420,7 +416,7 @@ stubs::UncachedNewHelper(VMFrame &f, uint32 argc, UncachedCallResult *ucr)
|
|||
/* Try to do a fast inline call before the general Invoke path. */
|
||||
if (IsFunctionObject(*vp, &ucr->fun) && ucr->fun->isInterpreted()) {
|
||||
ucr->callee = &vp->toObject();
|
||||
if (!UncachedInlineCall(f, JSFRAME_CONSTRUCTING, &ucr->codeAddr, argc))
|
||||
if (!UncachedInlineCall(f, JSFRAME_CONSTRUCTING, &ucr->codeAddr, &ucr->unjittable, argc))
|
||||
THROW();
|
||||
} else {
|
||||
if (!InvokeConstructor(cx, InvokeArgsAlreadyOnTheStack(vp, argc)))
|
||||
|
@ -470,7 +466,7 @@ stubs::UncachedCallHelper(VMFrame &f, uint32 argc, UncachedCallResult *ucr)
|
|||
ucr->fun = GET_FUNCTION_PRIVATE(cx, ucr->callee);
|
||||
|
||||
if (ucr->fun->isInterpreted()) {
|
||||
if (!UncachedInlineCall(f, 0, &ucr->codeAddr, argc))
|
||||
if (!UncachedInlineCall(f, 0, &ucr->codeAddr, &ucr->unjittable, argc))
|
||||
THROW();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#if !defined jsjaeger_logging_h__
|
||||
#if !defined jsjaeger_logging_h__ && (defined JS_METHODJIT || defined JS_TRACER)
|
||||
#define jsjaeger_logging_h__
|
||||
|
||||
#include "prmjtime.h"
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 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 Mozilla SpiderMonkey JavaScript 1.9 code, released
|
||||
* May 28, 2008.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Brendan Eich <brendan@mozilla.org>
|
||||
*
|
||||
* Contributor(s):
|
||||
* David Anderson <danderson@mozilla.com>
|
||||
* David Mandelin <dmandelin@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#if !defined jsjaeger_methodjit_inl_h__ && defined JS_METHODJIT
|
||||
#define jsjaeger_methodjit_inl_h__
|
||||
|
||||
namespace js {
|
||||
namespace mjit {
|
||||
|
||||
enum CompileRequest
|
||||
{
|
||||
CompileRequest_Interpreter,
|
||||
CompileRequest_JIT
|
||||
};
|
||||
|
||||
/* Number of times a script must be called before we run it in the methodjit. */
|
||||
static const size_t CALLS_BEFORE_COMPILE = 16;
|
||||
|
||||
/* Number of loop back-edges we execute in the interpreter before methodjitting. */
|
||||
static const size_t BACKEDGES_BEFORE_COMPILE = 16;
|
||||
|
||||
static inline CompileStatus
|
||||
CanMethodJIT(JSContext *cx, JSScript *script, JSStackFrame *fp, CompileRequest request)
|
||||
{
|
||||
if (!cx->methodJitEnabled)
|
||||
return Compile_Abort;
|
||||
JITScriptStatus status = script->getJITStatus(fp->isConstructing());
|
||||
if (status == JITScript_Invalid)
|
||||
return Compile_Abort;
|
||||
if (request == CompileRequest_Interpreter &&
|
||||
status == JITScript_None &&
|
||||
!cx->hasRunOption(JSOPTION_METHODJIT_ALWAYS) &&
|
||||
script->incCallCount() <= CALLS_BEFORE_COMPILE)
|
||||
{
|
||||
return Compile_Skipped;
|
||||
}
|
||||
if (status == JITScript_None)
|
||||
return TryCompile(cx, fp);
|
||||
return Compile_Okay;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called from a backedge in the interpreter to decide if we should transition to the
|
||||
* methodjit. If so, we compile the given function.
|
||||
*/
|
||||
static inline CompileStatus
|
||||
CanMethodJITAtBranch(JSContext *cx, JSScript *script, JSStackFrame *fp, jsbytecode *pc)
|
||||
{
|
||||
if (!cx->methodJitEnabled)
|
||||
return Compile_Abort;
|
||||
JITScriptStatus status = script->getJITStatus(fp->isConstructing());
|
||||
if (status == JITScript_Invalid)
|
||||
return Compile_Abort;
|
||||
if (status == JITScript_None &&
|
||||
!cx->hasRunOption(JSOPTION_METHODJIT_ALWAYS) &&
|
||||
cx->compartment->incBackEdgeCount(pc) <= BACKEDGES_BEFORE_COMPILE)
|
||||
{
|
||||
return Compile_Skipped;
|
||||
}
|
||||
if (status == JITScript_None)
|
||||
return TryCompile(cx, fp);
|
||||
return Compile_Okay;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -394,7 +394,8 @@ enum CompileStatus
|
|||
{
|
||||
Compile_Okay,
|
||||
Compile_Abort,
|
||||
Compile_Error
|
||||
Compile_Error,
|
||||
Compile_Skipped
|
||||
};
|
||||
|
||||
void JS_FASTCALL
|
||||
|
@ -406,19 +407,6 @@ TryCompile(JSContext *cx, JSStackFrame *fp);
|
|||
void
|
||||
ReleaseScriptCode(JSContext *cx, JSScript *script);
|
||||
|
||||
static inline CompileStatus
|
||||
CanMethodJIT(JSContext *cx, JSScript *script, JSStackFrame *fp)
|
||||
{
|
||||
if (!cx->methodJitEnabled)
|
||||
return Compile_Abort;
|
||||
JITScriptStatus status = script->getJITStatus(fp->isConstructing());
|
||||
if (status == JITScript_Invalid)
|
||||
return Compile_Abort;
|
||||
if (status == JITScript_None)
|
||||
return TryCompile(cx, fp);
|
||||
return Compile_Okay;
|
||||
}
|
||||
|
||||
struct CallSite
|
||||
{
|
||||
uint32 codeOffset;
|
||||
|
|
|
@ -950,7 +950,8 @@ class CallCompiler : public BaseCompiler
|
|||
// If the function cannot be jitted (generally unjittable or empty script),
|
||||
// patch this site to go to a slow path always.
|
||||
if (!ucr.codeAddr) {
|
||||
disable(jit);
|
||||
if (ucr.unjittable)
|
||||
disable(jit);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ void JS_FASTCALL LeaveScript(VMFrame &f);
|
|||
* These functions can have one of two results:
|
||||
*
|
||||
* (1) The function was executed in the interpreter. Then all fields
|
||||
* are NULL.
|
||||
* are NULL except unjittable.
|
||||
*
|
||||
* (2) The function was not executed, and the function has been compiled
|
||||
* to JM native code. Then all fields are non-NULL.
|
||||
|
@ -89,11 +89,13 @@ struct UncachedCallResult {
|
|||
JSObject *callee; // callee object
|
||||
JSFunction *fun; // callee function
|
||||
void *codeAddr; // code address of compiled callee function
|
||||
bool unjittable; // did we try to JIT and fail?
|
||||
|
||||
void init() {
|
||||
callee = NULL;
|
||||
fun = NULL;
|
||||
codeAddr = NULL;
|
||||
unjittable = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -582,6 +582,8 @@ usage(void)
|
|||
" -i Enable interactive read-eval-print loop\n"
|
||||
" -j Enable the TraceMonkey tracing JIT\n"
|
||||
" -m Enable the JaegerMonkey method JIT\n"
|
||||
" -a Always method JIT, ignore internal tuning\n"
|
||||
" This only has effect with -m\n"
|
||||
" -p Enable loop profiling for TraceMonkey\n"
|
||||
" -d Enable debug mode\n"
|
||||
" -b Print timing statistics\n"
|
||||
|
@ -634,9 +636,10 @@ static const struct {
|
|||
} js_options[] = {
|
||||
{"anonfunfix", JSOPTION_ANONFUNFIX},
|
||||
{"atline", JSOPTION_ATLINE},
|
||||
{"jitprofiling", JSOPTION_PROFILING},
|
||||
{"tracejit", JSOPTION_JIT},
|
||||
{"methodjit", JSOPTION_METHODJIT},
|
||||
{"jitprofiling", JSOPTION_PROFILING},
|
||||
{"methodjit_always",JSOPTION_METHODJIT_ALWAYS},
|
||||
{"relimit", JSOPTION_RELIMIT},
|
||||
{"strict", JSOPTION_STRICT},
|
||||
{"werror", JSOPTION_WERROR},
|
||||
|
@ -807,6 +810,10 @@ ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc)
|
|||
JS_ToggleOptions(cx, JSOPTION_METHODJIT);
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
JS_ToggleOptions(cx, JSOPTION_METHODJIT_ALWAYS);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
enableProfiling = !enableProfiling;
|
||||
JS_ToggleOptions(cx, JSOPTION_PROFILING);
|
||||
|
|
|
@ -25,3 +25,11 @@ skip-if(!xulRuntime.shell) script clone-errors.js
|
|||
skip-if(!xulRuntime.shell) script clone-forge.js
|
||||
script set-property-non-extensible.js
|
||||
script recursion.js
|
||||
script regress-627984-1.js
|
||||
script regress-627984-2.js
|
||||
script regress-627984-3.js
|
||||
script regress-627984-4.js
|
||||
script regress-627984-5.js
|
||||
script regress-627984-6.js
|
||||
script regress-627984-7.js
|
||||
script regress-631723.js
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
// See bug 627984, comment 17, item 1.
|
||||
var obj;
|
||||
var methods = [];
|
||||
for (var i = 0; i < 2; i++) {
|
||||
obj = {m: function () { return this.x; }};
|
||||
obj.watch("m", function (id, oldval, newval) { methods[i] = oldval; });
|
||||
obj.m = 0;
|
||||
}
|
||||
assertEq(typeof methods[0], "function");
|
||||
assertEq(typeof methods[1], "function");
|
||||
assertEq(methods[0] !== methods[1], true);
|
||||
|
||||
reportCompare(0, 0, 'ok');
|
|
@ -0,0 +1,15 @@
|
|||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
// See bug 627984, comment 17, item 2.
|
||||
var obj = {};
|
||||
var x;
|
||||
obj.watch("m", function (id, oldval, newval) {
|
||||
x = this.m;
|
||||
return newval;
|
||||
});
|
||||
delete obj.m;
|
||||
obj.m = function () { return this.method; };
|
||||
obj.m = 2;
|
||||
|
||||
reportCompare(0, 0, 'ok');
|
|
@ -0,0 +1,14 @@
|
|||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
// Don't write string value to method slot.
|
||||
// See bug 627984, comment 17, item 2.
|
||||
var obj = {};
|
||||
obj.watch("m", function (id, oldval, newval) {
|
||||
return 'ok';
|
||||
});
|
||||
delete obj.m;
|
||||
obj.m = function () { return this.x; };
|
||||
assertEq(obj.m, 'ok');
|
||||
|
||||
reportCompare(0, 0, 'ok');
|
|
@ -0,0 +1,15 @@
|
|||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
// See bug 627984, comment 17, item 3.
|
||||
var obj = {};
|
||||
obj.watch("m", function (id, oldval, newval) {
|
||||
delete obj.m;
|
||||
obj.m = function () {};
|
||||
return newval;
|
||||
});
|
||||
delete obj.m;
|
||||
obj.m = 1;
|
||||
assertEq(obj.m, 1);
|
||||
|
||||
reportCompare(0, 0, 'ok');
|
|
@ -0,0 +1,13 @@
|
|||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
// Bug 627984 comment 11.
|
||||
var o = ({});
|
||||
o.p = function() {};
|
||||
o.watch('p', function() { });
|
||||
o.q = function() {}
|
||||
delete o.p;
|
||||
o.p = function() {};
|
||||
assertEq(o.p, void 0);
|
||||
|
||||
reportCompare(0, 0, 'ok');
|
|
@ -0,0 +1,15 @@
|
|||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
// Bug 627984 description.
|
||||
var o = Array;
|
||||
o.p = function() {};
|
||||
o.watch('p', function() { });
|
||||
for(var x in o) {
|
||||
o[x];
|
||||
}
|
||||
delete o.p;
|
||||
o.p = function() {};
|
||||
assertEq(o.p, void 0);
|
||||
|
||||
reportCompare(0, 0, 'ok');
|
|
@ -0,0 +1,9 @@
|
|||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
// See bug 627984 comment 20.
|
||||
var obj = {m: function () {}};
|
||||
obj.watch("m", function () { throw 'FAIL'; });
|
||||
var f = obj.m; // don't call the watchpoint
|
||||
|
||||
reportCompare(0, 0, 'ok');
|
|
@ -0,0 +1,10 @@
|
|||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
var o = {a:1, b:2};
|
||||
o.watch("p", function() { return 13; });
|
||||
delete o.p;
|
||||
o.p = 0;
|
||||
assertEq(o.p, 13);
|
||||
|
||||
reportCompare(0, 0, 'ok');
|
|
@ -650,7 +650,8 @@ function optionsClear() {
|
|||
if (optionName &&
|
||||
optionName != "methodjit" &&
|
||||
optionName != "tracejit" &&
|
||||
optionName != "jitprofiling")
|
||||
optionName != "jitprofiling" &&
|
||||
optionName != "methodjit_always")
|
||||
{
|
||||
options(optionName);
|
||||
}
|
||||
|
|
|
@ -33,5 +33,6 @@ user_pref("javascript.options.methodjit.chrome", false);
|
|||
user_pref("javascript.options.methodjit.content", true);
|
||||
user_pref("javascript.options.jitprofiling.chrome", false);
|
||||
user_pref("javascript.options.jitprofiling.content", true);
|
||||
user_pref("javascript.options.methodjit_always", false);
|
||||
user_pref("javascript.options.strict", false);
|
||||
user_pref("javascript.options.werror", false);
|
||||
|
|
|
@ -1322,6 +1322,9 @@ ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc)
|
|||
case 'm':
|
||||
JS_ToggleOptions(cx, JSOPTION_METHODJIT);
|
||||
break;
|
||||
case 'p':
|
||||
JS_ToggleOptions(cx, JSOPTION_PROFILING);
|
||||
break;
|
||||
default:
|
||||
return usage();
|
||||
}
|
||||
|
|
|
@ -83,6 +83,7 @@ _TEST_FILES = bug500931_helper.html \
|
|||
test_bug629331.html \
|
||||
test1_bug629331.html \
|
||||
test2_bug629331.html \
|
||||
test_bug618017.html \
|
||||
$(NULL)
|
||||
|
||||
#test_bug484107.html \
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=618017
|
||||
|
||||
Parsing XML must not override the version.
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 618017</title>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<script type='application/javascript;version=1.7'>
|
||||
let x = 12;
|
||||
function doLetEval() {
|
||||
ok(eval('let x = 13; x') === 13, 'let statement is valid syntax in version 1.7');
|
||||
}
|
||||
</script>
|
||||
<script type='application/javascript;version=1.5'>
|
||||
ok(uneval(<test />) === '<test/>', 'xml can be parsed in any version');
|
||||
doLetEval(); // Call to a function with a different version.
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -184,11 +184,12 @@ WrapperFactory::PrepareForWrapping(JSContext *cx, JSObject *scope, JSObject *obj
|
|||
if (!wn->GetClassInfo())
|
||||
return DoubleWrap(cx, obj, flags);
|
||||
|
||||
JSAutoEnterCompartment ac;
|
||||
if (!ac.enter(cx, obj))
|
||||
return nsnull;
|
||||
XPCCallContext ccx(JS_CALLER, cx, obj);
|
||||
|
||||
{
|
||||
JSAutoEnterCompartment ac;
|
||||
if (!ac.enter(cx, obj))
|
||||
return nsnull;
|
||||
XPCCallContext ccx(JS_CALLER, cx, obj);
|
||||
if (NATIVE_HAS_FLAG(&ccx, WantPreCreate)) {
|
||||
// We have a precreate hook. This object might enforce that we only
|
||||
// ever create JS object for it.
|
||||
|
@ -211,16 +212,12 @@ WrapperFactory::PrepareForWrapping(JSContext *cx, JSObject *scope, JSObject *obj
|
|||
}
|
||||
}
|
||||
|
||||
// The object we're looking at might allow us to create a new wrapped
|
||||
// native in the new scope. Try it and continue wrapping on the
|
||||
// possibly-new object.
|
||||
JSAutoEnterCompartment ac;
|
||||
if (!ac.enter(cx, scope))
|
||||
return nsnull;
|
||||
|
||||
// NB: Passing a holder here inhibits slim wrappers under
|
||||
// WrapNativeToJSVal.
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
|
||||
|
||||
// This public WrapNativeToJSVal API enters the compartment of 'scope'
|
||||
// so we don't have to.
|
||||
jsval v;
|
||||
nsresult rv =
|
||||
nsXPConnect::FastGetXPConnect()->WrapNativeToJSVal(cx, scope, wn->Native(), nsnull,
|
||||
|
|
|
@ -604,6 +604,7 @@ pref("javascript.options.methodjit.content", true);
|
|||
pref("javascript.options.methodjit.chrome", false);
|
||||
pref("javascript.options.jitprofiling.content", true);
|
||||
pref("javascript.options.jitprofiling.chrome", false);
|
||||
pref("javascript.options.methodjit_always", false);
|
||||
// This preference limits the memory usage of javascript.
|
||||
// If you want to change these values for your device,
|
||||
// please find Bug 417052 comment 17 and Bug 456721
|
||||
|
|
Загрузка…
Ссылка в новой задаче