Bug 1738721 - Part 1: Use a shape rather than a template object to create |this| when calling a scripted constructor r=jandem

This replaces use of MCreateThisWithTemplate with MNewPlainObject. This adds a
MIR flag to replace checks for MCreatThisWithTemplate.

Differential Revision: https://phabricator.services.mozilla.com/D130104
This commit is contained in:
Jon Coppeard 2021-11-05 18:14:41 +00:00
Родитель 1572bd11bb
Коммит 68ee4eb8e2
8 изменённых файлов: 69 добавлений и 56 удалений

Просмотреть файл

@ -9403,10 +9403,10 @@ AttachDecision CallIRGenerator::tryAttachInlinableNative(
MOZ_CRASH("Shouldn't get here");
}
// Remember the template object associated with any script being called
// as a constructor, for later use during Ion compilation.
ScriptedThisResult CallIRGenerator::getThisForScripted(
HandleFunction calleeFunc, MutableHandleObject result) {
// Remember the shape of the this object for any script being called as a
// constructor, for later use during Ion compilation.
ScriptedThisResult CallIRGenerator::getThisShapeForScripted(
HandleFunction calleeFunc, MutableHandleShape result) {
// Some constructors allocate their own |this| object.
if (calleeFunc->constructorNeedsUninitializedThis()) {
return ScriptedThisResult::UninitializedThis;
@ -9421,16 +9421,15 @@ ScriptedThisResult CallIRGenerator::getThisForScripted(
}
AutoRealm ar(cx_, calleeFunc);
PlainObject* thisObject =
CreateThisForFunction(cx_, calleeFunc, newTarget, TenuredObject);
if (!thisObject) {
Shape* thisShape = ThisShapeForFunction(cx_, calleeFunc, newTarget);
if (!thisShape) {
cx_->clearPendingException();
return ScriptedThisResult::NoAction;
}
MOZ_ASSERT(thisObject->nonCCWRealm() == calleeFunc->realm());
result.set(thisObject);
return ScriptedThisResult::TemplateObject;
MOZ_ASSERT(thisShape->realm() == calleeFunc->realm());
result.set(thisShape);
return ScriptedThisResult::PlainObjectShape;
}
AttachDecision CallIRGenerator::tryAttachCallScripted(
@ -9470,10 +9469,10 @@ AttachDecision CallIRGenerator::tryAttachCallScripted(
return AttachDecision::NoAction;
}
RootedObject templateObj(cx_);
RootedShape thisShape(cx_);
if (isConstructing && isSpecialized) {
switch (getThisForScripted(calleeFunc, &templateObj)) {
case ScriptedThisResult::TemplateObject:
switch (getThisShapeForScripted(calleeFunc, &thisShape)) {
case ScriptedThisResult::PlainObjectShape:
break;
case ScriptedThisResult::UninitializedThis:
flags.setNeedsUninitializedThis();
@ -9492,12 +9491,11 @@ AttachDecision CallIRGenerator::tryAttachCallScripted(
ObjOperandId calleeObjId = writer.guardToObject(calleeValId);
if (isSpecialized) {
MOZ_ASSERT_IF(isConstructing,
templateObj || flags.needsUninitializedThis());
MOZ_ASSERT_IF(isConstructing, thisShape || flags.needsUninitializedThis());
// Ensure callee matches this stub's callee
emitCalleeGuard(calleeObjId, calleeFunc);
if (templateObj) {
if (thisShape) {
// Emit guards to ensure the newTarget's .prototype property is what we
// expect. Note that getThisForScripted checked newTarget is a function
// with a non-configurable .prototype data property.
@ -9527,7 +9525,7 @@ AttachDecision CallIRGenerator::tryAttachCallScripted(
// Call metaScriptedTemplateObject before emitting the call, so that Warp
// can use this template object before transpiling the call.
writer.metaScriptedTemplateObject(calleeFunc, templateObj);
writer.metaScriptedTemplateObject(calleeFunc, thisShape);
}
} else {
// Guard that object is a scripted function

Просмотреть файл

@ -1074,9 +1074,8 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter {
callNativeSetter_(receiver, setter, rhs, sameRealm, nargsAndFlags);
}
void metaScriptedTemplateObject(JSFunction* callee,
JSObject* templateObject) {
metaTwoByte_(callee, templateObject);
void metaScriptedTemplateObject(JSFunction* callee, Shape* thisShape) {
metaTwoByte_(callee, thisShape);
}
friend class CacheIRCloner;
@ -1633,7 +1632,7 @@ class MOZ_RAII OptimizeSpreadCallIRGenerator : public IRGenerator {
};
enum class StringChar { CodeAt, At };
enum class ScriptedThisResult { NoAction, UninitializedThis, TemplateObject };
enum class ScriptedThisResult { NoAction, UninitializedThis, PlainObjectShape };
class MOZ_RAII CallIRGenerator : public IRGenerator {
private:
@ -1644,8 +1643,8 @@ class MOZ_RAII CallIRGenerator : public IRGenerator {
HandleValue newTarget_;
HandleValueArray args_;
ScriptedThisResult getThisForScripted(HandleFunction calleeFunc,
MutableHandleObject result);
ScriptedThisResult getThisShapeForScripted(HandleFunction calleeFunc,
MutableHandleShape result);
void emitNativeCalleeGuard(JSFunction* callee);
void emitCalleeGuard(ObjOperandId calleeId, JSFunction* callee);

Просмотреть файл

@ -1666,7 +1666,7 @@
custom_writer: true
args:
functionObject: ObjectField
templateObject: ObjectField
thisShape: ShapeField
- name: LoadFixedSlotResult
shared: false

Просмотреть файл

@ -1931,6 +1931,8 @@ class MNewPlainObject : public MUnaryInstruction, public NoTypePolicy::Data {
[[nodiscard]] bool writeRecoverData(
CompactBufferWriter& writer) const override;
bool canRecoverOnBailout() const override { return true; }
AliasSet getAliasSet() const override { return AliasSet::None(); }
};
class MNewArrayObject : public MUnaryInstruction, public NoTypePolicy::Data {

Просмотреть файл

@ -29,6 +29,7 @@
#include "wasm/WasmCode.h"
#include "gc/ObjectKind-inl.h"
#include "vm/NativeObject-inl.h"
using namespace js;
using namespace js::jit;
@ -4553,7 +4554,7 @@ bool WarpCacheIRTranspiler::maybeCreateThis(MDefinition* callee,
}
MOZ_ASSERT(kind == CallKind::Scripted);
if (thisArg->isCreateThisWithTemplate()) {
if (thisArg->isNewPlainObject()) {
// We have already updated |this| based on MetaTwoByte. We do
// not need to generate a check.
return false;
@ -4740,7 +4741,7 @@ bool WarpCacheIRTranspiler::emitCallInlinedFunction(ObjOperandId calleeId,
// know that the constructor needs uninitialized this.
MOZ_ALWAYS_FALSE(maybeCreateThis(callee, flags, CallKind::Scripted));
mozilla::DebugOnly<MDefinition*> thisArg = callInfo_->thisArg();
MOZ_ASSERT(thisArg->isCreateThisWithTemplate() ||
MOZ_ASSERT(thisArg->isNewPlainObject() ||
thisArg->type() == MIRType::MagicUninitializedLexical);
}
@ -5042,14 +5043,24 @@ bool WarpCacheIRTranspiler::emitCallNativeSetter(ObjOperandId receiverId,
// TODO(post-Warp): rename the MetaTwoByte op when IonBuilder is gone.
bool WarpCacheIRTranspiler::emitMetaTwoByte(uint32_t functionObjectOffset,
uint32_t templateObjectOffset) {
JSObject* templateObj = tenuredObjectStubField(templateObjectOffset);
MConstant* templateConst = constant(ObjectValue(*templateObj));
uint32_t thisShapeOffset) {
Shape* shape = shapeStubField(thisShapeOffset);
MOZ_ASSERT(shape->getObjectClass() == &PlainObject::class_);
MConstant* shapeConst = MConstant::NewShape(alloc(), shape);
add(shapeConst);
// TODO: support pre-tenuring.
gc::InitialHeap heap = gc::DefaultHeap;
auto* createThis = MCreateThisWithTemplate::New(alloc(), templateConst, heap);
uint32_t numFixedSlots = shape->numFixedSlots();
uint32_t numDynamicSlots = NativeObject::calculateDynamicSlots(shape);
gc::AllocKind kind = gc::GetGCObjectKind(numFixedSlots);
MOZ_ASSERT(gc::CanChangeToBackgroundAllocKind(kind, &PlainObject::class_));
kind = gc::ForegroundToBackgroundAllocKind(kind);
auto* createThis = MNewPlainObject::New(alloc(), shapeConst, numFixedSlots,
numDynamicSlots, kind, heap);
add(createThis);
callInfo_->thisArg()->setImplicitlyUsedUnchecked();
@ -5130,10 +5141,10 @@ bool WarpCacheIRTranspiler::emitNewPlainObjectResult(uint32_t numFixedSlots,
auto* obj = MNewPlainObject::New(alloc(), shapeConstant, numFixedSlots,
numDynamicSlots, allocKind, heap);
addEffectful(obj);
add(obj);
pushResult(obj);
return resumeAfter(obj);
return true;
}
bool WarpCacheIRTranspiler::emitNewArrayObjectResult(uint32_t length,

Просмотреть файл

@ -74,7 +74,12 @@ static MOZ_ALWAYS_INLINE bool CreateThis(JSContext* cx,
MOZ_ASSERT(thisv.isMagic(JS_IS_CONSTRUCTING));
PlainObject* obj = CreateThisForFunction(cx, callee, newTarget, newKind);
RootedShape shape(cx, ThisShapeForFunction(cx, callee, newTarget));
if (!shape) {
return false;
}
PlainObject* obj = PlainObject::createWithShape(cx, shape, newKind);
if (!obj) {
return false;
}

Просмотреть файл

@ -28,10 +28,17 @@ using namespace js;
using JS::Handle;
using JS::Rooted;
PlainObject* js::CreateThisForFunction(JSContext* cx,
Handle<JSFunction*> callee,
Handle<JSObject*> newTarget,
NewObjectKind newKind) {
static MOZ_ALWAYS_INLINE Shape* GetPlainObjectShapeWithProto(
JSContext* cx, JSObject* proto, gc::AllocKind kind) {
MOZ_ASSERT(JSCLASS_RESERVED_SLOTS(&PlainObject::class_) == 0,
"all slots can be used for properties");
uint32_t nfixed = GetGCKindSlots(kind);
return SharedShape::getInitialShape(cx, &PlainObject::class_, cx->realm(),
TaggedProto(proto), nfixed);
}
Shape* js::ThisShapeForFunction(JSContext* cx, Handle<JSFunction*> callee,
Handle<JSObject*> newTarget) {
MOZ_ASSERT(cx->realm() == callee->realm());
MOZ_ASSERT(!callee->constructorNeedsUninitializedThis());
@ -42,14 +49,14 @@ PlainObject* js::CreateThisForFunction(JSContext* cx,
js::gc::AllocKind allocKind = NewObjectGCKind();
PlainObject* res;
if (proto) {
res = NewPlainObjectWithProtoAndAllocKind(cx, proto, allocKind, newKind);
Shape* res;
if (proto && proto != cx->global()->maybeGetPrototype(JSProto_Object)) {
res = GetPlainObjectShapeWithProto(cx, proto, allocKind);
} else {
res = NewPlainObjectWithAllocKind(cx, allocKind, newKind);
res = GlobalObject::getPlainObjectShapeWithDefaultProto(cx, allocKind);
}
MOZ_ASSERT_IF(res, res->nonCCWRealm() == callee->realm());
MOZ_ASSERT_IF(res, res->realm() == callee->realm());
return res;
}
@ -124,15 +131,6 @@ static bool AddPlainObjectProperties(JSContext* cx, HandlePlainObject obj,
return true;
}
static MOZ_ALWAYS_INLINE Shape* GetPlainObjectShapeWithProto(
JSContext* cx, JSObject* proto, gc::AllocKind kind) {
MOZ_ASSERT(JSCLASS_RESERVED_SLOTS(&PlainObject::class_) == 0,
"all slots can be used for properties");
uint32_t nfixed = GetGCKindSlots(kind);
return SharedShape::getInitialShape(cx, &PlainObject::class_, cx->realm(),
TaggedProto(proto), nfixed);
}
// static
Shape* GlobalObject::createPlainObjectShapeWithDefaultProto(
JSContext* cx, gc::AllocKind kind) {

Просмотреть файл

@ -70,11 +70,11 @@ extern bool CopyDataPropertiesNative(JSContext* cx,
JS::Handle<PlainObject*> excludedItems,
bool* optimized);
// Specialized call for constructing |this| with a known function callee.
extern PlainObject* CreateThisForFunction(JSContext* cx,
JS::Handle<JSFunction*> callee,
JS::Handle<JSObject*> newTarget,
NewObjectKind newKind);
// Specialized call to get the shape to use when creating |this| for a known
// function callee.
extern Shape* ThisShapeForFunction(JSContext* cx,
JS::Handle<JSFunction*> callee,
JS::Handle<JSObject*> newTarget);
// Create a new PlainObject with %Object.prototype% as prototype.
extern PlainObject* NewPlainObject(JSContext* cx,