Commit eb1d2d70 authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

[wasm] Make error messages deterministic

Compilation only stores whether an error has been found, but not the
exact error or it's location. This is generated by running a validation
pass once all wire bytes have been received.
This unifies error messages by removing one more location where we
generate compilation error messages, and makes it deterministic because
a) we always report the error in the first failing function, and
b) if names are present, the error message will always contain the
   function name.

R=titzer@chromium.org

Bug: chromium:926311, v8:8814
Change-Id: I79551b8bb73dcee503484de343a3ada60a6add4f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1521112
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarBen Titzer <titzer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60242}
parent e3aad1c8
...@@ -6020,8 +6020,7 @@ TurbofanWasmCompilationUnit::~TurbofanWasmCompilationUnit() = default; ...@@ -6020,8 +6020,7 @@ TurbofanWasmCompilationUnit::~TurbofanWasmCompilationUnit() = default;
bool TurbofanWasmCompilationUnit::BuildGraphForWasmFunction( bool TurbofanWasmCompilationUnit::BuildGraphForWasmFunction(
wasm::CompilationEnv* env, const wasm::FunctionBody& func_body, wasm::CompilationEnv* env, const wasm::FunctionBody& func_body,
wasm::WasmFeatures* detected, double* decode_ms, MachineGraph* mcgraph, wasm::WasmFeatures* detected, double* decode_ms, MachineGraph* mcgraph,
NodeOriginTable* node_origins, SourcePositionTable* source_positions, NodeOriginTable* node_origins, SourcePositionTable* source_positions) {
wasm::WasmError* error_out) {
base::ElapsedTimer decode_timer; base::ElapsedTimer decode_timer;
if (FLAG_trace_wasm_decode_time) { if (FLAG_trace_wasm_decode_time) {
decode_timer.Start(); decode_timer.Start();
...@@ -6039,7 +6038,6 @@ bool TurbofanWasmCompilationUnit::BuildGraphForWasmFunction( ...@@ -6039,7 +6038,6 @@ bool TurbofanWasmCompilationUnit::BuildGraphForWasmFunction(
<< graph_construction_result.error().message() << graph_construction_result.error().message()
<< std::endl; << std::endl;
} }
*error_out = graph_construction_result.error();
return false; return false;
} }
...@@ -6111,11 +6109,9 @@ wasm::WasmCompilationResult TurbofanWasmCompilationUnit::ExecuteCompilation( ...@@ -6111,11 +6109,9 @@ wasm::WasmCompilationResult TurbofanWasmCompilationUnit::ExecuteCompilation(
: nullptr; : nullptr;
SourcePositionTable* source_positions = SourcePositionTable* source_positions =
new (mcgraph->zone()) SourcePositionTable(mcgraph->graph()); new (mcgraph->zone()) SourcePositionTable(mcgraph->graph());
wasm::WasmError error;
if (!BuildGraphForWasmFunction(env, func_body, detected, &decode_ms, mcgraph, if (!BuildGraphForWasmFunction(env, func_body, detected, &decode_ms, mcgraph,
node_origins, source_positions, &error)) { node_origins, source_positions)) {
DCHECK(!error.empty()); return wasm::WasmCompilationResult{};
return wasm::WasmCompilationResult{std::move(error)};
} }
if (node_origins) { if (node_origins) {
...@@ -6161,9 +6157,7 @@ wasm::WasmCompilationResult InterpreterCompilationUnit::ExecuteCompilation( ...@@ -6161,9 +6157,7 @@ wasm::WasmCompilationResult InterpreterCompilationUnit::ExecuteCompilation(
wasm::WasmFullDecoder<wasm::Decoder::kValidate, wasm::EmptyInterface> decoder( wasm::WasmFullDecoder<wasm::Decoder::kValidate, wasm::EmptyInterface> decoder(
&zone, module, env->enabled_features, detected, func_body); &zone, module, env->enabled_features, detected, func_body);
decoder.Decode(); decoder.Decode();
if (decoder.failed()) { if (decoder.failed()) return wasm::WasmCompilationResult{};
return wasm::WasmCompilationResult{decoder.error()};
}
wasm::WasmCompilationResult result = CompileWasmInterpreterEntry( wasm::WasmCompilationResult result = CompileWasmInterpreterEntry(
wasm_unit_->wasm_engine_, env->enabled_features, wasm_unit_->func_index_, wasm_unit_->wasm_engine_, env->enabled_features, wasm_unit_->func_index_,
......
...@@ -55,8 +55,7 @@ class TurbofanWasmCompilationUnit { ...@@ -55,8 +55,7 @@ class TurbofanWasmCompilationUnit {
wasm::WasmFeatures* detected, wasm::WasmFeatures* detected,
double* decode_ms, MachineGraph* mcgraph, double* decode_ms, MachineGraph* mcgraph,
NodeOriginTable* node_origins, NodeOriginTable* node_origins,
SourcePositionTable* source_positions, SourcePositionTable* source_positions);
wasm::WasmError* error_out);
wasm::WasmCompilationResult ExecuteCompilation(wasm::CompilationEnv*, wasm::WasmCompilationResult ExecuteCompilation(wasm::CompilationEnv*,
const wasm::FunctionBody&, const wasm::FunctionBody&,
......
...@@ -2004,12 +2004,12 @@ WasmCompilationResult LiftoffCompilationUnit::ExecuteCompilation( ...@@ -2004,12 +2004,12 @@ WasmCompilationResult LiftoffCompilationUnit::ExecuteCompilation(
LiftoffCompiler* compiler = &decoder.interface(); LiftoffCompiler* compiler = &decoder.interface();
if (decoder.failed()) { if (decoder.failed()) {
compiler->OnFirstError(&decoder); compiler->OnFirstError(&decoder);
return WasmCompilationResult{decoder.error()}; return WasmCompilationResult{};
} }
if (!compiler->ok()) { if (!compiler->ok()) {
// Liftoff compilation failed. // Liftoff compilation failed.
counters->liftoff_unsupported_functions()->Increment(); counters->liftoff_unsupported_functions()->Increment();
return WasmCompilationResult{WasmError{0, "Liftoff bailout"}}; return WasmCompilationResult{};
} }
counters->liftoff_compiled_functions()->Increment(); counters->liftoff_compiled_functions()->Increment();
......
...@@ -109,7 +109,7 @@ class CompilationState { ...@@ -109,7 +109,7 @@ class CompilationState {
void AbortCompilation(); void AbortCompilation();
void SetError(uint32_t func_index, const WasmError& error); void SetError();
void SetWireBytesStorage(std::shared_ptr<WireBytesStorage>); void SetWireBytesStorage(std::shared_ptr<WireBytesStorage>);
......
...@@ -195,8 +195,7 @@ WasmCompilationResult WasmCompilationUnit::ExecuteCompilation( ...@@ -195,8 +195,7 @@ WasmCompilationResult WasmCompilationUnit::ExecuteCompilation(
WasmCode* WasmCompilationUnit::Publish(WasmCompilationResult result, WasmCode* WasmCompilationUnit::Publish(WasmCompilationResult result,
NativeModule* native_module) { NativeModule* native_module) {
if (!result.succeeded()) { if (!result.succeeded()) {
native_module->compilation_state()->SetError(func_index_, native_module->compilation_state()->SetError();
std::move(result.error));
return nullptr; return nullptr;
} }
......
...@@ -51,12 +51,7 @@ struct WasmCompilationResult { ...@@ -51,12 +51,7 @@ struct WasmCompilationResult {
public: public:
MOVE_ONLY_WITH_DEFAULT_CONSTRUCTORS(WasmCompilationResult); MOVE_ONLY_WITH_DEFAULT_CONSTRUCTORS(WasmCompilationResult);
explicit WasmCompilationResult(WasmError error) : error(std::move(error)) {} bool succeeded() const { return code_desc.buffer != nullptr; }
bool succeeded() const {
DCHECK_EQ(code_desc.buffer != nullptr, error.empty());
return error.empty();
}
operator bool() const { return succeeded(); } operator bool() const { return succeeded(); }
CodeDesc code_desc; CodeDesc code_desc;
...@@ -65,8 +60,6 @@ struct WasmCompilationResult { ...@@ -65,8 +60,6 @@ struct WasmCompilationResult {
uint32_t tagged_parameter_slots = 0; uint32_t tagged_parameter_slots = 0;
OwnedVector<byte> source_positions; OwnedVector<byte> source_positions;
OwnedVector<trap_handler::ProtectedInstructionData> protected_instructions; OwnedVector<trap_handler::ProtectedInstructionData> protected_instructions;
WasmError error;
}; };
class WasmCompilationUnit final { class WasmCompilationUnit final {
......
...@@ -120,7 +120,6 @@ class CompilationStateImpl { ...@@ -120,7 +120,6 @@ class CompilationStateImpl {
public: public:
CompilationStateImpl(const std::shared_ptr<NativeModule>& native_module, CompilationStateImpl(const std::shared_ptr<NativeModule>& native_module,
std::shared_ptr<Counters> async_counters); std::shared_ptr<Counters> async_counters);
~CompilationStateImpl();
// Cancel all background compilation and wait for all tasks to finish. Call // Cancel all background compilation and wait for all tasks to finish. Call
// this before destructing this object. // this before destructing this object.
...@@ -150,10 +149,10 @@ class CompilationStateImpl { ...@@ -150,10 +149,10 @@ class CompilationStateImpl {
void RestartBackgroundCompileTask(); void RestartBackgroundCompileTask();
void RestartBackgroundTasks(); void RestartBackgroundTasks();
void SetError(uint32_t func_index, const WasmError& error); void SetError();
bool failed() const { bool failed() const {
return compile_error_.load(std::memory_order_relaxed) != nullptr; return compile_failed_.load(std::memory_order_relaxed);
} }
bool baseline_compilation_finished() const { bool baseline_compilation_finished() const {
...@@ -166,27 +165,6 @@ class CompilationStateImpl { ...@@ -166,27 +165,6 @@ class CompilationStateImpl {
CompileMode compile_mode() const { return compile_mode_; } CompileMode compile_mode() const { return compile_mode_; }
WasmFeatures* detected_features() { return &detected_features_; } WasmFeatures* detected_features() { return &detected_features_; }
// Call {GetCompileError} from foreground threads only, since we access
// NativeModule::wire_bytes, which is set from the foreground thread once the
// stream has finished.
WasmError GetCompileError() {
CompilationError* error = compile_error_.load(std::memory_order_acquire);
DCHECK_NOT_NULL(error);
std::ostringstream error_msg;
error_msg << "Compiling wasm function \"";
wasm::ModuleWireBytes wire_bytes(native_module_->wire_bytes());
wasm::WireBytesRef name_ref = native_module_->module()->LookupFunctionName(
wire_bytes, error->func_index);
if (name_ref.is_set()) {
wasm::WasmName name = wire_bytes.GetNameOrNull(name_ref);
error_msg.write(name.start(), name.length());
} else {
error_msg << "wasm-function[" << error->func_index << "]";
}
error_msg << "\" failed: " << error->error.message();
return WasmError{error->error.offset(), error_msg.str()};
}
void SetWireBytesStorage( void SetWireBytesStorage(
std::shared_ptr<WireBytesStorage> wire_bytes_storage) { std::shared_ptr<WireBytesStorage> wire_bytes_storage) {
base::MutexGuard guard(&mutex_); base::MutexGuard guard(&mutex_);
...@@ -200,22 +178,14 @@ class CompilationStateImpl { ...@@ -200,22 +178,14 @@ class CompilationStateImpl {
} }
private: private:
struct CompilationError {
uint32_t const func_index;
WasmError const error;
CompilationError(uint32_t func_index, WasmError error)
: func_index(func_index), error(std::move(error)) {}
};
NativeModule* const native_module_; NativeModule* const native_module_;
const std::shared_ptr<BackgroundCompileToken> background_compile_token_; const std::shared_ptr<BackgroundCompileToken> background_compile_token_;
const CompileMode compile_mode_; const CompileMode compile_mode_;
const std::shared_ptr<Counters> async_counters_; const std::shared_ptr<Counters> async_counters_;
// Compilation error, atomically updated, but at most once (nullptr -> error). // Compilation error, atomically updated. This flag can be updated and read
// Uses acquire-release semantics (acquire on load, release on update). // using relaxed semantics.
// For checking whether an error is set, relaxed semantics can be used. std::atomic<bool> compile_failed_{false};
std::atomic<CompilationError*> compile_error_{nullptr};
// This mutex protects all information of this {CompilationStateImpl} which is // This mutex protects all information of this {CompilationStateImpl} which is
// being accessed concurrently. // being accessed concurrently.
...@@ -287,9 +257,7 @@ CompilationState::~CompilationState() { Impl(this)->~CompilationStateImpl(); } ...@@ -287,9 +257,7 @@ CompilationState::~CompilationState() { Impl(this)->~CompilationStateImpl(); }
void CompilationState::AbortCompilation() { Impl(this)->AbortCompilation(); } void CompilationState::AbortCompilation() { Impl(this)->AbortCompilation(); }
void CompilationState::SetError(uint32_t func_index, const WasmError& error) { void CompilationState::SetError() { Impl(this)->SetError(); }
Impl(this)->SetError(func_index, error);
}
void CompilationState::SetWireBytesStorage( void CompilationState::SetWireBytesStorage(
std::shared_ptr<WireBytesStorage> wire_bytes_storage) { std::shared_ptr<WireBytesStorage> wire_bytes_storage) {
...@@ -538,10 +506,7 @@ void CompileInParallel(Isolate* isolate, NativeModule* native_module) { ...@@ -538,10 +506,7 @@ void CompileInParallel(Isolate* isolate, NativeModule* native_module) {
compilation_state->PublishDetectedFeatures(isolate, detected_features); compilation_state->PublishDetectedFeatures(isolate, detected_features);
} }
void CompileSequentially(Isolate* isolate, NativeModule* native_module, void CompileSequentially(Isolate* isolate, NativeModule* native_module) {
ErrorThrower* thrower) {
DCHECK(!thrower->error());
ModuleWireBytes wire_bytes(native_module->wire_bytes()); ModuleWireBytes wire_bytes(native_module->wire_bytes());
const WasmModule* module = native_module->module(); const WasmModule* module = native_module->module();
WasmFeatures detected = kNoWasmFeatures; WasmFeatures detected = kNoWasmFeatures;
...@@ -554,10 +519,7 @@ void CompileSequentially(Isolate* isolate, NativeModule* native_module, ...@@ -554,10 +519,7 @@ void CompileSequentially(Isolate* isolate, NativeModule* native_module,
// Compile the function. // Compile the function.
WasmCompilationUnit::CompileWasmFunction(isolate, native_module, &detected, WasmCompilationUnit::CompileWasmFunction(isolate, native_module, &detected,
&func, tier); &func, tier);
if (comp_state->failed()) { if (comp_state->failed()) break;
thrower->CompileFailed(comp_state->GetCompileError());
break;
}
} }
UpdateFeatureUseCounts(isolate, detected); UpdateFeatureUseCounts(isolate, detected);
} }
...@@ -566,16 +528,15 @@ void ValidateSequentially(Isolate* isolate, NativeModule* native_module, ...@@ -566,16 +528,15 @@ void ValidateSequentially(Isolate* isolate, NativeModule* native_module,
ErrorThrower* thrower) { ErrorThrower* thrower) {
DCHECK(!thrower->error()); DCHECK(!thrower->error());
ModuleWireBytes wire_bytes(native_module->wire_bytes()); ModuleWireBytes wire_bytes{native_module->wire_bytes()};
const WasmModule* module = native_module->module(); const WasmModule* module = native_module->module();
uint32_t start = module->num_imported_functions; uint32_t start = module->num_imported_functions;
uint32_t end = start + module->num_declared_functions; uint32_t end = start + module->num_declared_functions;
for (uint32_t i = start; i < end; ++i) { for (uint32_t i = start; i < end; ++i) {
const WasmFunction& func = module->functions[i]; const WasmFunction* func = &module->functions[i];
const byte* base = wire_bytes.start(); Vector<const uint8_t> code = wire_bytes.GetFunctionBytes(func);
FunctionBody body{func.sig, func.code.offset(), base + func.code.offset(), FunctionBody body{func->sig, func->code.offset(), code.start(), code.end()};
base + func.code.end_offset()};
DecodeResult result; DecodeResult result;
{ {
auto time_counter = SELECT_WASM_COUNTER( auto time_counter = SELECT_WASM_COUNTER(
...@@ -588,11 +549,18 @@ void ValidateSequentially(Isolate* isolate, NativeModule* native_module, ...@@ -588,11 +549,18 @@ void ValidateSequentially(Isolate* isolate, NativeModule* native_module,
&detected, body); &detected, body);
} }
if (result.failed()) { if (result.failed()) {
TruncatedUserString<> name(wire_bytes.GetNameOrNull(&func, module)); WasmName name = wire_bytes.GetNameOrNull(func, module);
thrower->CompileError("Compiling function #%d:%.*s failed: %s @+%u", i, if (name.start() == nullptr) {
name.length(), name.start(), thrower->CompileError("Compiling function #%d failed: %s @+%u", i,
result.error().message().c_str(), result.error().message().c_str(),
result.error().offset()); result.error().offset());
} else {
TruncatedUserString<> name(wire_bytes.GetNameOrNull(func, module));
thrower->CompileError("Compiling function #%d:\"%.*s\" failed: %s @+%u",
i, name.length(), name.start(),
result.error().message().c_str(),
result.error().offset());
}
break; break;
} }
} }
...@@ -627,11 +595,12 @@ void CompileNativeModule(Isolate* isolate, ErrorThrower* thrower, ...@@ -627,11 +595,12 @@ void CompileNativeModule(Isolate* isolate, ErrorThrower* thrower,
if (compile_parallel) { if (compile_parallel) {
CompileInParallel(isolate, native_module); CompileInParallel(isolate, native_module);
} else { } else {
CompileSequentially(isolate, native_module, thrower); CompileSequentially(isolate, native_module);
} }
auto* compilation_state = Impl(native_module->compilation_state()); auto* compilation_state = Impl(native_module->compilation_state());
if (compilation_state->failed()) { if (compilation_state->failed()) {
thrower->CompileFailed(compilation_state->GetCompileError()); ValidateSequentially(isolate, native_module, thrower);
CHECK(thrower->error());
} }
} }
} }
...@@ -953,7 +922,7 @@ void AsyncCompileJob::FinishCompile() { ...@@ -953,7 +922,7 @@ void AsyncCompileJob::FinishCompile() {
FinishModule(); FinishModule();
} }
void AsyncCompileJob::AsyncCompileFailed(const WasmError& error) { void AsyncCompileJob::DecodeFailed(const WasmError& error) {
ErrorThrower thrower(isolate_, "WebAssembly.compile()"); ErrorThrower thrower(isolate_, "WebAssembly.compile()");
thrower.CompileFailed(error); thrower.CompileFailed(error);
// {job} keeps the {this} pointer alive. // {job} keeps the {this} pointer alive.
...@@ -962,6 +931,16 @@ void AsyncCompileJob::AsyncCompileFailed(const WasmError& error) { ...@@ -962,6 +931,16 @@ void AsyncCompileJob::AsyncCompileFailed(const WasmError& error) {
resolver_->OnCompilationFailed(thrower.Reify()); resolver_->OnCompilationFailed(thrower.Reify());
} }
void AsyncCompileJob::AsyncCompileFailed() {
ErrorThrower thrower(isolate_, "WebAssembly.compile()");
ValidateSequentially(isolate_, native_module_.get(), &thrower);
DCHECK(thrower.error());
// {job} keeps the {this} pointer alive.
std::shared_ptr<AsyncCompileJob> job =
isolate_->wasm_engine()->RemoveCompileJob(this);
resolver_->OnCompilationFailed(thrower.Reify());
}
void AsyncCompileJob::AsyncCompileSucceeded(Handle<WasmModuleObject> result) { void AsyncCompileJob::AsyncCompileSucceeded(Handle<WasmModuleObject> result) {
resolver_->OnCompilationSucceeded(result); resolver_->OnCompilationSucceeded(result);
} }
...@@ -986,7 +965,9 @@ class AsyncCompileJob::CompilationStateCallback { ...@@ -986,7 +965,9 @@ class AsyncCompileJob::CompilationStateCallback {
break; break;
case CompilationEvent::kFailedCompilation: { case CompilationEvent::kFailedCompilation: {
DCHECK(!last_event_.has_value()); DCHECK(!last_event_.has_value());
job_->DoSync<CompileFailed>(); if (job_->DecrementAndCheckFinisherCount()) {
job_->DoSync<CompileFailed>();
}
break; break;
} }
default: default:
...@@ -1173,8 +1154,8 @@ class AsyncCompileJob::DecodeFail : public CompileStep { ...@@ -1173,8 +1154,8 @@ class AsyncCompileJob::DecodeFail : public CompileStep {
void RunInForeground(AsyncCompileJob* job) override { void RunInForeground(AsyncCompileJob* job) override {
TRACE_COMPILE("(1b) Decoding failed.\n"); TRACE_COMPILE("(1b) Decoding failed.\n");
// {job_} is deleted in AsyncCompileFailed, therefore the {return}. // {job_} is deleted in DecodeFailed, therefore the {return}.
return job->AsyncCompileFailed(error_); return job->DecodeFailed(error_);
} }
}; };
...@@ -1234,11 +1215,10 @@ class AsyncCompileJob::CompileFailed : public CompileStep { ...@@ -1234,11 +1215,10 @@ class AsyncCompileJob::CompileFailed : public CompileStep {
private: private:
void RunInForeground(AsyncCompileJob* job) override { void RunInForeground(AsyncCompileJob* job) override {
TRACE_COMPILE("(3a) Compilation failed\n"); TRACE_COMPILE("(3a) Compilation failed\n");
DCHECK(job->native_module_->compilation_state()->failed());
WasmError error =
Impl(job->native_module_->compilation_state())->GetCompileError();
// {job_} is deleted in AsyncCompileFailed, therefore the {return}. // {job_} is deleted in AsyncCompileFailed, therefore the {return}.
return job->AsyncCompileFailed(error); return job->AsyncCompileFailed();
} }
}; };
...@@ -1271,6 +1251,7 @@ class AsyncCompileJob::CompileFinished : public CompileStep { ...@@ -1271,6 +1251,7 @@ class AsyncCompileJob::CompileFinished : public CompileStep {
private: private:
void RunInForeground(AsyncCompileJob* job) override { void RunInForeground(AsyncCompileJob* job) override {
TRACE_COMPILE("(3b) Compilation finished\n"); TRACE_COMPILE("(3b) Compilation finished\n");
DCHECK(!job->native_module_->compilation_state()->failed());
// Sample the generated code size when baseline compilation finished. // Sample the generated code size when baseline compilation finished.
job->native_module_->SampleCodeSize(job->isolate_->counters(), job->native_module_->SampleCodeSize(job->isolate_->counters(),
NativeModule::kAfterBaseline); NativeModule::kAfterBaseline);
...@@ -1452,7 +1433,11 @@ void AsyncStreamingProcessor::OnFinishedStream(OwnedVector<uint8_t> bytes) { ...@@ -1452,7 +1433,11 @@ void AsyncStreamingProcessor::OnFinishedStream(OwnedVector<uint8_t> bytes) {
job_->wire_bytes_ = ModuleWireBytes(bytes.as_vector()); job_->wire_bytes_ = ModuleWireBytes(bytes.as_vector());
job_->native_module_->SetWireBytes(std::move(bytes)); job_->native_module_->SetWireBytes(std::move(bytes));
if (needs_finish) { if (needs_finish) {
job_->FinishCompile(); if (job_->native_module_->compilation_state()->failed()) {
job_->AsyncCompileFailed();
} else {
job_->FinishCompile();
}
} }
} }
...@@ -1503,11 +1488,6 @@ CompilationStateImpl::CompilationStateImpl( ...@@ -1503,11 +1488,6 @@ CompilationStateImpl::CompilationStateImpl(
1, std::min(FLAG_wasm_num_compilation_tasks, 1, std::min(FLAG_wasm_num_compilation_tasks,
V8::GetCurrentPlatform()->NumberOfWorkerThreads()))) {} V8::GetCurrentPlatform()->NumberOfWorkerThreads()))) {}
CompilationStateImpl::~CompilationStateImpl() {
CompilationError* error = compile_error_.load(std::memory_order_acquire);
if (error != nullptr) delete error;
}
void CompilationStateImpl::AbortCompilation() { void CompilationStateImpl::AbortCompilation() {
background_compile_token_->Cancel(); background_compile_token_->Cancel();
// No more callbacks after abort. // No more callbacks after abort.
...@@ -1683,19 +1663,13 @@ void CompilationStateImpl::RestartBackgroundTasks() { ...@@ -1683,19 +1663,13 @@ void CompilationStateImpl::RestartBackgroundTasks() {
} }
} }
void CompilationStateImpl::SetError(uint32_t func_index, void CompilationStateImpl::SetError() {
const WasmError& error) { bool expected = false;
DCHECK(error.has_error()); if (!compile_failed_.compare_exchange_strong(expected, true,
std::unique_ptr<CompilationError> compile_error = std::memory_order_relaxed)) {
base::make_unique<CompilationError>(func_index, error); return; // Already failed before.
CompilationError* expected = nullptr; }
bool set = compile_error_.compare_exchange_strong(
expected, compile_error.get(), std::memory_order_acq_rel);
// Ignore all but the first error. If the previous value is not nullptr, just
// return (and free the allocated error).
if (!set) return;
// If set successfully, give up ownership.
compile_error.release();
base::MutexGuard callbacks_guard(&callbacks_mutex_); base::MutexGuard callbacks_guard(&callbacks_mutex_);
for (auto& callback : callbacks_) { for (auto& callback : callbacks_) {
callback(CompilationEvent::kFailedCompilation); callback(CompilationEvent::kFailedCompilation);
......
...@@ -109,7 +109,8 @@ class AsyncCompileJob { ...@@ -109,7 +109,8 @@ class AsyncCompileJob {
void FinishCompile(); void FinishCompile();
void AsyncCompileFailed(const WasmError&); void DecodeFailed(const WasmError&);
void AsyncCompileFailed();
void AsyncCompileSucceeded(Handle<WasmModuleObject> result); void AsyncCompileSucceeded(Handle<WasmModuleObject> result);
...@@ -154,7 +155,7 @@ class AsyncCompileJob { ...@@ -154,7 +155,7 @@ class AsyncCompileJob {
// Copy of the module wire bytes, moved into the {native_module_} on its // Copy of the module wire bytes, moved into the {native_module_} on its
// creation. // creation.
std::unique_ptr<byte[]> bytes_copy_; std::unique_ptr<byte[]> bytes_copy_;
// Reference to the wire bytes (hold in {bytes_copy_} or as part of // Reference to the wire bytes (held in {bytes_copy_} or as part of
// {native_module_}). // {native_module_}).
ModuleWireBytes wire_bytes_; ModuleWireBytes wire_bytes_;
Handle<Context> native_context_; Handle<Context> native_context_;
......
...@@ -66,7 +66,7 @@ assertPromiseResult(async function badFunctionInTheMiddle() { ...@@ -66,7 +66,7 @@ assertPromiseResult(async function badFunctionInTheMiddle() {
let buffer = builder.toBuffer(); let buffer = builder.toBuffer();
await assertCompileError( await assertCompileError(
buffer, buffer,
'Compiling wasm function \"bad\" failed: ' + 'Compiling function #10:\"bad\" failed: ' +
'expected 1 elements on the stack for fallthru to @1, found 0 @+94'); 'expected 1 elements on the stack for fallthru to @1, found 0 @+94');
}()); }());
......
...@@ -55,7 +55,7 @@ function assertConversionError(bytes, imports, msg) { ...@@ -55,7 +55,7 @@ function assertConversionError(bytes, imports, msg) {
(function TestValidationError() { (function TestValidationError() {
print(arguments.callee.name); print(arguments.callee.name);
let f_error = msg => 'Compiling wasm function "f" failed: ' + msg; let f_error = msg => 'Compiling function #0:"f" failed: ' + msg;
assertCompileError( assertCompileError(
builder().addFunction('f', kSig_i_v).end().toBuffer(), builder().addFunction('f', kSig_i_v).end().toBuffer(),
f_error('function body must end with "end" opcode @+24')); f_error('function body must end with "end" opcode @+24'));
...@@ -176,7 +176,6 @@ function import_error(index, module, func, msg) { ...@@ -176,7 +176,6 @@ function import_error(index, module, func, msg) {
assertConversionError(buffer, {}, kTrapMsgs[kTrapTypeError]); assertConversionError(buffer, {}, kTrapMsgs[kTrapTypeError]);
})(); })();
(function InternalDebugTrace() { (function InternalDebugTrace() {
print(arguments.callee.name); print(arguments.callee.name);
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
...@@ -192,3 +191,18 @@ function import_error(index, module, func, msg) { ...@@ -192,3 +191,18 @@ function import_error(index, module, func, msg) {
}).exports.main; }).exports.main;
main(); main();
})(); })();
(function TestMultipleCorruptFunctions() {
print(arguments.callee.name);
// Generate a module with multiple corrupt functions. The error message must
// be deterministic.
var builder = new WasmModuleBuilder();
var sig = builder.addType(kSig_v_v);
for (let i = 0; i < 10; ++i) {
builder.addFunction('f' + i, sig).addBody([kExprEnd]);
}
assertCompileError(
builder.toBuffer(),
'Compiling function #0:"f0" failed: ' +
'trailing code after function end @+33');
})();
...@@ -51,7 +51,7 @@ checkExports('☺☺mul☺☺', '☺☺mul☺☺', '☺☺add☺☺', '☺☺add ...@@ -51,7 +51,7 @@ checkExports('☺☺mul☺☺', '☺☺mul☺☺', '☺☺add☺☺', '☺☺add
builder.addFunction('three snowmen: ☃☃☃', kSig_i_v).addBody([]).exportFunc(); builder.addFunction('three snowmen: ☃☃☃', kSig_i_v).addBody([]).exportFunc();
assertThrows( assertThrows(
() => builder.instantiate(), WebAssembly.CompileError, () => builder.instantiate(), WebAssembly.CompileError,
/Compiling wasm function "three snowmen: ☃☃☃" failed: /); /Compiling function #0:"three snowmen: ☃☃☃" failed: /);
})(); })();
(function errorMessageUnicodeInImportModuleName() { (function errorMessageUnicodeInImportModuleName() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment