Bug 1487329 - Select wasm baseline compiler if content opts into gc types. r=bbouvier

Creates a level of indirection to encapsulate the compilation
parameters (mode, tier, debug, gc-enabled) so as to allow their
computation to be delayed.  This centers on the new struct
CompilerEnvironment, defined in WasmValidate.h.

After this change, compiler selection is driven by the presence of the
gc-feature-opt-in section.  We finalize the values in
CompilerEnvironment after having parsed that section.  (That parsing
is still under #ifdef.)

--wasm-gc is still used as a higher-level control; if it is not
present there will be no gc support at all.  But once we remove that
flag, very little will change here; all code that reads that flag can
instead pass HasGcTypes::True, and compiler selection will be entirely
driven by the presence of the opt-in section.

There are a few too many uses of HasGcTypes::False here; most of these
will disappear along with the --wasm-gc flag.

--HG--
extra : rebase_source : d2c2bd01309124caaa66f13564be2bcf24f34946
This commit is contained in:
Lars T Hansen 2018-09-03 20:02:38 +02:00
Родитель ee0d09389e
Коммит 680fd3178c
8 изменённых файлов: 191 добавлений и 67 удалений

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

@ -1470,6 +1470,7 @@ class MOZ_STACK_CLASS JS_HAZ_ROOTED ModuleValidator
ArrayViewVector arrayViews_;
// State used to build the AsmJSModule in finish():
CompilerEnvironment compilerEnv_;
ModuleEnvironment env_;
MutableAsmJSMetadata asmJSMetadata_;
@ -1530,12 +1531,13 @@ class MOZ_STACK_CLASS JS_HAZ_ROOTED ModuleValidator
sigSet_(cx),
funcImportMap_(cx),
arrayViews_(cx),
env_(CompileMode::Once, Tier::Ion, DebugEnabled::False, HasGcTypes::False,
Shareable::False, ModuleKind::AsmJS),
compilerEnv_(CompileMode::Once, Tier::Ion, DebugEnabled::False, HasGcTypes::False),
env_(HasGcTypes::False, &compilerEnv_, Shareable::False, ModuleKind::AsmJS),
errorString_(nullptr),
errorOffset_(UINT32_MAX),
errorOverRecursed_(false)
{
compilerEnv_.computeParameters(HasGcTypes::False);
env_.minMemoryLength = RoundUpToNextValidAsmJSHeapLength(0);
}

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

@ -3382,7 +3382,7 @@ class BaseCompiler final : public BaseCompilerInterface
GenerateFunctionPrologue(masm,
env_.funcTypes[func_.index]->id,
env_.mode == CompileMode::Tier1 ? Some(func_.index) : Nothing(),
env_.mode() == CompileMode::Tier1 ? Some(func_.index) : Nothing(),
&offsets_);
// Initialize DebugFrame fields before the stack overflow trap so that
@ -10352,7 +10352,7 @@ js::wasm::BaselineCompileFunctions(const ModuleEnvironment& env, LifoAlloc& lifo
const FuncCompileInputVector& inputs, CompiledCode* code,
UniqueChars* error)
{
MOZ_ASSERT(env.tier == Tier::Baseline);
MOZ_ASSERT(env.tier() == Tier::Baseline);
MOZ_ASSERT(env.kind == ModuleKind::Wasm);
// The MacroAssembler will sometimes access the jitContext.

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

@ -81,11 +81,11 @@ CompileArgs::CompileArgs(JSContext* cx, ScriptedCaller&& scriptedCaller)
bool gcEnabled = false;
#endif
baselineEnabled = cx->options().wasmBaseline() || gcEnabled;
ionEnabled = cx->options().wasmIon() && !gcEnabled;
baselineEnabled = cx->options().wasmBaseline();
ionEnabled = cx->options().wasmIon();
sharedMemoryEnabled = cx->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled();
gcTypesConfigured = gcEnabled ? HasGcTypes::True : HasGcTypes::False;
testTiering = (cx->options().testWasmAwaitTier2() || JitOptions.wasmDelayTier2) && !gcEnabled;
testTiering = cx->options().testWasmAwaitTier2() || JitOptions.wasmDelayTier2;
// Debug information such as source view or debug traps will require
// additional memory and permanently stay in baseline code, so we try to
@ -373,10 +373,51 @@ TieringBeneficial(uint32_t codeSize)
return true;
}
static void
InitialCompileFlags(const CompileArgs& args, Decoder& d, CompileMode* mode, Tier* tier,
DebugEnabled* debug)
CompilerEnvironment::CompilerEnvironment(const CompileArgs& args)
: state_(InitialWithArgs),
args_(&args)
{
}
CompilerEnvironment::CompilerEnvironment(CompileMode mode,
Tier tier,
DebugEnabled debugEnabled,
HasGcTypes gcTypesConfigured)
: state_(InitialWithModeTierDebug),
mode_(mode),
tier_(tier),
debug_(debugEnabled),
gcTypes_(gcTypesConfigured)
{
}
void
CompilerEnvironment::computeParameters(HasGcTypes gcFeatureOptIn)
{
MOZ_ASSERT(state_ == InitialWithModeTierDebug);
if (gcTypes_ == HasGcTypes::True)
gcTypes_ = gcFeatureOptIn;
state_ = Computed;
}
void
CompilerEnvironment::computeParameters(Decoder& d, HasGcTypes gcFeatureOptIn)
{
MOZ_ASSERT(!isComputed());
if (state_ == InitialWithModeTierDebug) {
computeParameters(gcFeatureOptIn);
return;
}
bool gcEnabled = args_->gcTypesConfigured == HasGcTypes::True &&
gcFeatureOptIn == HasGcTypes::True;
bool argBaselineEnabled = args_->baselineEnabled || gcEnabled;
bool argIonEnabled = args_->ionEnabled && !gcEnabled;
bool argTestTiering = args_->testTiering && !gcEnabled;
bool argDebugEnabled = args_->debugEnabled;
uint32_t codeSectionSize = 0;
SectionRange range;
@ -384,24 +425,25 @@ InitialCompileFlags(const CompileArgs& args, Decoder& d, CompileMode* mode, Tier
codeSectionSize = range.size;
// Attempt to default to ion if baseline is disabled.
bool baselineEnabled = BaselineCanCompile() && (args.baselineEnabled || args.testTiering);
bool debugEnabled = BaselineCanCompile() && args.debugEnabled;
bool ionEnabled = IonCanCompile() && (args.ionEnabled || !baselineEnabled || args.testTiering);
bool baselineEnabled = BaselineCanCompile() && (argBaselineEnabled || argTestTiering);
bool debugEnabled = BaselineCanCompile() && argDebugEnabled;
bool ionEnabled = IonCanCompile() && (argIonEnabled || !baselineEnabled || argTestTiering);
// HasCompilerSupport() should prevent failure here
MOZ_RELEASE_ASSERT(baselineEnabled || ionEnabled);
if (baselineEnabled && ionEnabled && !debugEnabled && CanUseExtraThreads() &&
(TieringBeneficial(codeSectionSize) || args.testTiering))
(TieringBeneficial(codeSectionSize) || argTestTiering))
{
*mode = CompileMode::Tier1;
*tier = Tier::Baseline;
mode_ = CompileMode::Tier1;
tier_ = Tier::Baseline;
} else {
*mode = CompileMode::Once;
*tier = debugEnabled || !ionEnabled ? Tier::Baseline : Tier::Ion;
mode_ = CompileMode::Once;
tier_ = debugEnabled || !ionEnabled ? Tier::Baseline : Tier::Ion;
}
*debug = debugEnabled ? DebugEnabled::True : DebugEnabled::False;
debug_ = debugEnabled ? DebugEnabled::True : DebugEnabled::False;
gcTypes_ = gcEnabled ? HasGcTypes::True : HasGcTypes::False;
state_ = Computed;
}
template <class DecoderT>
@ -462,12 +504,9 @@ wasm::CompileBuffer(const CompileArgs& args, const ShareableBytes& bytecode, Uni
Decoder d(bytecode.bytes, 0, error, warnings);
CompileMode mode;
Tier tier;
DebugEnabled debug;
InitialCompileFlags(args, d, &mode, &tier, &debug);
ModuleEnvironment env(mode, tier, debug, args.gcTypesConfigured,
CompilerEnvironment compilerEnv(args);
ModuleEnvironment env(args.gcTypesConfigured,
&compilerEnv,
args.sharedMemoryEnabled ? Shareable::True : Shareable::False);
if (!DecodeModuleEnvironment(d, &env))
return nullptr;
@ -493,13 +532,17 @@ wasm::CompileTier2(const CompileArgs& args, Module& module, Atomic<bool>* cancel
UniqueChars error;
Decoder d(module.bytecode().bytes, 0, &error);
MOZ_ASSERT(args.gcTypesConfigured == HasGcTypes::False, "can't ion-compile with gc types yet");
ModuleEnvironment env(CompileMode::Tier2, Tier::Ion, DebugEnabled::False, HasGcTypes::False,
HasGcTypes gcTypesConfigured = HasGcTypes::False; // No Ion support yet
CompilerEnvironment compilerEnv(CompileMode::Tier2, Tier::Ion, DebugEnabled::False,
gcTypesConfigured);
ModuleEnvironment env(gcTypesConfigured,
&compilerEnv,
args.sharedMemoryEnabled ? Shareable::True : Shareable::False);
if (!DecodeModuleEnvironment(d, &env))
return;
MOZ_ASSERT(env.gcTypesEnabled() == HasGcTypes::False, "can't ion-compile with gc types yet");
ModuleGenerator mg(args, &env, cancelled, &error);
if (!mg.init())
return;
@ -617,12 +660,9 @@ wasm::CompileStreaming(const CompileArgs& args,
{
Decoder d(envBytes, 0, error, warnings);
CompileMode mode;
Tier tier;
DebugEnabled debug;
InitialCompileFlags(args, d, &mode, &tier, &debug);
env.emplace(mode, tier, debug, args.gcTypesConfigured,
CompilerEnvironment compilerEnv(args);
env.emplace(args.gcTypesConfigured,
&compilerEnv,
args.sharedMemoryEnabled ? Shareable::True : Shareable::False);
if (!DecodeModuleEnvironment(d, env.ptr()))
return nullptr;

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

@ -607,7 +607,7 @@ ExecuteCompileTask(CompileTask* task, UniqueChars* error)
MOZ_ASSERT(task->lifo.isEmpty());
MOZ_ASSERT(task->output.empty());
switch (task->env.tier) {
switch (task->env.tier()) {
case Tier::Ion:
if (!IonCompileFunctions(task->env, task->lifo, task->inputs, &task->output, error))
return false;

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

@ -198,8 +198,8 @@ class MOZ_STACK_CLASS ModuleGenerator
UniqueModuleSegment finish(const ShareableBytes& bytecode);
bool isAsmJS() const { return env_->isAsmJS(); }
Tier tier() const { return env_->tier; }
CompileMode mode() const { return env_->mode; }
Tier tier() const { return env_->tier(); }
CompileMode mode() const { return env_->mode(); }
bool debugEnabled() const { return env_->debugEnabled(); }
public:

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

@ -3483,7 +3483,7 @@ wasm::IonCompileFunctions(const ModuleEnvironment& env, LifoAlloc& lifo,
const FuncCompileInputVector& inputs, CompiledCode* code,
UniqueChars* error)
{
MOZ_ASSERT(env.tier == Tier::Ion);
MOZ_ASSERT(env.tier() == Tier::Ion);
TempAllocator alloc(&lifo);
JitContext jitContext(&alloc);

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

@ -2072,8 +2072,13 @@ wasm::DecodeModuleEnvironment(Decoder& d, ModuleEnvironment* env)
#ifdef ENABLE_WASM_GC
if (!DecodeGCFeatureOptInSection(d, env))
return false;
HasGcTypes gcFeatureOptIn = env->gcFeatureOptIn;
#else
HasGcTypes gcFeatureOptIn = HasGcTypes::False;
#endif
env->compilerEnv->computeParameters(d, gcFeatureOptIn);
if (!DecodeTypeSection(d, env))
return false;
@ -2342,12 +2347,15 @@ wasm::Validate(JSContext* cx, const ShareableBytes& bytecode, UniqueChars* error
Decoder d(bytecode.bytes, 0, error);
#ifdef ENABLE_WASM_GC
HasGcTypes gcSupport = cx->options().wasmGc() ? HasGcTypes::True : HasGcTypes::False;
HasGcTypes gcTypesConfigured = cx->options().wasmGc() ? HasGcTypes::True : HasGcTypes::False;
#else
HasGcTypes gcSupport = HasGcTypes::False;
HasGcTypes gcTypesConfigured = HasGcTypes::False;
#endif
ModuleEnvironment env(CompileMode::Once, Tier::Ion, DebugEnabled::False, gcSupport,
CompilerEnvironment compilerEnv(CompileMode::Once, Tier::Ion, DebugEnabled::False,
gcTypesConfigured);
ModuleEnvironment env(gcTypesConfigured,
&compilerEnv,
cx->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled()
? Shareable::True
: Shareable::False);

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

@ -45,6 +45,83 @@ struct SectionRange
typedef Maybe<SectionRange> MaybeSectionRange;
// CompilerEnvironment holds any values that will be needed to compute
// compilation parameters once the module's feature opt-in sections have been
// parsed.
//
// Subsequent to construction a computeParameters() call will compute the final
// compilation parameters, and the object can then be queried for their values.
struct CompileArgs;
class Decoder;
struct CompilerEnvironment
{
// The object starts in one of two "initial" states; computeParameters moves
// it into the "computed" state.
enum State
{
InitialWithArgs,
InitialWithModeTierDebug,
Computed
};
State state_;
union {
// Value if the state_ == InitialWithArgs.
const CompileArgs* args_;
// Value in the other two states.
struct {
CompileMode mode_;
Tier tier_;
DebugEnabled debug_;
HasGcTypes gcTypes_;
};
};
public:
// Retain a reference to the CompileArgs. A subsequent computeParameters()
// will compute all parameters from the CompileArgs and additional values.
CompilerEnvironment(const CompileArgs& args);
// Save the provided values for mode, tier, and debug, and the initial value
// for gcTypes. A subsequent computeParameters() will compute the final
// value of gcTypes.
CompilerEnvironment(CompileMode mode,
Tier tier,
DebugEnabled debugEnabled,
HasGcTypes gcTypesConfigured);
// Compute any remaining compilation parameters.
void computeParameters(Decoder& d, HasGcTypes gcFeatureOptIn);
// Compute any remaining compilation parameters. Only use this method if
// the CompilerEnvironment was created with values for mode, tier, and
// debug.
void computeParameters(HasGcTypes gcFeatureOptIn);
bool isComputed() const {
return state_ == Computed;
}
CompileMode mode() const {
MOZ_ASSERT(isComputed());
return mode_;
}
Tier tier() const {
MOZ_ASSERT(isComputed());
return tier_;
}
DebugEnabled debug() const {
MOZ_ASSERT(isComputed());
return debug_;
}
HasGcTypes gcTypes() const {
MOZ_ASSERT(isComputed());
return gcTypes_;
}
};
// ModuleEnvironment contains all the state necessary to validate, process or
// render functions. It is created by decoding all the sections before the wasm
// code section and then used immutably during. When compiling a module using a
@ -56,21 +133,17 @@ typedef Maybe<SectionRange> MaybeSectionRange;
struct ModuleEnvironment
{
// Constant parameters for the entire compilation:
const DebugEnabled debug;
const ModuleKind kind;
const CompileMode mode;
const Shareable sharedMemoryEnabled;
const ModuleKind kind;
const Shareable sharedMemoryEnabled;
// `gcTypesConfigured` reflects the value of the flags --wasm-gc and
// javascript.options.wasm_gc. These flags will disappear eventually, thus
// allowing the removal of this variable and its replacement everywhere by
// the value HasGcTypes::True.
//
// For now, the value is used (a) in the value of gcTypesEnabled(), which
// controls whether ref types and struct types and associated instructions
// are accepted during validation, and (b) to control whether we emit code
// to suppress GC while wasm activations are on the stack.
const HasGcTypes gcTypesConfigured;
const Tier tier;
// For now, the value is used to control whether we emit code to suppress GC
// while wasm activations are on the stack.
const HasGcTypes gcTypesConfigured;
CompilerEnvironment* const compilerEnv;
// Module fields decoded from the module environment (or initialized while
// validating an asm.js module) and immutable during compilation:
@ -105,18 +178,14 @@ struct ModuleEnvironment
NameInBytecodeVector funcNames;
CustomSectionVector customSections;
explicit ModuleEnvironment(CompileMode mode,
Tier tier,
DebugEnabled debug,
HasGcTypes hasGcTypes,
explicit ModuleEnvironment(HasGcTypes gcTypesConfigured,
CompilerEnvironment* compilerEnv,
Shareable sharedMemoryEnabled,
ModuleKind kind = ModuleKind::Wasm)
: debug(debug),
kind(kind),
mode(mode),
: kind(kind),
sharedMemoryEnabled(sharedMemoryEnabled),
gcTypesConfigured(hasGcTypes),
tier(tier),
gcTypesConfigured(gcTypesConfigured),
compilerEnv(compilerEnv),
#ifdef ENABLE_WASM_GC
gcFeatureOptIn(HasGcTypes::False),
#endif
@ -124,6 +193,15 @@ struct ModuleEnvironment
minMemoryLength(0)
{}
Tier tier() const {
return compilerEnv->tier();
}
CompileMode mode() const {
return compilerEnv->mode();
}
DebugEnabled debug() const {
return compilerEnv->debug();
}
size_t numTables() const {
return tables.length();
}
@ -140,11 +218,7 @@ struct ModuleEnvironment
return funcTypes.length() - funcImportGlobalDataOffsets.length();
}
HasGcTypes gcTypesEnabled() const {
#ifdef ENABLE_WASM_GC
if (gcTypesConfigured == HasGcTypes::True)
return gcFeatureOptIn;
#endif
return HasGcTypes::False;
return compilerEnv->gcTypes();
}
bool usesMemory() const {
return memoryUsage != MemoryUsage::None;
@ -156,7 +230,7 @@ struct ModuleEnvironment
return kind == ModuleKind::AsmJS;
}
bool debugEnabled() const {
return debug == DebugEnabled::True;
return compilerEnv->debug() == DebugEnabled::True;
}
bool funcIsImport(uint32_t funcIndex) const {
return funcIndex < funcImportGlobalDataOffsets.length();