[WebAssembly] Write minimal types section

Don't include type signatures that are not referenced by
some relocation.

We don't include this in the -gc-sections settings since
we are always building the type section from scratch,
just like we do the table elements.

In the future we might want to unify the relocation
processing which is currently done once for gc-sections
and then again for building the sympathetic type and
table sections.

Differential Revision: https://reviews.llvm.org/D42747

llvm-svn: 323931
This commit is contained in:
Sam Clegg
2018-01-31 23:48:14 +00:00
parent 5ec448516d
commit 8f6d2def2b
7 changed files with 93 additions and 50 deletions

View File

@@ -43,21 +43,21 @@ define void @call_ptr(i64 (i64)* %arg) {
; CHECK-NEXT: ReturnType: I64
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: ReturnType: NORESULT
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Index: 2
; CHECK-NEXT: ReturnType: I32
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Index: 3
; CHECK-NEXT: ReturnType: NORESULT
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - I32
; CHECK-NEXT: - Index: 4
; CHECK-NEXT: - Index: 2
; CHECK-NEXT: ReturnType: I64
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - I64
; CHECK-NEXT: - Index: 3
; CHECK-NEXT: ReturnType: NORESULT
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Index: 4
; CHECK-NEXT: ReturnType: NORESULT
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - I32
; CHECK-NEXT: - Type: FUNCTION
; CHECK-NEXT: FunctionTypes: [ 0, 1, 2, 2, 3, 1 ]
; CHECK-NEXT: FunctionTypes: [ 0, 3, 1, 1, 4, 3 ]
; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables:
; CHECK-NEXT: - ElemType: ANYFUNC
@@ -120,16 +120,16 @@ define void @call_ptr(i64 (i64)* %arg) {
; CHECK-NEXT: Locals:
; CHECK-NEXT: - Type: I32
; CHECK-NEXT: Count: 1
; CHECK-NEXT: Body: 4100280284888080002100410028028088808000118080808000001A2000118280808000001A0B
; CHECK-NEXT: Body: 4100280284888080002100410028028088808000118080808000001A2000118180808000001A0B
; CHECK-NEXT: - Index: 2
; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 41020B
; CHECK-NEXT: - Index: 3
; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 410028028888808000118280808000001A41000B
; CHECK-NEXT: Body: 410028028888808000118180808000001A41000B
; CHECK-NEXT: - Index: 4
; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 42012000118480808000001A0B
; CHECK-NEXT: Body: 42012000118280808000001A0B
; CHECK-NEXT: - Index: 5
; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 0B

View File

@@ -7,12 +7,12 @@
target triple = "wasm32-unknown-unknown-wasm"
@unused_data = hidden global i32 1, align 4
@unused_data = hidden global i64 1, align 4
@used_data = hidden global i32 2, align 4
define hidden i32 @unused_function() {
%1 = load i32, i32* @unused_data, align 4
ret i32 %1
define hidden i64 @unused_function() {
%1 = load i64, i64* @unused_data, align 4
ret i64 %1
}
define hidden i32 @used_function() {
@@ -27,6 +27,17 @@ entry:
}
; RUN: obj2yaml %t1.wasm | FileCheck %s
; CHECK: - Type: TYPE
; CHECK-NEXT: Signatures:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: ReturnType: I32
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: ReturnType: NORESULT
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Type: FUNCTION
; CHECK: - Type: DATA
; CHECK-NEXT: Segments:
; CHECK-NEXT: - SectionOffset: 7
@@ -51,6 +62,20 @@ entry:
; RUN: lld -flavor wasm -print-gc-sections --no-gc-sections -o %t1.no-gc.wasm %t.o
; RUN: obj2yaml %t1.no-gc.wasm | FileCheck %s -check-prefix=NO-GC
; NO-GC: - Type: TYPE
; NO-GC-NEXT: Signatures:
; NO-GC-NEXT: - Index: 0
; NO-GC-NEXT: ReturnType: I64
; NO-GC-NEXT: ParamTypes:
; NO-GC-NEXT: - Index: 1
; NO-GC-NEXT: ReturnType: I32
; NO-GC-NEXT: ParamTypes:
; NO-GC-NEXT: - Index: 2
; NO-GC-NEXT: ReturnType: NORESULT
; NO-GC-NEXT: ParamTypes:
; NO-GC-NEXT: - Type: FUNCTION
; NO-GC: - Type: DATA
; NO-GC-NEXT: Segments:
; NO-GC-NEXT: - SectionOffset: 7
@@ -58,10 +83,10 @@ entry:
; NO-GC-NEXT: Offset:
; NO-GC-NEXT: Opcode: I32_CONST
; NO-GC-NEXT: Value: 1024
; NO-GC-NEXT: Content: '0100000002000000'
; NO-GC-NEXT: Content: '010000000000000002000000'
; NO-GC-NEXT: - Type: CUSTOM
; NO-GC-NEXT: Name: linking
; NO-GC-NEXT: DataSize: 8
; NO-GC-NEXT: DataSize: 12
; NO-GC-NEXT: - Type: CUSTOM
; NO-GC-NEXT: Name: name
; NO-GC-NEXT: FunctionNames:

View File

@@ -38,34 +38,34 @@ entry:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: ReturnType: NORESULT
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: ReturnType: NORESULT
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - I32
; CHECK-NEXT: - Index: 2
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: ReturnType: I32
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Index: 2
; CHECK-NEXT: ReturnType: NORESULT
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Type: IMPORT
; CHECK-NEXT: Imports:
; CHECK-NEXT: - Module: env
; CHECK-NEXT: Field: puts
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: SigIndex: 1
; CHECK-NEXT: SigIndex: 0
; CHECK-NEXT: - Module: env
; CHECK-NEXT: Field: foo_import
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: SigIndex: 2
; CHECK-NEXT: SigIndex: 1
; CHECK-NEXT: - Module: env
; CHECK-NEXT: Field: bar_import
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: SigIndex: 2
; CHECK-NEXT: SigIndex: 1
; CHECK-NEXT: - Module: env
; CHECK-NEXT: Field: data_import
; CHECK-NEXT: Kind: GLOBAL
; CHECK-NEXT: GlobalType: I32
; CHECK-NEXT: GlobalMutable: false
; CHECK-NEXT: - Type: FUNCTION
; CHECK-NEXT: FunctionTypes: [ 0, 2, 2 ]
; CHECK-NEXT: FunctionTypes: [ 2, 1, 1 ]
; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables:
; CHECK-NEXT: - ElemType: ANYFUNC

View File

@@ -59,14 +59,14 @@ public:
bool Discarded = false;
std::vector<OutputRelocation> OutRelocations;
const ObjFile *File;
ObjFile *File;
// The garbage collector sets sections' Live bits.
// If GC is disabled, all sections are considered live by default.
unsigned Live : 1;
protected:
InputChunk(const ObjFile *F, Kind K)
InputChunk(ObjFile *F, Kind K)
: File(F), Live(!Config->GcSections), SectionKind(K) {}
virtual ~InputChunk() = default;
void calcRelocations();
@@ -88,7 +88,7 @@ protected:
// each global variable.
class InputSegment : public InputChunk {
public:
InputSegment(const WasmSegment &Seg, const ObjFile *F)
InputSegment(const WasmSegment &Seg, ObjFile *F)
: InputChunk(F, InputChunk::DataSegment), Segment(Seg) {}
static bool classof(const InputChunk *C) { return C->kind() == DataSegment; }
@@ -127,7 +127,7 @@ protected:
class InputFunction : public InputChunk {
public:
InputFunction(const WasmSignature &S, const WasmFunction *Func,
const ObjFile *F)
ObjFile *F)
: InputChunk(F, InputChunk::Function), Signature(S), Function(Func) {}
static bool classof(const InputChunk *C) {

View File

@@ -63,6 +63,7 @@ uint32_t ObjFile::relocateFunctionIndex(uint32_t Original) const {
}
uint32_t ObjFile::relocateTypeIndex(uint32_t Original) const {
assert(TypeIsUsed[Original]);
return TypeMap[Original];
}
@@ -149,6 +150,9 @@ void ObjFile::parse() {
DataSection = &Section;
}
TypeMap.resize(getWasmObj()->types().size());
TypeIsUsed.resize(getWasmObj()->types().size(), false);
initializeSymbols();
}

View File

@@ -101,6 +101,7 @@ public:
const WasmSection *DataSection = nullptr;
std::vector<uint32_t> TypeMap;
std::vector<bool> TypeIsUsed;
std::vector<InputSegment *> Segments;
std::vector<InputFunction *> Functions;

View File

@@ -689,15 +689,23 @@ uint32_t Writer::registerType(const WasmSignature &Sig) {
}
void Writer::calculateTypes() {
// The output type section is the union of the following sets:
// 1. Any signature used in the TYPE relocation
// 2. The signatures of all imported functions
// 3. The signatures of all defined functions
for (ObjFile *File : Symtab->ObjectFiles) {
File->TypeMap.reserve(File->getWasmObj()->types().size());
for (const WasmSignature &Sig : File->getWasmObj()->types())
File->TypeMap.push_back(registerType(Sig));
ArrayRef<WasmSignature> Types = File->getWasmObj()->types();
for (uint32_t I = 0; I < Types.size(); I++)
if (File->TypeIsUsed[I])
File->TypeMap[I] = registerType(Types[I]);
}
for (Symbol *Sym : Symtab->getSymbols())
if (Sym->isFunction())
registerType(Sym->getFunctionType());
for (const Symbol *Sym : ImportedFunctions)
registerType(Sym->getFunctionType());
for (const InputFunction *F : DefinedFunctions)
registerType(F->Signature);
}
void Writer::assignIndexes() {
@@ -746,25 +754,30 @@ void Writer::assignIndexes() {
}
for (ObjFile *File : Symtab->ObjectFiles) {
DEBUG(dbgs() << "Table Indexes: " << File->getName() << "\n");
auto HandleTableRelocs = [&](InputChunk *Chunk) {
DEBUG(dbgs() << "Handle relocs: " << File->getName() << "\n");
auto HandleRelocs = [&](InputChunk *Chunk) {
if (Chunk->Discarded)
return;
ArrayRef<WasmSignature> Types = File->getWasmObj()->types();
for (const WasmRelocation& Reloc : Chunk->getRelocations()) {
if (Reloc.Type != R_WEBASSEMBLY_TABLE_INDEX_I32 &&
Reloc.Type != R_WEBASSEMBLY_TABLE_INDEX_SLEB)
continue;
Symbol *Sym = File->getFunctionSymbol(Reloc.Index);
if (Sym->hasTableIndex() || !Sym->hasOutputIndex())
continue;
Sym->setTableIndex(TableIndex++);
IndirectFunctions.emplace_back(Sym);
if (Reloc.Type == R_WEBASSEMBLY_TABLE_INDEX_I32 ||
Reloc.Type == R_WEBASSEMBLY_TABLE_INDEX_SLEB) {
Symbol *Sym = File->getFunctionSymbol(Reloc.Index);
if (Sym->hasTableIndex() || !Sym->hasOutputIndex())
continue;
Sym->setTableIndex(TableIndex++);
IndirectFunctions.emplace_back(Sym);
} else if (Reloc.Type == R_WEBASSEMBLY_TYPE_INDEX_LEB) {
Chunk->File->TypeMap[Reloc.Index] = registerType(Types[Reloc.Index]);
Chunk->File->TypeIsUsed[Reloc.Index] = true;
}
}
};
for (InputFunction* Function : File->Functions)
HandleTableRelocs(Function);
HandleRelocs(Function);
for (InputSegment* Segment : File->Segments)
HandleTableRelocs(Segment);
HandleRelocs(Segment);
}
}
@@ -858,8 +871,6 @@ void Writer::calculateInitFunctions() {
}
void Writer::run() {
log("-- calculateTypes");
calculateTypes();
log("-- calculateImports");
calculateImports();
log("-- assignIndexes");
@@ -870,6 +881,8 @@ void Writer::run() {
calculateInitFunctions();
if (!Config->Relocatable)
createCtorFunction();
log("-- calculateTypes");
calculateTypes();
if (errorHandler().Verbose) {
log("Defined Functions: " + Twine(DefinedFunctions.size()));