Backout bea3f06585ec (Bug 969012) for arm simulator failures.

This commit is contained in:
Terrence Cole 2014-02-17 19:22:34 -08:00
parent 7c5f729399
commit 7314440257
31 changed files with 386 additions and 785 deletions

View File

@ -257,28 +257,6 @@ MinorGC(JSContext *cx, unsigned argc, jsval *vp)
return true;
}
static bool
DisableGGC(JSContext *cx, unsigned argc, jsval *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
#ifdef JSGC_GENERATIONAL
JS::DisableGenerationalGC(cx->runtime());
#endif
args.rval().setUndefined();
return true;
}
static bool
EnableGGC(JSContext *cx, unsigned argc, jsval *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
#ifdef JSGC_GENERATIONAL
JS::EnableGenerationalGC(cx->runtime());
#endif
args.rval().setUndefined();
return true;
}
static const struct ParamPair {
const char *name;
JSGCParamKey param;
@ -1451,15 +1429,6 @@ static const JSFunctionSpecWithHelp TestingFunctions[] = {
" Run a minor collector on the Nursery. When aboutToOverflow is true, marks\n"
" the store buffer as about-to-overflow before collecting."),
JS_FN_HELP("disableGenerationalGC", ::DisableGGC, 0, 0,
"disableGenerationalGC()",
" In builds with support for generational GC, disable generational GC."),
JS_FN_HELP("enableGenerationalGC", ::EnableGGC, 0, 0,
"enableGenerationalGC()",
" In builds with support for generational GC, re-enable a disabled\n"
" generational GC."),
JS_FN_HELP("gcparam", GCParameter, 2, 0,
"gcparam(name [, value])",
" Wrapper for JS_[GS]etGCParameter. The name is one of " GC_PARAMETER_ARGS_LIST),

View File

@ -268,14 +268,20 @@ js::Nursery::allocateHugeSlots(JSContext *cx, size_t nslots)
return slots;
}
void
js::Nursery::notifyInitialSlots(Cell *cell, HeapSlot *slots)
{
if (isInside(cell) && !isInside(slots)) {
/* If this put fails, we will only leak the slots. */
(void)hugeSlots.put(slots);
}
}
void
js::Nursery::notifyNewElements(gc::Cell *cell, ObjectElements *elements)
{
JS_ASSERT(!isInside(elements));
if (isInside(cell)) {
/* If this put fails, we will only leak the slots. */
(void)hugeSlots.put(reinterpret_cast<HeapSlot *>(elements));
}
notifyInitialSlots(cell, reinterpret_cast<HeapSlot *>(elements));
}
void

View File

@ -54,9 +54,6 @@ class Nursery
static const size_t Alignment = gc::ChunkSize;
static const size_t NurserySize = gc::ChunkSize * NumNurseryChunks;
/* The maximum number of slots allowed to reside inline in the nursery. */
static const size_t MaxNurserySlots = 128;
explicit Nursery(JSRuntime *rt)
: runtime_(rt),
position_(0),
@ -104,6 +101,9 @@ class Nursery
/* Free a slots array. */
void freeSlots(JSContext *cx, HeapSlot *slots);
/* Add a slots to our tracking list if it is out-of-line. */
void notifyInitialSlots(gc::Cell *cell, HeapSlot *slots);
/* Add elements to our tracking list if it is out-of-line. */
void notifyNewElements(gc::Cell *cell, ObjectElements *elements);
@ -182,6 +182,9 @@ class Nursery
typedef HashSet<HeapSlot *, PointerHasher<HeapSlot *, 3>, SystemAllocPolicy> HugeSlotsSet;
HugeSlotsSet hugeSlots;
/* The maximum number of slots allowed to reside inline in the nursery. */
static const size_t MaxNurserySlots = 128;
/* The amount of space in the mapped nursery available to allocations. */
static const size_t NurseryChunkUsableSize = gc::ChunkSize - sizeof(gc::ChunkTrailer);

View File

@ -2,7 +2,7 @@
function f(y) {}
for each(let e in newGlobal()) {
if (e.name === "quit" || e.name == "readline" || e.name == "terminate" ||
e.name == "nestedShell" || e.name.endsWith("ableGenerationalGC"))
e.name == "nestedShell")
continue;
try {
e();
@ -15,7 +15,7 @@ for each(let e in newGlobal()) {
}
for each(b in []) {
if (b.name === "quit" || b.name == "readline" || b.name == "terminate" ||
b.name == "nestedShell" || b.name.endsWith("ableGenerationalGC"))
b.name == "nestedShell")
continue;
try {
f(b)

View File

@ -1,308 +0,0 @@
// |jit-test| tz-pacific
// This is a copy of date-format-tofte: one of the only current jit-tests that
// exercises CallObject creation with external slots. We disable GGC here to
// test the fallback path that gets excercised without it enabled.
disableGenerationalGC();
function arrayExists(array, x) {
for (var i = 0; i < array.length; i++) {
if (array[i] == x) return true;
}
return false;
}
Date.prototype.formatDate = function (input,time) {
// formatDate :
// a PHP date like function, for formatting date strings
// See: http://www.php.net/date
//
// input : format string
// time : epoch time (seconds, and optional)
//
// if time is not passed, formatting is based on
// the current "this" date object's set time.
//
// supported:
// a, A, B, d, D, F, g, G, h, H, i, j, l (lowercase L), L,
// m, M, n, O, r, s, S, t, U, w, W, y, Y, z
//
// unsupported:
// I (capital i), T, Z
var switches = ["a", "A", "B", "d", "D", "F", "g", "G", "h", "H",
"i", "j", "l", "L", "m", "M", "n", "O", "r", "s",
"S", "t", "U", "w", "W", "y", "Y", "z"];
var daysLong = ["Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"];
var daysShort = ["Sun", "Mon", "Tue", "Wed",
"Thu", "Fri", "Sat"];
var monthsShort = ["Jan", "Feb", "Mar", "Apr",
"May", "Jun", "Jul", "Aug", "Sep",
"Oct", "Nov", "Dec"];
var monthsLong = ["January", "February", "March", "April",
"May", "June", "July", "August", "September",
"October", "November", "December"];
var daysSuffix = ["st", "nd", "rd", "th", "th", "th", "th", // 1st - 7th
"th", "th", "th", "th", "th", "th", "th", // 8th - 14th
"th", "th", "th", "th", "th", "th", "st", // 15th - 21st
"nd", "rd", "th", "th", "th", "th", "th", // 22nd - 28th
"th", "th", "st"]; // 29th - 31st
function a() {
// Lowercase Ante meridiem and Post meridiem
return self.getHours() > 11? "pm" : "am";
}
function A() {
// Uppercase Ante meridiem and Post meridiem
return self.getHours() > 11? "PM" : "AM";
}
function B(){
// Swatch internet time. code simply grabbed from ppk,
// since I was feeling lazy:
// http://www.xs4all.nl/~ppk/js/beat.html
var off = (self.getTimezoneOffset() + 60)*60;
var theSeconds = (self.getHours() * 3600) +
(self.getMinutes() * 60) +
self.getSeconds() + off;
var beat = Math.floor(theSeconds/86.4);
if (beat > 1000) beat -= 1000;
if (beat < 0) beat += 1000;
if ((""+beat).length == 1) beat = "00"+beat;
if ((""+beat).length == 2) beat = "0"+beat;
return beat;
}
function d() {
// Day of the month, 2 digits with leading zeros
return new String(self.getDate()).length == 1?
"0"+self.getDate() : self.getDate();
}
function D() {
// A textual representation of a day, three letters
return daysShort[self.getDay()];
}
function F() {
// A full textual representation of a month
return monthsLong[self.getMonth()];
}
function g() {
// 12-hour format of an hour without leading zeros
return self.getHours() > 12? self.getHours()-12 : self.getHours();
}
function G() {
// 24-hour format of an hour without leading zeros
return self.getHours();
}
function h() {
// 12-hour format of an hour with leading zeros
if (self.getHours() > 12) {
var s = new String(self.getHours()-12);
return s.length == 1?
"0"+ (self.getHours()-12) : self.getHours()-12;
} else {
var s = new String(self.getHours());
return s.length == 1?
"0"+self.getHours() : self.getHours();
}
}
function H() {
// 24-hour format of an hour with leading zeros
return new String(self.getHours()).length == 1?
"0"+self.getHours() : self.getHours();
}
function i() {
// Minutes with leading zeros
return new String(self.getMinutes()).length == 1?
"0"+self.getMinutes() : self.getMinutes();
}
function j() {
// Day of the month without leading zeros
return self.getDate();
}
function l() {
// A full textual representation of the day of the week
return daysLong[self.getDay()];
}
function L() {
// leap year or not. 1 if leap year, 0 if not.
// the logic should match iso's 8601 standard.
var y_ = Y();
if (
(y_ % 4 == 0 && y_ % 100 != 0) ||
(y_ % 4 == 0 && y_ % 100 == 0 && y_ % 400 == 0)
) {
return 1;
} else {
return 0;
}
}
function m() {
// Numeric representation of a month, with leading zeros
return self.getMonth() < 9?
"0"+(self.getMonth()+1) :
self.getMonth()+1;
}
function M() {
// A short textual representation of a month, three letters
return monthsShort[self.getMonth()];
}
function n() {
// Numeric representation of a month, without leading zeros
return self.getMonth()+1;
}
function O() {
// Difference to Greenwich time (GMT) in hours
var os = Math.abs(self.getTimezoneOffset());
var h = ""+Math.floor(os/60);
var m = ""+(os%60);
h.length == 1? h = "0"+h:1;
m.length == 1? m = "0"+m:1;
return self.getTimezoneOffset() < 0 ? "+"+h+m : "-"+h+m;
}
function r() {
// RFC 822 formatted date
var r; // result
// Thu , 21 Dec 2000
r = D() + ", " + j() + " " + M() + " " + Y() +
// 16 : 01 : 07 +0200
" " + H() + ":" + i() + ":" + s() + " " + O();
return r;
}
function S() {
// English ordinal suffix for the day of the month, 2 characters
return daysSuffix[self.getDate()-1];
}
function s() {
// Seconds, with leading zeros
return new String(self.getSeconds()).length == 1?
"0"+self.getSeconds() : self.getSeconds();
}
function t() {
// thanks to Matt Bannon for some much needed code-fixes here!
var daysinmonths = [null,31,28,31,30,31,30,31,31,30,31,30,31];
if (L()==1 && n()==2) return 29; // leap day
return daysinmonths[n()];
}
function U() {
// Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)
return Math.round(self.getTime()/1000);
}
function W() {
// Weeknumber, as per ISO specification:
// http://www.cl.cam.ac.uk/~mgk25/iso-time.html
// if the day is three days before newyears eve,
// there's a chance it's "week 1" of next year.
// here we check for that.
var beforeNY = 364+L() - z();
var afterNY = z();
var weekday = w()!=0?w()-1:6; // makes sunday (0), into 6.
if (beforeNY <= 2 && weekday <= 2-beforeNY) {
return 1;
}
// similarly, if the day is within threedays of newyears
// there's a chance it belongs in the old year.
var ny = new Date("January 1 " + Y() + " 00:00:00");
var nyDay = ny.getDay()!=0?ny.getDay()-1:6;
if (
(afterNY <= 2) &&
(nyDay >=4) &&
(afterNY >= (6-nyDay))
) {
// Since I'm not sure we can just always return 53,
// i call the function here again, using the last day
// of the previous year, as the date, and then just
// return that week.
var prevNY = new Date("December 31 " + (Y()-1) + " 00:00:00");
return prevNY.formatDate("W");
}
// week 1, is the week that has the first thursday in it.
// note that this value is not zero index.
if (nyDay <= 3) {
// first day of the year fell on a thursday, or earlier.
return 1 + Math.floor( ( z() + nyDay ) / 7 );
} else {
// first day of the year fell on a friday, or later.
return 1 + Math.floor( ( z() - ( 7 - nyDay ) ) / 7 );
}
}
function w() {
// Numeric representation of the day of the week
return self.getDay();
}
function Y() {
// A full numeric representation of a year, 4 digits
// we first check, if getFullYear is supported. if it
// is, we just use that. ppks code is nice, but wont
// work with dates outside 1900-2038, or something like that
if (self.getFullYear) {
var newDate = new Date("January 1 2001 00:00:00 +0000");
var x = newDate .getFullYear();
if (x == 2001) {
// i trust the method now
return self.getFullYear();
}
}
// else, do this:
// codes thanks to ppk:
// http://www.xs4all.nl/~ppk/js/introdate.html
var x = self.getYear();
var y = x % 100;
y += (y < 38) ? 2000 : 1900;
return y;
}
function y() {
// A two-digit representation of a year
var y = Y()+"";
return y.substring(y.length-2,y.length);
}
function z() {
// The day of the year, zero indexed! 0 through 366
var t = new Date("January 1 " + Y() + " 00:00:00");
var diff = self.getTime() - t.getTime();
return Math.floor(diff/1000/60/60/24);
}
var self = this;
if (time) {
// save time
var prevTime = self.getTime();
self.setTime(time);
}
var ia = input.split("");
var ij = 0;
while (ia[ij]) {
if (ia[ij] == "\\") {
// this is our way of allowing users to escape stuff
ia.splice(ij,1);
} else {
if (arrayExists(switches,ia[ij])) {
ia[ij] = eval(ia[ij] + "()");
}
}
ij++;
}
// reset time, back to what it was
if (prevTime) {
self.setTime(prevTime);
}
return ia.join("");
}
var date = new Date("1/1/2007 1:11:11");
var ret = "";
for (i = 0; i < 10; ++i) {
var shortFormat = date.formatDate("Y-m-d");
var longFormat = date.formatDate("l, F d, Y g:i:s A");
ret += shortFormat + longFormat;
date.setTime(date.getTime() + 84266956);
}
var expected = "2007-01-01Monday, January 01, 2007 1:11:11 AM2007-01-02Tuesday, January 02, 2007 0:35:37 AM2007-01-03Wednesday, January 03, 2007 0:00:04 AM2007-01-03Wednesday, January 03, 2007 11:24:31 PM2007-01-04Thursday, January 04, 2007 10:48:58 PM2007-01-05Friday, January 05, 2007 10:13:25 PM2007-01-06Saturday, January 06, 2007 9:37:52 PM2007-01-07Sunday, January 07, 2007 9:02:19 PM2007-01-08Monday, January 08, 2007 8:26:46 PM2007-01-09Tuesday, January 09, 2007 7:51:13 PM";
assertEq(ret, expected);

View File

@ -3,6 +3,15 @@ load(libdir + "parallelarray-helpers.js");
function testClosureCreationAndInvocation() {
var a = range(0, 64);
function makeaddv(v) {
var u = 1;
var t = 2;
var s = 3;
var r = 4;
var q = 5;
var p = 6;
var o = 7;
var n = 8;
var m = 9;
var l = 10;
var k = 11;
var j = 12;
@ -25,6 +34,11 @@ function testClosureCreationAndInvocation() {
case 6: return g; case 7: return h;
case 8: return i; case 9: return j;
case 10: return k; case 11: return l;
case 12: return m; case 13: return n;
case 14: return o; case 15: return p;
case 16: return q; case 17: return r;
case 18: return s; case 19: return t;
case 20: return u;
}
});
}

View File

@ -3,6 +3,15 @@ load(libdir + "parallelarray-helpers.js");
function testClosureCreationAndInvocation() {
var a = range(0, 64);
function makeaddv(v) {
var u = 1;
var t = 2;
var s = 3;
var r = 4;
var q = 5;
var p = 6;
var o = 7;
var n = 8;
var m = 9;
var l = 10;
var k = 11;
var j = 12;
@ -23,6 +32,11 @@ function testClosureCreationAndInvocation() {
case 6: return g; case 7: return h;
case 8: return i; case 9: return j;
case 10: return k; case 11: return l;
case 12: return m; case 13: return n;
case 14: return o; case 15: return p;
case 16: return q; case 17: return r;
case 18: return s; case 19: return t;
case 20: return u;
}
};
};

View File

@ -142,133 +142,6 @@ MNewStringObject::templateObj() const {
return &templateObj_->as<StringObject>();
}
// API call to malloc for slots.
class OutOfLineMallocSlots : public OutOfLineCodeBase<CodeGenerator>
{
const Register result_;
int32_t nDynamicSlots_;
Label *failure_;
public:
OutOfLineMallocSlots(const Register &result, size_t nslots, Label *failure)
: result_(result), nDynamicSlots_(int32_t(nslots)), failure_(failure)
{
JS_ASSERT(nslots < INT32_MAX);
}
bool accept(CodeGenerator *codegen) {
return codegen->visitOutOfLineMallocSlots(this);
}
const Register &result() const {
return result_;
}
int32_t numDynamicSlots() const {
return nDynamicSlots_;
}
Label *failure() const {
return failure_;
}
};
bool
CodeGenerator::visitOutOfLineMallocSlots(OutOfLineMallocSlots *ool)
{
saveVolatile(ool->result());
RegisterSet regs = RegisterSet::Volatile();
regs.takeUnchecked(ool->result());
Register regRuntime = regs.takeGeneral();
Register regNSlots = regs.takeGeneral();
masm.setupUnalignedABICall(2, ool->result());
masm.movePtr(ImmPtr(GetIonContext()->runtime), regRuntime);
masm.passABIArg(regRuntime);
masm.move32(Imm32(uint32_t(ool->numDynamicSlots())), regNSlots);
masm.passABIArg(regNSlots);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, NewSlots));
masm.storeCallResult(ool->result());
restoreVolatile(ool->result());
masm.branchTestPtr(Assembler::Zero, ool->result(), ool->result(), ool->failure());
masm.jump(ool->rejoin());
return true;
}
// API call to free slots data on allocation failure.
class OutOfLineFreeSlots : public OutOfLineCodeBase<CodeGenerator>
{
const Register slots_;
Label *fallback_;
public:
OutOfLineFreeSlots(const Register &reg, Label *fallback)
: slots_(reg), fallback_(fallback)
{ }
bool accept(CodeGenerator *codegen) {
return codegen->visitOutOfLineFreeSlots(this);
}
Register slots() const {
return slots_;
}
Label *fallback() const {
return fallback_;
}
};
bool
CodeGenerator::visitOutOfLineFreeSlots(OutOfLineFreeSlots *ool)
{
saveVolatile(ool->slots());
RegisterSet regs = RegisterSet::Volatile();
regs.takeUnchecked(ool->slots());
Register temp = regs.takeGeneral();
masm.setupUnalignedABICall(1, temp);
masm.passABIArg(ool->slots());
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, FreeSlots));
restoreVolatile(ool->slots());
masm.jump(ool->fallback());
return true;
}
// Emit out-of-line code to provide malloc and free paths to allocate slots for
// objects that require them. In the case that such paths are not required, the
// given labels are returned as nullptr.
bool
CodeGenerator::emitOutOfLineMallocFree(const Register &reg, size_t nDynamicSlots,
Label *fallback, Label **mallocEntry, Label **mallocRejoin,
Label **freeEntry)
{
*mallocEntry = nullptr;
*mallocRejoin = nullptr;
*freeEntry = nullptr;
if (!nDynamicSlots)
return true;
OutOfLineMallocSlots *oolMalloc = new(alloc()) OutOfLineMallocSlots(reg, nDynamicSlots, fallback);
if (!addOutOfLineCode(oolMalloc))
return false;
OutOfLineFreeSlots *oolFree = new(alloc()) OutOfLineFreeSlots(reg, fallback);
if (!addOutOfLineCode(oolFree))
return false;
*mallocEntry = oolMalloc->entry();
*mallocRejoin = oolMalloc->rejoin();
*freeEntry = oolFree->entry();
return true;
}
CodeGenerator::CodeGenerator(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm)
: CodeGeneratorSpecific(gen, graph, masm)
#ifdef DEBUG
@ -1099,8 +972,8 @@ CodeGenerator::visitLambda(LLambda *lir)
JS_ASSERT(!info.singletonType);
masm.newGCObject(output, info.fun, ool->entry(), gc::DefaultHeap);
masm.initGCObject(output, info.fun);
masm.newGCThing(output, info.fun, ool->entry(), gc::DefaultHeap);
masm.initGCThing(output, info.fun);
emitLambdaInit(output, scopeChain, info);
@ -3487,6 +3360,29 @@ CodeGenerator::visitNewDerivedTypedObject(LNewDerivedTypedObject *lir)
return callVM(CreateDerivedTypedObjInfo, lir);
}
bool
CodeGenerator::visitNewSlots(LNewSlots *lir)
{
Register temp1 = ToRegister(lir->temp1());
Register temp2 = ToRegister(lir->temp2());
Register temp3 = ToRegister(lir->temp3());
Register output = ToRegister(lir->output());
masm.mov(ImmPtr(GetIonContext()->runtime), temp1);
masm.mov(ImmWord(lir->mir()->nslots()), temp2);
masm.setupUnalignedABICall(2, temp3);
masm.passABIArg(temp1);
masm.passABIArg(temp2);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, NewSlots));
masm.testPtr(output, output);
if (!bailoutIf(Assembler::Zero, lir->snapshot()))
return false;
return true;
}
bool CodeGenerator::visitAtan2D(LAtan2D *lir)
{
Register temp = ToRegister(lir->temp());
@ -3534,8 +3430,8 @@ CodeGenerator::visitNewArray(LNewArray *lir)
if (!addOutOfLineCode(ool))
return false;
masm.newGCObject(objReg, templateObject, ool->entry(), lir->mir()->initialHeap());
masm.initGCObject(objReg, templateObject);
masm.newGCThing(objReg, templateObject, ool->entry(), lir->mir()->initialHeap());
masm.initGCThing(objReg, templateObject);
masm.bind(ool->rejoin());
return true;
@ -3611,7 +3507,7 @@ CodeGenerator::visitNewObject(LNewObject *lir)
{
JS_ASSERT(gen->info().executionMode() == SequentialExecution);
Register objReg = ToRegister(lir->output());
JSObject *templateObj = lir->mir()->templateObject();
JSObject *templateObject = lir->mir()->templateObject();
if (lir->mir()->shouldUseVM())
return visitNewObjectVMCall(lir);
@ -3620,8 +3516,8 @@ CodeGenerator::visitNewObject(LNewObject *lir)
if (!addOutOfLineCode(ool))
return false;
masm.newGCObject(objReg, templateObj, ool->entry(), lir->mir()->initialHeap());
masm.initGCObject(objReg, templateObj);
masm.newGCThing(objReg, templateObject, ool->entry(), lir->mir()->initialHeap());
masm.initGCThing(objReg, templateObject);
masm.bind(ool->rejoin());
return true;
@ -3655,46 +3551,53 @@ CodeGenerator::visitNewDeclEnvObject(LNewDeclEnvObject *lir)
if (!ool)
return false;
masm.newGCObject(obj, templateObj, ool->entry(), gc::DefaultHeap);
masm.initGCObject(obj, templateObj);
masm.newGCThing(obj, templateObj, ool->entry(), gc::DefaultHeap);
masm.initGCThing(obj, templateObj);
masm.bind(ool->rejoin());
return true;
}
typedef JSObject *(*NewCallObjectFn)(JSContext *, HandleScript, HandleShape, HandleTypeObject);
static const VMFunction NewCallObjectInfo = FunctionInfo<NewCallObjectFn>(NewCallObject);
typedef JSObject *(*NewCallObjectFn)(JSContext *, HandleScript, HandleShape,
HandleTypeObject, HeapSlot *);
static const VMFunction NewCallObjectInfo =
FunctionInfo<NewCallObjectFn>(NewCallObject);
bool
CodeGenerator::visitNewCallObject(LNewCallObject *lir)
{
Register objReg = ToRegister(lir->output());
Register obj = ToRegister(lir->output());
JSObject *templateObj = lir->mir()->templateObject();
// If we have a template object, we can inline call object creation.
OutOfLineCode *ool =
oolCallVM(NewCallObjectInfo, lir,
(ArgList(), ImmGCPtr(lir->mir()->block()->info().script()),
ImmGCPtr(templateObj->lastProperty()),
ImmGCPtr(templateObj->hasSingletonType() ? nullptr : templateObj->type())),
StoreRegisterTo(objReg));
OutOfLineCode *ool;
if (lir->slots()->isRegister()) {
ool = oolCallVM(NewCallObjectInfo, lir,
(ArgList(), ImmGCPtr(lir->mir()->block()->info().script()),
ImmGCPtr(templateObj->lastProperty()),
ImmGCPtr(templateObj->hasSingletonType() ? nullptr : templateObj->type()),
ToRegister(lir->slots())),
StoreRegisterTo(obj));
} else {
ool = oolCallVM(NewCallObjectInfo, lir,
(ArgList(), ImmGCPtr(lir->mir()->block()->info().script()),
ImmGCPtr(templateObj->lastProperty()),
ImmGCPtr(templateObj->hasSingletonType() ? nullptr : templateObj->type()),
ImmPtr(nullptr)),
StoreRegisterTo(obj));
}
if (!ool)
return false;
Label *mallocEntry, *mallocRejoin, *freeEntry;
if (!emitOutOfLineMallocFree(objReg, templateObj->numDynamicSlots(), ool->entry(),
&mallocEntry, &mallocRejoin, &freeEntry))
{
return false;
}
if (lir->mir()->needsSingletonType()) {
// Objects can only be given singleton types in VM calls.
masm.jump(ool->entry());
} else {
masm.newGCObjectAndSlots(objReg, templateObj, ool->entry(), mallocEntry, mallocRejoin,
freeEntry, gc::DefaultHeap);
masm.initGCObject(objReg, templateObj);
masm.newGCThing(obj, templateObj, ool->entry(), gc::DefaultHeap);
masm.initGCThing(obj, templateObj);
if (lir->slots()->isRegister())
masm.storePtr(ToRegister(lir->slots()), Address(obj, JSObject::offsetOfSlots()));
}
masm.bind(ool->rejoin());
@ -3711,6 +3614,17 @@ CodeGenerator::visitNewCallObjectPar(LNewCallObjectPar *lir)
JSObject *templateObj = lir->mir()->templateObj();
emitAllocateGCThingPar(lir, resultReg, cxReg, tempReg1, tempReg2, templateObj);
// NB: !lir->slots()->isRegister() implies that there is no slots
// array at all, and the memory is already zeroed when copying
// from the template object
if (lir->slots()->isRegister()) {
Register slotsReg = ToRegister(lir->slots());
JS_ASSERT(slotsReg != resultReg);
masm.storePtr(slotsReg, Address(resultReg, JSObject::offsetOfSlots()));
}
return true;
}
@ -3734,7 +3648,7 @@ CodeGenerator::visitNewDenseArrayPar(LNewDenseArrayPar *lir)
// reality, we should probably just have the C helper also
// *allocate* the array, but that would require that it initialize
// the various fields of the object, and I didn't want to
// duplicate the code in initGCObject() that already does such an
// duplicate the code in initGCThing() that already does such an
// admirable job.
masm.setupUnalignedABICall(3, tempReg0);
masm.passABIArg(cxReg);
@ -3769,8 +3683,8 @@ CodeGenerator::visitNewStringObject(LNewStringObject *lir)
if (!ool)
return false;
masm.newGCObject(output, templateObj, ool->entry(), gc::DefaultHeap);
masm.initGCObject(output, templateObj);
masm.newGCThing(output, templateObj, ool->entry(), gc::DefaultHeap);
masm.initGCThing(output, templateObj);
masm.loadStringLength(input, temp);
@ -3823,7 +3737,7 @@ CodeGenerator::emitAllocateGCThingPar(LInstruction *lir, const Register &objReg,
masm.newGCThingPar(objReg, cxReg, tempReg1, tempReg2, templateObj, ool->entry());
masm.bind(ool->rejoin());
masm.initGCObject(objReg, templateObj);
masm.initGCThing(objReg, templateObj);
return true;
}
@ -4015,11 +3929,11 @@ CodeGenerator::visitCreateThisWithTemplate(LCreateThisWithTemplate *lir)
return false;
// Allocate. If the FreeList is empty, call to VM, which may GC.
masm.newGCObject(objReg, templateObject, ool->entry(), lir->mir()->initialHeap());
masm.newGCThing(objReg, templateObject, ool->entry(), lir->mir()->initialHeap());
// Initialize based on the templateObject.
masm.bind(ool->rejoin());
masm.initGCObject(objReg, templateObject);
masm.initGCThing(objReg, templateObject);
return true;
}
@ -5733,8 +5647,8 @@ CodeGenerator::visitArrayConcat(LArrayConcat *lir)
// Try to allocate an object.
JSObject *templateObj = lir->mir()->templateObj();
masm.newGCObject(temp1, templateObj, &fail, lir->mir()->initialHeap());
masm.initGCObject(temp1, templateObj);
masm.newGCThing(temp1, templateObj, &fail, lir->mir()->initialHeap());
masm.initGCThing(temp1, templateObj);
masm.jump(&call);
{
masm.bind(&fail);
@ -6105,8 +6019,8 @@ CodeGenerator::visitRest(LRest *lir)
JSObject *templateObject = lir->mir()->templateObject();
Label joinAlloc, failAlloc;
masm.newGCObject(temp2, templateObject, &failAlloc, gc::DefaultHeap);
masm.initGCObject(temp2, templateObject);
masm.newGCThing(temp2, templateObject, &failAlloc, gc::DefaultHeap);
masm.initGCThing(temp2, templateObject);
masm.jump(&joinAlloc);
{
masm.bind(&failAlloc);

View File

@ -39,8 +39,6 @@ class OutOfLineLoadTypedArray;
class OutOfLineNewGCThingPar;
class OutOfLineUpdateCache;
class OutOfLineCallPostWriteBarrier;
class OutOfLineMallocSlots;
class OutOfLineFreeSlots;
class CodeGenerator : public CodeGeneratorSpecific
{
@ -134,10 +132,7 @@ class CodeGenerator : public CodeGeneratorSpecific
bool visitCallDirectEvalV(LCallDirectEvalV *lir);
bool visitDoubleToInt32(LDoubleToInt32 *lir);
bool visitFloat32ToInt32(LFloat32ToInt32 *lir);
bool visitOutOfLineMallocSlots(OutOfLineMallocSlots *ool);
bool visitOutOfLineFreeSlots(OutOfLineFreeSlots *ool);
bool emitOutOfLineMallocFree(const Register &reg, size_t nDynamicSlots, Label *fallback,
Label **mallocEntry, Label **mallocRejoin, Label **freeEntry);
bool visitNewSlots(LNewSlots *lir);
bool visitNewArrayCallVM(LNewArray *lir);
bool visitNewArray(LNewArray *lir);
bool visitOutOfLineNewArray(OutOfLineNewArray *ool);

View File

@ -4596,9 +4596,23 @@ IonBuilder::createCallObject(MDefinition *callee, MDefinition *scope)
// creation.
CallObject *templateObj = inspector->templateCallObject();
// Allocate the actual object. Run-once scripts need a singleton type, so
// always do a VM call in such cases.
MNewCallObject *callObj = MNewCallObject::New(alloc(), templateObj, script()->treatAsRunOnce());
// If the CallObject needs dynamic slots, allocate those now.
MInstruction *slots;
if (templateObj->hasDynamicSlots()) {
size_t nslots = JSObject::dynamicSlotsCount(templateObj->numFixedSlots(),
templateObj->lastProperty()->slotSpan(templateObj->getClass()),
templateObj->getClass());
slots = MNewSlots::New(alloc(), nslots);
} else {
slots = MConstant::New(alloc(), NullValue());
}
current->add(slots);
// Allocate the actual object. It is important that no intervening
// instructions could potentially bailout, thus leaking the dynamic slots
// pointer. Run-once scripts need a singleton type, so always do a VM call
// in such cases.
MNewCallObject *callObj = MNewCallObject::New(alloc(), templateObj, script()->treatAsRunOnce(), slots);
current->add(callObj);
// Initialize the object's reserved slots. No post barrier is needed here,
@ -4607,20 +4621,14 @@ IonBuilder::createCallObject(MDefinition *callee, MDefinition *scope)
current->add(MStoreFixedSlot::New(alloc(), callObj, CallObject::calleeSlot(), callee));
// Initialize argument slots.
MSlots *slots = nullptr;
for (AliasedFormalIter i(script()); i; i++) {
unsigned slot = i.scopeSlot();
unsigned formal = i.frameIndex();
MDefinition *param = current->getSlot(info().argSlotUnchecked(formal));
if (slot >= templateObj->numFixedSlots()) {
if (!slots) {
slots = MSlots::New(alloc(), callObj);
current->add(slots);
}
if (slot >= templateObj->numFixedSlots())
current->add(MStoreSlot::New(alloc(), slots, slot - templateObj->numFixedSlots(), param));
} else {
else
current->add(MStoreFixedSlot::New(alloc(), callObj, slot, param));
}
}
return callObj;

View File

@ -633,11 +633,14 @@ MacroAssembler::clampDoubleToUint8(FloatRegister input, Register output)
#endif
}
// Inlined version of gc::CheckAllocatorState that checks the bare essentials
// and bails for anything that cannot be handled with our jit allocators.
void
MacroAssembler::checkAllocatorState(Label *fail)
MacroAssembler::newGCThing(const Register &result, gc::AllocKind allocKind, Label *fail,
gc::InitialHeap initialHeap /* = gc::DefaultHeap */)
{
// Inlined equivalent of js::gc::NewGCThing() without failure case handling.
int thingSize = int(gc::Arena::thingSize(allocKind));
#ifdef JS_GC_ZEAL
// Don't execute the inline path if gcZeal is active.
branch32(Assembler::NotEqual,
@ -649,164 +652,59 @@ MacroAssembler::checkAllocatorState(Label *fail)
// as the metadata to use for the object may vary between executions of the op.
if (GetIonContext()->compartment->hasObjectMetadataCallback())
jump(fail);
}
// Inline Nursery::allocateObject, when it is okay to do so. Return true if we
// emitted a nursery allocation path.
bool
MacroAssembler::nurseryAllocate(const Register &result, gc::AllocKind allocKind, Label *fail,
size_t nDynamicSlots, gc::InitialHeap initialHeap)
{
JS_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST);
#ifdef JSGC_GENERATIONAL
const Nursery &nursery = GetIonContext()->runtime->gcNursery();
// When the nursery is not enabled, the nursery's position == end pointer,
// so allocations will naturally fall back to the interpreter. Thus, the
// following check is not technically necessary. However, the nursery is
// generally only perma-disabled or disabled when using zeal, so prefer to
// compile the tenured fast-path instead so we don't bail constantly.
if (!nursery.isEnabled())
return false;
// Explicitly request for tenured allocation for these objects.
if (initialHeap == gc::TenuredHeap)
return false;
// This allocation site is requesting too many dynamic slots.
if (nDynamicSlots > Nursery::MaxNurserySlots)
return false;
// No explicit check for nursery.isEnabled() is needed, as the comparison
// with the nursery's end will always fail in such cases.
int thingSize = int(gc::Arena::thingSize(allocKind));
int totalSize = thingSize + nDynamicSlots * sizeof(HeapSlot);
loadPtr(AbsoluteAddress(nursery.addressOfPosition()), result);
addPtr(Imm32(totalSize), result);
branchPtr(Assembler::BelowOrEqual, AbsoluteAddress(nursery.addressOfCurrentEnd()), result, fail);
storePtr(result, AbsoluteAddress(nursery.addressOfPosition()));
if (!nDynamicSlots) {
JS_ASSERT(thingSize == totalSize);
subPtr(Imm32(totalSize), result);
} else {
// Offset to get the slots pointer in |result|.
subPtr(Imm32(totalSize - thingSize), result);
// Store the slots pointer into slots address as an offset from the
// slots so that we do not need to take a second register.
JS_ASSERT(int(JSObject::offsetOfSlots()) - thingSize < 0);
storePtr(result, Address(result, int(JSObject::offsetOfSlots()) - thingSize));
// Load the start of the object into result.
if (nursery.isEnabled() &&
allocKind <= gc::FINALIZE_OBJECT_LAST &&
initialHeap != gc::TenuredHeap)
{
// Inline Nursery::allocate. No explicit check for nursery.isEnabled()
// is needed, as the comparison with the nursery's end will always fail
// in such cases.
loadPtr(AbsoluteAddress(nursery.addressOfPosition()), result);
addPtr(Imm32(thingSize), result);
branchPtr(Assembler::BelowOrEqual, AbsoluteAddress(nursery.addressOfCurrentEnd()), result, fail);
storePtr(result, AbsoluteAddress(nursery.addressOfPosition()));
subPtr(Imm32(thingSize), result);
return;
}
return true;
#else
return false;
#endif // JSGC_GENERATIONAL
}
// Inlined version of FreeSpan::allocate.
void
MacroAssembler::freeSpanAllocate(const Register &result, gc::AllocKind allocKind, Label *fail)
{
CompileZone *zone = GetIonContext()->compartment->zone();
int thingSize = int(gc::Arena::thingSize(allocKind));
// Load FreeSpan::first of |zone|'s freeLists for |allocKind|. If there is
// no room remaining in the span, we bail to finish the allocation. The
// interpreter will call |refillFreeLists|, setting up a new FreeSpan so
// that we can continue allocating in the jit.
// Inline FreeSpan::allocate.
// There is always exactly one FreeSpan per allocKind per JSCompartment.
// If a FreeSpan is replaced, its members are updated in the freeLists table,
// which the code below always re-reads.
loadPtr(AbsoluteAddress(zone->addressOfFreeListFirst(allocKind)), result);
branchPtr(Assembler::BelowOrEqual, AbsoluteAddress(zone->addressOfFreeListLast(allocKind)), result, fail);
addPtr(Imm32(thingSize), result);
storePtr(result, AbsoluteAddress(zone->addressOfFreeListFirst(allocKind)));
subPtr(Imm32(thingSize), result);
}
// Inlined equivalent of gc::AllocateObject, without failure case handling.
void
MacroAssembler::allocateObject(const Register &result, gc::AllocKind allocKind, Label *fallback,
Label *mallocEntry, Label *mallocRejoin, Label *freeEntry,
size_t nDynamicSlots, gc::InitialHeap initialHeap)
{
JS_ASSERT_IF(nDynamicSlots, mallocEntry && mallocRejoin && freeEntry);
checkAllocatorState(fallback);
if (nurseryAllocate(result, allocKind, fallback, nDynamicSlots, initialHeap))
return;
if (!nDynamicSlots) {
freeSpanAllocate(result, allocKind, fallback);
} else {
// Exit to do the malloc out-of-line.
jump(mallocEntry);
// Since we have to jump out-of-line anyway, insert our failure
// handling code into the jumped-over block so that it does not force a
// jump in the success case below.
Label allocFail;
bind(&allocFail);
pop(result);
jump(freeEntry);
// Rejoin from successful malloc; malloc failure falls straight though
// to the fallback since there is no cleanup to do yet.
bind(mallocRejoin);
// Save our malloc pointer to the stack so we can re-use the register.
push(result);
// Allocate the object and write the malloced slots.
freeSpanAllocate(result, allocKind, &allocFail);
pop(Address(result, JSObject::offsetOfSlots()));
}
}
// Inlined equivalent of gc::AllocateNonObject, without failure case handling.
// Non-object allocation does not need to worry about slots, so can take a
// simpler path.
void
MacroAssembler::allocateNonObject(const Register &result, gc::AllocKind allocKind, Label *fail)
{
checkAllocatorState(fail);
freeSpanAllocate(result, allocKind, fail);
}
void
MacroAssembler::newGCObject(const Register &result, JSObject *templateObject, Label *fallback,
gc::InitialHeap initialHeap)
{
gc::AllocKind allocKind = templateObject->tenuredGetAllocKind();
JS_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST);
JS_ASSERT(templateObject->numDynamicSlots() == 0);
allocateObject(result, allocKind, fallback, nullptr, nullptr, nullptr, 0, initialHeap);
}
void
MacroAssembler::newGCObjectAndSlots(const Register &result, JSObject *templateObject, Label *fallback,
Label *mallocEntry, Label *mallocRejoin, Label *freeEntry,
gc::InitialHeap initialHeap)
MacroAssembler::newGCThing(const Register &result, JSObject *templateObject,
Label *fail, gc::InitialHeap initialHeap)
{
gc::AllocKind allocKind = templateObject->tenuredGetAllocKind();
JS_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST);
allocateObject(result, allocKind, fallback, mallocEntry, mallocRejoin, freeEntry,
templateObject->numDynamicSlots(), initialHeap);
newGCThing(result, allocKind, fail, initialHeap);
}
void
MacroAssembler::newGCString(const Register &result, Label *fail)
{
allocateNonObject(result, js::gc::FINALIZE_STRING, fail);
newGCThing(result, js::gc::FINALIZE_STRING, fail);
}
void
MacroAssembler::newGCShortString(const Register &result, Label *fail)
{
allocateNonObject(result, js::gc::FINALIZE_SHORT_STRING, fail);
newGCThing(result, js::gc::FINALIZE_SHORT_STRING, fail);
}
void
@ -855,9 +753,6 @@ MacroAssembler::newGCThingPar(const Register &result, const Register &cx,
// Update `first`
// tempReg1->first = tempReg2;
storePtr(tempReg2, Address(tempReg1, offsetof(gc::FreeSpan, first)));
// Initialize slots to nullptr, so that we can share initGCObject.
storePtr(ImmPtr(nullptr), Address(result, JSObject::offsetOfSlots()));
}
void
@ -888,31 +783,7 @@ MacroAssembler::newGCShortStringPar(const Register &result, const Register &cx,
}
void
MacroAssembler::initGCSlots(const Register &obj, JSObject *templateObject)
{
// Slots of non-array objects are required to be initialized.
// Use the values currently in the template object.
uint32_t nslots = templateObject->lastProperty()->slotSpan(templateObject->getClass());
if (nslots == 0)
return;
uint32_t nfixed = Min(templateObject->numFixedSlots(), nslots);
for (unsigned i = 0; i < nfixed; i++)
storeValue(templateObject->getFixedSlot(i), Address(obj, JSObject::getFixedSlotOffset(i)));
if (nfixed < nslots) {
JS_ASSERT(nslots - nfixed <= templateObject->numDynamicSlots());
push(obj);
loadPtr(Address(obj, JSObject::offsetOfSlots()), obj);
for (unsigned i = 0; i < nslots - nfixed; ++i)
storeValue(templateObject->getDynamicSlot(i), Address(obj, i * sizeof(HeapSlot)));
pop(obj);
}
}
void
MacroAssembler::initGCObject(const Register &obj, JSObject *templateObject)
MacroAssembler::initGCThing(const Register &obj, JSObject *templateObject)
{
// Fast initialization of an empty object returned by NewGCThing().
@ -920,9 +791,7 @@ MacroAssembler::initGCObject(const Register &obj, JSObject *templateObject)
storePtr(ImmGCPtr(templateObject->lastProperty()), Address(obj, JSObject::offsetOfShape()));
storePtr(ImmGCPtr(templateObject->type()), Address(obj, JSObject::offsetOfType()));
// Note: if we needed external slots, |slots| was initialized by object allocation.
if (!templateObject->hasDynamicSlots())
storePtr(ImmPtr(nullptr), Address(obj, JSObject::offsetOfSlots()));
storePtr(ImmPtr(nullptr), Address(obj, JSObject::offsetOfSlots()));
if (templateObject->is<ArrayObject>()) {
JS_ASSERT(!templateObject->getDenseInitializedLength());
@ -944,16 +813,24 @@ MacroAssembler::initGCObject(const Register &obj, JSObject *templateObject)
? ObjectElements::CONVERT_DOUBLE_ELEMENTS
: 0),
Address(obj, elementsOffset + ObjectElements::offsetOfFlags()));
JS_ASSERT(!templateObject->hasPrivate());
} else {
storePtr(ImmPtr(emptyObjectElements), Address(obj, JSObject::offsetOfElements()));
initGCSlots(obj, templateObject);
if (templateObject->hasPrivate()) {
uint32_t nfixed = templateObject->numFixedSlots();
storePtr(ImmPtr(templateObject->getPrivate()),
Address(obj, JSObject::getPrivateDataOffset(nfixed)));
// Fixed slots of non-array objects are required to be initialized.
// Use the values currently in the template object.
size_t nslots = Min(templateObject->numFixedSlots(),
templateObject->lastProperty()->slotSpan(templateObject->getClass()));
for (unsigned i = 0; i < nslots; i++) {
storeValue(templateObject->getFixedSlot(i),
Address(obj, JSObject::getFixedSlotOffset(i)));
}
}
if (templateObject->hasPrivate()) {
uint32_t nfixed = templateObject->numFixedSlots();
storePtr(ImmPtr(templateObject->getPrivate()),
Address(obj, JSObject::getPrivateDataOffset(nfixed)));
}
}
void

View File

@ -783,24 +783,10 @@ class MacroAssembler : public MacroAssemblerSpecific
Label *label);
// Inline allocation.
private:
void checkAllocatorState(Label *fail);
bool nurseryAllocate(const Register &result, gc::AllocKind allocKind, Label *fail,
size_t nDynamicSlots, gc::InitialHeap initialHeap);
void freeSpanAllocate(const Register &result, gc::AllocKind allocKind, Label *fail);
void allocateObject(const Register &result, gc::AllocKind allocKind, Label *fail,
Label *oolMalloc, Label *oolMallocExit, Label *oolFree,
size_t nDynamicSlots, gc::InitialHeap initialHeap);
void allocateNonObject(const Register &result, gc::AllocKind allocKind, Label *fail);
void initGCSlots(const Register &obj, JSObject *templateObject);
public:
void newGCObject(const Register &result, JSObject *templateObject, Label *fail,
gc::InitialHeap initialHeap);
void newGCObjectAndSlots(const Register &result, JSObject *templateObject, Label *fail,
Label *oolMalloc, Label *oolMallocExit, Label *oolFree,
gc::InitialHeap initialHeap);
void initGCObject(const Register &obj, JSObject *templateObject);
void newGCThing(const Register &result, gc::AllocKind allocKind, Label *fail,
gc::InitialHeap initialHeap = gc::DefaultHeap);
void newGCThing(const Register &result, JSObject *templateObject, Label *fail,
gc::InitialHeap initialHeap);
void newGCString(const Register &result, Label *fail);
void newGCShortString(const Register &result, Label *fail);
@ -810,13 +796,13 @@ class MacroAssembler : public MacroAssemblerSpecific
void newGCThingPar(const Register &result, const Register &cx,
const Register &tempReg1, const Register &tempReg2,
JSObject *templateObject, Label *fail);
void newGCStringPar(const Register &result, const Register &cx,
const Register &tempReg1, const Register &tempReg2,
Label *fail);
void newGCShortStringPar(const Register &result, const Register &cx,
const Register &tempReg1, const Register &tempReg2,
Label *fail);
void initGCThing(const Register &obj, JSObject *templateObject);
// Compares two strings for equality based on the JSOP.
// This checks for identical pointers, atoms and length and fails for everything else.

View File

@ -302,6 +302,32 @@ class LGoto : public LControlInstructionHelper<1, 0, 0>
}
};
class LNewSlots : public LCallInstructionHelper<1, 0, 3>
{
public:
LIR_HEADER(NewSlots)
LNewSlots(const LDefinition &temp1, const LDefinition &temp2, const LDefinition &temp3) {
setTemp(0, temp1);
setTemp(1, temp2);
setTemp(2, temp3);
}
const LDefinition *temp1() {
return getTemp(0);
}
const LDefinition *temp2() {
return getTemp(1);
}
const LDefinition *temp3() {
return getTemp(2);
}
MNewSlots *mir() const {
return mir_->toNewSlots();
}
};
class LNewArray : public LInstructionHelper<1, 0, 0>
{
public:
@ -414,27 +440,39 @@ class LNewDeclEnvObject : public LInstructionHelper<1, 0, 0>
}
};
// Allocates a new CallObject.
// Allocates a new CallObject. The inputs are:
// slots: either a reg representing a HeapSlot *, or a placeholder
// meaning that no slots pointer is needed.
//
// This instruction generates two possible instruction sets:
// (1) If the call object is extensible, this is a callVM to create the
// call object.
// (2) Otherwise, an inline allocation of the call object is attempted.
//
class LNewCallObject : public LInstructionHelper<1, 0, 0>
class LNewCallObject : public LInstructionHelper<1, 1, 0>
{
public:
LIR_HEADER(NewCallObject)
LNewCallObject(const LAllocation &slots) {
setOperand(0, slots);
}
const LAllocation *slots() {
return getOperand(0);
}
MNewCallObject *mir() const {
return mir_->toNewCallObject();
}
};
class LNewCallObjectPar : public LInstructionHelper<1, 1, 2>
class LNewCallObjectPar : public LInstructionHelper<1, 2, 2>
{
LNewCallObjectPar(const LAllocation &cx, const LDefinition &temp1, const LDefinition &temp2) {
LNewCallObjectPar(const LAllocation &cx, const LAllocation &slots,
const LDefinition &temp1, const LDefinition &temp2)
{
setOperand(0, cx);
setOperand(1, slots);
setTemp(0, temp1);
setTemp(1, temp2);
}
@ -442,16 +480,37 @@ class LNewCallObjectPar : public LInstructionHelper<1, 1, 2>
public:
LIR_HEADER(NewCallObjectPar);
static LNewCallObjectPar *New(TempAllocator &alloc, const LAllocation &cx,
const LDefinition &temp1, const LDefinition &temp2)
static LNewCallObjectPar *NewWithSlots(TempAllocator &alloc,
const LAllocation &cx, const LAllocation &slots,
const LDefinition &temp1, const LDefinition &temp2)
{
return new(alloc) LNewCallObjectPar(cx, temp1, temp2);
return new(alloc) LNewCallObjectPar(cx, slots, temp1, temp2);
}
static LNewCallObjectPar *NewSansSlots(TempAllocator &alloc,
const LAllocation &cx,
const LDefinition &temp1, const LDefinition &temp2)
{
LAllocation slots = LConstantIndex::Bogus();
return new(alloc) LNewCallObjectPar(cx, slots, temp1, temp2);
}
const LAllocation *forkJoinContext() {
return getOperand(0);
}
const LAllocation *slots() {
return getOperand(1);
}
const bool hasDynamicSlots() {
// TO INVESTIGATE: Felix tried using isRegister() method here,
// but for useFixed(_, CallTempN), isRegister() is false (and
// isUse() is true). So for now ignore that and try to match
// the LConstantIndex::Bogus() generated above instead.
return slots() && ! slots()->isConstant();
}
const MNewCallObjectPar *mir() const {
return mir_->toNewCallObjectPar();
}

View File

@ -25,6 +25,7 @@
_(Goto) \
_(NewArray) \
_(NewObject) \
_(NewSlots) \
_(NewDeclEnvObject) \
_(NewCallObject) \
_(NewStringObject) \

View File

@ -160,6 +160,17 @@ LIRGenerator::visitDefFun(MDefFun *ins)
return add(lir, ins) && assignSafepoint(lir, ins);
}
bool
LIRGenerator::visitNewSlots(MNewSlots *ins)
{
// No safepoint needed, since we don't pass a cx.
LNewSlots *lir = new(alloc()) LNewSlots(tempFixed(CallTempReg0), tempFixed(CallTempReg1),
tempFixed(CallTempReg2));
if (!assignSnapshot(lir))
return false;
return defineReturn(lir, ins);
}
bool
LIRGenerator::visitNewArray(MNewArray *ins)
{
@ -184,7 +195,13 @@ LIRGenerator::visitNewDeclEnvObject(MNewDeclEnvObject *ins)
bool
LIRGenerator::visitNewCallObject(MNewCallObject *ins)
{
LNewCallObject *lir = new(alloc()) LNewCallObject();
LAllocation slots;
if (ins->slots()->type() == MIRType_Slots)
slots = useRegister(ins->slots());
else
slots = LConstantIndex::Bogus();
LNewCallObject *lir = new(alloc()) LNewCallObject(slots);
if (!define(lir, ins))
return false;
@ -211,7 +228,14 @@ LIRGenerator::visitNewCallObjectPar(MNewCallObjectPar *ins)
const LDefinition &temp1 = temp();
const LDefinition &temp2 = temp();
LNewCallObjectPar *lir = LNewCallObjectPar::New(alloc(), parThreadContext, temp1, temp2);
LNewCallObjectPar *lir;
if (ins->slots()->type() == MIRType_Slots) {
const LAllocation &slots = useRegister(ins->slots());
lir = LNewCallObjectPar::NewWithSlots(alloc(), parThreadContext, slots, temp1, temp2);
} else {
lir = LNewCallObjectPar::NewSansSlots(alloc(), parThreadContext, temp1, temp2);
}
return define(lir, ins);
}

View File

@ -66,6 +66,7 @@ class LIRGenerator : public LIRGeneratorSpecific
bool visitCallee(MCallee *callee);
bool visitGoto(MGoto *ins);
bool visitTableSwitch(MTableSwitch *tableswitch);
bool visitNewSlots(MNewSlots *ins);
bool visitNewArray(MNewArray *ins);
bool visitNewObject(MNewObject *ins);
bool visitNewDeclEnvObject(MNewDeclEnvObject *ins);

View File

@ -8860,6 +8860,33 @@ class MPostWriteBarrier
#endif
};
class MNewSlots : public MNullaryInstruction
{
unsigned nslots_;
MNewSlots(unsigned nslots)
: nslots_(nslots)
{
setResultType(MIRType_Slots);
}
public:
INSTRUCTION_HEADER(NewSlots)
static MNewSlots *New(TempAllocator &alloc, unsigned nslots) {
return new(alloc) MNewSlots(nslots);
}
unsigned nslots() const {
return nslots_;
}
AliasSet getAliasSet() const {
return AliasSet::None();
}
bool possiblyCalls() const {
return true;
}
};
class MNewDeclEnvObject : public MNullaryInstruction
{
CompilerRootObject templateObj_;
@ -8886,13 +8913,13 @@ class MNewDeclEnvObject : public MNullaryInstruction
}
};
class MNewCallObject : public MNullaryInstruction
class MNewCallObject : public MUnaryInstruction
{
CompilerRootObject templateObj_;
bool needsSingletonType_;
MNewCallObject(JSObject *templateObj, bool needsSingletonType)
: MNullaryInstruction(),
MNewCallObject(JSObject *templateObj, bool needsSingletonType, MDefinition *slots)
: MUnaryInstruction(slots),
templateObj_(templateObj),
needsSingletonType_(needsSingletonType)
{
@ -8902,11 +8929,15 @@ class MNewCallObject : public MNullaryInstruction
public:
INSTRUCTION_HEADER(NewCallObject)
static MNewCallObject *New(TempAllocator &alloc, JSObject *templateObj, bool needsSingletonType)
static MNewCallObject *New(TempAllocator &alloc, JSObject *templateObj, bool needsSingletonType,
MDefinition *slots)
{
return new(alloc) MNewCallObject(templateObj, needsSingletonType);
return new(alloc) MNewCallObject(templateObj, needsSingletonType, slots);
}
MDefinition *slots() {
return getOperand(0);
}
JSObject *templateObject() {
return templateObj_;
}
@ -8918,13 +8949,13 @@ class MNewCallObject : public MNullaryInstruction
}
};
class MNewCallObjectPar : public MUnaryInstruction
class MNewCallObjectPar : public MBinaryInstruction
{
CompilerRootObject templateObj_;
MNewCallObjectPar(MDefinition *cx, JSObject *templateObj)
: MUnaryInstruction(cx),
templateObj_(templateObj)
MNewCallObjectPar(MDefinition *cx, JSObject *templateObj, MDefinition *slots)
: MBinaryInstruction(cx, slots),
templateObj_(templateObj)
{
setResultType(MIRType_Object);
}
@ -8933,14 +8964,17 @@ class MNewCallObjectPar : public MUnaryInstruction
INSTRUCTION_HEADER(NewCallObjectPar);
static MNewCallObjectPar *New(TempAllocator &alloc, MDefinition *cx, MNewCallObject *callObj) {
JS_ASSERT(!callObj->templateObject()->hasDynamicSlots());
return new(alloc) MNewCallObjectPar(cx, callObj->templateObject());
return new(alloc) MNewCallObjectPar(cx, callObj->templateObject(), callObj->slots());
}
MDefinition *forkJoinContext() const {
return getOperand(0);
}
MDefinition *slots() const {
return getOperand(1);
}
JSObject *templateObj() const {
return templateObj_;
}

View File

@ -85,6 +85,7 @@ namespace jit {
_(ToInt32) \
_(TruncateToInt32) \
_(ToString) \
_(NewSlots) \
_(NewArray) \
_(NewObject) \
_(NewDeclEnvObject) \

View File

@ -179,6 +179,7 @@ class ParallelSafetyVisitor : public MInstructionVisitor
SAFE_OP(TruncateToInt32)
SAFE_OP(MaybeToDoubleElement)
CUSTOM_OP(ToString)
SAFE_OP(NewSlots)
CUSTOM_OP(NewArray)
CUSTOM_OP(NewObject)
CUSTOM_OP(NewCallObject)
@ -522,10 +523,6 @@ ParallelSafetyVisitor::visitCreateThisWithTemplate(MCreateThisWithTemplate *ins)
bool
ParallelSafetyVisitor::visitNewCallObject(MNewCallObject *ins)
{
if (ins->templateObject()->hasDynamicSlots()) {
SpewMIR(ins, "call with dynamic slots");
return markUnsafe();
}
replace(ins, MNewCallObjectPar::New(alloc(), ForkJoinContext(), ins));
return true;
}
@ -640,6 +637,11 @@ ParallelSafetyVisitor::insertWriteGuard(MInstruction *writeInstruction,
object = valueBeingWritten->toSlots()->object();
break;
case MDefinition::Op_NewSlots:
// Values produced by new slots will ALWAYS be
// thread-local.
return true;
default:
SpewMIR(writeInstruction, "cannot insert write guard for %s",
valueBeingWritten->opName());

View File

@ -514,23 +514,21 @@ NewSlots(JSRuntime *rt, unsigned nslots)
{
JS_STATIC_ASSERT(sizeof(Value) == sizeof(HeapSlot));
Value *slots = rt->pod_malloc<Value>(nslots);
Value *slots = reinterpret_cast<Value *>(rt->malloc_(nslots * sizeof(Value)));
if (!slots)
return nullptr;
for (unsigned i = 0; i < nslots; i++)
slots[i] = UndefinedValue();
return reinterpret_cast<HeapSlot *>(slots);
}
void
FreeSlots(HeapSlot *slots)
{
js_free(slots);
}
JSObject *
NewCallObject(JSContext *cx, HandleScript script, HandleShape shape, HandleTypeObject type)
NewCallObject(JSContext *cx, HandleScript script,
HandleShape shape, HandleTypeObject type, HeapSlot *slots)
{
JSObject *obj = CallObject::create(cx, script, shape, type);
JSObject *obj = CallObject::create(cx, script, shape, type, slots);
if (!obj)
return nullptr;

View File

@ -618,9 +618,8 @@ bool SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, Handl
bool InterruptCheck(JSContext *cx);
HeapSlot *NewSlots(JSRuntime *rt, unsigned nslots);
void FreeSlots(HeapSlot *slots);
JSObject *NewCallObject(JSContext *cx, HandleScript script, HandleShape shape,
HandleTypeObject type);
JSObject *NewCallObject(JSContext *cx, HandleScript script,
HandleShape shape, HandleTypeObject type, HeapSlot *slots);
JSObject *NewStringObject(JSContext *cx, HandleString str);
bool SPSEnter(JSContext *cx, HandleScript script);

View File

@ -626,10 +626,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
void pop(const FloatRegister &reg) {
ma_vpop(VFPRegister(reg));
}
void pop(const Address &address) {
ma_ldr(Operand(address.base, address.offset), ScratchRegister);
ma_pop(ScratchRegister);
}
void popN(const Register &reg, Imm32 extraSpace) {
Imm32 totSpace = Imm32(extraSpace.value + 4);

View File

@ -1181,23 +1181,20 @@ class AssemblerX86Shared
masm.push_m(src.offset, src.base.code());
}
void pop(const Operand &dest) {
switch (dest.kind()) {
void pop(const Operand &src) {
switch (src.kind()) {
case Operand::REG:
masm.pop_r(dest.reg());
masm.pop_r(src.reg());
break;
case Operand::MEM_REG_DISP:
masm.pop_m(dest.disp(), dest.base());
masm.pop_m(src.disp(), src.base());
break;
default:
MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
}
}
void pop(const Register &dest) {
masm.pop_r(dest.code());
}
void pop(const Address &dest) {
masm.pop_m(dest.offset, dest.base.code());
void pop(const Register &src) {
masm.pop_r(src.code());
}
void pushFlags() {

View File

@ -940,13 +940,16 @@ JS::DisableGenerationalGC(JSRuntime *rt)
rt->gcStoreBuffer.disable();
}
#endif
++rt->gcGenerationalDisabled;
}
extern JS_FRIEND_API(void)
JS::EnableGenerationalGC(JSRuntime *rt)
{
JS_ASSERT(rt->gcGenerationalDisabled > 0);
--rt->gcGenerationalDisabled;
#ifdef JSGC_GENERATIONAL
if (!IsGenerationalGCEnabled(rt)) {
if (IsGenerationalGCEnabled(rt)) {
rt->gcNursery.enable();
rt->gcStoreBuffer.enable();
}
@ -956,11 +959,7 @@ JS::EnableGenerationalGC(JSRuntime *rt)
extern JS_FRIEND_API(bool)
JS::IsGenerationalGCEnabled(JSRuntime *rt)
{
#ifdef JSGC_GENERATIONAL
return rt->gcNursery.isEnabled();
#else
return false;
#endif
return rt->gcGenerationalDisabled == 0;
}
JS_FRIEND_API(bool)

View File

@ -255,7 +255,8 @@ class JSObject : public js::ObjectImpl
js::gc::AllocKind kind,
js::gc::InitialHeap heap,
js::HandleShape shape,
js::HandleTypeObject type);
js::HandleTypeObject type,
js::HeapSlot *extantSlots = nullptr);
/* Make an array object with the specified initial state. */
static inline js::ArrayObject *createArray(js::ExclusiveContext *cx,

View File

@ -480,7 +480,8 @@ inline bool JSObject::isVarObj()
/* static */ inline JSObject *
JSObject::create(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::InitialHeap heap,
js::HandleShape shape, js::HandleTypeObject type)
js::HandleShape shape, js::HandleTypeObject type,
js::HeapSlot *extantSlots /* = nullptr */)
{
/*
* Callers must use dynamicSlotsCount to size the initial slot array of the
@ -493,9 +494,13 @@ JSObject::create(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::Initi
JS_ASSERT(js::gc::GetGCKindSlots(kind, type->clasp()) == shape->numFixedSlots());
JS_ASSERT_IF(type->clasp()->flags & JSCLASS_BACKGROUND_FINALIZE, IsBackgroundFinalized(kind));
JS_ASSERT_IF(type->clasp()->finalize, heap == js::gc::TenuredHeap);
JS_ASSERT_IF(extantSlots, dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan(),
type->clasp()));
const js::Class *clasp = type->clasp();
size_t nDynamicSlots = dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan(), clasp);
size_t nDynamicSlots = 0;
if (!extantSlots)
nDynamicSlots = dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan(), clasp);
JSObject *obj = js::NewGCObject<js::CanGC>(cx, kind, nDynamicSlots, heap);
if (!obj)
@ -503,7 +508,13 @@ JSObject::create(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::Initi
obj->shape_.init(shape);
obj->type_.init(type);
JS_ASSERT_IF(nDynamicSlots, obj->slots);
if (extantSlots) {
#ifdef JSGC_GENERATIONAL
if (cx->isJSContext())
cx->asJSContext()->runtime()->gcNursery.notifyInitialSlots(obj, extantSlots);
#endif
obj->slots = extantSlots;
}
obj->elements = js::emptyObjectElements;
if (clasp->hasPrivate())

View File

@ -1387,12 +1387,6 @@ class ObjectImpl : public gc::BarrieredCell<ObjectImpl>
return fixedSlots()[slot];
}
const Value &getDynamicSlot(uint32_t slot) const {
MOZ_ASSERT(slots);
MOZ_ASSERT(slot < numDynamicSlots());
return slots[slot];
}
void setFixedSlot(uint32_t slot, const Value &value) {
MOZ_ASSERT(slot < numFixedSlots());
fixedSlots()[slot].set(this->asObjectPtr(), HeapSlot::Slot, slot, value);

View File

@ -216,6 +216,7 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads)
gcInterFrameGC(0),
gcSliceBudget(SliceBudget::Unlimited),
gcIncrementalEnabled(true),
gcGenerationalDisabled(0),
gcManipulatingDeadZones(false),
gcObjectsMarkedInDeadZones(0),
gcPoke(false),

View File

@ -1116,6 +1116,11 @@ struct JSRuntime : public JS::shadow::Runtime,
*/
bool gcIncrementalEnabled;
/*
* GGC can be enabled from the command line while testing.
*/
unsigned gcGenerationalDisabled;
/*
* This is true if we are in the middle of a brain transplant (e.g.,
* JS_TransplantObject) or some other operation that can manipulate

View File

@ -137,18 +137,18 @@ ScopeObject::setEnclosingScope(HandleObject obj)
}
/*
* Construct a bare-bones call object given a shape and type.
* Construct a bare-bones call object given a shape, type, and slots pointer.
* The call object must be further initialized to be usable.
*/
CallObject *
CallObject::create(JSContext *cx, HandleScript script, HandleShape shape, HandleTypeObject type)
CallObject::create(JSContext *cx, HandleScript script, HandleShape shape, HandleTypeObject type, HeapSlot *slots)
{
gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
JS_ASSERT(CanBeFinalizedInBackground(kind, &CallObject::class_));
kind = gc::GetBackgroundAllocKind(kind);
gc::InitialHeap heap = script->treatAsRunOnce() ? gc::TenuredHeap : gc::DefaultHeap;
JSObject *obj = JSObject::create(cx, kind, heap, shape, type);
JSObject *obj = JSObject::create(cx, kind, heap, shape, type, slots);
if (!obj)
return nullptr;

View File

@ -237,7 +237,7 @@ class CallObject : public ScopeObject
/* These functions are internal and are exposed only for JITs. */
static CallObject *
create(JSContext *cx, HandleScript script, HandleShape shape, HandleTypeObject type);
create(JSContext *cx, HandleScript script, HandleShape shape, HandleTypeObject type, HeapSlot *slots);
static CallObject *
createTemplateObject(JSContext *cx, HandleScript script, gc::InitialHeap heap);