mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Backout bea3f06585ec (Bug 969012) for arm simulator failures.
This commit is contained in:
parent
7c5f729399
commit
7314440257
@ -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),
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
@ -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;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -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 ®, 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 ®, 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);
|
||||
|
@ -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 ®, 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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
_(Goto) \
|
||||
_(NewArray) \
|
||||
_(NewObject) \
|
||||
_(NewSlots) \
|
||||
_(NewDeclEnvObject) \
|
||||
_(NewCallObject) \
|
||||
_(NewStringObject) \
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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_;
|
||||
}
|
||||
|
@ -85,6 +85,7 @@ namespace jit {
|
||||
_(ToInt32) \
|
||||
_(TruncateToInt32) \
|
||||
_(ToString) \
|
||||
_(NewSlots) \
|
||||
_(NewArray) \
|
||||
_(NewObject) \
|
||||
_(NewDeclEnvObject) \
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -626,10 +626,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
void pop(const FloatRegister ®) {
|
||||
ma_vpop(VFPRegister(reg));
|
||||
}
|
||||
void pop(const Address &address) {
|
||||
ma_ldr(Operand(address.base, address.offset), ScratchRegister);
|
||||
ma_pop(ScratchRegister);
|
||||
}
|
||||
|
||||
void popN(const Register ®, Imm32 extraSpace) {
|
||||
Imm32 totSpace = Imm32(extraSpace.value + 4);
|
||||
|
@ -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() {
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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())
|
||||
|
@ -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);
|
||||
|
@ -216,6 +216,7 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads)
|
||||
gcInterFrameGC(0),
|
||||
gcSliceBudget(SliceBudget::Unlimited),
|
||||
gcIncrementalEnabled(true),
|
||||
gcGenerationalDisabled(0),
|
||||
gcManipulatingDeadZones(false),
|
||||
gcObjectsMarkedInDeadZones(0),
|
||||
gcPoke(false),
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user