compiler: fix "fragment covers entire variable" bug
This bug could sometimes be triggered by syscall/js code it seems. But it's a generic bug, not specific to WebAssembly.
Этот коммит содержится в:
родитель
4be9802d26
коммит
b44d41d9ec
6 изменённых файлов: 45 добавлений и 16 удалений
|
@ -58,10 +58,10 @@ func (b *builder) createCall(fn llvm.Value, args []llvm.Value, name string) llvm
|
||||||
|
|
||||||
// Expand an argument type to a list that can be used in a function call
|
// Expand an argument type to a list that can be used in a function call
|
||||||
// parameter list.
|
// parameter list.
|
||||||
func expandFormalParamType(t llvm.Type, name string, goType types.Type) []paramInfo {
|
func (c *compilerContext) expandFormalParamType(t llvm.Type, name string, goType types.Type) []paramInfo {
|
||||||
switch t.TypeKind() {
|
switch t.TypeKind() {
|
||||||
case llvm.StructTypeKind:
|
case llvm.StructTypeKind:
|
||||||
fieldInfos := flattenAggregateType(t, name, goType)
|
fieldInfos := c.flattenAggregateType(t, name, goType)
|
||||||
if len(fieldInfos) <= maxFieldsPerParam {
|
if len(fieldInfos) <= maxFieldsPerParam {
|
||||||
return fieldInfos
|
return fieldInfos
|
||||||
} else {
|
} else {
|
||||||
|
@ -105,7 +105,7 @@ func (b *builder) expandFormalParamOffsets(t llvm.Type) []uint64 {
|
||||||
func (b *builder) expandFormalParam(v llvm.Value) []llvm.Value {
|
func (b *builder) expandFormalParam(v llvm.Value) []llvm.Value {
|
||||||
switch v.Type().TypeKind() {
|
switch v.Type().TypeKind() {
|
||||||
case llvm.StructTypeKind:
|
case llvm.StructTypeKind:
|
||||||
fieldInfos := flattenAggregateType(v.Type(), "", nil)
|
fieldInfos := b.flattenAggregateType(v.Type(), "", nil)
|
||||||
if len(fieldInfos) <= maxFieldsPerParam {
|
if len(fieldInfos) <= maxFieldsPerParam {
|
||||||
fields := b.flattenAggregate(v)
|
fields := b.flattenAggregate(v)
|
||||||
if len(fields) != len(fieldInfos) {
|
if len(fields) != len(fieldInfos) {
|
||||||
|
@ -124,12 +124,15 @@ func (b *builder) expandFormalParam(v llvm.Value) []llvm.Value {
|
||||||
|
|
||||||
// Try to flatten a struct type to a list of types. Returns a 1-element slice
|
// Try to flatten a struct type to a list of types. Returns a 1-element slice
|
||||||
// with the passed in type if this is not possible.
|
// with the passed in type if this is not possible.
|
||||||
func flattenAggregateType(t llvm.Type, name string, goType types.Type) []paramInfo {
|
func (c *compilerContext) flattenAggregateType(t llvm.Type, name string, goType types.Type) []paramInfo {
|
||||||
typeFlags := getTypeFlags(goType)
|
typeFlags := getTypeFlags(goType)
|
||||||
switch t.TypeKind() {
|
switch t.TypeKind() {
|
||||||
case llvm.StructTypeKind:
|
case llvm.StructTypeKind:
|
||||||
paramInfos := make([]paramInfo, 0, t.StructElementTypesCount())
|
var paramInfos []paramInfo
|
||||||
for i, subfield := range t.StructElementTypes() {
|
for i, subfield := range t.StructElementTypes() {
|
||||||
|
if c.targetData.TypeAllocSize(subfield) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
suffix := strconv.Itoa(i)
|
suffix := strconv.Itoa(i)
|
||||||
if goType != nil {
|
if goType != nil {
|
||||||
// Try to come up with a good suffix for this struct field,
|
// Try to come up with a good suffix for this struct field,
|
||||||
|
@ -152,7 +155,7 @@ func flattenAggregateType(t llvm.Type, name string, goType types.Type) []paramIn
|
||||||
suffix = []string{"context", "funcptr"}[i]
|
suffix = []string{"context", "funcptr"}[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
subInfos := flattenAggregateType(subfield, name+"."+suffix, extractSubfield(goType, i))
|
subInfos := c.flattenAggregateType(subfield, name+"."+suffix, extractSubfield(goType, i))
|
||||||
for i := range subInfos {
|
for i := range subInfos {
|
||||||
subInfos[i].flags |= typeFlags
|
subInfos[i].flags |= typeFlags
|
||||||
}
|
}
|
||||||
|
@ -218,8 +221,11 @@ func extractSubfield(t types.Type, field int) types.Type {
|
||||||
func (c *compilerContext) flattenAggregateTypeOffsets(t llvm.Type) []uint64 {
|
func (c *compilerContext) flattenAggregateTypeOffsets(t llvm.Type) []uint64 {
|
||||||
switch t.TypeKind() {
|
switch t.TypeKind() {
|
||||||
case llvm.StructTypeKind:
|
case llvm.StructTypeKind:
|
||||||
fields := make([]uint64, 0, t.StructElementTypesCount())
|
var fields []uint64
|
||||||
for fieldIndex, field := range t.StructElementTypes() {
|
for fieldIndex, field := range t.StructElementTypes() {
|
||||||
|
if c.targetData.TypeAllocSize(field) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
suboffsets := c.flattenAggregateTypeOffsets(field)
|
suboffsets := c.flattenAggregateTypeOffsets(field)
|
||||||
offset := c.targetData.ElementOffset(t, fieldIndex)
|
offset := c.targetData.ElementOffset(t, fieldIndex)
|
||||||
for i := range suboffsets {
|
for i := range suboffsets {
|
||||||
|
@ -238,8 +244,11 @@ func (c *compilerContext) flattenAggregateTypeOffsets(t llvm.Type) []uint64 {
|
||||||
func (b *builder) flattenAggregate(v llvm.Value) []llvm.Value {
|
func (b *builder) flattenAggregate(v llvm.Value) []llvm.Value {
|
||||||
switch v.Type().TypeKind() {
|
switch v.Type().TypeKind() {
|
||||||
case llvm.StructTypeKind:
|
case llvm.StructTypeKind:
|
||||||
fields := make([]llvm.Value, 0, v.Type().StructElementTypesCount())
|
var fields []llvm.Value
|
||||||
for i := range v.Type().StructElementTypes() {
|
for i, field := range v.Type().StructElementTypes() {
|
||||||
|
if b.targetData.TypeAllocSize(field) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
subfield := b.CreateExtractValue(v, i, "")
|
subfield := b.CreateExtractValue(v, i, "")
|
||||||
subfields := b.flattenAggregate(subfield)
|
subfields := b.flattenAggregate(subfield)
|
||||||
fields = append(fields, subfields...)
|
fields = append(fields, subfields...)
|
||||||
|
@ -266,10 +275,13 @@ func (b *builder) collapseFormalParam(t llvm.Type, fields []llvm.Value) llvm.Val
|
||||||
func (b *builder) collapseFormalParamInternal(t llvm.Type, fields []llvm.Value) (llvm.Value, []llvm.Value) {
|
func (b *builder) collapseFormalParamInternal(t llvm.Type, fields []llvm.Value) (llvm.Value, []llvm.Value) {
|
||||||
switch t.TypeKind() {
|
switch t.TypeKind() {
|
||||||
case llvm.StructTypeKind:
|
case llvm.StructTypeKind:
|
||||||
flattened := flattenAggregateType(t, "", nil)
|
flattened := b.flattenAggregateType(t, "", nil)
|
||||||
if len(flattened) <= maxFieldsPerParam {
|
if len(flattened) <= maxFieldsPerParam {
|
||||||
value := llvm.ConstNull(t)
|
value := llvm.ConstNull(t)
|
||||||
for i, subtyp := range t.StructElementTypes() {
|
for i, subtyp := range t.StructElementTypes() {
|
||||||
|
if b.targetData.TypeAllocSize(subtyp) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
structField, remaining := b.collapseFormalParamInternal(subtyp, fields)
|
structField, remaining := b.collapseFormalParamInternal(subtyp, fields)
|
||||||
fields = remaining
|
fields = remaining
|
||||||
value = b.CreateInsertValue(value, structField, i, "")
|
value = b.CreateInsertValue(value, structField, i, "")
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
// Version of the compiler pacakge. Must be incremented each time the compiler
|
// Version of the compiler pacakge. Must be incremented each time the compiler
|
||||||
// package changes in a way that affects the generated LLVM module.
|
// package changes in a way that affects the generated LLVM module.
|
||||||
// This version is independent of the TinyGo version number.
|
// This version is independent of the TinyGo version number.
|
||||||
const Version = 5 // last change: add method set to interface types
|
const Version = 6 // last change: fix issue 1304
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
llvm.InitializeAllTargets()
|
llvm.InitializeAllTargets()
|
||||||
|
@ -829,7 +829,7 @@ func (b *builder) createFunction() {
|
||||||
for _, param := range b.fn.Params {
|
for _, param := range b.fn.Params {
|
||||||
llvmType := b.getLLVMType(param.Type())
|
llvmType := b.getLLVMType(param.Type())
|
||||||
fields := make([]llvm.Value, 0, 1)
|
fields := make([]llvm.Value, 0, 1)
|
||||||
for _, info := range expandFormalParamType(llvmType, param.Name(), param.Type()) {
|
for _, info := range b.expandFormalParamType(llvmType, param.Name(), param.Type()) {
|
||||||
param := b.llvmFn.Param(llvmParamIndex)
|
param := b.llvmFn.Param(llvmParamIndex)
|
||||||
param.SetName(info.name)
|
param.SetName(info.name)
|
||||||
fields = append(fields, param)
|
fields = append(fields, param)
|
||||||
|
|
|
@ -124,13 +124,13 @@ func (c *compilerContext) getRawFuncType(typ *types.Signature) llvm.Type {
|
||||||
// The receiver is not an interface, but a i8* type.
|
// The receiver is not an interface, but a i8* type.
|
||||||
recv = c.i8ptrType
|
recv = c.i8ptrType
|
||||||
}
|
}
|
||||||
for _, info := range expandFormalParamType(recv, "", nil) {
|
for _, info := range c.expandFormalParamType(recv, "", nil) {
|
||||||
paramTypes = append(paramTypes, info.llvmType)
|
paramTypes = append(paramTypes, info.llvmType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i := 0; i < typ.Params().Len(); i++ {
|
for i := 0; i < typ.Params().Len(); i++ {
|
||||||
subType := c.getLLVMType(typ.Params().At(i).Type())
|
subType := c.getLLVMType(typ.Params().At(i).Type())
|
||||||
for _, info := range expandFormalParamType(subType, "", nil) {
|
for _, info := range c.expandFormalParamType(subType, "", nil) {
|
||||||
paramTypes = append(paramTypes, info.llvmType)
|
paramTypes = append(paramTypes, info.llvmType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -456,7 +456,7 @@ func (c *compilerContext) getInterfaceInvokeWrapper(fn *ssa.Function, llvmFn llv
|
||||||
// Get the expanded receiver type.
|
// Get the expanded receiver type.
|
||||||
receiverType := c.getLLVMType(fn.Signature.Recv().Type())
|
receiverType := c.getLLVMType(fn.Signature.Recv().Type())
|
||||||
var expandedReceiverType []llvm.Type
|
var expandedReceiverType []llvm.Type
|
||||||
for _, info := range expandFormalParamType(receiverType, "", nil) {
|
for _, info := range c.expandFormalParamType(receiverType, "", nil) {
|
||||||
expandedReceiverType = append(expandedReceiverType, info.llvmType)
|
expandedReceiverType = append(expandedReceiverType, info.llvmType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ func (c *compilerContext) getFunction(fn *ssa.Function) llvm.Value {
|
||||||
var paramInfos []paramInfo
|
var paramInfos []paramInfo
|
||||||
for _, param := range getParams(fn.Signature) {
|
for _, param := range getParams(fn.Signature) {
|
||||||
paramType := c.getLLVMType(param.Type())
|
paramType := c.getLLVMType(param.Type())
|
||||||
paramFragmentInfos := expandFormalParamType(paramType, param.Name(), param.Type())
|
paramFragmentInfos := c.expandFormalParamType(paramType, param.Name(), param.Type())
|
||||||
paramInfos = append(paramInfos, paramFragmentInfos...)
|
paramInfos = append(paramInfos, paramFragmentInfos...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
17
testdata/calls.go
предоставленный
17
testdata/calls.go
предоставленный
|
@ -74,6 +74,14 @@ func main() {
|
||||||
//Test deferred builtins
|
//Test deferred builtins
|
||||||
testDeferBuiltinClose()
|
testDeferBuiltinClose()
|
||||||
testDeferBuiltinDelete()
|
testDeferBuiltinDelete()
|
||||||
|
|
||||||
|
// Check for issue 1304.
|
||||||
|
// There are two fields in this struct, one of which is zero-length so the
|
||||||
|
// other covers the entire struct. This led to a verification error for
|
||||||
|
// debug info, which used DW_OP_LLVM_fragment for a field that practically
|
||||||
|
// covered the entire variable.
|
||||||
|
var x issue1304
|
||||||
|
x.call()
|
||||||
}
|
}
|
||||||
|
|
||||||
func runFunc(f func(int), arg int) {
|
func runFunc(f func(int), arg int) {
|
||||||
|
@ -211,3 +219,12 @@ func foo(bar *Bar) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type issue1304 struct {
|
||||||
|
a [0]int // zero-length field
|
||||||
|
b int // field 'b' covers entire struct
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x issue1304) call() {
|
||||||
|
// nothing to do
|
||||||
|
}
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче