blob: c5da2f7d3896dd3b8235860bceadabb56b1f22c0 [file] [log] [blame]
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "vm/source_map_resolver.h"
#include "base/flatbuffer_util.h"
#include "base/status.h"
#include "schemas/source_map_def_generated.h"
namespace iree {
namespace vm {
namespace {
Status PrintLocation(const SourceMapResolver& source_map,
const FunctionSourceMapDef& function_source_map,
const LocationDef& location, std::ostream* stream);
Status PrintFileLocation(const SourceMapResolver& source_map,
const FunctionSourceMapDef& function_source_map,
const FileLocationDef& location,
std::ostream* stream) {
ASSIGN_OR_RETURN(auto filename,
source_map.GetUniqueString(location.filename()));
*stream << filename << ":" << location.line() << ":" << location.column();
return OkStatus();
}
Status PrintNameLocation(const SourceMapResolver& source_map,
const FunctionSourceMapDef& function_source_map,
const NameLocationDef& location,
std::ostream* stream) {
ASSIGN_OR_RETURN(auto name, source_map.GetUniqueString(location.name()));
*stream << "\"" << name << "\"";
return OkStatus();
}
Status PrintCallSiteLocation(const SourceMapResolver& source_map,
const FunctionSourceMapDef& function_source_map,
const CallSiteLocationDef& location,
std::ostream* stream) {
*stream << "(callsites todo)";
return OkStatus();
}
Status PrintFusedLocation(const SourceMapResolver& source_map,
const FunctionSourceMapDef& function_source_map,
const FusedLocationDef& location,
std::ostream* stream) {
*stream << "fused[";
if (location.locations()) {
for (int i = 0; i < location.locations()->size(); ++i) {
if (i > 0) *stream << ", ";
int location_ordinal = location.locations()->Get(i);
const auto& child_location =
*function_source_map.location_table()->Get(location_ordinal);
RETURN_IF_ERROR(PrintLocation(source_map, function_source_map,
child_location, stream));
}
}
*stream << "]";
return OkStatus();
}
Status PrintLocation(const SourceMapResolver& source_map,
const FunctionSourceMapDef& function_source_map,
const LocationDef& location, std::ostream* stream) {
switch (location.location_union_type()) {
case LocationDefUnion::FileLocationDef:
return PrintFileLocation(source_map, function_source_map,
*location.location_union_as_FileLocationDef(),
stream);
case LocationDefUnion::NameLocationDef:
return PrintNameLocation(source_map, function_source_map,
*location.location_union_as_NameLocationDef(),
stream);
case LocationDefUnion::CallSiteLocationDef:
return PrintCallSiteLocation(
source_map, function_source_map,
*location.location_union_as_CallSiteLocationDef(), stream);
case LocationDefUnion::FusedLocationDef:
return PrintFusedLocation(source_map, function_source_map,
*location.location_union_as_FusedLocationDef(),
stream);
default:
return UnimplementedErrorBuilder(IREE_LOC)
<< "Unhandled location type "
<< static_cast<int>(location.location_union_type());
}
}
} // namespace
// static
SourceMapResolver SourceMapResolver::FromModule(const ModuleDef& module_def) {
if (module_def.source_map()) {
return SourceMapResolver{*module_def.source_map()};
}
return {};
}
StatusOr<absl::string_view> SourceMapResolver::GetUniqueString(
int string_index) const {
if (empty()) {
return NotFoundErrorBuilder(IREE_LOC) << "No source map present";
}
const auto* string_table = source_map_def_->string_table();
if (string_table && string_table->size() > string_index) {
return WrapString(string_table->Get(string_index));
}
return NotFoundErrorBuilder(IREE_LOC)
<< "String index " << string_index << " not present in string table";
}
StatusOr<const FunctionSourceMapDef*> SourceMapResolver::GetFunctionSourceMap(
int function_ordinal) const {
if (empty()) {
return NotFoundErrorBuilder(IREE_LOC) << "No source map present";
}
const auto* function_table = source_map_def_->function_table();
if (function_table && function_table->size() > function_ordinal) {
const auto* function_source_map = function_table->Get(function_ordinal);
if (function_source_map && function_source_map->location_table() &&
function_source_map->bytecode_map()) {
return function_source_map;
}
}
return NotFoundErrorBuilder(IREE_LOC)
<< "Function ordinal " << function_ordinal
<< " source map not present in function table";
}
absl::optional<rt::SourceLocation> SourceMapResolver::ResolveFunctionOffset(
const rt::Function& function, rt::SourceOffset offset) {
if (empty()) return absl::nullopt;
auto function_source_map_or = GetFunctionSourceMap(function.ordinal());
if (!function_source_map_or.ok()) {
return absl::nullopt;
}
const auto* function_source_map = function_source_map_or.ValueOrDie();
const auto* bytecode_map = function_source_map->bytecode_map();
if (!bytecode_map) return absl::nullopt;
// TODO(benvanik): allow fuzzy offset matching/table sparsity.
int location_ordinal = -1;
for (const auto* map_loc : *bytecode_map) {
if (map_loc->offset() == offset) {
location_ordinal = map_loc->location();
break;
}
}
if (location_ordinal == -1) {
return absl::nullopt;
}
return rt::SourceLocation(this,
{
reinterpret_cast<uint64_t>(function_source_map),
static_cast<uint64_t>(location_ordinal),
});
}
void SourceMapResolver::PrintSourceLocation(
rt::SourceResolverArgs resolver_args, std::ostream* stream) const {
if (empty()) {
*stream << "<unknown>";
return;
}
auto* function_source_map =
reinterpret_cast<FunctionSourceMapDef*>(resolver_args[0]);
int location_ordinal = static_cast<int>(resolver_args[1]);
const auto& location =
*function_source_map->location_table()->Get(location_ordinal);
auto status = PrintLocation(*this, *function_source_map, location, stream);
if (!status.ok()) {
*stream << status;
}
}
} // namespace vm
} // namespace iree