diff --git a/js/src/jit-test/tests/gc/bug-886630.js b/js/src/jit-test/tests/gc/bug-886630.js new file mode 100644 index 00000000000..e7d7203fe6a --- /dev/null +++ b/js/src/jit-test/tests/gc/bug-886630.js @@ -0,0 +1,112 @@ +function errorToString(e) { + try {} catch (e2) {} +} +Object.getOwnPropertyNames(this); +if (false) { + for (let x of constructors) + print(x); +} +var tryRunning = tryRunningDirectly; +function unlikelyToHang(code) { + var codeL = code.replace(/\s/g, " "); + return true && code.indexOf("infloop") == -1 && !(codeL.match(/const.*for/)) // can be an infinite loop: function() { const x = 1; for each(x in ({a1:1})) dumpln(3); } + && !(codeL.match(/for.*const/)) // can be an infinite loop: for each(x in ...); const x; + && !(codeL.match(/for.*in.*uneval/)) // can be slow to loop through the huge string uneval(this), for example + && !(codeL.match(/for.*for.*for/)) // nested for loops (including for..in, array comprehensions, etc) can take a while + && !(codeL.match(/for.*for.*gc/)) +} +function whatToTestSpidermonkeyTrunk(code) { + var codeL = code.replace(/\s/g, " "); + return { + allowParse: true, + allowExec: unlikelyToHang(code), + allowIter: true, + expectConsistentOutput: true && code.indexOf("Date") == -1 // time marches on + && code.indexOf("random") == -1 && code.indexOf("dumpObject") == -1 // shows heap addresses + && code.indexOf("oomAfterAllocations") == -1 && code.indexOf("ParallelArray") == -1, + expectConsistentOutputAcrossIter: true && code.indexOf("options") == -1 // options() is per-cx, and the js shell doesn't create a new cx for each sandbox/compartment + , + expectConsistentOutputAcrossJITs: true && code.indexOf("'strict") == -1 // bug 743425 + && code.indexOf("preventExtensions") == -1 // bug 887521 + && !(codeL.match(/\/.*[\u0000\u0080-\uffff]/)) // doesn't stay valid utf-8 after going through python (?) + }; +} +function tryRunningDirectly(f, code, wtt) { + try { + eval(code); + } catch (e) {} + try { + var rv = f(); + tryIteration(rv); + } catch (runError) { + var err = errorToString(runError); + } + tryEnsureSanity(); +} +var realEval = eval; +var realMath = Math; +var realFunction = Function; +var realGC = gc; +var realUneval = uneval; +function tryEnsureSanity() { + try { + delete this.Math; + delete this.Function; + delete this.gc; + delete this.uneval; + this.Math = realMath; + this.eval = realEval; + this.Function = realFunction; + this.gc = realGC; + this.uneval = realUneval; + } catch (e) {} +} +function tryIteration(rv) { + try { + var iterCount = 0; + for /* each */ + ( /* let */ iterValue in rv) + print("Iterating succeeded, iterCount == " + iterCount); + } catch (iterError) {} +} +function failsToCompileInTry(code) { + try { + new Function(" try { " + code + " } catch(e) { }"); + } catch (e) {} +} +function tryItOut(code) { + if (count % 1000 == 0) { + gc(); + } + var wtt = whatToTestSpidermonkeyTrunk(code); + code = code.replace(/\/\*DUPTRY\d+\*\//, function(k) { + var n = parseInt(k.substr(8), 10); + print(n); + return strTimes("try{}catch(e){}", n); + }) + try { + f = new Function(code); + } catch (compileError) {} + if (code.indexOf("\n") == -1 && code.indexOf("\r") == -1 && code.indexOf("\f") == -1 && code.indexOf("\0") == -1 && code.indexOf("\u2028") == -1 && code.indexOf("\u2029") == -1 && code.indexOf("<--") == -1 && code.indexOf("-->") == -1 && code.indexOf("//") == -1) { + var nCode = code; + if (nCode.indexOf("return") != -1 || nCode.indexOf("yield") != -1 || nCode.indexOf("const") != -1 || failsToCompileInTry(nCode)) nCode = "(function(){" + nCode + "})()" + } + tryRunning(f, code, false); +} +var count = 0; +tryItOut(""); +count = 2 +tryItOut(""); +tryItOut(""); +tryItOut("o") +tryItOut("") +tryItOut("") +tryItOut("\ + with((/ /-7))\ + {\ + for(let mjcpxc=0;mjcpxc<9;++mjcpxc)\ + {\ + e=mjcpxc;\ + yield/x/\ + }}") + diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 1bf49c28453..d82fb03b19b 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -1356,6 +1356,14 @@ GeneratorWriteBarrierPre(JSContext *cx, JSGenerator *gen) MarkGeneratorFrame(zone->barrierTracer(), gen); } +static void +GeneratorWriteBarrierPost(JSContext *cx, JSGenerator *gen) +{ +#ifdef JSGC_GENERATIONAL + cx->runtime()->gcStoreBuffer.putWholeCell(gen->obj); +#endif +} + /* * Only mark generator frames/slots when the generator is not active on the * stack or closed. Barriers when copying onto the stack or closing preserve @@ -1588,6 +1596,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, HandleObject obj, JS_ASSERT(op != JSGENOP_CLOSE); gen->fp->clearYielding(); gen->state = JSGEN_OPEN; + GeneratorWriteBarrierPost(cx, gen); return ok; }