summaryrefslogtreecommitdiffhomepage
path: root/tools/go_marshal/marshal/marshal.go
blob: cb21662529680f3e52e764b9efaf7acc529a394f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
// Copyright 2019 The gVisor Authors.
//
// 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
//
//     http://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.

// Package marshal defines the Marshallable interface for
// serialize/deserializing go data structures to/from memory, according to the
// Linux ABI.
//
// Implementations of this interface are typically automatically generated by
// tools/go_marshal. See the go_marshal README for details.
package marshal

import (
	"io"

	"gvisor.dev/gvisor/pkg/usermem"
)

// Task provides a subset of kernel.Task, used in marshalling. We don't import
// the kernel package directly to avoid circular dependency.
type Task interface {
	// CopyScratchBuffer provides a task goroutine-local scratch buffer. See
	// kernel.CopyScratchBuffer.
	CopyScratchBuffer(size int) []byte

	// CopyOutBytes writes the contents of b to the task's memory. See
	// kernel.CopyOutBytes.
	CopyOutBytes(addr usermem.Addr, b []byte) (int, error)

	// CopyInBytes reads the contents of the task's memory to b. See
	// kernel.CopyInBytes.
	CopyInBytes(addr usermem.Addr, b []byte) (int, error)
}

// Marshallable represents operations on a type that can be marshalled to and
// from memory.
//
// go-marshal automatically generates implementations for this interface for
// types marked as '+marshal'.
type Marshallable interface {
	io.WriterTo

	// SizeBytes is the size of the memory representation of a type in
	// marshalled form.
	//
	// SizeBytes must handle a nil receiver. Practically, this means SizeBytes
	// cannot deference any fields on the object implementing it (but will
	// likely make use of the type of these fields).
	SizeBytes() int

	// MarshalBytes serializes a copy of a type to dst. dst may be smaller than
	// SizeBytes(), which results in a part of the struct being marshalled. Note
	// that this may have unexpected results for non-packed types, as implicit
	// padding needs to be taken into account when reasoning about how much of
	// the type is serialized.
	MarshalBytes(dst []byte)

	// UnmarshalBytes deserializes a type from src. src may be smaller than
	// SizeBytes(), which results in a partially deserialized struct. Note that
	// this may have unexpected results for non-packed types, as implicit
	// padding needs to be taken into account when reasoning about how much of
	// the type is deserialized.
	UnmarshalBytes(src []byte)

	// Packed returns true if the marshalled size of the type is the same as the
	// size it occupies in memory. This happens when the type has no fields
	// starting at unaligned addresses (should always be true by default for ABI
	// structs, verified by automatically generated tests when using
	// go_marshal), and has no fields marked `marshal:"unaligned"`.
	//
	// Packed must return the same result for all possible values of the type
	// implementing it. Violating this constraint implies the type doesn't have
	// a static memory layout, and will lead to memory corruption.
	// Go-marshal-generated code reuses the result of Packed for multiple values
	// of the same type.
	Packed() bool

	// MarshalUnsafe serializes a type by bulk copying its in-memory
	// representation to the dst buffer. This is only safe to do when the type
	// has no implicit padding, see Marshallable.Packed. When Packed would
	// return false, MarshalUnsafe should fall back to the safer but slower
	// MarshalBytes. dst may be smaller than SizeBytes(), see comment for
	// MarshalBytes for implications.
	MarshalUnsafe(dst []byte)

	// UnmarshalUnsafe deserializes a type by directly copying to the underlying
	// memory allocated for the object by the runtime.
	//
	// This allows much faster unmarshalling of types which have no implicit
	// padding, see Marshallable.Packed. When Packed would return false,
	// UnmarshalUnsafe should fall back to the safer but slower unmarshal
	// mechanism implemented in UnmarshalBytes. src may be smaller than
	// SizeBytes(), see comment for UnmarshalBytes for implications.
	UnmarshalUnsafe(src []byte)

	// CopyIn deserializes a Marshallable type from a task's memory. This may
	// only be called from a task goroutine. This is more efficient than calling
	// UnmarshalUnsafe on Marshallable.Packed types, as the type being
	// marshalled does not escape. The implementation should avoid creating
	// extra copies in memory by directly deserializing to the object's
	// underlying memory.
	//
	// If the copy-in from the task memory is only partially successful, CopyIn
	// should still attempt to deserialize as much data as possible. See comment
	// for UnmarshalBytes.
	CopyIn(task Task, addr usermem.Addr) (int, error)

	// CopyOut serializes a Marshallable type to a task's memory. This may only
	// be called from a task goroutine. This is more efficient than calling
	// MarshalUnsafe on Marshallable.Packed types, as the type being serialized
	// does not escape. The implementation should avoid creating extra copies in
	// memory by directly serializing from the object's underlying memory.
	//
	// The copy-out to the task memory may be partially successful, in which
	// case CopyOut returns how much data was serialized. See comment for
	// MarshalBytes for implications.
	CopyOut(task Task, addr usermem.Addr) (int, error)

	// CopyOutN is like CopyOut, but explicitly requests a partial
	// copy-out. Note that this may yield unexpected results for non-packed
	// types and the caller may only want to allow this for packed types. See
	// comment on MarshalBytes.
	//
	// The limit must be less than or equal to SizeBytes().
	CopyOutN(task Task, addr usermem.Addr, limit int) (int, error)
}

// go-marshal generates additional functions for a type based on additional
// clauses to the +marshal directive. They are documented below.
//
// Slice API
// =========
//
// Adding a "slice" clause to the +marshal directive for structs or newtypes on
// primitives like this:
//
// // +marshal slice:FooSlice
// type Foo struct { ... }
//
// Generates four additional functions for marshalling slices of Foos like this:
//
// // MarshalUnsafeFooSlice is like Foo.MarshalUnsafe, buf for a []Foo. It's
// // more efficient that repeatedly calling calling Foo.MarshalUnsafe over a
// // []Foo in a loop.
// func MarshalUnsafeFooSlice(src []Foo, dst []byte) (int, error) { ... }
//
// // UnmarshalUnsafeFooSlice is like Foo.UnmarshalUnsafe, buf for a []Foo. It's
// // more efficient that repeatedly calling calling Foo.UnmarshalUnsafe over a
// // []Foo in a loop.
// func UnmarshalUnsafeFooSlice(dst []Foo, src []byte) (int, error) { ... }
//
// // CopyFooSliceIn copies in a slice of Foo objects from the task's memory.
// func CopyFooSliceIn(task marshal.Task, addr usermem.Addr, dst []Foo) (int, error) { ... }
//
// // CopyFooSliceIn copies out a slice of Foo objects to the task's memory.
// func CopyFooSliceOut(task marshal.Task, addr usermem.Addr, src []Foo) (int, error) { ... }
//
// The name of the functions are of the format "Copy%sIn" and "Copy%sOut", where
// %s is the first argument to the slice clause. This directive is not supported
// for newtypes on arrays.
//
// The slice clause also takes an optional second argument, which must be the
// value "inner":
//
// // +marshal slice:Int32Slice:inner
// type Int32 int32
//
// This is only valid on newtypes on primitives, and causes the generated
// functions to accept slices of the inner type instead:
//
// func CopyInt32SliceIn(task marshal.Task, addr usermem.Addr, dst []int32) (int, error) { ... }
//
// Without "inner", they would instead be:
//
// func CopyInt32SliceIn(task marshal.Task, addr usermem.Addr, dst []Int32) (int, error) { ... }
//
// This may help avoid a cast depending on how the generated functions are used.