Remove unboxed object code from js

This commit is contained in:
Fedor 2019-07-08 13:08:41 +03:00
parent c2483721f0
commit e2d5ce2fef
83 changed files with 776 additions and 8386 deletions

View File

@ -947,7 +947,7 @@ ModuleObject::evaluate(JSContext* cx, HandleModuleObject self, MutableHandleValu
ModuleObject::createNamespace(JSContext* cx, HandleModuleObject self, HandleObject exports)
{
MOZ_ASSERT(!self->namespace_());
MOZ_ASSERT(exports->is<ArrayObject>() || exports->is<UnboxedArrayObject>());
MOZ_ASSERT(exports->is<ArrayObject>());
RootedModuleNamespaceObject ns(cx, ModuleNamespaceObject::create(cx, self));
if (!ns)

View File

@ -6281,8 +6281,8 @@ ParseNode::getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObje
}
MOZ_ASSERT(idx == count);
JSObject* obj = ObjectGroup::newArrayObject(cx, values.begin(), values.length(),
newKind, arrayKind);
ArrayObject* obj = ObjectGroup::newArrayObject(cx, values.begin(), values.length(),
newKind, arrayKind);
if (!obj)
return false;
@ -9192,7 +9192,7 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn)
return false;
}
if (!emitArray(args, argc, JSOP_SPREADCALLARRAY))
if (!emitArray(args, argc))
return false;
if (optCodeEmitted) {
@ -9683,11 +9683,11 @@ BytecodeEmitter::emitArrayLiteral(ParseNode* pn)
}
}
return emitArray(pn->pn_head, pn->pn_count, JSOP_NEWARRAY);
return emitArray(pn->pn_head, pn->pn_count);
}
bool
BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count, JSOp op)
BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count)
{
/*
@ -9698,7 +9698,6 @@ BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count, JSOp op)
* to avoid dup'ing and popping the array as each element is added, as
* JSOP_SETELEM/JSOP_SETPROP would do.
*/
MOZ_ASSERT(op == JSOP_NEWARRAY || op == JSOP_SPREADCALLARRAY);
uint32_t nspread = 0;
for (ParseNode* elt = pn; elt; elt = elt->pn_next) {
@ -9719,7 +9718,7 @@ BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count, JSOp op)
// For arrays with spread, this is a very pessimistic allocation, the
// minimum possible final size.
if (!emitUint32Operand(op, count - nspread)) // ARRAY
if (!emitUint32Operand(JSOP_NEWARRAY, count - nspread)) // ARRAY
return false;
ParseNode* pn2 = pn;

View File

@ -521,7 +521,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitAtomOp(ParseNode* pn, JSOp op);
MOZ_MUST_USE bool emitArrayLiteral(ParseNode* pn);
MOZ_MUST_USE bool emitArray(ParseNode* pn, uint32_t count, JSOp op);
MOZ_MUST_USE bool emitArray(ParseNode* pn, uint32_t count);
MOZ_MUST_USE bool emitArrayComp(ParseNode* pn);
MOZ_MUST_USE bool emitInternedScopeOp(uint32_t index, JSOp op);

View File

@ -18,6 +18,7 @@
#include "builtin/ModuleObject.h"
#include "gc/GCInternals.h"
#include "gc/Policy.h"
#include "gc/StoreBuffer-inl.h"
#include "jit/IonCode.h"
#include "js/SliceBudget.h"
#include "vm/ArgumentsObject.h"
@ -28,7 +29,6 @@
#include "vm/Shape.h"
#include "vm/Symbol.h"
#include "vm/TypedArrayObject.h"
#include "vm/UnboxedObject.h"
#include "wasm/WasmJS.h"
#include "jscompartmentinlines.h"
@ -37,7 +37,6 @@
#include "gc/Nursery-inl.h"
#include "vm/String-inl.h"
#include "vm/UnboxedObject-inl.h"
using namespace js;
using namespace js::gc;
@ -1395,14 +1394,6 @@ js::ObjectGroup::traceChildren(JSTracer* trc)
if (maybePreliminaryObjects())
maybePreliminaryObjects()->trace(trc);
if (maybeUnboxedLayout())
unboxedLayout().trace(trc);
if (ObjectGroup* unboxedGroup = maybeOriginalUnboxedGroup()) {
TraceManuallyBarrieredEdge(trc, &unboxedGroup, "group_original_unboxed_group");
setOriginalUnboxedGroup(unboxedGroup);
}
if (JSObject* descr = maybeTypeDescr()) {
TraceManuallyBarrieredEdge(trc, &descr, "group_type_descr");
setTypeDescr(&descr->as<TypeDescr>());
@ -1436,12 +1427,6 @@ js::GCMarker::lazilyMarkChildren(ObjectGroup* group)
if (group->maybePreliminaryObjects())
group->maybePreliminaryObjects()->trace(this);
if (group->maybeUnboxedLayout())
group->unboxedLayout().trace(this);
if (ObjectGroup* unboxedGroup = group->maybeOriginalUnboxedGroup())
traverseEdge(group, unboxedGroup);
if (TypeDescr* descr = group->maybeTypeDescr())
traverseEdge(group, static_cast<JSObject*>(descr));
@ -1484,23 +1469,6 @@ CallTraceHook(Functor f, JSTracer* trc, JSObject* obj, CheckGeneration check, Ar
return nullptr;
}
if (clasp == &UnboxedPlainObject::class_) {
JSObject** pexpando = obj->as<UnboxedPlainObject>().addressOfExpando();
if (*pexpando)
f(pexpando, mozilla::Forward<Args>(args)...);
UnboxedPlainObject& unboxed = obj->as<UnboxedPlainObject>();
const UnboxedLayout& layout = check == CheckGeneration::DoChecks
? unboxed.layout()
: unboxed.layoutDontCheckGeneration();
if (layout.traceList()) {
VisitTraceList(f, layout.traceList(), unboxed.data(),
mozilla::Forward<Args>(args)...);
}
return nullptr;
}
clasp->doTrace(trc, obj);
if (!clasp->isNative())
@ -2293,18 +2261,6 @@ static inline void
TraceWholeCell(TenuringTracer& mover, JSObject* object)
{
mover.traceObject(object);
// Additionally trace the expando object attached to any unboxed plain
// objects. Baseline and Ion can write properties to the expando while
// only adding a post barrier to the owning unboxed object. Note that
// it isn't possible for a nursery unboxed object to have a tenured
// expando, so that adding a post barrier on the original object will
// capture any tenured->nursery edges in the expando as well.
if (object->is<UnboxedPlainObject>()) {
if (UnboxedExpandoObject* expando = object->as<UnboxedPlainObject>().maybeExpando())
expando->traceChildren(&mover);
}
}
static inline void
@ -2548,8 +2504,6 @@ js::TenuringTracer::moveObjectToTenured(JSObject* dst, JSObject* src, AllocKind
InlineTypedObject::objectMovedDuringMinorGC(this, dst, src);
} else if (src->is<TypedArrayObject>()) {
tenuredSize += TypedArrayObject::objectMovedDuringMinorGC(this, dst, src, dstKind);
} else if (src->is<UnboxedArrayObject>()) {
tenuredSize += UnboxedArrayObject::objectMovedDuringMinorGC(this, dst, src, dstKind);
} else if (src->is<ArgumentsObject>()) {
tenuredSize += ArgumentsObject::objectMovedDuringMinorGC(this, dst, src);
} else if (src->is<ProxyObject>()) {

View File

@ -201,80 +201,15 @@ gc::TraceCycleCollectorChildren(JS::CallbackTracer* trc, Shape* shape)
} while (shape);
}
// Object groups can point to other object groups via an UnboxedLayout or the
// the original unboxed group link. There can potentially be deep or cyclic
// chains of such groups to trace through without going through a thing that
// participates in cycle collection. These need to be handled iteratively to
// avoid blowing the stack when running the cycle collector's callback tracer.
struct ObjectGroupCycleCollectorTracer : public JS::CallbackTracer
{
explicit ObjectGroupCycleCollectorTracer(JS::CallbackTracer* innerTracer)
: JS::CallbackTracer(innerTracer->runtime(), DoNotTraceWeakMaps),
innerTracer(innerTracer)
{}
void onChild(const JS::GCCellPtr& thing) override;
JS::CallbackTracer* innerTracer;
Vector<ObjectGroup*, 4, SystemAllocPolicy> seen, worklist;
};
void
ObjectGroupCycleCollectorTracer::onChild(const JS::GCCellPtr& thing)
{
if (thing.is<BaseShape>()) {
// The CC does not care about BaseShapes, and no additional GC things
// will be reached by following this edge.
return;
}
if (thing.is<JSObject>() || thing.is<JSScript>()) {
// Invoke the inner cycle collector callback on this child. It will not
// recurse back into TraceChildren.
innerTracer->onChild(thing);
return;
}
if (thing.is<ObjectGroup>()) {
// If this group is required to be in an ObjectGroup chain, trace it
// via the provided worklist rather than continuing to recurse.
ObjectGroup& group = thing.as<ObjectGroup>();
if (group.maybeUnboxedLayout()) {
for (size_t i = 0; i < seen.length(); i++) {
if (seen[i] == &group)
return;
}
if (seen.append(&group) && worklist.append(&group)) {
return;
} else {
// If append fails, keep tracing normally. The worst that will
// happen is we end up overrecursing.
}
}
}
TraceChildren(this, thing.asCell(), thing.kind());
}
void
gc::TraceCycleCollectorChildren(JS::CallbackTracer* trc, ObjectGroup* group)
{
MOZ_ASSERT(trc->isCallbackTracer());
// Early return if this group is not required to be in an ObjectGroup chain.
if (!group->maybeUnboxedLayout())
return group->traceChildren(trc);
ObjectGroupCycleCollectorTracer groupTracer(trc->asCallbackTracer());
group->traceChildren(&groupTracer);
while (!groupTracer.worklist.empty()) {
ObjectGroup* innerGroup = groupTracer.worklist.popCopy();
innerGroup->traceChildren(&groupTracer);
}
group->traceChildren(trc);
}
/*** Traced Edge Printer *************************************************************************/
static size_t

View File

@ -1,49 +0,0 @@
function Foo(a, b) {
this.a = a;
this.b = b;
}
function invalidate_foo() {
var a = [];
var counter = 0;
for (var i = 0; i < 50; i++)
a.push(new Foo(i, i + 1));
Object.defineProperty(Foo.prototype, "a", {configurable: true, set: function() { counter++; }});
for (var i = 0; i < 50; i++)
a.push(new Foo(i, i + 1));
delete Foo.prototype.a;
var total = 0;
for (var i = 0; i < a.length; i++) {
assertEq('a' in a[i], i < 50);
total += a[i].b;
}
assertEq(total, 2550);
assertEq(counter, 50);
}
invalidate_foo();
function Bar(a, b, fn) {
this.a = a;
if (b == 30)
Object.defineProperty(Bar.prototype, "b", {configurable: true, set: fn});
this.b = b;
}
function invalidate_bar() {
var a = [];
var counter = 0;
function fn() { counter++; }
for (var i = 0; i < 50; i++)
a.push(new Bar(i, i + 1, fn));
delete Bar.prototype.b;
var total = 0;
for (var i = 0; i < a.length; i++) {
assertEq('a' in a[i], true);
assertEq('b' in a[i], i < 29);
total += a[i].a;
}
assertEq(total, 1225);
assertEq(counter, 21);
}
invalidate_bar();

View File

@ -1,47 +0,0 @@
// Test various ways of converting an unboxed object to native.
function Foo(a, b) {
this.a = a;
this.b = b;
}
var proxyObj = {
get: function(recipient, name) {
return recipient[name] + 2;
}
};
function f() {
var a = [];
for (var i = 0; i < 50; i++)
a.push(new Foo(i, i + 1));
var prop = "a";
i = 0;
for (; i < 5; i++)
a[i].c = i;
for (; i < 10; i++)
Object.defineProperty(a[i], 'c', {value: i});
for (; i < 15; i++)
a[i] = new Proxy(a[i], proxyObj);
for (; i < 20; i++)
a[i].a = 3.5;
for (; i < 25; i++)
delete a[i].b;
for (; i < 30; i++)
a[prop] = 4;
var total = 0;
for (i = 0; i < a.length; i++) {
if ('a' in a[i])
total += a[i].a;
if ('b' in a[i])
total += a[i].b;
if ('c' in a[i])
total += a[i].c;
}
assertEq(total, 2382.5);
}
f();

View File

@ -1,20 +0,0 @@
function f() {
var propNames = ["a","b","c","d","e","f","g","h","i","j","x","y"];
var arr = [];
for (var i=0; i<64; i++)
arr.push({x:1, y:2});
for (var i=0; i<64; i++) {
// Make sure there are expandos with dynamic slots for each object.
for (var j = 0; j < propNames.length; j++)
arr[i][propNames[j]] = j;
}
var res = 0;
for (var i=0; i<100000; i++) {
var o = arr[i % 64];
var p = propNames[i % propNames.length];
res += o[p];
}
assertEq(res, 549984);
}
f();

View File

@ -1,31 +0,0 @@
// Use the correct receiver when non-native objects are prototypes of other objects.
function Thing(a, b) {
this.a = a;
this.b = b;
}
function foo() {
var array = [];
for (var i = 0; i < 10000; i++)
array.push(new Thing(i, i + 1));
var proto = new Thing(1, 2);
var obj = Object.create(proto);
Object.defineProperty(Thing.prototype, "c", {set:function() { this.d = 0; }});
obj.c = 3;
assertEq(obj.c, undefined);
assertEq(obj.d, 0);
assertEq(obj.hasOwnProperty("d"), true);
assertEq(proto.d, undefined);
assertEq(proto.hasOwnProperty("d"), false);
obj.a = 3;
assertEq(obj.a, 3);
assertEq(proto.a, 1);
assertEq(obj.hasOwnProperty("a"), true);
}
foo();

View File

@ -1,24 +0,0 @@
function O() {
this.x = 1;
this.y = 2;
}
function testUnboxed() {
var arr = [];
for (var i=0; i<100; i++)
arr.push(new O);
var o = arr[arr.length-1];
o[0] = 0;
o[2] = 2;
var sym = Symbol();
o[sym] = 1;
o.z = 3;
Object.defineProperty(o, '3', {value:1,enumerable:false,configurable:false,writable:false});
o[4] = 4;
var props = Reflect.ownKeys(o);
assertEq(props[props.length-1], sym);
assertEq(Object.getOwnPropertyNames(o).join(""), "0234xyz");
}
testUnboxed();

View File

@ -1,16 +0,0 @@
var a = [];
for (var i = 0; i < 2000; i++)
a.push({f:i});
function f() {
var total = 0;
for (var i = 0; i < a.length; i++)
total += a[i].f;
return total;
}
assertEq(f(), 1999000);
var sub = Object.create(a[0]);
assertEq(f(), 1999000);

View File

@ -93,10 +93,6 @@ GetObject(const MDefinition* ins)
case MDefinition::Op_Elements:
case MDefinition::Op_MaybeCopyElementsForWrite:
case MDefinition::Op_MaybeToDoubleElement:
case MDefinition::Op_UnboxedArrayLength:
case MDefinition::Op_UnboxedArrayInitializedLength:
case MDefinition::Op_IncrementUnboxedArrayInitializedLength:
case MDefinition::Op_SetUnboxedArrayInitializedLength:
case MDefinition::Op_TypedArrayLength:
case MDefinition::Op_SetTypedObjectOffset:
case MDefinition::Op_SetDisjointTypedElements:
@ -114,8 +110,6 @@ GetObject(const MDefinition* ins)
case MDefinition::Op_GuardObjectGroup:
case MDefinition::Op_GuardObjectIdentity:
case MDefinition::Op_GuardClass:
case MDefinition::Op_GuardUnboxedExpando:
case MDefinition::Op_LoadUnboxedExpando:
case MDefinition::Op_LoadSlot:
case MDefinition::Op_StoreSlot:
case MDefinition::Op_InArray:

View File

@ -16,7 +16,7 @@ using namespace js;
using namespace js::jit;
// OperandLocation represents the location of an OperandId. The operand is
// either in a register or on the stack, and is either boxed or unboxed.
// either in a register or on the stack.
class OperandLocation
{
public:
@ -787,9 +787,6 @@ BaselineCacheIRCompiler::emitGuardClass()
case GuardClassKind::Array:
clasp = &ArrayObject::class_;
break;
case GuardClassKind::UnboxedArray:
clasp = &UnboxedArrayObject::class_;
break;
case GuardClassKind::MappedArguments:
clasp = &MappedArgumentsObject::class_;
break;
@ -817,36 +814,6 @@ BaselineCacheIRCompiler::emitGuardSpecificObject()
return true;
}
bool
BaselineCacheIRCompiler::emitGuardNoUnboxedExpando()
{
Register obj = allocator.useRegister(masm, reader.objOperandId());
FailurePath* failure;
if (!addFailurePath(&failure))
return false;
Address expandoAddr(obj, UnboxedPlainObject::offsetOfExpando());
masm.branchPtr(Assembler::NotEqual, expandoAddr, ImmWord(0), failure->label());
return true;
}
bool
BaselineCacheIRCompiler::emitGuardAndLoadUnboxedExpando()
{
Register obj = allocator.useRegister(masm, reader.objOperandId());
Register output = allocator.defineRegister(masm, reader.objOperandId());
FailurePath* failure;
if (!addFailurePath(&failure))
return false;
Address expandoAddr(obj, UnboxedPlainObject::offsetOfExpando());
masm.loadPtr(expandoAddr, output);
masm.branchTestPtr(Assembler::Zero, output, output, failure->label());
return true;
}
bool
BaselineCacheIRCompiler::emitLoadFixedSlotResult()
{
@ -873,26 +840,6 @@ BaselineCacheIRCompiler::emitLoadDynamicSlotResult()
return true;
}
bool
BaselineCacheIRCompiler::emitLoadUnboxedPropertyResult()
{
Register obj = allocator.useRegister(masm, reader.objOperandId());
AutoScratchRegister scratch(allocator, masm);
JSValueType fieldType = reader.valueType();
Address fieldOffset(stubAddress(reader.stubOffset()));
masm.load32(fieldOffset, scratch);
masm.loadUnboxedProperty(BaseIndex(obj, scratch, TimesOne), fieldType, R0);
if (fieldType == JSVAL_TYPE_OBJECT)
emitEnterTypeMonitorIC();
else
emitReturnFromIC();
return true;
}
bool
BaselineCacheIRCompiler::emitGuardNoDetachedTypedObjects()
{
@ -1003,19 +950,6 @@ BaselineCacheIRCompiler::emitLoadInt32ArrayLengthResult()
return true;
}
bool
BaselineCacheIRCompiler::emitLoadUnboxedArrayLengthResult()
{
Register obj = allocator.useRegister(masm, reader.objOperandId());
masm.load32(Address(obj, UnboxedArrayObject::offsetOfLength()), R0.scratchReg());
masm.tagValue(JSVAL_TYPE_INT32, R0.scratchReg(), R0);
// The int32 type was monitored when attaching the stub, so we can
// just return.
emitReturnFromIC();
return true;
}
bool
BaselineCacheIRCompiler::emitLoadArgumentsObjectLengthResult()
{

View File

@ -2049,13 +2049,7 @@ BaselineCompiler::emit_JSOP_NEWARRAY()
return true;
}
bool
BaselineCompiler::emit_JSOP_SPREADCALLARRAY()
{
return emit_JSOP_NEWARRAY();
}
typedef JSObject* (*NewArrayCopyOnWriteFn)(JSContext*, HandleArrayObject, gc::InitialHeap);
typedef ArrayObject* (*NewArrayCopyOnWriteFn)(JSContext*, HandleArrayObject, gc::InitialHeap);
const VMFunction jit::NewArrayCopyOnWriteInfo =
FunctionInfo<NewArrayCopyOnWriteFn>(js::NewDenseCopyOnWriteArray, "NewDenseCopyOnWriteArray");
@ -4136,14 +4130,14 @@ BaselineCompiler::emit_JSOP_REST()
{
frame.syncStack(0);
JSObject* templateObject =
ArrayObject* templateObject =
ObjectGroup::newArrayObject(cx, nullptr, 0, TenuredObject,
ObjectGroup::NewArrayKind::UnknownIndex);
if (!templateObject)
return false;
// Call IC.
ICRest_Fallback::Compiler compiler(cx, &templateObject->as<ArrayObject>());
ICRest_Fallback::Compiler compiler(cx, templateObject);
if (!emitOpIC(compiler.getStub(&stubSpace_)))
return false;

View File

@ -100,7 +100,6 @@ namespace jit {
_(JSOP_BITNOT) \
_(JSOP_NEG) \
_(JSOP_NEWARRAY) \
_(JSOP_SPREADCALLARRAY) \
_(JSOP_NEWARRAY_COPYONWRITE) \
_(JSOP_INITELEM_ARRAY) \
_(JSOP_NEWOBJECT) \

View File

@ -42,8 +42,8 @@
#include "jit/shared/Lowering-shared-inl.h"
#include "vm/EnvironmentObject-inl.h"
#include "vm/Interpreter-inl.h"
#include "vm/NativeObject-inl.h"
#include "vm/StringObject-inl.h"
#include "vm/UnboxedObject-inl.h"
using mozilla::DebugOnly;
@ -289,7 +289,7 @@ DoTypeUpdateFallback(JSContext* cx, BaselineFrame* frame, ICUpdatedStub* stub, H
case ICStub::SetProp_Native:
case ICStub::SetProp_NativeAdd:
case ICStub::SetProp_Unboxed: {
MOZ_ASSERT(obj->isNative() || obj->is<UnboxedPlainObject>());
MOZ_ASSERT(obj->isNative());
jsbytecode* pc = stub->getChainFallback()->icEntry()->pc(script);
if (*pc == JSOP_SETALIASEDVAR || *pc == JSOP_INITALIASEDLEXICAL)
id = NameToId(EnvironmentCoordinateName(cx->caches.envCoordinateNameCache, script, pc));
@ -732,11 +732,6 @@ LastPropertyForSetProp(JSObject* obj)
if (obj->isNative())
return obj->as<NativeObject>().lastProperty();
if (obj->is<UnboxedPlainObject>()) {
UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando();
return expando ? expando->lastProperty() : nullptr;
}
return nullptr;
}
@ -1153,56 +1148,6 @@ TryAttachNativeOrUnboxedGetValueElemStub(JSContext* cx, HandleScript script, jsb
ICStub* monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
if (obj->is<UnboxedPlainObject>() && holder == obj) {
const UnboxedLayout::Property* property = obj->as<UnboxedPlainObject>().layout().lookup(id);
// Once unboxed objects support symbol-keys, we need to change the following accordingly
MOZ_ASSERT_IF(!keyVal.isString(), !property);
if (property) {
if (!cx->runtime()->jitSupportsFloatingPoint)
return true;
RootedPropertyName name(cx, JSID_TO_ATOM(id)->asPropertyName());
ICGetElemNativeCompiler<PropertyName*> compiler(cx, ICStub::GetElem_UnboxedPropertyName,
monitorStub, obj, holder,
name,
ICGetElemNativeStub::UnboxedProperty,
needsAtomize, property->offset +
UnboxedPlainObject::offsetOfData(),
property->type);
ICStub* newStub = compiler.getStub(compiler.getStubSpace(script));
if (!newStub)
return false;
stub->addNewStub(newStub);
*attached = true;
return true;
}
Shape* shape = obj->as<UnboxedPlainObject>().maybeExpando()->lookup(cx, id);
if (!shape->hasDefaultGetter() || !shape->hasSlot())
return true;
bool isFixedSlot;
uint32_t offset;
GetFixedOrDynamicSlotOffset(shape, &isFixedSlot, &offset);
ICGetElemNativeStub::AccessType acctype =
isFixedSlot ? ICGetElemNativeStub::FixedSlot
: ICGetElemNativeStub::DynamicSlot;
ICGetElemNativeCompiler<T> compiler(cx, getGetElemStubKind<T>(ICStub::GetElem_NativeSlotName),
monitorStub, obj, holder, key,
acctype, needsAtomize, offset);
ICStub* newStub = compiler.getStub(compiler.getStubSpace(script));
if (!newStub)
return false;
stub->addNewStub(newStub);
*attached = true;
return true;
}
if (!holder->isNative())
return true;
@ -1366,7 +1311,7 @@ IsNativeDenseElementAccess(HandleObject obj, HandleValue key)
static bool
IsNativeOrUnboxedDenseElementAccess(HandleObject obj, HandleValue key)
{
if (!obj->isNative() && !obj->is<UnboxedArrayObject>())
if (!obj->isNative())
return false;
if (key.isInt32() && key.toInt32() >= 0 && !obj->is<TypedArrayObject>())
return true;
@ -1450,7 +1395,7 @@ TryAttachGetElemStub(JSContext* cx, JSScript* script, jsbytecode* pc, ICGetElem_
}
// Check for NativeObject[id] and UnboxedPlainObject[id] shape-optimizable accesses.
if (obj->isNative() || obj->is<UnboxedPlainObject>()) {
if (obj->isNative()) {
RootedScript rootedScript(cx, script);
if (rhs.isString()) {
if (!TryAttachNativeOrUnboxedGetValueElemStub<PropertyName*>(cx, rootedScript, pc, stub,
@ -1470,20 +1415,6 @@ TryAttachGetElemStub(JSContext* cx, JSScript* script, jsbytecode* pc, ICGetElem_
script = rootedScript;
}
// Check for UnboxedArray[int] accesses.
if (obj->is<UnboxedArrayObject>() && rhs.isInt32() && rhs.toInt32() >= 0) {
JitSpew(JitSpew_BaselineIC, " Generating GetElem(UnboxedArray[Int32]) stub");
ICGetElem_UnboxedArray::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
obj->group());
ICStub* unboxedStub = compiler.getStub(compiler.getStubSpace(script));
if (!unboxedStub)
return false;
stub->addNewStub(unboxedStub);
*attached = true;
return true;
}
// Check for TypedArray[int] => Number and TypedObject[int] => Number accesses.
if ((obj->is<TypedArrayObject>() || IsPrimitiveArrayTypedObject(obj)) &&
rhs.isNumber() &&
@ -1876,14 +1807,6 @@ ICGetElemNativeCompiler<T>::generateStubCode(MacroAssembler& masm)
Register holderReg;
if (obj_ == holder_) {
holderReg = objReg;
if (obj_->is<UnboxedPlainObject>() && acctype_ != ICGetElemNativeStub::UnboxedProperty) {
// The property will be loaded off the unboxed expando.
masm.push(R1.scratchReg());
popR1 = true;
holderReg = R1.scratchReg();
masm.loadPtr(Address(objReg, UnboxedPlainObject::offsetOfExpando()), holderReg);
}
} else {
// Shape guard holder.
if (regs.empty()) {
@ -1934,13 +1857,6 @@ ICGetElemNativeCompiler<T>::generateStubCode(MacroAssembler& masm)
if (popR1)
masm.addToStackPtr(ImmWord(sizeof(size_t)));
} else if (acctype_ == ICGetElemNativeStub::UnboxedProperty) {
masm.load32(Address(ICStubReg, ICGetElemNativeSlotStub<T>::offsetOfOffset()),
scratchReg);
masm.loadUnboxedProperty(BaseIndex(objReg, scratchReg, TimesOne), unboxedType_,
TypedOrValueRegister(R0));
if (popR1)
masm.addToStackPtr(ImmWord(sizeof(size_t)));
} else {
MOZ_ASSERT(acctype_ == ICGetElemNativeStub::NativeGetter ||
acctype_ == ICGetElemNativeStub::ScriptedGetter);
@ -2089,56 +2005,6 @@ ICGetElem_Dense::Compiler::generateStubCode(MacroAssembler& masm)
return true;
}
//
// GetElem_UnboxedArray
//
bool
ICGetElem_UnboxedArray::Compiler::generateStubCode(MacroAssembler& masm)
{
MOZ_ASSERT(engine_ == Engine::Baseline);
Label failure;
masm.branchTestObject(Assembler::NotEqual, R0, &failure);
masm.branchTestInt32(Assembler::NotEqual, R1, &failure);
AllocatableGeneralRegisterSet regs(availableGeneralRegs(2));
Register scratchReg = regs.takeAny();
// Unbox R0 and group guard.
Register obj = masm.extractObject(R0, ExtractTemp0);
masm.loadPtr(Address(ICStubReg, ICGetElem_UnboxedArray::offsetOfGroup()), scratchReg);
masm.branchTestObjGroup(Assembler::NotEqual, obj, scratchReg, &failure);
// Unbox key.
Register key = masm.extractInt32(R1, ExtractTemp1);
// Bounds check.
masm.load32(Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()),
scratchReg);
masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), scratchReg);
masm.branch32(Assembler::BelowOrEqual, scratchReg, key, &failure);
// Load obj->elements.
masm.loadPtr(Address(obj, UnboxedArrayObject::offsetOfElements()), scratchReg);
// Load value.
size_t width = UnboxedTypeSize(elementType_);
BaseIndex addr(scratchReg, key, ScaleFromElemWidth(width));
masm.loadUnboxedProperty(addr, elementType_, R0);
// Only monitor the result if its type might change.
if (elementType_ == JSVAL_TYPE_OBJECT)
EmitEnterTypeMonitorIC(masm);
else
EmitReturnFromIC(masm);
// Failure case - jump to next stub
masm.bind(&failure);
EmitStubGuardFailure(masm);
return true;
}
//
// GetElem_TypedArray
//
@ -2437,8 +2303,8 @@ CanOptimizeDenseOrUnboxedArraySetElem(JSObject* obj, uint32_t index,
Shape* oldShape, uint32_t oldCapacity, uint32_t oldInitLength,
bool* isAddingCaseOut, size_t* protoDepthOut)
{
uint32_t initLength = GetAnyBoxedOrUnboxedInitializedLength(obj);
uint32_t capacity = GetAnyBoxedOrUnboxedCapacity(obj);
uint32_t initLength = obj->as<NativeObject>().getDenseInitializedLength();
uint32_t capacity = obj->as<NativeObject>().getDenseCapacity();
*isAddingCaseOut = false;
*protoDepthOut = 0;
@ -2447,10 +2313,6 @@ CanOptimizeDenseOrUnboxedArraySetElem(JSObject* obj, uint32_t index,
if (initLength < oldInitLength || capacity < oldCapacity)
return false;
// Unboxed arrays need to be able to emit floating point code.
if (obj->is<UnboxedArrayObject>() && !obj->runtimeFromMainThread()->jitSupportsFloatingPoint)
return false;
Shape* shape = obj->maybeShape();
// Cannot optimize if the shape changed.
@ -2532,8 +2394,8 @@ DoSetElemFallback(JSContext* cx, BaselineFrame* frame, ICSetElem_Fallback* stub_
uint32_t oldCapacity = 0;
uint32_t oldInitLength = 0;
if (index.isInt32() && index.toInt32() >= 0) {
oldCapacity = GetAnyBoxedOrUnboxedCapacity(obj);
oldInitLength = GetAnyBoxedOrUnboxedInitializedLength(obj);
oldCapacity = obj->as<NativeObject>().getDenseCapacity();
oldInitLength = obj->as<NativeObject>().getDenseInitializedLength();
}
if (op == JSOP_INITELEM || op == JSOP_INITHIDDENELEM) {
@ -2741,18 +2603,6 @@ BaselineScript::noteArrayWriteHole(uint32_t pcOffset)
// SetElem_DenseOrUnboxedArray
//
template <typename T>
void
EmitUnboxedPreBarrierForBaseline(MacroAssembler &masm, T address, JSValueType type)
{
if (type == JSVAL_TYPE_OBJECT)
EmitPreBarrier(masm, address, MIRType::Object);
else if (type == JSVAL_TYPE_STRING)
EmitPreBarrier(masm, address, MIRType::String);
else
MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(type));
}
bool
ICSetElem_DenseOrUnboxedArray::Compiler::generateStubCode(MacroAssembler& masm)
{
@ -2871,29 +2721,6 @@ ICSetElem_DenseOrUnboxedArray::Compiler::generateStubCode(MacroAssembler& masm)
masm.loadValue(valueAddr, tmpVal);
EmitPreBarrier(masm, element, MIRType::Value);
masm.storeValue(tmpVal, element);
} else {
// Set element on an unboxed array.
// Bounds check.
Address initLength(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
masm.load32(initLength, scratchReg);
masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), scratchReg);
masm.branch32(Assembler::BelowOrEqual, scratchReg, key, &failure);
// Load obj->elements.
masm.loadPtr(Address(obj, UnboxedArrayObject::offsetOfElements()), scratchReg);
// Compute the address being written to.
BaseIndex address(scratchReg, key, ScaleFromElemWidth(UnboxedTypeSize(unboxedType_)));
EmitUnboxedPreBarrierForBaseline(masm, address, unboxedType_);
Address valueAddr(masm.getStackPointer(), ICStackValueOffset + sizeof(Value));
masm.Push(R0);
masm.loadValue(valueAddr, R0);
masm.storeUnboxedProperty(address, unboxedType_,
ConstantOrRegister(TypedOrValueRegister(R0)), &failurePopR0);
masm.Pop(R0);
}
EmitReturnFromIC(masm);
@ -3087,40 +2914,6 @@ ICSetElemDenseOrUnboxedArrayAddCompiler::generateStubCode(MacroAssembler& masm)
BaseIndex element(scratchReg, key, TimesEight);
masm.loadValue(valueAddr, tmpVal);
masm.storeValue(tmpVal, element);
} else {
// Adding element to an unboxed array.
// Bounds check (key == initLength)
Address initLengthAddr(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
masm.load32(initLengthAddr, scratchReg);
masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), scratchReg);
masm.branch32(Assembler::NotEqual, scratchReg, key, &failure);
// Capacity check.
masm.checkUnboxedArrayCapacity(obj, RegisterOrInt32Constant(key), scratchReg, &failure);
// Load obj->elements.
masm.loadPtr(Address(obj, UnboxedArrayObject::offsetOfElements()), scratchReg);
// Write the value first, since this can fail. No need for pre-barrier
// since we're not overwriting an old value.
masm.Push(R0);
Address valueAddr(masm.getStackPointer(), ICStackValueOffset + sizeof(Value));
masm.loadValue(valueAddr, R0);
BaseIndex address(scratchReg, key, ScaleFromElemWidth(UnboxedTypeSize(unboxedType_)));
masm.storeUnboxedProperty(address, unboxedType_,
ConstantOrRegister(TypedOrValueRegister(R0)), &failurePopR0);
masm.Pop(R0);
// Increment initialized length.
masm.add32(Imm32(1), initLengthAddr);
// If length is now <= key, increment length.
Address lengthAddr(obj, UnboxedArrayObject::offsetOfLength());
Label skipIncrementLength;
masm.branch32(Assembler::Above, lengthAddr, key, &skipIncrementLength);
masm.add32(Imm32(1), lengthAddr);
masm.bind(&skipIncrementLength);
}
EmitReturnFromIC(masm);
@ -4256,18 +4049,7 @@ TryAttachSetValuePropStub(JSContext* cx, HandleScript script, jsbytecode* pc, IC
return true;
if (!obj->isNative()) {
if (obj->is<UnboxedPlainObject>()) {
UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando();
if (expando) {
shape = expando->lookup(cx, name);
if (!shape)
return true;
} else {
return true;
}
} else {
return true;
}
return true;
}
size_t chainDepth;
@ -4417,40 +4199,6 @@ TryAttachSetAccessorPropStub(JSContext* cx, HandleScript script, jsbytecode* pc,
return true;
}
static bool
TryAttachUnboxedSetPropStub(JSContext* cx, HandleScript script,
ICSetProp_Fallback* stub, HandleId id,
HandleObject obj, HandleValue rhs, bool* attached)
{
MOZ_ASSERT(!*attached);
if (!cx->runtime()->jitSupportsFloatingPoint)
return true;
if (!obj->is<UnboxedPlainObject>())
return true;
const UnboxedLayout::Property* property = obj->as<UnboxedPlainObject>().layout().lookup(id);
if (!property)
return true;
ICSetProp_Unboxed::Compiler compiler(cx, obj->group(),
property->offset + UnboxedPlainObject::offsetOfData(),
property->type);
ICUpdatedStub* newStub = compiler.getStub(compiler.getStubSpace(script));
if (!newStub)
return false;
if (compiler.needsUpdateStubs() && !newStub->addUpdateStubForValue(cx, script, obj, id, rhs))
return false;
stub->addNewStub(newStub);
StripPreliminaryObjectStubs(cx, stub);
*attached = true;
return true;
}
static bool
TryAttachTypedObjectSetPropStub(JSContext* cx, HandleScript script,
ICSetProp_Fallback* stub, HandleId id,
@ -4534,12 +4282,6 @@ DoSetPropFallback(JSContext* cx, BaselineFrame* frame, ICSetProp_Fallback* stub_
return false;
RootedReceiverGuard oldGuard(cx, ReceiverGuard(obj));
if (obj->is<UnboxedPlainObject>()) {
MOZ_ASSERT(!oldShape);
if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando())
oldShape = expando->lastProperty();
}
bool attached = false;
// There are some reasons we can fail to attach a stub that are temporary.
// We want to avoid calling noteUnoptimizableAccess() if the reason we
@ -4610,15 +4352,6 @@ DoSetPropFallback(JSContext* cx, BaselineFrame* frame, ICSetProp_Fallback* stub_
if (attached)
return true;
if (!attached &&
lhs.isObject() &&
!TryAttachUnboxedSetPropStub(cx, script, stub, id, obj, rhs, &attached))
{
return false;
}
if (attached)
return true;
if (!attached &&
lhs.isObject() &&
!TryAttachTypedObjectSetPropStub(cx, script, stub, id, obj, rhs, &attached))
@ -4703,20 +4436,7 @@ GuardGroupAndShapeMaybeUnboxedExpando(MacroAssembler& masm, JSObject* obj,
// Guard against shape or expando shape.
masm.loadPtr(Address(ICStubReg, offsetOfShape), scratch);
if (obj->is<UnboxedPlainObject>()) {
Address expandoAddress(object, UnboxedPlainObject::offsetOfExpando());
masm.branchPtr(Assembler::Equal, expandoAddress, ImmWord(0), failure);
Label done;
masm.push(object);
masm.loadPtr(expandoAddress, object);
masm.branchTestObjShape(Assembler::Equal, object, scratch, &done);
masm.pop(object);
masm.jump(failure);
masm.bind(&done);
masm.pop(object);
} else {
masm.branchTestObjShape(Assembler::NotEqual, object, scratch, failure);
}
masm.branchTestObjShape(Assembler::NotEqual, object, scratch, failure);
}
bool
@ -4755,13 +4475,7 @@ ICSetProp_Native::Compiler::generateStubCode(MacroAssembler& masm)
regs.takeUnchecked(objReg);
Register holderReg;
if (obj_->is<UnboxedPlainObject>()) {
// We are loading off the expando object, so use that for the holder.
holderReg = regs.takeAny();
masm.loadPtr(Address(objReg, UnboxedPlainObject::offsetOfExpando()), holderReg);
if (!isFixedSlot_)
masm.loadPtr(Address(holderReg, NativeObject::offsetOfSlots()), holderReg);
} else if (isFixedSlot_) {
if (isFixedSlot_) {
holderReg = objReg;
} else {
holderReg = regs.takeAny();
@ -4898,31 +4612,17 @@ ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler& masm)
regs.add(R0);
regs.takeUnchecked(objReg);
if (obj_->is<UnboxedPlainObject>()) {
holderReg = regs.takeAny();
masm.loadPtr(Address(objReg, UnboxedPlainObject::offsetOfExpando()), holderReg);
// Write the object's new shape.
Address shapeAddr(objReg, ShapedObject::offsetOfShape());
EmitPreBarrier(masm, shapeAddr, MIRType::Shape);
masm.loadPtr(Address(ICStubReg, ICSetProp_NativeAdd::offsetOfNewShape()), scratch);
masm.storePtr(scratch, shapeAddr);
// Write the expando object's new shape.
Address shapeAddr(holderReg, ShapedObject::offsetOfShape());
EmitPreBarrier(masm, shapeAddr, MIRType::Shape);
masm.loadPtr(Address(ICStubReg, ICSetProp_NativeAdd::offsetOfNewShape()), scratch);
masm.storePtr(scratch, shapeAddr);
if (!isFixedSlot_)
masm.loadPtr(Address(holderReg, NativeObject::offsetOfSlots()), holderReg);
if (isFixedSlot_) {
holderReg = objReg;
} else {
// Write the object's new shape.
Address shapeAddr(objReg, ShapedObject::offsetOfShape());
EmitPreBarrier(masm, shapeAddr, MIRType::Shape);
masm.loadPtr(Address(ICStubReg, ICSetProp_NativeAdd::offsetOfNewShape()), scratch);
masm.storePtr(scratch, shapeAddr);
if (isFixedSlot_) {
holderReg = objReg;
} else {
holderReg = regs.takeAny();
masm.loadPtr(Address(objReg, NativeObject::offsetOfSlots()), holderReg);
}
holderReg = regs.takeAny();
masm.loadPtr(Address(objReg, NativeObject::offsetOfSlots()), holderReg);
}
// Perform the store. No write barrier required since this is a new
@ -4953,70 +4653,6 @@ ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler& masm)
return true;
}
bool
ICSetProp_Unboxed::Compiler::generateStubCode(MacroAssembler& masm)
{
MOZ_ASSERT(engine_ == Engine::Baseline);
Label failure;
// Guard input is an object.
masm.branchTestObject(Assembler::NotEqual, R0, &failure);
AllocatableGeneralRegisterSet regs(availableGeneralRegs(2));
Register scratch = regs.takeAny();
// Unbox and group guard.
Register object = masm.extractObject(R0, ExtractTemp0);
masm.loadPtr(Address(ICStubReg, ICSetProp_Unboxed::offsetOfGroup()), scratch);
masm.branchPtr(Assembler::NotEqual, Address(object, JSObject::offsetOfGroup()), scratch,
&failure);
if (needsUpdateStubs()) {
// Stow both R0 and R1 (object and value).
EmitStowICValues(masm, 2);
// Move RHS into R0 for TypeUpdate check.
masm.moveValue(R1, R0);
// Call the type update stub.
if (!callTypeUpdateIC(masm, sizeof(Value)))
return false;
// Unstow R0 and R1 (object and key)
EmitUnstowICValues(masm, 2);
// The TypeUpdate IC may have smashed object. Rederive it.
masm.unboxObject(R0, object);
// Trigger post barriers here on the values being written. Fields which
// objects can be written to also need update stubs.
LiveGeneralRegisterSet saveRegs;
saveRegs.add(R0);
saveRegs.add(R1);
saveRegs.addUnchecked(object);
saveRegs.add(ICStubReg);
emitPostWriteBarrierSlot(masm, object, R1, scratch, saveRegs);
}
// Compute the address being written to.
masm.load32(Address(ICStubReg, ICSetProp_Unboxed::offsetOfFieldOffset()), scratch);
BaseIndex address(object, scratch, TimesOne);
EmitUnboxedPreBarrierForBaseline(masm, address, fieldType_);
masm.storeUnboxedProperty(address, fieldType_,
ConstantOrRegister(TypedOrValueRegister(R1)), &failure);
// The RHS has to be in R0.
masm.moveValue(R1, R0);
EmitReturnFromIC(masm);
masm.bind(&failure);
EmitStubGuardFailure(masm);
return true;
}
bool
ICSetProp_TypedObject::Compiler::generateStubCode(MacroAssembler& masm)
{
@ -5490,13 +5126,6 @@ GetTemplateObjectForSimd(JSContext* cx, JSFunction* target, MutableHandleObject
return true;
}
static void
EnsureArrayGroupAnalyzed(JSContext* cx, JSObject* obj)
{
if (PreliminaryObjectArrayWithTemplate* objects = obj->group()->maybePreliminaryObjects())
objects->maybeAnalyze(cx, obj->group(), /* forceAnalyze = */ true);
}
static bool
GetTemplateObjectForNative(JSContext* cx, HandleFunction target, const CallArgs& args,
MutableHandleObject res, bool* skipAttach)
@ -5528,10 +5157,7 @@ GetTemplateObjectForNative(JSContext* cx, HandleFunction target, const CallArgs&
// With this and other array templates, analyze the group so that
// we don't end up with a template whose structure might change later.
res.set(NewFullyAllocatedArrayForCallingAllocationSite(cx, count, TenuredObject));
if (!res)
return false;
EnsureArrayGroupAnalyzed(cx, res);
return true;
return !!res;
}
}
@ -5557,10 +5183,7 @@ GetTemplateObjectForNative(JSContext* cx, HandleFunction target, const CallArgs&
}
res.set(NewFullyAllocatedArrayTryReuseGroup(cx, &args.thisv().toObject(), 0,
TenuredObject));
if (!res)
return false;
EnsureArrayGroupAnalyzed(cx, res);
return true;
return !!res;
}
}
}
@ -5577,10 +5200,7 @@ GetTemplateObjectForNative(JSContext* cx, HandleFunction target, const CallArgs&
}
res.set(NewFullyAllocatedArrayForCallingAllocationSite(cx, 0, TenuredObject));
if (!res)
return false;
EnsureArrayGroupAnalyzed(cx, res);
return true;
return !!res;
}
if (native == StringConstructor) {
@ -5793,7 +5413,7 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb
if (!thisObject)
return false;
if (thisObject->is<PlainObject>() || thisObject->is<UnboxedPlainObject>())
if (thisObject->is<PlainObject>())
templateObject = thisObject;
}
@ -5887,15 +5507,24 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb
}
static bool
CopyArray(JSContext* cx, HandleObject obj, MutableHandleValue result)
CopyArray(JSContext* cx, HandleArrayObject arr, MutableHandleValue result)
{
uint32_t length = GetAnyBoxedOrUnboxedArrayLength(obj);
JSObject* nobj = NewFullyAllocatedArrayTryReuseGroup(cx, obj, length, TenuredObject);
uint32_t length = arr->length();
ArrayObject* nobj = NewFullyAllocatedArrayTryReuseGroup(cx, arr, length, TenuredObject);
if (!nobj)
return false;
EnsureArrayGroupAnalyzed(cx, nobj);
CopyAnyBoxedOrUnboxedDenseElements(cx, nobj, obj, 0, 0, length);
MOZ_ASSERT(arr->isNative());
MOZ_ASSERT(nobj->isNative());
MOZ_ASSERT(nobj->as<NativeObject>().getDenseInitializedLength() == 0);
MOZ_ASSERT(arr->as<NativeObject>().getDenseInitializedLength() >= length);
MOZ_ASSERT(nobj->as<NativeObject>().getDenseCapacity() >= length);
nobj->as<NativeObject>().setDenseInitializedLength(length);
const Value* vp = arr->as<NativeObject>().getDenseElements();
nobj->as<NativeObject>().initDenseElements(0, vp, length);
result.setObject(*nobj);
return true;
}
@ -5926,26 +5555,22 @@ TryAttachStringSplit(JSContext* cx, ICCall_Fallback* stub, HandleScript script,
RootedValue arr(cx);
// Copy the array before storing in stub.
if (!CopyArray(cx, obj, &arr))
if (!CopyArray(cx, obj.as<ArrayObject>(), &arr))
return false;
// Atomize all elements of the array.
RootedObject arrObj(cx, &arr.toObject());
uint32_t initLength = GetAnyBoxedOrUnboxedArrayLength(arrObj);
RootedArrayObject arrObj(cx, &arr.toObject().as<ArrayObject>());
uint32_t initLength = arrObj->length();
for (uint32_t i = 0; i < initLength; i++) {
JSAtom* str = js::AtomizeString(cx, GetAnyBoxedOrUnboxedDenseElement(arrObj, i).toString());
JSAtom* str = js::AtomizeString(cx, arrObj->getDenseElement(i).toString());
if (!str)
return false;
if (!SetAnyBoxedOrUnboxedDenseElement(cx, arrObj, i, StringValue(str))) {
// The value could not be stored to an unboxed dense element.
return true;
}
arrObj->setDenseElementWithType(cx, i, StringValue(str));
}
ICCall_StringSplit::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
script->pcToOffset(pc), str, sep,
arr);
script->pcToOffset(pc), str, sep, arrObj);
ICStub* newStub = compiler.getStub(compiler.getStubSpace(script));
if (!newStub)
return false;
@ -6830,7 +6455,7 @@ ICCallScriptedCompiler::generateStubCode(MacroAssembler& masm)
return true;
}
typedef bool (*CopyArrayFn)(JSContext*, HandleObject, MutableHandleValue);
typedef bool (*CopyArrayFn)(JSContext*, HandleArrayObject, MutableHandleValue);
static const VMFunction CopyArrayInfo = FunctionInfo<CopyArrayFn>(CopyArray, "CopyArray");
bool
@ -8301,19 +7926,6 @@ ICGetElem_Dense::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorSt
return New<ICGetElem_Dense>(cx, space, other.jitCode(), firstMonitorStub, other.shape_);
}
ICGetElem_UnboxedArray::ICGetElem_UnboxedArray(JitCode* stubCode, ICStub* firstMonitorStub,
ObjectGroup *group)
: ICMonitoredStub(GetElem_UnboxedArray, stubCode, firstMonitorStub),
group_(group)
{ }
/* static */ ICGetElem_UnboxedArray*
ICGetElem_UnboxedArray::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
ICGetElem_UnboxedArray& other)
{
return New<ICGetElem_UnboxedArray>(cx, space, other.jitCode(), firstMonitorStub, other.group_);
}
ICGetElem_TypedArray::ICGetElem_TypedArray(JitCode* stubCode, Shape* shape, Scalar::Type type)
: ICStub(GetElem_TypedArray, stubCode),
shape_(shape)
@ -8689,8 +8301,8 @@ static bool DoRestFallback(JSContext* cx, BaselineFrame* frame, ICRest_Fallback*
unsigned numRest = numActuals > numFormals ? numActuals - numFormals : 0;
Value* rest = frame->argv() + numFormals;
JSObject* obj = ObjectGroup::newArrayObject(cx, rest, numRest, GenericObject,
ObjectGroup::NewArrayKind::UnknownIndex);
ArrayObject* obj = ObjectGroup::newArrayObject(cx, rest, numRest, GenericObject,
ObjectGroup::NewArrayKind::UnknownIndex);
if (!obj)
return false;
res.setObject(*obj);

View File

@ -22,7 +22,6 @@
#include "jit/SharedICRegisters.h"
#include "js/GCVector.h"
#include "vm/ArrayObject.h"
#include "vm/UnboxedObject.h"
namespace js {
namespace jit {
@ -892,54 +891,6 @@ class ICGetElem_Dense : public ICMonitoredStub
};
};
class ICGetElem_UnboxedArray : public ICMonitoredStub
{
friend class ICStubSpace;
GCPtrObjectGroup group_;
ICGetElem_UnboxedArray(JitCode* stubCode, ICStub* firstMonitorStub, ObjectGroup* group);
public:
static ICGetElem_UnboxedArray* Clone(JSContext* cx, ICStubSpace* space,
ICStub* firstMonitorStub, ICGetElem_UnboxedArray& other);
static size_t offsetOfGroup() {
return offsetof(ICGetElem_UnboxedArray, group_);
}
GCPtrObjectGroup& group() {
return group_;
}
class Compiler : public ICStubCompiler {
ICStub* firstMonitorStub_;
RootedObjectGroup group_;
JSValueType elementType_;
protected:
MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
virtual int32_t getKey() const {
return static_cast<int32_t>(engine_) |
(static_cast<int32_t>(kind) << 1) |
(static_cast<int32_t>(elementType_) << 17);
}
public:
Compiler(JSContext* cx, ICStub* firstMonitorStub, ObjectGroup* group)
: ICStubCompiler(cx, ICStub::GetElem_UnboxedArray, Engine::Baseline),
firstMonitorStub_(firstMonitorStub),
group_(cx, group),
elementType_(group->unboxedLayoutDontCheckGeneration().elementType())
{}
ICStub* getStub(ICStubSpace* space) {
return newStub<ICGetElem_UnboxedArray>(space, getStubCode(), firstMonitorStub_, group_);
}
};
};
// Accesses scalar elements of a typed array or typed object.
class ICGetElem_TypedArray : public ICStub
{
@ -1115,9 +1066,7 @@ class ICSetElem_DenseOrUnboxedArray : public ICUpdatedStub
: ICStubCompiler(cx, ICStub::SetElem_DenseOrUnboxedArray, Engine::Baseline),
shape_(cx, shape),
group_(cx, group),
unboxedType_(shape
? JSVAL_TYPE_MAGIC
: group->unboxedLayoutDontCheckGeneration().elementType())
unboxedType_(JSVAL_TYPE_MAGIC)
{}
ICUpdatedStub* getStub(ICStubSpace* space) {
@ -1225,9 +1174,7 @@ class ICSetElemDenseOrUnboxedArrayAddCompiler : public ICStubCompiler {
: ICStubCompiler(cx, ICStub::SetElem_DenseOrUnboxedArrayAdd, Engine::Baseline),
obj_(cx, obj),
protoChainDepth_(protoChainDepth),
unboxedType_(obj->is<UnboxedArrayObject>()
? obj->as<UnboxedArrayObject>().elementType()
: JSVAL_TYPE_MAGIC)
unboxedType_(JSVAL_TYPE_MAGIC)
{}
template <size_t ProtoChainDepth>
@ -1875,8 +1822,7 @@ class ICSetProp_Native : public ICUpdatedStub
virtual int32_t getKey() const {
return static_cast<int32_t>(engine_) |
(static_cast<int32_t>(kind) << 1) |
(static_cast<int32_t>(isFixedSlot_) << 17) |
(static_cast<int32_t>(obj_->is<UnboxedPlainObject>()) << 18);
(static_cast<int32_t>(isFixedSlot_) << 17);
}
MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
@ -1981,7 +1927,6 @@ class ICSetPropNativeAddCompiler : public ICStubCompiler
return static_cast<int32_t>(engine_) |
(static_cast<int32_t>(kind) << 1) |
(static_cast<int32_t>(isFixedSlot_) << 17) |
(static_cast<int32_t>(obj_->is<UnboxedPlainObject>()) << 18) |
(static_cast<int32_t>(protoChainDepth_) << 19);
}
@ -2006,10 +1951,7 @@ class ICSetPropNativeAddCompiler : public ICStubCompiler
newGroup = nullptr;
RootedShape newShape(cx);
if (obj_->isNative())
newShape = obj_->as<NativeObject>().lastProperty();
else
newShape = obj_->as<UnboxedPlainObject>().maybeExpando()->lastProperty();
newShape = obj_->as<NativeObject>().lastProperty();
return newStub<ICSetProp_NativeAddImpl<ProtoChainDepth>>(
space, getStubCode(), oldGroup_, shapes, newShape, newGroup, offset_);
@ -2870,10 +2812,10 @@ class ICCall_StringSplit : public ICMonitoredStub
uint32_t pcOffset_;
GCPtrString expectedStr_;
GCPtrString expectedSep_;
GCPtrObject templateObject_;
GCPtrArrayObject templateObject_;
ICCall_StringSplit(JitCode* stubCode, ICStub* firstMonitorStub, uint32_t pcOffset, JSString* str,
JSString* sep, JSObject* templateObject)
JSString* sep, ArrayObject* templateObject)
: ICMonitoredStub(ICStub::Call_StringSplit, stubCode, firstMonitorStub),
pcOffset_(pcOffset), expectedStr_(str), expectedSep_(sep),
templateObject_(templateObject)
@ -2900,7 +2842,7 @@ class ICCall_StringSplit : public ICMonitoredStub
return expectedSep_;
}
GCPtrObject& templateObject() {
GCPtrArrayObject& templateObject() {
return templateObject_;
}
@ -2910,7 +2852,7 @@ class ICCall_StringSplit : public ICMonitoredStub
uint32_t pcOffset_;
RootedString expectedStr_;
RootedString expectedSep_;
RootedObject templateObject_;
RootedArrayObject templateObject_;
MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
@ -2921,13 +2863,13 @@ class ICCall_StringSplit : public ICMonitoredStub
public:
Compiler(JSContext* cx, ICStub* firstMonitorStub, uint32_t pcOffset, HandleString str,
HandleString sep, HandleValue templateObject)
HandleString sep, HandleArrayObject templateObject)
: ICCallStubCompiler(cx, ICStub::Call_StringSplit),
firstMonitorStub_(firstMonitorStub),
pcOffset_(pcOffset),
expectedStr_(cx, str),
expectedSep_(cx, sep),
templateObject_(cx, &templateObject.toObject())
templateObject_(cx, templateObject)
{ }
ICStub* getStub(ICStubSpace* space) {

View File

@ -96,32 +96,19 @@ VectorAppendNoDuplicate(S& list, T value)
static bool
AddReceiver(const ReceiverGuard& receiver,
BaselineInspector::ReceiverVector& receivers,
BaselineInspector::ObjectGroupVector& convertUnboxedGroups)
BaselineInspector::ReceiverVector& receivers)
{
if (receiver.group && receiver.group->maybeUnboxedLayout()) {
if (receiver.group->unboxedLayout().nativeGroup())
return VectorAppendNoDuplicate(convertUnboxedGroups, receiver.group);
}
return VectorAppendNoDuplicate(receivers, receiver);
}
static bool
GetCacheIRReceiverForNativeReadSlot(ICCacheIR_Monitored* stub, ReceiverGuard* receiver)
{
// We match either:
// We match:
//
// GuardIsObject 0
// GuardShape 0
// LoadFixedSlotResult 0 or LoadDynamicSlotResult 0
//
// or
//
// GuardIsObject 0
// GuardGroup 0
// 1: GuardAndLoadUnboxedExpando 0
// GuardShape 1
// LoadFixedSlotResult 1 or LoadDynamicSlotResult 1
*receiver = ReceiverGuard();
CacheIRReader reader(stub->stubInfo());
@ -130,14 +117,6 @@ GetCacheIRReceiverForNativeReadSlot(ICCacheIR_Monitored* stub, ReceiverGuard* re
if (!reader.matchOp(CacheOp::GuardIsObject, objId))
return false;
if (reader.matchOp(CacheOp::GuardGroup, objId)) {
receiver->group = stub->stubInfo()->getStubField<ObjectGroup*>(stub, reader.stubOffset());
if (!reader.matchOp(CacheOp::GuardAndLoadUnboxedExpando, objId))
return false;
objId = reader.objOperandId();
}
if (reader.matchOp(CacheOp::GuardShape, objId)) {
receiver->shape = stub->stubInfo()->getStubField<Shape*>(stub, reader.stubOffset());
return reader.matchOpEither(CacheOp::LoadFixedSlotResult, CacheOp::LoadDynamicSlotResult);
@ -146,40 +125,13 @@ GetCacheIRReceiverForNativeReadSlot(ICCacheIR_Monitored* stub, ReceiverGuard* re
return false;
}
static bool
GetCacheIRReceiverForUnboxedProperty(ICCacheIR_Monitored* stub, ReceiverGuard* receiver)
{
// We match:
//
// GuardIsObject 0
// GuardGroup 0
// LoadUnboxedPropertyResult 0 ..
*receiver = ReceiverGuard();
CacheIRReader reader(stub->stubInfo());
ObjOperandId objId = ObjOperandId(0);
if (!reader.matchOp(CacheOp::GuardIsObject, objId))
return false;
if (!reader.matchOp(CacheOp::GuardGroup, objId))
return false;
receiver->group = stub->stubInfo()->getStubField<ObjectGroup*>(stub, reader.stubOffset());
return reader.matchOp(CacheOp::LoadUnboxedPropertyResult, objId);
}
bool
BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receivers,
ObjectGroupVector& convertUnboxedGroups)
BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receivers)
{
// Return a list of the receivers seen by the baseline IC for the current
// op. Empty lists indicate no receivers are known, or there was an
// uncacheable access. convertUnboxedGroups is used for unboxed object
// groups which have been seen, but have had instances converted to native
// objects and should be eagerly converted by Ion.
// uncacheable access.
MOZ_ASSERT(receivers.empty());
MOZ_ASSERT(convertUnboxedGroups.empty());
if (!hasBaselineScript())
return true;
@ -191,8 +143,7 @@ BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receiv
while (stub->next()) {
ReceiverGuard receiver;
if (stub->isCacheIR_Monitored()) {
if (!GetCacheIRReceiverForNativeReadSlot(stub->toCacheIR_Monitored(), &receiver) &&
!GetCacheIRReceiverForUnboxedProperty(stub->toCacheIR_Monitored(), &receiver))
if (!GetCacheIRReceiverForNativeReadSlot(stub->toCacheIR_Monitored(), &receiver))
{
receivers.clear();
return true;
@ -200,14 +151,12 @@ BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receiv
} else if (stub->isSetProp_Native()) {
receiver = ReceiverGuard(stub->toSetProp_Native()->group(),
stub->toSetProp_Native()->shape());
} else if (stub->isSetProp_Unboxed()) {
receiver = ReceiverGuard(stub->toSetProp_Unboxed()->group(), nullptr);
} else {
receivers.clear();
return true;
}
if (!AddReceiver(receiver, receivers, convertUnboxedGroups))
if (!AddReceiver(receiver, receivers))
return false;
stub = stub->next();
@ -589,7 +538,7 @@ BaselineInspector::getTemplateObjectForNative(jsbytecode* pc, Native native)
bool
BaselineInspector::isOptimizableCallStringSplit(jsbytecode* pc, JSString** strOut, JSString** sepOut,
JSObject** objOut)
ArrayObject** objOut)
{
if (!hasBaselineScript())
return false;
@ -700,14 +649,12 @@ bool
BaselineInspector::commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape,
JSFunction** commonGetter, Shape** globalShape,
bool* isOwnProperty,
ReceiverVector& receivers,
ObjectGroupVector& convertUnboxedGroups)
ReceiverVector& receivers)
{
if (!hasBaselineScript())
return false;
MOZ_ASSERT(receivers.empty());
MOZ_ASSERT(convertUnboxedGroups.empty());
*holder = nullptr;
const ICEntry& entry = icEntryFromPC(pc);
@ -719,7 +666,7 @@ BaselineInspector::commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shap
{
ICGetPropCallGetter* nstub = static_cast<ICGetPropCallGetter*>(stub);
bool isOwn = nstub->isOwnGetter();
if (!isOwn && !AddReceiver(nstub->receiverGuard(), receivers, convertUnboxedGroups))
if (!isOwn && !AddReceiver(nstub->receiverGuard(), receivers))
return false;
if (!*holder) {
@ -751,21 +698,19 @@ BaselineInspector::commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shap
if (!*holder)
return false;
MOZ_ASSERT(*isOwnProperty == (receivers.empty() && convertUnboxedGroups.empty()));
MOZ_ASSERT(*isOwnProperty == (receivers.empty()));
return true;
}
bool
BaselineInspector::commonSetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape,
JSFunction** commonSetter, bool* isOwnProperty,
ReceiverVector& receivers,
ObjectGroupVector& convertUnboxedGroups)
ReceiverVector& receivers)
{
if (!hasBaselineScript())
return false;
MOZ_ASSERT(receivers.empty());
MOZ_ASSERT(convertUnboxedGroups.empty());
*holder = nullptr;
const ICEntry& entry = icEntryFromPC(pc);
@ -774,7 +719,7 @@ BaselineInspector::commonSetPropFunction(jsbytecode* pc, JSObject** holder, Shap
if (stub->isSetProp_CallScripted() || stub->isSetProp_CallNative()) {
ICSetPropCallSetter* nstub = static_cast<ICSetPropCallSetter*>(stub);
bool isOwn = nstub->isOwnSetter();
if (!isOwn && !AddReceiver(nstub->receiverGuard(), receivers, convertUnboxedGroups))
if (!isOwn && !AddReceiver(nstub->receiverGuard(), receivers))
return false;
if (!*holder) {

View File

@ -95,8 +95,7 @@ class BaselineInspector
public:
typedef Vector<ReceiverGuard, 4, JitAllocPolicy> ReceiverVector;
typedef Vector<ObjectGroup*, 4, JitAllocPolicy> ObjectGroupVector;
MOZ_MUST_USE bool maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receivers,
ObjectGroupVector& convertUnboxedGroups);
MOZ_MUST_USE bool maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receivers);
SetElemICInspector setElemICInspector(jsbytecode* pc) {
return makeICInspector<SetElemICInspector>(pc, ICStub::SetElem_Fallback);
@ -114,7 +113,7 @@ class BaselineInspector
bool hasSeenNonStringIterMore(jsbytecode* pc);
MOZ_MUST_USE bool isOptimizableCallStringSplit(jsbytecode* pc, JSString** strOut,
JSString** sepOut, JSObject** objOut);
JSString** sepOut, ArrayObject** objOut);
JSObject* getTemplateObject(jsbytecode* pc);
JSObject* getTemplateObjectForNative(jsbytecode* pc, Native native);
JSObject* getTemplateObjectForClassHook(jsbytecode* pc, const Class* clasp);
@ -131,12 +130,10 @@ class BaselineInspector
MOZ_MUST_USE bool commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape,
JSFunction** commonGetter, Shape** globalShape,
bool* isOwnProperty, ReceiverVector& receivers,
ObjectGroupVector& convertUnboxedGroups);
bool* isOwnProperty, ReceiverVector& receivers);
MOZ_MUST_USE bool commonSetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape,
JSFunction** commonSetter, bool* isOwnProperty,
ReceiverVector& receivers,
ObjectGroupVector& convertUnboxedGroups);
ReceiverVector& receivers);
MOZ_MUST_USE bool instanceOfData(jsbytecode* pc, Shape** shape, uint32_t* slot,
JSObject** prototypeObject);

View File

@ -10,8 +10,7 @@
#include "jit/IonCaches.h"
#include "jsobjinlines.h"
#include "vm/UnboxedObject-inl.h"
#include "vm/NativeObject-inl.h"
using namespace js;
using namespace js::jit;
@ -60,10 +59,6 @@ GetPropIRGenerator::tryAttachStub(Maybe<CacheIRWriter>& writer)
return false;
if (!emitted_ && !tryAttachNative(*writer, obj, objId))
return false;
if (!emitted_ && !tryAttachUnboxed(*writer, obj, objId))
return false;
if (!emitted_ && !tryAttachUnboxedExpando(*writer, obj, objId))
return false;
if (!emitted_ && !tryAttachTypedObject(*writer, obj, objId))
return false;
if (!emitted_ && !tryAttachModuleNamespace(*writer, obj, objId))
@ -163,19 +158,9 @@ GeneratePrototypeGuards(CacheIRWriter& writer, JSObject* obj, JSObject* holder,
}
static void
TestMatchingReceiver(CacheIRWriter& writer, JSObject* obj, Shape* shape, ObjOperandId objId,
Maybe<ObjOperandId>* expandoId)
TestMatchingReceiver(CacheIRWriter& writer, JSObject* obj, Shape* shape, ObjOperandId objId)
{
if (obj->is<UnboxedPlainObject>()) {
writer.guardGroup(objId, obj->group());
if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando()) {
expandoId->emplace(writer.guardAndLoadUnboxedExpando(objId));
writer.guardShape(expandoId->ref(), expando->lastProperty());
} else {
writer.guardNoUnboxedExpando(objId);
}
} else if (obj->is<UnboxedArrayObject>() || obj->is<TypedObject>()) {
if (obj->is<TypedObject>()) {
writer.guardGroup(objId, obj->group());
} else {
Shape* shape = obj->maybeShape();
@ -188,8 +173,7 @@ static void
EmitReadSlotResult(CacheIRWriter& writer, JSObject* obj, JSObject* holder,
Shape* shape, ObjOperandId objId)
{
Maybe<ObjOperandId> expandoId;
TestMatchingReceiver(writer, obj, shape, objId, &expandoId);
TestMatchingReceiver(writer, obj, shape, objId);
ObjOperandId holderId;
if (obj != holder) {
@ -212,9 +196,6 @@ EmitReadSlotResult(CacheIRWriter& writer, JSObject* obj, JSObject* holder,
lastObjId = protoId;
}
}
} else if (obj->is<UnboxedPlainObject>()) {
holder = obj->as<UnboxedPlainObject>().maybeExpando();
holderId = *expandoId;
} else {
holderId = objId;
}
@ -265,51 +246,6 @@ GetPropIRGenerator::tryAttachNative(CacheIRWriter& writer, HandleObject obj, Obj
return true;
}
bool
GetPropIRGenerator::tryAttachUnboxed(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId)
{
MOZ_ASSERT(!emitted_);
if (!obj->is<UnboxedPlainObject>())
return true;
const UnboxedLayout::Property* property = obj->as<UnboxedPlainObject>().layout().lookup(name_);
if (!property)
return true;
if (!cx_->runtime()->jitSupportsFloatingPoint)
return true;
writer.guardGroup(objId, obj->group());
writer.loadUnboxedPropertyResult(objId, property->type,
UnboxedPlainObject::offsetOfData() + property->offset);
emitted_ = true;
preliminaryObjectAction_ = PreliminaryObjectAction::Unlink;
return true;
}
bool
GetPropIRGenerator::tryAttachUnboxedExpando(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId)
{
MOZ_ASSERT(!emitted_);
if (!obj->is<UnboxedPlainObject>())
return true;
UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando();
if (!expando)
return true;
Shape* shape = expando->lookup(cx_, NameToId(name_));
if (!shape || !shape->hasDefaultGetter() || !shape->hasSlot())
return true;
emitted_ = true;
EmitReadSlotResult(writer, obj, obj, shape, objId);
return true;
}
bool
GetPropIRGenerator::tryAttachTypedObject(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId)
{
@ -368,13 +304,6 @@ GetPropIRGenerator::tryAttachObjectLength(CacheIRWriter& writer, HandleObject ob
return true;
}
if (obj->is<UnboxedArrayObject>()) {
writer.guardClass(objId, GuardClassKind::UnboxedArray);
writer.loadUnboxedArrayLengthResult(objId);
emitted_ = true;
return true;
}
if (obj->is<ArgumentsObject>() && !obj->as<ArgumentsObject>().hasOverriddenLength()) {
if (obj->is<MappedArgumentsObject>()) {
writer.guardClass(objId, GuardClassKind::MappedArguments);

View File

@ -87,16 +87,12 @@ class ObjOperandId : public OperandId
_(GuardClass) \
_(GuardSpecificObject) \
_(GuardNoDetachedTypedObjects) \
_(GuardNoUnboxedExpando) \
_(GuardAndLoadUnboxedExpando) \
_(LoadObject) \
_(LoadProto) \
_(LoadFixedSlotResult) \
_(LoadDynamicSlotResult) \
_(LoadUnboxedPropertyResult) \
_(LoadTypedObjectResult) \
_(LoadInt32ArrayLengthResult) \
_(LoadUnboxedArrayLengthResult) \
_(LoadArgumentsObjectLengthResult) \
_(LoadUndefinedResult)
@ -128,7 +124,6 @@ struct StubField {
enum class GuardClassKind
{
Array,
UnboxedArray,
MappedArguments,
UnmappedArguments,
};
@ -276,15 +271,6 @@ class MOZ_RAII CacheIRWriter
void guardNoDetachedTypedObjects() {
writeOp(CacheOp::GuardNoDetachedTypedObjects);
}
void guardNoUnboxedExpando(ObjOperandId obj) {
writeOpWithOperandId(CacheOp::GuardNoUnboxedExpando, obj);
}
ObjOperandId guardAndLoadUnboxedExpando(ObjOperandId obj) {
ObjOperandId res(nextOperandId_++);
writeOpWithOperandId(CacheOp::GuardAndLoadUnboxedExpando, obj);
writeOperandId(res);
return res;
}
ObjOperandId loadObject(JSObject* obj) {
ObjOperandId res(nextOperandId_++);
@ -310,11 +296,6 @@ class MOZ_RAII CacheIRWriter
writeOpWithOperandId(CacheOp::LoadDynamicSlotResult, obj);
addStubWord(offset, StubField::GCType::NoGCThing);
}
void loadUnboxedPropertyResult(ObjOperandId obj, JSValueType type, size_t offset) {
writeOpWithOperandId(CacheOp::LoadUnboxedPropertyResult, obj);
buffer_.writeByte(uint32_t(type));
addStubWord(offset, StubField::GCType::NoGCThing);
}
void loadTypedObjectResult(ObjOperandId obj, uint32_t offset, TypedThingLayout layout,
uint32_t typeDescr) {
MOZ_ASSERT(uint32_t(layout) <= UINT8_MAX);
@ -327,9 +308,6 @@ class MOZ_RAII CacheIRWriter
void loadInt32ArrayLengthResult(ObjOperandId obj) {
writeOpWithOperandId(CacheOp::LoadInt32ArrayLengthResult, obj);
}
void loadUnboxedArrayLengthResult(ObjOperandId obj) {
writeOpWithOperandId(CacheOp::LoadUnboxedArrayLengthResult, obj);
}
void loadArgumentsObjectLengthResult(ObjOperandId obj) {
writeOpWithOperandId(CacheOp::LoadArgumentsObjectLengthResult, obj);
}
@ -411,9 +389,6 @@ class MOZ_RAII GetPropIRGenerator
PreliminaryObjectAction preliminaryObjectAction_;
MOZ_MUST_USE bool tryAttachNative(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId);
MOZ_MUST_USE bool tryAttachUnboxed(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId);
MOZ_MUST_USE bool tryAttachUnboxedExpando(CacheIRWriter& writer, HandleObject obj,
ObjOperandId objId);
MOZ_MUST_USE bool tryAttachTypedObject(CacheIRWriter& writer, HandleObject obj,
ObjOperandId objId);
MOZ_MUST_USE bool tryAttachObjectLength(CacheIRWriter& writer, HandleObject obj,

View File

@ -25,6 +25,7 @@
#include "builtin/Eval.h"
#include "builtin/TypedObject.h"
#include "gc/Nursery.h"
#include "gc/StoreBuffer-inl.h"
#include "irregexp/NativeRegExpMacroAssembler.h"
#include "jit/AtomicOperations.h"
#include "jit/BaselineCompiler.h"
@ -3027,19 +3028,10 @@ CodeGenerator::visitStoreSlotV(LStoreSlotV* lir)
static void
GuardReceiver(MacroAssembler& masm, const ReceiverGuard& guard,
Register obj, Register scratch, Label* miss, bool checkNullExpando)
Register obj, Register scratch, Label* miss)
{
if (guard.group) {
masm.branchTestObjGroup(Assembler::NotEqual, obj, guard.group, miss);
Address expandoAddress(obj, UnboxedPlainObject::offsetOfExpando());
if (guard.shape) {
masm.loadPtr(expandoAddress, scratch);
masm.branchPtr(Assembler::Equal, scratch, ImmWord(0), miss);
masm.branchTestObjShape(Assembler::NotEqual, scratch, guard.shape, miss);
} else if (checkNullExpando) {
masm.branchPtr(Assembler::NotEqual, expandoAddress, ImmWord(0), miss);
}
} else {
masm.branchTestObjShape(Assembler::NotEqual, obj, guard.shape, miss);
}
@ -3058,13 +3050,11 @@ CodeGenerator::emitGetPropertyPolymorphic(LInstruction* ins, Register obj, Regis
Label next;
masm.comment("GuardReceiver");
GuardReceiver(masm, receiver, obj, scratch, &next, /* checkNullExpando = */ false);
GuardReceiver(masm, receiver, obj, scratch, &next);
if (receiver.shape) {
masm.comment("loadTypedOrValue");
// If this is an unboxed expando access, GuardReceiver loaded the
// expando object into scratch.
Register target = receiver.group ? scratch : obj;
Register target = obj;
Shape* shape = mir->shape(i);
if (shape->slot() < shape->numFixedSlots()) {
@ -3077,13 +3067,6 @@ CodeGenerator::emitGetPropertyPolymorphic(LInstruction* ins, Register obj, Regis
masm.loadPtr(Address(target, NativeObject::offsetOfSlots()), scratch);
masm.loadTypedOrValue(Address(scratch, offset), output);
}
} else {
masm.comment("loadUnboxedProperty");
const UnboxedLayout::Property* property =
receiver.group->unboxedLayout().lookup(mir->name());
Address propertyAddr(obj, UnboxedPlainObject::offsetOfData() + property->offset);
masm.loadUnboxedProperty(propertyAddr, property->type, output);
}
if (i == mir->numReceivers() - 1) {
@ -3124,8 +3107,6 @@ EmitUnboxedPreBarrier(MacroAssembler &masm, T address, JSValueType type)
masm.patchableCallPreBarrier(address, MIRType::Object);
else if (type == JSVAL_TYPE_STRING)
masm.patchableCallPreBarrier(address, MIRType::String);
else
MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(type));
}
void
@ -3139,12 +3120,10 @@ CodeGenerator::emitSetPropertyPolymorphic(LInstruction* ins, Register obj, Regis
ReceiverGuard receiver = mir->receiver(i);
Label next;
GuardReceiver(masm, receiver, obj, scratch, &next, /* checkNullExpando = */ false);
GuardReceiver(masm, receiver, obj, scratch, &next);
if (receiver.shape) {
// If this is an unboxed expando access, GuardReceiver loaded the
// expando object into scratch.
Register target = receiver.group ? scratch : obj;
Register target = obj;
Shape* shape = mir->shape(i);
if (shape->slot() < shape->numFixedSlots()) {
@ -3161,13 +3140,6 @@ CodeGenerator::emitSetPropertyPolymorphic(LInstruction* ins, Register obj, Regis
emitPreBarrier(addr);
masm.storeConstantOrRegister(value, addr);
}
} else {
const UnboxedLayout::Property* property =
receiver.group->unboxedLayout().lookup(mir->name());
Address propertyAddr(obj, UnboxedPlainObject::offsetOfData() + property->offset);
EmitUnboxedPreBarrier(masm, propertyAddr, property->type);
masm.storeUnboxedProperty(propertyAddr, property->type, value, nullptr);
}
if (i == mir->numReceivers() - 1) {
@ -3208,9 +3180,7 @@ CodeGenerator::visitSetPropertyPolymorphicT(LSetPropertyPolymorphicT* ins)
void
CodeGenerator::visitElements(LElements* lir)
{
Address elements(ToRegister(lir->object()),
lir->mir()->unboxed() ? UnboxedArrayObject::offsetOfElements()
: NativeObject::offsetOfElements());
Address elements(ToRegister(lir->object()), NativeObject::offsetOfElements());
masm.loadPtr(elements, ToRegister(lir->output()));
}
@ -3319,7 +3289,7 @@ CodeGenerator::visitGuardReceiverPolymorphic(LGuardReceiverPolymorphic* lir)
const ReceiverGuard& receiver = mir->receiver(i);
Label next;
GuardReceiver(masm, receiver, obj, temp, &next, /* checkNullExpando = */ true);
GuardReceiver(masm, receiver, obj, temp, &next);
if (i == mir->numReceivers() - 1) {
bailoutFrom(&next, lir->snapshot());
@ -3332,27 +3302,6 @@ CodeGenerator::visitGuardReceiverPolymorphic(LGuardReceiverPolymorphic* lir)
masm.bind(&done);
}
void
CodeGenerator::visitGuardUnboxedExpando(LGuardUnboxedExpando* lir)
{
Label miss;
Register obj = ToRegister(lir->object());
masm.branchPtr(lir->mir()->requireExpando() ? Assembler::Equal : Assembler::NotEqual,
Address(obj, UnboxedPlainObject::offsetOfExpando()), ImmWord(0), &miss);
bailoutFrom(&miss, lir->snapshot());
}
void
CodeGenerator::visitLoadUnboxedExpando(LLoadUnboxedExpando* lir)
{
Register obj = ToRegister(lir->object());
Register result = ToRegister(lir->getDef(0));
masm.loadPtr(Address(obj, UnboxedPlainObject::offsetOfExpando()), result);
}
void
CodeGenerator::visitTypeBarrierV(LTypeBarrierV* lir)
{
@ -5217,11 +5166,11 @@ static JSObject*
NewArrayWithGroup(JSContext* cx, uint32_t length, HandleObjectGroup group,
bool convertDoubleElements)
{
JSObject* res = NewFullyAllocatedArrayTryUseGroup(cx, group, length);
ArrayObject* res = NewFullyAllocatedArrayTryUseGroup(cx, group, length);
if (!res)
return nullptr;
if (convertDoubleElements)
res->as<ArrayObject>().setShouldConvertDoubleElements();
res->setShouldConvertDoubleElements();
return res;
}
@ -5367,7 +5316,7 @@ CodeGenerator::visitNewArrayCopyOnWrite(LNewArrayCopyOnWrite* lir)
masm.bind(ool->rejoin());
}
typedef JSObject* (*ArrayConstructorOneArgFn)(JSContext*, HandleObjectGroup, int32_t length);
typedef ArrayObject* (*ArrayConstructorOneArgFn)(JSContext*, HandleObjectGroup, int32_t length);
static const VMFunction ArrayConstructorOneArgInfo =
FunctionInfo<ArrayConstructorOneArgFn>(ArrayConstructorOneArg, "ArrayConstructorOneArg");
@ -5387,21 +5336,11 @@ CodeGenerator::visitNewArrayDynamicLength(LNewArrayDynamicLength* lir)
bool canInline = true;
size_t inlineLength = 0;
if (templateObject->is<ArrayObject>()) {
if (templateObject->as<ArrayObject>().hasFixedElements()) {
size_t numSlots = gc::GetGCKindSlots(templateObject->asTenured().getAllocKind());
inlineLength = numSlots - ObjectElements::VALUES_PER_HEADER;
} else {
canInline = false;
}
if (templateObject->as<ArrayObject>().hasFixedElements()) {
size_t numSlots = gc::GetGCKindSlots(templateObject->asTenured().getAllocKind());
inlineLength = numSlots - ObjectElements::VALUES_PER_HEADER;
} else {
if (templateObject->as<UnboxedArrayObject>().hasInlineElements()) {
size_t nbytes =
templateObject->tenuredSizeOfThis() - UnboxedArrayObject::offsetOfInlineElements();
inlineLength = nbytes / templateObject->as<UnboxedArrayObject>().elementSize();
} else {
canInline = false;
}
canInline = false;
}
if (canInline) {
@ -7823,7 +7762,7 @@ CodeGenerator::visitSinCos(LSinCos *lir)
masm.freeStack(sizeof(double) * 2);
}
typedef JSObject* (*StringSplitFn)(JSContext*, HandleObjectGroup, HandleString, HandleString, uint32_t);
typedef ArrayObject* (*StringSplitFn)(JSContext*, HandleObjectGroup, HandleString, HandleString, uint32_t);
static const VMFunction StringSplitInfo =
FunctionInfo<StringSplitFn>(js::str_split_string, "str_split_string");
@ -7857,49 +7796,6 @@ CodeGenerator::visitSetInitializedLength(LSetInitializedLength* lir)
masm.dec32(&index);
}
void
CodeGenerator::visitUnboxedArrayLength(LUnboxedArrayLength* lir)
{
Register obj = ToRegister(lir->object());
Register result = ToRegister(lir->output());
masm.load32(Address(obj, UnboxedArrayObject::offsetOfLength()), result);
}
void
CodeGenerator::visitUnboxedArrayInitializedLength(LUnboxedArrayInitializedLength* lir)
{
Register obj = ToRegister(lir->object());
Register result = ToRegister(lir->output());
masm.load32(Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), result);
masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), result);
}
void
CodeGenerator::visitIncrementUnboxedArrayInitializedLength(LIncrementUnboxedArrayInitializedLength* lir)
{
Register obj = ToRegister(lir->object());
masm.add32(Imm32(1), Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()));
}
void
CodeGenerator::visitSetUnboxedArrayInitializedLength(LSetUnboxedArrayInitializedLength* lir)
{
Register obj = ToRegister(lir->object());
RegisterOrInt32Constant key = ToRegisterOrInt32Constant(lir->length());
Register temp = ToRegister(lir->temp());
Address initLengthAddr(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
masm.load32(initLengthAddr, temp);
masm.and32(Imm32(UnboxedArrayObject::CapacityMask), temp);
if (key.isRegister())
masm.or32(key.reg(), temp);
else
masm.or32(Imm32(key.constant()), temp);
masm.store32(temp, initLengthAddr);
}
void
CodeGenerator::visitNotO(LNotO* lir)
{
@ -8196,46 +8092,19 @@ CodeGenerator::emitStoreElementHoleT(T* lir)
OutOfLineStoreElementHole* ool = new(alloc()) OutOfLineStoreElementHole(lir);
addOutOfLineCode(ool, lir->mir());
Register obj = ToRegister(lir->object());
Register elements = ToRegister(lir->elements());
const LAllocation* index = lir->index();
RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index);
JSValueType unboxedType = lir->mir()->unboxedType();
if (unboxedType == JSVAL_TYPE_MAGIC) {
Address initLength(elements, ObjectElements::offsetOfInitializedLength());
masm.branch32(Assembler::BelowOrEqual, initLength, key, ool->entry());
Address initLength(elements, ObjectElements::offsetOfInitializedLength());
masm.branch32(Assembler::BelowOrEqual, initLength, key, ool->entry());
if (lir->mir()->needsBarrier())
emitPreBarrier(elements, index, 0);
if (lir->mir()->needsBarrier())
emitPreBarrier(elements, index, 0);
masm.bind(ool->rejoinStore());
emitStoreElementTyped(lir->value(), lir->mir()->value()->type(), lir->mir()->elementType(),
elements, index, 0);
} else {
Register temp = ToRegister(lir->getTemp(0));
Address initLength(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
masm.load32(initLength, temp);
masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), temp);
masm.branch32(Assembler::BelowOrEqual, temp, key, ool->entry());
ConstantOrRegister v = ToConstantOrRegister(lir->value(), lir->mir()->value()->type());
if (index->isConstant()) {
Address address(elements, ToInt32(index) * UnboxedTypeSize(unboxedType));
EmitUnboxedPreBarrier(masm, address, unboxedType);
masm.bind(ool->rejoinStore());
masm.storeUnboxedProperty(address, unboxedType, v, nullptr);
} else {
BaseIndex address(elements, ToRegister(index),
ScaleFromElemWidth(UnboxedTypeSize(unboxedType)));
EmitUnboxedPreBarrier(masm, address, unboxedType);
masm.bind(ool->rejoinStore());
masm.storeUnboxedProperty(address, unboxedType, v, nullptr);
}
}
masm.bind(ool->rejoinStore());
emitStoreElementTyped(lir->value(), lir->mir()->value()->type(), lir->mir()->elementType(),
elements, index, 0);
masm.bind(ool->rejoin());
}
@ -8255,47 +8124,22 @@ CodeGenerator::emitStoreElementHoleV(T* lir)
OutOfLineStoreElementHole* ool = new(alloc()) OutOfLineStoreElementHole(lir);
addOutOfLineCode(ool, lir->mir());
Register obj = ToRegister(lir->object());
Register elements = ToRegister(lir->elements());
const LAllocation* index = lir->index();
const ValueOperand value = ToValue(lir, T::Value);
RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index);
JSValueType unboxedType = lir->mir()->unboxedType();
if (unboxedType == JSVAL_TYPE_MAGIC) {
Address initLength(elements, ObjectElements::offsetOfInitializedLength());
masm.branch32(Assembler::BelowOrEqual, initLength, key, ool->entry());
Address initLength(elements, ObjectElements::offsetOfInitializedLength());
masm.branch32(Assembler::BelowOrEqual, initLength, key, ool->entry());
if (lir->mir()->needsBarrier())
emitPreBarrier(elements, index, 0);
if (lir->mir()->needsBarrier())
emitPreBarrier(elements, index, 0);
masm.bind(ool->rejoinStore());
if (index->isConstant())
masm.storeValue(value, Address(elements, ToInt32(index) * sizeof(js::Value)));
else
masm.storeValue(value, BaseIndex(elements, ToRegister(index), TimesEight));
} else {
Register temp = ToRegister(lir->getTemp(0));
Address initLength(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
masm.load32(initLength, temp);
masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), temp);
masm.branch32(Assembler::BelowOrEqual, temp, key, ool->entry());
if (index->isConstant()) {
Address address(elements, ToInt32(index) * UnboxedTypeSize(unboxedType));
EmitUnboxedPreBarrier(masm, address, unboxedType);
masm.bind(ool->rejoinStore());
masm.storeUnboxedProperty(address, unboxedType, ConstantOrRegister(value), nullptr);
} else {
BaseIndex address(elements, ToRegister(index),
ScaleFromElemWidth(UnboxedTypeSize(unboxedType)));
EmitUnboxedPreBarrier(masm, address, unboxedType);
masm.bind(ool->rejoinStore());
masm.storeUnboxedProperty(address, unboxedType, ConstantOrRegister(value), nullptr);
}
}
masm.bind(ool->rejoinStore());
if (index->isConstant())
masm.storeValue(value, Address(elements, ToInt32(index) * sizeof(js::Value)));
else
masm.storeValue(value, BaseIndex(elements, ToRegister(index), TimesEight));
masm.bind(ool->rejoin());
}
@ -8366,11 +8210,10 @@ CodeGenerator::visitFallibleStoreElementV(LFallibleStoreElementV* lir)
masm.bind(&isFrozen);
}
typedef bool (*SetDenseOrUnboxedArrayElementFn)(JSContext*, HandleObject, int32_t,
HandleValue, bool strict);
static const VMFunction SetDenseOrUnboxedArrayElementInfo =
FunctionInfo<SetDenseOrUnboxedArrayElementFn>(SetDenseOrUnboxedArrayElement,
"SetDenseOrUnboxedArrayElement");
typedef bool (*SetDenseElementFn)(JSContext*, HandleNativeObject, int32_t, HandleValue,
bool strict);
static const VMFunction SetDenseElementInfo =
FunctionInfo<SetDenseElementFn>(jit::SetDenseElement, "SetDenseElement");
void
CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
@ -8380,8 +8223,6 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
const LAllocation* index;
MIRType valueType;
ConstantOrRegister value;
JSValueType unboxedType;
LDefinition *temp = nullptr;
if (ins->isStoreElementHoleV()) {
LStoreElementHoleV* store = ins->toStoreElementHoleV();
@ -8390,8 +8231,6 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
index = store->index();
valueType = store->mir()->value()->type();
value = TypedOrValueRegister(ToValue(store, LStoreElementHoleV::Value));
unboxedType = store->mir()->unboxedType();
temp = store->getTemp(0);
} else if (ins->isFallibleStoreElementV()) {
LFallibleStoreElementV* store = ins->toFallibleStoreElementV();
object = ToRegister(store->object());
@ -8399,8 +8238,6 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
index = store->index();
valueType = store->mir()->value()->type();
value = TypedOrValueRegister(ToValue(store, LFallibleStoreElementV::Value));
unboxedType = store->mir()->unboxedType();
temp = store->getTemp(0);
} else if (ins->isStoreElementHoleT()) {
LStoreElementHoleT* store = ins->toStoreElementHoleT();
object = ToRegister(store->object());
@ -8411,8 +8248,6 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
value = ConstantOrRegister(store->value()->toConstant()->toJSValue());
else
value = TypedOrValueRegister(valueType, ToAnyRegister(store->value()));
unboxedType = store->mir()->unboxedType();
temp = store->getTemp(0);
} else { // ins->isFallibleStoreElementT()
LFallibleStoreElementT* store = ins->toFallibleStoreElementT();
object = ToRegister(store->object());
@ -8423,8 +8258,6 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
value = ConstantOrRegister(store->value()->toConstant()->toJSValue());
else
value = TypedOrValueRegister(valueType, ToAnyRegister(store->value()));
unboxedType = store->mir()->unboxedType();
temp = store->getTemp(0);
}
RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index);
@ -8435,54 +8268,32 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
Label callStub;
#if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
// Had to reimplement for MIPS because there are no flags.
if (unboxedType == JSVAL_TYPE_MAGIC) {
Address initLength(elements, ObjectElements::offsetOfInitializedLength());
masm.branch32(Assembler::NotEqual, initLength, key, &callStub);
} else {
Address initLength(object, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
masm.load32(initLength, ToRegister(temp));
masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), ToRegister(temp));
masm.branch32(Assembler::NotEqual, ToRegister(temp), key, &callStub);
}
Address initLength(elements, ObjectElements::offsetOfInitializedLength());
masm.branch32(Assembler::NotEqual, initLength, key, &callStub);
#else
masm.j(Assembler::NotEqual, &callStub);
#endif
if (unboxedType == JSVAL_TYPE_MAGIC) {
// Check array capacity.
masm.branch32(Assembler::BelowOrEqual, Address(elements, ObjectElements::offsetOfCapacity()),
key, &callStub);
// Check array capacity.
masm.branch32(Assembler::BelowOrEqual, Address(elements, ObjectElements::offsetOfCapacity()),
key, &callStub);
// Update initialized length. The capacity guard above ensures this won't overflow,
// due to MAX_DENSE_ELEMENTS_COUNT.
masm.inc32(&key);
masm.store32(key, Address(elements, ObjectElements::offsetOfInitializedLength()));
// Update initialized length. The capacity guard above ensures this won't overflow,
// due to MAX_DENSE_ELEMENTS_COUNT.
masm.inc32(&key);
masm.store32(key, Address(elements, ObjectElements::offsetOfInitializedLength()));
// Update length if length < initializedLength.
Label dontUpdate;
masm.branch32(Assembler::AboveOrEqual, Address(elements, ObjectElements::offsetOfLength()),
key, &dontUpdate);
masm.store32(key, Address(elements, ObjectElements::offsetOfLength()));
masm.bind(&dontUpdate);
// Update length if length < initializedLength.
Label dontUpdate;
masm.branch32(Assembler::AboveOrEqual, Address(elements, ObjectElements::offsetOfLength()),
key, &dontUpdate);
masm.store32(key, Address(elements, ObjectElements::offsetOfLength()));
masm.bind(&dontUpdate);
masm.dec32(&key);
} else {
// Check array capacity.
masm.checkUnboxedArrayCapacity(object, key, ToRegister(temp), &callStub);
// Update initialized length.
masm.add32(Imm32(1), Address(object, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()));
// Update length if length < initializedLength.
Address lengthAddr(object, UnboxedArrayObject::offsetOfLength());
Label dontUpdate;
masm.branch32(Assembler::Above, lengthAddr, key, &dontUpdate);
masm.add32(Imm32(1), lengthAddr);
masm.bind(&dontUpdate);
}
masm.dec32(&key);
if ((ins->isStoreElementHoleT() || ins->isFallibleStoreElementT()) &&
unboxedType == JSVAL_TYPE_MAGIC && valueType != MIRType::Double)
valueType != MIRType::Double)
{
// The inline path for StoreElementHoleT and FallibleStoreElementT does not always store
// the type tag, so we do the store on the OOL path. We use MIRType::None for the element
@ -8511,7 +8322,7 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
else
pushArg(ToRegister(index));
pushArg(object);
callVM(SetDenseOrUnboxedArrayElementInfo, ins);
callVM(SetDenseElementInfo, ins);
restoreLive(ins);
masm.jump(ool->rejoin());
@ -8568,29 +8379,6 @@ CodeGenerator::visitStoreUnboxedPointer(LStoreUnboxedPointer* lir)
}
}
typedef bool (*ConvertUnboxedObjectToNativeFn)(JSContext*, JSObject*);
static const VMFunction ConvertUnboxedPlainObjectToNativeInfo =
FunctionInfo<ConvertUnboxedObjectToNativeFn>(UnboxedPlainObject::convertToNative,
"UnboxedPlainObject::convertToNative");
static const VMFunction ConvertUnboxedArrayObjectToNativeInfo =
FunctionInfo<ConvertUnboxedObjectToNativeFn>(UnboxedArrayObject::convertToNative,
"UnboxedArrayObject::convertToNative");
void
CodeGenerator::visitConvertUnboxedObjectToNative(LConvertUnboxedObjectToNative* lir)
{
Register object = ToRegister(lir->getOperand(0));
OutOfLineCode* ool = oolCallVM(lir->mir()->group()->unboxedLayoutDontCheckGeneration().isArray()
? ConvertUnboxedArrayObjectToNativeInfo
: ConvertUnboxedPlainObjectToNativeInfo,
lir, ArgList(object), StoreNothing());
masm.branchPtr(Assembler::Equal, Address(object, JSObject::offsetOfGroup()),
ImmGCPtr(lir->mir()->group()), ool->entry());
masm.bind(ool->rejoin());
}
typedef bool (*ArrayPopShiftFn)(JSContext*, HandleObject, MutableHandleValue);
static const VMFunction ArrayPopDenseInfo =
FunctionInfo<ArrayPopShiftFn>(jit::ArrayPopDense, "ArrayPopDense");
@ -8615,20 +8403,11 @@ CodeGenerator::emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, R
// Load elements and length, and VM call if length != initializedLength.
RegisterOrInt32Constant key = RegisterOrInt32Constant(lengthTemp);
if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp);
masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), lengthTemp);
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp);
masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), lengthTemp);
Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength());
masm.branch32(Assembler::NotEqual, initLength, key, ool->entry());
} else {
masm.loadPtr(Address(obj, UnboxedArrayObject::offsetOfElements()), elementsTemp);
masm.load32(Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), lengthTemp);
masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), lengthTemp);
Address lengthAddr(obj, UnboxedArrayObject::offsetOfLength());
masm.branch32(Assembler::NotEqual, lengthAddr, key, ool->entry());
}
Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength());
masm.branch32(Assembler::NotEqual, initLength, key, ool->entry());
// Test for length != 0. On zero length either take a VM call or generate
// an undefined value, depending on whether the call is known to produce
@ -8640,13 +8419,10 @@ CodeGenerator::emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, R
// According to the spec we need to set the length 0 (which is already 0).
// This is observable when the array length is made non-writable.
// Handle this case in the OOL. When freezing an unboxed array it is converted
// to an normal array.
if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
Address elementFlags(elementsTemp, ObjectElements::offsetOfFlags());
Imm32 bit(ObjectElements::NONWRITABLE_ARRAY_LENGTH);
masm.branchTest32(Assembler::NonZero, elementFlags, bit, ool->entry());
}
// Handle this case in the OOL.
Address elementFlags(elementsTemp, ObjectElements::offsetOfFlags());
Imm32 bit(ObjectElements::NONWRITABLE_ARRAY_LENGTH);
masm.branchTest32(Assembler::NonZero, elementFlags, bit, ool->entry());
masm.moveValue(UndefinedValue(), out.valueReg());
masm.jump(&done);
@ -8658,41 +8434,25 @@ CodeGenerator::emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, R
masm.dec32(&key);
if (mir->mode() == MArrayPopShift::Pop) {
if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
BaseIndex addr(elementsTemp, lengthTemp, TimesEight);
masm.loadElementTypedOrValue(addr, out, mir->needsHoleCheck(), ool->entry());
} else {
size_t elemSize = UnboxedTypeSize(mir->unboxedType());
BaseIndex addr(elementsTemp, lengthTemp, ScaleFromElemWidth(elemSize));
masm.loadUnboxedProperty(addr, mir->unboxedType(), out);
}
BaseIndex addr(elementsTemp, lengthTemp, TimesEight);
masm.loadElementTypedOrValue(addr, out, mir->needsHoleCheck(), ool->entry());
} else {
MOZ_ASSERT(mir->mode() == MArrayPopShift::Shift);
Address addr(elementsTemp, 0);
if (mir->unboxedType() == JSVAL_TYPE_MAGIC)
masm.loadElementTypedOrValue(addr, out, mir->needsHoleCheck(), ool->entry());
else
masm.loadUnboxedProperty(addr, mir->unboxedType(), out);
masm.loadElementTypedOrValue(addr, out, mir->needsHoleCheck(), ool->entry());
}
if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
// Handle the failure case when the array length is non-writable in the
// OOL path. (Unlike in the adding-an-element cases, we can't rely on the
// capacity <= length invariant for such arrays to avoid an explicit
// check.)
Address elementFlags(elementsTemp, ObjectElements::offsetOfFlags());
Imm32 bit(ObjectElements::NONWRITABLE_ARRAY_LENGTH);
masm.branchTest32(Assembler::NonZero, elementFlags, bit, ool->entry());
// Handle the failure case when the array length is non-writable in the
// OOL path. (Unlike in the adding-an-element cases, we can't rely on the
// capacity <= length invariant for such arrays to avoid an explicit
// check.)
Address elementFlags(elementsTemp, ObjectElements::offsetOfFlags());
Imm32 bit(ObjectElements::NONWRITABLE_ARRAY_LENGTH);
masm.branchTest32(Assembler::NonZero, elementFlags, bit, ool->entry());
// Now adjust length and initializedLength.
masm.store32(lengthTemp, Address(elementsTemp, ObjectElements::offsetOfLength()));
masm.store32(lengthTemp, Address(elementsTemp, ObjectElements::offsetOfInitializedLength()));
} else {
// Unboxed arrays always have writable lengths. Adjust length and
// initializedLength.
masm.store32(lengthTemp, Address(obj, UnboxedArrayObject::offsetOfLength()));
masm.add32(Imm32(-1), Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()));
}
// Now adjust length and initializedLength.
masm.store32(lengthTemp, Address(elementsTemp, ObjectElements::offsetOfLength()));
masm.store32(lengthTemp, Address(elementsTemp, ObjectElements::offsetOfInitializedLength()));
if (mir->mode() == MArrayPopShift::Shift) {
// Don't save the temp registers.
@ -8731,7 +8491,7 @@ CodeGenerator::visitArrayPopShiftT(LArrayPopShiftT* lir)
emitArrayPopShift(lir, lir->mir(), obj, elements, length, out);
}
typedef bool (*ArrayPushDenseFn)(JSContext*, HandleObject, HandleValue, uint32_t*);
typedef bool (*ArrayPushDenseFn)(JSContext*, HandleArrayObject, HandleValue, uint32_t*);
static const VMFunction ArrayPushDenseInfo =
FunctionInfo<ArrayPushDenseFn>(jit::ArrayPushDense, "ArrayPushDense");
@ -8742,50 +8502,27 @@ CodeGenerator::emitArrayPush(LInstruction* lir, const MArrayPush* mir, Register
OutOfLineCode* ool = oolCallVM(ArrayPushDenseInfo, lir, ArgList(obj, value), StoreRegisterTo(length));
RegisterOrInt32Constant key = RegisterOrInt32Constant(length);
if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
// Load elements and length.
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp);
masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), length);
// Guard length == initializedLength.
Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength());
masm.branch32(Assembler::NotEqual, initLength, key, ool->entry());
// Load elements and length.
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp);
masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), length);
// Guard length < capacity.
Address capacity(elementsTemp, ObjectElements::offsetOfCapacity());
masm.branch32(Assembler::BelowOrEqual, capacity, key, ool->entry());
// Guard length == initializedLength.
Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength());
masm.branch32(Assembler::NotEqual, initLength, key, ool->entry());
// Do the store.
masm.storeConstantOrRegister(value, BaseIndex(elementsTemp, length, TimesEight));
} else {
// Load initialized length.
masm.load32(Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), length);
masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), length);
// Guard length < capacity.
Address capacity(elementsTemp, ObjectElements::offsetOfCapacity());
masm.branch32(Assembler::BelowOrEqual, capacity, key, ool->entry());
// Guard length == initializedLength.
Address lengthAddr(obj, UnboxedArrayObject::offsetOfLength());
masm.branch32(Assembler::NotEqual, lengthAddr, key, ool->entry());
// Guard length < capacity.
masm.checkUnboxedArrayCapacity(obj, key, elementsTemp, ool->entry());
// Load elements and do the store.
masm.loadPtr(Address(obj, UnboxedArrayObject::offsetOfElements()), elementsTemp);
size_t elemSize = UnboxedTypeSize(mir->unboxedType());
BaseIndex addr(elementsTemp, length, ScaleFromElemWidth(elemSize));
masm.storeUnboxedProperty(addr, mir->unboxedType(), value, nullptr);
}
// Do the store.
masm.storeConstantOrRegister(value, BaseIndex(elementsTemp, length, TimesEight));
masm.inc32(&key);
// Update length and initialized length.
if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfLength()));
masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfInitializedLength()));
} else {
masm.store32(length, Address(obj, UnboxedArrayObject::offsetOfLength()));
masm.add32(Imm32(1), Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()));
}
masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfLength()));
masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfInitializedLength()));
masm.bind(ool->rejoin());
}
@ -8934,11 +8671,11 @@ CodeGenerator::visitIteratorStartO(LIteratorStartO* lir)
masm.loadPtr(Address(niTemp, offsetof(NativeIterator, guard_array)), temp2);
// Compare object with the first receiver guard. The last iterator can only
// match for native objects and unboxed objects.
// match for native objects.
{
Address groupAddr(temp2, offsetof(ReceiverGuard, group));
Address shapeAddr(temp2, offsetof(ReceiverGuard, shape));
Label guardDone, shapeMismatch, noExpando;
Label guardDone, shapeMismatch;
masm.loadObjShape(obj, temp1);
masm.branchPtr(Assembler::NotEqual, shapeAddr, temp1, &shapeMismatch);
@ -8950,12 +8687,6 @@ CodeGenerator::visitIteratorStartO(LIteratorStartO* lir)
masm.bind(&shapeMismatch);
masm.loadObjGroup(obj, temp1);
masm.branchPtr(Assembler::NotEqual, groupAddr, temp1, ool->entry());
masm.loadPtr(Address(obj, UnboxedPlainObject::offsetOfExpando()), temp1);
masm.branchTestPtr(Assembler::Zero, temp1, temp1, &noExpando);
branchIfNotEmptyObjectElements(temp1, ool->entry());
masm.loadObjShape(temp1, temp1);
masm.bind(&noExpando);
masm.branchPtr(Assembler::NotEqual, shapeAddr, temp1, ool->entry());
masm.bind(&guardDone);
}
@ -10590,22 +10321,11 @@ CodeGenerator::visitLoadElementHole(LLoadElementHole* lir)
else
masm.branch32(Assembler::BelowOrEqual, initLength, ToRegister(lir->index()), &undefined);
if (mir->unboxedType() != JSVAL_TYPE_MAGIC) {
size_t width = UnboxedTypeSize(mir->unboxedType());
if (lir->index()->isConstant()) {
Address addr(elements, ToInt32(lir->index()) * width);
masm.loadUnboxedProperty(addr, mir->unboxedType(), out);
} else {
BaseIndex addr(elements, ToRegister(lir->index()), ScaleFromElemWidth(width));
masm.loadUnboxedProperty(addr, mir->unboxedType(), out);
}
if (lir->index()->isConstant()) {
NativeObject::elementsSizeMustNotOverflow();
masm.loadValue(Address(elements, ToInt32(lir->index()) * sizeof(Value)), out);
} else {
if (lir->index()->isConstant()) {
NativeObject::elementsSizeMustNotOverflow();
masm.loadValue(Address(elements, ToInt32(lir->index()) * sizeof(Value)), out);
} else {
masm.loadValue(BaseObjectElementIndex(elements, ToRegister(lir->index())), out);
}
masm.loadValue(BaseObjectElementIndex(elements, ToRegister(lir->index())), out);
}
// If a hole check is needed, and the value wasn't a hole, we're done.
@ -10983,7 +10703,7 @@ CodeGenerator::visitInArray(LInArray* lir)
}
masm.branch32(Assembler::BelowOrEqual, initLength, Imm32(index), failedInitLength);
if (mir->needsHoleCheck() && mir->unboxedType() == JSVAL_TYPE_MAGIC) {
if (mir->needsHoleCheck()) {
NativeObject::elementsSizeMustNotOverflow();
Address address = Address(elements, index * sizeof(Value));
masm.branchTestMagic(Assembler::Equal, address, &falseBranch);
@ -10996,7 +10716,7 @@ CodeGenerator::visitInArray(LInArray* lir)
failedInitLength = &negativeIntCheck;
masm.branch32(Assembler::BelowOrEqual, initLength, index, failedInitLength);
if (mir->needsHoleCheck() && mir->unboxedType() == JSVAL_TYPE_MAGIC) {
if (mir->needsHoleCheck()) {
BaseIndex address = BaseIndex(elements, ToRegister(lir->index()), TimesEight);
masm.branchTestMagic(Assembler::Equal, address, &falseBranch);
}

View File

@ -148,8 +148,6 @@ class CodeGenerator final : public CodeGeneratorSpecific
void visitMaybeCopyElementsForWrite(LMaybeCopyElementsForWrite* lir);
void visitGuardObjectIdentity(LGuardObjectIdentity* guard);
void visitGuardReceiverPolymorphic(LGuardReceiverPolymorphic* lir);
void visitGuardUnboxedExpando(LGuardUnboxedExpando* lir);
void visitLoadUnboxedExpando(LLoadUnboxedExpando* lir);
void visitTypeBarrierV(LTypeBarrierV* lir);
void visitTypeBarrierO(LTypeBarrierO* lir);
void visitMonitorTypes(LMonitorTypes* lir);
@ -236,10 +234,6 @@ class CodeGenerator final : public CodeGeneratorSpecific
void visitSubstr(LSubstr* lir);
void visitInitializedLength(LInitializedLength* lir);
void visitSetInitializedLength(LSetInitializedLength* lir);
void visitUnboxedArrayLength(LUnboxedArrayLength* lir);
void visitUnboxedArrayInitializedLength(LUnboxedArrayInitializedLength* lir);
void visitIncrementUnboxedArrayInitializedLength(LIncrementUnboxedArrayInitializedLength* lir);
void visitSetUnboxedArrayInitializedLength(LSetUnboxedArrayInitializedLength* lir);
void visitNotO(LNotO* ins);
void visitNotV(LNotV* ins);
void visitBoundsCheck(LBoundsCheck* lir);
@ -310,7 +304,6 @@ class CodeGenerator final : public CodeGeneratorSpecific
void visitFallibleStoreElementV(LFallibleStoreElementV* lir);
void visitFallibleStoreElementT(LFallibleStoreElementT* lir);
void visitStoreUnboxedPointer(LStoreUnboxedPointer* lir);
void visitConvertUnboxedObjectToNative(LConvertUnboxedObjectToNative* lir);
void emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, Register obj,
Register elementsTemp, Register lengthTemp, TypedOrValueRegister out);
void visitArrayPopShiftV(LArrayPopShiftV* lir);

View File

@ -3515,8 +3515,6 @@ PassthroughOperand(MDefinition* def)
return def->toConvertElementsToDoubles()->elements();
if (def->isMaybeCopyElementsForWrite())
return def->toMaybeCopyElementsForWrite()->object();
if (def->isConvertUnboxedObjectToNative())
return def->toConvertUnboxedObjectToNative()->object();
return nullptr;
}

File diff suppressed because it is too large Load Diff

View File

@ -346,9 +346,8 @@ class IonBuilder
MConstant* constant(const Value& v);
MConstant* constantInt(int32_t i);
MInstruction* initializedLength(MDefinition* obj, MDefinition* elements,
JSValueType unboxedType);
MInstruction* setInitializedLength(MDefinition* obj, JSValueType unboxedType, size_t count);
MInstruction* initializedLength(MDefinition* obj, MDefinition* elements);
MInstruction* setInitializedLength(MDefinition* obj, size_t count);
// Improve the type information at tests
MOZ_MUST_USE bool improveTypesAtTest(MDefinition* ins, bool trueBranch, MTest* test);
@ -401,7 +400,6 @@ class IonBuilder
MInstruction* addBoundsCheck(MDefinition* index, MDefinition* length);
MInstruction* addShapeGuard(MDefinition* obj, Shape* const shape, BailoutKind bailoutKind);
MInstruction* addGroupGuard(MDefinition* obj, ObjectGroup* group, BailoutKind bailoutKind);
MInstruction* addUnboxedExpandoGuard(MDefinition* obj, bool hasExpando, BailoutKind bailoutKind);
MInstruction* addSharedTypedArrayGuard(MDefinition* obj);
MInstruction*
@ -441,8 +439,6 @@ class IonBuilder
BarrierKind barrier, TemporaryTypeSet* types);
MOZ_MUST_USE bool getPropTryModuleNamespace(bool* emitted, MDefinition* obj, PropertyName* name,
BarrierKind barrier, TemporaryTypeSet* types);
MOZ_MUST_USE bool getPropTryUnboxed(bool* emitted, MDefinition* obj, PropertyName* name,
BarrierKind barrier, TemporaryTypeSet* types);
MOZ_MUST_USE bool getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName* name,
TemporaryTypeSet* types);
MOZ_MUST_USE bool getPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName* name,
@ -475,9 +471,6 @@ class IonBuilder
MOZ_MUST_USE bool setPropTryDefiniteSlot(bool* emitted, MDefinition* obj,
PropertyName* name, MDefinition* value,
bool barrier, TemporaryTypeSet* objTypes);
MOZ_MUST_USE bool setPropTryUnboxed(bool* emitted, MDefinition* obj,
PropertyName* name, MDefinition* value,
bool barrier, TemporaryTypeSet* objTypes);
MOZ_MUST_USE bool setPropTryInlineAccess(bool* emitted, MDefinition* obj,
PropertyName* name, MDefinition* value,
bool barrier, TemporaryTypeSet* objTypes);
@ -617,7 +610,6 @@ class IonBuilder
TypedObjectPrediction elemTypeReprs,
uint32_t elemSize);
MOZ_MUST_USE bool initializeArrayElement(MDefinition* obj, size_t index, MDefinition* value,
JSValueType unboxedType,
bool addResumePointAndIncrementInitializedLength);
// jsop_getelem() helpers.
@ -729,15 +721,13 @@ class IonBuilder
MOZ_MUST_USE bool jsop_bindname(PropertyName* name);
MOZ_MUST_USE bool jsop_bindvar();
MOZ_MUST_USE bool jsop_getelem();
MOZ_MUST_USE bool jsop_getelem_dense(MDefinition* obj, MDefinition* index,
JSValueType unboxedType);
MOZ_MUST_USE bool jsop_getelem_dense(MDefinition* obj, MDefinition* index);
MOZ_MUST_USE bool jsop_getelem_typed(MDefinition* obj, MDefinition* index,
ScalarTypeDescr::Type arrayType);
MOZ_MUST_USE bool jsop_setelem();
MOZ_MUST_USE bool jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion,
MDefinition* object, MDefinition* index,
MDefinition* value, JSValueType unboxedType,
bool writeHole, bool* emitted);
MDefinition* value, bool writeHole, bool* emitted);
MOZ_MUST_USE bool jsop_setelem_typed(ScalarTypeDescr::Type arrayType,
MDefinition* object, MDefinition* index,
MDefinition* value);
@ -1041,7 +1031,6 @@ class IonBuilder
MDefinition*
addShapeGuardsForGetterSetter(MDefinition* obj, JSObject* holder, Shape* holderShape,
const BaselineInspector::ReceiverVector& receivers,
const BaselineInspector::ObjectGroupVector& convertUnboxedGroups,
bool isOwnProperty);
MOZ_MUST_USE bool annotateGetPropertyCache(MDefinition* obj, PropertyName* name,
@ -1059,22 +1048,6 @@ class IonBuilder
ResultWithOOM<bool> testNotDefinedProperty(MDefinition* obj, jsid id);
uint32_t getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_t* pnfixed);
MDefinition* convertUnboxedObjects(MDefinition* obj);
MDefinition* convertUnboxedObjects(MDefinition* obj,
const BaselineInspector::ObjectGroupVector& list);
uint32_t getUnboxedOffset(TemporaryTypeSet* types, PropertyName* name,
JSValueType* punboxedType);
MInstruction* loadUnboxedProperty(MDefinition* obj, size_t offset, JSValueType unboxedType,
BarrierKind barrier, TemporaryTypeSet* types);
MInstruction* loadUnboxedValue(MDefinition* elements, size_t elementsOffset,
MDefinition* scaledOffset, JSValueType unboxedType,
BarrierKind barrier, TemporaryTypeSet* types);
MInstruction* storeUnboxedProperty(MDefinition* obj, size_t offset, JSValueType unboxedType,
MDefinition* value);
MInstruction* storeUnboxedValue(MDefinition* obj,
MDefinition* elements, int32_t elementsOffset,
MDefinition* scaledOffset, JSValueType unboxedType,
MDefinition* value, bool preBarrier = true);
MOZ_MUST_USE bool checkPreliminaryGroups(MDefinition *obj);
MOZ_MUST_USE bool freezePropTypeSets(TemporaryTypeSet* types,
JSObject* foundProto, PropertyName* name);

View File

@ -619,29 +619,7 @@ TestMatchingReceiver(MacroAssembler& masm, IonCache::StubAttacher& attacher,
Register object, JSObject* obj, Label* failure,
bool alwaysCheckGroup = false)
{
if (obj->is<UnboxedPlainObject>()) {
MOZ_ASSERT(failure);
masm.branchTestObjGroup(Assembler::NotEqual, object, obj->group(), failure);
Address expandoAddress(object, UnboxedPlainObject::offsetOfExpando());
if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando()) {
masm.branchPtr(Assembler::Equal, expandoAddress, ImmWord(0), failure);
Label success;
masm.push(object);
masm.loadPtr(expandoAddress, object);
masm.branchTestObjShape(Assembler::Equal, object, expando->lastProperty(),
&success);
masm.pop(object);
masm.jump(failure);
masm.bind(&success);
masm.pop(object);
} else {
masm.branchPtr(Assembler::NotEqual, expandoAddress, ImmWord(0), failure);
}
} else if (obj->is<UnboxedArrayObject>()) {
MOZ_ASSERT(failure);
masm.branchTestObjGroup(Assembler::NotEqual, object, obj->group(), failure);
} else if (obj->is<TypedObject>()) {
if (obj->is<TypedObject>()) {
attacher.branchNextStubOrLabel(masm, Assembler::NotEqual,
Address(object, JSObject::offsetOfGroup()),
ImmGCPtr(obj->group()), failure);
@ -758,7 +736,6 @@ GenerateReadSlot(JSContext* cx, IonScript* ion, MacroAssembler& masm,
// jump directly. Otherwise, jump to the end of the stub, so there's a
// common point to patch.
bool multipleFailureJumps = (obj != holder)
|| obj->is<UnboxedPlainObject>()
|| (checkTDZ && output.hasValue())
|| (failures != nullptr && failures->used());
@ -777,7 +754,6 @@ GenerateReadSlot(JSContext* cx, IonScript* ion, MacroAssembler& masm,
Register scratchReg = Register::FromCode(0); // Quell compiler warning.
if (obj != holder ||
obj->is<UnboxedPlainObject>() ||
!holder->as<NativeObject>().isFixedSlot(shape->slot()))
{
if (output.hasValue()) {
@ -838,10 +814,6 @@ GenerateReadSlot(JSContext* cx, IonScript* ion, MacroAssembler& masm,
holderReg = InvalidReg;
}
} else if (obj->is<UnboxedPlainObject>()) {
holder = obj->as<UnboxedPlainObject>().maybeExpando();
holderReg = scratchReg;
masm.loadPtr(Address(object, UnboxedPlainObject::offsetOfExpando()), holderReg);
} else {
holderReg = object;
}
@ -869,30 +841,6 @@ GenerateReadSlot(JSContext* cx, IonScript* ion, MacroAssembler& masm,
attacher.jumpNextStub(masm);
}
static void
GenerateReadUnboxed(JSContext* cx, IonScript* ion, MacroAssembler& masm,
IonCache::StubAttacher& attacher, JSObject* obj,
const UnboxedLayout::Property* property,
Register object, TypedOrValueRegister output,
Label* failures = nullptr)
{
// Guard on the group of the object.
attacher.branchNextStubOrLabel(masm, Assembler::NotEqual,
Address(object, JSObject::offsetOfGroup()),
ImmGCPtr(obj->group()), failures);
Address address(object, UnboxedPlainObject::offsetOfData() + property->offset);
masm.loadUnboxedProperty(address, property->type, output);
attacher.jumpRejoin(masm);
if (failures) {
masm.bind(failures);
attacher.jumpNextStub(masm);
}
}
static bool
EmitGetterCall(JSContext* cx, MacroAssembler& masm,
IonCache::StubAttacher& attacher, JSObject* obj,
@ -1187,39 +1135,6 @@ GenerateArrayLength(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher&
return true;
}
static void
GenerateUnboxedArrayLength(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& attacher,
JSObject* array, Register object, TypedOrValueRegister output,
Label* failures)
{
Register outReg;
if (output.hasValue()) {
outReg = output.valueReg().scratchReg();
} else {
MOZ_ASSERT(output.type() == MIRType::Int32);
outReg = output.typedReg().gpr();
}
MOZ_ASSERT(object != outReg);
TestMatchingReceiver(masm, attacher, object, array, failures);
// Load length.
masm.load32(Address(object, UnboxedArrayObject::offsetOfLength()), outReg);
// Check for a length that fits in an int32.
masm.branchTest32(Assembler::Signed, outReg, outReg, failures);
if (output.hasValue())
masm.tagValue(JSVAL_TYPE_INT32, outReg, output.valueReg());
// Success.
attacher.jumpRejoin(masm);
// Failure.
masm.bind(failures);
attacher.jumpNextStub(masm);
}
// In this case, the code for TypedArray and SharedTypedArray is not the same,
// because the code embeds pointers to the respective class arrays. Code that
// caches the stub code must distinguish between the two cases.
@ -1532,101 +1447,6 @@ GetPropertyIC::tryAttachNative(JSContext* cx, HandleScript outerScript, IonScrip
return linkAndAttachStub(cx, masm, attacher, ion, attachKind, outcome);
}
bool
GetPropertyIC::tryAttachUnboxed(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject obj, HandleId id, void* returnAddr, bool* emitted)
{
MOZ_ASSERT(canAttachStub());
MOZ_ASSERT(!*emitted);
MOZ_ASSERT(outerScript->ionScript() == ion);
if (!obj->is<UnboxedPlainObject>())
return true;
const UnboxedLayout::Property* property = obj->as<UnboxedPlainObject>().layout().lookup(id);
if (!property)
return true;
*emitted = true;
MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_);
Label failures;
emitIdGuard(masm, id, &failures);
Label* maybeFailures = failures.used() ? &failures : nullptr;
StubAttacher attacher(*this);
GenerateReadUnboxed(cx, ion, masm, attacher, obj, property, object(), output(), maybeFailures);
return linkAndAttachStub(cx, masm, attacher, ion, "read unboxed",
JS::TrackedOutcome::ICGetPropStub_UnboxedRead);
}
bool
GetPropertyIC::tryAttachUnboxedExpando(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject obj, HandleId id, void* returnAddr, bool* emitted)
{
MOZ_ASSERT(canAttachStub());
MOZ_ASSERT(!*emitted);
MOZ_ASSERT(outerScript->ionScript() == ion);
if (!obj->is<UnboxedPlainObject>())
return true;
Rooted<UnboxedExpandoObject*> expando(cx, obj->as<UnboxedPlainObject>().maybeExpando());
if (!expando)
return true;
Shape* shape = expando->lookup(cx, id);
if (!shape || !shape->hasDefaultGetter() || !shape->hasSlot())
return true;
*emitted = true;
MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_);
Label failures;
emitIdGuard(masm, id, &failures);
Label* maybeFailures = failures.used() ? &failures : nullptr;
StubAttacher attacher(*this);
GenerateReadSlot(cx, ion, masm, attacher, DontCheckTDZ, obj, obj,
shape, object(), output(), maybeFailures);
return linkAndAttachStub(cx, masm, attacher, ion, "read unboxed expando",
JS::TrackedOutcome::ICGetPropStub_UnboxedReadExpando);
}
bool
GetPropertyIC::tryAttachUnboxedArrayLength(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject obj, HandleId id, void* returnAddr,
bool* emitted)
{
MOZ_ASSERT(canAttachStub());
MOZ_ASSERT(!*emitted);
MOZ_ASSERT(outerScript->ionScript() == ion);
if (!obj->is<UnboxedArrayObject>())
return true;
if (!JSID_IS_ATOM(id, cx->names().length))
return true;
if (obj->as<UnboxedArrayObject>().length() > INT32_MAX)
return true;
if (!allowArrayLength(cx))
return true;
*emitted = true;
MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_);
Label failures;
emitIdGuard(masm, id, &failures);
StubAttacher attacher(*this);
GenerateUnboxedArrayLength(cx, masm, attacher, obj, object(), output(), &failures);
return linkAndAttachStub(cx, masm, attacher, ion, "unboxed array length",
JS::TrackedOutcome::ICGetPropStub_UnboxedArrayLength);
}
bool
GetPropertyIC::tryAttachTypedArrayLength(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject obj, HandleId id, bool* emitted)
@ -2196,15 +2016,6 @@ GetPropertyIC::tryAttachStub(JSContext* cx, HandleScript outerScript, IonScript*
if (!*emitted && !tryAttachNative(cx, outerScript, ion, obj, id, returnAddr, emitted))
return false;
if (!*emitted && !tryAttachUnboxed(cx, outerScript, ion, obj, id, returnAddr, emitted))
return false;
if (!*emitted && !tryAttachUnboxedExpando(cx, outerScript, ion, obj, id, returnAddr, emitted))
return false;
if (!*emitted && !tryAttachUnboxedArrayLength(cx, outerScript, ion, obj, id, returnAddr, emitted))
return false;
if (!*emitted && !tryAttachTypedArrayLength(cx, outerScript, ion, obj, id, emitted))
return false;
}
@ -2383,12 +2194,6 @@ GenerateSetSlot(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& att
NativeObject::slotsSizeMustNotOverflow();
if (obj->is<UnboxedPlainObject>()) {
obj = obj->as<UnboxedPlainObject>().maybeExpando();
masm.loadPtr(Address(object, UnboxedPlainObject::offsetOfExpando()), tempReg);
object = tempReg;
}
if (obj->as<NativeObject>().isFixedSlot(shape->slot())) {
Address addr(object, NativeObject::getFixedSlotOffset(shape->slot()));
@ -3026,23 +2831,13 @@ GenerateAddSlot(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& att
masm.branchTestObjGroup(Assembler::NotEqual, object, oldGroup, failures);
if (obj->maybeShape()) {
masm.branchTestObjShape(Assembler::NotEqual, object, oldShape, failures);
} else {
MOZ_ASSERT(obj->is<UnboxedPlainObject>());
Address expandoAddress(object, UnboxedPlainObject::offsetOfExpando());
masm.branchPtr(Assembler::Equal, expandoAddress, ImmWord(0), failures);
masm.loadPtr(expandoAddress, tempReg);
masm.branchTestObjShape(Assembler::NotEqual, tempReg, oldShape, failures);
}
Shape* newShape = obj->maybeShape();
if (!newShape)
newShape = obj->as<UnboxedPlainObject>().maybeExpando()->lastProperty();
// Guard that the incoming value is in the type set for the property
// if a type barrier is required.
if (checkTypeset)
if (newShape && checkTypeset)
CheckTypeSetForWrite(masm, obj, newShape->propid(), tempReg, value, failures);
// Guard shapes along prototype chain.
@ -3063,9 +2858,7 @@ GenerateAddSlot(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& att
}
// Call a stub to (re)allocate dynamic slots, if necessary.
uint32_t newNumDynamicSlots = obj->is<UnboxedPlainObject>()
? obj->as<UnboxedPlainObject>().maybeExpando()->numDynamicSlots()
: obj->as<NativeObject>().numDynamicSlots();
uint32_t newNumDynamicSlots = obj->as<NativeObject>().numDynamicSlots();
if (NativeObject::dynamicSlotsCount(oldShape) != newNumDynamicSlots) {
AllocatableRegisterSet regs(RegisterSet::Volatile());
LiveRegisterSet save(regs.asLiveSet());
@ -3076,12 +2869,6 @@ GenerateAddSlot(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& att
Register temp1 = regs.takeAnyGeneral();
Register temp2 = regs.takeAnyGeneral();
if (obj->is<UnboxedPlainObject>()) {
// Pass the expando object to the stub.
masm.Push(object);
masm.loadPtr(Address(object, UnboxedPlainObject::offsetOfExpando()), object);
}
masm.setupUnalignedABICall(temp1);
masm.loadJSContext(temp1);
masm.passABIArg(temp1);
@ -3098,27 +2885,16 @@ GenerateAddSlot(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& att
masm.jump(&allocDone);
masm.bind(&allocFailed);
if (obj->is<UnboxedPlainObject>())
masm.Pop(object);
masm.PopRegsInMask(save);
masm.jump(failures);
masm.bind(&allocDone);
masm.setFramePushed(framePushedAfterCall);
if (obj->is<UnboxedPlainObject>())
masm.Pop(object);
masm.PopRegsInMask(save);
}
bool popObject = false;
if (obj->is<UnboxedPlainObject>()) {
masm.push(object);
popObject = true;
obj = obj->as<UnboxedPlainObject>().maybeExpando();
masm.loadPtr(Address(object, UnboxedPlainObject::offsetOfExpando()), object);
}
// Write the object or expando object's new shape.
Address shapeAddr(object, ShapedObject::offsetOfShape());
if (cx->zone()->needsIncrementalBarrier())
@ -3126,8 +2902,6 @@ GenerateAddSlot(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& att
masm.storePtr(ImmGCPtr(newShape), shapeAddr);
if (oldGroup != obj->group()) {
MOZ_ASSERT(!obj->is<UnboxedPlainObject>());
// Changing object's group from a partially to fully initialized group,
// per the acquired properties analysis. Only change the group if the
// old group still has a newScript.
@ -3370,141 +3144,6 @@ CanAttachNativeSetProp(JSContext* cx, HandleObject obj, HandleId id, const Const
return SetPropertyIC::CanAttachNone;
}
static void
GenerateSetUnboxed(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& attacher,
JSObject* obj, jsid id, uint32_t unboxedOffset, JSValueType unboxedType,
Register object, Register tempReg, const ConstantOrRegister& value,
bool checkTypeset, Label* failures)
{
// Guard on the type of the object.
masm.branchPtr(Assembler::NotEqual,
Address(object, JSObject::offsetOfGroup()),
ImmGCPtr(obj->group()), failures);
if (checkTypeset)
CheckTypeSetForWrite(masm, obj, id, tempReg, value, failures);
Address address(object, UnboxedPlainObject::offsetOfData() + unboxedOffset);
if (cx->zone()->needsIncrementalBarrier()) {
if (unboxedType == JSVAL_TYPE_OBJECT)
masm.callPreBarrier(address, MIRType::Object);
else if (unboxedType == JSVAL_TYPE_STRING)
masm.callPreBarrier(address, MIRType::String);
else
MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(unboxedType));
}
masm.storeUnboxedProperty(address, unboxedType, value, failures);
attacher.jumpRejoin(masm);
masm.bind(failures);
attacher.jumpNextStub(masm);
}
static bool
CanAttachSetUnboxed(JSContext* cx, HandleObject obj, HandleId id, const ConstantOrRegister& val,
bool needsTypeBarrier, bool* checkTypeset,
uint32_t* unboxedOffset, JSValueType* unboxedType)
{
if (!obj->is<UnboxedPlainObject>())
return false;
const UnboxedLayout::Property* property = obj->as<UnboxedPlainObject>().layout().lookup(id);
if (property) {
*checkTypeset = false;
if (needsTypeBarrier && !CanInlineSetPropTypeCheck(obj, id, val, checkTypeset))
return false;
*unboxedOffset = property->offset;
*unboxedType = property->type;
return true;
}
return false;
}
static bool
CanAttachSetUnboxedExpando(JSContext* cx, HandleObject obj, HandleId id,
const ConstantOrRegister& val,
bool needsTypeBarrier, bool* checkTypeset, Shape** pshape)
{
if (!obj->is<UnboxedPlainObject>())
return false;
Rooted<UnboxedExpandoObject*> expando(cx, obj->as<UnboxedPlainObject>().maybeExpando());
if (!expando)
return false;
Shape* shape = expando->lookupPure(id);
if (!shape || !shape->hasDefaultSetter() || !shape->hasSlot() || !shape->writable())
return false;
*checkTypeset = false;
if (needsTypeBarrier && !CanInlineSetPropTypeCheck(obj, id, val, checkTypeset))
return false;
*pshape = shape;
return true;
}
static bool
CanAttachAddUnboxedExpando(JSContext* cx, HandleObject obj, HandleShape oldShape,
HandleId id, const ConstantOrRegister& val,
bool needsTypeBarrier, bool* checkTypeset)
{
if (!obj->is<UnboxedPlainObject>())
return false;
Rooted<UnboxedExpandoObject*> expando(cx, obj->as<UnboxedPlainObject>().maybeExpando());
if (!expando || expando->inDictionaryMode())
return false;
Shape* newShape = expando->lastProperty();
if (newShape->isEmptyShape() || newShape->propid() != id || newShape->previous() != oldShape)
return false;
MOZ_ASSERT(newShape->hasDefaultSetter() && newShape->hasSlot() && newShape->writable());
if (PrototypeChainShadowsPropertyAdd(cx, obj, id))
return false;
*checkTypeset = false;
if (needsTypeBarrier && !CanInlineSetPropTypeCheck(obj, id, val, checkTypeset))
return false;
return true;
}
bool
SetPropertyIC::tryAttachUnboxed(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject obj, HandleId id, bool* emitted)
{
MOZ_ASSERT(!*emitted);
bool checkTypeset = false;
uint32_t unboxedOffset;
JSValueType unboxedType;
if (!CanAttachSetUnboxed(cx, obj, id, value(), needsTypeBarrier(), &checkTypeset,
&unboxedOffset, &unboxedType))
{
return true;
}
*emitted = true;
MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_);
StubAttacher attacher(*this);
Label failures;
emitIdGuard(masm, id, &failures);
GenerateSetUnboxed(cx, masm, attacher, obj, id, unboxedOffset, unboxedType,
object(), temp(), value(), checkTypeset, &failures);
return linkAndAttachStub(cx, masm, attacher, ion, "set_unboxed",
JS::TrackedOutcome::ICSetPropStub_SetUnboxed);
}
bool
SetPropertyIC::tryAttachProxy(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject obj, HandleId id, bool* emitted)
@ -3585,26 +3224,6 @@ SetPropertyIC::tryAttachNative(JSContext* cx, HandleScript outerScript, IonScrip
MOZ_CRASH("Unreachable");
}
bool
SetPropertyIC::tryAttachUnboxedExpando(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject obj, HandleId id, bool* emitted)
{
MOZ_ASSERT(!*emitted);
RootedShape shape(cx);
bool checkTypeset = false;
if (!CanAttachSetUnboxedExpando(cx, obj, id, value(), needsTypeBarrier(),
&checkTypeset, shape.address()))
{
return true;
}
if (!attachSetSlot(cx, outerScript, ion, obj, shape, checkTypeset))
return false;
*emitted = true;
return true;
}
bool
SetPropertyIC::tryAttachStub(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject obj, HandleValue idval, HandleValue value,
@ -3630,12 +3249,6 @@ SetPropertyIC::tryAttachStub(JSContext* cx, HandleScript outerScript, IonScript*
if (!*emitted && !tryAttachNative(cx, outerScript, ion, obj, id, emitted, tryNativeAddSlot))
return false;
if (!*emitted && !tryAttachUnboxed(cx, outerScript, ion, obj, id, emitted))
return false;
if (!*emitted && !tryAttachUnboxedExpando(cx, outerScript, ion, obj, id, emitted))
return false;
}
if (idval.isInt32()) {
@ -3687,16 +3300,6 @@ SetPropertyIC::tryAttachAddSlot(JSContext* cx, HandleScript outerScript, IonScri
return true;
}
checkTypeset = false;
if (CanAttachAddUnboxedExpando(cx, obj, oldShape, id, value(), needsTypeBarrier(),
&checkTypeset))
{
if (!attachAddSlot(cx, outerScript, ion, obj, id, oldShape, oldGroup, checkTypeset))
return false;
*emitted = true;
return true;
}
return true;
}
@ -3718,11 +3321,6 @@ SetPropertyIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex
return false;
oldShape = obj->maybeShape();
if (obj->is<UnboxedPlainObject>()) {
MOZ_ASSERT(!oldShape);
if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando())
oldShape = expando->lastProperty();
}
}
RootedId id(cx);
@ -4025,7 +3623,7 @@ GetPropertyIC::tryAttachDenseElementHole(JSContext* cx, HandleScript outerScript
GetPropertyIC::canAttachTypedOrUnboxedArrayElement(JSObject* obj, const Value& idval,
TypedOrValueRegister output)
{
if (!obj->is<TypedArrayObject>() && !obj->is<UnboxedArrayObject>())
if (!obj->is<TypedArrayObject>())
return false;
MOZ_ASSERT(idval.isInt32() || idval.isString());
@ -4056,13 +3654,6 @@ GetPropertyIC::canAttachTypedOrUnboxedArrayElement(JSObject* obj, const Value& i
return output.hasValue() || !output.typedReg().isFloat();
}
if (index >= obj->as<UnboxedArrayObject>().initializedLength())
return false;
JSValueType elementType = obj->as<UnboxedArrayObject>().elementType();
if (elementType == JSVAL_TYPE_DOUBLE)
return output.hasValue();
return output.hasValue() || !output.typedReg().isFloat();
}
@ -4139,46 +3730,27 @@ GenerateGetTypedOrUnboxedArrayElement(JSContext* cx, MacroAssembler& masm,
Label popObjectAndFail;
if (array->is<TypedArrayObject>()) {
// Guard on the initialized length.
Address length(object, TypedArrayObject::lengthOffset());
masm.branch32(Assembler::BelowOrEqual, length, indexReg, &failures);
// Guard on the initialized length.
Address length(object, TypedArrayObject::lengthOffset());
masm.branch32(Assembler::BelowOrEqual, length, indexReg, &failures);
// Save the object register on the stack in case of failure.
Register elementReg = object;
masm.push(object);
// Save the object register on the stack in case of failure.
Register elementReg = object;
masm.push(object);
// Load elements vector.
masm.loadPtr(Address(object, TypedArrayObject::dataOffset()), elementReg);
// Load elements vector.
masm.loadPtr(Address(object, TypedArrayObject::dataOffset()), elementReg);
// Load the value. We use an invalid register because the destination
// register is necessary a non double register.
Scalar::Type arrayType = array->as<TypedArrayObject>().type();
int width = Scalar::byteSize(arrayType);
BaseIndex source(elementReg, indexReg, ScaleFromElemWidth(width));
if (output.hasValue()) {
masm.loadFromTypedArray(arrayType, source, output.valueReg(), allowDoubleResult,
elementReg, &popObjectAndFail);
} else {
masm.loadFromTypedArray(arrayType, source, output.typedReg(), elementReg, &popObjectAndFail);
}
// Load the value. We use an invalid register because the destination
// register is necessary a non double register.
Scalar::Type arrayType = array->as<TypedArrayObject>().type();
int width = Scalar::byteSize(arrayType);
BaseIndex source(elementReg, indexReg, ScaleFromElemWidth(width));
if (output.hasValue()) {
masm.loadFromTypedArray(arrayType, source, output.valueReg(), allowDoubleResult,
elementReg, &popObjectAndFail);
} else {
// Save the object register on the stack in case of failure.
masm.push(object);
// Guard on the initialized length.
masm.load32(Address(object, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), object);
masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), object);
masm.branch32(Assembler::BelowOrEqual, object, indexReg, &popObjectAndFail);
// Load elements vector.
Register elementReg = object;
masm.loadPtr(Address(masm.getStackPointer(), 0), object);
masm.loadPtr(Address(object, UnboxedArrayObject::offsetOfElements()), elementReg);
JSValueType elementType = array->as<UnboxedArrayObject>().elementType();
BaseIndex source(elementReg, indexReg, ScaleFromElemWidth(UnboxedTypeSize(elementType)));
masm.loadUnboxedProperty(source, elementType, output);
masm.loadFromTypedArray(arrayType, source, output.typedReg(), elementReg, &popObjectAndFail);
}
masm.pop(object);

View File

@ -529,18 +529,6 @@ class GetPropertyIC : public IonCache
HandleObject obj, HandleId id, void* returnAddr,
bool* emitted);
MOZ_MUST_USE bool tryAttachUnboxed(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject obj, HandleId id, void* returnAddr,
bool* emitted);
MOZ_MUST_USE bool tryAttachUnboxedExpando(JSContext* cx, HandleScript outerScript,
IonScript* ion, HandleObject obj, HandleId id,
void* returnAddr, bool* emitted);
MOZ_MUST_USE bool tryAttachUnboxedArrayLength(JSContext* cx, HandleScript outerScript,
IonScript* ion, HandleObject obj, HandleId id,
void* returnAddr, bool* emitted);
MOZ_MUST_USE bool tryAttachTypedArrayLength(JSContext* cx, HandleScript outerScript,
IonScript* ion, HandleObject obj, HandleId id,
bool* emitted);

View File

@ -221,9 +221,6 @@ DefaultJitOptions::DefaultJitOptions()
Warn(forcedRegisterAllocatorEnv, env);
}
// Toggles whether unboxed plain objects can be created by the VM.
SET_DEFAULT(disableUnboxedObjects, true);
// Test whether Atomics are allowed in asm.js code.
SET_DEFAULT(asmJSAtomicsEnable, false);

View File

@ -91,9 +91,6 @@ struct DefaultJitOptions
mozilla::Maybe<uint32_t> forcedDefaultIonSmallFunctionWarmUpThreshold;
mozilla::Maybe<IonRegisterAllocator> forcedRegisterAllocator;
// The options below affect the rest of the VM, and not just the JIT.
bool disableUnboxedObjects;
DefaultJitOptions();
bool isSmallFunction(JSScript* script) const;
void setEagerCompilation();

View File

@ -2888,32 +2888,6 @@ LIRGenerator::visitSetInitializedLength(MSetInitializedLength* ins)
useRegisterOrConstant(ins->index())), ins);
}
void
LIRGenerator::visitUnboxedArrayLength(MUnboxedArrayLength* ins)
{
define(new(alloc()) LUnboxedArrayLength(useRegisterAtStart(ins->object())), ins);
}
void
LIRGenerator::visitUnboxedArrayInitializedLength(MUnboxedArrayInitializedLength* ins)
{
define(new(alloc()) LUnboxedArrayInitializedLength(useRegisterAtStart(ins->object())), ins);
}
void
LIRGenerator::visitIncrementUnboxedArrayInitializedLength(MIncrementUnboxedArrayInitializedLength* ins)
{
add(new(alloc()) LIncrementUnboxedArrayInitializedLength(useRegister(ins->object())), ins);
}
void
LIRGenerator::visitSetUnboxedArrayInitializedLength(MSetUnboxedArrayInitializedLength* ins)
{
add(new(alloc()) LSetUnboxedArrayInitializedLength(useRegister(ins->object()),
useRegisterOrConstant(ins->length()),
temp()), ins);
}
void
LIRGenerator::visitNot(MNot* ins)
{
@ -3163,22 +3137,16 @@ LIRGenerator::visitStoreElementHole(MStoreElementHole* ins)
const LUse elements = useRegister(ins->elements());
const LAllocation index = useRegisterOrConstant(ins->index());
// Use a temp register when adding new elements to unboxed arrays.
LDefinition tempDef = LDefinition::BogusTemp();
if (ins->unboxedType() != JSVAL_TYPE_MAGIC)
tempDef = temp();
LInstruction* lir;
switch (ins->value()->type()) {
case MIRType::Value:
lir = new(alloc()) LStoreElementHoleV(object, elements, index, useBox(ins->value()),
tempDef);
lir = new(alloc()) LStoreElementHoleV(object, elements, index, useBox(ins->value()));
break;
default:
{
const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
lir = new(alloc()) LStoreElementHoleT(object, elements, index, value, tempDef);
lir = new(alloc()) LStoreElementHoleT(object, elements, index, value);
break;
}
}
@ -3197,20 +3165,14 @@ LIRGenerator::visitFallibleStoreElement(MFallibleStoreElement* ins)
const LUse elements = useRegister(ins->elements());
const LAllocation index = useRegisterOrConstant(ins->index());
// Use a temp register when adding new elements to unboxed arrays.
LDefinition tempDef = LDefinition::BogusTemp();
if (ins->unboxedType() != JSVAL_TYPE_MAGIC)
tempDef = temp();
LInstruction* lir;
switch (ins->value()->type()) {
case MIRType::Value:
lir = new(alloc()) LFallibleStoreElementV(object, elements, index, useBox(ins->value()),
tempDef);
lir = new(alloc()) LFallibleStoreElementV(object, elements, index, useBox(ins->value()));
break;
default:
const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
lir = new(alloc()) LFallibleStoreElementT(object, elements, index, value, tempDef);
lir = new(alloc()) LFallibleStoreElementT(object, elements, index, value);
break;
}
@ -3251,14 +3213,6 @@ LIRGenerator::visitStoreUnboxedString(MStoreUnboxedString* ins)
add(lir, ins);
}
void
LIRGenerator::visitConvertUnboxedObjectToNative(MConvertUnboxedObjectToNative* ins)
{
LInstruction* check = new(alloc()) LConvertUnboxedObjectToNative(useRegister(ins->object()));
add(check, ins);
assignSafepoint(check, ins);
}
void
LIRGenerator::visitEffectiveAddress(MEffectiveAddress* ins)
{
@ -3776,24 +3730,6 @@ LIRGenerator::visitGuardReceiverPolymorphic(MGuardReceiverPolymorphic* ins)
redefine(ins, ins->object());
}
void
LIRGenerator::visitGuardUnboxedExpando(MGuardUnboxedExpando* ins)
{
LGuardUnboxedExpando* guard =
new(alloc()) LGuardUnboxedExpando(useRegister(ins->object()));
assignSnapshot(guard, ins->bailoutKind());
add(guard, ins);
redefine(ins, ins->object());
}
void
LIRGenerator::visitLoadUnboxedExpando(MLoadUnboxedExpando* ins)
{
LLoadUnboxedExpando* lir =
new(alloc()) LLoadUnboxedExpando(useRegisterAtStart(ins->object()));
define(lir, ins);
}
void
LIRGenerator::visitAssertRange(MAssertRange* ins)
{

View File

@ -216,10 +216,6 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitTypedObjectDescr(MTypedObjectDescr* ins);
void visitInitializedLength(MInitializedLength* ins);
void visitSetInitializedLength(MSetInitializedLength* ins);
void visitUnboxedArrayLength(MUnboxedArrayLength* ins);
void visitUnboxedArrayInitializedLength(MUnboxedArrayInitializedLength* ins);
void visitIncrementUnboxedArrayInitializedLength(MIncrementUnboxedArrayInitializedLength* ins);
void visitSetUnboxedArrayInitializedLength(MSetUnboxedArrayInitializedLength* ins);
void visitNot(MNot* ins);
void visitBoundsCheck(MBoundsCheck* ins);
void visitBoundsCheckLower(MBoundsCheckLower* ins);
@ -232,7 +228,6 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitFallibleStoreElement(MFallibleStoreElement* ins);
void visitStoreUnboxedObjectOrNull(MStoreUnboxedObjectOrNull* ins);
void visitStoreUnboxedString(MStoreUnboxedString* ins);
void visitConvertUnboxedObjectToNative(MConvertUnboxedObjectToNative* ins);
void visitEffectiveAddress(MEffectiveAddress* ins);
void visitArrayPopShift(MArrayPopShift* ins);
void visitArrayPush(MArrayPush* ins);
@ -256,8 +251,6 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitGuardObject(MGuardObject* ins);
void visitGuardString(MGuardString* ins);
void visitGuardReceiverPolymorphic(MGuardReceiverPolymorphic* ins);
void visitGuardUnboxedExpando(MGuardUnboxedExpando* ins);
void visitLoadUnboxedExpando(MLoadUnboxedExpando* ins);
void visitPolyInlineGuard(MPolyInlineGuard* ins);
void visitAssertRange(MAssertRange* ins);
void visitCallGetProperty(MCallGetProperty* ins);

View File

@ -30,7 +30,6 @@
#include "jit/shared/Lowering-shared-inl.h"
#include "vm/NativeObject-inl.h"
#include "vm/StringObject-inl.h"
#include "vm/UnboxedObject-inl.h"
using mozilla::ArrayLength;
using mozilla::AssertedCast;
@ -475,11 +474,6 @@ IonBuilder::inlineArray(CallInfo& callInfo)
return InliningStatus_NotInlined;
}
if (templateObject->is<UnboxedArrayObject>()) {
if (templateObject->group()->unboxedLayout().nativeGroup())
return InliningStatus_NotInlined;
}
// Multiple arguments imply array initialization, not just construction.
if (callInfo.argc() >= 2) {
initLength = callInfo.argc();
@ -527,7 +521,7 @@ IonBuilder::inlineArray(CallInfo& callInfo)
// Make sure initLength matches the template object's length. This is
// not guaranteed to be the case, for instance if we're inlining the
// MConstant may come from an outer script.
if (initLength != GetAnyBoxedOrUnboxedArrayLength(templateObject))
if (initLength != templateObject->as<ArrayObject>().length())
return InliningStatus_NotInlined;
// Don't inline large allocations.
@ -542,16 +536,15 @@ IonBuilder::inlineArray(CallInfo& callInfo)
MDefinition* array = current->peek(-1);
if (callInfo.argc() >= 2) {
JSValueType unboxedType = GetBoxedOrUnboxedType(templateObject);
for (uint32_t i = 0; i < initLength; i++) {
if (!alloc().ensureBallast())
return InliningStatus_Error;
MDefinition* value = callInfo.getArg(i);
if (!initializeArrayElement(array, i, value, unboxedType, /* addResumePoint = */ false))
if (!initializeArrayElement(array, i, value, /* addResumePoint = */ false))
return InliningStatus_Error;
}
MInstruction* setLength = setInitializedLength(array, unboxedType, initLength);
MInstruction* setLength = setInitializedLength(array, initLength);
if (!resumeAfter(setLength))
return InliningStatus_Error;
}
@ -584,7 +577,7 @@ IonBuilder::inlineArrayIsArray(CallInfo& callInfo)
if (!clasp || clasp->isProxy())
return InliningStatus_NotInlined;
isArray = (clasp == &ArrayObject::class_ || clasp == &UnboxedArrayObject::class_);
isArray = (clasp == &ArrayObject::class_);
}
pushConstant(BooleanValue(isArray));
@ -615,12 +608,12 @@ IonBuilder::inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode)
OBJECT_FLAG_LENGTH_OVERFLOW |
OBJECT_FLAG_ITERATED;
MDefinition* obj = convertUnboxedObjects(callInfo.thisArg());
MDefinition* obj = callInfo.thisArg();
TemporaryTypeSet* thisTypes = obj->resultTypeSet();
if (!thisTypes)
return InliningStatus_NotInlined;
const Class* clasp = thisTypes->getKnownClass(constraints());
if (clasp != &ArrayObject::class_ && clasp != &UnboxedArrayObject::class_)
if (clasp != &ArrayObject::class_)
return InliningStatus_NotInlined;
if (thisTypes->hasObjectFlags(constraints(), unhandledFlags)) {
trackOptimizationOutcome(TrackedOutcome::ArrayBadFlags);
@ -632,17 +625,9 @@ IonBuilder::inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode)
return InliningStatus_NotInlined;
}
JSValueType unboxedType = JSVAL_TYPE_MAGIC;
if (clasp == &UnboxedArrayObject::class_) {
unboxedType = UnboxedArrayElementType(constraints(), obj, nullptr);
if (unboxedType == JSVAL_TYPE_MAGIC)
return InliningStatus_NotInlined;
}
callInfo.setImplicitlyUsedUnchecked();
if (clasp == &ArrayObject::class_)
obj = addMaybeCopyElementsForWrite(obj, /* checkNative = */ false);
obj = addMaybeCopyElementsForWrite(obj, /* checkNative = */ false);
TemporaryTypeSet* returnTypes = getInlineReturnTypeSet();
bool needsHoleCheck = thisTypes->hasObjectFlags(constraints(), OBJECT_FLAG_NON_PACKED);
@ -653,8 +638,7 @@ IonBuilder::inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode)
if (barrier != BarrierKind::NoBarrier)
returnType = MIRType::Value;
MArrayPopShift* ins = MArrayPopShift::New(alloc(), obj, mode,
unboxedType, needsHoleCheck, maybeUndefined);
MArrayPopShift* ins = MArrayPopShift::New(alloc(), obj, mode, needsHoleCheck, maybeUndefined);
current->add(ins);
current->push(ins);
ins->setResultType(returnType);
@ -743,7 +727,7 @@ IonBuilder::inlineArrayPush(CallInfo& callInfo)
return InliningStatus_NotInlined;
}
MDefinition* obj = convertUnboxedObjects(callInfo.thisArg());
MDefinition* obj = callInfo.thisArg();
MDefinition* value = callInfo.getArg(0);
if (PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current,
&obj, nullptr, &value, /* canModify = */ false))
@ -761,7 +745,7 @@ IonBuilder::inlineArrayPush(CallInfo& callInfo)
if (!thisTypes)
return InliningStatus_NotInlined;
const Class* clasp = thisTypes->getKnownClass(constraints());
if (clasp != &ArrayObject::class_ && clasp != &UnboxedArrayObject::class_)
if (clasp != &ArrayObject::class_)
return InliningStatus_NotInlined;
if (thisTypes->hasObjectFlags(constraints(), OBJECT_FLAG_SPARSE_INDEXES |
OBJECT_FLAG_LENGTH_OVERFLOW))
@ -782,13 +766,6 @@ IonBuilder::inlineArrayPush(CallInfo& callInfo)
return InliningStatus_NotInlined;
}
JSValueType unboxedType = JSVAL_TYPE_MAGIC;
if (clasp == &UnboxedArrayObject::class_) {
unboxedType = UnboxedArrayElementType(constraints(), obj, nullptr);
if (unboxedType == JSVAL_TYPE_MAGIC)
return InliningStatus_NotInlined;
}
callInfo.setImplicitlyUsedUnchecked();
if (conversion == TemporaryTypeSet::AlwaysConvertToDoubles ||
@ -799,13 +776,12 @@ IonBuilder::inlineArrayPush(CallInfo& callInfo)
value = valueDouble;
}
if (unboxedType == JSVAL_TYPE_MAGIC)
obj = addMaybeCopyElementsForWrite(obj, /* checkNative = */ false);
obj = addMaybeCopyElementsForWrite(obj, /* checkNative = */ false);
if (NeedsPostBarrier(value))
current->add(MPostWriteBarrier::New(alloc(), obj, value));
MArrayPush* ins = MArrayPush::New(alloc(), obj, value, unboxedType);
MArrayPush* ins = MArrayPush::New(alloc(), obj, value);
current->add(ins);
current->push(ins);
@ -822,7 +798,7 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo)
return InliningStatus_NotInlined;
}
MDefinition* obj = convertUnboxedObjects(callInfo.thisArg());
MDefinition* obj = callInfo.thisArg();
// Ensure |this| and result are objects.
if (getInlineReturnType() != MIRType::Object)
@ -846,7 +822,7 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo)
return InliningStatus_NotInlined;
const Class* clasp = thisTypes->getKnownClass(constraints());
if (clasp != &ArrayObject::class_ && clasp != &UnboxedArrayObject::class_)
if (clasp != &ArrayObject::class_)
return InliningStatus_NotInlined;
if (thisTypes->hasObjectFlags(constraints(), OBJECT_FLAG_SPARSE_INDEXES |
OBJECT_FLAG_LENGTH_OVERFLOW))
@ -855,13 +831,6 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo)
return InliningStatus_NotInlined;
}
JSValueType unboxedType = JSVAL_TYPE_MAGIC;
if (clasp == &UnboxedArrayObject::class_) {
unboxedType = UnboxedArrayElementType(constraints(), obj, nullptr);
if (unboxedType == JSVAL_TYPE_MAGIC)
return InliningStatus_NotInlined;
}
// Watch out for indexed properties on the prototype.
if (ArrayPrototypeHasIndexedProperty(this, script())) {
trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps);
@ -882,15 +851,8 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo)
if (!templateObj)
return InliningStatus_NotInlined;
if (unboxedType == JSVAL_TYPE_MAGIC) {
if (!templateObj->is<ArrayObject>())
return InliningStatus_NotInlined;
} else {
if (!templateObj->is<UnboxedArrayObject>())
return InliningStatus_NotInlined;
if (templateObj->as<UnboxedArrayObject>().elementType() != unboxedType)
return InliningStatus_NotInlined;
}
if (!templateObj->is<ArrayObject>())
return InliningStatus_NotInlined;
callInfo.setImplicitlyUsedUnchecked();
@ -909,16 +871,12 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo)
end = MArrayLength::New(alloc(), elements);
current->add(end->toInstruction());
} else {
end = MUnboxedArrayLength::New(alloc(), obj);
current->add(end->toInstruction());
}
MArraySlice* ins = MArraySlice::New(alloc(), constraints(),
obj, begin, end,
templateObj,
templateObj->group()->initialHeap(constraints()),
unboxedType);
templateObj->group()->initialHeap(constraints()));
current->add(ins);
current->push(ins);
@ -1437,7 +1395,7 @@ IonBuilder::inlineConstantStringSplitString(CallInfo& callInfo)
// Check if exist a template object in stub.
JSString* stringStr = nullptr;
JSString* stringSep = nullptr;
JSObject* templateObject = nullptr;
ArrayObject* templateObject = nullptr;
if (!inspector->isOptimizableCallStringSplit(pc, &stringStr, &stringSep, &templateObject))
return InliningStatus_NotInlined;
@ -1463,13 +1421,13 @@ IonBuilder::inlineConstantStringSplitString(CallInfo& callInfo)
if (!key.maybeTypes()->hasType(TypeSet::StringType()))
return InliningStatus_NotInlined;
uint32_t initLength = GetAnyBoxedOrUnboxedArrayLength(templateObject);
if (GetAnyBoxedOrUnboxedInitializedLength(templateObject) != initLength)
uint32_t initLength = templateObject->length();
if (templateObject->getDenseInitializedLength() != initLength)
return InliningStatus_NotInlined;
Vector<MConstant*, 0, SystemAllocPolicy> arrayValues;
for (uint32_t i = 0; i < initLength; i++) {
Value str = GetAnyBoxedOrUnboxedDenseElement(templateObject, i);
Value str = templateObject->getDenseElement(i);
MOZ_ASSERT(str.toString()->isAtom());
MConstant* value = MConstant::New(alloc().fallible(), str, constraints());
if (!value)
@ -1500,8 +1458,6 @@ IonBuilder::inlineConstantStringSplitString(CallInfo& callInfo)
return InliningStatus_Inlined;
}
JSValueType unboxedType = GetBoxedOrUnboxedType(templateObject);
// Store all values, no need to initialize the length after each as
// jsop_initelem_array is doing because we do not expect to bailout
// because the memory is supposed to be allocated by now.
@ -1512,11 +1468,11 @@ IonBuilder::inlineConstantStringSplitString(CallInfo& callInfo)
MConstant* value = arrayValues[i];
current->add(value);
if (!initializeArrayElement(array, i, value, unboxedType, /* addResumePoint = */ false))
if (!initializeArrayElement(array, i, value, /* addResumePoint = */ false))
return InliningStatus_Error;
}
MInstruction* setLength = setInitializedLength(array, unboxedType, initLength);
MInstruction* setLength = setInitializedLength(array, initLength);
if (!resumeAfter(setLength))
return InliningStatus_Error;
@ -2152,7 +2108,7 @@ IonBuilder::inlineDefineDataProperty(CallInfo& callInfo)
if (callInfo.argc() != 3)
return InliningStatus_NotInlined;
MDefinition* obj = convertUnboxedObjects(callInfo.getArg(0));
MDefinition* obj = callInfo.getArg(0);
MDefinition* id = callInfo.getArg(1);
MDefinition* value = callInfo.getArg(2);

View File

@ -4810,35 +4810,8 @@ MBeta::printOpcode(GenericPrinter& out) const
bool
MCreateThisWithTemplate::canRecoverOnBailout() const
{
MOZ_ASSERT(templateObject()->is<PlainObject>() || templateObject()->is<UnboxedPlainObject>());
MOZ_ASSERT_IF(templateObject()->is<PlainObject>(),
!templateObject()->as<PlainObject>().denseElementsAreCopyOnWrite());
return true;
}
bool
OperandIndexMap::init(TempAllocator& alloc, JSObject* templateObject)
{
const UnboxedLayout& layout =
templateObject->as<UnboxedPlainObject>().layoutDontCheckGeneration();
const UnboxedLayout::PropertyVector& properties = layout.properties();
MOZ_ASSERT(properties.length() < 255);
// Allocate an array of indexes, where the top of each field correspond to
// the index of the operand in the MObjectState instance.
if (!map.init(alloc, layout.size()))
return false;
// Reset all indexes to 0, which is an error code.
for (size_t i = 0; i < map.length(); i++)
map[i] = 0;
// Map the property offsets to the indexes of MObjectState operands.
uint8_t index = 1;
for (size_t i = 0; i < properties.length(); i++, index++)
map[properties[i].offset] = index;
MOZ_ASSERT(templateObject()->is<PlainObject>());
MOZ_ASSERT(!templateObject()->as<PlainObject>().denseElementsAreCopyOnWrite());
return true;
}
@ -4858,17 +4831,11 @@ MObjectState::MObjectState(JSObject *templateObject, OperandIndexMap* operandInd
setResultType(MIRType::Object);
setRecoveredOnBailout();
if (templateObject->is<NativeObject>()) {
NativeObject* nativeObject = &templateObject->as<NativeObject>();
numSlots_ = nativeObject->slotSpan();
numFixedSlots_ = nativeObject->numFixedSlots();
} else {
const UnboxedLayout& layout =
templateObject->as<UnboxedPlainObject>().layoutDontCheckGeneration();
// Same as UnboxedLayout::makeNativeGroup
numSlots_ = layout.properties().length();
numFixedSlots_ = gc::GetGCKindSlots(layout.getAllocKind());
}
MOZ_ASSERT(templateObject->is<NativeObject>());
NativeObject* nativeObject = &templateObject->as<NativeObject>();
numSlots_ = nativeObject->slotSpan();
numFixedSlots_ = nativeObject->numFixedSlots();
operandIndex_ = operandIndex;
}
@ -4905,39 +4872,21 @@ MObjectState::initFromTemplateObject(TempAllocator& alloc, MDefinition* undefine
// the template object. This is needed to account values which are baked in
// the template objects and not visible in IonMonkey, such as the
// uninitialized-lexical magic value of call objects.
if (templateObject->is<UnboxedPlainObject>()) {
UnboxedPlainObject& unboxedObject = templateObject->as<UnboxedPlainObject>();
const UnboxedLayout& layout = unboxedObject.layoutDontCheckGeneration();
const UnboxedLayout::PropertyVector& properties = layout.properties();
NativeObject& nativeObject = templateObject->as<NativeObject>();
MOZ_ASSERT(nativeObject.slotSpan() == numSlots());
for (size_t i = 0; i < properties.length(); i++) {
Value val = unboxedObject.getValue(properties[i], /* maybeUninitialized = */ true);
MDefinition *def = undefinedVal;
if (!val.isUndefined()) {
MConstant* ins = val.isObject() ?
MConstant::NewConstraintlessObject(alloc, &val.toObject()) :
MConstant::New(alloc, val);
block()->insertBefore(this, ins);
def = ins;
}
initSlot(i, def);
}
} else {
NativeObject& nativeObject = templateObject->as<NativeObject>();
MOZ_ASSERT(nativeObject.slotSpan() == numSlots());
for (size_t i = 0; i < numSlots(); i++) {
Value val = nativeObject.getSlot(i);
MDefinition *def = undefinedVal;
if (!val.isUndefined()) {
MConstant* ins = val.isObject() ?
MConstant::NewConstraintlessObject(alloc, &val.toObject()) :
MConstant::New(alloc, val);
block()->insertBefore(this, ins);
def = ins;
}
initSlot(i, def);
MOZ_ASSERT(templateObject->is<NativeObject>());
for (size_t i = 0; i < numSlots(); i++) {
Value val = nativeObject.getSlot(i);
MDefinition *def = undefinedVal;
if (!val.isUndefined()) {
MConstant* ins = val.isObject() ?
MConstant::NewConstraintlessObject(alloc, &val.toObject()) :
MConstant::New(alloc, val);
block()->insertBefore(this, ins);
def = ins;
}
initSlot(i, def);
}
return true;
}
@ -4948,14 +4897,7 @@ MObjectState::New(TempAllocator& alloc, MDefinition* obj)
JSObject* templateObject = templateObjectOf(obj);
MOZ_ASSERT(templateObject, "Unexpected object creation.");
OperandIndexMap* operandIndex = nullptr;
if (templateObject->is<UnboxedPlainObject>()) {
operandIndex = new(alloc) OperandIndexMap;
if (!operandIndex || !operandIndex->init(alloc, templateObject))
return nullptr;
}
MObjectState* res = new(alloc) MObjectState(templateObject, operandIndex);
MObjectState* res = new(alloc) MObjectState(templateObject, nullptr);
if (!res || !res->init(alloc, obj))
return nullptr;
return res;
@ -5862,35 +5804,6 @@ MGetFirstDollarIndex::foldsTo(TempAllocator& alloc)
return MConstant::New(alloc, Int32Value(index));
}
MConvertUnboxedObjectToNative*
MConvertUnboxedObjectToNative::New(TempAllocator& alloc, MDefinition* obj, ObjectGroup* group)
{
MConvertUnboxedObjectToNative* res = new(alloc) MConvertUnboxedObjectToNative(obj, group);
ObjectGroup* nativeGroup = group->unboxedLayout().nativeGroup();
// Make a new type set for the result of this instruction which replaces
// the input group with the native group we will convert it to.
TemporaryTypeSet* types = obj->resultTypeSet();
if (types && !types->unknownObject()) {
TemporaryTypeSet* newTypes = types->cloneWithoutObjects(alloc.lifoAlloc());
if (newTypes) {
for (size_t i = 0; i < types->getObjectCount(); i++) {
TypeSet::ObjectKey* key = types->getObject(i);
if (!key)
continue;
if (key->unknownProperties() || !key->isGroup() || key->group() != group)
newTypes->addType(TypeSet::ObjectType(key), alloc.lifoAlloc());
else
newTypes->addType(TypeSet::ObjectType(nativeGroup), alloc.lifoAlloc());
}
res->setResultTypeSet(newTypes);
}
}
return res;
}
bool
jit::ElementAccessIsDenseNative(CompilerConstraintList* constraints,
MDefinition* obj, MDefinition* id)
@ -5910,48 +5823,6 @@ jit::ElementAccessIsDenseNative(CompilerConstraintList* constraints,
return clasp && clasp->isNative() && !IsTypedArrayClass(clasp);
}
JSValueType
jit::UnboxedArrayElementType(CompilerConstraintList* constraints, MDefinition* obj,
MDefinition* id)
{
if (obj->mightBeType(MIRType::String))
return JSVAL_TYPE_MAGIC;
if (id && id->type() != MIRType::Int32 && id->type() != MIRType::Double)
return JSVAL_TYPE_MAGIC;
TemporaryTypeSet* types = obj->resultTypeSet();
if (!types || types->unknownObject())
return JSVAL_TYPE_MAGIC;
JSValueType elementType = JSVAL_TYPE_MAGIC;
for (unsigned i = 0; i < types->getObjectCount(); i++) {
TypeSet::ObjectKey* key = types->getObject(i);
if (!key)
continue;
if (key->unknownProperties() || !key->isGroup())
return JSVAL_TYPE_MAGIC;
if (key->clasp() != &UnboxedArrayObject::class_)
return JSVAL_TYPE_MAGIC;
const UnboxedLayout &layout = key->group()->unboxedLayout();
if (layout.nativeGroup())
return JSVAL_TYPE_MAGIC;
if (elementType == layout.elementType() || elementType == JSVAL_TYPE_MAGIC)
elementType = layout.elementType();
else
return JSVAL_TYPE_MAGIC;
key->watchStateChangeForUnboxedConvertedToNative(constraints);
}
return elementType;
}
bool
jit::ElementAccessIsTypedArray(CompilerConstraintList* constraints,
MDefinition* obj, MDefinition* id,
@ -6111,11 +5982,6 @@ ObjectSubsumes(TypeSet::ObjectKey* first, TypeSet::ObjectKey* second)
firstElements.maybeTypes()->equals(secondElements.maybeTypes());
}
if (first->clasp() == &UnboxedArrayObject::class_) {
return first->group()->unboxedLayout().elementType() ==
second->group()->unboxedLayout().elementType();
}
return false;
}
@ -6579,23 +6445,6 @@ jit::PropertyWriteNeedsTypeBarrier(TempAllocator& alloc, CompilerConstraintList*
}
}
// Perform additional filtering to make sure that any unboxed property
// being written can accommodate the value.
for (size_t i = 0; i < types->getObjectCount(); i++) {
TypeSet::ObjectKey* key = types->getObject(i);
if (key && key->isGroup() && key->group()->maybeUnboxedLayout()) {
const UnboxedLayout& layout = key->group()->unboxedLayout();
if (name) {
const UnboxedLayout::Property* property = layout.lookup(name);
if (property && !CanStoreUnboxedType(alloc, property->type, *pvalue))
return true;
} else {
if (layout.isArray() && !CanStoreUnboxedType(alloc, layout.elementType(), *pvalue))
return true;
}
}
}
if (success)
return false;
@ -6626,17 +6475,6 @@ jit::PropertyWriteNeedsTypeBarrier(TempAllocator& alloc, CompilerConstraintList*
MOZ_ASSERT(excluded);
// If the excluded object is a group with an unboxed layout, make sure it
// does not have a corresponding native group. Objects with the native
// group might appear even though they are not in the type set.
if (excluded->isGroup()) {
if (UnboxedLayout* layout = excluded->group()->maybeUnboxedLayout()) {
if (layout->nativeGroup())
return true;
excluded->watchStateChangeForUnboxedConvertedToNative(constraints);
}
}
*pobj = AddGroupGuard(alloc, current, *pobj, excluded, /* bailOnEquality = */ true);
return false;
}

View File

@ -30,7 +30,6 @@
#include "vm/EnvironmentObject.h"
#include "vm/SharedMem.h"
#include "vm/TypedArrayCommon.h"
#include "vm/UnboxedObject.h"
// Undo windows.h damage on Win64
#undef MemoryBarrier
@ -376,8 +375,7 @@ class AliasSet {
Element = 1 << 1, // A Value member of obj->elements or
// a typed object.
UnboxedElement = 1 << 2, // An unboxed scalar or reference member of
// a typed array, typed object, or unboxed
// object.
// typed object or unboxed object.
DynamicSlot = 1 << 3, // A Value member of obj->slots.
FixedSlot = 1 << 4, // A Value member of obj->fixedSlots().
DOMProperty = 1 << 5, // A DOM property
@ -434,9 +432,6 @@ class AliasSet {
MOZ_ASSERT(flags && !(flags & Store_));
return AliasSet(flags | Store_);
}
static uint32_t BoxedOrUnboxedElements(JSValueType type) {
return (type == JSVAL_TYPE_MAGIC) ? Element : UnboxedElement;
}
};
typedef Vector<MDefinition*, 6, JitAllocPolicy> MDefinitionVector;
@ -3795,7 +3790,6 @@ class MObjectState
MOZ_MUST_USE bool initFromTemplateObject(TempAllocator& alloc, MDefinition* undefinedVal);
size_t numFixedSlots() const {
MOZ_ASSERT(!isUnboxed());
return numFixedSlots_;
}
size_t numSlots() const {
@ -8746,102 +8740,6 @@ class MSetInitializedLength
ALLOW_CLONE(MSetInitializedLength)
};
// Load the length from an unboxed array.
class MUnboxedArrayLength
: public MUnaryInstruction,
public SingleObjectPolicy::Data
{
explicit MUnboxedArrayLength(MDefinition* object)
: MUnaryInstruction(object)
{
setResultType(MIRType::Int32);
setMovable();
}
public:
INSTRUCTION_HEADER(UnboxedArrayLength)
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, object))
bool congruentTo(const MDefinition* ins) const override {
return congruentIfOperandsEqual(ins);
}
AliasSet getAliasSet() const override {
return AliasSet::Load(AliasSet::ObjectFields);
}
ALLOW_CLONE(MUnboxedArrayLength)
};
// Load the initialized length from an unboxed array.
class MUnboxedArrayInitializedLength
: public MUnaryInstruction,
public SingleObjectPolicy::Data
{
explicit MUnboxedArrayInitializedLength(MDefinition* object)
: MUnaryInstruction(object)
{
setResultType(MIRType::Int32);
setMovable();
}
public:
INSTRUCTION_HEADER(UnboxedArrayInitializedLength)
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, object))
bool congruentTo(const MDefinition* ins) const override {
return congruentIfOperandsEqual(ins);
}
AliasSet getAliasSet() const override {
return AliasSet::Load(AliasSet::ObjectFields);
}
ALLOW_CLONE(MUnboxedArrayInitializedLength)
};
// Increment the initialized length of an unboxed array object.
class MIncrementUnboxedArrayInitializedLength
: public MUnaryInstruction,
public SingleObjectPolicy::Data
{
explicit MIncrementUnboxedArrayInitializedLength(MDefinition* obj)
: MUnaryInstruction(obj)
{}
public:
INSTRUCTION_HEADER(IncrementUnboxedArrayInitializedLength)
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, object))
AliasSet getAliasSet() const override {
return AliasSet::Store(AliasSet::ObjectFields);
}
ALLOW_CLONE(MIncrementUnboxedArrayInitializedLength)
};
// Set the initialized length of an unboxed array object.
class MSetUnboxedArrayInitializedLength
: public MBinaryInstruction,
public SingleObjectPolicy::Data
{
explicit MSetUnboxedArrayInitializedLength(MDefinition* obj, MDefinition* length)
: MBinaryInstruction(obj, length)
{}
public:
INSTRUCTION_HEADER(SetUnboxedArrayInitializedLength)
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, object), (1, length))
AliasSet getAliasSet() const override {
return AliasSet::Store(AliasSet::ObjectFields);
}
ALLOW_CLONE(MSetUnboxedArrayInitializedLength)
};
// Load the array length from an elements header.
class MArrayLength
: public MUnaryInstruction,
@ -9335,23 +9233,19 @@ class MLoadElement
ALLOW_CLONE(MLoadElement)
};
// Load a value from the elements vector for a dense native or unboxed array.
// Load a value from the elements vector of a native object.
// If the index is out-of-bounds, or the indexed slot has a hole, undefined is
// returned instead.
class MLoadElementHole
: public MTernaryInstruction,
public SingleObjectPolicy::Data
{
// Unboxed element type, JSVAL_TYPE_MAGIC for dense native elements.
JSValueType unboxedType_;
bool needsNegativeIntCheck_;
bool needsHoleCheck_;
MLoadElementHole(MDefinition* elements, MDefinition* index, MDefinition* initLength,
JSValueType unboxedType, bool needsHoleCheck)
bool needsHoleCheck)
: MTernaryInstruction(elements, index, initLength),
unboxedType_(unboxedType),
needsNegativeIntCheck_(true),
needsHoleCheck_(needsHoleCheck)
{
@ -9373,9 +9267,6 @@ class MLoadElementHole
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, elements), (1, index), (2, initLength))
JSValueType unboxedType() const {
return unboxedType_;
}
bool needsNegativeIntCheck() const {
return needsNegativeIntCheck_;
}
@ -9386,8 +9277,6 @@ class MLoadElementHole
if (!ins->isLoadElementHole())
return false;
const MLoadElementHole* other = ins->toLoadElementHole();
if (unboxedType() != other->unboxedType())
return false;
if (needsHoleCheck() != other->needsHoleCheck())
return false;
if (needsNegativeIntCheck() != other->needsNegativeIntCheck())
@ -9395,7 +9284,7 @@ class MLoadElementHole
return congruentIfOperandsEqual(other);
}
AliasSet getAliasSet() const override {
return AliasSet::Load(AliasSet::BoxedOrUnboxedElements(unboxedType()));
return AliasSet::Load(AliasSet::Element);
}
void collectRangeInfoPreTrunc() override;
@ -9575,20 +9464,17 @@ class MStoreElement
ALLOW_CLONE(MStoreElement)
};
// Like MStoreElement, but supports indexes >= initialized length, and can
// handle unboxed arrays. The downside is that we cannot hoist the elements
// vector and bounds check, since this instruction may update the (initialized)
// length and reallocate the elements vector.
// Like MStoreElement, but supports indexes >= initialized length. The downside
// is that we cannot hoist the elements vector and bounds check, since this
// instruction may update the (initialized) length and reallocate the elements
// vector.
class MStoreElementHole
: public MAryInstruction<4>,
public MStoreElementCommon,
public MixPolicy<SingleObjectPolicy, NoFloatPolicy<3> >::Data
{
JSValueType unboxedType_;
MStoreElementHole(MDefinition* object, MDefinition* elements,
MDefinition* index, MDefinition* value, JSValueType unboxedType)
: unboxedType_(unboxedType)
MDefinition* index, MDefinition* value)
{
initOperand(0, object);
initOperand(1, elements);
@ -9603,14 +9489,10 @@ class MStoreElementHole
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, object), (1, elements), (2, index), (3, value))
JSValueType unboxedType() const {
return unboxedType_;
}
AliasSet getAliasSet() const override {
// StoreElementHole can update the initialized length, the array length
// or reallocate obj->elements.
return AliasSet::Store(AliasSet::ObjectFields |
AliasSet::BoxedOrUnboxedElements(unboxedType()));
return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element);
}
ALLOW_CLONE(MStoreElementHole)
@ -9623,13 +9505,11 @@ class MFallibleStoreElement
public MStoreElementCommon,
public MixPolicy<SingleObjectPolicy, NoFloatPolicy<3> >::Data
{
JSValueType unboxedType_;
bool strict_;
MFallibleStoreElement(MDefinition* object, MDefinition* elements,
MDefinition* index, MDefinition* value,
JSValueType unboxedType, bool strict)
: unboxedType_(unboxedType)
bool strict)
{
initOperand(0, object);
initOperand(1, elements);
@ -9645,12 +9525,8 @@ class MFallibleStoreElement
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, object), (1, elements), (2, index), (3, value))
JSValueType unboxedType() const {
return unboxedType_;
}
AliasSet getAliasSet() const override {
return AliasSet::Store(AliasSet::ObjectFields |
AliasSet::BoxedOrUnboxedElements(unboxedType()));
return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element);
}
bool strict() const {
return strict_;
@ -9742,59 +9618,6 @@ class MStoreUnboxedString
ALLOW_CLONE(MStoreUnboxedString)
};
// Passes through an object, after ensuring it is converted from an unboxed
// object to a native representation.
class MConvertUnboxedObjectToNative
: public MUnaryInstruction,
public SingleObjectPolicy::Data
{
CompilerObjectGroup group_;
explicit MConvertUnboxedObjectToNative(MDefinition* obj, ObjectGroup* group)
: MUnaryInstruction(obj),
group_(group)
{
setGuard();
setMovable();
setResultType(MIRType::Object);
}
public:
INSTRUCTION_HEADER(ConvertUnboxedObjectToNative)
NAMED_OPERANDS((0, object))
static MConvertUnboxedObjectToNative* New(TempAllocator& alloc, MDefinition* obj,
ObjectGroup* group);
ObjectGroup* group() const {
return group_;
}
bool congruentTo(const MDefinition* ins) const override {
if (!congruentIfOperandsEqual(ins))
return false;
return ins->toConvertUnboxedObjectToNative()->group() == group();
}
AliasSet getAliasSet() const override {
// This instruction can read and write to all parts of the object, but
// is marked as non-effectful so it can be consolidated by LICM and GVN
// and avoid inhibiting other optimizations.
//
// This is valid to do because when unboxed objects might have a native
// group they can be converted to, we do not optimize accesses to the
// unboxed objects and do not guard on their group or shape (other than
// in this opcode).
//
// Later accesses can assume the object has a native representation
// and optimize accordingly. Those accesses cannot be reordered before
// this instruction, however. This is prevented by chaining this
// instruction with the object itself, in the same way as MBoundsCheck.
return AliasSet::None();
}
bool appendRoots(MRootList& roots) const override {
return roots.append(group_);
}
};
// Array.prototype.pop or Array.prototype.shift on a dense array.
class MArrayPopShift
: public MUnaryInstruction,
@ -9808,13 +9631,12 @@ class MArrayPopShift
private:
Mode mode_;
JSValueType unboxedType_;
bool needsHoleCheck_;
bool maybeUndefined_;
MArrayPopShift(MDefinition* object, Mode mode, JSValueType unboxedType,
MArrayPopShift(MDefinition* object, Mode mode,
bool needsHoleCheck, bool maybeUndefined)
: MUnaryInstruction(object), mode_(mode), unboxedType_(unboxedType),
: MUnaryInstruction(object), mode_(mode),
needsHoleCheck_(needsHoleCheck), maybeUndefined_(maybeUndefined)
{ }
@ -9832,12 +9654,8 @@ class MArrayPopShift
bool mode() const {
return mode_;
}
JSValueType unboxedType() const {
return unboxedType_;
}
AliasSet getAliasSet() const override {
return AliasSet::Store(AliasSet::ObjectFields |
AliasSet::BoxedOrUnboxedElements(unboxedType()));
return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element);
}
ALLOW_CLONE(MArrayPopShift)
@ -9848,10 +9666,8 @@ class MArrayPush
: public MBinaryInstruction,
public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >::Data
{
JSValueType unboxedType_;
MArrayPush(MDefinition* object, MDefinition* value, JSValueType unboxedType)
: MBinaryInstruction(object, value), unboxedType_(unboxedType)
MArrayPush(MDefinition* object, MDefinition* value)
: MBinaryInstruction(object, value)
{
setResultType(MIRType::Int32);
}
@ -9861,12 +9677,8 @@ class MArrayPush
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, object), (1, value))
JSValueType unboxedType() const {
return unboxedType_;
}
AliasSet getAliasSet() const override {
return AliasSet::Store(AliasSet::ObjectFields |
AliasSet::BoxedOrUnboxedElements(unboxedType()));
return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element);
}
void computeRange(TempAllocator& alloc) override;
@ -9880,15 +9692,13 @@ class MArraySlice
{
CompilerObject templateObj_;
gc::InitialHeap initialHeap_;
JSValueType unboxedType_;
MArraySlice(CompilerConstraintList* constraints, MDefinition* obj,
MDefinition* begin, MDefinition* end,
JSObject* templateObj, gc::InitialHeap initialHeap, JSValueType unboxedType)
JSObject* templateObj, gc::InitialHeap initialHeap)
: MTernaryInstruction(obj, begin, end),
templateObj_(templateObj),
initialHeap_(initialHeap),
unboxedType_(unboxedType)
initialHeap_(initialHeap)
{
setResultType(MIRType::Object);
}
@ -9906,10 +9716,6 @@ class MArraySlice
return initialHeap_;
}
JSValueType unboxedType() const {
return unboxedType_;
}
bool possiblyCalls() const override {
return true;
}
@ -11174,11 +10980,6 @@ class MGuardShape
setMovable();
setResultType(MIRType::Object);
setResultTypeSet(obj->resultTypeSet());
// Disallow guarding on unboxed object shapes. The group is better to
// guard on, and guarding on the shape can interact badly with
// MConvertUnboxedObjectToNative.
MOZ_ASSERT(shape->getObjectClass() != &UnboxedPlainObject::class_);
}
public:
@ -11273,11 +11074,6 @@ class MGuardObjectGroup
setGuard();
setMovable();
setResultType(MIRType::Object);
// Unboxed groups which might be converted to natives can't be guarded
// on, due to MConvertUnboxedObjectToNative.
MOZ_ASSERT_IF(group->maybeUnboxedLayoutDontCheckGeneration(),
!group->unboxedLayoutDontCheckGeneration().nativeGroup());
}
public:
@ -11386,73 +11182,6 @@ class MGuardClass
ALLOW_CLONE(MGuardClass)
};
// Guard on the presence or absence of an unboxed object's expando.
class MGuardUnboxedExpando
: public MUnaryInstruction,
public SingleObjectPolicy::Data
{
bool requireExpando_;
BailoutKind bailoutKind_;
MGuardUnboxedExpando(MDefinition* obj, bool requireExpando, BailoutKind bailoutKind)
: MUnaryInstruction(obj),
requireExpando_(requireExpando),
bailoutKind_(bailoutKind)
{
setGuard();
setMovable();
setResultType(MIRType::Object);
}
public:
INSTRUCTION_HEADER(GuardUnboxedExpando)
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, object))
bool requireExpando() const {
return requireExpando_;
}
BailoutKind bailoutKind() const {
return bailoutKind_;
}
bool congruentTo(const MDefinition* ins) const override {
if (!congruentIfOperandsEqual(ins))
return false;
if (requireExpando() != ins->toGuardUnboxedExpando()->requireExpando())
return false;
return true;
}
AliasSet getAliasSet() const override {
return AliasSet::Load(AliasSet::ObjectFields);
}
};
// Load an unboxed plain object's expando.
class MLoadUnboxedExpando
: public MUnaryInstruction,
public SingleObjectPolicy::Data
{
private:
explicit MLoadUnboxedExpando(MDefinition* object)
: MUnaryInstruction(object)
{
setResultType(MIRType::Object);
setMovable();
}
public:
INSTRUCTION_HEADER(LoadUnboxedExpando)
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, object))
bool congruentTo(const MDefinition* ins) const override {
return congruentIfOperandsEqual(ins);
}
AliasSet getAliasSet() const override {
return AliasSet::Load(AliasSet::ObjectFields);
}
};
// Load from vp[slot] (slots that are not inline in an object).
class MLoadSlot
: public MUnaryInstruction,
@ -12355,15 +12084,13 @@ class MInArray
{
bool needsHoleCheck_;
bool needsNegativeIntCheck_;
JSValueType unboxedType_;
MInArray(MDefinition* elements, MDefinition* index,
MDefinition* initLength, MDefinition* object,
bool needsHoleCheck, JSValueType unboxedType)
bool needsHoleCheck)
: MQuaternaryInstruction(elements, index, initLength, object),
needsHoleCheck_(needsHoleCheck),
needsNegativeIntCheck_(true),
unboxedType_(unboxedType)
needsNegativeIntCheck_(true)
{
setResultType(MIRType::Boolean);
setMovable();
@ -12383,9 +12110,6 @@ class MInArray
bool needsNegativeIntCheck() const {
return needsNegativeIntCheck_;
}
JSValueType unboxedType() const {
return unboxedType_;
}
void collectRangeInfoPreTrunc() override;
AliasSet getAliasSet() const override {
return AliasSet::Load(AliasSet::Element);
@ -12398,8 +12122,6 @@ class MInArray
return false;
if (needsNegativeIntCheck() != other->needsNegativeIntCheck())
return false;
if (unboxedType() != other->unboxedType())
return false;
return congruentIfOperandsEqual(other);
}
};
@ -14300,8 +14022,6 @@ MDefinition::maybeConstantValue()
bool ElementAccessIsDenseNative(CompilerConstraintList* constraints,
MDefinition* obj, MDefinition* id);
JSValueType UnboxedArrayElementType(CompilerConstraintList* constraints, MDefinition* obj,
MDefinition* id);
bool ElementAccessIsTypedArray(CompilerConstraintList* constraints,
MDefinition* obj, MDefinition* id,
Scalar::Type* arrayType);

View File

@ -187,8 +187,6 @@ namespace jit {
_(GuardObjectGroup) \
_(GuardObjectIdentity) \
_(GuardClass) \
_(GuardUnboxedExpando) \
_(LoadUnboxedExpando) \
_(ArrayLength) \
_(SetArrayLength) \
_(GetNextEntryForIterator) \
@ -200,10 +198,6 @@ namespace jit {
_(SetTypedObjectOffset) \
_(InitializedLength) \
_(SetInitializedLength) \
_(UnboxedArrayLength) \
_(UnboxedArrayInitializedLength) \
_(IncrementUnboxedArrayInitializedLength) \
_(SetUnboxedArrayInitializedLength) \
_(Not) \
_(BoundsCheck) \
_(BoundsCheckLower) \
@ -219,7 +213,6 @@ namespace jit {
_(StoreUnboxedScalar) \
_(StoreUnboxedObjectOrNull) \
_(StoreUnboxedString) \
_(ConvertUnboxedObjectToNative) \
_(ArrayPopShift) \
_(ArrayPush) \
_(ArraySlice) \

View File

@ -126,20 +126,14 @@ MacroAssembler::guardTypeSetMightBeIncomplete(TypeSet* types, Register obj, Regi
{
// Type set guards might miss when an object's group changes. In this case
// either its old group's properties will become unknown, or it will change
// to a native object with an original unboxed group. Jump to label if this
// might have happened for the input object.
// to a native object. Jump to label if this might have happened for the
// input object.
if (types->unknownObject()) {
jump(label);
return;
}
loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch);
load32(Address(scratch, ObjectGroup::offsetOfFlags()), scratch);
and32(Imm32(OBJECT_FLAG_ADDENDUM_MASK), scratch);
branch32(Assembler::Equal,
scratch, Imm32(ObjectGroup::addendumOriginalUnboxedGroupValue()), label);
for (size_t i = 0; i < types->getObjectCount(); i++) {
if (JSObject* singleton = types->getSingletonNoBarrier(i)) {
movePtr(ImmGCPtr(singleton), scratch);
@ -468,268 +462,6 @@ template void MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const A
template void MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const BaseIndex& src, const ValueOperand& dest,
bool allowDouble, Register temp, Label* fail);
template <typename T>
void
MacroAssembler::loadUnboxedProperty(T address, JSValueType type, TypedOrValueRegister output)
{
switch (type) {
case JSVAL_TYPE_INT32: {
// Handle loading an int32 into a double reg.
if (output.type() == MIRType::Double) {
convertInt32ToDouble(address, output.typedReg().fpu());
break;
}
MOZ_FALLTHROUGH;
}
case JSVAL_TYPE_BOOLEAN:
case JSVAL_TYPE_STRING: {
Register outReg;
if (output.hasValue()) {
outReg = output.valueReg().scratchReg();
} else {
MOZ_ASSERT(output.type() == MIRTypeFromValueType(type));
outReg = output.typedReg().gpr();
}
switch (type) {
case JSVAL_TYPE_BOOLEAN:
load8ZeroExtend(address, outReg);
break;
case JSVAL_TYPE_INT32:
load32(address, outReg);
break;
case JSVAL_TYPE_STRING:
loadPtr(address, outReg);
break;
default:
MOZ_CRASH();
}
if (output.hasValue())
tagValue(type, outReg, output.valueReg());
break;
}
case JSVAL_TYPE_OBJECT:
if (output.hasValue()) {
Register scratch = output.valueReg().scratchReg();
loadPtr(address, scratch);
Label notNull, done;
branchPtr(Assembler::NotEqual, scratch, ImmWord(0), &notNull);
moveValue(NullValue(), output.valueReg());
jump(&done);
bind(&notNull);
tagValue(JSVAL_TYPE_OBJECT, scratch, output.valueReg());
bind(&done);
} else {
// Reading null can't be possible here, as otherwise the result
// would be a value (either because null has been read before or
// because there is a barrier).
Register reg = output.typedReg().gpr();
loadPtr(address, reg);
#ifdef DEBUG
Label ok;
branchTestPtr(Assembler::NonZero, reg, reg, &ok);
assumeUnreachable("Null not possible");
bind(&ok);
#endif
}
break;
case JSVAL_TYPE_DOUBLE:
// Note: doubles in unboxed objects are not accessed through other
// views and do not need canonicalization.
if (output.hasValue())
loadValue(address, output.valueReg());
else
loadDouble(address, output.typedReg().fpu());
break;
default:
MOZ_CRASH();
}
}
template void
MacroAssembler::loadUnboxedProperty(Address address, JSValueType type,
TypedOrValueRegister output);
template void
MacroAssembler::loadUnboxedProperty(BaseIndex address, JSValueType type,
TypedOrValueRegister output);
static void
StoreUnboxedFailure(MacroAssembler& masm, Label* failure)
{
// Storing a value to an unboxed property is a fallible operation and
// the caller must provide a failure label if a particular unboxed store
// might fail. Sometimes, however, a store that cannot succeed (such as
// storing a string to an int32 property) will be marked as infallible.
// This can only happen if the code involved is unreachable.
if (failure)
masm.jump(failure);
else
masm.assumeUnreachable("Incompatible write to unboxed property");
}
template <typename T>
void
MacroAssembler::storeUnboxedProperty(T address, JSValueType type,
const ConstantOrRegister& value, Label* failure)
{
switch (type) {
case JSVAL_TYPE_BOOLEAN:
if (value.constant()) {
if (value.value().isBoolean())
store8(Imm32(value.value().toBoolean()), address);
else
StoreUnboxedFailure(*this, failure);
} else if (value.reg().hasTyped()) {
if (value.reg().type() == MIRType::Boolean)
store8(value.reg().typedReg().gpr(), address);
else
StoreUnboxedFailure(*this, failure);
} else {
if (failure)
branchTestBoolean(Assembler::NotEqual, value.reg().valueReg(), failure);
storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ 1);
}
break;
case JSVAL_TYPE_INT32:
if (value.constant()) {
if (value.value().isInt32())
store32(Imm32(value.value().toInt32()), address);
else
StoreUnboxedFailure(*this, failure);
} else if (value.reg().hasTyped()) {
if (value.reg().type() == MIRType::Int32)
store32(value.reg().typedReg().gpr(), address);
else
StoreUnboxedFailure(*this, failure);
} else {
if (failure)
branchTestInt32(Assembler::NotEqual, value.reg().valueReg(), failure);
storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ 4);
}
break;
case JSVAL_TYPE_DOUBLE:
if (value.constant()) {
if (value.value().isNumber()) {
loadConstantDouble(value.value().toNumber(), ScratchDoubleReg);
storeDouble(ScratchDoubleReg, address);
} else {
StoreUnboxedFailure(*this, failure);
}
} else if (value.reg().hasTyped()) {
if (value.reg().type() == MIRType::Int32) {
convertInt32ToDouble(value.reg().typedReg().gpr(), ScratchDoubleReg);
storeDouble(ScratchDoubleReg, address);
} else if (value.reg().type() == MIRType::Double) {
storeDouble(value.reg().typedReg().fpu(), address);
} else {
StoreUnboxedFailure(*this, failure);
}
} else {
ValueOperand reg = value.reg().valueReg();
Label notInt32, end;
branchTestInt32(Assembler::NotEqual, reg, &notInt32);
int32ValueToDouble(reg, ScratchDoubleReg);
storeDouble(ScratchDoubleReg, address);
jump(&end);
bind(&notInt32);
if (failure)
branchTestDouble(Assembler::NotEqual, reg, failure);
storeValue(reg, address);
bind(&end);
}
break;
case JSVAL_TYPE_OBJECT:
if (value.constant()) {
if (value.value().isObjectOrNull())
storePtr(ImmGCPtr(value.value().toObjectOrNull()), address);
else
StoreUnboxedFailure(*this, failure);
} else if (value.reg().hasTyped()) {
MOZ_ASSERT(value.reg().type() != MIRType::Null);
if (value.reg().type() == MIRType::Object)
storePtr(value.reg().typedReg().gpr(), address);
else
StoreUnboxedFailure(*this, failure);
} else {
if (failure) {
Label ok;
branchTestNull(Assembler::Equal, value.reg().valueReg(), &ok);
branchTestObject(Assembler::NotEqual, value.reg().valueReg(), failure);
bind(&ok);
}
storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ sizeof(uintptr_t));
}
break;
case JSVAL_TYPE_STRING:
if (value.constant()) {
if (value.value().isString())
storePtr(ImmGCPtr(value.value().toString()), address);
else
StoreUnboxedFailure(*this, failure);
} else if (value.reg().hasTyped()) {
if (value.reg().type() == MIRType::String)
storePtr(value.reg().typedReg().gpr(), address);
else
StoreUnboxedFailure(*this, failure);
} else {
if (failure)
branchTestString(Assembler::NotEqual, value.reg().valueReg(), failure);
storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ sizeof(uintptr_t));
}
break;
default:
MOZ_CRASH();
}
}
template void
MacroAssembler::storeUnboxedProperty(Address address, JSValueType type,
const ConstantOrRegister& value, Label* failure);
template void
MacroAssembler::storeUnboxedProperty(BaseIndex address, JSValueType type,
const ConstantOrRegister& value, Label* failure);
void
MacroAssembler::checkUnboxedArrayCapacity(Register obj, const RegisterOrInt32Constant& index,
Register temp, Label* failure)
{
Address initLengthAddr(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
Address lengthAddr(obj, UnboxedArrayObject::offsetOfLength());
Label capacityIsIndex, done;
load32(initLengthAddr, temp);
branchTest32(Assembler::NonZero, temp, Imm32(UnboxedArrayObject::CapacityMask), &capacityIsIndex);
branch32(Assembler::BelowOrEqual, lengthAddr, index, failure);
jump(&done);
bind(&capacityIsIndex);
// Do a partial shift so that we can get an absolute offset from the base
// of CapacityArray to use.
JS_STATIC_ASSERT(sizeof(UnboxedArrayObject::CapacityArray[0]) == 4);
rshiftPtr(Imm32(UnboxedArrayObject::CapacityShift - 2), temp);
and32(Imm32(~0x3), temp);
addPtr(ImmPtr(&UnboxedArrayObject::CapacityArray), temp);
branch32(Assembler::BelowOrEqual, Address(temp, 0), index, failure);
bind(&done);
}
// Inlined version of gc::CheckAllocatorState that checks the bare essentials
// and bails for anything that cannot be handled with our jit allocators.
void
@ -1277,20 +1009,6 @@ MacroAssembler::initGCThing(Register obj, Register temp, JSObject* templateObj,
nbytes = (nbytes < sizeof(uintptr_t)) ? 0 : nbytes - sizeof(uintptr_t);
offset += sizeof(uintptr_t);
}
} else if (templateObj->is<UnboxedPlainObject>()) {
storePtr(ImmWord(0), Address(obj, UnboxedPlainObject::offsetOfExpando()));
if (initContents)
initUnboxedObjectContents(obj, &templateObj->as<UnboxedPlainObject>());
} else if (templateObj->is<UnboxedArrayObject>()) {
MOZ_ASSERT(templateObj->as<UnboxedArrayObject>().hasInlineElements());
int elementsOffset = UnboxedArrayObject::offsetOfInlineElements();
computeEffectiveAddress(Address(obj, elementsOffset), temp);
storePtr(temp, Address(obj, UnboxedArrayObject::offsetOfElements()));
store32(Imm32(templateObj->as<UnboxedArrayObject>().length()),
Address(obj, UnboxedArrayObject::offsetOfLength()));
uint32_t capacityIndex = templateObj->as<UnboxedArrayObject>().capacityIndex();
store32(Imm32(capacityIndex << UnboxedArrayObject::CapacityShift),
Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()));
} else {
MOZ_CRASH("Unknown object");
}
@ -1311,29 +1029,6 @@ MacroAssembler::initGCThing(Register obj, Register temp, JSObject* templateObj,
#endif
}
void
MacroAssembler::initUnboxedObjectContents(Register object, UnboxedPlainObject* templateObject)
{
const UnboxedLayout& layout = templateObject->layoutDontCheckGeneration();
// Initialize reference fields of the object, per UnboxedPlainObject::create.
if (const int32_t* list = layout.traceList()) {
while (*list != -1) {
storePtr(ImmGCPtr(GetJitContext()->runtime->names().empty),
Address(object, UnboxedPlainObject::offsetOfData() + *list));
list++;
}
list++;
while (*list != -1) {
storePtr(ImmWord(0),
Address(object, UnboxedPlainObject::offsetOfData() + *list));
list++;
}
// Unboxed objects don't have Values to initialize.
MOZ_ASSERT(*(list + 1) == -1);
}
}
void
MacroAssembler::compareStrings(JSOp op, Register left, Register right, Register result,
Label* fail)

View File

@ -36,7 +36,6 @@
#include "vm/ProxyObject.h"
#include "vm/Shape.h"
#include "vm/TypedArrayObject.h"
#include "vm/UnboxedObject.h"
using mozilla::FloatingPoint;
@ -1626,20 +1625,6 @@ class MacroAssembler : public MacroAssemblerSpecific
void storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister value, const Address& dest,
unsigned numElems = 0);
// Load a property from an UnboxedPlainObject or UnboxedArrayObject.
template <typename T>
void loadUnboxedProperty(T address, JSValueType type, TypedOrValueRegister output);
// Store a property to an UnboxedPlainObject, without triggering barriers.
// If failure is null, the value definitely has a type suitable for storing
// in the property.
template <typename T>
void storeUnboxedProperty(T address, JSValueType type,
const ConstantOrRegister& value, Label* failure);
void checkUnboxedArrayCapacity(Register obj, const RegisterOrInt32Constant& index,
Register temp, Label* failure);
Register extractString(const Address& address, Register scratch) {
return extractObject(address, scratch);
}
@ -1716,8 +1701,6 @@ class MacroAssembler : public MacroAssemblerSpecific
LiveRegisterSet liveRegs, Label* fail,
TypedArrayObject* templateObj, TypedArrayLength lengthKind);
void initUnboxedObjectContents(Register object, UnboxedPlainObject* templateObject);
void newGCString(Register result, Register temp, Label* fail);
void newGCFatInlineString(Register result, Register temp, Label* fail);

View File

@ -844,8 +844,6 @@ MaybeConstructorFromType(TypeSet::Type ty)
return nullptr;
ObjectGroup* obj = ty.group();
TypeNewScript* newScript = obj->newScript();
if (!newScript && obj->maybeUnboxedLayout())
newScript = obj->unboxedLayout().newScript();
return newScript ? newScript->function() : nullptr;
}

View File

@ -1354,7 +1354,7 @@ RNewArray::recover(JSContext* cx, SnapshotIterator& iter) const
RootedValue result(cx);
RootedObjectGroup group(cx, templateObject->group());
JSObject* resultObject = NewFullyAllocatedArrayTryUseGroup(cx, group, count_);
ArrayObject* resultObject = NewFullyAllocatedArrayTryUseGroup(cx, group, count_);
if (!resultObject)
return false;
@ -1539,37 +1539,12 @@ RObjectState::recover(JSContext* cx, SnapshotIterator& iter) const
RootedObject object(cx, &iter.read().toObject());
RootedValue val(cx);
if (object->is<UnboxedPlainObject>()) {
const UnboxedLayout& layout = object->as<UnboxedPlainObject>().layout();
RootedNativeObject nativeObject(cx, &object->as<NativeObject>());
MOZ_ASSERT(nativeObject->slotSpan() == numSlots());
RootedId id(cx);
RootedValue receiver(cx, ObjectValue(*object));
const UnboxedLayout::PropertyVector& properties = layout.properties();
for (size_t i = 0; i < properties.length(); i++) {
val = iter.read();
// This is the default placeholder value of MObjectState, when no
// properties are defined yet.
if (val.isUndefined())
continue;
id = NameToId(properties[i].name);
ObjectOpResult result;
// SetProperty can only fail due to OOM.
if (!SetProperty(cx, object, id, val, receiver, result))
return false;
if (!result)
return result.reportError(cx, object, id);
}
} else {
RootedNativeObject nativeObject(cx, &object->as<NativeObject>());
MOZ_ASSERT(nativeObject->slotSpan() == numSlots());
for (size_t i = 0; i < numSlots(); i++) {
val = iter.read();
nativeObject->setSlot(i, val);
}
for (size_t i = 0; i < numSlots(); i++) {
val = iter.read();
nativeObject->setSlot(i, val);
}
val.setObject(*object);

View File

@ -13,7 +13,6 @@
#include "jit/MIR.h"
#include "jit/MIRGenerator.h"
#include "jit/MIRGraph.h"
#include "vm/UnboxedObject.h"
#include "jsobjinlines.h"
@ -183,25 +182,6 @@ IsObjectEscaped(MInstruction* ins, JSObject* objDefault)
JitSpewDef(JitSpew_Escape, "is escaped by\n", def);
return true;
case MDefinition::Op_LoadUnboxedScalar:
case MDefinition::Op_StoreUnboxedScalar:
case MDefinition::Op_LoadUnboxedObjectOrNull:
case MDefinition::Op_StoreUnboxedObjectOrNull:
case MDefinition::Op_LoadUnboxedString:
case MDefinition::Op_StoreUnboxedString:
// Not escaped if it is the first argument.
if (def->indexOf(*i) != 0) {
JitSpewDef(JitSpew_Escape, "is escaped by\n", def);
return true;
}
if (!def->getOperand(1)->isConstant()) {
JitSpewDef(JitSpew_Escape, "is addressed with unknown index\n", def);
return true;
}
break;
case MDefinition::Op_PostWriteBarrier:
break;
@ -305,12 +285,6 @@ class ObjectMemoryView : public MDefinitionVisitorDefaultNoop
void visitGuardShape(MGuardShape* ins);
void visitFunctionEnvironment(MFunctionEnvironment* ins);
void visitLambda(MLambda* ins);
void visitStoreUnboxedScalar(MStoreUnboxedScalar* ins);
void visitLoadUnboxedScalar(MLoadUnboxedScalar* ins);
void visitStoreUnboxedObjectOrNull(MStoreUnboxedObjectOrNull* ins);
void visitLoadUnboxedObjectOrNull(MLoadUnboxedObjectOrNull* ins);
void visitStoreUnboxedString(MStoreUnboxedString* ins);
void visitLoadUnboxedString(MLoadUnboxedString* ins);
private:
void storeOffset(MInstruction* ins, size_t offset, MDefinition* value);
@ -656,21 +630,6 @@ ObjectMemoryView::visitLambda(MLambda* ins)
ins->setIncompleteObject();
}
static size_t
GetOffsetOf(MDefinition* index, size_t width, int32_t baseOffset)
{
int32_t idx = index->toConstant()->toInt32();
MOZ_ASSERT(idx >= 0);
MOZ_ASSERT(baseOffset >= 0 && size_t(baseOffset) >= UnboxedPlainObject::offsetOfData());
return idx * width + baseOffset - UnboxedPlainObject::offsetOfData();
}
static size_t
GetOffsetOf(MDefinition* index, Scalar::Type type, int32_t baseOffset)
{
return GetOffsetOf(index, Scalar::byteSize(type), baseOffset);
}
void
ObjectMemoryView::storeOffset(MInstruction* ins, size_t offset, MDefinition* value)
{
@ -700,77 +659,6 @@ ObjectMemoryView::loadOffset(MInstruction* ins, size_t offset)
ins->block()->discard(ins);
}
void
ObjectMemoryView::visitStoreUnboxedScalar(MStoreUnboxedScalar* ins)
{
// Skip stores made on other objects.
if (ins->elements() != obj_)
return;
size_t offset = GetOffsetOf(ins->index(), ins->storageType(), ins->offsetAdjustment());
storeOffset(ins, offset, ins->value());
}
void
ObjectMemoryView::visitLoadUnboxedScalar(MLoadUnboxedScalar* ins)
{
// Skip loads made on other objects.
if (ins->elements() != obj_)
return;
// Replace load by the slot value.
size_t offset = GetOffsetOf(ins->index(), ins->storageType(), ins->offsetAdjustment());
loadOffset(ins, offset);
}
void
ObjectMemoryView::visitStoreUnboxedObjectOrNull(MStoreUnboxedObjectOrNull* ins)
{
// Skip stores made on other objects.
if (ins->elements() != obj_)
return;
// Clone the state and update the slot value.
size_t offset = GetOffsetOf(ins->index(), sizeof(uintptr_t), ins->offsetAdjustment());
storeOffset(ins, offset, ins->value());
}
void
ObjectMemoryView::visitLoadUnboxedObjectOrNull(MLoadUnboxedObjectOrNull* ins)
{
// Skip loads made on other objects.
if (ins->elements() != obj_)
return;
// Replace load by the slot value.
size_t offset = GetOffsetOf(ins->index(), sizeof(uintptr_t), ins->offsetAdjustment());
loadOffset(ins, offset);
}
void
ObjectMemoryView::visitStoreUnboxedString(MStoreUnboxedString* ins)
{
// Skip stores made on other objects.
if (ins->elements() != obj_)
return;
// Clone the state and update the slot value.
size_t offset = GetOffsetOf(ins->index(), sizeof(uintptr_t), ins->offsetAdjustment());
storeOffset(ins, offset, ins->value());
}
void
ObjectMemoryView::visitLoadUnboxedString(MLoadUnboxedString* ins)
{
// Skip loads made on other objects.
if (ins->elements() != obj_)
return;
// Replace load by the slot value.
size_t offset = GetOffsetOf(ins->index(), sizeof(uintptr_t), ins->offsetAdjustment());
loadOffset(ins, offset);
}
static bool
IndexOf(MDefinition* ins, int32_t* res)
{
@ -907,11 +795,6 @@ IsArrayEscaped(MInstruction* ins)
return true;
}
if (obj->is<UnboxedArrayObject>()) {
JitSpew(JitSpew_Escape, "Template object is an unboxed plain object.");
return true;
}
if (length >= 16) {
JitSpew(JitSpew_Escape, "Array has too many elements");
return true;

View File

@ -27,6 +27,7 @@
#endif
#include "jit/VMFunctions.h"
#include "vm/Interpreter.h"
#include "vm/NativeObject-inl.h"
#include "jit/MacroAssembler-inl.h"
#include "vm/Interpreter-inl.h"
@ -285,11 +286,6 @@ ICStub::trace(JSTracer* trc)
TraceEdge(trc, &getElemStub->shape(), "baseline-getelem-dense-shape");
break;
}
case ICStub::GetElem_UnboxedArray: {
ICGetElem_UnboxedArray* getElemStub = toGetElem_UnboxedArray();
TraceEdge(trc, &getElemStub->group(), "baseline-getelem-unboxed-array-group");
break;
}
case ICStub::GetElem_TypedArray: {
ICGetElem_TypedArray* getElemStub = toGetElem_TypedArray();
TraceEdge(trc, &getElemStub->shape(), "baseline-getelem-typedarray-shape");
@ -2248,9 +2244,7 @@ IsCacheableProtoChain(JSObject* obj, JSObject* holder, bool isDOMProxy)
if (!isDOMProxy && !obj->isNative()) {
if (obj == holder)
return false;
if (!obj->is<UnboxedPlainObject>() &&
!obj->is<UnboxedArrayObject>() &&
!obj->is<TypedObject>())
if (!obj->is<TypedObject>())
{
return false;
}
@ -2578,12 +2572,6 @@ CheckHasNoSuchProperty(JSContext* cx, JSObject* obj, PropertyName* name,
} else if (curObj != obj) {
// Non-native objects are only handled as the original receiver.
return false;
} else if (curObj->is<UnboxedPlainObject>()) {
if (curObj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx, NameToId(name)))
return false;
} else if (curObj->is<UnboxedArrayObject>()) {
if (name == cx->names().length)
return false;
} else if (curObj->is<TypedObject>()) {
if (curObj->as<TypedObject>().typeDescr().hasProperty(cx->names(), NameToId(name)))
return false;
@ -2848,34 +2836,15 @@ GuardReceiverObject(MacroAssembler& masm, ReceiverGuard guard,
{
Address groupAddress(ICStubReg, receiverGuardOffset + HeapReceiverGuard::offsetOfGroup());
Address shapeAddress(ICStubReg, receiverGuardOffset + HeapReceiverGuard::offsetOfShape());
Address expandoAddress(object, UnboxedPlainObject::offsetOfExpando());
if (guard.group) {
masm.loadPtr(groupAddress, scratch);
masm.branchTestObjGroup(Assembler::NotEqual, object, scratch, failure);
if (guard.group->clasp() == &UnboxedPlainObject::class_ && !guard.shape) {
// Guard the unboxed object has no expando object.
masm.branchPtr(Assembler::NotEqual, expandoAddress, ImmWord(0), failure);
}
}
if (guard.shape) {
masm.loadPtr(shapeAddress, scratch);
if (guard.group && guard.group->clasp() == &UnboxedPlainObject::class_) {
// Guard the unboxed object has a matching expando object.
masm.branchPtr(Assembler::Equal, expandoAddress, ImmWord(0), failure);
Label done;
masm.push(object);
masm.loadPtr(expandoAddress, object);
masm.branchTestObjShape(Assembler::Equal, object, scratch, &done);
masm.pop(object);
masm.jump(failure);
masm.bind(&done);
masm.pop(object);
} else {
masm.branchTestObjShape(Assembler::NotEqual, object, scratch, failure);
}
masm.branchTestObjShape(Assembler::NotEqual, object, scratch, failure);
}
}
@ -4259,8 +4228,7 @@ DoNewObject(JSContext* cx, void* payload, ICNewObject_Fallback* stub, MutableHan
return false;
if (!stub->invalid() &&
(templateObject->is<UnboxedPlainObject>() ||
!templateObject->as<PlainObject>().hasDynamicSlots()))
!templateObject->as<PlainObject>().hasDynamicSlots())
{
JitCode* code = GenerateNewObjectWithTemplateCode(cx, templateObject);
if (!code)

View File

@ -28,7 +28,7 @@
#include "vm/NativeObject-inl.h"
#include "vm/StringObject-inl.h"
#include "vm/TypeInference-inl.h"
#include "vm/UnboxedObject-inl.h"
#include "gc/StoreBuffer-inl.h"
using namespace js;
using namespace js::jit;
@ -318,7 +318,7 @@ ArraySpliceDense(JSContext* cx, HandleObject obj, uint32_t start, uint32_t delet
bool
ArrayPopDense(JSContext* cx, HandleObject obj, MutableHandleValue rval)
{
MOZ_ASSERT(obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>());
MOZ_ASSERT(obj->is<ArrayObject>());
AutoDetectInvalidation adi(cx, rval);
@ -337,12 +337,11 @@ ArrayPopDense(JSContext* cx, HandleObject obj, MutableHandleValue rval)
}
bool
ArrayPushDense(JSContext* cx, HandleObject obj, HandleValue v, uint32_t* length)
ArrayPushDense(JSContext* cx, HandleArrayObject arr, HandleValue v, uint32_t* length)
{
*length = GetAnyBoxedOrUnboxedArrayLength(obj);
DenseElementResult result =
SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, *length, v.address(), 1,
ShouldUpdateTypes::DontUpdate);
*length = arr->length();
DenseElementResult result = arr->setOrExtendDenseElements(cx, *length, v.address(), 1,
ShouldUpdateTypes::DontUpdate);
if (result != DenseElementResult::Incomplete) {
(*length)++;
return result == DenseElementResult::Success;
@ -350,7 +349,7 @@ ArrayPushDense(JSContext* cx, HandleObject obj, HandleValue v, uint32_t* length)
JS::AutoValueArray<3> argv(cx);
argv[0].setUndefined();
argv[1].setObject(*obj);
argv[1].setObject(*arr);
argv[2].set(v);
if (!js::array_push(cx, 1, argv.begin()))
return false;
@ -362,7 +361,7 @@ ArrayPushDense(JSContext* cx, HandleObject obj, HandleValue v, uint32_t* length)
bool
ArrayShiftDense(JSContext* cx, HandleObject obj, MutableHandleValue rval)
{
MOZ_ASSERT(obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>());
MOZ_ASSERT(obj->is<ArrayObject>());
AutoDetectInvalidation adi(cx, rval);
@ -1143,16 +1142,14 @@ Recompile(JSContext* cx)
}
bool
SetDenseOrUnboxedArrayElement(JSContext* cx, HandleObject obj, int32_t index,
HandleValue value, bool strict)
SetDenseElement(JSContext* cx, HandleNativeObject obj, int32_t index, HandleValue value, bool strict)
{
// This function is called from Ion code for StoreElementHole's OOL path.
// In this case we know the object is native or an unboxed array and that
// no type changes are needed.
// In this case we know the object is native and that no type changes are
// needed.
DenseElementResult result =
SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, index, value.address(), 1,
ShouldUpdateTypes::DontUpdate);
DenseElementResult result = obj->setOrExtendDenseElements(cx, index, value.address(), 1,
ShouldUpdateTypes::DontUpdate);
if (result != DenseElementResult::Incomplete)
return result == DenseElementResult::Success;

View File

@ -622,7 +622,7 @@ template<bool Equal>
bool StringsEqual(JSContext* cx, HandleString left, HandleString right, bool* res);
MOZ_MUST_USE bool ArrayPopDense(JSContext* cx, HandleObject obj, MutableHandleValue rval);
MOZ_MUST_USE bool ArrayPushDense(JSContext* cx, HandleObject obj, HandleValue v, uint32_t* length);
MOZ_MUST_USE bool ArrayPushDense(JSContext* cx, HandleArrayObject obj, HandleValue v, uint32_t* length);
MOZ_MUST_USE bool ArrayShiftDense(JSContext* cx, HandleObject obj, MutableHandleValue rval);
JSString* ArrayJoin(JSContext* cx, HandleObject array, HandleString sep);
@ -748,8 +748,8 @@ ForcedRecompile(JSContext* cx);
JSString* StringReplace(JSContext* cx, HandleString string, HandleString pattern,
HandleString repl);
MOZ_MUST_USE bool SetDenseOrUnboxedArrayElement(JSContext* cx, HandleObject obj, int32_t index,
HandleValue value, bool strict);
MOZ_MUST_USE bool SetDenseElement(JSContext* cx, HandleNativeObject obj, int32_t index,
HandleValue value, bool strict);
void AssertValidObjectPtr(JSContext* cx, JSObject* obj);
void AssertValidObjectOrNullPtr(JSContext* cx, JSObject* obj);

View File

@ -5165,72 +5165,6 @@ class LSetInitializedLength : public LInstructionHelper<0, 2, 0>
}
};
class LUnboxedArrayLength : public LInstructionHelper<1, 1, 0>
{
public:
LIR_HEADER(UnboxedArrayLength)
explicit LUnboxedArrayLength(const LAllocation& object) {
setOperand(0, object);
}
const LAllocation* object() {
return getOperand(0);
}
};
class LUnboxedArrayInitializedLength : public LInstructionHelper<1, 1, 0>
{
public:
LIR_HEADER(UnboxedArrayInitializedLength)
explicit LUnboxedArrayInitializedLength(const LAllocation& object) {
setOperand(0, object);
}
const LAllocation* object() {
return getOperand(0);
}
};
class LIncrementUnboxedArrayInitializedLength : public LInstructionHelper<0, 1, 0>
{
public:
LIR_HEADER(IncrementUnboxedArrayInitializedLength)
explicit LIncrementUnboxedArrayInitializedLength(const LAllocation& object) {
setOperand(0, object);
}
const LAllocation* object() {
return getOperand(0);
}
};
class LSetUnboxedArrayInitializedLength : public LInstructionHelper<0, 2, 1>
{
public:
LIR_HEADER(SetUnboxedArrayInitializedLength)
explicit LSetUnboxedArrayInitializedLength(const LAllocation& object,
const LAllocation& length,
const LDefinition& temp) {
setOperand(0, object);
setOperand(1, length);
setTemp(0, temp);
}
const LAllocation* object() {
return getOperand(0);
}
const LAllocation* length() {
return getOperand(1);
}
const LDefinition* temp() {
return getTemp(0);
}
};
// Load the length from an elements header.
class LArrayLength : public LInstructionHelper<1, 1, 0>
{
@ -5735,19 +5669,17 @@ class LStoreElementT : public LInstructionHelper<0, 3, 0>
};
// Like LStoreElementV, but supports indexes >= initialized length.
class LStoreElementHoleV : public LInstructionHelper<0, 3 + BOX_PIECES, 1>
class LStoreElementHoleV : public LInstructionHelper<0, 3 + BOX_PIECES, 0>
{
public:
LIR_HEADER(StoreElementHoleV)
LStoreElementHoleV(const LAllocation& object, const LAllocation& elements,
const LAllocation& index, const LBoxAllocation& value,
const LDefinition& temp) {
const LAllocation& index, const LBoxAllocation& value) {
setOperand(0, object);
setOperand(1, elements);
setOperand(2, index);
setBoxOperand(Value, value);
setTemp(0, temp);
}
static const size_t Value = 3;
@ -5767,19 +5699,17 @@ class LStoreElementHoleV : public LInstructionHelper<0, 3 + BOX_PIECES, 1>
};
// Like LStoreElementT, but supports indexes >= initialized length.
class LStoreElementHoleT : public LInstructionHelper<0, 4, 1>
class LStoreElementHoleT : public LInstructionHelper<0, 4, 0>
{
public:
LIR_HEADER(StoreElementHoleT)
LStoreElementHoleT(const LAllocation& object, const LAllocation& elements,
const LAllocation& index, const LAllocation& value,
const LDefinition& temp) {
const LAllocation& index, const LAllocation& value) {
setOperand(0, object);
setOperand(1, elements);
setOperand(2, index);
setOperand(3, value);
setTemp(0, temp);
}
const MStoreElementHole* mir() const {
@ -5800,19 +5730,17 @@ class LStoreElementHoleT : public LInstructionHelper<0, 4, 1>
};
// Like LStoreElementV, but can just ignore assignment (for eg. frozen objects)
class LFallibleStoreElementV : public LInstructionHelper<0, 3 + BOX_PIECES, 1>
class LFallibleStoreElementV : public LInstructionHelper<0, 3 + BOX_PIECES, 0>
{
public:
LIR_HEADER(FallibleStoreElementV)
LFallibleStoreElementV(const LAllocation& object, const LAllocation& elements,
const LAllocation& index, const LBoxAllocation& value,
const LDefinition& temp) {
const LAllocation& index, const LBoxAllocation& value) {
setOperand(0, object);
setOperand(1, elements);
setOperand(2, index);
setBoxOperand(Value, value);
setTemp(0, temp);
}
static const size_t Value = 3;
@ -5832,19 +5760,17 @@ class LFallibleStoreElementV : public LInstructionHelper<0, 3 + BOX_PIECES, 1>
};
// Like LStoreElementT, but can just ignore assignment (for eg. frozen objects)
class LFallibleStoreElementT : public LInstructionHelper<0, 4, 1>
class LFallibleStoreElementT : public LInstructionHelper<0, 4, 0>
{
public:
LIR_HEADER(FallibleStoreElementT)
LFallibleStoreElementT(const LAllocation& object, const LAllocation& elements,
const LAllocation& index, const LAllocation& value,
const LDefinition& temp) {
const LAllocation& index, const LAllocation& value) {
setOperand(0, object);
setOperand(1, elements);
setOperand(2, index);
setOperand(3, value);
setTemp(0, temp);
}
const MFallibleStoreElement* mir() const {
@ -5891,22 +5817,6 @@ class LStoreUnboxedPointer : public LInstructionHelper<0, 3, 0>
}
};
// If necessary, convert an unboxed object in a particular group to its native
// representation.
class LConvertUnboxedObjectToNative : public LInstructionHelper<0, 1, 0>
{
public:
LIR_HEADER(ConvertUnboxedObjectToNative)
explicit LConvertUnboxedObjectToNative(const LAllocation& object) {
setOperand(0, object);
}
MConvertUnboxedObjectToNative* mir() {
return mir_->toConvertUnboxedObjectToNative();
}
};
class LArrayPopShiftV : public LInstructionHelper<BOX_PIECES, 1, 2>
{
public:
@ -7429,38 +7339,6 @@ class LGuardReceiverPolymorphic : public LInstructionHelper<0, 1, 1>
}
};
class LGuardUnboxedExpando : public LInstructionHelper<0, 1, 0>
{
public:
LIR_HEADER(GuardUnboxedExpando)
explicit LGuardUnboxedExpando(const LAllocation& in) {
setOperand(0, in);
}
const LAllocation* object() {
return getOperand(0);
}
const MGuardUnboxedExpando* mir() const {
return mir_->toGuardUnboxedExpando();
}
};
class LLoadUnboxedExpando : public LInstructionHelper<1, 1, 0>
{
public:
LIR_HEADER(LoadUnboxedExpando)
explicit LLoadUnboxedExpando(const LAllocation& in) {
setOperand(0, in);
}
const LAllocation* object() {
return getOperand(0);
}
const MLoadUnboxedExpando* mir() const {
return mir_->toLoadUnboxedExpando();
}
};
// Guard that a value is in a TypeSet.
class LTypeBarrierV : public LInstructionHelper<0, BOX_PIECES, 1>
{

View File

@ -258,8 +258,6 @@
_(GuardObjectGroup) \
_(GuardObjectIdentity) \
_(GuardClass) \
_(GuardUnboxedExpando) \
_(LoadUnboxedExpando) \
_(TypeBarrierV) \
_(TypeBarrierO) \
_(MonitorTypes) \
@ -269,10 +267,6 @@
_(PostWriteElementBarrierV) \
_(InitializedLength) \
_(SetInitializedLength) \
_(UnboxedArrayLength) \
_(UnboxedArrayInitializedLength) \
_(IncrementUnboxedArrayInitializedLength) \
_(SetUnboxedArrayInitializedLength) \
_(BoundsCheck) \
_(BoundsCheckRange) \
_(BoundsCheckLower) \
@ -287,7 +281,6 @@
_(StoreElementT) \
_(StoreUnboxedScalar) \
_(StoreUnboxedPointer) \
_(ConvertUnboxedObjectToNative) \
_(ArrayPopShiftV) \
_(ArrayPopShiftT) \
_(ArrayPushV) \

View File

@ -6434,9 +6434,6 @@ JS_SetGlobalJitCompilerOption(JSContext* cx, JSJitCompilerOption opt, uint32_t v
}
jit::JitOptions.jumpThreshold = value;
break;
case JSJITCOMPILER_UNBOXED_OBJECTS:
jit::JitOptions.disableUnboxedObjects = !value;
break;
case JSJITCOMPILER_ASMJS_ATOMICS_ENABLE:
jit::JitOptions.asmJSAtomicsEnable = !!value;
break;

View File

@ -1093,7 +1093,6 @@ class JS_PUBLIC_API(ContextOptions) {
wasmAlwaysBaseline_(false),
throwOnAsmJSValidationFailure_(false),
nativeRegExp_(true),
unboxedArrays_(false),
asyncStack_(true),
throwOnDebuggeeWouldRun_(true),
dumpStackOnDebuggeeWouldRun_(false),
@ -1170,12 +1169,6 @@ class JS_PUBLIC_API(ContextOptions) {
return *this;
}
bool unboxedArrays() const { return unboxedArrays_; }
ContextOptions& setUnboxedArrays(bool flag) {
unboxedArrays_ = flag;
return *this;
}
bool asyncStack() const { return asyncStack_; }
ContextOptions& setAsyncStack(bool flag) {
asyncStack_ = flag;
@ -1238,7 +1231,6 @@ class JS_PUBLIC_API(ContextOptions) {
bool wasmAlwaysBaseline_ : 1;
bool throwOnAsmJSValidationFailure_ : 1;
bool nativeRegExp_ : 1;
bool unboxedArrays_ : 1;
bool asyncStack_ : 1;
bool throwOnDebuggeeWouldRun_ : 1;
bool dumpStackOnDebuggeeWouldRun_ : 1;
@ -5783,20 +5775,19 @@ JS_SetParallelParsingEnabled(JSContext* cx, bool enabled);
extern JS_PUBLIC_API(void)
JS_SetOffthreadIonCompilationEnabled(JSContext* cx, bool enabled);
#define JIT_COMPILER_OPTIONS(Register) \
Register(BASELINE_WARMUP_TRIGGER, "baseline.warmup.trigger") \
Register(ION_WARMUP_TRIGGER, "ion.warmup.trigger") \
Register(ION_GVN_ENABLE, "ion.gvn.enable") \
Register(ION_FORCE_IC, "ion.forceinlineCaches") \
Register(ION_ENABLE, "ion.enable") \
#define JIT_COMPILER_OPTIONS(Register) \
Register(BASELINE_WARMUP_TRIGGER, "baseline.warmup.trigger") \
Register(ION_WARMUP_TRIGGER, "ion.warmup.trigger") \
Register(ION_GVN_ENABLE, "ion.gvn.enable") \
Register(ION_FORCE_IC, "ion.forceinlineCaches") \
Register(ION_ENABLE, "ion.enable") \
Register(ION_INTERRUPT_WITHOUT_SIGNAL, "ion.interrupt-without-signals") \
Register(ION_CHECK_RANGE_ANALYSIS, "ion.check-range-analysis") \
Register(BASELINE_ENABLE, "baseline.enable") \
Register(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable") \
Register(JUMP_THRESHOLD, "jump-threshold") \
Register(UNBOXED_OBJECTS, "unboxed_objects") \
Register(ASMJS_ATOMICS_ENABLE, "asmjs.atomics.enable") \
Register(WASM_TEST_MODE, "wasm.test-mode") \
Register(ION_CHECK_RANGE_ANALYSIS, "ion.check-range-analysis") \
Register(BASELINE_ENABLE, "baseline.enable") \
Register(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable") \
Register(JUMP_THRESHOLD, "jump-threshold") \
Register(ASMJS_ATOMICS_ENABLE, "asmjs.atomics.enable") \
Register(WASM_TEST_MODE, "wasm.test-mode") \
Register(WASM_FOLD_OFFSETS, "wasm.fold-offsets")
typedef enum JSJitCompilerOption {

View File

@ -45,7 +45,6 @@
#include "vm/Caches-inl.h"
#include "vm/Interpreter-inl.h"
#include "vm/NativeObject-inl.h"
#include "vm/UnboxedObject-inl.h"
using namespace js;
using namespace js::gc;
@ -64,7 +63,7 @@ using JS::ToUint32;
bool
JS::IsArray(JSContext* cx, HandleObject obj, IsArrayAnswer* answer)
{
if (obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()) {
if (obj->is<ArrayObject>()) {
*answer = IsArrayAnswer::Array;
return true;
}
@ -100,11 +99,6 @@ js::GetLengthProperty(JSContext* cx, HandleObject obj, uint32_t* lengthp)
return true;
}
if (obj->is<UnboxedArrayObject>()) {
*lengthp = obj->as<UnboxedArrayObject>().length();
return true;
}
if (obj->is<ArgumentsObject>()) {
ArgumentsObject& argsobj = obj->as<ArgumentsObject>();
if (!argsobj.hasOverriddenLength()) {
@ -253,18 +247,20 @@ static bool
GetElement(JSContext* cx, HandleObject obj, HandleObject receiver,
uint32_t index, bool* hole, MutableHandleValue vp)
{
AssertGreaterThanZero(index);
if (index < GetAnyBoxedOrUnboxedInitializedLength(obj)) {
vp.set(GetAnyBoxedOrUnboxedDenseElement(obj, uint32_t(index)));
if (!vp.isMagic(JS_ELEMENTS_HOLE)) {
*hole = false;
return true;
if (obj->isNative()) {
NativeObject* nobj = &obj->as<NativeObject>();
if (index < nobj->getDenseInitializedLength()) {
vp.set(nobj->getDenseElement(size_t(index)));
if (!vp.isMagic(JS_ELEMENTS_HOLE)) {
*hole = false;
return true;
}
}
}
if (obj->is<ArgumentsObject>()) {
if (obj->as<ArgumentsObject>().maybeGetElement(uint32_t(index), vp)) {
*hole = false;
return true;
if (nobj->is<ArgumentsObject>() && index <= UINT32_MAX) {
if (nobj->as<ArgumentsObject>().maybeGetElement(uint32_t(index), vp)) {
*hole = false;
return true;
}
}
}
@ -283,8 +279,8 @@ ElementAdder::append(JSContext* cx, HandleValue v)
{
MOZ_ASSERT(index_ < length_);
if (resObj_) {
DenseElementResult result =
SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, resObj_, index_, v.address(), 1);
NativeObject* resObj = &resObj_->as<NativeObject>();
DenseElementResult result = resObj->setOrExtendDenseElements(cx, index_, v.address(), 1);
if (result == DenseElementResult::Failure)
return false;
if (result == DenseElementResult::Incomplete) {
@ -336,37 +332,31 @@ js::GetElementsWithAdder(JSContext* cx, HandleObject obj, HandleObject receiver,
return true;
}
template <JSValueType Type>
DenseElementResult
GetBoxedOrUnboxedDenseElements(JSObject* aobj, uint32_t length, Value* vp)
static bool
GetDenseElements(NativeObject* aobj, uint32_t length, Value* vp)
{
MOZ_ASSERT(!ObjectMayHaveExtraIndexedProperties(aobj));
if (length > GetBoxedOrUnboxedInitializedLength<Type>(aobj))
return DenseElementResult::Incomplete;
if (length > aobj->getDenseInitializedLength())
return false;
for (size_t i = 0; i < length; i++) {
vp[i] = GetBoxedOrUnboxedDenseElement<Type>(aobj, i);
vp[i] = aobj->getDenseElement(i);
// No other indexed properties so hole => undefined.
if (vp[i].isMagic(JS_ELEMENTS_HOLE))
vp[i] = UndefinedValue();
}
return DenseElementResult::Success;
return true;
}
DefineBoxedOrUnboxedFunctor3(GetBoxedOrUnboxedDenseElements,
JSObject*, uint32_t, Value*);
bool
js::GetElements(JSContext* cx, HandleObject aobj, uint32_t length, Value* vp)
{
if (!ObjectMayHaveExtraIndexedProperties(aobj)) {
GetBoxedOrUnboxedDenseElementsFunctor functor(aobj, length, vp);
DenseElementResult result = CallBoxedOrUnboxedSpecialization(functor, aobj);
if (result != DenseElementResult::Incomplete)
return result == DenseElementResult::Success;
if (GetDenseElements(&aobj->as<NativeObject>(), length, vp))
return true;
}
if (aobj->is<ArgumentsObject>()) {
@ -398,9 +388,9 @@ SetArrayElement(JSContext* cx, HandleObject obj, double index, HandleValue v)
{
MOZ_ASSERT(index >= 0);
if ((obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()) && !obj->isIndexed() && index <= UINT32_MAX) {
DenseElementResult result =
SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, uint32_t(index), v.address(), 1);
if (obj->is<ArrayObject>() && !obj->isIndexed() && index <= UINT32_MAX) {
NativeObject* nobj = &obj->as<NativeObject>();
DenseElementResult result = nobj->setOrExtendDenseElements(cx, uint32_t(index), v.address(), 1);
if (result != DenseElementResult::Incomplete)
return result == DenseElementResult::Success;
}
@ -520,24 +510,6 @@ struct ReverseIndexComparator
}
};
bool
js::CanonicalizeArrayLengthValue(JSContext* cx, HandleValue v, uint32_t* newLen)
{
double d;
if (!ToUint32(cx, v, newLen))
return false;
if (!ToNumber(cx, v, &d))
return false;
if (d == *newLen)
return true;
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
return false;
}
/* ES6 draft rev 34 (2015 Feb 20) 9.4.2.4 ArraySetLength */
bool
js::ArraySetLength(JSContext* cx, Handle<ArrayObject*> arr, HandleId id,
@ -559,12 +531,22 @@ js::ArraySetLength(JSContext* cx, Handle<ArrayObject*> arr, HandleId id,
} else {
// Step 2 is irrelevant in our implementation.
// Steps 3-7.
MOZ_ASSERT_IF(attrs & JSPROP_IGNORE_VALUE, value.isUndefined());
if (!CanonicalizeArrayLengthValue(cx, value, &newLen))
// Step 3.
if (!ToUint32(cx, value, &newLen))
return false;
// Step 8 is irrelevant in our implementation.
// Step 4.
double d;
if (!ToNumber(cx, value, &d))
return false;
// Step 5.
if (d != newLen) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
return false;
}
// Steps 6-8 are irrelevant in our implementation.
}
// Steps 9-11.
@ -823,7 +805,7 @@ array_addProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v)
static inline bool
ObjectMayHaveExtraIndexedOwnProperties(JSObject* obj)
{
return (!obj->isNative() && !obj->is<UnboxedArrayObject>()) ||
return !obj->isNative() ||
obj->isIndexed() ||
obj->is<TypedArrayObject>() ||
ClassMayResolveId(*obj->runtimeFromAnyThread()->commonNames,
@ -854,7 +836,7 @@ js::ObjectMayHaveExtraIndexedProperties(JSObject* obj)
if (ObjectMayHaveExtraIndexedOwnProperties(obj))
return true;
if (GetAnyBoxedOrUnboxedInitializedLength(obj) != 0)
if (obj->as<NativeObject>().getDenseInitializedLength() != 0)
return true;
} while (true);
}
@ -1064,31 +1046,32 @@ struct StringSeparatorOp
}
};
template <typename SeparatorOp, JSValueType Type>
static DenseElementResult
ArrayJoinDenseKernel(JSContext* cx, SeparatorOp sepOp, HandleObject obj, uint32_t length,
template <typename SeparatorOp>
static bool
ArrayJoinDenseKernel(JSContext* cx, SeparatorOp sepOp, HandleNativeObject obj, uint64_t length,
StringBuffer& sb, uint32_t* numProcessed)
{
// This loop handles all elements up to initializedLength. If
// length > initLength we rely on the second loop to add the
// other elements.
MOZ_ASSERT(*numProcessed == 0);
uint32_t initLength = Min<uint32_t>(GetBoxedOrUnboxedInitializedLength<Type>(obj), length);
uint32_t initLength = Min<uint32_t>(obj->getDenseInitializedLength(),
length);
while (*numProcessed < initLength) {
if (!CheckForInterrupt(cx))
return DenseElementResult::Failure;
return false;
Value elem = GetBoxedOrUnboxedDenseElement<Type>(obj, *numProcessed);
Value elem = obj->as<NativeObject>().getDenseElement(*numProcessed);
if (elem.isString()) {
if (!sb.append(elem.toString()))
return DenseElementResult::Failure;
return false;
} else if (elem.isNumber()) {
if (!NumberValueToStringBuffer(cx, elem, sb))
return DenseElementResult::Failure;
return false;
} else if (elem.isBoolean()) {
if (!BooleanToStringBuffer(elem.toBoolean(), sb))
return DenseElementResult::Failure;
return false;
} else if (elem.isObject() || elem.isSymbol()) {
/*
* Object stringifying could modify the initialized length or make
@ -1104,32 +1087,12 @@ ArrayJoinDenseKernel(JSContext* cx, SeparatorOp sepOp, HandleObject obj, uint32_
}
if (++(*numProcessed) != length && !sepOp(cx, sb))
return DenseElementResult::Failure;
return false;
}
return DenseElementResult::Incomplete;
return true;
}
template <typename SeparatorOp>
struct ArrayJoinDenseKernelFunctor {
JSContext* cx;
SeparatorOp sepOp;
HandleObject obj;
uint32_t length;
StringBuffer& sb;
uint32_t* numProcessed;
ArrayJoinDenseKernelFunctor(JSContext* cx, SeparatorOp sepOp, HandleObject obj,
uint32_t length, StringBuffer& sb, uint32_t* numProcessed)
: cx(cx), sepOp(sepOp), obj(obj), length(length), sb(sb), numProcessed(numProcessed)
{}
template <JSValueType Type>
DenseElementResult operator()() {
return ArrayJoinDenseKernel<SeparatorOp, Type>(cx, sepOp, obj, length, sb, numProcessed);
}
};
template <typename SeparatorOp>
static bool
ArrayJoinKernel(JSContext* cx, SeparatorOp sepOp, HandleObject obj, uint32_t length,
@ -1138,10 +1101,10 @@ ArrayJoinKernel(JSContext* cx, SeparatorOp sepOp, HandleObject obj, uint32_t len
uint32_t i = 0;
if (!ObjectMayHaveExtraIndexedProperties(obj)) {
ArrayJoinDenseKernelFunctor<SeparatorOp> functor(cx, sepOp, obj, length, sb, &i);
DenseElementResult result = CallBoxedOrUnboxedSpecialization(functor, obj);
if (result == DenseElementResult::Failure)
if (!ArrayJoinDenseKernel<SeparatorOp>(cx, sepOp, obj.as<NativeObject>(), length, sb, &i))
{
return false;
}
}
if (i != length) {
@ -1212,11 +1175,14 @@ js::array_join(JSContext* cx, unsigned argc, Value* vp)
// An optimized version of a special case of steps 7-11: when length==1 and
// the 0th element is a string, ToString() of that element is a no-op and
// so it can be immediately returned as the result.
if (length == 1 && GetAnyBoxedOrUnboxedInitializedLength(obj) == 1) {
Value elem0 = GetAnyBoxedOrUnboxedDenseElement(obj, 0);
if (elem0.isString()) {
args.rval().set(elem0);
return true;
if (length == 1 && obj->isNative()) {
NativeObject* nobj = &obj->as<NativeObject>();
if (nobj->getDenseInitializedLength() == 1) {
Value elem0 = nobj->getDenseElement(0);
if (elem0.isString()) {
args.rval().set(elem0);
return true;
}
}
}
@ -1259,7 +1225,7 @@ js::array_join(JSContext* cx, unsigned argc, Value* vp)
}
// Step 11
JSString *str = sb.finishString();
JSString* str = sb.finishString();
if (!str)
return false;
@ -1288,10 +1254,6 @@ array_toLocaleString(JSContext* cx, unsigned argc, Value* vp)
args.rval().setString(cx->names().empty);
return true;
}
if (obj->is<UnboxedArrayObject>() && obj->as<UnboxedArrayObject>().length() == 0) {
args.rval().setString(cx->names().empty);
return true;
}
AutoCycleDetector detector(cx, obj);
if (!detector.init())
@ -1328,8 +1290,9 @@ InitArrayElements(JSContext* cx, HandleObject obj, uint32_t start,
return false;
if (!ObjectMayHaveExtraIndexedProperties(obj)) {
DenseElementResult result =
SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, start, vector, count, updateTypes);
NativeObject* nobj = &obj->as<NativeObject>();
DenseElementResult result = nobj->setOrExtendDenseElements(cx, uint32_t(start), vector,
count, updateTypes);
if (result != DenseElementResult::Incomplete)
return result == DenseElementResult::Success;
}
@ -1363,54 +1326,45 @@ InitArrayElements(JSContext* cx, HandleObject obj, uint32_t start,
return true;
}
template <JSValueType Type>
DenseElementResult
ArrayReverseDenseKernel(JSContext* cx, HandleObject obj, uint32_t length)
static DenseElementResult
ArrayReverseDenseKernel(JSContext* cx, HandleNativeObject obj, uint32_t length)
{
/* An empty array or an array with no elements is already reversed. */
if (length == 0 || GetBoxedOrUnboxedInitializedLength<Type>(obj) == 0)
if (length == 0 || obj->getDenseInitializedLength() == 0)
return DenseElementResult::Success;
if (Type == JSVAL_TYPE_MAGIC) {
if (obj->as<NativeObject>().denseElementsAreFrozen())
return DenseElementResult::Incomplete;
if (obj->denseElementsAreFrozen())
return DenseElementResult::Incomplete;
/*
* It's actually surprisingly complicated to reverse an array due to the
* orthogonality of array length and array capacity while handling
* leading and trailing holes correctly. Reversing seems less likely to
* be a common operation than other array mass-mutation methods, so for
* now just take a probably-small memory hit (in the absence of too many
* holes in the array at its start) and ensure that the capacity is
* sufficient to hold all the elements in the array if it were full.
*/
DenseElementResult result = obj->as<NativeObject>().ensureDenseElements(cx, length, 0);
if (result != DenseElementResult::Success)
return result;
/*
* It's actually surprisingly complicated to reverse an array due to the
* orthogonality of array length and array capacity while handling
* leading and trailing holes correctly. Reversing seems less likely to
* be a common operation than other array mass-mutation methods, so for
* now just take a probably-small memory hit (in the absence of too many
* holes in the array at its start) and ensure that the capacity is
* sufficient to hold all the elements in the array if it were full.
*/
DenseElementResult result = obj->ensureDenseElements(cx, length, 0);
if (result != DenseElementResult::Success)
return result;
/* Fill out the array's initialized length to its proper length. */
obj->as<NativeObject>().ensureDenseInitializedLength(cx, length, 0);
} else {
// Unboxed arrays can only be reversed here if their initialized length
// matches their actual length. Otherwise the reversal will place holes
// at the beginning of the array, which we don't support.
if (length != obj->as<UnboxedArrayObject>().initializedLength())
return DenseElementResult::Incomplete;
}
/* Fill out the array's initialized length to its proper length. */
obj->ensureDenseInitializedLength(cx, length, 0);
RootedValue origlo(cx), orighi(cx);
uint32_t lo = 0, hi = length - 1;
for (; lo < hi; lo++, hi--) {
origlo = GetBoxedOrUnboxedDenseElement<Type>(obj, lo);
orighi = GetBoxedOrUnboxedDenseElement<Type>(obj, hi);
SetBoxedOrUnboxedDenseElementNoTypeChange<Type>(obj, lo, orighi);
origlo = obj->getDenseElement(lo);
orighi = obj->getDenseElement(hi);
obj->setDenseElement(lo, orighi);
if (orighi.isMagic(JS_ELEMENTS_HOLE) &&
!SuppressDeletedProperty(cx, obj, INT_TO_JSID(lo)))
{
return DenseElementResult::Failure;
}
SetBoxedOrUnboxedDenseElementNoTypeChange<Type>(obj, hi, origlo);
obj->setDenseElement(hi, origlo);
if (origlo.isMagic(JS_ELEMENTS_HOLE) &&
!SuppressDeletedProperty(cx, obj, INT_TO_JSID(hi)))
{
@ -1421,9 +1375,6 @@ ArrayReverseDenseKernel(JSContext* cx, HandleObject obj, uint32_t length)
return DenseElementResult::Success;
}
DefineBoxedOrUnboxedFunctor3(ArrayReverseDenseKernel,
JSContext*, HandleObject, uint32_t);
bool
js::array_reverse(JSContext* cx, unsigned argc, Value* vp)
{
@ -1438,8 +1389,8 @@ js::array_reverse(JSContext* cx, unsigned argc, Value* vp)
return false;
if (!ObjectMayHaveExtraIndexedProperties(obj)) {
ArrayReverseDenseKernelFunctor functor(cx, obj, len);
DenseElementResult result = CallBoxedOrUnboxedSpecialization(functor, obj);
DenseElementResult result =
ArrayReverseDenseKernel(cx, obj.as<NativeObject>(), uint32_t(len));
if (result != DenseElementResult::Incomplete) {
/*
* Per ECMA-262, don't update the length of the array, even if the new
@ -2082,8 +2033,8 @@ js::array_push(JSContext* cx, unsigned argc, Value* vp)
if (!ObjectMayHaveExtraIndexedProperties(obj)) {
DenseElementResult result =
SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, length,
args.array(), args.length());
obj->as<NativeObject>().setOrExtendDenseElements(cx, uint32_t(length),
args.array(), args.length());
if (result != DenseElementResult::Incomplete) {
if (result == DenseElementResult::Failure)
return false;
@ -2091,14 +2042,8 @@ js::array_push(JSContext* cx, unsigned argc, Value* vp)
uint32_t newlength = length + args.length();
args.rval().setNumber(newlength);
// SetOrExtendAnyBoxedOrUnboxedDenseElements takes care of updating the
// length for boxed and unboxed arrays. Handle updates to the length of
// non-arrays here.
bool isArray;
if (!IsArray(cx, obj, &isArray))
return false;
if (!isArray)
// Handle updates to the length of non-arrays here.
if (!obj->is<ArrayObject>())
return SetLengthProperty(cx, obj, newlength);
return true;
@ -2154,42 +2099,46 @@ js::array_pop(JSContext* cx, unsigned argc, Value* vp)
return SetLengthProperty(cx, obj, index);
}
template <JSValueType Type>
static inline DenseElementResult
ShiftMoveBoxedOrUnboxedDenseElements(JSObject* obj)
void
js::ArrayShiftMoveElements(NativeObject* obj)
{
MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<Type>(obj));
MOZ_ASSERT_IF(obj->is<ArrayObject>(), obj->as<ArrayObject>().lengthIsWritable());
size_t initlen = obj->getDenseInitializedLength();
MOZ_ASSERT(initlen > 0);
/*
* At this point the length and initialized length have already been
* decremented and the result fetched, so just shift the array elements
* themselves.
*/
size_t initlen = GetBoxedOrUnboxedInitializedLength<Type>(obj);
if (Type == JSVAL_TYPE_MAGIC) {
obj->as<NativeObject>().moveDenseElementsNoPreBarrier(0, 1, initlen);
} else {
uint8_t* data = obj->as<UnboxedArrayObject>().elements();
size_t elementSize = UnboxedTypeSize(Type);
memmove(data, data + elementSize, initlen * elementSize);
}
obj->moveDenseElementsNoPreBarrier(0, 1, initlen);
}
static inline void
SetInitializedLength(JSContext* cx, NativeObject* obj, size_t initlen)
{
size_t oldInitlen = obj->getDenseInitializedLength();
obj->setDenseInitializedLength(initlen);
if (initlen < oldInitlen)
obj->shrinkElements(cx, initlen);
}
static DenseElementResult
MoveDenseElements(JSContext* cx, NativeObject* obj, uint32_t dstStart, uint32_t srcStart,
uint32_t length)
{
if (obj->denseElementsAreFrozen())
return DenseElementResult::Incomplete;
if (!obj->maybeCopyElementsForWrite(cx))
return DenseElementResult::Failure;
obj->moveDenseElements(dstStart, srcStart, length);
return DenseElementResult::Success;
}
DefineBoxedOrUnboxedFunctor1(ShiftMoveBoxedOrUnboxedDenseElements, JSObject*);
void
js::ArrayShiftMoveElements(JSObject* obj)
{
MOZ_ASSERT_IF(obj->is<ArrayObject>(), obj->as<ArrayObject>().lengthIsWritable());
ShiftMoveBoxedOrUnboxedDenseElementsFunctor functor(obj);
JS_ALWAYS_TRUE(CallBoxedOrUnboxedSpecialization(functor, obj) == DenseElementResult::Success);
}
template <JSValueType Type>
DenseElementResult
static DenseElementResult
ArrayShiftDenseKernel(JSContext* cx, HandleObject obj, MutableHandleValue rval)
{
if (ObjectMayHaveExtraIndexedProperties(obj))
@ -2202,25 +2151,22 @@ ArrayShiftDenseKernel(JSContext* cx, HandleObject obj, MutableHandleValue rval)
if (MOZ_UNLIKELY(group->hasAllFlags(OBJECT_FLAG_ITERATED)))
return DenseElementResult::Incomplete;
size_t initlen = GetBoxedOrUnboxedInitializedLength<Type>(obj);
size_t initlen = obj->as<NativeObject>().getDenseInitializedLength();
if (initlen == 0)
return DenseElementResult::Incomplete;
rval.set(GetBoxedOrUnboxedDenseElement<Type>(obj, 0));
rval.set(obj->as<NativeObject>().getDenseElement(0));
if (rval.isMagic(JS_ELEMENTS_HOLE))
rval.setUndefined();
DenseElementResult result = MoveBoxedOrUnboxedDenseElements<Type>(cx, obj, 0, 1, initlen - 1);
DenseElementResult result = MoveDenseElements(cx, &obj->as<NativeObject>(), 0, 1, initlen - 1);
if (result != DenseElementResult::Success)
return result;
SetBoxedOrUnboxedInitializedLength<Type>(cx, obj, initlen - 1);
SetInitializedLength(cx, obj.as<NativeObject>(), initlen - 1);
return DenseElementResult::Success;
}
DefineBoxedOrUnboxedFunctor3(ArrayShiftDenseKernel,
JSContext*, HandleObject, MutableHandleValue);
/* ES5 15.4.4.9 */
bool
js::array_shift(JSContext* cx, unsigned argc, Value* vp)
@ -2252,8 +2198,7 @@ js::array_shift(JSContext* cx, unsigned argc, Value* vp)
uint32_t newlen = len - 1;
/* Fast paths. */
ArrayShiftDenseKernelFunctor functor(cx, obj, args.rval());
DenseElementResult result = CallBoxedOrUnboxedSpecialization(functor, obj);
DenseElementResult result = ArrayShiftDenseKernel(cx, obj, args.rval());
if (result != DenseElementResult::Incomplete) {
if (result == DenseElementResult::Failure)
return false;
@ -2307,9 +2252,6 @@ js::array_unshift(JSContext* cx, unsigned argc, Value* vp)
if (args.length() > 0) {
/* Slide up the array to make room for all args at the bottom. */
if (length > 0) {
// Only include a fast path for boxed arrays. Unboxed arrays can'nt
// be optimized here because unshifting temporarily places holes at
// the start of the array.
bool optimized = false;
do {
if (!obj->is<ArrayObject>())
@ -2369,10 +2311,10 @@ js::array_unshift(JSContext* cx, unsigned argc, Value* vp)
}
/*
* Returns true if this is a dense or unboxed array whose |count| properties
* starting from |startingIndex| may be accessed (get, set, delete) directly
* through its contiguous vector of elements without fear of getters, setters,
* etc. along the prototype chain, or of enumerators requiring notification of
* Returns true if this is a dense array whose properties ending at |endIndex|
* (exclusive) may be accessed (get, set, delete) directly through its
* contiguous vector of elements without fear of getters, setters, etc. along
* the prototype chain, or of enumerators requiring notification of
* modifications.
*/
static inline bool
@ -2383,11 +2325,11 @@ CanOptimizeForDenseStorage(HandleObject arr, uint32_t startingIndex, uint32_t co
return false;
/* There's no optimizing possible if it's not an array. */
if (!arr->is<ArrayObject>() && !arr->is<UnboxedArrayObject>())
if (!arr->is<ArrayObject>())
return false;
/* If it's a frozen array, always pick the slow path */
if (arr->is<ArrayObject>() && arr->as<ArrayObject>().denseElementsAreFrozen())
if (arr->as<ArrayObject>().denseElementsAreFrozen())
return false;
/*
@ -2419,7 +2361,23 @@ CanOptimizeForDenseStorage(HandleObject arr, uint32_t startingIndex, uint32_t co
* is subsumed by the initializedLength comparison.)
*/
return !ObjectMayHaveExtraIndexedProperties(arr) &&
startingIndex + count <= GetAnyBoxedOrUnboxedInitializedLength(arr);
startingIndex + count <= arr->as<NativeObject>().getDenseInitializedLength();
}
static inline DenseElementResult
CopyDenseElements(JSContext* cx, NativeObject* dst, NativeObject* src,
uint32_t dstStart, uint32_t srcStart, uint32_t length)
{
MOZ_ASSERT(dst->getDenseInitializedLength() == dstStart);
MOZ_ASSERT(src->getDenseInitializedLength() >= srcStart + length);
MOZ_ASSERT(dst->getDenseCapacity() >= dstStart + length);
dst->setDenseInitializedLength(dstStart + length);
const Value* vp = src->getDenseElements() + srcStart;
dst->initDenseElements(dstStart, vp, length);
return DenseElementResult::Success;
}
/* ES 2016 draft Mar 25, 2016 22.1.3.26. */
@ -2520,7 +2478,9 @@ js::array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueI
/* Steps 10-11. */
DebugOnly<DenseElementResult> result =
CopyAnyBoxedOrUnboxedDenseElements(cx, arr, obj, 0, actualStart, actualDeleteCount);
CopyDenseElements(cx, &arr->as<NativeObject>(),
&obj->as<NativeObject>(), 0,
actualStart, actualDeleteCount);
MOZ_ASSERT(result.value == DenseElementResult::Success);
/* Step 12 (implicit). */
@ -2557,14 +2517,13 @@ js::array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueI
if (CanOptimizeForDenseStorage(obj, 0, len, cx)) {
/* Steps 15.a-b. */
DenseElementResult result =
MoveAnyBoxedOrUnboxedDenseElements(cx, obj, targetIndex, sourceIndex,
len - sourceIndex);
MoveDenseElements(cx, &obj->as<NativeObject>(), targetIndex, sourceIndex, len - sourceIndex);
MOZ_ASSERT(result != DenseElementResult::Incomplete);
if (result == DenseElementResult::Failure)
return false;
/* Steps 15.c-d. */
SetAnyBoxedOrUnboxedInitializedLength(cx, obj, finalLength);
SetInitializedLength(cx, obj.as<NativeObject>(), finalLength);
} else {
/*
* This is all very slow if the length is very large. We don't yet
@ -2644,15 +2603,15 @@ js::array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueI
if (CanOptimizeForDenseStorage(obj, len, itemCount - actualDeleteCount, cx)) {
DenseElementResult result =
MoveAnyBoxedOrUnboxedDenseElements(cx, obj, actualStart + itemCount,
actualStart + actualDeleteCount,
len - (actualStart + actualDeleteCount));
MoveDenseElements(cx, &obj->as<NativeObject>(), actualStart + itemCount,
actualStart + actualDeleteCount,
len - (actualStart + actualDeleteCount));
MOZ_ASSERT(result != DenseElementResult::Incomplete);
if (result == DenseElementResult::Failure)
return false;
/* Steps 16.a-b. */
SetAnyBoxedOrUnboxedInitializedLength(cx, obj, len + itemCount - actualDeleteCount);
SetInitializedLength(cx, obj.as<NativeObject>(), len + itemCount - actualDeleteCount);
} else {
RootedValue fromValue(cx);
for (double k = len - actualDeleteCount; k > actualStart; k--) {
@ -2824,7 +2783,7 @@ SliceSlowly(JSContext* cx, HandleObject obj, HandleObject receiver,
}
static bool
SliceSparse(JSContext* cx, HandleObject obj, uint32_t begin, uint32_t end, HandleObject result)
SliceSparse(JSContext* cx, HandleObject obj, uint32_t begin, uint32_t end, HandleArrayObject result)
{
MOZ_ASSERT(begin <= end);
@ -2874,26 +2833,28 @@ ArraySliceOrdinary(JSContext* cx, HandleObject obj, uint32_t length, uint32_t be
begin = end;
if (!ObjectMayHaveExtraIndexedProperties(obj)) {
size_t initlen = GetAnyBoxedOrUnboxedInitializedLength(obj);
size_t initlen = obj->as<NativeObject>().getDenseInitializedLength();
size_t count = 0;
if (initlen > begin)
count = Min<size_t>(initlen - begin, end - begin);
RootedObject narr(cx, NewFullyAllocatedArrayTryReuseGroup(cx, obj, count));
RootedArrayObject narr(cx, NewFullyAllocatedArrayTryReuseGroup(cx, obj, count));
if (!narr)
return false;
SetAnyBoxedOrUnboxedArrayLength(cx, narr, end - begin);
MOZ_ASSERT(count >= narr->as<ArrayObject>().length());
narr->as<ArrayObject>().setLength(cx, count);
if (count) {
DebugOnly<DenseElementResult> result =
CopyAnyBoxedOrUnboxedDenseElements(cx, narr, obj, 0, begin, count);
CopyDenseElements(cx, &narr->as<NativeObject>(), &obj->as<NativeObject>(), 0, begin, count);
MOZ_ASSERT(result.value == DenseElementResult::Success);
}
arr.set(narr);
return true;
}
RootedObject narr(cx, NewPartlyAllocatedArrayTryReuseGroup(cx, obj, end - begin));
RootedArrayObject narr(cx, NewPartlyAllocatedArrayTryReuseGroup(cx, obj, end - begin));
if (!narr)
return false;
@ -3010,11 +2971,10 @@ js::array_slice(JSContext* cx, unsigned argc, Value* vp)
return true;
}
template <JSValueType Type>
DenseElementResult
ArraySliceDenseKernel(JSContext* cx, JSObject* obj, int32_t beginArg, int32_t endArg, JSObject* result)
static bool
ArraySliceDenseKernel(JSContext* cx, ArrayObject* arr, int32_t beginArg, int32_t endArg, ArrayObject* result)
{
int32_t length = GetAnyBoxedOrUnboxedArrayLength(obj);
int32_t length = arr->length();
uint32_t begin = NormalizeSliceTerm(beginArg, length);
uint32_t end = NormalizeSliceTerm(endArg, length);
@ -3022,33 +2982,33 @@ ArraySliceDenseKernel(JSContext* cx, JSObject* obj, int32_t beginArg, int32_t en
if (begin > end)
begin = end;
size_t initlen = GetBoxedOrUnboxedInitializedLength<Type>(obj);
size_t initlen = arr->getDenseInitializedLength();
size_t count = Min<size_t>(initlen - begin, end - begin);
if (initlen > begin) {
size_t count = Min<size_t>(initlen - begin, end - begin);
if (count) {
DenseElementResult rv = EnsureBoxedOrUnboxedDenseElements<Type>(cx, result, count);
if (rv != DenseElementResult::Success)
return rv;
CopyBoxedOrUnboxedDenseElements<Type, Type>(cx, result, obj, 0, begin, count);
if (!result->ensureElements(cx, count))
return false;
CopyDenseElements(cx, &result->as<NativeObject>(), &arr->as<NativeObject>(), 0, begin, count);
}
}
SetAnyBoxedOrUnboxedArrayLength(cx, result, end - begin);
return DenseElementResult::Success;
}
MOZ_ASSERT(count >= result->length());
result->setLength(cx, count);
DefineBoxedOrUnboxedFunctor5(ArraySliceDenseKernel,
JSContext*, JSObject*, int32_t, int32_t, JSObject*);
return true;
}
JSObject*
js::array_slice_dense(JSContext* cx, HandleObject obj, int32_t begin, int32_t end,
HandleObject result)
{
if (result && IsArraySpecies(cx, obj)) {
ArraySliceDenseKernelFunctor functor(cx, obj, begin, end, result);
DenseElementResult rv = CallBoxedOrUnboxedSpecialization(functor, result);
MOZ_ASSERT(rv != DenseElementResult::Incomplete);
return rv == DenseElementResult::Success ? result : nullptr;
if (!ArraySliceDenseKernel(cx, &obj->as<ArrayObject>(), begin, end,
&result->as<ArrayObject>()))
{
return nullptr;
}
return result;
}
// Slower path if the JIT wasn't able to allocate an object inline.
@ -3079,7 +3039,7 @@ array_isArray(JSContext* cx, unsigned argc, Value* vp)
static bool
ArrayFromCallArgs(JSContext* cx, CallArgs& args, HandleObject proto = nullptr)
{
JSObject* obj = NewCopiedArrayForCallingAllocationSite(cx, args.array(), args.length(), proto);
ArrayObject* obj = NewCopiedArrayForCallingAllocationSite(cx, args.array(), args.length(), proto);
if (!obj)
return false;
@ -3244,7 +3204,7 @@ ArrayConstructorImpl(JSContext* cx, CallArgs& args, bool isConstructor)
}
}
JSObject* obj = NewPartlyAllocatedArrayForCallingAllocationSite(cx, length, proto);
ArrayObject* obj = NewPartlyAllocatedArrayForCallingAllocationSite(cx, length, proto);
if (!obj)
return false;
@ -3270,7 +3230,7 @@ js::array_construct(JSContext* cx, unsigned argc, Value* vp)
return ArrayConstructorImpl(cx, args, /* isConstructor = */ false);
}
JSObject*
ArrayObject*
js::ArrayConstructorOneArg(JSContext* cx, HandleObjectGroup group, int32_t lengthInt)
{
if (lengthInt < 0) {
@ -3565,7 +3525,7 @@ js::NewDenseFullyAllocatedArrayWithTemplate(JSContext* cx, uint32_t length, JSOb
return arr;
}
JSObject*
ArrayObject*
js::NewDenseCopyOnWriteArray(JSContext* cx, HandleArrayObject templateObject, gc::InitialHeap heap)
{
MOZ_ASSERT(!gc::IsInsideNursery(templateObject));
@ -3578,30 +3538,21 @@ js::NewDenseCopyOnWriteArray(JSContext* cx, HandleArrayObject templateObject, gc
return arr;
}
// Return a new boxed or unboxed array with the specified length and allocated
// capacity (up to maxLength), using the specified group if possible. If the
// specified group cannot be used, ensure that the created array at least has
// the given [[Prototype]].
// Return a new array with the specified length and allocated capacity (up to
// maxLength), using the specified group if possible. If the specified group
// cannot be used, ensure that the created array at least has the given
// [[Prototype]].
template <uint32_t maxLength>
static inline JSObject*
static inline ArrayObject*
NewArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length,
NewObjectKind newKind = GenericObject)
{
MOZ_ASSERT(newKind != SingletonObject);
if (group->maybePreliminaryObjects())
group->maybePreliminaryObjects()->maybeAnalyze(cx, group);
if (group->shouldPreTenure() || group->maybePreliminaryObjects())
if (group->shouldPreTenure())
newKind = TenuredObject;
RootedObject proto(cx, group->proto().toObject());
if (group->maybeUnboxedLayout()) {
if (length > UnboxedArrayObject::MaximumCapacity)
return NewArray<maxLength>(cx, length, proto, newKind);
return UnboxedArrayObject::create(cx, group, length, newKind, maxLength);
}
ArrayObject* res = NewArray<maxLength>(cx, length, proto, newKind);
if (!res)
return nullptr;
@ -3613,20 +3564,17 @@ NewArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length
if (res->length() > INT32_MAX)
res->setLength(cx, res->length());
if (PreliminaryObjectArray* preliminaryObjects = group->maybePreliminaryObjects())
preliminaryObjects->registerNewObject(res);
return res;
}
JSObject*
ArrayObject*
js::NewFullyAllocatedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length,
NewObjectKind newKind)
{
return NewArrayTryUseGroup<UINT32_MAX>(cx, group, length, newKind);
}
JSObject*
ArrayObject*
js::NewPartlyAllocatedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length)
{
return NewArrayTryUseGroup<ArrayObject::EagerAllocationMaxLength>(cx, group, length);
@ -3635,16 +3583,13 @@ js::NewPartlyAllocatedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup g
// Return a new array with the default prototype and specified allocated
// capacity and length. If possible, try to reuse the group of the input
// object. The resulting array will either reuse the input object's group or
// will have unknown property types. Additionally, the result will have the
// same boxed/unboxed elements representation as the input object, unless
// |length| is larger than the input object's initialized length (in which case
// UnboxedArrayObject::MaximumCapacity might be exceeded).
// will have unknown property types.
template <uint32_t maxLength>
static inline JSObject*
static inline ArrayObject*
NewArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length,
NewObjectKind newKind = GenericObject)
{
if (!obj->is<ArrayObject>() && !obj->is<UnboxedArrayObject>())
if (!obj->is<ArrayObject>())
return NewArray<maxLength>(cx, length, nullptr, newKind);
if (obj->staticPrototype() != cx->global()->maybeGetArrayPrototype())
@ -3657,20 +3602,20 @@ NewArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length,
return NewArrayTryUseGroup<maxLength>(cx, group, length, newKind);
}
JSObject*
ArrayObject*
js::NewFullyAllocatedArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length,
NewObjectKind newKind)
{
return NewArrayTryReuseGroup<UINT32_MAX>(cx, obj, length, newKind);
}
JSObject*
ArrayObject*
js::NewPartlyAllocatedArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length)
{
return NewArrayTryReuseGroup<ArrayObject::EagerAllocationMaxLength>(cx, obj, length);
}
JSObject*
ArrayObject*
js::NewFullyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length,
NewObjectKind newKind)
{
@ -3680,7 +3625,7 @@ js::NewFullyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length,
return NewArrayTryUseGroup<UINT32_MAX>(cx, group, length, newKind);
}
JSObject*
ArrayObject*
js::NewPartlyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length, HandleObject proto)
{
RootedObjectGroup group(cx, ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Array, proto));
@ -3689,68 +3634,23 @@ js::NewPartlyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length
return NewArrayTryUseGroup<ArrayObject::EagerAllocationMaxLength>(cx, group, length);
}
bool
js::MaybeAnalyzeBeforeCreatingLargeArray(ExclusiveContext* cx, HandleObjectGroup group,
const Value* vp, size_t length)
{
static const size_t EagerPreliminaryObjectAnalysisThreshold = 800;
// Force analysis to see if an unboxed array can be used when making a
// sufficiently large array, to avoid excessive analysis and copying later
// on. If this is the first array of its group that is being created, first
// make a dummy array with the initial elements of the array we are about
// to make, so there is some basis for the unboxed array analysis.
if (length > EagerPreliminaryObjectAnalysisThreshold) {
if (PreliminaryObjectArrayWithTemplate* objects = group->maybePreliminaryObjects()) {
if (objects->empty()) {
size_t nlength = Min<size_t>(length, 100);
JSObject* obj = NewFullyAllocatedArrayTryUseGroup(cx, group, nlength);
if (!obj)
return false;
DebugOnly<DenseElementResult> result =
SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, 0, vp, nlength,
ShouldUpdateTypes::Update);
MOZ_ASSERT(result.value == DenseElementResult::Success);
}
objects->maybeAnalyze(cx, group, /* forceAnalyze = */ true);
}
}
return true;
}
JSObject*
ArrayObject*
js::NewCopiedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group,
const Value* vp, size_t length, NewObjectKind newKind,
ShouldUpdateTypes updateTypes)
{
if (!MaybeAnalyzeBeforeCreatingLargeArray(cx, group, vp, length))
return nullptr;
JSObject* obj = NewFullyAllocatedArrayTryUseGroup(cx, group, length, newKind);
ArrayObject* obj = NewFullyAllocatedArrayTryUseGroup(cx, group, length, newKind);
if (!obj)
return nullptr;
DenseElementResult result =
SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, 0, vp, length, updateTypes);
DenseElementResult result = obj->setOrExtendDenseElements(cx->asJSContext(), 0, vp, length, updateTypes);
if (result == DenseElementResult::Failure)
return nullptr;
if (result == DenseElementResult::Success)
return obj;
MOZ_ASSERT(obj->is<UnboxedArrayObject>());
if (!UnboxedArrayObject::convertToNative(cx->asJSContext(), obj))
return nullptr;
result = SetOrExtendBoxedOrUnboxedDenseElements<JSVAL_TYPE_MAGIC>(cx, obj, 0, vp, length,
updateTypes);
MOZ_ASSERT(result != DenseElementResult::Incomplete);
if (result == DenseElementResult::Failure)
return nullptr;
MOZ_ASSERT(result == DenseElementResult::Success);
return obj;
}
JSObject*
ArrayObject*
js::NewCopiedArrayForCallingAllocationSite(JSContext* cx, const Value* vp, size_t length,
HandleObject proto /* = nullptr */)
{

View File

@ -72,49 +72,37 @@ extern ArrayObject*
NewDenseFullyAllocatedArrayWithTemplate(JSContext* cx, uint32_t length, JSObject* templateObject);
/* Create a dense array with the same copy-on-write elements as another object. */
extern JSObject*
extern ArrayObject*
NewDenseCopyOnWriteArray(JSContext* cx, HandleArrayObject templateObject, gc::InitialHeap heap);
// The methods below can create either boxed or unboxed arrays.
extern JSObject*
extern ArrayObject*
NewFullyAllocatedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length,
NewObjectKind newKind = GenericObject);
extern JSObject*
extern ArrayObject*
NewPartlyAllocatedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length);
extern JSObject*
extern ArrayObject*
NewFullyAllocatedArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length,
NewObjectKind newKind = GenericObject);
extern JSObject*
extern ArrayObject*
NewPartlyAllocatedArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length);
extern JSObject*
extern ArrayObject*
NewFullyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length,
NewObjectKind newKind = GenericObject);
extern JSObject*
extern ArrayObject*
NewPartlyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length, HandleObject proto);
enum class ShouldUpdateTypes
{
Update,
DontUpdate
};
extern bool
MaybeAnalyzeBeforeCreatingLargeArray(ExclusiveContext* cx, HandleObjectGroup group,
const Value* vp, size_t length);
extern JSObject*
extern ArrayObject*
NewCopiedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group,
const Value* vp, size_t length,
NewObjectKind newKind = GenericObject,
ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update);
extern JSObject*
extern ArrayObject*
NewCopiedArrayForCallingAllocationSite(JSContext* cx, const Value* vp, size_t length,
HandleObject proto = nullptr);
@ -129,13 +117,6 @@ NewValuePair(JSContext* cx, const Value& val1, const Value& val2, MutableHandleV
extern bool
WouldDefinePastNonwritableLength(HandleNativeObject obj, uint32_t index);
/*
* Canonicalize |vp| to a uint32_t value potentially suitable for use as an
* array length.
*/
extern bool
CanonicalizeArrayLengthValue(JSContext* cx, HandleValue v, uint32_t* canonicalized);
extern bool
GetLengthProperty(JSContext* cx, HandleObject obj, uint32_t* lengthp);
@ -172,7 +153,7 @@ extern bool
array_join(JSContext* cx, unsigned argc, js::Value* vp);
extern void
ArrayShiftMoveElements(JSObject* obj);
ArrayShiftMoveElements(NativeObject* obj);
extern bool
array_shift(JSContext* cx, unsigned argc, js::Value* vp);
@ -202,7 +183,7 @@ array_splice(JSContext* cx, unsigned argc, js::Value* vp);
extern bool
NewbornArrayPush(JSContext* cx, HandleObject obj, const Value& v);
extern JSObject*
extern ArrayObject*
ArrayConstructorOneArg(JSContext* cx, HandleObjectGroup group, int32_t lengthInt);
#ifdef DEBUG

View File

@ -112,13 +112,6 @@ JSCompartment::~JSCompartment()
js_delete(nonSyntacticLexicalEnvironments_),
js_free(enumerators);
#ifdef DEBUG
// Avoid assertion destroying the unboxed layouts list if the embedding
// leaked GC things.
if (!rt->gc.shutdownCollectedEverything())
unboxedLayouts.clear();
#endif
runtime_->numCompartments--;
}

View File

@ -529,9 +529,6 @@ struct JSCompartment
// table manages references from such typed objects to their buffers.
js::ObjectWeakMap* lazyArrayBuffers;
// All unboxed layouts in the compartment.
mozilla::LinkedList<js::UnboxedLayout> unboxedLayouts;
// WebAssembly state for the compartment.
js::wasm::Compartment wasm;

View File

@ -269,9 +269,9 @@ js::GetBuiltinClass(JSContext* cx, HandleObject obj, ESClass* cls)
if (MOZ_UNLIKELY(obj->is<ProxyObject>()))
return Proxy::getBuiltinClass(cx, obj, cls);
if (obj->is<PlainObject>() || obj->is<UnboxedPlainObject>())
if (obj->is<PlainObject>())
*cls = ESClass::Object;
else if (obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>())
else if (obj->is<ArrayObject>())
*cls = ESClass::Array;
else if (obj->is<NumberObject>())
*cls = ESClass::Number;

View File

@ -6190,12 +6190,6 @@ gc::MergeCompartments(JSCompartment* source, JSCompartment* target)
for (auto group = source->zone()->cellIter<ObjectGroup>(); !group.done(); group.next()) {
group->setGeneration(target->zone()->types.generation);
group->compartment_ = target;
// Remove any unboxed layouts from the list in the off thread
// compartment. These do not need to be reinserted in the target
// compartment's list, as the list is not required to be complete.
if (UnboxedLayout* layout = group->maybeUnboxedLayoutDontCheckGeneration())
layout->detachFromCompartment();
}
// Fixup zone pointers in source's zone to refer to target's zone.

View File

@ -157,8 +157,11 @@ SortComparatorIntegerIds(jsid a, jsid b, bool* lessOrEqualp)
}
static bool
EnumerateNativeProperties(JSContext* cx, HandleNativeObject pobj, unsigned flags, Maybe<IdSet>& ht,
AutoIdVector* props, Handle<UnboxedPlainObject*> unboxed = nullptr)
EnumerateNativeProperties(JSContext* cx,
HandleNativeObject pobj,
unsigned flags,
Maybe<IdSet>& ht,
AutoIdVector* props)
{
bool enumerateSymbols;
if (flags & JSITER_SYMBOLSONLY) {
@ -220,16 +223,6 @@ EnumerateNativeProperties(JSContext* cx, HandleNativeObject pobj, unsigned flags
return false;
}
if (unboxed) {
// If |unboxed| is set then |pobj| is the expando for an unboxed
// plain object we are enumerating. Add the unboxed properties
// themselves here since they are all property names that were
// given to the object before any of the expando's properties.
MOZ_ASSERT(pobj->is<UnboxedExpandoObject>());
if (!EnumerateExtraProperties(cx, unboxed, flags, ht, props))
return false;
}
size_t initialLength = props->length();
/* Collect all unique property names from this object's shape. */
@ -355,22 +348,12 @@ Snapshot(JSContext* cx, HandleObject pobj_, unsigned flags, AutoIdVector* props)
do {
if (pobj->getOpsEnumerate()) {
if (pobj->is<UnboxedPlainObject>() && pobj->as<UnboxedPlainObject>().maybeExpando()) {
// Special case unboxed objects with an expando object.
RootedNativeObject expando(cx, pobj->as<UnboxedPlainObject>().maybeExpando());
if (!EnumerateNativeProperties(cx, expando, flags, ht, props,
pobj.as<UnboxedPlainObject>()))
{
return false;
}
} else {
if (!EnumerateExtraProperties(cx, pobj, flags, ht, props))
return false;
if (!EnumerateExtraProperties(cx, pobj, flags, ht, props))
return false;
if (pobj->isNative()) {
if (!EnumerateNativeProperties(cx, pobj.as<NativeObject>(), flags, ht, props))
return false;
}
if (pobj->isNative()) {
if (!EnumerateNativeProperties(cx, pobj.as<NativeObject>(), flags, ht, props))
return false;
}
} else if (pobj->isNative()) {
// Give the object a chance to resolve all lazy properties
@ -785,11 +768,6 @@ CanCompareIterableObjectToCache(JSObject* obj)
{
if (obj->isNative())
return obj->as<NativeObject>().hasEmptyElements();
if (obj->is<UnboxedPlainObject>()) {
if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando())
return expando->hasEmptyElements();
return true;
}
return false;
}

View File

@ -43,6 +43,7 @@
#include "frontend/BytecodeCompiler.h"
#include "gc/Marking.h"
#include "gc/Policy.h"
#include "gc/StoreBuffer-inl.h"
#include "jit/BaselineJIT.h"
#include "js/MemoryMetrics.h"
#include "js/Proxy.h"
@ -869,9 +870,6 @@ static inline JSObject*
CreateThisForFunctionWithGroup(JSContext* cx, HandleObjectGroup group,
NewObjectKind newKind)
{
if (group->maybeUnboxedLayout() && newKind != SingletonObject)
return UnboxedPlainObject::create(cx, group, newKind);
if (TypeNewScript* newScript = group->newScript()) {
if (newScript->analyzed()) {
// The definite properties analysis has been performed for this
@ -1145,19 +1143,18 @@ js::CloneObject(JSContext* cx, HandleObject obj, Handle<js::TaggedProto> proto)
}
static bool
GetScriptArrayObjectElements(JSContext* cx, HandleObject obj, MutableHandle<GCVector<Value>> values)
GetScriptArrayObjectElements(JSContext* cx, HandleArrayObject arr, MutableHandle<GCVector<Value>> values)
{
MOZ_ASSERT(!obj->isSingleton());
MOZ_ASSERT(obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>());
MOZ_ASSERT(!obj->isIndexed());
MOZ_ASSERT(!arr->isSingleton());
MOZ_ASSERT(!arr->isIndexed());
size_t length = GetAnyBoxedOrUnboxedArrayLength(obj);
size_t length = arr->length();
if (!values.appendN(MagicValue(JS_ELEMENTS_HOLE), length))
return false;
size_t initlen = GetAnyBoxedOrUnboxedInitializedLength(obj);
size_t initlen = arr->getDenseInitializedLength();
for (size_t i = 0; i < initlen; i++)
values[i].set(GetAnyBoxedOrUnboxedDenseElement(obj, i));
values[i].set(arr->getDenseElement(i));
return true;
}
@ -1166,46 +1163,27 @@ static bool
GetScriptPlainObjectProperties(JSContext* cx, HandleObject obj,
MutableHandle<IdValueVector> properties)
{
if (obj->is<PlainObject>()) {
PlainObject* nobj = &obj->as<PlainObject>();
MOZ_ASSERT(obj->is<PlainObject>());
PlainObject* nobj = &obj->as<PlainObject>();
if (!properties.appendN(IdValuePair(), nobj->slotSpan()))
return false;
if (!properties.appendN(IdValuePair(), nobj->slotSpan()))
return false;
for (Shape::Range<NoGC> r(nobj->lastProperty()); !r.empty(); r.popFront()) {
Shape& shape = r.front();
MOZ_ASSERT(shape.isDataDescriptor());
uint32_t slot = shape.slot();
properties[slot].get().id = shape.propid();
properties[slot].get().value = nobj->getSlot(slot);
}
for (size_t i = 0; i < nobj->getDenseInitializedLength(); i++) {
Value v = nobj->getDenseElement(i);
if (!v.isMagic(JS_ELEMENTS_HOLE) && !properties.append(IdValuePair(INT_TO_JSID(i), v)))
return false;
}
return true;
for (Shape::Range<NoGC> r(nobj->lastProperty()); !r.empty(); r.popFront()) {
Shape& shape = r.front();
MOZ_ASSERT(shape.isDataDescriptor());
uint32_t slot = shape.slot();
properties[slot].get().id = shape.propid();
properties[slot].get().value = nobj->getSlot(slot);
}
if (obj->is<UnboxedPlainObject>()) {
UnboxedPlainObject* nobj = &obj->as<UnboxedPlainObject>();
const UnboxedLayout& layout = nobj->layout();
if (!properties.appendN(IdValuePair(), layout.properties().length()))
for (size_t i = 0; i < nobj->getDenseInitializedLength(); i++) {
Value v = nobj->getDenseElement(i);
if (!v.isMagic(JS_ELEMENTS_HOLE) && !properties.append(IdValuePair(INT_TO_JSID(i), v)))
return false;
for (size_t i = 0; i < layout.properties().length(); i++) {
const UnboxedLayout::Property& property = layout.properties()[i];
properties[i].get().id = NameToId(property.name);
properties[i].get().value = nobj->getValue(property);
}
return true;
}
MOZ_CRASH("Bad object kind");
return true;
}
static bool
@ -1227,13 +1205,13 @@ js::DeepCloneObjectLiteral(JSContext* cx, HandleObject obj, NewObjectKind newKin
/* NB: Keep this in sync with XDRObjectLiteral. */
MOZ_ASSERT_IF(obj->isSingleton(),
cx->compartment()->behaviors().getSingletonsAsTemplates());
MOZ_ASSERT(obj->is<PlainObject>() || obj->is<UnboxedPlainObject>() ||
obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>());
MOZ_ASSERT(obj->is<PlainObject>() ||
obj->is<ArrayObject>());
MOZ_ASSERT(newKind != SingletonObject);
if (obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()) {
if (obj->is<ArrayObject>()) {
Rooted<GCVector<Value>> values(cx, GCVector<Value>(cx));
if (!GetScriptArrayObjectElements(cx, obj, &values))
if (!GetScriptArrayObjectElements(cx, obj.as<ArrayObject>(), &values))
return nullptr;
// Deep clone any elements.
@ -1347,10 +1325,8 @@ js::XDRObjectLiteral(XDRState<mode>* xdr, MutableHandleObject obj)
{
if (mode == XDR_ENCODE) {
MOZ_ASSERT(obj->is<PlainObject>() ||
obj->is<UnboxedPlainObject>() ||
obj->is<ArrayObject>() ||
obj->is<UnboxedArrayObject>());
isArray = (obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()) ? 1 : 0;
obj->is<ArrayObject>());
isArray = obj->is<ArrayObject>() ? 1 : 0;
}
if (!xdr->codeUint32(&isArray))
@ -1362,8 +1338,11 @@ js::XDRObjectLiteral(XDRState<mode>* xdr, MutableHandleObject obj)
if (isArray) {
Rooted<GCVector<Value>> values(cx, GCVector<Value>(cx));
if (mode == XDR_ENCODE && !GetScriptArrayObjectElements(cx, obj, &values))
return false;
if (mode == XDR_ENCODE) {
RootedArrayObject arr(cx, &obj->as<ArrayObject>());
if (!GetScriptArrayObjectElements(cx, arr, &values))
return false;
}
uint32_t initialized;
if (mode == XDR_ENCODE)
@ -2333,16 +2312,6 @@ js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Shape**
// us the resolve hook won't define a property with this id.
if (ClassMayResolveId(cx->names(), obj->getClass(), id, obj))
return false;
} else if (obj->is<UnboxedPlainObject>()) {
if (obj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx, id)) {
MarkNonNativePropertyFound<NoGC>(propp);
return true;
}
} else if (obj->is<UnboxedArrayObject>()) {
if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) {
MarkNonNativePropertyFound<NoGC>(propp);
return true;
}
} else if (obj->is<TypedObject>()) {
if (obj->as<TypedObject>().typeDescr().hasProperty(cx->names(), id)) {
MarkNonNativePropertyFound<NoGC>(propp);
@ -2590,11 +2559,6 @@ js::SetPrototype(JSContext* cx, HandleObject obj, HandleObject proto, JS::Object
break;
}
// Convert unboxed objects to their native representations before changing
// their prototype/group, as they depend on the group for their layout.
if (!MaybeConvertUnboxedObjectToNative(cx, obj))
return false;
Rooted<TaggedProto> taggedProto(cx, TaggedProto(proto));
if (!SetClassAndProto(cx, obj, obj->getClass(), taggedProto))
return false;
@ -2618,9 +2582,6 @@ js::PreventExtensions(JSContext* cx, HandleObject obj, ObjectOpResult& result, I
if (!obj->nonProxyIsExtensible())
return result.succeed();
if (!MaybeConvertUnboxedObjectToNative(cx, obj))
return false;
// Force lazy properties to be resolved.
AutoIdVector props(cx);
if (!js::GetPropertyKeys(cx, obj, JSITER_HIDDEN | JSITER_OWNONLY, &props))
@ -3714,22 +3675,6 @@ JSObject::allocKindForTenure(const js::Nursery& nursery) const
if (IsProxy(this))
return as<ProxyObject>().allocKindForTenure();
// Unboxed plain objects are sized according to the data they store.
if (is<UnboxedPlainObject>()) {
size_t nbytes = as<UnboxedPlainObject>().layoutDontCheckGeneration().size();
return GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() + nbytes);
}
// Unboxed arrays use inline data if their size is small enough.
if (is<UnboxedArrayObject>()) {
const UnboxedArrayObject* nobj = &as<UnboxedArrayObject>();
size_t nbytes = UnboxedArrayObject::offsetOfInlineElements() +
nobj->capacity() * nobj->elementSize();
if (nbytes <= JSObject::MAX_BYTE_SIZE)
return GetGCObjectKindForBytes(nbytes);
return AllocKind::OBJECT0;
}
// Inlined typed objects are followed by their data, so make sure we copy
// it all over to the new object.
if (is<InlineTypedObject>()) {

View File

@ -32,21 +32,6 @@
#include "vm/ShapedObject-inl.h"
#include "vm/TypeInference-inl.h"
namespace js {
// This is needed here for ensureShape() below.
inline bool
MaybeConvertUnboxedObjectToNative(ExclusiveContext* cx, JSObject* obj)
{
if (obj->is<UnboxedPlainObject>())
return UnboxedPlainObject::convertToNative(cx->asJSContext(), obj);
if (obj->is<UnboxedArrayObject>())
return UnboxedArrayObject::convertToNative(cx->asJSContext(), obj);
return true;
}
} // namespace js
inline js::Shape*
JSObject::maybeShape() const
{
@ -59,8 +44,6 @@ JSObject::maybeShape() const
inline js::Shape*
JSObject::ensureShape(js::ExclusiveContext* cx)
{
if (!js::MaybeConvertUnboxedObjectToNative(cx, this))
return nullptr;
js::Shape* shape = maybeShape();
MOZ_ASSERT(shape);
return shape;

View File

@ -2369,7 +2369,7 @@ js::str_replace_string_raw(JSContext* cx, HandleString string, HandleString patt
}
// ES 2016 draft Mar 25, 2016 21.1.3.17 steps 4, 8, 12-18.
static JSObject*
static ArrayObject*
SplitHelper(JSContext* cx, HandleLinearString str, uint32_t limit, HandleLinearString sep,
HandleObjectGroup group)
{
@ -2466,7 +2466,7 @@ SplitHelper(JSContext* cx, HandleLinearString str, uint32_t limit, HandleLinearS
}
// Fast-path for splitting a string into a character array via split("").
static JSObject*
static ArrayObject*
CharSplitHelper(JSContext* cx, HandleLinearString str, uint32_t limit, HandleObjectGroup group)
{
size_t strLength = str->length();
@ -2491,7 +2491,7 @@ CharSplitHelper(JSContext* cx, HandleLinearString str, uint32_t limit, HandleObj
}
// ES 2016 draft Mar 25, 2016 21.1.3.17 steps 4, 8, 12-18.
JSObject*
ArrayObject*
js::str_split_string(JSContext* cx, HandleObjectGroup group, HandleString str, HandleString sep, uint32_t limit)
{

View File

@ -465,7 +465,7 @@ FileEscapedString(FILE* fp, const char* chars, size_t length, uint32_t quote)
return res;
}
JSObject*
ArrayObject*
str_split_string(JSContext* cx, HandleObjectGroup group, HandleString str, HandleString sep,
uint32_t limit);

View File

@ -355,7 +355,6 @@ UNIFIED_SOURCES += [
'vm/UbiNode.cpp',
'vm/UbiNodeCensus.cpp',
'vm/UbiNodeShortestPaths.cpp',
'vm/UnboxedObject.cpp',
'vm/Unicode.cpp',
'vm/Value.cpp',
'vm/WeakMapPtr.cpp',

View File

@ -320,7 +320,6 @@ static bool enableIon = false;
static bool enableAsmJS = false;
static bool enableWasm = false;
static bool enableNativeRegExp = false;
static bool enableUnboxedArrays = false;
static bool enableSharedMemory = SHARED_MEMORY_DEFAULT;
static bool enableWasmAlwaysBaseline = false;
static bool enableArrayProtoValues = true;
@ -7260,7 +7259,6 @@ SetContextOptions(JSContext* cx, const OptionParser& op)
enableAsmJS = !op.getBoolOption("no-asmjs");
enableWasm = !op.getBoolOption("no-wasm");
enableNativeRegExp = !op.getBoolOption("no-native-regexp");
enableUnboxedArrays = op.getBoolOption("unboxed-arrays");
enableWasmAlwaysBaseline = op.getBoolOption("wasm-always-baseline");
enableArrayProtoValues = !op.getBoolOption("no-array-proto-values");
@ -7270,15 +7268,11 @@ SetContextOptions(JSContext* cx, const OptionParser& op)
.setWasm(enableWasm)
.setWasmAlwaysBaseline(enableWasmAlwaysBaseline)
.setNativeRegExp(enableNativeRegExp)
.setUnboxedArrays(enableUnboxedArrays)
.setArrayProtoValues(enableArrayProtoValues);
if (op.getBoolOption("wasm-check-bce"))
jit::JitOptions.wasmAlwaysCheckBounds = true;
if (op.getBoolOption("no-unboxed-objects"))
jit::JitOptions.disableUnboxedObjects = true;
if (const char* str = op.getStringOption("cache-ir-stubs")) {
if (strcmp(str, "on") == 0)
jit::JitOptions.disableCacheIR = false;
@ -7542,7 +7536,6 @@ SetWorkerContextOptions(JSContext* cx)
.setWasm(enableWasm)
.setWasmAlwaysBaseline(enableWasmAlwaysBaseline)
.setNativeRegExp(enableNativeRegExp)
.setUnboxedArrays(enableUnboxedArrays)
.setArrayProtoValues(enableArrayProtoValues);
cx->setOffthreadIonCompilationEnabled(offthreadCompilation);
cx->profilingScripts = enableCodeCoverage || enableDisassemblyDumps;
@ -7712,8 +7705,6 @@ main(int argc, char** argv, char** envp)
|| !op.addBoolOption('\0', "no-asmjs", "Disable asm.js compilation")
|| !op.addBoolOption('\0', "no-wasm", "Disable WebAssembly compilation")
|| !op.addBoolOption('\0', "no-native-regexp", "Disable native regexp compilation")
|| !op.addBoolOption('\0', "no-unboxed-objects", "Disable creating unboxed plain objects")
|| !op.addBoolOption('\0', "unboxed-arrays", "Allow creating unboxed arrays")
|| !op.addBoolOption('\0', "wasm-always-baseline", "Enable wasm baseline compiler when possible")
|| !op.addBoolOption('\0', "wasm-check-bce", "Always generate wasm bounds check, even redundant ones.")
|| !op.addBoolOption('\0', "no-array-proto-values", "Remove Array.prototype.values")

View File

@ -22,7 +22,6 @@
#include "vm/EnvironmentObject-inl.h"
#include "vm/Stack-inl.h"
#include "vm/String-inl.h"
#include "vm/UnboxedObject-inl.h"
namespace js {
@ -337,14 +336,10 @@ InitGlobalLexicalOperation(JSContext* cx, LexicalEnvironmentObject* lexicalEnvAr
inline bool
InitPropertyOperation(JSContext* cx, JSOp op, HandleObject obj, HandleId id, HandleValue rhs)
{
if (obj->is<PlainObject>() || obj->is<JSFunction>()) {
unsigned propAttrs = GetInitDataPropAttrs(op);
return NativeDefineProperty(cx, obj.as<NativeObject>(), id, rhs, nullptr, nullptr,
propAttrs);
}
MOZ_ASSERT(obj->as<UnboxedPlainObject>().layout().lookup(id));
return PutProperty(cx, obj, id, rhs, false);
MOZ_ASSERT(obj->is<PlainObject>() || obj->is<JSFunction>());
unsigned propAttrs = GetInitDataPropAttrs(op);
return NativeDefineProperty(cx, obj.as<NativeObject>(), id, rhs,
nullptr, nullptr, propAttrs);
}
inline bool
@ -598,7 +593,7 @@ InitArrayElemOperation(JSContext* cx, jsbytecode* pc, HandleObject obj, uint32_t
JSOp op = JSOp(*pc);
MOZ_ASSERT(op == JSOP_INITELEM_ARRAY || op == JSOP_INITELEM_INC);
MOZ_ASSERT(obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>());
MOZ_ASSERT(obj->is<ArrayObject>());
if (op == JSOP_INITELEM_INC && index == INT32_MAX) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SPREAD_TOO_LARGE);

View File

@ -1916,6 +1916,7 @@ CASE(EnableInterruptsPseudoOpcode)
/* Various 1-byte no-ops. */
CASE(JSOP_NOP)
CASE(JSOP_NOP_DESTRUCTURING)
CASE(JSOP_UNUSED126)
CASE(JSOP_UNUSED192)
CASE(JSOP_UNUSED209)
CASE(JSOP_UNUSED210)
@ -3636,7 +3637,6 @@ CASE(JSOP_NEWINIT)
END_CASE(JSOP_NEWINIT)
CASE(JSOP_NEWARRAY)
CASE(JSOP_SPREADCALLARRAY)
{
uint32_t length = GET_UINT32(REGS.pc);
JSObject* obj = NewArrayOperation(cx, script, REGS.pc, length);
@ -4111,7 +4111,7 @@ CASE(JSOP_INITHOMEOBJECT)
/* Load the home object */
ReservedRooted<JSObject*> obj(&rootObject0);
obj = &REGS.sp[int(-2 - skipOver)].toObject();
MOZ_ASSERT(obj->is<PlainObject>() || obj->is<UnboxedPlainObject>() || obj->is<JSFunction>());
MOZ_ASSERT(obj->is<PlainObject>() || obj->is<JSFunction>());
func->setExtendedSlot(FunctionExtended::METHOD_HOMEOBJECT_SLOT, ObjectValue(*obj));
}
@ -4927,18 +4927,13 @@ js::NewObjectOperation(JSContext* cx, HandleScript script, jsbytecode* pc,
return nullptr;
if (group->maybePreliminaryObjects()) {
group->maybePreliminaryObjects()->maybeAnalyze(cx, group);
if (group->maybeUnboxedLayout())
group->maybeUnboxedLayout()->setAllocationSite(script, pc);
}
if (group->shouldPreTenure() || group->maybePreliminaryObjects())
newKind = TenuredObject;
if (group->maybeUnboxedLayout())
return UnboxedPlainObject::create(cx, group, newKind);
}
RootedObject obj(cx);
RootedPlainObject obj(cx);
if (*pc == JSOP_NEWOBJECT) {
RootedPlainObject baseObject(cx, &script->getObject(pc)->as<PlainObject>());
@ -4975,11 +4970,6 @@ js::NewObjectOperationWithTemplate(JSContext* cx, HandleObject templateObject)
NewObjectKind newKind = templateObject->group()->shouldPreTenure() ? TenuredObject : GenericObject;
if (templateObject->group()->maybeUnboxedLayout()) {
RootedObjectGroup group(cx, templateObject->group());
return UnboxedPlainObject::create(cx, group, newKind);
}
JSObject* obj = CopyInitializerObject(cx, templateObject.as<PlainObject>(), newKind);
if (!obj)
return nullptr;
@ -5006,9 +4996,6 @@ js::NewArrayOperation(JSContext* cx, HandleScript script, jsbytecode* pc, uint32
if (group->shouldPreTenure() || group->maybePreliminaryObjects())
newKind = TenuredObject;
if (group->maybeUnboxedLayout())
return UnboxedArrayObject::create(cx, group, length, newKind);
}
ArrayObject* obj = NewDenseFullyAllocatedArray(cx, length, nullptr, newKind);
@ -5019,9 +5006,6 @@ js::NewArrayOperation(JSContext* cx, HandleScript script, jsbytecode* pc, uint32
MOZ_ASSERT(obj->isSingleton());
} else {
obj->setGroup(group);
if (PreliminaryObjectArray* preliminaryObjects = group->maybePreliminaryObjects())
preliminaryObjects->registerNewObject(obj);
}
return obj;
@ -5034,12 +5018,6 @@ js::NewArrayOperationWithTemplate(JSContext* cx, HandleObject templateObject)
NewObjectKind newKind = templateObject->group()->shouldPreTenure() ? TenuredObject : GenericObject;
if (templateObject->is<UnboxedArrayObject>()) {
uint32_t length = templateObject->as<UnboxedArrayObject>().length();
RootedObjectGroup group(cx, templateObject->group());
return UnboxedArrayObject::create(cx, group, length, newKind);
}
ArrayObject* obj = NewDenseFullyAllocatedArray(cx, templateObject->as<ArrayObject>().length(),
nullptr, newKind);
if (!obj)

View File

@ -606,8 +606,8 @@ JSONParserBase::finishArray(MutableHandleValue vp, ElementVector& elements)
{
MOZ_ASSERT(&elements == &stack.back().elements());
JSObject* obj = ObjectGroup::newArrayObject(cx, elements.begin(), elements.length(),
GenericObject);
ArrayObject* obj = ObjectGroup::newArrayObject(cx, elements.begin(), elements.length(),
GenericObject);
if (!obj)
return false;

View File

@ -235,6 +235,38 @@ NativeObject::ensureDenseElements(ExclusiveContext* cx, uint32_t index, uint32_t
return DenseElementResult::Success;
}
inline DenseElementResult
NativeObject::setOrExtendDenseElements(JSContext* cx, uint32_t start, const Value* vp,
uint32_t count,
ShouldUpdateTypes updateTypes)
{
if (denseElementsAreFrozen())
return DenseElementResult::Incomplete;
if (is<ArrayObject>() &&
!as<ArrayObject>().lengthIsWritable() &&
start + count >= as<ArrayObject>().length())
{
return DenseElementResult::Incomplete;
}
DenseElementResult result = ensureDenseElements(cx, start, count);
if (result != DenseElementResult::Success)
return result;
if (is<ArrayObject>() && start + count >= as<ArrayObject>().length())
as<ArrayObject>().setLengthInt32(start + count);
if (updateTypes == ShouldUpdateTypes::DontUpdate && !shouldConvertDoubleElements()) {
copyDenseElements(start, vp, count);
} else {
for (size_t i = 0; i < count; i++)
setDenseElementWithType(cx, start + i, vp[i]);
}
return DenseElementResult::Success;
}
inline Value
NativeObject::getDenseOrTypedArrayElement(uint32_t idx)
{

View File

@ -390,33 +390,6 @@ NativeObject::setLastPropertyMakeNonNative(Shape* shape)
shape_ = shape;
}
void
NativeObject::setLastPropertyMakeNative(ExclusiveContext* cx, Shape* shape)
{
MOZ_ASSERT(getClass()->isNative());
MOZ_ASSERT(shape->getObjectClass()->isNative());
MOZ_ASSERT(!shape->inDictionary());
// This method is used to convert unboxed objects into native objects. In
// this case, the shape_ field was previously used to store other data and
// this should be treated as an initialization.
shape_.init(shape);
slots_ = nullptr;
elements_ = emptyObjectElements;
size_t oldSpan = shape->numFixedSlots();
size_t newSpan = shape->slotSpan();
initializeSlotRange(0, oldSpan);
// A failure at this point will leave the object as a mutant, and we
// can't recover.
AutoEnterOOMUnsafeRegion oomUnsafe;
if (oldSpan != newSpan && !updateSlotsForSpan(cx, oldSpan, newSpan))
oomUnsafe.crash("NativeObject::setLastPropertyMakeNative");
}
bool
NativeObject::setSlotSpan(ExclusiveContext* cx, uint32_t span)
{

View File

@ -339,16 +339,19 @@ IsObjectValueInCompartment(const Value& v, JSCompartment* comp);
#endif
// Operations which change an object's dense elements can either succeed, fail,
// or be unable to complete. For native objects, the latter is used when the
// object's elements must become sparse instead. The enum below is used for
// such operations, and for similar operations on unboxed arrays and methods
// that work on both kinds of objects.
// or be unable to complete. The latter is used when the object's elements must
// become sparse instead. The enum below is used for such operations.
enum class DenseElementResult {
Failure,
Success,
Incomplete
};
enum class ShouldUpdateTypes {
Update,
DontUpdate
};
/*
* NativeObject specifies the internal implementation of a native object.
*
@ -467,11 +470,6 @@ class NativeObject : public ShapedObject
// that are (temporarily) inconsistent.
void setLastPropertyMakeNonNative(Shape* shape);
// As for setLastProperty(), but changes the class associated with the
// object to a native one. The object's type has already been changed, and
// this brings the shape into sync with it.
void setLastPropertyMakeNative(ExclusiveContext* cx, Shape* shape);
// Newly-created TypedArrays that map a SharedArrayBuffer are
// marked as shared by giving them an ObjectElements that has the
// ObjectElements::SHARED_MEMORY flag set.
@ -1147,6 +1145,10 @@ class NativeObject : public ShapedObject
elementsRangeWriteBarrierPost(dstStart, count);
}
inline DenseElementResult
setOrExtendDenseElements(JSContext* cx, uint32_t start, const Value* vp, uint32_t count,
ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update);
bool shouldConvertDoubleElements() {
return getElementsHeader()->shouldConvertDoubleElements();
}

View File

@ -108,20 +108,6 @@ ObjectGroup::maybePreliminaryObjects()
return maybePreliminaryObjectsDontCheckGeneration();
}
inline UnboxedLayout*
ObjectGroup::maybeUnboxedLayout()
{
maybeSweep(nullptr);
return maybeUnboxedLayoutDontCheckGeneration();
}
inline UnboxedLayout&
ObjectGroup::unboxedLayout()
{
maybeSweep(nullptr);
return unboxedLayoutDontCheckGeneration();
}
} // namespace js
#endif /* vm_ObjectGroup_inl_h */

View File

@ -18,11 +18,10 @@
#include "vm/ArrayObject.h"
#include "vm/Shape.h"
#include "vm/TaggedProto.h"
#include "vm/UnboxedObject.h"
#include "jsobjinlines.h"
#include "vm/UnboxedObject-inl.h"
#include "vm/NativeObject-inl.h"
using namespace js;
@ -56,7 +55,6 @@ ObjectGroup::finalize(FreeOp* fop)
if (newScriptDontCheckGeneration())
newScriptDontCheckGeneration()->clear();
fop->delete_(newScriptDontCheckGeneration());
fop->delete_(maybeUnboxedLayoutDontCheckGeneration());
if (maybePreliminaryObjectsDontCheckGeneration())
maybePreliminaryObjectsDontCheckGeneration()->clear();
fop->delete_(maybePreliminaryObjectsDontCheckGeneration());
@ -83,8 +81,6 @@ ObjectGroup::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
size_t n = 0;
if (TypeNewScript* newScript = newScriptDontCheckGeneration())
n += newScript->sizeOfIncludingThis(mallocSizeOf);
if (UnboxedLayout* layout = maybeUnboxedLayoutDontCheckGeneration())
n += layout->sizeOfIncludingThis(mallocSizeOf);
return n;
}
@ -530,8 +526,7 @@ ObjectGroup::defaultNewGroup(ExclusiveContext* cx, const Class* clasp,
if (p) {
ObjectGroup* group = p->group;
MOZ_ASSERT_IF(clasp, group->clasp() == clasp);
MOZ_ASSERT_IF(!clasp, group->clasp() == &PlainObject::class_ ||
group->clasp() == &UnboxedPlainObject::class_);
MOZ_ASSERT_IF(!clasp, group->clasp() == &PlainObject::class_);
MOZ_ASSERT(group->proto() == proto);
return group;
}
@ -774,7 +769,7 @@ GetValueTypeForTable(const Value& v)
return type;
}
/* static */ JSObject*
/* static */ ArrayObject*
ObjectGroup::newArrayObject(ExclusiveContext* cx,
const Value* vp, size_t length,
NewObjectKind newKind, NewArrayKind arrayKind)
@ -838,56 +833,13 @@ ObjectGroup::newArrayObject(ExclusiveContext* cx,
AddTypePropertyId(cx, group, nullptr, JSID_VOID, elementType);
if (elementType != TypeSet::UnknownType()) {
// Keep track of the initial objects we create with this type.
// If the initial ones have a consistent shape and property types, we
// will try to use an unboxed layout for the group.
PreliminaryObjectArrayWithTemplate* preliminaryObjects =
cx->new_<PreliminaryObjectArrayWithTemplate>(nullptr);
if (!preliminaryObjects)
return nullptr;
group->setPreliminaryObjects(preliminaryObjects);
}
if (!p.add(cx, *table, ObjectGroupCompartment::ArrayObjectKey(elementType), group))
return nullptr;
}
// The type of the elements being added will already be reflected in type
// information, but make sure when creating an unboxed array that the
// common element type is suitable for the unboxed representation.
// information.
ShouldUpdateTypes updateTypes = ShouldUpdateTypes::DontUpdate;
if (!MaybeAnalyzeBeforeCreatingLargeArray(cx, group, vp, length))
return nullptr;
if (group->maybePreliminaryObjects())
group->maybePreliminaryObjects()->maybeAnalyze(cx, group);
if (group->maybeUnboxedLayout()) {
switch (group->unboxedLayout().elementType()) {
case JSVAL_TYPE_BOOLEAN:
if (elementType != TypeSet::BooleanType())
updateTypes = ShouldUpdateTypes::Update;
break;
case JSVAL_TYPE_INT32:
if (elementType != TypeSet::Int32Type())
updateTypes = ShouldUpdateTypes::Update;
break;
case JSVAL_TYPE_DOUBLE:
if (elementType != TypeSet::Int32Type() && elementType != TypeSet::DoubleType())
updateTypes = ShouldUpdateTypes::Update;
break;
case JSVAL_TYPE_STRING:
if (elementType != TypeSet::StringType())
updateTypes = ShouldUpdateTypes::Update;
break;
case JSVAL_TYPE_OBJECT:
if (elementType != TypeSet::NullType() && !elementType.get().isObjectUnchecked())
updateTypes = ShouldUpdateTypes::Update;
break;
default:
MOZ_CRASH();
}
}
return NewCopiedArrayTryUseGroup(cx, group, vp, length, newKind, updateTypes);
}
@ -897,49 +849,15 @@ GiveObjectGroup(ExclusiveContext* cx, JSObject* source, JSObject* target)
{
MOZ_ASSERT(source->group() != target->group());
if (!target->is<ArrayObject>() && !target->is<UnboxedArrayObject>())
return true;
if (target->group()->maybePreliminaryObjects()) {
bool force = IsInsideNursery(source);
target->group()->maybePreliminaryObjects()->maybeAnalyze(cx, target->group(), force);
}
if (target->is<ArrayObject>()) {
ObjectGroup* sourceGroup = source->group();
if (source->is<UnboxedArrayObject>()) {
Shape* shape = target->as<ArrayObject>().lastProperty();
if (!UnboxedArrayObject::convertToNativeWithGroup(cx, source, target->group(), shape))
return false;
} else if (source->is<ArrayObject>()) {
source->setGroup(target->group());
} else {
return true;
}
if (sourceGroup->maybePreliminaryObjects())
sourceGroup->maybePreliminaryObjects()->unregisterObject(source);
if (target->group()->maybePreliminaryObjects())
target->group()->maybePreliminaryObjects()->registerNewObject(source);
for (size_t i = 0; i < source->as<ArrayObject>().getDenseInitializedLength(); i++) {
Value v = source->as<ArrayObject>().getDenseElement(i);
AddTypePropertyId(cx, source->group(), source, JSID_VOID, v);
}
if (!target->is<ArrayObject>() || !source->is<ArrayObject>()) {
return true;
}
if (target->is<UnboxedArrayObject>()) {
if (!source->is<UnboxedArrayObject>())
return true;
if (source->as<UnboxedArrayObject>().elementType() != JSVAL_TYPE_INT32)
return true;
if (target->as<UnboxedArrayObject>().elementType() != JSVAL_TYPE_DOUBLE)
return true;
source->setGroup(target->group());
return source->as<UnboxedArrayObject>().convertInt32ToDouble(cx, target->group());
for (size_t i = 0; i < source->as<ArrayObject>().getDenseInitializedLength(); i++) {
Value v = source->as<ArrayObject>().getDenseElement(i);
AddTypePropertyId(cx, source->group(), source, JSID_VOID, v);
}
return true;
@ -1048,46 +966,6 @@ js::CombinePlainObjectPropertyTypes(ExclusiveContext* cx, JSObject* newObj,
}
}
}
} else if (newObj->is<UnboxedPlainObject>()) {
const UnboxedLayout& layout = newObj->as<UnboxedPlainObject>().layout();
const int32_t* traceList = layout.traceList();
if (!traceList)
return true;
uint8_t* newData = newObj->as<UnboxedPlainObject>().data();
uint8_t* oldData = oldObj->as<UnboxedPlainObject>().data();
for (; *traceList != -1; traceList++) {}
traceList++;
for (; *traceList != -1; traceList++) {
JSObject* newInnerObj = *reinterpret_cast<JSObject**>(newData + *traceList);
JSObject* oldInnerObj = *reinterpret_cast<JSObject**>(oldData + *traceList);
if (!newInnerObj || !oldInnerObj || SameGroup(oldInnerObj, newInnerObj))
continue;
if (!GiveObjectGroup(cx, newInnerObj, oldInnerObj))
return false;
if (SameGroup(oldInnerObj, newInnerObj))
continue;
if (!GiveObjectGroup(cx, oldInnerObj, newInnerObj))
return false;
if (SameGroup(oldInnerObj, newInnerObj)) {
for (size_t i = 1; i < ncompare; i++) {
if (compare[i].isObject() && SameGroup(&compare[i].toObject(), newObj)) {
uint8_t* otherData = compare[i].toObject().as<UnboxedPlainObject>().data();
JSObject* otherInnerObj = *reinterpret_cast<JSObject**>(otherData + *traceList);
if (otherInnerObj && !SameGroup(otherInnerObj, newInnerObj)) {
if (!GiveObjectGroup(cx, otherInnerObj, newInnerObj))
return false;
}
}
}
}
}
}
return true;
@ -1311,12 +1189,6 @@ ObjectGroup::newPlainObject(ExclusiveContext* cx, IdValuePair* properties, size_
RootedObjectGroup group(cx, p->value().group);
// Watch for existing groups which now use an unboxed layout.
if (group->maybeUnboxedLayout()) {
MOZ_ASSERT(group->unboxedLayout().properties().length() == nproperties);
return UnboxedPlainObject::createWithProperties(cx, group, newKind, properties);
}
// Update property types according to the properties we are about to add.
// Do this before we do anything which can GC, which might move or remove
// this table entry.
@ -1503,18 +1375,6 @@ ObjectGroup::allocationSiteGroup(JSContext* cx, JSScript* scriptArg, jsbytecode*
}
}
if (kind == JSProto_Array &&
(JSOp(*pc) == JSOP_NEWARRAY || IsCallPC(pc)) &&
cx->options().unboxedArrays())
{
PreliminaryObjectArrayWithTemplate* preliminaryObjects =
cx->new_<PreliminaryObjectArrayWithTemplate>(nullptr);
if (preliminaryObjects)
res->setPreliminaryObjects(preliminaryObjects);
else
cx->recoverFromOutOfMemory();
}
if (!table->add(p, key, res)) {
ReportOutOfMemory(cx);
return nullptr;

View File

@ -20,7 +20,6 @@
namespace js {
class TypeDescr;
class UnboxedLayout;
class PreliminaryObjectArrayWithTemplate;
class TypeNewScript;
@ -154,16 +153,6 @@ class ObjectGroup : public gc::TenuredCell
// For some plain objects, the addendum stores a PreliminaryObjectArrayWithTemplate.
Addendum_PreliminaryObjects,
// When objects in this group have an unboxed representation, the
// addendum stores an UnboxedLayout (which might have a TypeNewScript
// as well, if the group is also constructed using 'new').
Addendum_UnboxedLayout,
// If this group is used by objects that have been converted from an
// unboxed representation and/or have the same allocation kind as such
// objects, the addendum points to that unboxed group.
Addendum_OriginalUnboxedGroup,
// When used by typed objects, the addendum stores a TypeDescr.
Addendum_TypeDescr
};
@ -225,34 +214,6 @@ class ObjectGroup : public gc::TenuredCell
maybePreliminaryObjectsDontCheckGeneration();
}
inline UnboxedLayout* maybeUnboxedLayout();
inline UnboxedLayout& unboxedLayout();
UnboxedLayout* maybeUnboxedLayoutDontCheckGeneration() const {
if (addendumKind() == Addendum_UnboxedLayout)
return reinterpret_cast<UnboxedLayout*>(addendum_);
return nullptr;
}
UnboxedLayout& unboxedLayoutDontCheckGeneration() const {
MOZ_ASSERT(addendumKind() == Addendum_UnboxedLayout);
return *maybeUnboxedLayoutDontCheckGeneration();
}
void setUnboxedLayout(UnboxedLayout* layout) {
setAddendum(Addendum_UnboxedLayout, layout);
}
ObjectGroup* maybeOriginalUnboxedGroup() const {
if (addendumKind() == Addendum_OriginalUnboxedGroup)
return reinterpret_cast<ObjectGroup*>(addendum_);
return nullptr;
}
void setOriginalUnboxedGroup(ObjectGroup* group) {
setAddendum(Addendum_OriginalUnboxedGroup, group);
}
TypeDescr* maybeTypeDescr() {
// Note: there is no need to sweep when accessing the type descriptor
// of an object, as it is strongly held and immutable.
@ -313,9 +274,8 @@ class ObjectGroup : public gc::TenuredCell
* that can be read out of that property in actual JS objects. In native
* objects, property types account for plain data properties (those with a
* slot and no getter or setter hook) and dense elements. In typed objects
* and unboxed objects, property types account for object and value
* properties and elements in the object, and expando properties in unboxed
* objects.
* property types account for object and value properties and elements in
* the object.
*
* For accesses on these properties, the correspondence is as follows:
*
@ -338,10 +298,9 @@ class ObjectGroup : public gc::TenuredCell
* 2. Array lengths are special cased by the compiler and VM and are not
* reflected in property types.
*
* 3. In typed objects (but not unboxed objects), the initial values of
* properties (null pointers and undefined values) are not reflected in
* the property types. These values are always possible when reading the
* property.
* 3. In typed objects, the initial values of properties (null pointers and
* undefined values) are not reflected in the property types. These
* values are always possible when reading the property.
*
* We establish these by using write barriers on calls to setProperty and
* defineProperty which are on native properties, and on any jitcode which
@ -455,12 +414,6 @@ class ObjectGroup : public gc::TenuredCell
return &flags_;
}
// Get the bit pattern stored in an object's addendum when it has an
// original unboxed group.
static inline int32_t addendumOriginalUnboxedGroupValue() {
return Addendum_OriginalUnboxedGroup << OBJECT_FLAG_ADDENDUM_SHIFT;
}
inline uint32_t basePropertyCount();
private:
@ -505,14 +458,14 @@ class ObjectGroup : public gc::TenuredCell
UnknownIndex // Make an array with an unknown element type.
};
// Create an ArrayObject or UnboxedArrayObject with the specified elements
// and a group specialized for the elements.
static JSObject* newArrayObject(ExclusiveContext* cx, const Value* vp, size_t length,
NewObjectKind newKind,
NewArrayKind arrayKind = NewArrayKind::Normal);
// Create an ArrayObject with the specified elements and a group specialized
// for the elements.
static ArrayObject* newArrayObject(ExclusiveContext* cx, const Value* vp, size_t length,
NewObjectKind newKind,
NewArrayKind arrayKind = NewArrayKind::Normal);
// Create a PlainObject or UnboxedPlainObject with the specified properties
// and a group specialized for those properties.
// Create a PlainObject with the specified properties and a group specialized
// for those properties.
static JSObject* newPlainObject(ExclusiveContext* cx,
IdValuePair* properties, size_t nproperties,
NewObjectKind newKind);

View File

@ -1281,17 +1281,7 @@
* Stack: receiver, obj, propval => obj[propval]
*/ \
macro(JSOP_GETELEM_SUPER, 125, "getelem-super", NULL, 1, 3, 1, JOF_BYTE |JOF_ELEM|JOF_LEFTASSOC) \
/*
* Pushes newly created array for a spread call onto the stack. This has
* the same semantics as JSOP_NEWARRAY, but is distinguished to avoid
* using unboxed arrays in spread calls, which would make compiling spread
* calls in baseline more complex.
* Category: Literals
* Type: Array
* Operands: uint32_t length
* Stack: => obj
*/ \
macro(JSOP_SPREADCALLARRAY, 126, "spreadcallarray", NULL, 5, 0, 1, JOF_UINT32) \
macro(JSOP_UNUSED126, 126, "unused126", NULL, 5, 0, 1, JOF_UINT32) \
\
/*
* Defines the given function on the current scope.

View File

@ -7,7 +7,6 @@
#include "vm/ReceiverGuard.h"
#include "builtin/TypedObject.h"
#include "vm/UnboxedObject.h"
#include "jsobjinlines.h"
using namespace js;
@ -16,11 +15,7 @@ ReceiverGuard::ReceiverGuard(JSObject* obj)
: group(nullptr), shape(nullptr)
{
if (obj) {
if (obj->is<UnboxedPlainObject>()) {
group = obj->group();
if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando())
shape = expando->lastProperty();
} else if (obj->is<UnboxedArrayObject>() || obj->is<TypedObject>()) {
if (obj->is<TypedObject>()) {
group = obj->group();
} else {
shape = obj->maybeShape();
@ -33,9 +28,7 @@ ReceiverGuard::ReceiverGuard(ObjectGroup* group, Shape* shape)
{
if (group) {
const Class* clasp = group->clasp();
if (clasp == &UnboxedPlainObject::class_) {
// Keep both group and shape.
} else if (clasp == &UnboxedArrayObject::class_ || IsTypedObjectClass(clasp)) {
if (IsTypedObjectClass(clasp)) {
this->shape = nullptr;
} else {
this->group = nullptr;
@ -46,12 +39,8 @@ ReceiverGuard::ReceiverGuard(ObjectGroup* group, Shape* shape)
/* static */ int32_t
HeapReceiverGuard::keyBits(JSObject* obj)
{
if (obj->is<UnboxedPlainObject>()) {
// Both the group and shape need to be guarded for unboxed plain objects.
return obj->as<UnboxedPlainObject>().maybeExpando() ? 0 : 1;
}
if (obj->is<UnboxedArrayObject>() || obj->is<TypedObject>()) {
// Only the group needs to be guarded for unboxed arrays and typed objects.
if (obj->is<TypedObject>()) {
// Only the group needs to be guarded for typed objects.
return 2;
}
// Other objects only need the shape to be guarded.

View File

@ -28,11 +28,6 @@ namespace js {
// TypedObject: The structure of a typed object is determined by its group.
// All typed objects with the same group have the same class, prototype, and
// own properties.
//
// UnboxedPlainObject: The structure of an unboxed plain object is determined
// by its group and its expando object's shape, if there is one. All unboxed
// plain objects with the same group and expando shape have the same
// properties except those stored in the expando's dense elements.
class HeapReceiverGuard;
class RootedReceiverGuard;

View File

@ -82,7 +82,7 @@ InterpreterFrame::isNonGlobalEvalFrame() const
return isEvalFrame() && script()->bodyScope()->as<EvalScope>().isNonGlobal();
}
JSObject*
ArrayObject*
InterpreterFrame::createRestParameter(JSContext* cx)
{
MOZ_ASSERT(script()->hasRest());

View File

@ -523,7 +523,7 @@ class InterpreterFrame
ArgumentsObject& argsObj() const;
void initArgsObj(ArgumentsObject& argsobj);
JSObject* createRestParameter(JSContext* cx);
ArrayObject* createRestParameter(JSContext* cx);
/*
* Environment chain

View File

@ -23,7 +23,6 @@
#include "vm/SharedArrayObject.h"
#include "vm/StringObject.h"
#include "vm/TypedArrayObject.h"
#include "vm/UnboxedObject.h"
#include "jscntxtinlines.h"
@ -285,10 +284,6 @@ TypeIdString(jsid id)
*/
struct AutoEnterAnalysis
{
// For use when initializing an UnboxedLayout. The UniquePtr's destructor
// must run when GC is not suppressed.
UniquePtr<UnboxedLayout> unboxedLayoutToCleanUp;
// Prevent GC activity in the middle of analysis.
gc::AutoSuppressGC suppressGC;

View File

@ -35,7 +35,6 @@
#include "vm/Opcodes.h"
#include "vm/Shape.h"
#include "vm/Time.h"
#include "vm/UnboxedObject.h"
#include "jsatominlines.h"
#include "jsscriptinlines.h"
@ -297,9 +296,6 @@ js::ObjectGroupHasProperty(JSContext* cx, ObjectGroup* group, jsid id, const Val
return true;
}
}
JSObject* obj = &value.toObject();
if (!obj->hasLazyGroup() && obj->group()->maybeOriginalUnboxedGroup())
return true;
}
if (!types->hasType(type)) {
@ -1944,33 +1940,6 @@ class ConstraintDataFreezeObjectForTypedArrayData
}
};
// Constraint which triggers recompilation if an unboxed object in some group
// is converted to a native object.
class ConstraintDataFreezeObjectForUnboxedConvertedToNative
{
public:
ConstraintDataFreezeObjectForUnboxedConvertedToNative()
{}
const char* kind() { return "freezeObjectForUnboxedConvertedToNative"; }
bool invalidateOnNewType(TypeSet::Type type) { return false; }
bool invalidateOnNewPropertyState(TypeSet* property) { return false; }
bool invalidateOnNewObjectState(ObjectGroup* group) {
return group->unboxedLayout().nativeGroup() != nullptr;
}
bool constraintHolds(JSContext* cx,
const HeapTypeSetKey& property, TemporaryTypeSet* expected)
{
return !invalidateOnNewObjectState(property.object()->maybeGroup());
}
bool shouldSweep() { return false; }
JSCompartment* maybeCompartment() { return nullptr; }
};
} /* anonymous namespace */
void
@ -1995,17 +1964,6 @@ TypeSet::ObjectKey::watchStateChangeForTypedArrayData(CompilerConstraintList* co
ConstraintDataFreezeObjectForTypedArrayData(tarray)));
}
void
TypeSet::ObjectKey::watchStateChangeForUnboxedConvertedToNative(CompilerConstraintList* constraints)
{
HeapTypeSetKey objectProperty = property(JSID_EMPTY);
LifoAlloc* alloc = constraints->alloc();
typedef CompilerConstraintInstance<ConstraintDataFreezeObjectForUnboxedConvertedToNative> T;
constraints->add(alloc->new_<T>(alloc, objectProperty,
ConstraintDataFreezeObjectForUnboxedConvertedToNative()));
}
static void
ObjectStateChange(ExclusiveContext* cxArg, ObjectGroup* group, bool markingUnknown)
{
@ -2516,8 +2474,6 @@ TemporaryTypeSet::propertyNeedsBarrier(CompilerConstraintList* constraints, jsid
bool
js::ClassCanHaveExtraProperties(const Class* clasp)
{
if (clasp == &UnboxedPlainObject::class_ || clasp == &UnboxedArrayObject::class_)
return false;
return clasp->getResolve()
|| clasp->getOpsLookupProperty()
|| clasp->getOpsGetProperty()
@ -2816,15 +2772,6 @@ js::AddTypePropertyId(ExclusiveContext* cx, ObjectGroup* group, JSObject* obj, j
// from acquiring the fully initialized group.
if (group->newScript() && group->newScript()->initializedGroup())
AddTypePropertyId(cx, group->newScript()->initializedGroup(), nullptr, id, type);
// Maintain equivalent type information for unboxed object groups and their
// corresponding native group. Since type sets might contain the unboxed
// group but not the native group, this ensures optimizations based on the
// unboxed group are valid for the native group.
if (group->maybeUnboxedLayout() && group->maybeUnboxedLayout()->nativeGroup())
AddTypePropertyId(cx, group->maybeUnboxedLayout()->nativeGroup(), nullptr, id, type);
if (ObjectGroup* unboxedGroup = group->maybeOriginalUnboxedGroup())
AddTypePropertyId(cx, unboxedGroup, nullptr, id, type);
}
void
@ -2896,12 +2843,6 @@ ObjectGroup::setFlags(ExclusiveContext* cx, ObjectGroupFlags flags)
// acquired properties analysis.
if (newScript() && newScript()->initializedGroup())
newScript()->initializedGroup()->setFlags(cx, flags);
// Propagate flag changes between unboxed and corresponding native groups.
if (maybeUnboxedLayout() && maybeUnboxedLayout()->nativeGroup())
maybeUnboxedLayout()->nativeGroup()->setFlags(cx, flags);
if (ObjectGroup* unboxedGroup = maybeOriginalUnboxedGroup())
unboxedGroup->setFlags(cx, flags);
}
void
@ -2934,13 +2875,6 @@ ObjectGroup::markUnknown(ExclusiveContext* cx)
prop->types.setNonDataProperty(cx);
}
}
if (ObjectGroup* unboxedGroup = maybeOriginalUnboxedGroup())
MarkObjectGroupUnknownProperties(cx, unboxedGroup);
if (maybeUnboxedLayout() && maybeUnboxedLayout()->nativeGroup())
MarkObjectGroupUnknownProperties(cx, maybeUnboxedLayout()->nativeGroup());
if (ObjectGroup* unboxedGroup = maybeOriginalUnboxedGroup())
MarkObjectGroupUnknownProperties(cx, unboxedGroup);
}
TypeNewScript*
@ -2948,8 +2882,6 @@ ObjectGroup::anyNewScript()
{
if (newScript())
return newScript();
if (maybeUnboxedLayout())
return unboxedLayout().newScript();
return nullptr;
}
@ -2979,10 +2911,7 @@ ObjectGroup::detachNewScript(bool writeBarrier, ObjectGroup* replacement)
MOZ_ASSERT(!replacement);
}
if (this->newScript())
setAddendum(Addendum_None, nullptr, writeBarrier);
else
unboxedLayout().setNewScript(nullptr, writeBarrier);
setAddendum(Addendum_None, nullptr, writeBarrier);
}
void
@ -3404,7 +3333,7 @@ JSFunction::setTypeForScriptedFunction(ExclusiveContext* cx, HandleFunction fun,
/////////////////////////////////////////////////////////////////////
void
PreliminaryObjectArray::registerNewObject(JSObject* res)
PreliminaryObjectArray::registerNewObject(PlainObject* res)
{
// The preliminary object pointers are weak, and won't be swept properly
// during nursery collections, so the preliminary objects need to be
@ -3422,7 +3351,7 @@ PreliminaryObjectArray::registerNewObject(JSObject* res)
}
void
PreliminaryObjectArray::unregisterObject(JSObject* obj)
PreliminaryObjectArray::unregisterObject(PlainObject* obj)
{
for (size_t i = 0; i < COUNT; i++) {
if (objects[i] == obj) {
@ -3462,22 +3391,6 @@ PreliminaryObjectArray::sweep()
for (size_t i = 0; i < COUNT; i++) {
JSObject** ptr = &objects[i];
if (*ptr && IsAboutToBeFinalizedUnbarriered(ptr)) {
// Before we clear this reference, change the object's group to the
// Object.prototype group. This is done to ensure JSObject::finalize
// sees a NativeObject Class even if we change the current group's
// Class to one of the unboxed object classes in the meantime. If
// the compartment's global is dead, we don't do anything as the
// group's Class is not going to change in that case.
JSObject* obj = *ptr;
GlobalObject* global = obj->compartment()->unsafeUnbarrieredMaybeGlobal();
if (global && !obj->isSingleton()) {
JSObject* objectProto = GetBuiltinPrototypePure(global, JSProto_Object);
obj->setGroup(objectProto->groupRaw());
MOZ_ASSERT(obj->is<NativeObject>());
MOZ_ASSERT(obj->getClass() == objectProto->getClass());
MOZ_ASSERT(!obj->getClass()->hasFinalize());
}
*ptr = nullptr;
}
}
@ -3577,17 +3490,11 @@ PreliminaryObjectArrayWithTemplate::maybeAnalyze(ExclusiveContext* cx, ObjectGro
}
}
TryConvertToUnboxedLayout(cx, enter, shape(), group, preliminaryObjects);
if (group->maybeUnboxedLayout())
return;
if (shape()) {
// We weren't able to use an unboxed layout, but since the preliminary
// objects still reflect the template object's properties, and all
// objects in the future will be created with those properties, the
// properties can be marked as definite for objects in the group.
group->addDefiniteProperties(cx, shape());
}
// Since the preliminary objects still reflect the template object's
// properties, and all objects in the future will be created with those
// properties, the properties can be marked as definitive for objects in
// the group.
group->addDefiniteProperties(cx, shape());
}
/////////////////////////////////////////////////////////////////////
@ -3601,7 +3508,6 @@ TypeNewScript::make(JSContext* cx, ObjectGroup* group, JSFunction* fun)
{
MOZ_ASSERT(cx->zone()->types.activeAnalysis);
MOZ_ASSERT(!group->newScript());
MOZ_ASSERT(!group->maybeUnboxedLayout());
// rollbackPartiallyInitializedObjects expects function_ to be
// canonicalized.
@ -3861,34 +3767,9 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate,
PodCopy(initializerList, initializerVector.begin(), initializerVector.length());
}
// Try to use an unboxed representation for the group.
if (!TryConvertToUnboxedLayout(cx, enter, templateObject()->lastProperty(), group, preliminaryObjects))
return false;
js_delete(preliminaryObjects);
preliminaryObjects = nullptr;
if (group->maybeUnboxedLayout()) {
// An unboxed layout was constructed for the group, and this has already
// been hooked into it.
MOZ_ASSERT(group->unboxedLayout().newScript() == this);
destroyNewScript.group = nullptr;
// Clear out the template object, which is not used for TypeNewScripts
// with an unboxed layout. Currently it is a mutant object with a
// non-native group and native shape, so make it safe for GC by changing
// its group to the default for its prototype.
AutoEnterOOMUnsafeRegion oomUnsafe;
ObjectGroup* plainGroup = ObjectGroup::defaultNewGroup(cx, &PlainObject::class_,
group->proto());
if (!plainGroup)
oomUnsafe.crash("TypeNewScript::maybeAnalyze");
templateObject_->setGroup(plainGroup);
templateObject_ = nullptr;
return true;
}
if (prefixShape->slotSpan() == templateObject()->slotSpan()) {
// The definite properties analysis found exactly the properties that
// are held in common by the preliminary objects. No further analysis
@ -3984,12 +3865,6 @@ TypeNewScript::rollbackPartiallyInitializedObjects(JSContext* cx, ObjectGroup* g
continue;
}
if (thisv.toObject().is<UnboxedPlainObject>()) {
AutoEnterOOMUnsafeRegion oomUnsafe;
if (!UnboxedPlainObject::convertToNative(cx, &thisv.toObject()))
oomUnsafe.crash("rollbackPartiallyInitializedObjects");
}
// Found a matching frame.
RootedPlainObject obj(cx, &thisv.toObject().as<PlainObject>());
@ -4183,12 +4058,6 @@ ConstraintTypeSet::sweep(Zone* zone, AutoClearTypeInferenceStateOnOOM& oom)
// Object sets containing objects with unknown properties might
// not be complete. Mark the type set as unknown, which it will
// be treated as during Ion compilation.
//
// Note that we don't have to do this when the type set might
// be missing the native group corresponding to an unboxed
// object group. In this case, the native group points to the
// unboxed object group via its addendum, so as long as objects
// with either group exist, neither group will be finalized.
flags |= TYPE_FLAG_ANYOBJECT;
clearObjects();
objectCount = 0;
@ -4272,21 +4141,6 @@ ObjectGroup::sweep(AutoClearTypeInferenceStateOnOOM* oom)
Maybe<AutoClearTypeInferenceStateOnOOM> fallbackOOM;
EnsureHasAutoClearTypeInferenceStateOnOOM(oom, zone(), fallbackOOM);
if (maybeUnboxedLayout()) {
// Remove unboxed layouts that are about to be finalized from the
// compartment wide list while we are still on the main thread.
ObjectGroup* group = this;
if (IsAboutToBeFinalizedUnbarriered(&group))
unboxedLayout().detachFromCompartment();
if (unboxedLayout().newScript())
unboxedLayout().newScript()->sweep();
// Discard constructor code to avoid holding onto ExecutablePools.
if (zone()->isGCCompacting())
unboxedLayout().setConstructorCode(nullptr);
}
if (maybePreliminaryObjects())
maybePreliminaryObjects()->sweep();

View File

@ -262,7 +262,6 @@ class TypeSet
bool hasStableClassAndProto(CompilerConstraintList* constraints);
void watchStateChangeForInlinedCall(CompilerConstraintList* constraints);
void watchStateChangeForTypedArrayData(CompilerConstraintList* constraints);
void watchStateChangeForUnboxedConvertedToNative(CompilerConstraintList* constraints);
HeapTypeSetKey property(jsid id);
void ensureTrackedProperty(JSContext* cx, jsid id);
@ -815,8 +814,8 @@ class PreliminaryObjectArray
public:
PreliminaryObjectArray() = default;
void registerNewObject(JSObject* res);
void unregisterObject(JSObject* obj);
void registerNewObject(PlainObject* res);
void unregisterObject(PlainObject* obj);
JSObject* get(size_t i) const {
MOZ_ASSERT(i < COUNT);

View File

@ -1,840 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef vm_UnboxedObject_inl_h
#define vm_UnboxedObject_inl_h
#include "vm/UnboxedObject.h"
#include "gc/StoreBuffer-inl.h"
#include "vm/ArrayObject-inl.h"
#include "vm/NativeObject-inl.h"
namespace js {
static inline Value
GetUnboxedValue(uint8_t* p, JSValueType type, bool maybeUninitialized)
{
switch (type) {
case JSVAL_TYPE_BOOLEAN:
return BooleanValue(*p != 0);
case JSVAL_TYPE_INT32:
return Int32Value(*reinterpret_cast<int32_t*>(p));
case JSVAL_TYPE_DOUBLE: {
// During unboxed plain object creation, non-GC thing properties are
// left uninitialized. This is normally fine, since the properties will
// be filled in shortly, but if they are read before that happens we
// need to make sure that doubles are canonical.
double d = *reinterpret_cast<double*>(p);
if (maybeUninitialized)
return DoubleValue(JS::CanonicalizeNaN(d));
return DoubleValue(d);
}
case JSVAL_TYPE_STRING:
return StringValue(*reinterpret_cast<JSString**>(p));
case JSVAL_TYPE_OBJECT:
return ObjectOrNullValue(*reinterpret_cast<JSObject**>(p));
default:
MOZ_CRASH("Invalid type for unboxed value");
}
}
static inline void
SetUnboxedValueNoTypeChange(JSObject* unboxedObject,
uint8_t* p, JSValueType type, const Value& v,
bool preBarrier)
{
switch (type) {
case JSVAL_TYPE_BOOLEAN:
*p = v.toBoolean();
return;
case JSVAL_TYPE_INT32:
*reinterpret_cast<int32_t*>(p) = v.toInt32();
return;
case JSVAL_TYPE_DOUBLE:
*reinterpret_cast<double*>(p) = v.toNumber();
return;
case JSVAL_TYPE_STRING: {
MOZ_ASSERT(!IsInsideNursery(v.toString()));
JSString** np = reinterpret_cast<JSString**>(p);
if (preBarrier)
JSString::writeBarrierPre(*np);
*np = v.toString();
return;
}
case JSVAL_TYPE_OBJECT: {
JSObject** np = reinterpret_cast<JSObject**>(p);
// Manually trigger post barriers on the whole object. If we treat
// the pointer as a HeapPtrObject we will get confused later if the
// object is converted to its native representation.
JSObject* obj = v.toObjectOrNull();
if (IsInsideNursery(obj) && !IsInsideNursery(unboxedObject)) {
JSRuntime* rt = unboxedObject->runtimeFromMainThread();
rt->gc.storeBuffer.putWholeCell(unboxedObject);
}
if (preBarrier)
JSObject::writeBarrierPre(*np);
*np = obj;
return;
}
default:
MOZ_CRASH("Invalid type for unboxed value");
}
}
static inline bool
SetUnboxedValue(ExclusiveContext* cx, JSObject* unboxedObject, jsid id,
uint8_t* p, JSValueType type, const Value& v, bool preBarrier)
{
switch (type) {
case JSVAL_TYPE_BOOLEAN:
if (v.isBoolean()) {
*p = v.toBoolean();
return true;
}
return false;
case JSVAL_TYPE_INT32:
if (v.isInt32()) {
*reinterpret_cast<int32_t*>(p) = v.toInt32();
return true;
}
return false;
case JSVAL_TYPE_DOUBLE:
if (v.isNumber()) {
*reinterpret_cast<double*>(p) = v.toNumber();
return true;
}
return false;
case JSVAL_TYPE_STRING:
if (v.isString()) {
MOZ_ASSERT(!IsInsideNursery(v.toString()));
JSString** np = reinterpret_cast<JSString**>(p);
if (preBarrier)
JSString::writeBarrierPre(*np);
*np = v.toString();
return true;
}
return false;
case JSVAL_TYPE_OBJECT:
if (v.isObjectOrNull()) {
JSObject** np = reinterpret_cast<JSObject**>(p);
// Update property types when writing object properties. Types for
// other properties were captured when the unboxed layout was
// created.
AddTypePropertyId(cx, unboxedObject, id, v);
// As above, trigger post barriers on the whole object.
JSObject* obj = v.toObjectOrNull();
if (IsInsideNursery(v.toObjectOrNull()) && !IsInsideNursery(unboxedObject)) {
JSRuntime* rt = unboxedObject->runtimeFromMainThread();
rt->gc.storeBuffer.putWholeCell(unboxedObject);
}
if (preBarrier)
JSObject::writeBarrierPre(*np);
*np = obj;
return true;
}
return false;
default:
MOZ_CRASH("Invalid type for unboxed value");
}
}
/////////////////////////////////////////////////////////////////////
// UnboxedPlainObject
/////////////////////////////////////////////////////////////////////
inline const UnboxedLayout&
UnboxedPlainObject::layout() const
{
return group()->unboxedLayout();
}
/////////////////////////////////////////////////////////////////////
// UnboxedArrayObject
/////////////////////////////////////////////////////////////////////
inline const UnboxedLayout&
UnboxedArrayObject::layout() const
{
return group()->unboxedLayout();
}
inline void
UnboxedArrayObject::setLength(ExclusiveContext* cx, uint32_t length)
{
if (length > INT32_MAX) {
// Track objects with overflowing lengths in type information.
MarkObjectGroupFlags(cx, this, OBJECT_FLAG_LENGTH_OVERFLOW);
}
length_ = length;
}
inline void
UnboxedArrayObject::setInitializedLength(uint32_t initlen)
{
if (initlen < initializedLength()) {
switch (elementType()) {
case JSVAL_TYPE_STRING:
for (size_t i = initlen; i < initializedLength(); i++)
triggerPreBarrier<JSVAL_TYPE_STRING>(i);
break;
case JSVAL_TYPE_OBJECT:
for (size_t i = initlen; i < initializedLength(); i++)
triggerPreBarrier<JSVAL_TYPE_OBJECT>(i);
break;
default:
MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(elementType()));
}
}
setInitializedLengthNoBarrier(initlen);
}
template <JSValueType Type>
inline bool
UnboxedArrayObject::setElementSpecific(ExclusiveContext* cx, size_t index, const Value& v)
{
MOZ_ASSERT(index < initializedLength());
MOZ_ASSERT(Type == elementType());
uint8_t* p = elements() + index * UnboxedTypeSize(Type);
return SetUnboxedValue(cx, this, JSID_VOID, p, elementType(), v, /* preBarrier = */ true);
}
template <JSValueType Type>
inline void
UnboxedArrayObject::setElementNoTypeChangeSpecific(size_t index, const Value& v)
{
MOZ_ASSERT(index < initializedLength());
MOZ_ASSERT(Type == elementType());
uint8_t* p = elements() + index * UnboxedTypeSize(Type);
return SetUnboxedValueNoTypeChange(this, p, elementType(), v, /* preBarrier = */ true);
}
template <JSValueType Type>
inline bool
UnboxedArrayObject::initElementSpecific(ExclusiveContext* cx, size_t index, const Value& v)
{
MOZ_ASSERT(index < initializedLength());
MOZ_ASSERT(Type == elementType());
uint8_t* p = elements() + index * UnboxedTypeSize(Type);
return SetUnboxedValue(cx, this, JSID_VOID, p, elementType(), v, /* preBarrier = */ false);
}
template <JSValueType Type>
inline void
UnboxedArrayObject::initElementNoTypeChangeSpecific(size_t index, const Value& v)
{
MOZ_ASSERT(index < initializedLength());
MOZ_ASSERT(Type == elementType());
uint8_t* p = elements() + index * UnboxedTypeSize(Type);
return SetUnboxedValueNoTypeChange(this, p, elementType(), v, /* preBarrier = */ false);
}
template <JSValueType Type>
inline Value
UnboxedArrayObject::getElementSpecific(size_t index)
{
MOZ_ASSERT(index < initializedLength());
MOZ_ASSERT(Type == elementType());
uint8_t* p = elements() + index * UnboxedTypeSize(Type);
return GetUnboxedValue(p, Type, /* maybeUninitialized = */ false);
}
template <JSValueType Type>
inline void
UnboxedArrayObject::triggerPreBarrier(size_t index)
{
MOZ_ASSERT(UnboxedTypeNeedsPreBarrier(Type));
uint8_t* p = elements() + index * UnboxedTypeSize(Type);
switch (Type) {
case JSVAL_TYPE_STRING: {
JSString** np = reinterpret_cast<JSString**>(p);
JSString::writeBarrierPre(*np);
break;
}
case JSVAL_TYPE_OBJECT: {
JSObject** np = reinterpret_cast<JSObject**>(p);
JSObject::writeBarrierPre(*np);
break;
}
default:
MOZ_CRASH("Bad type");
}
}
/////////////////////////////////////////////////////////////////////
// Combined methods for NativeObject and UnboxedArrayObject accesses.
/////////////////////////////////////////////////////////////////////
static inline bool
HasAnyBoxedOrUnboxedDenseElements(JSObject* obj)
{
return obj->isNative() || obj->is<UnboxedArrayObject>();
}
static inline size_t
GetAnyBoxedOrUnboxedInitializedLength(JSObject* obj)
{
if (obj->isNative())
return obj->as<NativeObject>().getDenseInitializedLength();
if (obj->is<UnboxedArrayObject>())
return obj->as<UnboxedArrayObject>().initializedLength();
return 0;
}
static inline size_t
GetAnyBoxedOrUnboxedCapacity(JSObject* obj)
{
if (obj->isNative())
return obj->as<NativeObject>().getDenseCapacity();
if (obj->is<UnboxedArrayObject>())
return obj->as<UnboxedArrayObject>().capacity();
return 0;
}
static inline Value
GetAnyBoxedOrUnboxedDenseElement(JSObject* obj, size_t index)
{
if (obj->isNative())
return obj->as<NativeObject>().getDenseElement(index);
return obj->as<UnboxedArrayObject>().getElement(index);
}
static inline size_t
GetAnyBoxedOrUnboxedArrayLength(JSObject* obj)
{
if (obj->is<ArrayObject>())
return obj->as<ArrayObject>().length();
return obj->as<UnboxedArrayObject>().length();
}
static inline void
SetAnyBoxedOrUnboxedArrayLength(JSContext* cx, JSObject* obj, size_t length)
{
if (obj->is<ArrayObject>()) {
MOZ_ASSERT(length >= obj->as<ArrayObject>().length());
obj->as<ArrayObject>().setLength(cx, length);
} else {
MOZ_ASSERT(length >= obj->as<UnboxedArrayObject>().length());
obj->as<UnboxedArrayObject>().setLength(cx, length);
}
}
static inline bool
SetAnyBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const Value& value)
{
if (obj->isNative()) {
obj->as<NativeObject>().setDenseElementWithType(cx, index, value);
return true;
}
return obj->as<UnboxedArrayObject>().setElement(cx, index, value);
}
static inline bool
InitAnyBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const Value& value)
{
if (obj->isNative()) {
obj->as<NativeObject>().initDenseElementWithType(cx, index, value);
return true;
}
return obj->as<UnboxedArrayObject>().initElement(cx, index, value);
}
/////////////////////////////////////////////////////////////////////
// Template methods for NativeObject and UnboxedArrayObject accesses.
/////////////////////////////////////////////////////////////////////
static inline JSValueType
GetBoxedOrUnboxedType(JSObject* obj)
{
if (obj->isNative())
return JSVAL_TYPE_MAGIC;
return obj->as<UnboxedArrayObject>().elementType();
}
template <JSValueType Type>
static inline bool
HasBoxedOrUnboxedDenseElements(JSObject* obj)
{
if (Type == JSVAL_TYPE_MAGIC)
return obj->isNative();
return obj->is<UnboxedArrayObject>() && obj->as<UnboxedArrayObject>().elementType() == Type;
}
template <JSValueType Type>
static inline size_t
GetBoxedOrUnboxedInitializedLength(JSObject* obj)
{
if (Type == JSVAL_TYPE_MAGIC)
return obj->as<NativeObject>().getDenseInitializedLength();
return obj->as<UnboxedArrayObject>().initializedLength();
}
template <JSValueType Type>
static inline DenseElementResult
SetBoxedOrUnboxedInitializedLength(JSContext* cx, JSObject* obj, size_t initlen)
{
size_t oldInitlen = GetBoxedOrUnboxedInitializedLength<Type>(obj);
if (Type == JSVAL_TYPE_MAGIC) {
obj->as<NativeObject>().setDenseInitializedLength(initlen);
if (initlen < oldInitlen)
obj->as<NativeObject>().shrinkElements(cx, initlen);
} else {
obj->as<UnboxedArrayObject>().setInitializedLength(initlen);
if (initlen < oldInitlen)
obj->as<UnboxedArrayObject>().shrinkElements(cx, initlen);
}
return DenseElementResult::Success;
}
template <JSValueType Type>
static inline size_t
GetBoxedOrUnboxedCapacity(JSObject* obj)
{
if (Type == JSVAL_TYPE_MAGIC)
return obj->as<NativeObject>().getDenseCapacity();
return obj->as<UnboxedArrayObject>().capacity();
}
template <JSValueType Type>
static inline Value
GetBoxedOrUnboxedDenseElement(JSObject* obj, size_t index)
{
if (Type == JSVAL_TYPE_MAGIC)
return obj->as<NativeObject>().getDenseElement(index);
return obj->as<UnboxedArrayObject>().getElementSpecific<Type>(index);
}
template <JSValueType Type>
static inline void
SetBoxedOrUnboxedDenseElementNoTypeChange(JSObject* obj, size_t index, const Value& value)
{
if (Type == JSVAL_TYPE_MAGIC)
obj->as<NativeObject>().setDenseElement(index, value);
else
obj->as<UnboxedArrayObject>().setElementNoTypeChangeSpecific<Type>(index, value);
}
template <JSValueType Type>
static inline bool
SetBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const Value& value)
{
if (Type == JSVAL_TYPE_MAGIC) {
obj->as<NativeObject>().setDenseElementWithType(cx, index, value);
return true;
}
return obj->as<UnboxedArrayObject>().setElementSpecific<Type>(cx, index, value);
}
template <JSValueType Type>
static inline DenseElementResult
EnsureBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t count)
{
if (Type == JSVAL_TYPE_MAGIC) {
if (!obj->as<ArrayObject>().ensureElements(cx, count))
return DenseElementResult::Failure;
} else {
if (obj->as<UnboxedArrayObject>().capacity() < count) {
if (!obj->as<UnboxedArrayObject>().growElements(cx, count))
return DenseElementResult::Failure;
}
}
return DenseElementResult::Success;
}
template <JSValueType Type>
static inline DenseElementResult
SetOrExtendBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj,
uint32_t start, const Value* vp, uint32_t count,
ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update)
{
if (Type == JSVAL_TYPE_MAGIC) {
NativeObject* nobj = &obj->as<NativeObject>();
if (nobj->denseElementsAreFrozen())
return DenseElementResult::Incomplete;
if (obj->is<ArrayObject>() &&
!obj->as<ArrayObject>().lengthIsWritable() &&
start + count >= obj->as<ArrayObject>().length())
{
return DenseElementResult::Incomplete;
}
DenseElementResult result = nobj->ensureDenseElements(cx, start, count);
if (result != DenseElementResult::Success)
return result;
if (obj->is<ArrayObject>() && start + count >= obj->as<ArrayObject>().length())
obj->as<ArrayObject>().setLengthInt32(start + count);
if (updateTypes == ShouldUpdateTypes::DontUpdate && !nobj->shouldConvertDoubleElements()) {
nobj->copyDenseElements(start, vp, count);
} else {
for (size_t i = 0; i < count; i++)
nobj->setDenseElementWithType(cx, start + i, vp[i]);
}
return DenseElementResult::Success;
}
UnboxedArrayObject* nobj = &obj->as<UnboxedArrayObject>();
if (start > nobj->initializedLength())
return DenseElementResult::Incomplete;
if (start + count >= UnboxedArrayObject::MaximumCapacity)
return DenseElementResult::Incomplete;
if (start + count > nobj->capacity() && !nobj->growElements(cx, start + count))
return DenseElementResult::Failure;
size_t oldInitlen = nobj->initializedLength();
// Overwrite any existing elements covered by the new range. If we fail
// after this point due to some incompatible type being written to the
// object's elements, afterwards the contents will be different from when
// we started. The caller must retry the operation using a generic path,
// which will overwrite the already-modified elements as well as the ones
// that were left alone.
size_t i = 0;
if (updateTypes == ShouldUpdateTypes::DontUpdate) {
for (size_t j = start; i < count && j < oldInitlen; i++, j++)
nobj->setElementNoTypeChangeSpecific<Type>(j, vp[i]);
} else {
for (size_t j = start; i < count && j < oldInitlen; i++, j++) {
if (!nobj->setElementSpecific<Type>(cx, j, vp[i]))
return DenseElementResult::Incomplete;
}
}
if (i != count) {
obj->as<UnboxedArrayObject>().setInitializedLength(start + count);
if (updateTypes == ShouldUpdateTypes::DontUpdate) {
for (; i < count; i++)
nobj->initElementNoTypeChangeSpecific<Type>(start + i, vp[i]);
} else {
for (; i < count; i++) {
if (!nobj->initElementSpecific<Type>(cx, start + i, vp[i])) {
nobj->setInitializedLengthNoBarrier(oldInitlen);
return DenseElementResult::Incomplete;
}
}
}
}
if (start + count >= nobj->length())
nobj->setLength(cx, start + count);
return DenseElementResult::Success;
}
template <JSValueType Type>
static inline DenseElementResult
MoveBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, uint32_t dstStart, uint32_t srcStart,
uint32_t length)
{
MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<Type>(obj));
if (Type == JSVAL_TYPE_MAGIC) {
if (obj->as<NativeObject>().denseElementsAreFrozen())
return DenseElementResult::Incomplete;
if (!obj->as<NativeObject>().maybeCopyElementsForWrite(cx))
return DenseElementResult::Failure;
obj->as<NativeObject>().moveDenseElements(dstStart, srcStart, length);
} else {
uint8_t* data = obj->as<UnboxedArrayObject>().elements();
size_t elementSize = UnboxedTypeSize(Type);
if (UnboxedTypeNeedsPreBarrier(Type) &&
JS::shadow::Zone::asShadowZone(obj->zone())->needsIncrementalBarrier())
{
// Trigger pre barriers on any elements we are overwriting. See
// NativeObject::moveDenseElements. No post barrier is needed as
// only whole cell post barriers are used with unboxed objects.
for (size_t i = 0; i < length; i++)
obj->as<UnboxedArrayObject>().triggerPreBarrier<Type>(dstStart + i);
}
memmove(data + dstStart * elementSize,
data + srcStart * elementSize,
length * elementSize);
}
return DenseElementResult::Success;
}
template <JSValueType DstType, JSValueType SrcType>
static inline DenseElementResult
CopyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src,
uint32_t dstStart, uint32_t srcStart, uint32_t length)
{
MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<SrcType>(src));
MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<DstType>(dst));
MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength<DstType>(dst) == dstStart);
MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength<SrcType>(src) >= srcStart + length);
MOZ_ASSERT(GetBoxedOrUnboxedCapacity<DstType>(dst) >= dstStart + length);
SetBoxedOrUnboxedInitializedLength<DstType>(cx, dst, dstStart + length);
if (DstType == JSVAL_TYPE_MAGIC) {
if (SrcType == JSVAL_TYPE_MAGIC) {
const Value* vp = src->as<NativeObject>().getDenseElements() + srcStart;
dst->as<NativeObject>().initDenseElements(dstStart, vp, length);
} else {
for (size_t i = 0; i < length; i++) {
Value v = GetBoxedOrUnboxedDenseElement<SrcType>(src, srcStart + i);
dst->as<NativeObject>().initDenseElement(dstStart + i, v);
}
}
} else if (DstType == SrcType) {
uint8_t* dstData = dst->as<UnboxedArrayObject>().elements();
uint8_t* srcData = src->as<UnboxedArrayObject>().elements();
size_t elementSize = UnboxedTypeSize(DstType);
memcpy(dstData + dstStart * elementSize,
srcData + srcStart * elementSize,
length * elementSize);
// Add a store buffer entry if we might have copied a nursery pointer to dst.
if (UnboxedTypeNeedsPostBarrier(DstType) && !IsInsideNursery(dst))
dst->runtimeFromMainThread()->gc.storeBuffer.putWholeCell(dst);
} else if (DstType == JSVAL_TYPE_DOUBLE && SrcType == JSVAL_TYPE_INT32) {
uint8_t* dstData = dst->as<UnboxedArrayObject>().elements();
uint8_t* srcData = src->as<UnboxedArrayObject>().elements();
for (size_t i = 0; i < length; i++) {
int32_t v = *reinterpret_cast<int32_t*>(srcData + (srcStart + i) * sizeof(int32_t));
*reinterpret_cast<double*>(dstData + (dstStart + i) * sizeof(double)) = v;
}
} else {
for (size_t i = 0; i < length; i++) {
Value v = GetBoxedOrUnboxedDenseElement<SrcType>(src, srcStart + i);
dst->as<UnboxedArrayObject>().initElementNoTypeChangeSpecific<DstType>(dstStart + i, v);
}
}
return DenseElementResult::Success;
}
/////////////////////////////////////////////////////////////////////
// Dispatch to specialized methods based on the type of an object.
/////////////////////////////////////////////////////////////////////
// Goop to fix MSVC. See DispatchTraceKindTyped in TraceKind.h.
// The clang-cl front end defines _MSC_VER, but still requires the explicit
// template declaration, so we must test for __clang__ here as well.
#if defined(_MSC_VER) && !defined(__clang__)
# define DEPENDENT_TEMPLATE_HINT
#else
# define DEPENDENT_TEMPLATE_HINT template
#endif
// Function to dispatch a method specialized to whatever boxed or unboxed dense
// elements which an input object has.
template <typename F>
DenseElementResult
CallBoxedOrUnboxedSpecialization(F f, JSObject* obj)
{
if (!HasAnyBoxedOrUnboxedDenseElements(obj))
return DenseElementResult::Incomplete;
switch (GetBoxedOrUnboxedType(obj)) {
case JSVAL_TYPE_MAGIC:
return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_MAGIC>();
case JSVAL_TYPE_BOOLEAN:
return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_BOOLEAN>();
case JSVAL_TYPE_INT32:
return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_INT32>();
case JSVAL_TYPE_DOUBLE:
return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_DOUBLE>();
case JSVAL_TYPE_STRING:
return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_STRING>();
case JSVAL_TYPE_OBJECT:
return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_OBJECT>();
default:
MOZ_CRASH();
}
}
// As above, except the specialization can reflect the unboxed type of two objects.
template <typename F>
DenseElementResult
CallBoxedOrUnboxedSpecialization(F f, JSObject* obj1, JSObject* obj2)
{
if (!HasAnyBoxedOrUnboxedDenseElements(obj1) || !HasAnyBoxedOrUnboxedDenseElements(obj2))
return DenseElementResult::Incomplete;
#define SPECIALIZE_OBJ2(TYPE) \
switch (GetBoxedOrUnboxedType(obj2)) { \
case JSVAL_TYPE_MAGIC: \
return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_MAGIC>(); \
case JSVAL_TYPE_BOOLEAN: \
return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_BOOLEAN>(); \
case JSVAL_TYPE_INT32: \
return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_INT32>(); \
case JSVAL_TYPE_DOUBLE: \
return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_DOUBLE>(); \
case JSVAL_TYPE_STRING: \
return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_STRING>(); \
case JSVAL_TYPE_OBJECT: \
return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_OBJECT>(); \
default: \
MOZ_CRASH(); \
}
switch (GetBoxedOrUnboxedType(obj1)) {
case JSVAL_TYPE_MAGIC:
SPECIALIZE_OBJ2(JSVAL_TYPE_MAGIC)
case JSVAL_TYPE_BOOLEAN:
SPECIALIZE_OBJ2(JSVAL_TYPE_BOOLEAN)
case JSVAL_TYPE_INT32:
SPECIALIZE_OBJ2(JSVAL_TYPE_INT32)
case JSVAL_TYPE_DOUBLE:
SPECIALIZE_OBJ2(JSVAL_TYPE_DOUBLE)
case JSVAL_TYPE_STRING:
SPECIALIZE_OBJ2(JSVAL_TYPE_STRING)
case JSVAL_TYPE_OBJECT:
SPECIALIZE_OBJ2(JSVAL_TYPE_OBJECT)
default:
MOZ_CRASH();
}
#undef SPECIALIZE_OBJ2
}
#undef DEPENDENT_TEMPLATE_HINT
#define DefineBoxedOrUnboxedFunctor1(Signature, A) \
struct Signature ## Functor { \
A a; \
explicit Signature ## Functor(A a) \
: a(a) \
{} \
template <JSValueType Type> \
DenseElementResult operator()() { \
return Signature<Type>(a); \
} \
}
#define DefineBoxedOrUnboxedFunctor3(Signature, A, B, C) \
struct Signature ## Functor { \
A a; B b; C c; \
Signature ## Functor(A a, B b, C c) \
: a(a), b(b), c(c) \
{} \
template <JSValueType Type> \
DenseElementResult operator()() { \
return Signature<Type>(a, b, c); \
} \
}
#define DefineBoxedOrUnboxedFunctor4(Signature, A, B, C, D) \
struct Signature ## Functor { \
A a; B b; C c; D d; \
Signature ## Functor(A a, B b, C c, D d) \
: a(a), b(b), c(c), d(d) \
{} \
template <JSValueType Type> \
DenseElementResult operator()() { \
return Signature<Type>(a, b, c, d); \
} \
}
#define DefineBoxedOrUnboxedFunctorPair4(Signature, A, B, C, D) \
struct Signature ## Functor { \
A a; B b; C c; D d; \
Signature ## Functor(A a, B b, C c, D d) \
: a(a), b(b), c(c), d(d) \
{} \
template <JSValueType TypeOne, JSValueType TypeTwo> \
DenseElementResult operator()() { \
return Signature<TypeOne, TypeTwo>(a, b, c, d); \
} \
}
#define DefineBoxedOrUnboxedFunctor5(Signature, A, B, C, D, E) \
struct Signature ## Functor { \
A a; B b; C c; D d; E e; \
Signature ## Functor(A a, B b, C c, D d, E e) \
: a(a), b(b), c(c), d(d), e(e) \
{} \
template <JSValueType Type> \
DenseElementResult operator()() { \
return Signature<Type>(a, b, c, d, e); \
} \
}
#define DefineBoxedOrUnboxedFunctor6(Signature, A, B, C, D, E, F) \
struct Signature ## Functor { \
A a; B b; C c; D d; E e; F f; \
Signature ## Functor(A a, B b, C c, D d, E e, F f) \
: a(a), b(b), c(c), d(d), e(e), f(f) \
{} \
template <JSValueType Type> \
DenseElementResult operator()() { \
return Signature<Type>(a, b, c, d, e, f); \
} \
}
#define DefineBoxedOrUnboxedFunctorPair6(Signature, A, B, C, D, E, F) \
struct Signature ## Functor { \
A a; B b; C c; D d; E e; F f; \
Signature ## Functor(A a, B b, C c, D d, E e, F f) \
: a(a), b(b), c(c), d(d), e(e), f(f) \
{} \
template <JSValueType TypeOne, JSValueType TypeTwo> \
DenseElementResult operator()() { \
return Signature<TypeOne, TypeTwo>(a, b, c, d, e, f); \
} \
}
DenseElementResult
SetOrExtendAnyBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj,
uint32_t start, const Value* vp, uint32_t count,
ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update);
DenseElementResult
MoveAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj,
uint32_t dstStart, uint32_t srcStart, uint32_t length);
DenseElementResult
CopyAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src,
uint32_t dstStart, uint32_t srcStart, uint32_t length);
void
SetAnyBoxedOrUnboxedInitializedLength(JSContext* cx, JSObject* obj, size_t initlen);
DenseElementResult
EnsureAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t count);
} // namespace js
#endif // vm_UnboxedObject_inl_h

File diff suppressed because it is too large Load Diff

View File

@ -1,531 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef vm_UnboxedObject_h
#define vm_UnboxedObject_h
#include "jsgc.h"
#include "jsobj.h"
#include "vm/Runtime.h"
#include "vm/TypeInference.h"
namespace js {
// Memory required for an unboxed value of a given type. Returns zero for types
// which can't be used for unboxed objects.
static inline size_t
UnboxedTypeSize(JSValueType type)
{
switch (type) {
case JSVAL_TYPE_BOOLEAN: return 1;
case JSVAL_TYPE_INT32: return 4;
case JSVAL_TYPE_DOUBLE: return 8;
case JSVAL_TYPE_STRING: return sizeof(void*);
case JSVAL_TYPE_OBJECT: return sizeof(void*);
default: return 0;
}
}
static inline bool
UnboxedTypeNeedsPreBarrier(JSValueType type)
{
return type == JSVAL_TYPE_STRING || type == JSVAL_TYPE_OBJECT;
}
static inline bool
UnboxedTypeNeedsPostBarrier(JSValueType type)
{
return type == JSVAL_TYPE_OBJECT;
}
// Class tracking information specific to unboxed objects.
class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout>
{
public:
struct Property {
PropertyName* name;
uint32_t offset;
JSValueType type;
Property()
: name(nullptr), offset(UINT32_MAX), type(JSVAL_TYPE_MAGIC)
{}
};
typedef Vector<Property, 0, SystemAllocPolicy> PropertyVector;
private:
// If objects in this group have ever been converted to native objects,
// these store the corresponding native group and initial shape for such
// objects. Type information for this object is reflected in nativeGroup.
GCPtrObjectGroup nativeGroup_;
GCPtrShape nativeShape_;
// Any script/pc which the associated group is created for.
GCPtrScript allocationScript_;
jsbytecode* allocationPc_;
// If nativeGroup is set and this object originally had a TypeNewScript or
// was keyed to an allocation site, this points to the group which replaced
// this one. This link is only needed to keep the replacement group from
// being GC'ed. If it were GC'ed and a new one regenerated later, that new
// group might have a different allocation kind from this group.
GCPtrObjectGroup replacementGroup_;
// The following members are only used for unboxed plain objects.
// All properties on objects with this layout, in enumeration order.
PropertyVector properties_;
// Byte size of the data for objects with this layout.
size_t size_;
// Any 'new' script information associated with this layout.
TypeNewScript* newScript_;
// List for use in tracing objects with this layout. This has the same
// structure as the trace list on a TypeDescr.
int32_t* traceList_;
// If this layout has been used to construct script or JSON constant
// objects, this code might be filled in to more quickly fill in objects
// from an array of values.
GCPtrJitCode constructorCode_;
// The following members are only used for unboxed arrays.
// The type of array elements.
JSValueType elementType_;
public:
UnboxedLayout()
: nativeGroup_(nullptr), nativeShape_(nullptr),
allocationScript_(nullptr), allocationPc_(nullptr), replacementGroup_(nullptr),
size_(0), newScript_(nullptr), traceList_(nullptr), constructorCode_(nullptr),
elementType_(JSVAL_TYPE_MAGIC)
{}
bool initProperties(const PropertyVector& properties, size_t size) {
size_ = size;
return properties_.appendAll(properties);
}
void initArray(JSValueType elementType) {
elementType_ = elementType;
}
~UnboxedLayout() {
if (newScript_)
newScript_->clear();
js_delete(newScript_);
js_free(traceList_);
nativeGroup_.init(nullptr);
nativeShape_.init(nullptr);
replacementGroup_.init(nullptr);
constructorCode_.init(nullptr);
}
bool isArray() const {
return elementType_ != JSVAL_TYPE_MAGIC;
}
void detachFromCompartment();
const PropertyVector& properties() const {
return properties_;
}
TypeNewScript* newScript() const {
return newScript_;
}
void setNewScript(TypeNewScript* newScript, bool writeBarrier = true);
JSScript* allocationScript() const {
return allocationScript_;
}
jsbytecode* allocationPc() const {
return allocationPc_;
}
void setAllocationSite(JSScript* script, jsbytecode* pc) {
allocationScript_ = script;
allocationPc_ = pc;
}
const int32_t* traceList() const {
return traceList_;
}
void setTraceList(int32_t* traceList) {
traceList_ = traceList;
}
const Property* lookup(JSAtom* atom) const {
for (size_t i = 0; i < properties_.length(); i++) {
if (properties_[i].name == atom)
return &properties_[i];
}
return nullptr;
}
const Property* lookup(jsid id) const {
if (JSID_IS_STRING(id))
return lookup(JSID_TO_ATOM(id));
return nullptr;
}
size_t size() const {
return size_;
}
ObjectGroup* nativeGroup() const {
return nativeGroup_;
}
Shape* nativeShape() const {
return nativeShape_;
}
jit::JitCode* constructorCode() const {
return constructorCode_;
}
void setConstructorCode(jit::JitCode* code) {
constructorCode_ = code;
}
JSValueType elementType() const {
return elementType_;
}
inline gc::AllocKind getAllocKind() const;
void trace(JSTracer* trc);
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
static bool makeNativeGroup(JSContext* cx, ObjectGroup* group);
static bool makeConstructorCode(JSContext* cx, HandleObjectGroup group);
};
// Class for expando objects holding extra properties given to an unboxed plain
// object. These objects behave identically to normal native plain objects, and
// have a separate Class to distinguish them for memory usage reporting.
class UnboxedExpandoObject : public NativeObject
{
public:
static const Class class_;
};
// Class for a plain object using an unboxed representation. The physical
// layout of these objects is identical to that of an InlineTypedObject, though
// these objects use an UnboxedLayout instead of a TypeDescr to keep track of
// how their properties are stored.
class UnboxedPlainObject : public JSObject
{
// Optional object which stores extra properties on this object. This is
// not automatically barriered to avoid problems if the object is converted
// to a native. See ensureExpando().
UnboxedExpandoObject* expando_;
// Start of the inline data, which immediately follows the group and extra properties.
uint8_t data_[1];
public:
static const Class class_;
static bool obj_lookupProperty(JSContext* cx, HandleObject obj,
HandleId id, MutableHandleObject objp,
MutableHandleShape propp);
static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id,
Handle<PropertyDescriptor> desc,
ObjectOpResult& result);
static bool obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp);
static bool obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver,
HandleId id, MutableHandleValue vp);
static bool obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
HandleValue receiver, ObjectOpResult& result);
static bool obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
MutableHandle<PropertyDescriptor> desc);
static bool obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id,
ObjectOpResult& result);
static bool obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties,
bool enumerableOnly);
static bool obj_watch(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable);
inline const UnboxedLayout& layout() const;
const UnboxedLayout& layoutDontCheckGeneration() const {
return group()->unboxedLayoutDontCheckGeneration();
}
uint8_t* data() {
return &data_[0];
}
UnboxedExpandoObject* maybeExpando() const {
return expando_;
}
void initExpando() {
expando_ = nullptr;
}
// For use during GC.
JSObject** addressOfExpando() {
return reinterpret_cast<JSObject**>(&expando_);
}
bool containsUnboxedOrExpandoProperty(ExclusiveContext* cx, jsid id) const;
static UnboxedExpandoObject* ensureExpando(JSContext* cx, Handle<UnboxedPlainObject*> obj);
bool setValue(ExclusiveContext* cx, const UnboxedLayout::Property& property, const Value& v);
Value getValue(const UnboxedLayout::Property& property, bool maybeUninitialized = false);
static bool convertToNative(JSContext* cx, JSObject* obj);
static UnboxedPlainObject* create(ExclusiveContext* cx, HandleObjectGroup group,
NewObjectKind newKind);
static JSObject* createWithProperties(ExclusiveContext* cx, HandleObjectGroup group,
NewObjectKind newKind, IdValuePair* properties);
void fillAfterConvert(ExclusiveContext* cx,
Handle<GCVector<Value>> values, size_t* valueCursor);
static void trace(JSTracer* trc, JSObject* object);
static size_t offsetOfExpando() {
return offsetof(UnboxedPlainObject, expando_);
}
static size_t offsetOfData() {
return offsetof(UnboxedPlainObject, data_[0]);
}
};
// Try to construct an UnboxedLayout for each of the preliminary objects,
// provided they all match the template shape. If successful, converts the
// preliminary objects and their group to the new unboxed representation.
bool
TryConvertToUnboxedLayout(ExclusiveContext* cx, AutoEnterAnalysis& enter, Shape* templateShape,
ObjectGroup* group, PreliminaryObjectArray* objects);
inline gc::AllocKind
UnboxedLayout::getAllocKind() const
{
MOZ_ASSERT(size());
return gc::GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() + size());
}
// Class for an array object using an unboxed representation.
class UnboxedArrayObject : public JSObject
{
// Elements pointer for the object.
uint8_t* elements_;
// The nominal array length. This always fits in an int32_t.
uint32_t length_;
// Value indicating the allocated capacity and initialized length of the
// array. The top CapacityBits bits are an index into CapacityArray, which
// indicates the elements capacity. The low InitializedLengthBits store the
// initialized length of the array.
uint32_t capacityIndexAndInitializedLength_;
// If the elements are inline, they will point here.
uint8_t inlineElements_[1];
public:
static const uint32_t CapacityBits = 6;
static const uint32_t CapacityShift = 26;
static const uint32_t CapacityMask = uint32_t(-1) << CapacityShift;
static const uint32_t InitializedLengthMask = (1 << CapacityShift) - 1;
static const uint32_t MaximumCapacity = InitializedLengthMask;
static const uint32_t MinimumDynamicCapacity = 8;
static const uint32_t CapacityArray[];
// Capacity index which indicates the array's length is also its capacity.
static const uint32_t CapacityMatchesLengthIndex = 0;
private:
static inline uint32_t computeCapacity(uint32_t index, uint32_t length) {
if (index == CapacityMatchesLengthIndex)
return length;
return CapacityArray[index];
}
static uint32_t chooseCapacityIndex(uint32_t capacity, uint32_t length);
static uint32_t exactCapacityIndex(uint32_t capacity);
public:
static const Class class_;
static bool obj_lookupProperty(JSContext* cx, HandleObject obj,
HandleId id, MutableHandleObject objp,
MutableHandleShape propp);
static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id,
Handle<PropertyDescriptor> desc,
ObjectOpResult& result);
static bool obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp);
static bool obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver,
HandleId id, MutableHandleValue vp);
static bool obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
HandleValue receiver, ObjectOpResult& result);
static bool obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
MutableHandle<PropertyDescriptor> desc);
static bool obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id,
ObjectOpResult& result);
static bool obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties,
bool enumerableOnly);
static bool obj_watch(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable);
inline const UnboxedLayout& layout() const;
const UnboxedLayout& layoutDontCheckGeneration() const {
return group()->unboxedLayoutDontCheckGeneration();
}
JSValueType elementType() const {
return layoutDontCheckGeneration().elementType();
}
uint32_t elementSize() const {
return UnboxedTypeSize(elementType());
}
static bool convertToNative(JSContext* cx, JSObject* obj);
static UnboxedArrayObject* create(ExclusiveContext* cx, HandleObjectGroup group,
uint32_t length, NewObjectKind newKind,
uint32_t maxLength = MaximumCapacity);
static bool convertToNativeWithGroup(ExclusiveContext* cx, JSObject* obj,
ObjectGroup* group, Shape* shape);
bool convertInt32ToDouble(ExclusiveContext* cx, ObjectGroup* group);
void fillAfterConvert(ExclusiveContext* cx,
Handle<GCVector<Value>> values, size_t* valueCursor);
static void trace(JSTracer* trc, JSObject* object);
static void objectMoved(JSObject* obj, const JSObject* old);
static void finalize(FreeOp* fop, JSObject* obj);
static size_t objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObject* src,
gc::AllocKind allocKind);
uint8_t* elements() {
return elements_;
}
bool hasInlineElements() const {
return elements_ == &inlineElements_[0];
}
uint32_t length() const {
return length_;
}
uint32_t initializedLength() const {
return capacityIndexAndInitializedLength_ & InitializedLengthMask;
}
uint32_t capacityIndex() const {
return (capacityIndexAndInitializedLength_ & CapacityMask) >> CapacityShift;
}
uint32_t capacity() const {
return computeCapacity(capacityIndex(), length());
}
bool containsProperty(ExclusiveContext* cx, jsid id);
bool setElement(ExclusiveContext* cx, size_t index, const Value& v);
bool initElement(ExclusiveContext* cx, size_t index, const Value& v);
void initElementNoTypeChange(size_t index, const Value& v);
Value getElement(size_t index);
template <JSValueType Type> inline bool setElementSpecific(ExclusiveContext* cx, size_t index,
const Value& v);
template <JSValueType Type> inline void setElementNoTypeChangeSpecific(size_t index, const Value& v);
template <JSValueType Type> inline bool initElementSpecific(ExclusiveContext* cx, size_t index,
const Value& v);
template <JSValueType Type> inline void initElementNoTypeChangeSpecific(size_t index, const Value& v);
template <JSValueType Type> inline Value getElementSpecific(size_t index);
template <JSValueType Type> inline void triggerPreBarrier(size_t index);
bool growElements(ExclusiveContext* cx, size_t cap);
void shrinkElements(ExclusiveContext* cx, size_t cap);
static uint32_t offsetOfElements() {
return offsetof(UnboxedArrayObject, elements_);
}
static uint32_t offsetOfLength() {
return offsetof(UnboxedArrayObject, length_);
}
static uint32_t offsetOfCapacityIndexAndInitializedLength() {
return offsetof(UnboxedArrayObject, capacityIndexAndInitializedLength_);
}
static uint32_t offsetOfInlineElements() {
return offsetof(UnboxedArrayObject, inlineElements_);
}
void setLengthInt32(uint32_t length) {
MOZ_ASSERT(length <= INT32_MAX);
length_ = length;
}
inline void setLength(ExclusiveContext* cx, uint32_t len);
inline void setInitializedLength(uint32_t initlen);
inline void setInitializedLengthNoBarrier(uint32_t initlen) {
MOZ_ASSERT(initlen <= InitializedLengthMask);
capacityIndexAndInitializedLength_ =
(capacityIndexAndInitializedLength_ & CapacityMask) | initlen;
}
private:
void setInlineElements() {
elements_ = &inlineElements_[0];
}
void setCapacityIndex(uint32_t index) {
MOZ_ASSERT(index <= (CapacityMask >> CapacityShift));
capacityIndexAndInitializedLength_ =
(index << CapacityShift) | initializedLength();
}
};
} // namespace js
namespace JS {
template <>
struct DeletePolicy<js::UnboxedLayout> : public js::GCManagedDeletePolicy<js::UnboxedLayout>
{};
} /* namespace JS */
#endif /* vm_UnboxedObject_h */

View File

@ -1427,8 +1427,6 @@ ReloadPrefsCallback(const char* pref, void* data)
bool extraWarnings = Preferences::GetBool(JS_OPTIONS_DOT_STR "strict");
bool unboxedObjects = Preferences::GetBool(JS_OPTIONS_DOT_STR "unboxed_objects");
sSharedMemoryEnabled = Preferences::GetBool(JS_OPTIONS_DOT_STR "shared_memory");
#ifdef DEBUG
@ -1457,8 +1455,6 @@ ReloadPrefsCallback(const char* pref, void* data)
useBaselineEager ? 0 : -1);
JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_ION_WARMUP_TRIGGER,
useIonEager ? 0 : -1);
JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_UNBOXED_OBJECTS,
unboxedObjects);
}
XPCJSContext::~XPCJSContext()

View File

@ -1268,7 +1268,6 @@ pref("javascript.options.strict", false);
#ifdef DEBUG
pref("javascript.options.strict.debug", false);
#endif
pref("javascript.options.unboxed_objects", false);
pref("javascript.options.baselinejit", true);
pref("javascript.options.ion", true);
pref("javascript.options.asmjs", true);