mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-20 00:20:37 +00:00
Bug 1899500 - Implement explicit resource management in Baseline compiler. r=arai
Differential Revision: https://phabricator.services.mozilla.com/D219406
This commit is contained in:
parent
007f725207
commit
6e13466a0a
@ -239,24 +239,12 @@ set_config(
|
||||
|
||||
# JIT support
|
||||
# =======================================================
|
||||
@depends(
|
||||
target,
|
||||
"--enable-record-tuple",
|
||||
"--enable-portable-baseline-interp",
|
||||
"--enable-explicit-resource-management",
|
||||
)
|
||||
def jit_default(
|
||||
target,
|
||||
enable_record_tuple,
|
||||
enable_portable_baseline_interp,
|
||||
enable_explicit_resource_management,
|
||||
):
|
||||
@depends(target, "--enable-record-tuple", "--enable-portable-baseline-interp")
|
||||
def jit_default(target, enable_record_tuple, enable_portable_baseline_interp):
|
||||
if enable_record_tuple:
|
||||
return False
|
||||
if enable_portable_baseline_interp:
|
||||
return False
|
||||
if enable_explicit_resource_management:
|
||||
return False
|
||||
if target.cpu in (
|
||||
"x86",
|
||||
"x86_64",
|
||||
|
@ -16,6 +16,53 @@ using namespace js::frontend;
|
||||
|
||||
UsingEmitter::UsingEmitter(BytecodeEmitter* bce) : bce_(bce) {}
|
||||
|
||||
bool UsingEmitter::emitTakeDisposeCapability() {
|
||||
if (!bce_->emit1(JSOp::TakeDisposeCapability)) {
|
||||
// [stack] RESOURCES-OR-UNDEF
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bce_->emit1(JSOp::IsNullOrUndefined)) {
|
||||
// [stack] RESOURCES-OR-UNDEF IS-UNDEF
|
||||
return false;
|
||||
}
|
||||
|
||||
InternalIfEmitter ifUndefined(bce_);
|
||||
|
||||
if (!ifUndefined.emitThenElse()) {
|
||||
// [stack] UNDEFINED
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bce_->emit1(JSOp::Zero)) {
|
||||
// [stack] UNDEFINED 0
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ifUndefined.emitElse()) {
|
||||
// [stack] RESOURCES
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bce_->emit1(JSOp::Dup)) {
|
||||
// [stack] RESOURCES RESOURCES
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bce_->emitAtomOp(JSOp::GetProp,
|
||||
TaggedParserAtomIndex::WellKnown::length())) {
|
||||
// [stack] RESOURCES COUNT
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ifUndefined.emitEnd()) {
|
||||
// [stack] RESOURCES COUNT
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UsingEmitter::emitThrowIfException() {
|
||||
// [stack] EXC THROWING
|
||||
|
||||
@ -128,7 +175,7 @@ bool UsingEmitter::emitDisposeLoop(EmitterScope& es,
|
||||
// no code is executed in that case.
|
||||
// Step 6. Set disposeCapability.[[DisposableResourceStack]] to a new empty
|
||||
// List.
|
||||
if (!bce_->emit1(JSOp::TakeDisposeCapability)) {
|
||||
if (!emitTakeDisposeCapability()) {
|
||||
// [stack] ... RESOURCES COUNT
|
||||
return false;
|
||||
}
|
||||
|
@ -30,6 +30,8 @@ class MOZ_STACK_CLASS UsingEmitter {
|
||||
|
||||
[[nodiscard]] bool emitThrowIfException();
|
||||
|
||||
[[nodiscard]] bool emitTakeDisposeCapability();
|
||||
|
||||
[[nodiscard]] bool emitDisposeLoop(
|
||||
EmitterScope& es,
|
||||
CompletionKind initialCompletion = CompletionKind::Normal);
|
||||
|
@ -4877,21 +4877,57 @@ bool BaselineCodeGen<Handler>::emit_LeaveWith() {
|
||||
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||
template <typename Handler>
|
||||
bool BaselineCodeGen<Handler>::emit_AddDisposable() {
|
||||
// TODO: AddDisposable to be implemented for Baseline (Bug 1899500)
|
||||
MOZ_CRASH("AddDisposable has not been implemented for baseline");
|
||||
frame.syncStack(0);
|
||||
|
||||
prepareVMCall();
|
||||
masm.loadBaselineFramePtr(FramePointer, R0.scratchReg());
|
||||
masm.loadValue(frame.addressOfStackValue(-1), R1);
|
||||
|
||||
pushUint8BytecodeOperandArg(R2.scratchReg());
|
||||
pushArg(R1);
|
||||
pushArg(R0.scratchReg());
|
||||
|
||||
using Fn =
|
||||
bool (*)(JSContext*, BaselineFrame*, JS::Handle<JS::Value>, UsingHint);
|
||||
return callVM<Fn, jit::AddDisposableResource>();
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
bool BaselineCodeGen<Handler>::emit_TakeDisposeCapability() {
|
||||
// TODO: TakeDisposeCapability to be implemented for Baseline (Bug 1899500)
|
||||
MOZ_CRASH("TakeDisposeCapability has not been implemented for baseline");
|
||||
frame.syncStack(0);
|
||||
prepareVMCall();
|
||||
masm.loadBaselineFramePtr(FramePointer, R0.scratchReg());
|
||||
|
||||
pushArg(R0.scratchReg());
|
||||
|
||||
using Fn = bool (*)(JSContext*, BaselineFrame*, JS::MutableHandle<JS::Value>);
|
||||
if (!callVM<Fn, jit::TakeDisposeCapability>()) {
|
||||
return false;
|
||||
}
|
||||
frame.push(R0);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
bool BaselineCodeGen<Handler>::emit_CreateSuppressedError() {
|
||||
// TODO: CreateSuppressedError to be implemented for Baseline (Bug
|
||||
// 1899500)
|
||||
MOZ_CRASH("CreateSuppressedError has not been implemented for baseline");
|
||||
frame.popRegsAndSync(2);
|
||||
prepareVMCall();
|
||||
|
||||
masm.loadBaselineFramePtr(FramePointer, R2.scratchReg());
|
||||
|
||||
using Fn = bool (*)(JSContext*, BaselineFrame*, JS::Handle<JS::Value>,
|
||||
JS::Handle<JS::Value>, JS::MutableHandle<JS::Value>);
|
||||
|
||||
pushArg(R1); // suppressed
|
||||
pushArg(R0); // error
|
||||
pushArg(R2.scratchReg());
|
||||
|
||||
if (!callVM<Fn, jit::CreateSuppressedError>()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
frame.push(R0);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -105,6 +105,35 @@ bool BaselineFrame::pushVarEnvironment(JSContext* cx, Handle<Scope*> scope) {
|
||||
return js::PushVarEnvironmentObject(cx, scope, this);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||
ArrayObject* BaselineFrame::getOrCreateDisposeCapability(JSContext* cx) {
|
||||
JSObject* env = environmentChain();
|
||||
|
||||
if (env->is<LexicalEnvironmentObject>()) {
|
||||
return env->as<LexicalEnvironmentObject>().getOrCreateDisposeCapability(cx);
|
||||
}
|
||||
MOZ_ASSERT(env->is<ModuleEnvironmentObject>());
|
||||
return env->as<ModuleEnvironmentObject>().getOrCreateDisposeCapability(cx);
|
||||
}
|
||||
|
||||
bool BaselineFrame::takeDisposeCapability(
|
||||
JSContext* cx, JS::MutableHandle<JS::Value> capability) {
|
||||
JSObject* env = environmentChain();
|
||||
|
||||
if (env->is<LexicalEnvironmentObject>()) {
|
||||
// TODO: The get & clear disposables function can be merged. (bug 1907736)
|
||||
capability.set(env->as<LexicalEnvironmentObject>().getDisposables());
|
||||
env->as<LexicalEnvironmentObject>().clearDisposables();
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(env->is<ModuleEnvironmentObject>());
|
||||
capability.set(env->as<ModuleEnvironmentObject>().getDisposables());
|
||||
env->as<ModuleEnvironmentObject>().clearDisposables();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void BaselineFrame::setInterpreterFields(JSScript* script, jsbytecode* pc) {
|
||||
uint32_t pcOffset = script->pcToOffset(pc);
|
||||
interpreterScript_ = script;
|
||||
|
@ -317,6 +317,13 @@ class BaselineFrame {
|
||||
Handle<ClassBodyScope*> scope);
|
||||
[[nodiscard]] bool pushVarEnvironment(JSContext* cx, Handle<Scope*> scope);
|
||||
|
||||
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||
[[nodiscard]] ArrayObject* getOrCreateDisposeCapability(JSContext* cx);
|
||||
|
||||
[[nodiscard]] bool takeDisposeCapability(
|
||||
JSContext* cx, JS::MutableHandle<JS::Value> capability);
|
||||
#endif
|
||||
|
||||
void initArgsObjUnchecked(ArgumentsObject& argsobj) {
|
||||
flags_ |= HAS_ARGS_OBJ;
|
||||
argsObj_ = &argsobj;
|
||||
|
@ -48,6 +48,8 @@ namespace jit {
|
||||
// non-argument Values the VM wrapper should pop from the stack. This is used
|
||||
// for tail calls for Baseline ICs. This list must be sorted on the name field.
|
||||
#define VMFUNCTION_LIST(_) \
|
||||
IF_EXPLICIT_RESOURCE_MANAGEMENT( \
|
||||
_(AddDisposableResource, js::jit::AddDisposableResource)) \
|
||||
_(AddOrUpdateSparseElementHelper, js::AddOrUpdateSparseElementHelper) \
|
||||
_(AddSlotAndCallAddPropHook, js::AddSlotAndCallAddPropHook) \
|
||||
_(ArgumentsObjectCreateForInlinedIon, \
|
||||
@ -131,6 +133,8 @@ namespace jit {
|
||||
_(CreateBigIntFromUint64, js::jit::CreateBigIntFromUint64) \
|
||||
_(CreateGenerator, js::jit::CreateGenerator) \
|
||||
_(CreateGeneratorFromFrame, js::jit::CreateGeneratorFromFrame) \
|
||||
IF_EXPLICIT_RESOURCE_MANAGEMENT( \
|
||||
_(CreateSuppressedError, js::jit::CreateSuppressedError)) \
|
||||
_(CreateThisFromIC, js::jit::CreateThisFromIC) \
|
||||
_(CreateThisFromIon, js::jit::CreateThisFromIon) \
|
||||
_(DebugAfterYield, js::jit::DebugAfterYield) \
|
||||
@ -329,6 +333,8 @@ namespace jit {
|
||||
_(StringsEqual, js::jit::StringsEqual<js::jit::EqualityKind::Equal>) \
|
||||
_(StringsNotEqual, js::jit::StringsEqual<js::jit::EqualityKind::NotEqual>) \
|
||||
_(SubstringKernel, js::SubstringKernel) \
|
||||
IF_EXPLICIT_RESOURCE_MANAGEMENT( \
|
||||
_(TakeDisposeCapability, js::jit::TakeDisposeCapability)) \
|
||||
_(ThrowBadDerivedReturnOrUninitializedThis, \
|
||||
js::jit::ThrowBadDerivedReturnOrUninitializedThis) \
|
||||
_(ThrowCheckIsObject, js::ThrowCheckIsObject) \
|
||||
|
@ -1330,6 +1330,36 @@ bool PushVarEnv(JSContext* cx, BaselineFrame* frame, Handle<Scope*> scope) {
|
||||
return frame->pushVarEnvironment(cx, scope);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||
bool AddDisposableResource(JSContext* cx, BaselineFrame* frame,
|
||||
JS::Handle<JS::Value> val, UsingHint hint) {
|
||||
JS::Rooted<ArrayObject*> disposeCapability(
|
||||
cx, frame->getOrCreateDisposeCapability(cx));
|
||||
if (!disposeCapability) {
|
||||
return false;
|
||||
}
|
||||
return js::AddDisposableResource(cx, disposeCapability, val, hint,
|
||||
JS::NothingHandleValue);
|
||||
}
|
||||
|
||||
bool TakeDisposeCapability(JSContext* cx, BaselineFrame* frame,
|
||||
JS::MutableHandle<JS::Value> capability) {
|
||||
return frame->takeDisposeCapability(cx, capability);
|
||||
}
|
||||
|
||||
bool CreateSuppressedError(JSContext* cx, BaselineFrame* frame,
|
||||
JS::Handle<JS::Value> error,
|
||||
JS::Handle<JS::Value> suppressed,
|
||||
JS::MutableHandle<JS::Value> rval) {
|
||||
ErrorObject* errorObj = js::CreateSuppressedError(cx, error, suppressed);
|
||||
if (!errorObj) {
|
||||
return false;
|
||||
}
|
||||
rval.setObject(*errorObj);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool EnterWith(JSContext* cx, BaselineFrame* frame, HandleValue val,
|
||||
Handle<WithScope*> templ) {
|
||||
return EnterWithOperation(cx, frame, val, templ);
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "js/ScalarType.h"
|
||||
#include "js/TypeDecls.h"
|
||||
#include "vm/TypeofEqOperand.h"
|
||||
#include "vm/UsingHint.h"
|
||||
|
||||
class JSJitInfo;
|
||||
class JSLinearString;
|
||||
@ -496,6 +497,21 @@ ArrayObject* InitRestParameter(JSContext* cx, uint32_t length, Value* rest,
|
||||
[[nodiscard]] bool PushVarEnv(JSContext* cx, BaselineFrame* frame,
|
||||
Handle<Scope*> scope);
|
||||
|
||||
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||
[[nodiscard]] bool AddDisposableResource(JSContext*, BaselineFrame* frame,
|
||||
JS::Handle<JS::Value> val,
|
||||
UsingHint hint);
|
||||
|
||||
[[nodiscard]] bool CreateSuppressedError(JSContext* cx, BaselineFrame* frame,
|
||||
JS::Handle<JS::Value> error,
|
||||
JS::Handle<JS::Value> suppressed,
|
||||
JS::MutableHandle<JS::Value> rval);
|
||||
|
||||
[[nodiscard]] bool TakeDisposeCapability(
|
||||
JSContext* cx, BaselineFrame* frame,
|
||||
JS::MutableHandle<JS::Value> capability);
|
||||
#endif
|
||||
|
||||
[[nodiscard]] bool InitBaselineFrameForOsr(BaselineFrame* frame,
|
||||
InterpreterFrame* interpFrame,
|
||||
uint32_t numStackValues);
|
||||
|
@ -631,7 +631,10 @@ class ModuleEnvironmentObject : public EnvironmentObject {
|
||||
static const JSClass class_;
|
||||
|
||||
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||
static constexpr uint32_t RESERVED_SLOTS = 3;
|
||||
// While there are only 3 reserved slots, this needs to be set to 4, given
|
||||
// there are some code expect the number of fixed slot to be same as the
|
||||
// number of reserved slots for the lexical environments (bug 1913864).
|
||||
static constexpr uint32_t RESERVED_SLOTS = 4;
|
||||
#else
|
||||
static constexpr uint32_t RESERVED_SLOTS = 2;
|
||||
#endif
|
||||
@ -762,7 +765,8 @@ class LexicalEnvironmentObject : public EnvironmentObject {
|
||||
static const JSClass class_;
|
||||
|
||||
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||
static constexpr uint32_t RESERVED_SLOTS = 3;
|
||||
// See comment on RESERVED_SLOTS in ModuleEnvironmentObject.
|
||||
static constexpr uint32_t RESERVED_SLOTS = 4;
|
||||
#else
|
||||
static constexpr uint32_t RESERVED_SLOTS = 2;
|
||||
#endif
|
||||
|
@ -2307,12 +2307,8 @@ bool MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER js::Interpret(JSContext* cx,
|
||||
|
||||
if (maybeDisposables.isUndefined()) {
|
||||
PUSH_UNDEFINED();
|
||||
PUSH_INT32(0);
|
||||
} else {
|
||||
PUSH_OBJECT(maybeDisposables.toObject());
|
||||
PUSH_INT32(maybeDisposables.toObject()
|
||||
.as<ArrayObject>()
|
||||
.getDenseInitializedLength());
|
||||
if (env->is<LexicalEnvironmentObject>()) {
|
||||
env->as<LexicalEnvironmentObject>().clearDisposables();
|
||||
} else {
|
||||
|
@ -3415,20 +3415,20 @@
|
||||
*/ \
|
||||
IF_EXPLICIT_RESOURCE_MANAGEMENT(MACRO(AddDisposable, add_disposable, NULL, 2, 1, 1, JOF_UINT8)) \
|
||||
/*
|
||||
* Get the dispose capability of the present environment object and the
|
||||
* length of the same. In case the dispose capability of the environment
|
||||
* Get the dispose capability of the present environment object.
|
||||
* In case the dispose capability of the environment
|
||||
* has already been cleared or if no disposables have been
|
||||
* pushed to the capability, it shall push undefined as the dispose
|
||||
* capability and 0 as the length. After extracting a non-empty dispose
|
||||
* capability. After extracting a non-empty dispose
|
||||
* capability, the dispose capability is cleared from the present
|
||||
* environment object by setting it to undefined value.
|
||||
*
|
||||
* Category: Variables and scopes
|
||||
* Type: Entering and leaving environments
|
||||
* Operands:
|
||||
* Stack: => disposeCapability, count
|
||||
* Stack: => disposeCapability
|
||||
*/ \
|
||||
IF_EXPLICIT_RESOURCE_MANAGEMENT(MACRO(TakeDisposeCapability, take_dispose_capability, NULL, 1, 0, 2, JOF_BYTE)) \
|
||||
IF_EXPLICIT_RESOURCE_MANAGEMENT(MACRO(TakeDisposeCapability, take_dispose_capability, NULL, 1, 0, 1, JOF_BYTE)) \
|
||||
/*
|
||||
* Push the current VariableEnvironment (the environment on the environment
|
||||
* chain designated to receive new variables).
|
||||
|
Loading…
x
Reference in New Issue
Block a user