зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
1572bd11bb
Коммит
68ee4eb8e2
|
@ -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,
|
||||
|
|
Загрузка…
Ссылка в новой задаче