-
Notifications
You must be signed in to change notification settings - Fork 352
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
21 changed files
with
2,995 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,7 @@ _cgo_export.* | |
_testmain.go | ||
|
||
*.exe | ||
*.bin | ||
*.test | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
.PHONY: toc | ||
|
||
toc: | ||
docker run --rm -it -v ${PWD}:/usr/src jorgeandrada/doctoc --github | ||
$(shell tail -n +`grep -n '# \`go-internals\`' README.md | tr ':' ' ' | awk '{print $$1}'` README.md > /tmp/README2.md) | ||
cp /tmp/README2.md README.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
GOOS=linux | ||
GOARCH=amd64 | ||
|
||
SOURCES := $(wildcard *.go) | ||
OBJECTS = $(SOURCES:.go=.o) | ||
EXECUTABLES = $(OBJECTS:.o=.bin) | ||
|
||
.SECONDARY: ${OBJECTS} | ||
|
||
all: ${EXECUTABLES} | ||
|
||
%.o: %.go | ||
GOOS=${GOOS} GOARCH=${GOARCH} go tool compile $< | ||
|
||
%.bin: %.o | ||
GOOS=${GOOS} GOARCH=${GOARCH} go tool link -o $@ $< | ||
|
||
clean: | ||
rm -f ${OBJECTS} | ||
rm -f ${EXECUTABLES} |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package main | ||
|
||
type Adder interface{ Add(a, b int32) int32 } | ||
type Subber interface{ Sub(a, b int32) int32 } | ||
|
||
type Mather interface { | ||
Adder | ||
Subber | ||
} | ||
|
||
type Calculator struct{ id int32 } | ||
|
||
func (c *Calculator) Add(a, b int32) int32 { return a + b } | ||
func (c *Calculator) Sub(a, b int32) int32 { return a - b } | ||
|
||
func main() { | ||
calc := Calculator{id: 6754} | ||
var m Mather = &calc | ||
m.Sub(10, 32) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package main | ||
|
||
//go:noinline | ||
func Add(a, b int32) int32 { return a + b } | ||
|
||
type Adder struct{ id int32 } | ||
|
||
//go:noinline | ||
func (adder *Adder) AddPtr(a, b int32) int32 { return a + b } | ||
|
||
//go:noinline | ||
func (adder Adder) AddVal(a, b int32) int32 { return a + b } | ||
|
||
func main() { | ||
Add(10, 32) // direct call of top-level function | ||
|
||
adder := Adder{id: 6754} | ||
adder.AddPtr(10, 32) // direct call of method with pointer receiver | ||
adder.AddVal(10, 32) // direct call of method with value receiver | ||
|
||
(&adder).AddVal(10, 32) // implicit dereferencing | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
#!/usr/bin/env bash | ||
|
||
BIN="$1" | ||
test "$BIN" | ||
SECTION="$2" | ||
test "$SECTION" | ||
SYM="$3" | ||
test "$SYM" | ||
|
||
section_offset=$( | ||
readelf -St -W "$BIN" | \ | ||
grep -A 1 "$SECTION" | \ | ||
tail -n +2 | \ | ||
awk '{print toupper($3)}' | ||
) | ||
section_offset_dec=$(echo "ibase=16;$section_offset" | bc) | ||
echo "$SECTION file-offset: $section_offset_dec" | ||
|
||
section_vma=$( | ||
readelf -St -W "$BIN" | \ | ||
grep -A 1 "$SECTION" | \ | ||
tail -n +2 | \ | ||
awk '{print toupper($2)}' | ||
) | ||
section_vma_dec=$(echo "ibase=16;$section_vma" | bc) | ||
echo "$SECTION VMA: $section_vma_dec" | ||
|
||
sym_vma=$(objdump -t -j "$SECTION" "$BIN" | grep "$SYM" | awk '{print toupper($1)}') | ||
sym_vma_dec=$(echo "ibase=16;$sym_vma" | bc) | ||
echo "$SYM VMA: $sym_vma_dec" | ||
sym_size=$(objdump -t -j "$SECTION" "$BIN" | grep "$SYM" | awk '{print toupper($5)}') | ||
sym_size_dec=$(echo "ibase=16;$sym_size" | bc) | ||
echo -e "$SYM SIZE: $sym_size_dec\n" | ||
|
||
sym_offset=$(( $sym_vma_dec - $section_vma_dec + $section_offset_dec )) | ||
dd if="$BIN" of=/dev/stdout bs=1 count=$sym_size_dec skip="$sym_offset" 2>/dev/null | hexdump |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
package main | ||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
func BenchmarkEfaceScalar(b *testing.B) { | ||
var Uint uint32 | ||
b.Run("uint32", func(b *testing.B) { | ||
for i := 0; i < b.N; i++ { | ||
// MOVL DX, (AX) | ||
Uint = uint32(i) | ||
} | ||
}) | ||
var Eface interface{} | ||
b.Run("eface32", func(b *testing.B) { | ||
for i := 0; i < b.N; i++ { | ||
// MOVL CX, ""..autotmp_3+36(SP) | ||
// LEAQ type.uint32(SB), AX | ||
// MOVQ AX, (SP) | ||
// LEAQ ""..autotmp_3+36(SP), DX | ||
// MOVQ DX, 8(SP) | ||
// CALL runtime.convT2E32(SB) | ||
// MOVQ 24(SP), AX | ||
// MOVQ 16(SP), CX | ||
// MOVQ "".&Eface+48(SP), DX | ||
// MOVQ CX, (DX) | ||
// MOVL runtime.writeBarrier(SB), CX | ||
// LEAQ 8(DX), DI | ||
// TESTL CX, CX | ||
// JNE 148 | ||
// MOVQ AX, 8(DX) | ||
// JMP 46 | ||
// CALL runtime.gcWriteBarrier(SB) | ||
// JMP 46 | ||
Eface = uint32(i) | ||
} | ||
}) | ||
b.Run("eface8", func(b *testing.B) { | ||
for i := 0; i < b.N; i++ { | ||
// LEAQ type.uint8(SB), BX | ||
// MOVQ BX, (CX) | ||
// MOVBLZX AL, SI | ||
// LEAQ runtime.staticbytes(SB), R8 | ||
// ADDQ R8, SI | ||
// MOVL runtime.writeBarrier(SB), R9 | ||
// LEAQ 8(CX), DI | ||
// TESTL R9, R9 | ||
// JNE 100 | ||
// MOVQ SI, 8(CX) | ||
// JMP 40 | ||
// MOVQ AX, R9 | ||
// MOVQ SI, AX | ||
// CALL runtime.gcWriteBarrier(SB) | ||
// MOVQ R9, AX | ||
// JMP 40 | ||
Eface = uint8(i) | ||
} | ||
}) | ||
b.Run("eface-zeroval", func(b *testing.B) { | ||
for i := 0; i < b.N; i++ { | ||
// MOVL $0, ""..autotmp_3+36(SP) | ||
// LEAQ type.uint32(SB), AX | ||
// MOVQ AX, (SP) | ||
// LEAQ ""..autotmp_3+36(SP), CX | ||
// MOVQ CX, 8(SP) | ||
// CALL runtime.convT2E32(SB) | ||
// MOVQ 16(SP), AX | ||
// MOVQ 24(SP), CX | ||
// MOVQ "".&Eface+48(SP), DX | ||
// MOVQ AX, (DX) | ||
// MOVL runtime.writeBarrier(SB), AX | ||
// LEAQ 8(DX), DI | ||
// TESTL AX, AX | ||
// JNE 152 | ||
// MOVQ CX, 8(DX) | ||
// JMP 46 | ||
// MOVQ CX, AX | ||
// CALL runtime.gcWriteBarrier(SB) | ||
// JMP 46 | ||
Eface = uint32(i - i) // outsmart the compiler | ||
} | ||
}) | ||
b.Run("eface-static", func(b *testing.B) { | ||
for i := 0; i < b.N; i++ { | ||
// LEAQ type.uint64(SB), BX | ||
// MOVQ BX, (CX) | ||
// MOVL runtime.writeBarrier(SB), SI | ||
// LEAQ 8(CX), DI | ||
// TESTL SI, SI | ||
// JNE 92 | ||
// LEAQ "".statictmp_0(SB), SI | ||
// MOVQ SI, 8(CX) | ||
// JMP 40 | ||
// MOVQ AX, SI | ||
// LEAQ "".statictmp_0(SB), AX | ||
// CALL runtime.gcWriteBarrier(SB) | ||
// MOVQ SI, AX | ||
// LEAQ "".statictmp_0(SB), SI | ||
// JMP 40 | ||
Eface = uint64(42) | ||
} | ||
}) | ||
} | ||
|
||
func main() { | ||
// So that we can easily compile this and retrieve `main.statictmp_0` | ||
// from the final executable. | ||
BenchmarkEfaceScalar(&testing.B{}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package main | ||
|
||
var j uint32 | ||
var Eface interface{} // outsmart compiler (avoid static inference) | ||
|
||
func assertion() { | ||
i := uint32(42) | ||
Eface = i | ||
|
||
// 0x0065 00101 MOVQ "".Eface(SB), AX ;; AX = Eface._type | ||
// 0x006c 00108 MOVQ "".Eface+8(SB), CX ;; CX = Eface.data | ||
// 0x0073 00115 LEAQ type.uint32(SB), DX ;; DX = type.uint32 | ||
// 0x007a 00122 CMPQ AX, DX ;; Eface._type == type.uint32 ? | ||
// 0x007d 00125 JNE 162 ;; no? panic our way outta here | ||
// 0x007f 00127 MOVL (CX), AX ;; AX = *Eface.data | ||
// 0x0081 00129 MOVL AX, "".j(SB) ;; j = AX = *Eface.data | ||
// ;; exit | ||
// 0x0087 00135 MOVQ 40(SP), BP | ||
// 0x008c 00140 ADDQ $48, SP | ||
// 0x0090 00144 RET | ||
// ;; panic: interface conversion: <iface> is <have>, not <want> | ||
// 0x00a2 00162 MOVQ AX, (SP) ;; have: Eface._type | ||
// 0x00a6 00166 MOVQ DX, 8(SP) ;; want: type.uint32 | ||
// 0x00ab 00171 LEAQ type.interface {}(SB), AX ;; AX = type.interface{} (eface) | ||
// 0x00b2 00178 MOVQ AX, 16(SP) ;; iface: AX | ||
// 0x00b7 00183 CALL runtime.panicdottypeE(SB) ;; func panicdottypeE(have, want, iface *_type) | ||
// 0x00bc 00188 UNDEF | ||
// 0x00be 00190 NOP | ||
j = Eface.(uint32) | ||
} | ||
|
||
func typeSwitch() { | ||
i := uint32(42) | ||
Eface = i | ||
|
||
// ;; switch v := Eface.(type) | ||
// 0x0065 00101 MOVQ "".Eface(SB), AX ;; AX = Eface._type | ||
// 0x006c 00108 MOVQ "".Eface+8(SB), CX ;; CX = Eface.data | ||
// 0x0073 00115 TESTQ AX, AX ;; Eface._type == nil ? | ||
// 0x0076 00118 JEQ 153 ;; yes? exit the switch | ||
// 0x0078 00120 MOVL 16(AX), DX ;; DX = Eface.type._hash | ||
// ;; case uint32 | ||
// 0x007b 00123 CMPL DX, $-800397251 ;; Eface.type._hash == type.uint32.hash ? | ||
// 0x0081 00129 JNE 163 ;; no? go to next case (uint16) | ||
// 0x0083 00131 LEAQ type.uint32(SB), BX ;; BX = type.uint32 | ||
// 0x008a 00138 CMPQ BX, AX ;; type.uint32 == Eface._type ? (HASH COLLISION?) | ||
// 0x008d 00141 JNE 206 ;; no? clear BX and go to next case (uint16) | ||
// 0x008f 00143 MOVL (CX), BX ;; BX = *Eface.data | ||
// 0x0091 00145 JNE 163 ;; landsite for indirect jump starting at 0x00d3 | ||
// 0x0093 00147 MOVL BX, "".j(SB) ;; j = BX = *Eface.data | ||
// ;; exit | ||
// 0x0099 00153 MOVQ 40(SP), BP | ||
// 0x009e 00158 ADDQ $48, SP | ||
// 0x00a2 00162 RET | ||
// ;; case uint16 | ||
// 0x00a3 00163 CMPL DX, $-269349216 ;; Eface.type._hash == type.uint16.hash ? | ||
// 0x00a9 00169 JNE 153 ;; no? exit the switch | ||
// 0x00ab 00171 LEAQ type.uint16(SB), DX ;; DX = type.uint16 | ||
// 0x00b2 00178 CMPQ DX, AX ;; type.uint16 == Eface._type ? (HASH COLLISION?) | ||
// 0x00b5 00181 JNE 199 ;; no? clear AX and exit the switch | ||
// 0x00b7 00183 MOVWLZX (CX), AX ;; AX = uint16(*Eface.data) | ||
// 0x00ba 00186 JNE 153 ;; landsite for indirect jump starting at 0x00cc | ||
// 0x00bc 00188 MOVWLZX AX, AX ;; AX = uint16(AX) (redundant) | ||
// 0x00bf 00191 MOVL AX, "".j(SB) ;; j = AX = *Eface.data | ||
// 0x00c5 00197 JMP 153 ;; we're done, exit the switch | ||
// ;; indirect jump table | ||
// 0x00c7 00199 MOVL $0, AX ;; AX = $0 | ||
// 0x00cc 00204 JMP 186 ;; indirect jump to 153 (exit) | ||
// 0x00ce 00206 MOVL $0, BX ;; BX = $0 | ||
// 0x00d3 00211 JMP 145 ;; indirect jump to 163 (case uint16) | ||
switch v := Eface.(type) { | ||
case uint16: | ||
j = uint32(v) | ||
case uint32: | ||
j = v | ||
} | ||
} | ||
|
||
func main() { | ||
assertion() | ||
typeSwitch() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package main | ||
|
||
import "testing" | ||
|
||
var j uint32 | ||
var eface interface{} = uint32(42) | ||
|
||
func BenchmarkEfaceToType(b *testing.B) { | ||
b.Run("switch-small", func(b *testing.B) { | ||
for i := 0; i < b.N; i++ { | ||
switch v := eface.(type) { | ||
case int8: | ||
j = uint32(v) | ||
case uint32: | ||
j = uint32(v) | ||
case int16: | ||
j = uint32(v) | ||
default: | ||
j = v.(uint32) | ||
} | ||
} | ||
}) | ||
b.Run("switch-big", func(b *testing.B) { | ||
for i := 0; i < b.N; i++ { | ||
switch v := eface.(type) { | ||
case int8: | ||
j = uint32(v) | ||
case int16: | ||
j = uint32(v) | ||
case int32: | ||
j = uint32(v) | ||
case uint32: | ||
j = uint32(v) | ||
case int64: | ||
j = uint32(v) | ||
case uint8: | ||
j = uint32(v) | ||
case uint16: | ||
j = uint32(v) | ||
case uint64: | ||
j = uint32(v) | ||
default: | ||
j = v.(uint32) | ||
} | ||
} | ||
}) | ||
} | ||
|
||
func main() {} |
Oops, something went wrong.