fix: coop-cloud
👉 toolshed
migrate
#463
@ -10,7 +10,7 @@ steps:
|
||||
- name: make test
|
||||
image: golang:1.22
|
||||
environment:
|
||||
CATL_URL: https://git.coopcloud.tech/coop-cloud/recipes-catalogue-json.git
|
||||
CATL_URL: https://git.coopcloud.tech/toolshed/recipes-catalogue-json.git
|
||||
commands:
|
||||
- mkdir -p $HOME/.abra
|
||||
- git clone $CATL_URL $HOME/.abra/catalogue
|
||||
@ -50,7 +50,7 @@ steps:
|
||||
username: 3wordchant
|
||||
password:
|
||||
from_secret: git_coopcloud_tech_token_3wc
|
||||
repo: git.coopcloud.tech/coop-cloud/abra
|
||||
repo: git.coopcloud.tech/toolshed/abra
|
||||
tags: dev
|
||||
registry: git.coopcloud.tech
|
||||
when:
|
||||
@ -74,7 +74,7 @@ steps:
|
||||
request_pty: true
|
||||
script:
|
||||
- |
|
||||
wget https://git.coopcloud.tech/coop-cloud/abra/raw/branch/main/scripts/tests/run-ci-int -O run-ci-int
|
||||
wget https://git.coopcloud.tech/toolshed/abra/raw/branch/main/scripts/tests/run-ci-int -O run-ci-int
|
||||
chmod +x run-ci-int
|
||||
sh run-ci-int
|
||||
when:
|
||||
|
@ -1,8 +0,0 @@
|
||||
---
|
||||
name: "Do not use this issue tracker"
|
||||
about: "Do not use this issue tracker"
|
||||
title: "Do not use this issue tracker"
|
||||
labels: []
|
||||
---
|
||||
|
||||
Please report your issue on [`coop-cloud/organising`](https://git.coopcloud.tech/coop-cloud/organising)
|
@ -1,7 +1,7 @@
|
||||
# `abra`
|
||||
|
||||
[](https://build.coopcloud.tech/coop-cloud/abra)
|
||||
[](https://goreportcard.com/report/git.coopcloud.tech/coop-cloud/abra)
|
||||
[](https://build.coopcloud.tech/toolshed/abra)
|
||||
[](https://goreportcard.com/report/git.coopcloud.tech/toolshed/abra)
|
||||
[](https://pkg.go.dev/coopcloud.tech/abra)
|
||||
|
||||
The Co-op Cloud utility belt 🎩🐇
|
||||
|
@ -13,7 +13,7 @@ func TestParseCmdArgs(t *testing.T) {
|
||||
}{
|
||||
// `--` is not parsed when passed in from the command-line e.g. -- foo bar baz
|
||||
// so we need to eumlate that as missing when testing if bash args are passed in
|
||||
// see https://git.coopcloud.tech/coop-cloud/organising/issues/336 for more
|
||||
// see https://git.coopcloud.tech/toolshed/organising/issues/336 for more
|
||||
{[]string{"foo.com", "app", "test"}, false, ""},
|
||||
{[]string{"foo.com", "app", "test", "foo"}, true, "foo "},
|
||||
{[]string{"foo.com", "app", "test", "foo", "bar", "baz"}, true, "foo bar baz "},
|
||||
|
@ -28,8 +28,8 @@ It is possible to generate new metadata for a single recipe by passing
|
||||
[recipe]. The existing local catalogue will be updated, not overwritten.
|
||||
|
||||
It is quite easy to get rate limited by Docker Hub when running this command.
|
||||
If you have a Hub account you can have Abra log you in to avoid this. Pass
|
||||
"--user" and "--pass".
|
||||
If you have a Hub account you can "docker login" and Abra will automatically
|
||||
use those details.
|
||||
|
||||
Push your new release to git.coopcloud.tech with "--publish/-p". This requires
|
||||
that you have permission to git push to these repositories and have your SSH
|
||||
@ -47,12 +47,14 @@ keys configured on your account.`,
|
||||
recipeName = args[0]
|
||||
}
|
||||
|
||||
r := recipe.Get(recipeName)
|
||||
|
||||
if recipeName != "" {
|
||||
internal.ValidateRecipe(args, cmd.Name())
|
||||
}
|
||||
|
||||
if err := catalogue.EnsureCatalogue(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if !internal.Chaos {
|
||||
if err := catalogue.EnsureIsClean(); err != nil {
|
||||
log.Fatal(err)
|
||||
@ -89,6 +91,14 @@ keys configured on your account.`,
|
||||
continue
|
||||
}
|
||||
|
||||
// NOTE(d1): the "example" recipe is a temporary special case
|
||||
// https://git.coopcloud.tech/toolshed/organising/issues/666
|
||||
if recipeMeta.Name == "example" {
|
||||
catlBar.Add(1)
|
||||
continue
|
||||
}
|
||||
|
||||
r := recipe.Get(recipeMeta.Name)
|
||||
versions, err := r.GetRecipeVersions()
|
||||
if err != nil {
|
||||
log.Warn(err)
|
||||
@ -168,7 +178,7 @@ keys configured on your account.`,
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
sshURL := fmt.Sprintf(config.SSH_URL_TEMPLATE, config.CATALOGUE_JSON_REPO_NAME)
|
||||
sshURL := fmt.Sprintf(config.TOOLSHED_SSH_URL_TEMPLATE, config.CATALOGUE_JSON_REPO_NAME)
|
||||
if err := gitPkg.CreateRemote(repo, "origin-ssh", sshURL, internal.Dry); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
21
go.mod
21
go.mod
@ -4,11 +4,9 @@ go 1.22.7
|
||||
|
||||
toolchain go1.23.1
|
||||
|
||||
replace github.com/urfave/cli/v3 => github.com/urfave/cli/v3 v3.0.0-alpha9.1.0.20241019193437-5053ec708a44
|
||||
|
||||
require (
|
||||
coopcloud.tech/tagcmp v0.0.0-20230809071031-eb3e7758d4eb
|
||||
git.coopcloud.tech/coop-cloud/godotenv v1.5.2-0.20231130100509-01bff8284355
|
||||
git.coopcloud.tech/toolshed/godotenv v1.5.2-0.20250103171850-4d0ca41daa5c
|
||||
github.com/AlecAivazis/survey/v2 v2.3.7
|
||||
github.com/charmbracelet/lipgloss v1.0.0
|
||||
github.com/charmbracelet/log v0.4.0
|
||||
@ -16,7 +14,7 @@ require (
|
||||
github.com/docker/cli v27.4.1+incompatible
|
||||
github.com/docker/docker v27.4.1+incompatible
|
||||
github.com/docker/go-units v0.5.0
|
||||
github.com/go-git/go-git/v5 v5.12.0
|
||||
github.com/go-git/go-git/v5 v5.13.1
|
||||
github.com/google/go-cmp v0.6.0
|
||||
github.com/moby/sys/signal v0.7.1
|
||||
github.com/moby/term v0.5.0
|
||||
@ -30,7 +28,7 @@ require (
|
||||
require (
|
||||
dario.cat/mergo v1.0.1 // indirect
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
|
||||
github.com/BurntSushi/toml v1.4.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.1.3 // indirect
|
||||
@ -54,7 +52,7 @@ require (
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.6.0 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.6.1 // indirect
|
||||
github.com/go-logfmt/logfmt v0.6.0 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
@ -77,6 +75,7 @@ require (
|
||||
github.com/miekg/pkcs11 v1.1.1 // indirect
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/mmcloughlin/avo v0.6.0 // indirect
|
||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||
github.com/moby/sys/mountinfo v0.6.2 // indirect
|
||||
github.com/moby/sys/user v0.3.0 // indirect
|
||||
@ -88,7 +87,7 @@ require (
|
||||
github.com/opencontainers/runc v1.1.13 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.1.0 // indirect
|
||||
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.61.0 // indirect
|
||||
@ -114,13 +113,15 @@ require (
|
||||
go.opentelemetry.io/otel/trace v1.33.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.4.0 // indirect
|
||||
golang.org/x/crypto v0.31.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect
|
||||
golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329 // indirect
|
||||
golang.org/x/mod v0.22.0 // indirect
|
||||
golang.org/x/net v0.33.0 // indirect
|
||||
golang.org/x/sync v0.10.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/time v0.8.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241223144023-3abc09e42ca8 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 // indirect
|
||||
golang.org/x/tools v0.28.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d // indirect
|
||||
google.golang.org/grpc v1.69.2 // indirect
|
||||
google.golang.org/protobuf v1.36.1 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
|
30
go.sum
30
go.sum
@ -27,8 +27,8 @@ coopcloud.tech/tagcmp v0.0.0-20230809071031-eb3e7758d4eb/go.mod h1:ESVm0wQKcbcFi
|
||||
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
||||
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
git.coopcloud.tech/coop-cloud/godotenv v1.5.2-0.20231130100509-01bff8284355 h1:tCv2B4qoN6RMheKDnCzIafOkWS5BB1h7hwhmo+9bVeE=
|
||||
git.coopcloud.tech/coop-cloud/godotenv v1.5.2-0.20231130100509-01bff8284355/go.mod h1:Q8V1zbtPAlzYSr/Dvky3wS6x58IQAl3rot2me1oSO2Q=
|
||||
git.coopcloud.tech/toolshed/godotenv v1.5.2-0.20250103171850-4d0ca41daa5c h1:oeKnUB79PKYD8D0/unYuu7MRcWryQQWOns8+JL+acrs=
|
||||
git.coopcloud.tech/toolshed/godotenv v1.5.2-0.20250103171850-4d0ca41daa5c/go.mod h1:fQuhwrpg6qb9NlFXKYi/LysWu1wxjraS8sxyW12CUF0=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
|
||||
github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ=
|
||||
@ -37,6 +37,8 @@ github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9mo
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||
github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw=
|
||||
@ -131,6 +133,7 @@ github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInq
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
@ -342,6 +345,7 @@ github.com/dvsekhvalnov/jose2go v0.0.0-20170216131308-f21a8cedbbae/go.mod h1:7Bv
|
||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU=
|
||||
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||
github.com/elazarl/goproxy v1.2.3 h1:xwIyKHbaP5yfT6O9KIeYJR5549MXRQkoQMRXGztz8YQ=
|
||||
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||
@ -374,14 +378,19 @@ github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE=
|
||||
github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8=
|
||||
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||
github.com/go-git/go-billy/v5 v5.6.0 h1:w2hPNtoehvJIxR00Vb4xX94qHQi/ApZfX+nBE2Cjio8=
|
||||
github.com/go-git/go-billy/v5 v5.6.0/go.mod h1:sFDq7xD3fn3E0GOwUSZqHo9lrkmx8xJhA0ZrfvjBRGM=
|
||||
github.com/go-git/go-billy/v5 v5.6.1 h1:u+dcrgaguSSkbjzHwelEjc0Yj300NUevrrPphk/SoRA=
|
||||
github.com/go-git/go-billy/v5 v5.6.1/go.mod h1:0AsLr1z2+Uksi4NlElmMblP5rPcDZNRCD8ujZCRR2BE=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||
github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys=
|
||||
github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY=
|
||||
github.com/go-git/go-git/v5 v5.13.1 h1:DAQ9APonnlvSWpvolXWIuV6Q6zXy2wHbN4cVlNR5Q+M=
|
||||
github.com/go-git/go-git/v5 v5.13.1/go.mod h1:qryJB4cSBoq3FRoBRf5A77joojuBcmPJ0qu3XXXVixc=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
@ -519,6 +528,7 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ=
|
||||
@ -649,6 +659,8 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
|
||||
github.com/mmcloughlin/avo v0.6.0 h1:QH6FU8SKoTLaVs80GA8TJuLNkUYl4VokHKlPhVDg4YY=
|
||||
github.com/mmcloughlin/avo v0.6.0/go.mod h1:8CoAGaCSYXtCPR+8y18Y9aB/kxb8JSS6FRI7mSkvD+8=
|
||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
|
||||
@ -750,6 +762,8 @@ github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
|
||||
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
|
||||
github.com/pjbgf/sha1cd v0.3.1 h1:Dh2GYdpJnO84lIw0LJwTFXjcNbasP/bklicSznyAaPI=
|
||||
github.com/pjbgf/sha1cd v0.3.1/go.mod h1:Y8t7jSB/dEI/lQE04A1HVKteqjj9bX5O4+Cex0TCu8s=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
@ -804,6 +818,7 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
@ -990,6 +1005,8 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo=
|
||||
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
||||
golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329 h1:9kj3STMvgqy3YA4VQXBrN7925ICMxD5wzMRcgA30588=
|
||||
golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@ -1012,6 +1029,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
|
||||
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@ -1224,6 +1243,8 @@ golang.org/x/tools v0.0.0-20200916195026-c9a70fc28ce3/go.mod h1:z6u4i615ZeAfBE4X
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
|
||||
golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@ -1274,8 +1295,12 @@ google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece/go.mod h1:jDfRM7Fc
|
||||
google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241223144023-3abc09e42ca8 h1:st3LcW/BPi75W4q1jJTEor/QWwbNlPlDG0JTn6XhZu0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241223144023-3abc09e42ca8/go.mod h1:klhJGKFyG8Tn50enBn7gizg4nXGXJ+jqEREdCWaPcV4=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d h1:H8tOf8XM88HvKqLTxe755haY6r1fqqzLbEnfrmLXlSA=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d/go.mod h1:2v7Z7gP2ZUOGsaFyxATQSRoBnKygqVq2Cwnvom7QiqY=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 h1:TqExAhdPaB60Ux47Cn0oLV07rGnxZzIsaRhQaqS666A=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d h1:xJJRGY7TJcvIlpSrN3K6LAWgNFUILlO+OMAqtg9aqnw=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4=
|
||||
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
@ -1351,6 +1376,7 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
||||
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
|
||||
|
@ -97,16 +97,17 @@ func (a Abra) GetCatalogueDir() string { return path.Join(a.GetAbraDir(), "catal
|
||||
var config = LoadAbraConfig()
|
||||
|
||||
var (
|
||||
ABRA_DIR = config.GetAbraDir()
|
||||
SERVERS_DIR = config.GetServersDir()
|
||||
RECIPES_DIR = config.GetRecipesDir()
|
||||
VENDOR_DIR = config.GetVendorDir()
|
||||
BACKUP_DIR = config.GetBackupDir()
|
||||
CATALOGUE_DIR = config.GetCatalogueDir()
|
||||
RECIPES_JSON = path.Join(config.GetCatalogueDir(), "recipes.json")
|
||||
REPOS_BASE_URL = "https://git.coopcloud.tech/coop-cloud"
|
||||
CATALOGUE_JSON_REPO_NAME = "recipes-catalogue-json"
|
||||
SSH_URL_TEMPLATE = "ssh://git@git.coopcloud.tech:2222/coop-cloud/%s.git"
|
||||
ABRA_DIR = config.GetAbraDir()
|
||||
SERVERS_DIR = config.GetServersDir()
|
||||
RECIPES_DIR = config.GetRecipesDir()
|
||||
VENDOR_DIR = config.GetVendorDir()
|
||||
BACKUP_DIR = config.GetBackupDir()
|
||||
CATALOGUE_DIR = config.GetCatalogueDir()
|
||||
RECIPES_JSON = path.Join(config.GetCatalogueDir(), "recipes.json")
|
||||
REPOS_BASE_URL = "https://git.coopcloud.tech/coop-cloud"
|
||||
CATALOGUE_JSON_REPO_NAME = "recipes-catalogue-json"
|
||||
TOOLSHED_SSH_URL_TEMPLATE = "ssh://git@git.coopcloud.tech:2222/toolshed/%s.git"
|
||||
RECIPES_SSH_URL_TEMPLATE = "ssh://git@git.coopcloud.tech:2222/coop-cloud/%s.git"
|
||||
|
||||
// NOTE(d1): please note, this was done purely out of laziness on our part
|
||||
// AFAICR. it's easy to punt the value into the label because that is what is
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"git.coopcloud.tech/coop-cloud/godotenv"
|
||||
"git.coopcloud.tech/toolshed/godotenv"
|
||||
)
|
||||
|
||||
// envVarModifiers is a list of env var modifier strings. These are added to
|
||||
|
@ -150,7 +150,7 @@ func Get(name string) Recipe {
|
||||
}
|
||||
|
||||
gitURL := fmt.Sprintf("%s/%s.git", config.REPOS_BASE_URL, name)
|
||||
sshURL := fmt.Sprintf(config.SSH_URL_TEMPLATE, name)
|
||||
sshURL := fmt.Sprintf(config.RECIPES_SSH_URL_TEMPLATE, name)
|
||||
if strings.Contains(name, "/") {
|
||||
u, err := url.Parse(name)
|
||||
if err != nil {
|
||||
|
@ -21,8 +21,8 @@ func TestGet(t *testing.T) {
|
||||
recipe: Recipe{
|
||||
Name: "foo",
|
||||
Dir: path.Join(cfg.GetAbraDir(), "/recipes/foo"),
|
||||
GitURL: "https://git.coopcloud.tech/coop-cloud/foo.git",
|
||||
SSHURL: "ssh://git@git.coopcloud.tech:2222/coop-cloud/foo.git",
|
||||
GitURL: "https://git.coopcloud.tech/toolshed/foo.git",
|
||||
SSHURL: "ssh://git@git.coopcloud.tech:2222/toolshed/foo.git",
|
||||
ComposePath: path.Join(cfg.GetAbraDir(), "recipes/foo/compose.yml"),
|
||||
ReadmePath: path.Join(cfg.GetAbraDir(), "recipes/foo/README.md"),
|
||||
SampleEnvPath: path.Join(cfg.GetAbraDir(), "recipes/foo/.env.sample"),
|
||||
@ -35,8 +35,8 @@ func TestGet(t *testing.T) {
|
||||
Name: "foo",
|
||||
EnvVersion: "1.2.3",
|
||||
Dir: path.Join(cfg.GetAbraDir(), "/recipes/foo"),
|
||||
GitURL: "https://git.coopcloud.tech/coop-cloud/foo.git",
|
||||
SSHURL: "ssh://git@git.coopcloud.tech:2222/coop-cloud/foo.git",
|
||||
GitURL: "https://git.coopcloud.tech/toolshed/foo.git",
|
||||
SSHURL: "ssh://git@git.coopcloud.tech:2222/toolshed/foo.git",
|
||||
ComposePath: path.Join(cfg.GetAbraDir(), "recipes/foo/compose.yml"),
|
||||
ReadmePath: path.Join(cfg.GetAbraDir(), "recipes/foo/README.md"),
|
||||
SampleEnvPath: path.Join(cfg.GetAbraDir(), "recipes/foo/.env.sample"),
|
||||
@ -100,7 +100,7 @@ func TestGetVersionLabelLocalDoesNotUseTimeoutLabel(t *testing.T) {
|
||||
// returns it. hopefully this won't fail too often! if you're here because
|
||||
// of a failure, just update the `defaultTimeoutLabel` value & permalink
|
||||
// below
|
||||
// https://git.coopcloud.tech/coop-cloud/traefik/src/commit/ac3a47fe8ca3ef92db84f64cfedfbb348000faee/.env.sample#L2
|
||||
// https://git.coopcloud.tech/toolshed/traefik/src/commit/ac3a47fe8ca3ef92db84f64cfedfbb348000faee/.env.sample#L2
|
||||
defaultTimeoutLabel := "300"
|
||||
assert.NotEqual(t, label, defaultTimeoutLabel)
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
ABRA_VERSION="0.9.0-beta"
|
||||
ABRA_RELEASE_URL="https://git.coopcloud.tech/api/v1/repos/coop-cloud/abra/releases/tags/$ABRA_VERSION"
|
||||
ABRA_RELEASE_URL="https://git.coopcloud.tech/api/v1/repos/toolshed/abra/releases/tags/$ABRA_VERSION"
|
||||
RC_VERSION="0.8.0-rc1-beta"
|
||||
RC_VERSION_URL="https://git.coopcloud.tech/api/v1/repos/coop-cloud/abra/releases/tags/$RC_VERSION"
|
||||
RC_VERSION_URL="https://git.coopcloud.tech/api/v1/repos/toolshed/abra/releases/tags/$RC_VERSION"
|
||||
|
||||
for arg in "$@"; do
|
||||
if [ "$arg" == "--rc" ]; then
|
||||
@ -40,7 +40,7 @@ function install_abra_release {
|
||||
if ! type "wget" > /dev/null 2>&1; then
|
||||
echo "'wget' is not installed, cannot proceed..."
|
||||
echo "perhaps try installing manually via the releases URL?"
|
||||
echo "https://git.coopcloud.tech/coop-cloud/abra/releases"
|
||||
echo "https://git.coopcloud.tech/toolshed/abra/releases"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
@ -42,7 +42,7 @@ echo "========================================================================"
|
||||
echo "CLONING ABRA"
|
||||
echo "========================================================================"
|
||||
rm -rf abra
|
||||
git clone ssh://git@git.coopcloud.tech:2222/coop-cloud/abra.git
|
||||
git clone ssh://git@git.coopcloud.tech:2222/toolshed/abra.git
|
||||
cd abra
|
||||
git checkout main
|
||||
echo "========================================================================"
|
||||
|
@ -27,18 +27,18 @@ teardown(){
|
||||
|
||||
# bats test_tags=slow
|
||||
@test "deploy remote recipe" {
|
||||
run sed -i 's/TYPE=abra-test-recipe:.*/TYPE=git.coopcloud.tech\/coop-cloud\/abra-test-recipe/g' \
|
||||
run sed -i 's/TYPE=abra-test-recipe:.*/TYPE=git.coopcloud.tech\/toolshed\/abra-test-recipe/g' \
|
||||
"$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env"
|
||||
assert_success
|
||||
|
||||
run $ABRA app deploy "$TEST_APP_DOMAIN" --no-input --no-converge-checks
|
||||
assert_success
|
||||
assert_output --partial "git.coopcloud.tech/coop-cloud/abra-test-recipe"
|
||||
assert_output --partial "git.coopcloud.tech/toolshed/abra-test-recipe"
|
||||
}
|
||||
|
||||
# bats test_tags=slow
|
||||
@test "deploy remote recipe with version" {
|
||||
run sed -i 's/TYPE=abra-test-recipe:.*/TYPE=git.coopcloud.tech\/coop-cloud\/abra-test-recipe:0.2.0+1.21.0/g' \
|
||||
run sed -i 's/TYPE=abra-test-recipe:.*/TYPE=git.coopcloud.tech\/toolshed\/abra-test-recipe:0.2.0+1.21.0/g' \
|
||||
"$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env"
|
||||
assert_success
|
||||
|
||||
@ -49,7 +49,7 @@ teardown(){
|
||||
|
||||
# bats test_tags=slow
|
||||
@test "deploy remote recipe with chaos commit" {
|
||||
run sed -i 's/TYPE=abra-test-recipe:.*/TYPE=git.coopcloud.tech\/coop-cloud\/abra-test-recipe:1e83340e/g' \
|
||||
run sed -i 's/TYPE=abra-test-recipe:.*/TYPE=git.coopcloud.tech\/toolshed\/abra-test-recipe:1e83340e/g' \
|
||||
"$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env"
|
||||
assert_success
|
||||
|
||||
@ -60,14 +60,14 @@ teardown(){
|
||||
|
||||
# bats test_tags=slow
|
||||
@test "remote recipe version written to env" {
|
||||
run sed -i 's/TYPE=abra-test-recipe:.*/TYPE=git.coopcloud.tech\/coop-cloud\/abra-test-recipe/g' \
|
||||
run sed -i 's/TYPE=abra-test-recipe:.*/TYPE=git.coopcloud.tech\/toolshed\/abra-test-recipe/g' \
|
||||
"$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env"
|
||||
assert_success
|
||||
|
||||
run $ABRA app deploy "$TEST_APP_DOMAIN" --no-input --no-converge-checks
|
||||
assert_success
|
||||
|
||||
run grep -q "TYPE=git.coopcloud.tech\/coop-cloud\/abra-test-recipe:$(_latest_release)" \
|
||||
run grep -q "TYPE=git.coopcloud.tech\/toolshed\/abra-test-recipe:$(_latest_release)" \
|
||||
"$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env"
|
||||
assert_success
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ _fetch_recipe() {
|
||||
run mkdir -p "$ABRA_DIR/recipes"
|
||||
assert_success
|
||||
|
||||
run git clone "https://git.coopcloud.tech/coop-cloud/$TEST_RECIPE" "$ABRA_DIR/recipes/$TEST_RECIPE"
|
||||
run git clone "https://git.coopcloud.tech/toolshed/$TEST_RECIPE" "$ABRA_DIR/recipes/$TEST_RECIPE"
|
||||
assert_success
|
||||
fi
|
||||
}
|
||||
@ -33,7 +33,7 @@ _ensure_latest_version(){
|
||||
|
||||
_ensure_catalogue(){
|
||||
if [[ ! -d "$ABRA_DIR/catalogue" ]]; then
|
||||
run git clone https://git.coopcloud.tech/coop-cloud/recipes-catalogue-json.git $ABRA_DIR/catalogue
|
||||
run git clone https://git.coopcloud.tech/toolshed/recipes-catalogue-json.git $ABRA_DIR/catalogue
|
||||
assert_success
|
||||
fi
|
||||
}
|
||||
|
18
vendor/github.com/Azure/go-ansiterm/osc_string_state.go
generated
vendored
18
vendor/github.com/Azure/go-ansiterm/osc_string_state.go
generated
vendored
@ -11,21 +11,13 @@ func (oscState oscStringState) Handle(b byte) (s state, e error) {
|
||||
return nextState, err
|
||||
}
|
||||
|
||||
switch {
|
||||
case isOscStringTerminator(b):
|
||||
// There are several control characters and sequences which can
|
||||
// terminate an OSC string. Most of them are handled by the baseState
|
||||
// handler. The ANSI_BEL character is a special case which behaves as a
|
||||
// terminator only for an OSC string.
|
||||
if b == ANSI_BEL {
|
||||
return oscState.parser.ground, nil
|
||||
}
|
||||
|
||||
return oscState, nil
|
||||
}
|
||||
|
||||
// See below for OSC string terminators for linux
|
||||
// http://man7.org/linux/man-pages/man4/console_codes.4.html
|
||||
func isOscStringTerminator(b byte) bool {
|
||||
|
||||
if b == ANSI_BEL || b == 0x5C {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
3
vendor/github.com/go-git/go-git/v5/COMPATIBILITY.md
generated
vendored
3
vendor/github.com/go-git/go-git/v5/COMPATIBILITY.md
generated
vendored
@ -11,7 +11,7 @@ compatibility status with go-git.
|
||||
| `init` | `--bare` | ✅ | | |
|
||||
| `init` | `--template` <br/> `--separate-git-dir` <br/> `--shared` | ❌ | | |
|
||||
| `clone` | | ✅ | | - [PlainClone](_examples/clone/main.go) |
|
||||
| `clone` | Authentication: <br/> - none <br/> - access token <br/> - username + password <br/> - ssh | ✅ | | - [clone ssh](_examples/clone/auth/ssh/main.go) <br/> - [clone access token](_examples/clone/auth/basic/access_token/main.go) <br/> - [clone user + password](_examples/clone/auth/basic/username_password/main.go) |
|
||||
| `clone` | Authentication: <br/> - none <br/> - access token <br/> - username + password <br/> - ssh | ✅ | | - [clone ssh (private_key)](_examples/clone/auth/ssh/private_key/main.go) <br/> - [clone ssh (ssh_agent)](_examples/clone/auth/ssh/ssh_agent/main.go) <br/> - [clone access token](_examples/clone/auth/basic/access_token/main.go) <br/> - [clone user + password](_examples/clone/auth/basic/username_password/main.go) |
|
||||
| `clone` | `--progress` <br/> `--single-branch` <br/> `--depth` <br/> `--origin` <br/> `--recurse-submodules` <br/>`--shared` | ✅ | | - [recurse submodules](_examples/clone/main.go) <br/> - [progress](_examples/progress/main.go) |
|
||||
|
||||
## Basic snapshotting
|
||||
@ -34,6 +34,7 @@ compatibility status with go-git.
|
||||
| `merge` | | ⚠️ (partial) | Fast-forward only | |
|
||||
| `mergetool` | | ❌ | | |
|
||||
| `stash` | | ❌ | | |
|
||||
| `sparse-checkout` | | ✅ | | - [sparse-checkout](_examples/sparse-checkout/main.go) |
|
||||
| `tag` | | ✅ | | - [tag](_examples/tag/main.go) <br/> - [tag create and push](_examples/tag-create-push/main.go) |
|
||||
|
||||
## Sharing and updating projects
|
||||
|
7
vendor/github.com/go-git/go-git/v5/CONTRIBUTING.md
generated
vendored
7
vendor/github.com/go-git/go-git/v5/CONTRIBUTING.md
generated
vendored
@ -31,6 +31,13 @@ In order for a PR to be accepted it needs to pass a list of requirements:
|
||||
- If the PR is a new feature, it has to come with a suite of unit tests, that tests the new functionality.
|
||||
- In any case, all the PRs have to pass the personal evaluation of at least one of the maintainers of go-git.
|
||||
|
||||
### Branches
|
||||
|
||||
The `master` branch is currently used for maintaining the `v5` major release only. The accepted changes would
|
||||
be dependency bumps, bug fixes and small changes that aren't needed for `v6`. New development should target the
|
||||
`v6-exp` branch, and if agreed with at least one go-git maintainer, it can be back ported to `v5` by creating
|
||||
a new PR that targets `master`.
|
||||
|
||||
### Format of the commit message
|
||||
|
||||
Every commit message should describe what was changed, under which context and, if applicable, the GitHub issue it relates to:
|
||||
|
13
vendor/github.com/go-git/go-git/v5/blame.go
generated
vendored
13
vendor/github.com/go-git/go-git/v5/blame.go
generated
vendored
@ -97,13 +97,10 @@ func Blame(c *object.Commit, path string) (*BlameResult, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if finished == true {
|
||||
if finished {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b.lineToCommit = make([]*object.Commit, finalLength)
|
||||
for i := range needsMap {
|
||||
@ -309,8 +306,8 @@ func (b *blame) addBlames(curItems []*queueItem) (bool, error) {
|
||||
for h := range hunks {
|
||||
hLines := countLines(hunks[h].Text)
|
||||
for hl := 0; hl < hLines; hl++ {
|
||||
switch {
|
||||
case hunks[h].Type == diffmatchpatch.DiffEqual:
|
||||
switch hunks[h].Type {
|
||||
case diffmatchpatch.DiffEqual:
|
||||
prevl++
|
||||
curl++
|
||||
if curl == curItem.NeedsMap[need].Cur {
|
||||
@ -322,7 +319,7 @@ func (b *blame) addBlames(curItems []*queueItem) (bool, error) {
|
||||
break out
|
||||
}
|
||||
}
|
||||
case hunks[h].Type == diffmatchpatch.DiffInsert:
|
||||
case diffmatchpatch.DiffInsert:
|
||||
curl++
|
||||
if curl == curItem.NeedsMap[need].Cur {
|
||||
// the line we want is added, it may have been added here (or by another parent), skip it for now
|
||||
@ -331,7 +328,7 @@ func (b *blame) addBlames(curItems []*queueItem) (bool, error) {
|
||||
break out
|
||||
}
|
||||
}
|
||||
case hunks[h].Type == diffmatchpatch.DiffDelete:
|
||||
case diffmatchpatch.DiffDelete:
|
||||
prevl += hLines
|
||||
continue out
|
||||
default:
|
||||
|
2
vendor/github.com/go-git/go-git/v5/config/config.go
generated
vendored
2
vendor/github.com/go-git/go-git/v5/config/config.go
generated
vendored
@ -252,6 +252,7 @@ const (
|
||||
extensionsSection = "extensions"
|
||||
fetchKey = "fetch"
|
||||
urlKey = "url"
|
||||
pushurlKey = "pushurl"
|
||||
bareKey = "bare"
|
||||
worktreeKey = "worktree"
|
||||
commentCharKey = "commentChar"
|
||||
@ -633,6 +634,7 @@ func (c *RemoteConfig) unmarshal(s *format.Subsection) error {
|
||||
|
||||
c.Name = c.raw.Name
|
||||
c.URLs = append([]string(nil), c.raw.Options.GetAll(urlKey)...)
|
||||
c.URLs = append(c.URLs, c.raw.Options.GetAll(pushurlKey)...)
|
||||
c.Fetch = fetch
|
||||
c.Mirror = c.raw.Options.Get(mirrorKey) == "true"
|
||||
|
||||
|
7
vendor/github.com/go-git/go-git/v5/internal/revision/scanner.go
generated
vendored
7
vendor/github.com/go-git/go-git/v5/internal/revision/scanner.go
generated
vendored
@ -43,6 +43,11 @@ func tokenizeExpression(ch rune, tokenType token, check runeCategoryValidator, r
|
||||
return tokenType, string(data), nil
|
||||
}
|
||||
|
||||
// maxRevisionLength holds the maximum length that will be parsed for a
|
||||
// revision. Git itself doesn't enforce a max length, but rather leans on
|
||||
// the OS to enforce it via its ARG_MAX.
|
||||
const maxRevisionLength = 128 * 1024 // 128kb
|
||||
|
||||
var zeroRune = rune(0)
|
||||
|
||||
// scanner represents a lexical scanner.
|
||||
@ -52,7 +57,7 @@ type scanner struct {
|
||||
|
||||
// newScanner returns a new instance of scanner.
|
||||
func newScanner(r io.Reader) *scanner {
|
||||
return &scanner{r: bufio.NewReader(r)}
|
||||
return &scanner{r: bufio.NewReader(io.LimitReader(r, maxRevisionLength))}
|
||||
}
|
||||
|
||||
// Scan extracts tokens and their strings counterpart
|
||||
|
26
vendor/github.com/go-git/go-git/v5/options.go
generated
vendored
26
vendor/github.com/go-git/go-git/v5/options.go
generated
vendored
@ -416,6 +416,9 @@ type ResetOptions struct {
|
||||
// the index (resetting it to the tree of Commit) and the working tree
|
||||
// depending on Mode. If empty MixedReset is used.
|
||||
Mode ResetMode
|
||||
// Files, if not empty will constrain the reseting the index to only files
|
||||
// specified in this list.
|
||||
Files []string
|
||||
}
|
||||
|
||||
// Validate validates the fields and sets the default values.
|
||||
@ -790,3 +793,26 @@ type PlainInitOptions struct {
|
||||
|
||||
// Validate validates the fields and sets the default values.
|
||||
func (o *PlainInitOptions) Validate() error { return nil }
|
||||
|
||||
var (
|
||||
ErrNoRestorePaths = errors.New("you must specify path(s) to restore")
|
||||
)
|
||||
|
||||
// RestoreOptions describes how a restore should be performed.
|
||||
type RestoreOptions struct {
|
||||
// Marks to restore the content in the index
|
||||
Staged bool
|
||||
// Marks to restore the content of the working tree
|
||||
Worktree bool
|
||||
// List of file paths that will be restored
|
||||
Files []string
|
||||
}
|
||||
|
||||
// Validate validates the fields and sets the default values.
|
||||
func (o *RestoreOptions) Validate() error {
|
||||
if len(o.Files) == 0 {
|
||||
return ErrNoRestorePaths
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
4
vendor/github.com/go-git/go-git/v5/plumbing/format/gitignore/dir.go
generated
vendored
4
vendor/github.com/go-git/go-git/v5/plumbing/format/gitignore/dir.go
generated
vendored
@ -64,6 +64,10 @@ func ReadPatterns(fs billy.Filesystem, path []string) (ps []Pattern, err error)
|
||||
|
||||
for _, fi := range fis {
|
||||
if fi.IsDir() && fi.Name() != gitDir {
|
||||
if NewMatcher(ps).Match(append(path, fi.Name()), true) {
|
||||
continue
|
||||
}
|
||||
|
||||
var subps []Pattern
|
||||
subps, err = ReadPatterns(fs, append(path, fi.Name()))
|
||||
if err != nil {
|
||||
|
115
vendor/github.com/go-git/go-git/v5/plumbing/format/index/decoder.go
generated
vendored
115
vendor/github.com/go-git/go-git/v5/plumbing/format/index/decoder.go
generated
vendored
@ -24,8 +24,8 @@ var (
|
||||
// ErrInvalidChecksum is returned by Decode if the SHA1 hash mismatch with
|
||||
// the read content
|
||||
ErrInvalidChecksum = errors.New("invalid checksum")
|
||||
|
||||
errUnknownExtension = errors.New("unknown extension")
|
||||
// ErrUnknownExtension is returned when an index extension is encountered that is considered mandatory
|
||||
ErrUnknownExtension = errors.New("unknown extension")
|
||||
)
|
||||
|
||||
const (
|
||||
@ -39,6 +39,7 @@ const (
|
||||
|
||||
// A Decoder reads and decodes index files from an input stream.
|
||||
type Decoder struct {
|
||||
buf *bufio.Reader
|
||||
r io.Reader
|
||||
hash hash.Hash
|
||||
lastEntry *Entry
|
||||
@ -49,8 +50,10 @@ type Decoder struct {
|
||||
// NewDecoder returns a new decoder that reads from r.
|
||||
func NewDecoder(r io.Reader) *Decoder {
|
||||
h := hash.New(hash.CryptoType)
|
||||
buf := bufio.NewReader(r)
|
||||
return &Decoder{
|
||||
r: io.TeeReader(r, h),
|
||||
buf: buf,
|
||||
r: io.TeeReader(buf, h),
|
||||
hash: h,
|
||||
extReader: bufio.NewReader(nil),
|
||||
}
|
||||
@ -210,71 +213,75 @@ func (d *Decoder) readExtensions(idx *Index) error {
|
||||
// count that they are not supported by jgit or libgit
|
||||
|
||||
var expected []byte
|
||||
var peeked []byte
|
||||
var err error
|
||||
|
||||
var header [4]byte
|
||||
// we should always be able to peek for 4 bytes (header) + 4 bytes (extlen) + final hash
|
||||
// if this fails, we know that we're at the end of the index
|
||||
peekLen := 4 + 4 + d.hash.Size()
|
||||
|
||||
for {
|
||||
expected = d.hash.Sum(nil)
|
||||
|
||||
var n int
|
||||
if n, err = io.ReadFull(d.r, header[:]); err != nil {
|
||||
if n == 0 {
|
||||
err = io.EOF
|
||||
}
|
||||
|
||||
peeked, err = d.buf.Peek(peekLen)
|
||||
if len(peeked) < peekLen {
|
||||
// there can't be an extension at this point, so let's bail out
|
||||
break
|
||||
}
|
||||
|
||||
err = d.readExtension(idx, header[:])
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if err != errUnknownExtension {
|
||||
return err
|
||||
}
|
||||
|
||||
return d.readChecksum(expected, header)
|
||||
}
|
||||
|
||||
func (d *Decoder) readExtension(idx *Index, header []byte) error {
|
||||
switch {
|
||||
case bytes.Equal(header, treeExtSignature):
|
||||
r, err := d.getExtensionReader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = d.readExtension(idx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return d.readChecksum(expected)
|
||||
}
|
||||
|
||||
func (d *Decoder) readExtension(idx *Index) error {
|
||||
var header [4]byte
|
||||
|
||||
if _, err := io.ReadFull(d.r, header[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r, err := d.getExtensionReader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch {
|
||||
case bytes.Equal(header[:], treeExtSignature):
|
||||
idx.Cache = &Tree{}
|
||||
d := &treeExtensionDecoder{r}
|
||||
if err := d.Decode(idx.Cache); err != nil {
|
||||
return err
|
||||
}
|
||||
case bytes.Equal(header, resolveUndoExtSignature):
|
||||
r, err := d.getExtensionReader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case bytes.Equal(header[:], resolveUndoExtSignature):
|
||||
idx.ResolveUndo = &ResolveUndo{}
|
||||
d := &resolveUndoDecoder{r}
|
||||
if err := d.Decode(idx.ResolveUndo); err != nil {
|
||||
return err
|
||||
}
|
||||
case bytes.Equal(header, endOfIndexEntryExtSignature):
|
||||
r, err := d.getExtensionReader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case bytes.Equal(header[:], endOfIndexEntryExtSignature):
|
||||
idx.EndOfIndexEntry = &EndOfIndexEntry{}
|
||||
d := &endOfIndexEntryDecoder{r}
|
||||
if err := d.Decode(idx.EndOfIndexEntry); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return errUnknownExtension
|
||||
// See https://git-scm.com/docs/index-format, which says:
|
||||
// If the first byte is 'A'..'Z' the extension is optional and can be ignored.
|
||||
if header[0] < 'A' || header[0] > 'Z' {
|
||||
return ErrUnknownExtension
|
||||
}
|
||||
|
||||
d := &unknownExtensionDecoder{r}
|
||||
if err := d.Decode(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -290,11 +297,10 @@ func (d *Decoder) getExtensionReader() (*bufio.Reader, error) {
|
||||
return d.extReader, nil
|
||||
}
|
||||
|
||||
func (d *Decoder) readChecksum(expected []byte, alreadyRead [4]byte) error {
|
||||
func (d *Decoder) readChecksum(expected []byte) error {
|
||||
var h plumbing.Hash
|
||||
copy(h[:4], alreadyRead[:])
|
||||
|
||||
if _, err := io.ReadFull(d.r, h[4:]); err != nil {
|
||||
if _, err := io.ReadFull(d.r, h[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -476,3 +482,22 @@ func (d *endOfIndexEntryDecoder) Decode(e *EndOfIndexEntry) error {
|
||||
_, err = io.ReadFull(d.r, e.Hash[:])
|
||||
return err
|
||||
}
|
||||
|
||||
type unknownExtensionDecoder struct {
|
||||
r *bufio.Reader
|
||||
}
|
||||
|
||||
func (d *unknownExtensionDecoder) Decode() error {
|
||||
var buf [1024]byte
|
||||
|
||||
for {
|
||||
_, err := d.r.Read(buf[:])
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
94
vendor/github.com/go-git/go-git/v5/plumbing/format/index/encoder.go
generated
vendored
94
vendor/github.com/go-git/go-git/v5/plumbing/format/index/encoder.go
generated
vendored
@ -3,8 +3,11 @@ package index
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-git/go-git/v5/plumbing/hash"
|
||||
@ -13,7 +16,7 @@ import (
|
||||
|
||||
var (
|
||||
// EncodeVersionSupported is the range of supported index versions
|
||||
EncodeVersionSupported uint32 = 3
|
||||
EncodeVersionSupported uint32 = 4
|
||||
|
||||
// ErrInvalidTimestamp is returned by Encode if a Index with a Entry with
|
||||
// negative timestamp values
|
||||
@ -22,20 +25,25 @@ var (
|
||||
|
||||
// An Encoder writes an Index to an output stream.
|
||||
type Encoder struct {
|
||||
w io.Writer
|
||||
hash hash.Hash
|
||||
w io.Writer
|
||||
hash hash.Hash
|
||||
lastEntry *Entry
|
||||
}
|
||||
|
||||
// NewEncoder returns a new encoder that writes to w.
|
||||
func NewEncoder(w io.Writer) *Encoder {
|
||||
h := hash.New(hash.CryptoType)
|
||||
mw := io.MultiWriter(w, h)
|
||||
return &Encoder{mw, h}
|
||||
return &Encoder{mw, h, nil}
|
||||
}
|
||||
|
||||
// Encode writes the Index to the stream of the encoder.
|
||||
func (e *Encoder) Encode(idx *Index) error {
|
||||
// TODO: support v4
|
||||
return e.encode(idx, true)
|
||||
}
|
||||
|
||||
func (e *Encoder) encode(idx *Index, footer bool) error {
|
||||
|
||||
// TODO: support extensions
|
||||
if idx.Version > EncodeVersionSupported {
|
||||
return ErrUnsupportedVersion
|
||||
@ -49,7 +57,10 @@ func (e *Encoder) Encode(idx *Index) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return e.encodeFooter()
|
||||
if footer {
|
||||
return e.encodeFooter()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeHeader(idx *Index) error {
|
||||
@ -64,7 +75,7 @@ func (e *Encoder) encodeEntries(idx *Index) error {
|
||||
sort.Sort(byName(idx.Entries))
|
||||
|
||||
for _, entry := range idx.Entries {
|
||||
if err := e.encodeEntry(entry); err != nil {
|
||||
if err := e.encodeEntry(idx, entry); err != nil {
|
||||
return err
|
||||
}
|
||||
entryLength := entryHeaderLength
|
||||
@ -73,7 +84,7 @@ func (e *Encoder) encodeEntries(idx *Index) error {
|
||||
}
|
||||
|
||||
wrote := entryLength + len(entry.Name)
|
||||
if err := e.padEntry(wrote); err != nil {
|
||||
if err := e.padEntry(idx, wrote); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -81,7 +92,7 @@ func (e *Encoder) encodeEntries(idx *Index) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeEntry(entry *Entry) error {
|
||||
func (e *Encoder) encodeEntry(idx *Index, entry *Entry) error {
|
||||
sec, nsec, err := e.timeToUint32(&entry.CreatedAt)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -132,9 +143,68 @@ func (e *Encoder) encodeEntry(entry *Entry) error {
|
||||
return err
|
||||
}
|
||||
|
||||
switch idx.Version {
|
||||
case 2, 3:
|
||||
err = e.encodeEntryName(entry)
|
||||
case 4:
|
||||
err = e.encodeEntryNameV4(entry)
|
||||
default:
|
||||
err = ErrUnsupportedVersion
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeEntryName(entry *Entry) error {
|
||||
return binary.Write(e.w, []byte(entry.Name))
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeEntryNameV4(entry *Entry) error {
|
||||
name := entry.Name
|
||||
l := 0
|
||||
if e.lastEntry != nil {
|
||||
dir := path.Dir(e.lastEntry.Name) + "/"
|
||||
if strings.HasPrefix(entry.Name, dir) {
|
||||
l = len(e.lastEntry.Name) - len(dir)
|
||||
name = strings.TrimPrefix(entry.Name, dir)
|
||||
} else {
|
||||
l = len(e.lastEntry.Name)
|
||||
}
|
||||
}
|
||||
|
||||
e.lastEntry = entry
|
||||
|
||||
err := binary.WriteVariableWidthInt(e.w, int64(l))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return binary.Write(e.w, []byte(name+string('\x00')))
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeRawExtension(signature string, data []byte) error {
|
||||
if len(signature) != 4 {
|
||||
return fmt.Errorf("invalid signature length")
|
||||
}
|
||||
|
||||
_, err := e.w.Write([]byte(signature))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = binary.WriteUint32(e.w, uint32(len(data)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = e.w.Write(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Encoder) timeToUint32(t *time.Time) (uint32, uint32, error) {
|
||||
if t.IsZero() {
|
||||
return 0, 0, nil
|
||||
@ -147,7 +217,11 @@ func (e *Encoder) timeToUint32(t *time.Time) (uint32, uint32, error) {
|
||||
return uint32(t.Unix()), uint32(t.Nanosecond()), nil
|
||||
}
|
||||
|
||||
func (e *Encoder) padEntry(wrote int) error {
|
||||
func (e *Encoder) padEntry(idx *Index, wrote int) error {
|
||||
if idx.Version == 4 {
|
||||
return nil
|
||||
}
|
||||
|
||||
padLen := 8 - wrote%8
|
||||
|
||||
_, err := e.w.Write(bytes.Repeat([]byte{'\x00'}, padLen))
|
||||
|
20
vendor/github.com/go-git/go-git/v5/plumbing/format/packfile/delta_index.go
generated
vendored
20
vendor/github.com/go-git/go-git/v5/plumbing/format/packfile/delta_index.go
generated
vendored
@ -32,19 +32,17 @@ func (idx *deltaIndex) findMatch(src, tgt []byte, tgtOffset int) (srcOffset, l i
|
||||
return 0, -1
|
||||
}
|
||||
|
||||
if len(tgt) >= tgtOffset+s && len(src) >= blksz {
|
||||
h := hashBlock(tgt, tgtOffset)
|
||||
tIdx := h & idx.mask
|
||||
eIdx := idx.table[tIdx]
|
||||
if eIdx != 0 {
|
||||
srcOffset = idx.entries[eIdx]
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
l = matchLength(src, tgt, tgtOffset, srcOffset)
|
||||
h := hashBlock(tgt, tgtOffset)
|
||||
tIdx := h & idx.mask
|
||||
eIdx := idx.table[tIdx]
|
||||
if eIdx == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
srcOffset = idx.entries[eIdx]
|
||||
|
||||
l = matchLength(src, tgt, tgtOffset, srcOffset)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
21
vendor/github.com/go-git/go-git/v5/plumbing/format/packfile/patch_delta.go
generated
vendored
21
vendor/github.com/go-git/go-git/v5/plumbing/format/packfile/patch_delta.go
generated
vendored
@ -26,6 +26,13 @@ var (
|
||||
const (
|
||||
payload = 0x7f // 0111 1111
|
||||
continuation = 0x80 // 1000 0000
|
||||
|
||||
// maxPatchPreemptionSize defines what is the max size of bytes to be
|
||||
// premptively made available for a patch operation.
|
||||
maxPatchPreemptionSize uint = 65536
|
||||
|
||||
// minDeltaSize defines the smallest size for a delta.
|
||||
minDeltaSize = 4
|
||||
)
|
||||
|
||||
type offset struct {
|
||||
@ -86,9 +93,13 @@ func ApplyDelta(target, base plumbing.EncodedObject, delta []byte) (err error) {
|
||||
}
|
||||
|
||||
// PatchDelta returns the result of applying the modification deltas in delta to src.
|
||||
// An error will be returned if delta is corrupted (ErrDeltaLen) or an action command
|
||||
// An error will be returned if delta is corrupted (ErrInvalidDelta) or an action command
|
||||
// is not copy from source or copy from delta (ErrDeltaCmd).
|
||||
func PatchDelta(src, delta []byte) ([]byte, error) {
|
||||
if len(src) == 0 || len(delta) < minDeltaSize {
|
||||
return nil, ErrInvalidDelta
|
||||
}
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
if err := patchDelta(b, src, delta); err != nil {
|
||||
return nil, err
|
||||
@ -239,7 +250,9 @@ func patchDelta(dst *bytes.Buffer, src, delta []byte) error {
|
||||
remainingTargetSz := targetSz
|
||||
|
||||
var cmd byte
|
||||
dst.Grow(int(targetSz))
|
||||
|
||||
growSz := min(targetSz, maxPatchPreemptionSize)
|
||||
dst.Grow(int(growSz))
|
||||
for {
|
||||
if len(delta) == 0 {
|
||||
return ErrInvalidDelta
|
||||
@ -403,6 +416,10 @@ func patchDeltaWriter(dst io.Writer, base io.ReaderAt, delta io.Reader,
|
||||
// This must be called twice on the delta data buffer, first to get the
|
||||
// expected source buffer size, and again to get the target buffer size.
|
||||
func decodeLEB128(input []byte) (uint, []byte) {
|
||||
if len(input) == 0 {
|
||||
return 0, input
|
||||
}
|
||||
|
||||
var num, sz uint
|
||||
var b byte
|
||||
for {
|
||||
|
2
vendor/github.com/go-git/go-git/v5/plumbing/format/pktline/scanner.go
generated
vendored
2
vendor/github.com/go-git/go-git/v5/plumbing/format/pktline/scanner.go
generated
vendored
@ -140,6 +140,8 @@ func asciiHexToByte(b byte) (byte, error) {
|
||||
return b - '0', nil
|
||||
case b >= 'a' && b <= 'f':
|
||||
return b - 'a' + 10, nil
|
||||
case b >= 'A' && b <= 'F':
|
||||
return b - 'A' + 10, nil
|
||||
default:
|
||||
return 0, ErrInvalidPktLen
|
||||
}
|
||||
|
1
vendor/github.com/go-git/go-git/v5/plumbing/object/signature.go
generated
vendored
1
vendor/github.com/go-git/go-git/v5/plumbing/object/signature.go
generated
vendored
@ -19,6 +19,7 @@ var (
|
||||
// a PKCS#7 (S/MIME) signature.
|
||||
x509SignatureFormat = signatureFormat{
|
||||
[]byte("-----BEGIN CERTIFICATE-----"),
|
||||
[]byte("-----BEGIN SIGNED MESSAGE-----"),
|
||||
}
|
||||
|
||||
// sshSignatureFormat is the format of an SSH signature.
|
||||
|
1
vendor/github.com/go-git/go-git/v5/plumbing/object/tree.go
generated
vendored
1
vendor/github.com/go-git/go-git/v5/plumbing/object/tree.go
generated
vendored
@ -295,6 +295,7 @@ func (s TreeEntrySorter) Swap(i, j int) {
|
||||
}
|
||||
|
||||
// Encode transforms a Tree into a plumbing.EncodedObject.
|
||||
// The tree entries must be sorted by name.
|
||||
func (t *Tree) Encode(o plumbing.EncodedObject) (err error) {
|
||||
o.SetType(plumbing.TreeObject)
|
||||
w, err := o.Writer()
|
||||
|
76
vendor/github.com/go-git/go-git/v5/plumbing/protocol/packp/filter.go
generated
vendored
Normal file
76
vendor/github.com/go-git/go-git/v5/plumbing/protocol/packp/filter.go
generated
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
package packp
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var ErrUnsupportedObjectFilterType = errors.New("unsupported object filter type")
|
||||
|
||||
// Filter values enable the partial clone capability which causes
|
||||
// the server to omit objects that match the filter.
|
||||
//
|
||||
// See [Git's documentation] for more details.
|
||||
//
|
||||
// [Git's documentation]: https://github.com/git/git/blob/e02ecfcc534e2021aae29077a958dd11c3897e4c/Documentation/rev-list-options.txt#L948
|
||||
type Filter string
|
||||
|
||||
type BlobLimitPrefix string
|
||||
|
||||
const (
|
||||
BlobLimitPrefixNone BlobLimitPrefix = ""
|
||||
BlobLimitPrefixKibi BlobLimitPrefix = "k"
|
||||
BlobLimitPrefixMebi BlobLimitPrefix = "m"
|
||||
BlobLimitPrefixGibi BlobLimitPrefix = "g"
|
||||
)
|
||||
|
||||
// FilterBlobNone omits all blobs.
|
||||
func FilterBlobNone() Filter {
|
||||
return "blob:none"
|
||||
}
|
||||
|
||||
// FilterBlobLimit omits blobs of size at least n bytes (when prefix is
|
||||
// BlobLimitPrefixNone), n kibibytes (when prefix is BlobLimitPrefixKibi),
|
||||
// n mebibytes (when prefix is BlobLimitPrefixMebi) or n gibibytes (when
|
||||
// prefix is BlobLimitPrefixGibi). n can be zero, in which case all blobs
|
||||
// will be omitted.
|
||||
func FilterBlobLimit(n uint64, prefix BlobLimitPrefix) Filter {
|
||||
return Filter(fmt.Sprintf("blob:limit=%d%s", n, prefix))
|
||||
}
|
||||
|
||||
// FilterTreeDepth omits all blobs and trees whose depth from the root tree
|
||||
// is larger or equal to depth.
|
||||
func FilterTreeDepth(depth uint64) Filter {
|
||||
return Filter(fmt.Sprintf("tree:%d", depth))
|
||||
}
|
||||
|
||||
// FilterObjectType omits all objects which are not of the requested type t.
|
||||
// Supported types are TagObject, CommitObject, TreeObject and BlobObject.
|
||||
func FilterObjectType(t plumbing.ObjectType) (Filter, error) {
|
||||
switch t {
|
||||
case plumbing.TagObject:
|
||||
fallthrough
|
||||
case plumbing.CommitObject:
|
||||
fallthrough
|
||||
case plumbing.TreeObject:
|
||||
fallthrough
|
||||
case plumbing.BlobObject:
|
||||
return Filter(fmt.Sprintf("object:type=%s", t.String())), nil
|
||||
default:
|
||||
return "", fmt.Errorf("%w: %s", ErrUnsupportedObjectFilterType, t.String())
|
||||
}
|
||||
}
|
||||
|
||||
// FilterCombine combines multiple Filter values together.
|
||||
func FilterCombine(filters ...Filter) Filter {
|
||||
var escapedFilters []string
|
||||
|
||||
for _, filter := range filters {
|
||||
escapedFilters = append(escapedFilters, url.QueryEscape(string(filter)))
|
||||
}
|
||||
|
||||
return Filter(fmt.Sprintf("combine:%s", strings.Join(escapedFilters, "+")))
|
||||
}
|
2
vendor/github.com/go-git/go-git/v5/plumbing/protocol/packp/sideband/demux.go
generated
vendored
2
vendor/github.com/go-git/go-git/v5/plumbing/protocol/packp/sideband/demux.go
generated
vendored
@ -114,7 +114,7 @@ func (d *Demuxer) nextPackData() ([]byte, error) {
|
||||
|
||||
size := len(content)
|
||||
if size == 0 {
|
||||
return nil, nil
|
||||
return nil, io.EOF
|
||||
} else if size > d.max {
|
||||
return nil, ErrMaxPackedExceeded
|
||||
}
|
||||
|
3
vendor/github.com/go-git/go-git/v5/plumbing/protocol/packp/srvresp.go
generated
vendored
3
vendor/github.com/go-git/go-git/v5/plumbing/protocol/packp/srvresp.go
generated
vendored
@ -120,6 +120,9 @@ func (r *ServerResponse) decodeACKLine(line []byte) error {
|
||||
}
|
||||
|
||||
sp := bytes.Index(line, []byte(" "))
|
||||
if sp+41 > len(line) {
|
||||
return fmt.Errorf("malformed ACK %q", line)
|
||||
}
|
||||
h := plumbing.NewHash(string(line[sp+1 : sp+41]))
|
||||
r.ACKs = append(r.ACKs, h)
|
||||
return nil
|
||||
|
1
vendor/github.com/go-git/go-git/v5/plumbing/protocol/packp/ulreq.go
generated
vendored
1
vendor/github.com/go-git/go-git/v5/plumbing/protocol/packp/ulreq.go
generated
vendored
@ -17,6 +17,7 @@ type UploadRequest struct {
|
||||
Wants []plumbing.Hash
|
||||
Shallows []plumbing.Hash
|
||||
Depth Depth
|
||||
Filter Filter
|
||||
}
|
||||
|
||||
// Depth values stores the desired depth of the requested packfile: see
|
||||
|
11
vendor/github.com/go-git/go-git/v5/plumbing/protocol/packp/ulreq_encode.go
generated
vendored
11
vendor/github.com/go-git/go-git/v5/plumbing/protocol/packp/ulreq_encode.go
generated
vendored
@ -132,6 +132,17 @@ func (e *ulReqEncoder) encodeDepth() stateFn {
|
||||
return nil
|
||||
}
|
||||
|
||||
return e.encodeFilter
|
||||
}
|
||||
|
||||
func (e *ulReqEncoder) encodeFilter() stateFn {
|
||||
if filter := e.data.Filter; filter != "" {
|
||||
if err := e.pe.Encodef("filter %s\n", filter); err != nil {
|
||||
e.err = fmt.Errorf("encoding filter %s: %s", filter, err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return e.encodeFlush
|
||||
}
|
||||
|
||||
|
4
vendor/github.com/go-git/go-git/v5/plumbing/reference.go
generated
vendored
4
vendor/github.com/go-git/go-git/v5/plumbing/reference.go
generated
vendored
@ -188,7 +188,7 @@ func (r ReferenceName) Validate() error {
|
||||
|
||||
isBranch := r.IsBranch()
|
||||
isTag := r.IsTag()
|
||||
for _, part := range parts {
|
||||
for i, part := range parts {
|
||||
// rule 6
|
||||
if len(part) == 0 {
|
||||
return ErrInvalidReferenceName
|
||||
@ -205,7 +205,7 @@ func (r ReferenceName) Validate() error {
|
||||
return ErrInvalidReferenceName
|
||||
}
|
||||
|
||||
if (isBranch || isTag) && strings.HasPrefix(part, "-") { // branches & tags can't start with -
|
||||
if (isBranch || isTag) && strings.HasPrefix(part, "-") && (i == 2) { // branches & tags can't start with -
|
||||
return ErrInvalidReferenceName
|
||||
}
|
||||
}
|
||||
|
7
vendor/github.com/go-git/go-git/v5/plumbing/transport/common.go
generated
vendored
7
vendor/github.com/go-git/go-git/v5/plumbing/transport/common.go
generated
vendored
@ -19,6 +19,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@ -295,7 +296,11 @@ func parseFile(endpoint string) (*Endpoint, bool) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
path := endpoint
|
||||
path, err := filepath.Abs(endpoint)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return &Endpoint{
|
||||
Protocol: "file",
|
||||
Path: path,
|
||||
|
19
vendor/github.com/go-git/go-git/v5/plumbing/transport/file/client.go
generated
vendored
19
vendor/github.com/go-git/go-git/v5/plumbing/transport/file/client.go
generated
vendored
@ -7,6 +7,7 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/go-git/go-git/v5/plumbing/transport"
|
||||
@ -95,7 +96,23 @@ func (r *runner) Command(cmd string, ep *transport.Endpoint, auth transport.Auth
|
||||
}
|
||||
}
|
||||
|
||||
return &command{cmd: execabs.Command(cmd, ep.Path)}, nil
|
||||
return &command{cmd: execabs.Command(cmd, adjustPathForWindows(ep.Path))}, nil
|
||||
}
|
||||
|
||||
func isDriveLetter(c byte) bool {
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
|
||||
}
|
||||
|
||||
// On Windows, the path that results from a file: URL has a leading slash. This
|
||||
// has to be removed if there's a drive letter
|
||||
func adjustPathForWindows(p string) string {
|
||||
if runtime.GOOS != "windows" {
|
||||
return p
|
||||
}
|
||||
if len(p) >= 3 && p[0] == '/' && isDriveLetter(p[1]) && p[2] == ':' {
|
||||
return p[1:]
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
type command struct {
|
||||
|
6
vendor/github.com/go-git/go-git/v5/plumbing/transport/http/common.go
generated
vendored
6
vendor/github.com/go-git/go-git/v5/plumbing/transport/http/common.go
generated
vendored
@ -430,11 +430,11 @@ func NewErr(r *http.Response) error {
|
||||
|
||||
switch r.StatusCode {
|
||||
case http.StatusUnauthorized:
|
||||
return transport.ErrAuthenticationRequired
|
||||
return fmt.Errorf("%w: %s", transport.ErrAuthenticationRequired, reason)
|
||||
case http.StatusForbidden:
|
||||
return transport.ErrAuthorizationFailed
|
||||
return fmt.Errorf("%w: %s", transport.ErrAuthorizationFailed, reason)
|
||||
case http.StatusNotFound:
|
||||
return transport.ErrRepositoryNotFound
|
||||
return fmt.Errorf("%w: %s", transport.ErrRepositoryNotFound, reason)
|
||||
}
|
||||
|
||||
return plumbing.NewUnexpectedError(&Err{r, reason})
|
||||
|
12
vendor/github.com/go-git/go-git/v5/plumbing/transport/server/loader.go
generated
vendored
12
vendor/github.com/go-git/go-git/v5/plumbing/transport/server/loader.go
generated
vendored
@ -40,8 +40,16 @@ func (l *fsLoader) Load(ep *transport.Endpoint) (storer.Storer, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := fs.Stat("config"); err != nil {
|
||||
return nil, transport.ErrRepositoryNotFound
|
||||
var bare bool
|
||||
if _, err := fs.Stat("config"); err == nil {
|
||||
bare = true
|
||||
}
|
||||
|
||||
if !bare {
|
||||
// do not use git.GitDirName due to import cycle
|
||||
if _, err := fs.Stat(".git"); err != nil {
|
||||
return nil, transport.ErrRepositoryNotFound
|
||||
}
|
||||
}
|
||||
|
||||
return filesystem.NewStorage(fs, cache.NewObjectLRUDefault()), nil
|
||||
|
33
vendor/github.com/go-git/go-git/v5/remote.go
generated
vendored
33
vendor/github.com/go-git/go-git/v5/remote.go
generated
vendored
@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/go-git/go-billy/v5/osfs"
|
||||
|
||||
"github.com/go-git/go-git/v5/config"
|
||||
"github.com/go-git/go-git/v5/internal/url"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
@ -82,7 +83,7 @@ func (r *Remote) String() string {
|
||||
var fetch, push string
|
||||
if len(r.c.URLs) > 0 {
|
||||
fetch = r.c.URLs[0]
|
||||
push = r.c.URLs[0]
|
||||
push = r.c.URLs[len(r.c.URLs)-1]
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s\t%s (fetch)\n%[1]s\t%[3]s (push)", r.c.Name, fetch, push)
|
||||
@ -109,8 +110,8 @@ func (r *Remote) PushContext(ctx context.Context, o *PushOptions) (err error) {
|
||||
return fmt.Errorf("remote names don't match: %s != %s", o.RemoteName, r.c.Name)
|
||||
}
|
||||
|
||||
if o.RemoteURL == "" {
|
||||
o.RemoteURL = r.c.URLs[0]
|
||||
if o.RemoteURL == "" && len(r.c.URLs) > 0 {
|
||||
o.RemoteURL = r.c.URLs[len(r.c.URLs)-1]
|
||||
}
|
||||
|
||||
s, err := newSendPackSession(o.RemoteURL, o.Auth, o.InsecureSkipTLS, o.CABundle, o.ProxyOptions)
|
||||
@ -491,7 +492,18 @@ func (r *Remote) fetch(ctx context.Context, o *FetchOptions) (sto storer.Referen
|
||||
}
|
||||
|
||||
if !updated && !updatedPrune {
|
||||
return remoteRefs, NoErrAlreadyUpToDate
|
||||
// No references updated, but may have fetched new objects, check if we now have any of our wants
|
||||
for _, hash := range req.Wants {
|
||||
exists, _ := objectExists(r.s, hash)
|
||||
if exists {
|
||||
updated = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !updated {
|
||||
return remoteRefs, NoErrAlreadyUpToDate
|
||||
}
|
||||
}
|
||||
|
||||
return remoteRefs, nil
|
||||
@ -878,17 +890,12 @@ func getHavesFromRef(
|
||||
return nil
|
||||
}
|
||||
|
||||
// No need to load the commit if we know the remote already
|
||||
// has this hash.
|
||||
if remoteRefs[h] {
|
||||
haves[h] = true
|
||||
return nil
|
||||
}
|
||||
|
||||
commit, err := object.GetCommit(s, h)
|
||||
if err != nil {
|
||||
// Ignore the error if this isn't a commit.
|
||||
haves[ref.Hash()] = true
|
||||
if !errors.Is(err, plumbing.ErrObjectNotFound) {
|
||||
// Ignore the error if this isn't a commit.
|
||||
haves[ref.Hash()] = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
4
vendor/github.com/go-git/go-git/v5/repository.go
generated
vendored
4
vendor/github.com/go-git/go-git/v5/repository.go
generated
vendored
@ -956,7 +956,7 @@ func (r *Repository) clone(ctx context.Context, o *CloneOptions) error {
|
||||
}
|
||||
|
||||
if o.RecurseSubmodules != NoRecurseSubmodules {
|
||||
if err := w.updateSubmodules(&SubmoduleUpdateOptions{
|
||||
if err := w.updateSubmodules(ctx, &SubmoduleUpdateOptions{
|
||||
RecurseSubmodules: o.RecurseSubmodules,
|
||||
Depth: func() int {
|
||||
if o.ShallowSubmodules {
|
||||
@ -1037,7 +1037,7 @@ func (r *Repository) setIsBare(isBare bool) error {
|
||||
return r.Storer.SetConfig(cfg)
|
||||
}
|
||||
|
||||
func (r *Repository) updateRemoteConfigIfNeeded(o *CloneOptions, c *config.RemoteConfig, head *plumbing.Reference) error {
|
||||
func (r *Repository) updateRemoteConfigIfNeeded(o *CloneOptions, c *config.RemoteConfig, _ *plumbing.Reference) error {
|
||||
if !o.SingleBranch {
|
||||
return nil
|
||||
}
|
||||
|
69
vendor/github.com/go-git/go-git/v5/status.go
generated
vendored
69
vendor/github.com/go-git/go-git/v5/status.go
generated
vendored
@ -4,6 +4,9 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
mindex "github.com/go-git/go-git/v5/utils/merkletrie/index"
|
||||
"github.com/go-git/go-git/v5/utils/merkletrie/noder"
|
||||
)
|
||||
|
||||
// Status represents the current status of a Worktree.
|
||||
@ -77,3 +80,69 @@ const (
|
||||
Copied StatusCode = 'C'
|
||||
UpdatedButUnmerged StatusCode = 'U'
|
||||
)
|
||||
|
||||
// StatusStrategy defines the different types of strategies when processing
|
||||
// the worktree status.
|
||||
type StatusStrategy int
|
||||
|
||||
const (
|
||||
// TODO: (V6) Review the default status strategy.
|
||||
// TODO: (V6) Review the type used to represent Status, to enable lazy
|
||||
// processing of statuses going direct to the backing filesystem.
|
||||
defaultStatusStrategy = Empty
|
||||
|
||||
// Empty starts its status map from empty. Missing entries for a given
|
||||
// path means that the file is untracked. This causes a known issue (#119)
|
||||
// whereby unmodified files can be incorrectly reported as untracked.
|
||||
//
|
||||
// This can be used when returning the changed state within a modified Worktree.
|
||||
// For example, to check whether the current worktree is clean.
|
||||
Empty StatusStrategy = 0
|
||||
// Preload goes through all existing nodes from the index and add them to the
|
||||
// status map as unmodified. This is currently the most reliable strategy
|
||||
// although it comes at a performance cost in large repositories.
|
||||
//
|
||||
// This method is recommended when fetching the status of unmodified files.
|
||||
// For example, to confirm the status of a specific file that is either
|
||||
// untracked or unmodified.
|
||||
Preload StatusStrategy = 1
|
||||
)
|
||||
|
||||
func (s StatusStrategy) new(w *Worktree) (Status, error) {
|
||||
switch s {
|
||||
case Preload:
|
||||
return preloadStatus(w)
|
||||
case Empty:
|
||||
return make(Status), nil
|
||||
}
|
||||
return nil, fmt.Errorf("%w: %+v", ErrUnsupportedStatusStrategy, s)
|
||||
}
|
||||
|
||||
func preloadStatus(w *Worktree) (Status, error) {
|
||||
idx, err := w.r.Storer.Index()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
idxRoot := mindex.NewRootNode(idx)
|
||||
nodes := []noder.Noder{idxRoot}
|
||||
|
||||
status := make(Status)
|
||||
for len(nodes) > 0 {
|
||||
var node noder.Noder
|
||||
node, nodes = nodes[0], nodes[1:]
|
||||
if node.IsDir() {
|
||||
children, err := node.Children()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nodes = append(nodes, children...)
|
||||
continue
|
||||
}
|
||||
fs := status.File(node.Name())
|
||||
fs.Worktree = Unmodified
|
||||
fs.Staging = Unmodified
|
||||
}
|
||||
|
||||
return status, nil
|
||||
}
|
||||
|
35
vendor/github.com/go-git/go-git/v5/storage/filesystem/dotgit/dotgit.go
generated
vendored
35
vendor/github.com/go-git/go-git/v5/storage/filesystem/dotgit/dotgit.go
generated
vendored
@ -72,6 +72,9 @@ var (
|
||||
// ErrIsDir is returned when a reference file is attempting to be read,
|
||||
// but the path specified is a directory.
|
||||
ErrIsDir = errors.New("reference path is a directory")
|
||||
// ErrEmptyRefFile is returned when a reference file is attempted to be read,
|
||||
// but the file is empty
|
||||
ErrEmptyRefFile = errors.New("ref file is empty")
|
||||
)
|
||||
|
||||
// Options holds configuration for the storage.
|
||||
@ -249,7 +252,7 @@ func (d *DotGit) objectPacks() ([]plumbing.Hash, error) {
|
||||
continue
|
||||
}
|
||||
|
||||
h := plumbing.NewHash(n[5 : len(n)-5]) //pack-(hash).pack
|
||||
h := plumbing.NewHash(n[5 : len(n)-5]) // pack-(hash).pack
|
||||
if h.IsZero() {
|
||||
// Ignore files with badly-formatted names.
|
||||
continue
|
||||
@ -661,18 +664,33 @@ func (d *DotGit) readReferenceFrom(rd io.Reader, name string) (ref *plumbing.Ref
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(b) == 0 {
|
||||
return nil, ErrEmptyRefFile
|
||||
}
|
||||
|
||||
line := strings.TrimSpace(string(b))
|
||||
return plumbing.NewReferenceFromStrings(name, line), nil
|
||||
}
|
||||
|
||||
// checkReferenceAndTruncate reads the reference from the given file, or the `pack-refs` file if
|
||||
// the file was empty. Then it checks that the old reference matches the stored reference and
|
||||
// truncates the file.
|
||||
func (d *DotGit) checkReferenceAndTruncate(f billy.File, old *plumbing.Reference) error {
|
||||
if old == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
ref, err := d.readReferenceFrom(f, old.Name().String())
|
||||
if errors.Is(err, ErrEmptyRefFile) {
|
||||
// This may happen if the reference is being read from a newly created file.
|
||||
// In that case, try getting the reference from the packed refs file.
|
||||
ref, err = d.packedRef(old.Name())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ref.Hash() != old.Hash() {
|
||||
return storage.ErrReferenceHasChanged
|
||||
}
|
||||
@ -701,7 +719,11 @@ func (d *DotGit) SetRef(r, old *plumbing.Reference) error {
|
||||
// Symbolic references are resolved and included in the output.
|
||||
func (d *DotGit) Refs() ([]*plumbing.Reference, error) {
|
||||
var refs []*plumbing.Reference
|
||||
var seen = make(map[plumbing.ReferenceName]bool)
|
||||
seen := make(map[plumbing.ReferenceName]bool)
|
||||
if err := d.addRefFromHEAD(&refs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := d.addRefsFromRefDir(&refs, seen); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -710,10 +732,6 @@ func (d *DotGit) Refs() ([]*plumbing.Reference, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := d.addRefFromHEAD(&refs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return refs, nil
|
||||
}
|
||||
|
||||
@ -815,7 +833,8 @@ func (d *DotGit) addRefsFromPackedRefsFile(refs *[]*plumbing.Reference, f billy.
|
||||
}
|
||||
|
||||
func (d *DotGit) openAndLockPackedRefs(doCreate bool) (
|
||||
pr billy.File, err error) {
|
||||
pr billy.File, err error,
|
||||
) {
|
||||
var f billy.File
|
||||
defer func() {
|
||||
if err != nil && f != nil {
|
||||
@ -1020,7 +1039,7 @@ func (d *DotGit) readReferenceFile(path, name string) (ref *plumbing.Reference,
|
||||
|
||||
func (d *DotGit) CountLooseRefs() (int, error) {
|
||||
var refs []*plumbing.Reference
|
||||
var seen = make(map[plumbing.ReferenceName]bool)
|
||||
seen := make(map[plumbing.ReferenceName]bool)
|
||||
if err := d.addRefsFromRefDir(&refs, seen); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
2
vendor/github.com/go-git/go-git/v5/storage/filesystem/index.go
generated
vendored
2
vendor/github.com/go-git/go-git/v5/storage/filesystem/index.go
generated
vendored
@ -48,7 +48,7 @@ func (s *IndexStorage) Index() (i *index.Index, err error) {
|
||||
|
||||
defer ioutil.CheckClose(f, &err)
|
||||
|
||||
d := index.NewDecoder(bufio.NewReader(f))
|
||||
d := index.NewDecoder(f)
|
||||
err = d.Decode(idx)
|
||||
return idx, err
|
||||
}
|
||||
|
4
vendor/github.com/go-git/go-git/v5/storage/filesystem/object.go
generated
vendored
4
vendor/github.com/go-git/go-git/v5/storage/filesystem/object.go
generated
vendored
@ -431,13 +431,13 @@ func (s *ObjectStorage) getFromUnpacked(h plumbing.Hash) (obj plumbing.EncodedOb
|
||||
|
||||
defer ioutil.CheckClose(w, &err)
|
||||
|
||||
s.objectCache.Put(obj)
|
||||
|
||||
bufp := copyBufferPool.Get().(*[]byte)
|
||||
buf := *bufp
|
||||
_, err = io.CopyBuffer(w, r, buf)
|
||||
copyBufferPool.Put(bufp)
|
||||
|
||||
s.objectCache.Put(obj)
|
||||
|
||||
return obj, err
|
||||
}
|
||||
|
||||
|
6
vendor/github.com/go-git/go-git/v5/submodule.go
generated
vendored
6
vendor/github.com/go-git/go-git/v5/submodule.go
generated
vendored
@ -214,10 +214,10 @@ func (s *Submodule) update(ctx context.Context, o *SubmoduleUpdateOptions, force
|
||||
return err
|
||||
}
|
||||
|
||||
return s.doRecursiveUpdate(r, o)
|
||||
return s.doRecursiveUpdate(ctx, r, o)
|
||||
}
|
||||
|
||||
func (s *Submodule) doRecursiveUpdate(r *Repository, o *SubmoduleUpdateOptions) error {
|
||||
func (s *Submodule) doRecursiveUpdate(ctx context.Context, r *Repository, o *SubmoduleUpdateOptions) error {
|
||||
if o.RecurseSubmodules == NoRecurseSubmodules {
|
||||
return nil
|
||||
}
|
||||
@ -236,7 +236,7 @@ func (s *Submodule) doRecursiveUpdate(r *Repository, o *SubmoduleUpdateOptions)
|
||||
*new = *o
|
||||
|
||||
new.RecurseSubmodules--
|
||||
return l.Update(new)
|
||||
return l.UpdateContext(ctx, new)
|
||||
}
|
||||
|
||||
func (s *Submodule) fetchAndCheckout(
|
||||
|
9
vendor/github.com/go-git/go-git/v5/utils/merkletrie/change.go
generated
vendored
9
vendor/github.com/go-git/go-git/v5/utils/merkletrie/change.go
generated
vendored
@ -1,12 +1,17 @@
|
||||
package merkletrie
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/go-git/go-git/v5/utils/merkletrie/noder"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrEmptyFileName = errors.New("empty filename in tree entry")
|
||||
)
|
||||
|
||||
// Action values represent the kind of things a Change can represent:
|
||||
// insertion, deletions or modifications of files.
|
||||
type Action int
|
||||
@ -121,6 +126,10 @@ func (l *Changes) AddRecursiveDelete(root noder.Path) error {
|
||||
type noderToChangeFn func(noder.Path) Change // NewInsert or NewDelete
|
||||
|
||||
func (l *Changes) addRecursive(root noder.Path, ctor noderToChangeFn) error {
|
||||
if root.String() == "" {
|
||||
return ErrEmptyFileName
|
||||
}
|
||||
|
||||
if !root.IsDir() {
|
||||
l.Add(ctor(root))
|
||||
return nil
|
||||
|
2
vendor/github.com/go-git/go-git/v5/utils/merkletrie/difftree.go
generated
vendored
2
vendor/github.com/go-git/go-git/v5/utils/merkletrie/difftree.go
generated
vendored
@ -11,7 +11,7 @@ package merkletrie
|
||||
// corresponding changes and move the iterators further over both
|
||||
// trees.
|
||||
//
|
||||
// The table bellow show all the possible comparison results, along
|
||||
// The table below shows all the possible comparison results, along
|
||||
// with what changes should we produce and how to advance the
|
||||
// iterators.
|
||||
//
|
||||
|
2
vendor/github.com/go-git/go-git/v5/utils/sync/bufio.go
generated
vendored
2
vendor/github.com/go-git/go-git/v5/utils/sync/bufio.go
generated
vendored
@ -13,7 +13,7 @@ var bufioReader = sync.Pool{
|
||||
}
|
||||
|
||||
// GetBufioReader returns a *bufio.Reader that is managed by a sync.Pool.
|
||||
// Returns a bufio.Reader that is resetted with reader and ready for use.
|
||||
// Returns a bufio.Reader that is reset with reader and ready for use.
|
||||
//
|
||||
// After use, the *bufio.Reader should be put back into the sync.Pool
|
||||
// by calling PutBufioReader.
|
||||
|
2
vendor/github.com/go-git/go-git/v5/utils/sync/bytes.go
generated
vendored
2
vendor/github.com/go-git/go-git/v5/utils/sync/bytes.go
generated
vendored
@ -35,7 +35,7 @@ func PutByteSlice(buf *[]byte) {
|
||||
}
|
||||
|
||||
// GetBytesBuffer returns a *bytes.Buffer that is managed by a sync.Pool.
|
||||
// Returns a buffer that is resetted and ready for use.
|
||||
// Returns a buffer that is reset and ready for use.
|
||||
//
|
||||
// After use, the *bytes.Buffer should be put back into the sync.Pool
|
||||
// by calling PutBytesBuffer.
|
||||
|
4
vendor/github.com/go-git/go-git/v5/utils/sync/zlib.go
generated
vendored
4
vendor/github.com/go-git/go-git/v5/utils/sync/zlib.go
generated
vendored
@ -35,7 +35,7 @@ type ZLibReader struct {
|
||||
}
|
||||
|
||||
// GetZlibReader returns a ZLibReader that is managed by a sync.Pool.
|
||||
// Returns a ZLibReader that is resetted using a dictionary that is
|
||||
// Returns a ZLibReader that is reset using a dictionary that is
|
||||
// also managed by a sync.Pool.
|
||||
//
|
||||
// After use, the ZLibReader should be put back into the sync.Pool
|
||||
@ -58,7 +58,7 @@ func PutZlibReader(z ZLibReader) {
|
||||
}
|
||||
|
||||
// GetZlibWriter returns a *zlib.Writer that is managed by a sync.Pool.
|
||||
// Returns a writer that is resetted with w and ready for use.
|
||||
// Returns a writer that is reset with w and ready for use.
|
||||
//
|
||||
// After use, the *zlib.Writer should be put back into the sync.Pool
|
||||
// by calling PutZlibWriter.
|
||||
|
117
vendor/github.com/go-git/go-git/v5/worktree.go
generated
vendored
117
vendor/github.com/go-git/go-git/v5/worktree.go
generated
vendored
@ -25,11 +25,12 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
ErrWorktreeNotClean = errors.New("worktree is not clean")
|
||||
ErrSubmoduleNotFound = errors.New("submodule not found")
|
||||
ErrUnstagedChanges = errors.New("worktree contains unstaged changes")
|
||||
ErrGitModulesSymlink = errors.New(gitmodulesFile + " is a symlink")
|
||||
ErrNonFastForwardUpdate = errors.New("non-fast-forward update")
|
||||
ErrWorktreeNotClean = errors.New("worktree is not clean")
|
||||
ErrSubmoduleNotFound = errors.New("submodule not found")
|
||||
ErrUnstagedChanges = errors.New("worktree contains unstaged changes")
|
||||
ErrGitModulesSymlink = errors.New(gitmodulesFile + " is a symlink")
|
||||
ErrNonFastForwardUpdate = errors.New("non-fast-forward update")
|
||||
ErrRestoreWorktreeOnlyNotSupported = errors.New("worktree only is not supported")
|
||||
)
|
||||
|
||||
// Worktree represents a git worktree.
|
||||
@ -139,7 +140,7 @@ func (w *Worktree) PullContext(ctx context.Context, o *PullOptions) error {
|
||||
}
|
||||
|
||||
if o.RecurseSubmodules != NoRecurseSubmodules {
|
||||
return w.updateSubmodules(&SubmoduleUpdateOptions{
|
||||
return w.updateSubmodules(ctx, &SubmoduleUpdateOptions{
|
||||
RecurseSubmodules: o.RecurseSubmodules,
|
||||
Auth: o.Auth,
|
||||
})
|
||||
@ -148,13 +149,13 @@ func (w *Worktree) PullContext(ctx context.Context, o *PullOptions) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *Worktree) updateSubmodules(o *SubmoduleUpdateOptions) error {
|
||||
func (w *Worktree) updateSubmodules(ctx context.Context, o *SubmoduleUpdateOptions) error {
|
||||
s, err := w.Submodules()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.Init = true
|
||||
return s.Update(o)
|
||||
return s.UpdateContext(ctx, o)
|
||||
}
|
||||
|
||||
// Checkout switch branches or restore working tree files.
|
||||
@ -307,13 +308,13 @@ func (w *Worktree) ResetSparsely(opts *ResetOptions, dirs []string) error {
|
||||
}
|
||||
|
||||
if opts.Mode == MixedReset || opts.Mode == MergeReset || opts.Mode == HardReset {
|
||||
if err := w.resetIndex(t, dirs); err != nil {
|
||||
if err := w.resetIndex(t, dirs, opts.Files); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if opts.Mode == MergeReset || opts.Mode == HardReset {
|
||||
if err := w.resetWorktree(t); err != nil {
|
||||
if err := w.resetWorktree(t, opts.Files); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -321,20 +322,52 @@ func (w *Worktree) ResetSparsely(opts *ResetOptions, dirs []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Restore restores specified files in the working tree or stage with contents from
|
||||
// a restore source. If a path is tracked but does not exist in the restore,
|
||||
// source, it will be removed to match the source.
|
||||
//
|
||||
// If Staged and Worktree are true, then the restore source will be the index.
|
||||
// If only Staged is true, then the restore source will be HEAD.
|
||||
// If only Worktree is true or neither Staged nor Worktree are true, will
|
||||
// result in ErrRestoreWorktreeOnlyNotSupported because restoring the working
|
||||
// tree while leaving the stage untouched is not currently supported.
|
||||
//
|
||||
// Restore with no files specified will return ErrNoRestorePaths.
|
||||
func (w *Worktree) Restore(o *RestoreOptions) error {
|
||||
if err := o.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if o.Staged {
|
||||
opts := &ResetOptions{
|
||||
Files: o.Files,
|
||||
}
|
||||
|
||||
if o.Worktree {
|
||||
// If we are doing both Worktree and Staging then it is a hard reset
|
||||
opts.Mode = HardReset
|
||||
} else {
|
||||
// If we are doing just staging then it is a mixed reset
|
||||
opts.Mode = MixedReset
|
||||
}
|
||||
|
||||
return w.Reset(opts)
|
||||
}
|
||||
|
||||
return ErrRestoreWorktreeOnlyNotSupported
|
||||
}
|
||||
|
||||
// Reset the worktree to a specified state.
|
||||
func (w *Worktree) Reset(opts *ResetOptions) error {
|
||||
return w.ResetSparsely(opts, nil)
|
||||
}
|
||||
|
||||
func (w *Worktree) resetIndex(t *object.Tree, dirs []string) error {
|
||||
func (w *Worktree) resetIndex(t *object.Tree, dirs []string, files []string) error {
|
||||
idx, err := w.r.Storer.Index()
|
||||
if len(dirs) > 0 {
|
||||
idx.SkipUnless(dirs)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b := newIndexBuilder(idx)
|
||||
|
||||
changes, err := w.diffTreeWithStaging(t, true)
|
||||
@ -362,6 +395,13 @@ func (w *Worktree) resetIndex(t *object.Tree, dirs []string) error {
|
||||
name = ch.From.String()
|
||||
}
|
||||
|
||||
if len(files) > 0 {
|
||||
contains := inFiles(files, name)
|
||||
if !contains {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
b.Remove(name)
|
||||
if e == nil {
|
||||
continue
|
||||
@ -376,10 +416,25 @@ func (w *Worktree) resetIndex(t *object.Tree, dirs []string) error {
|
||||
}
|
||||
|
||||
b.Write(idx)
|
||||
|
||||
if len(dirs) > 0 {
|
||||
idx.SkipUnless(dirs)
|
||||
}
|
||||
|
||||
return w.r.Storer.SetIndex(idx)
|
||||
}
|
||||
|
||||
func (w *Worktree) resetWorktree(t *object.Tree) error {
|
||||
func inFiles(files []string, v string) bool {
|
||||
for _, s := range files {
|
||||
if s == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (w *Worktree) resetWorktree(t *object.Tree, files []string) error {
|
||||
changes, err := w.diffStagingWithWorktree(true, false)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -395,6 +450,25 @@ func (w *Worktree) resetWorktree(t *object.Tree) error {
|
||||
if err := w.validChange(ch); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(files) > 0 {
|
||||
file := ""
|
||||
if ch.From != nil {
|
||||
file = ch.From.String()
|
||||
} else if ch.To != nil {
|
||||
file = ch.To.String()
|
||||
}
|
||||
|
||||
if file == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
contains := inFiles(files, file)
|
||||
if !contains {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if err := w.checkoutChange(ch, t, b); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -642,7 +716,7 @@ func (w *Worktree) checkoutChangeRegularFile(name string,
|
||||
return err
|
||||
}
|
||||
|
||||
return w.addIndexFromFile(name, e.Hash, idx)
|
||||
return w.addIndexFromFile(name, e.Hash, f.Mode, idx)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -725,18 +799,13 @@ func (w *Worktree) addIndexFromTreeEntry(name string, f *object.TreeEntry, idx *
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *Worktree) addIndexFromFile(name string, h plumbing.Hash, idx *indexBuilder) error {
|
||||
func (w *Worktree) addIndexFromFile(name string, h plumbing.Hash, mode filemode.FileMode, idx *indexBuilder) error {
|
||||
idx.Remove(name)
|
||||
fi, err := w.Filesystem.Lstat(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mode, err := filemode.NewFromOSFileMode(fi.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
e := &index.Entry{
|
||||
Hash: h,
|
||||
Name: name,
|
||||
@ -1058,7 +1127,7 @@ func rmFileAndDirsIfEmpty(fs billy.Filesystem, name string) error {
|
||||
dir := filepath.Dir(name)
|
||||
for {
|
||||
removed, err := removeDirIfEmpty(fs, dir)
|
||||
if err != nil {
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
|
43
vendor/github.com/go-git/go-git/v5/worktree_commit.go
generated
vendored
43
vendor/github.com/go-git/go-git/v5/worktree_commit.go
generated
vendored
@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"io"
|
||||
"path"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
@ -23,6 +24,10 @@ var (
|
||||
// ErrEmptyCommit occurs when a commit is attempted using a clean
|
||||
// working tree, with no changes to be committed.
|
||||
ErrEmptyCommit = errors.New("cannot create empty commit: clean working tree")
|
||||
|
||||
// characters to be removed from user name and/or email before using them to build a commit object
|
||||
// See https://git-scm.com/docs/git-commit#_commit_information
|
||||
invalidCharactersRe = regexp.MustCompile(`[<>\n]`)
|
||||
)
|
||||
|
||||
// Commit stores the current contents of the index in a new commit along with
|
||||
@ -38,8 +43,6 @@ func (w *Worktree) Commit(msg string, opts *CommitOptions) (plumbing.Hash, error
|
||||
}
|
||||
}
|
||||
|
||||
var treeHash plumbing.Hash
|
||||
|
||||
if opts.Amend {
|
||||
head, err := w.r.Head()
|
||||
if err != nil {
|
||||
@ -61,16 +64,34 @@ func (w *Worktree) Commit(msg string, opts *CommitOptions) (plumbing.Hash, error
|
||||
return plumbing.ZeroHash, err
|
||||
}
|
||||
|
||||
// First handle the case of the first commit in the repository being empty.
|
||||
if len(opts.Parents) == 0 && len(idx.Entries) == 0 && !opts.AllowEmptyCommits {
|
||||
return plumbing.ZeroHash, ErrEmptyCommit
|
||||
}
|
||||
|
||||
h := &buildTreeHelper{
|
||||
fs: w.Filesystem,
|
||||
s: w.r.Storer,
|
||||
}
|
||||
|
||||
treeHash, err = h.BuildTree(idx, opts)
|
||||
treeHash, err := h.BuildTree(idx, opts)
|
||||
if err != nil {
|
||||
return plumbing.ZeroHash, err
|
||||
}
|
||||
|
||||
previousTree := plumbing.ZeroHash
|
||||
if len(opts.Parents) > 0 {
|
||||
parentCommit, err := w.r.CommitObject(opts.Parents[0])
|
||||
if err != nil {
|
||||
return plumbing.ZeroHash, err
|
||||
}
|
||||
previousTree = parentCommit.TreeHash
|
||||
}
|
||||
|
||||
if treeHash == previousTree && !opts.AllowEmptyCommits {
|
||||
return plumbing.ZeroHash, ErrEmptyCommit
|
||||
}
|
||||
|
||||
commit, err := w.buildCommitObject(msg, opts, treeHash)
|
||||
if err != nil {
|
||||
return plumbing.ZeroHash, err
|
||||
@ -121,8 +142,8 @@ func (w *Worktree) updateHEAD(commit plumbing.Hash) error {
|
||||
|
||||
func (w *Worktree) buildCommitObject(msg string, opts *CommitOptions, tree plumbing.Hash) (plumbing.Hash, error) {
|
||||
commit := &object.Commit{
|
||||
Author: *opts.Author,
|
||||
Committer: *opts.Committer,
|
||||
Author: w.sanitize(*opts.Author),
|
||||
Committer: w.sanitize(*opts.Committer),
|
||||
Message: msg,
|
||||
TreeHash: tree,
|
||||
ParentHashes: opts.Parents,
|
||||
@ -148,6 +169,14 @@ func (w *Worktree) buildCommitObject(msg string, opts *CommitOptions, tree plumb
|
||||
return w.r.Storer.SetEncodedObject(obj)
|
||||
}
|
||||
|
||||
func (w *Worktree) sanitize(signature object.Signature) object.Signature {
|
||||
return object.Signature{
|
||||
Name: invalidCharactersRe.ReplaceAllString(signature.Name, ""),
|
||||
Email: invalidCharactersRe.ReplaceAllString(signature.Email, ""),
|
||||
When: signature.When,
|
||||
}
|
||||
}
|
||||
|
||||
type gpgSigner struct {
|
||||
key *openpgp.Entity
|
||||
cfg *packet.Config
|
||||
@ -175,10 +204,6 @@ type buildTreeHelper struct {
|
||||
// BuildTree builds the tree objects and push its to the storer, the hash
|
||||
// of the root tree is returned.
|
||||
func (h *buildTreeHelper) BuildTree(idx *index.Index, opts *CommitOptions) (plumbing.Hash, error) {
|
||||
if len(idx.Entries) == 0 && (opts == nil || !opts.AllowEmptyCommits) {
|
||||
return plumbing.ZeroHash, ErrEmptyCommit
|
||||
}
|
||||
|
||||
const rootNode = ""
|
||||
h.trees = map[string]*object.Tree{rootNode: {}}
|
||||
h.entries = map[string]*object.TreeEntry{}
|
||||
|
3
vendor/github.com/go-git/go-git/v5/worktree_linux.go
generated
vendored
3
vendor/github.com/go-git/go-git/v5/worktree_linux.go
generated
vendored
@ -1,3 +1,4 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package git
|
||||
@ -21,6 +22,6 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
func isSymlinkWindowsNonAdmin(err error) bool {
|
||||
func isSymlinkWindowsNonAdmin(_ error) bool {
|
||||
return false
|
||||
}
|
||||
|
34
vendor/github.com/go-git/go-git/v5/worktree_status.go
generated
vendored
34
vendor/github.com/go-git/go-git/v5/worktree_status.go
generated
vendored
@ -29,10 +29,23 @@ var (
|
||||
// ErrGlobNoMatches in an AddGlob if the glob pattern does not match any
|
||||
// files in the worktree.
|
||||
ErrGlobNoMatches = errors.New("glob pattern did not match any files")
|
||||
// ErrUnsupportedStatusStrategy occurs when an invalid StatusStrategy is used
|
||||
// when processing the Worktree status.
|
||||
ErrUnsupportedStatusStrategy = errors.New("unsupported status strategy")
|
||||
)
|
||||
|
||||
// Status returns the working tree status.
|
||||
func (w *Worktree) Status() (Status, error) {
|
||||
return w.StatusWithOptions(StatusOptions{Strategy: defaultStatusStrategy})
|
||||
}
|
||||
|
||||
// StatusOptions defines the options for Worktree.StatusWithOptions().
|
||||
type StatusOptions struct {
|
||||
Strategy StatusStrategy
|
||||
}
|
||||
|
||||
// StatusWithOptions returns the working tree status.
|
||||
func (w *Worktree) StatusWithOptions(o StatusOptions) (Status, error) {
|
||||
var hash plumbing.Hash
|
||||
|
||||
ref, err := w.r.Head()
|
||||
@ -44,11 +57,14 @@ func (w *Worktree) Status() (Status, error) {
|
||||
hash = ref.Hash()
|
||||
}
|
||||
|
||||
return w.status(hash)
|
||||
return w.status(o.Strategy, hash)
|
||||
}
|
||||
|
||||
func (w *Worktree) status(commit plumbing.Hash) (Status, error) {
|
||||
s := make(Status)
|
||||
func (w *Worktree) status(ss StatusStrategy, commit plumbing.Hash) (Status, error) {
|
||||
s, err := ss.new(w)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
left, err := w.diffCommitWithStaging(commit, false)
|
||||
if err != nil {
|
||||
@ -488,7 +504,7 @@ func (w *Worktree) copyFileToStorage(path string) (hash plumbing.Hash, err error
|
||||
return w.r.Storer.SetEncodedObject(obj)
|
||||
}
|
||||
|
||||
func (w *Worktree) fillEncodedObjectFromFile(dst io.Writer, path string, fi os.FileInfo) (err error) {
|
||||
func (w *Worktree) fillEncodedObjectFromFile(dst io.Writer, path string, _ os.FileInfo) (err error) {
|
||||
src, err := w.Filesystem.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -503,7 +519,7 @@ func (w *Worktree) fillEncodedObjectFromFile(dst io.Writer, path string, fi os.F
|
||||
return err
|
||||
}
|
||||
|
||||
func (w *Worktree) fillEncodedObjectFromSymlink(dst io.Writer, path string, fi os.FileInfo) error {
|
||||
func (w *Worktree) fillEncodedObjectFromSymlink(dst io.Writer, path string, _ os.FileInfo) error {
|
||||
target, err := w.Filesystem.Readlink(path)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -543,9 +559,11 @@ func (w *Worktree) doUpdateFileToIndex(e *index.Entry, filename string, h plumbi
|
||||
return err
|
||||
}
|
||||
|
||||
if e.Mode.IsRegular() {
|
||||
e.Size = uint32(info.Size())
|
||||
}
|
||||
// The entry size must always reflect the current state, otherwise
|
||||
// it will cause go-git's Worktree.Status() to divert from "git status".
|
||||
// The size of a symlink is the length of the path to the target.
|
||||
// The size of Regular and Executable files is the size of the files.
|
||||
e.Size = uint32(info.Size())
|
||||
|
||||
fillSystemInfo(e, info.Sys())
|
||||
return nil
|
||||
|
29
vendor/github.com/mmcloughlin/avo/LICENSE
generated
vendored
Normal file
29
vendor/github.com/mmcloughlin/avo/LICENSE
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2018, Michael McLoughlin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
45
vendor/github.com/mmcloughlin/avo/attr/attr.go
generated
vendored
Normal file
45
vendor/github.com/mmcloughlin/avo/attr/attr.go
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
// Package attr provides attributes for text and data sections.
|
||||
package attr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/bits"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Attribute represents TEXT or DATA flags.
|
||||
type Attribute uint16
|
||||
|
||||
//go:generate go run make_textflag.go -output ztextflag.go
|
||||
|
||||
// Asm returns a representation of the attributes in assembly syntax. This may use macros from "textflags.h"; see ContainsTextFlags() to determine if this header is required.
|
||||
func (a Attribute) Asm() string {
|
||||
parts, rest := a.split()
|
||||
if len(parts) == 0 || rest != 0 {
|
||||
parts = append(parts, fmt.Sprintf("%d", rest))
|
||||
}
|
||||
return strings.Join(parts, "|")
|
||||
}
|
||||
|
||||
// ContainsTextFlags returns whether the Asm() representation requires macros in "textflags.h".
|
||||
func (a Attribute) ContainsTextFlags() bool {
|
||||
flags, _ := a.split()
|
||||
return len(flags) > 0
|
||||
}
|
||||
|
||||
// split splits a into known flags and any remaining bits.
|
||||
func (a Attribute) split() ([]string, Attribute) {
|
||||
var flags []string
|
||||
var rest Attribute
|
||||
for a != 0 {
|
||||
i := uint(bits.TrailingZeros16(uint16(a)))
|
||||
bit := Attribute(1) << i
|
||||
if flag := attrname[bit]; flag != "" {
|
||||
flags = append(flags, flag)
|
||||
} else {
|
||||
rest |= bit
|
||||
}
|
||||
a ^= bit
|
||||
}
|
||||
return flags, rest
|
||||
}
|
39
vendor/github.com/mmcloughlin/avo/attr/textflag.h
generated
vendored
Normal file
39
vendor/github.com/mmcloughlin/avo/attr/textflag.h
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
// Code generated by downloading from https://github.com/golang/go/raw/go1.16.2/src/runtime/textflag.h. DO NOT EDIT.
|
||||
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file defines flags attached to various functions
|
||||
// and data objects. The compilers, assemblers, and linker must
|
||||
// all agree on these values.
|
||||
//
|
||||
// Keep in sync with src/cmd/internal/obj/textflag.go.
|
||||
|
||||
// Don't profile the marked routine. This flag is deprecated.
|
||||
#define NOPROF 1
|
||||
// It is ok for the linker to get multiple of these symbols. It will
|
||||
// pick one of the duplicates to use.
|
||||
#define DUPOK 2
|
||||
// Don't insert stack check preamble.
|
||||
#define NOSPLIT 4
|
||||
// Put this data in a read-only section.
|
||||
#define RODATA 8
|
||||
// This data contains no pointers.
|
||||
#define NOPTR 16
|
||||
// This is a wrapper function and should not count as disabling 'recover'.
|
||||
#define WRAPPER 32
|
||||
// This function uses its incoming context register.
|
||||
#define NEEDCTXT 64
|
||||
// Allocate a word of thread local storage and store the offset from the
|
||||
// thread local base to the thread local storage in this variable.
|
||||
#define TLSBSS 256
|
||||
// Do not insert instructions to allocate a stack frame for this function.
|
||||
// Only valid on functions that declare a frame size of 0.
|
||||
// TODO(mwhudson): only implemented for ppc64x at present.
|
||||
#define NOFRAME 512
|
||||
// Function can call reflect.Type.Method or reflect.Type.MethodByName.
|
||||
#define REFLECTMETHOD 1024
|
||||
// Function is the top of the call stack. Call stack unwinders should stop
|
||||
// at this function.
|
||||
#define TOPFRAME 2048
|
90
vendor/github.com/mmcloughlin/avo/attr/ztextflag.go
generated
vendored
Normal file
90
vendor/github.com/mmcloughlin/avo/attr/ztextflag.go
generated
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
// Code generated by make_textflag.go. DO NOT EDIT.
|
||||
|
||||
package attr
|
||||
|
||||
// Attribute values defined in textflag.h.
|
||||
const (
|
||||
// Don't profile the marked routine. This flag is deprecated.
|
||||
NOPROF Attribute = 1
|
||||
|
||||
// It is ok for the linker to get multiple of these symbols. It will
|
||||
// pick one of the duplicates to use.
|
||||
DUPOK Attribute = 2
|
||||
|
||||
// Don't insert stack check preamble.
|
||||
NOSPLIT Attribute = 4
|
||||
|
||||
// Put this data in a read-only section.
|
||||
RODATA Attribute = 8
|
||||
|
||||
// This data contains no pointers.
|
||||
NOPTR Attribute = 16
|
||||
|
||||
// This is a wrapper function and should not count as disabling 'recover'.
|
||||
WRAPPER Attribute = 32
|
||||
|
||||
// This function uses its incoming context register.
|
||||
NEEDCTXT Attribute = 64
|
||||
|
||||
// Allocate a word of thread local storage and store the offset from the
|
||||
// thread local base to the thread local storage in this variable.
|
||||
TLSBSS Attribute = 256
|
||||
|
||||
// Do not insert instructions to allocate a stack frame for this function.
|
||||
// Only valid on functions that declare a frame size of 0.
|
||||
NOFRAME Attribute = 512
|
||||
|
||||
// Function can call reflect.Type.Method or reflect.Type.MethodByName.
|
||||
REFLECTMETHOD Attribute = 1024
|
||||
|
||||
// Function is the top of the call stack. Call stack unwinders should stop
|
||||
// at this function.
|
||||
TOPFRAME Attribute = 2048
|
||||
)
|
||||
|
||||
var attrname = map[Attribute]string{
|
||||
NOPROF: "NOPROF",
|
||||
DUPOK: "DUPOK",
|
||||
NOSPLIT: "NOSPLIT",
|
||||
RODATA: "RODATA",
|
||||
NOPTR: "NOPTR",
|
||||
WRAPPER: "WRAPPER",
|
||||
NEEDCTXT: "NEEDCTXT",
|
||||
TLSBSS: "TLSBSS",
|
||||
NOFRAME: "NOFRAME",
|
||||
REFLECTMETHOD: "REFLECTMETHOD",
|
||||
TOPFRAME: "TOPFRAME",
|
||||
}
|
||||
|
||||
// NOPROF reports whether the NOPROF flag is set.
|
||||
func (a Attribute) NOPROF() bool { return (a & NOPROF) != 0 }
|
||||
|
||||
// DUPOK reports whether the DUPOK flag is set.
|
||||
func (a Attribute) DUPOK() bool { return (a & DUPOK) != 0 }
|
||||
|
||||
// NOSPLIT reports whether the NOSPLIT flag is set.
|
||||
func (a Attribute) NOSPLIT() bool { return (a & NOSPLIT) != 0 }
|
||||
|
||||
// RODATA reports whether the RODATA flag is set.
|
||||
func (a Attribute) RODATA() bool { return (a & RODATA) != 0 }
|
||||
|
||||
// NOPTR reports whether the NOPTR flag is set.
|
||||
func (a Attribute) NOPTR() bool { return (a & NOPTR) != 0 }
|
||||
|
||||
// WRAPPER reports whether the WRAPPER flag is set.
|
||||
func (a Attribute) WRAPPER() bool { return (a & WRAPPER) != 0 }
|
||||
|
||||
// NEEDCTXT reports whether the NEEDCTXT flag is set.
|
||||
func (a Attribute) NEEDCTXT() bool { return (a & NEEDCTXT) != 0 }
|
||||
|
||||
// TLSBSS reports whether the TLSBSS flag is set.
|
||||
func (a Attribute) TLSBSS() bool { return (a & TLSBSS) != 0 }
|
||||
|
||||
// NOFRAME reports whether the NOFRAME flag is set.
|
||||
func (a Attribute) NOFRAME() bool { return (a & NOFRAME) != 0 }
|
||||
|
||||
// REFLECTMETHOD reports whether the REFLECTMETHOD flag is set.
|
||||
func (a Attribute) REFLECTMETHOD() bool { return (a & REFLECTMETHOD) != 0 }
|
||||
|
||||
// TOPFRAME reports whether the TOPFRAME flag is set.
|
||||
func (a Attribute) TOPFRAME() bool { return (a & TOPFRAME) != 0 }
|
18
vendor/github.com/mmcloughlin/avo/build/attr.go
generated
vendored
Normal file
18
vendor/github.com/mmcloughlin/avo/build/attr.go
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
package build
|
||||
|
||||
import "github.com/mmcloughlin/avo/attr"
|
||||
|
||||
// TEXT and DATA attribute values included for convenience.
|
||||
const (
|
||||
NOPROF = attr.NOPROF
|
||||
DUPOK = attr.DUPOK
|
||||
NOSPLIT = attr.NOSPLIT
|
||||
RODATA = attr.RODATA
|
||||
NOPTR = attr.NOPTR
|
||||
WRAPPER = attr.WRAPPER
|
||||
NEEDCTXT = attr.NEEDCTXT
|
||||
TLSBSS = attr.TLSBSS
|
||||
NOFRAME = attr.NOFRAME
|
||||
REFLECTMETHOD = attr.REFLECTMETHOD
|
||||
TOPFRAME = attr.TOPFRAME
|
||||
)
|
171
vendor/github.com/mmcloughlin/avo/build/cli.go
generated
vendored
Normal file
171
vendor/github.com/mmcloughlin/avo/build/cli.go
generated
vendored
Normal file
@ -0,0 +1,171 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"runtime/pprof"
|
||||
|
||||
"github.com/mmcloughlin/avo/pass"
|
||||
"github.com/mmcloughlin/avo/printer"
|
||||
)
|
||||
|
||||
// Config contains options for an avo main function.
|
||||
type Config struct {
|
||||
ErrOut io.Writer
|
||||
MaxErrors int // max errors to report; 0 means unlimited
|
||||
CPUProfile io.WriteCloser
|
||||
Passes []pass.Interface
|
||||
}
|
||||
|
||||
// Main is the standard main function for an avo program. This extracts the
|
||||
// result from the build Context (logging and exiting on error), and performs
|
||||
// configured passes.
|
||||
func Main(cfg *Config, context *Context) int {
|
||||
diag := log.New(cfg.ErrOut, "", 0)
|
||||
|
||||
if cfg.CPUProfile != nil {
|
||||
defer cfg.CPUProfile.Close()
|
||||
if err := pprof.StartCPUProfile(cfg.CPUProfile); err != nil {
|
||||
diag.Println("could not start CPU profile: ", err)
|
||||
return 1
|
||||
}
|
||||
defer pprof.StopCPUProfile()
|
||||
}
|
||||
|
||||
f, err := context.Result()
|
||||
if err != nil {
|
||||
LogError(diag, err, cfg.MaxErrors)
|
||||
return 1
|
||||
}
|
||||
|
||||
p := pass.Concat(cfg.Passes...)
|
||||
if err := p.Execute(f); err != nil {
|
||||
diag.Println(err)
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// Flags represents CLI flags for an avo program.
|
||||
type Flags struct {
|
||||
errout *outputValue
|
||||
allerrors bool
|
||||
cpuprof *outputValue
|
||||
pkg string
|
||||
printers []*printerValue
|
||||
}
|
||||
|
||||
// NewFlags initializes avo flags for the given FlagSet.
|
||||
func NewFlags(fs *flag.FlagSet) *Flags {
|
||||
f := &Flags{}
|
||||
|
||||
f.errout = newOutputValue(os.Stderr)
|
||||
fs.Var(f.errout, "log", "diagnostics output")
|
||||
|
||||
fs.BoolVar(&f.allerrors, "e", false, "no limit on number of errors reported")
|
||||
|
||||
f.cpuprof = newOutputValue(nil)
|
||||
fs.Var(f.cpuprof, "cpuprofile", "write cpu profile to `file`")
|
||||
|
||||
fs.StringVar(&f.pkg, "pkg", "", "package name (defaults to current directory name)")
|
||||
|
||||
goasm := newPrinterValue(printer.NewGoAsm, os.Stdout)
|
||||
fs.Var(goasm, "out", "assembly output")
|
||||
f.printers = append(f.printers, goasm)
|
||||
|
||||
stubs := newPrinterValue(printer.NewStubs, nil)
|
||||
fs.Var(stubs, "stubs", "go stub file")
|
||||
f.printers = append(f.printers, stubs)
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
// Config builds a configuration object based on flag values.
|
||||
func (f *Flags) Config() *Config {
|
||||
pc := printer.NewGoRunConfig()
|
||||
if f.pkg != "" {
|
||||
pc.Pkg = f.pkg
|
||||
}
|
||||
passes := []pass.Interface{pass.Compile}
|
||||
for _, pv := range f.printers {
|
||||
p := pv.Build(pc)
|
||||
if p != nil {
|
||||
passes = append(passes, p)
|
||||
}
|
||||
}
|
||||
|
||||
cfg := &Config{
|
||||
ErrOut: f.errout.w,
|
||||
MaxErrors: 10,
|
||||
CPUProfile: f.cpuprof.w,
|
||||
Passes: passes,
|
||||
}
|
||||
|
||||
if f.allerrors {
|
||||
cfg.MaxErrors = 0
|
||||
}
|
||||
|
||||
return cfg
|
||||
}
|
||||
|
||||
type outputValue struct {
|
||||
w io.WriteCloser
|
||||
filename string
|
||||
}
|
||||
|
||||
func newOutputValue(dflt io.WriteCloser) *outputValue {
|
||||
return &outputValue{w: dflt}
|
||||
}
|
||||
|
||||
func (o *outputValue) String() string {
|
||||
if o == nil {
|
||||
return ""
|
||||
}
|
||||
return o.filename
|
||||
}
|
||||
|
||||
func (o *outputValue) Set(s string) error {
|
||||
o.filename = s
|
||||
if s == "-" {
|
||||
o.w = nopwritecloser{os.Stdout}
|
||||
return nil
|
||||
}
|
||||
f, err := os.Create(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.w = f
|
||||
return nil
|
||||
}
|
||||
|
||||
type printerValue struct {
|
||||
*outputValue
|
||||
Builder printer.Builder
|
||||
}
|
||||
|
||||
func newPrinterValue(b printer.Builder, dflt io.WriteCloser) *printerValue {
|
||||
return &printerValue{
|
||||
outputValue: newOutputValue(dflt),
|
||||
Builder: b,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *printerValue) Build(cfg printer.Config) pass.Interface {
|
||||
if p.outputValue.w == nil {
|
||||
return nil
|
||||
}
|
||||
return &pass.Output{
|
||||
Writer: p.outputValue.w,
|
||||
Printer: p.Builder(cfg),
|
||||
}
|
||||
}
|
||||
|
||||
// nopwritecloser wraps a Writer and provides a null implementation of Close().
|
||||
type nopwritecloser struct {
|
||||
io.Writer
|
||||
}
|
||||
|
||||
func (nopwritecloser) Close() error { return nil }
|
224
vendor/github.com/mmcloughlin/avo/build/context.go
generated
vendored
Normal file
224
vendor/github.com/mmcloughlin/avo/build/context.go
generated
vendored
Normal file
@ -0,0 +1,224 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/types"
|
||||
|
||||
"golang.org/x/tools/go/packages"
|
||||
|
||||
"github.com/mmcloughlin/avo/attr"
|
||||
"github.com/mmcloughlin/avo/buildtags"
|
||||
"github.com/mmcloughlin/avo/gotypes"
|
||||
"github.com/mmcloughlin/avo/ir"
|
||||
"github.com/mmcloughlin/avo/operand"
|
||||
"github.com/mmcloughlin/avo/reg"
|
||||
)
|
||||
|
||||
//go:generate avogen -output zinstructions.go build
|
||||
//go:generate avogen -output zinstructions_test.go buildtest
|
||||
|
||||
// Context maintains state for incrementally building an avo File.
|
||||
type Context struct {
|
||||
pkg *packages.Package
|
||||
file *ir.File
|
||||
function *ir.Function
|
||||
global *ir.Global
|
||||
errs ErrorList
|
||||
reg.Collection
|
||||
}
|
||||
|
||||
// NewContext initializes an empty build Context.
|
||||
func NewContext() *Context {
|
||||
return &Context{
|
||||
file: ir.NewFile(),
|
||||
Collection: *reg.NewCollection(),
|
||||
}
|
||||
}
|
||||
|
||||
// Package sets the package the generated file will belong to. Required to be able to reference types in the package.
|
||||
func (c *Context) Package(path string) {
|
||||
cfg := &packages.Config{
|
||||
Mode: packages.NeedTypes | packages.NeedDeps | packages.NeedImports,
|
||||
}
|
||||
pkgs, err := packages.Load(cfg, path)
|
||||
if err != nil {
|
||||
c.adderror(err)
|
||||
return
|
||||
}
|
||||
pkg := pkgs[0]
|
||||
if len(pkg.Errors) > 0 {
|
||||
for _, err := range pkg.Errors {
|
||||
c.adderror(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
c.pkg = pkg
|
||||
}
|
||||
|
||||
// Constraints sets build constraints for the file.
|
||||
func (c *Context) Constraints(t buildtags.ConstraintsConvertable) {
|
||||
cs := t.ToConstraints()
|
||||
if err := cs.Validate(); err != nil {
|
||||
c.adderror(err)
|
||||
return
|
||||
}
|
||||
c.file.Constraints = cs
|
||||
}
|
||||
|
||||
// Constraint appends a constraint to the file's build constraints.
|
||||
func (c *Context) Constraint(t buildtags.ConstraintConvertable) {
|
||||
c.Constraints(append(c.file.Constraints, t.ToConstraint()))
|
||||
}
|
||||
|
||||
// ConstraintExpr appends a constraint to the file's build constraints. The
|
||||
// constraint to add is parsed from the given expression. The expression should
|
||||
// look the same as the content following "// +build " in regular build
|
||||
// constraint comments.
|
||||
func (c *Context) ConstraintExpr(expr string) {
|
||||
constraint, err := buildtags.ParseConstraint(expr)
|
||||
if err != nil {
|
||||
c.adderror(err)
|
||||
return
|
||||
}
|
||||
c.Constraint(constraint)
|
||||
}
|
||||
|
||||
// Function starts building a new function with the given name.
|
||||
func (c *Context) Function(name string) {
|
||||
c.function = ir.NewFunction(name)
|
||||
c.file.AddSection(c.function)
|
||||
}
|
||||
|
||||
// Doc sets documentation comment lines for the currently active function.
|
||||
func (c *Context) Doc(lines ...string) {
|
||||
c.activefunc().Doc = lines
|
||||
}
|
||||
|
||||
// Pragma adds a compiler directive to the currently active function.
|
||||
func (c *Context) Pragma(directive string, args ...string) {
|
||||
c.activefunc().AddPragma(directive, args...)
|
||||
}
|
||||
|
||||
// Attributes sets function attributes for the currently active function.
|
||||
func (c *Context) Attributes(a attr.Attribute) {
|
||||
c.activefunc().Attributes = a
|
||||
}
|
||||
|
||||
// Signature sets the signature for the currently active function.
|
||||
func (c *Context) Signature(s *gotypes.Signature) {
|
||||
c.activefunc().SetSignature(s)
|
||||
}
|
||||
|
||||
// SignatureExpr parses the signature expression and sets it as the active function's signature.
|
||||
func (c *Context) SignatureExpr(expr string) {
|
||||
s, err := gotypes.ParseSignatureInPackage(c.types(), expr)
|
||||
if err != nil {
|
||||
c.adderror(err)
|
||||
return
|
||||
}
|
||||
c.Signature(s)
|
||||
}
|
||||
|
||||
// Implement starts building a function of the given name, whose type is
|
||||
// specified by a stub in the containing package.
|
||||
func (c *Context) Implement(name string) {
|
||||
pkg := c.types()
|
||||
if pkg == nil {
|
||||
c.adderrormessage("no package specified")
|
||||
return
|
||||
}
|
||||
s, err := gotypes.LookupSignature(pkg, name)
|
||||
if err != nil {
|
||||
c.adderror(err)
|
||||
return
|
||||
}
|
||||
c.Function(name)
|
||||
c.Signature(s)
|
||||
}
|
||||
|
||||
func (c *Context) types() *types.Package {
|
||||
if c.pkg == nil {
|
||||
return nil
|
||||
}
|
||||
return c.pkg.Types
|
||||
}
|
||||
|
||||
// AllocLocal allocates size bytes in the stack of the currently active function.
|
||||
// Returns a reference to the base pointer for the newly allocated region.
|
||||
func (c *Context) AllocLocal(size int) operand.Mem {
|
||||
return c.activefunc().AllocLocal(size)
|
||||
}
|
||||
|
||||
// Instruction adds an instruction to the active function.
|
||||
func (c *Context) Instruction(i *ir.Instruction) {
|
||||
c.activefunc().AddInstruction(i)
|
||||
}
|
||||
|
||||
// Label adds a label to the active function.
|
||||
func (c *Context) Label(name string) {
|
||||
c.activefunc().AddLabel(ir.Label(name))
|
||||
}
|
||||
|
||||
// Comment adds comment lines to the active function.
|
||||
func (c *Context) Comment(lines ...string) {
|
||||
c.activefunc().AddComment(lines...)
|
||||
}
|
||||
|
||||
// Commentf adds a formtted comment line.
|
||||
func (c *Context) Commentf(format string, a ...any) {
|
||||
c.Comment(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
func (c *Context) activefunc() *ir.Function {
|
||||
if c.function == nil {
|
||||
c.adderrormessage("no active function")
|
||||
return ir.NewFunction("")
|
||||
}
|
||||
return c.function
|
||||
}
|
||||
|
||||
// StaticGlobal adds a new static data section to the file and returns a pointer to it.
|
||||
func (c *Context) StaticGlobal(name string) operand.Mem {
|
||||
c.global = ir.NewStaticGlobal(name)
|
||||
c.file.AddSection(c.global)
|
||||
return c.global.Base()
|
||||
}
|
||||
|
||||
// DataAttributes sets the attributes on the current active global data section.
|
||||
func (c *Context) DataAttributes(a attr.Attribute) {
|
||||
c.activeglobal().Attributes = a
|
||||
}
|
||||
|
||||
// AddDatum adds constant v at offset to the current active global data section.
|
||||
func (c *Context) AddDatum(offset int, v operand.Constant) {
|
||||
if err := c.activeglobal().AddDatum(ir.NewDatum(offset, v)); err != nil {
|
||||
c.adderror(err)
|
||||
}
|
||||
}
|
||||
|
||||
// AppendDatum appends a constant to the current active global data section.
|
||||
func (c *Context) AppendDatum(v operand.Constant) {
|
||||
c.activeglobal().Append(v)
|
||||
}
|
||||
|
||||
func (c *Context) activeglobal() *ir.Global {
|
||||
if c.global == nil {
|
||||
c.adderrormessage("no active global")
|
||||
return ir.NewStaticGlobal("")
|
||||
}
|
||||
return c.global
|
||||
}
|
||||
|
||||
func (c *Context) adderror(err error) {
|
||||
c.errs.addext(err)
|
||||
}
|
||||
|
||||
func (c *Context) adderrormessage(msg string) {
|
||||
c.adderror(errors.New(msg))
|
||||
}
|
||||
|
||||
// Result returns the built file and any accumulated errors.
|
||||
func (c *Context) Result() (*ir.File, error) {
|
||||
return c.file, c.errs.Err()
|
||||
}
|
2
vendor/github.com/mmcloughlin/avo/build/doc.go
generated
vendored
Normal file
2
vendor/github.com/mmcloughlin/avo/build/doc.go
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
// Package build provides an assembly-like interface for incremental building of avo Files.
|
||||
package build
|
91
vendor/github.com/mmcloughlin/avo/build/error.go
generated
vendored
Normal file
91
vendor/github.com/mmcloughlin/avo/build/error.go
generated
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/mmcloughlin/avo/internal/stack"
|
||||
"github.com/mmcloughlin/avo/src"
|
||||
)
|
||||
|
||||
// Error represents an error during building, optionally tagged with the position at which it happened.
|
||||
type Error struct {
|
||||
Position src.Position
|
||||
Err error
|
||||
}
|
||||
|
||||
// exterr constructs an Error with position derived from the first frame in the
|
||||
// call stack outside this package.
|
||||
func exterr(err error) Error {
|
||||
e := Error{Err: err}
|
||||
if f := stack.ExternalCaller(); f != nil {
|
||||
e.Position = src.FramePosition(*f).Relwd()
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
func (e Error) Error() string {
|
||||
msg := e.Err.Error()
|
||||
if e.Position.IsValid() {
|
||||
return e.Position.String() + ": " + msg
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
// ErrorList is a collection of errors for a source file.
|
||||
type ErrorList []Error
|
||||
|
||||
// Add appends an error to the list.
|
||||
func (e *ErrorList) Add(err Error) {
|
||||
*e = append(*e, err)
|
||||
}
|
||||
|
||||
// AddAt appends an error at position p.
|
||||
func (e *ErrorList) AddAt(p src.Position, err error) {
|
||||
e.Add(Error{p, err})
|
||||
}
|
||||
|
||||
// addext appends an error to the list, tagged with the first external position
|
||||
// outside this package.
|
||||
func (e *ErrorList) addext(err error) {
|
||||
e.Add(exterr(err))
|
||||
}
|
||||
|
||||
// Err returns an error equivalent to this error list.
|
||||
// If the list is empty, Err returns nil.
|
||||
func (e ErrorList) Err() error {
|
||||
if len(e) == 0 {
|
||||
return nil
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
// Error implements the error interface.
|
||||
func (e ErrorList) Error() string {
|
||||
switch len(e) {
|
||||
case 0:
|
||||
return "no errors"
|
||||
case 1:
|
||||
return e[0].Error()
|
||||
}
|
||||
return fmt.Sprintf("%s (and %d more errors)", e[0], len(e)-1)
|
||||
}
|
||||
|
||||
// LogError logs a list of errors, one error per line, if the err parameter is
|
||||
// an ErrorList. Otherwise it just logs the err string. Reports at most max
|
||||
// errors, or unlimited if max is 0.
|
||||
func LogError(l *log.Logger, err error, max int) {
|
||||
var list ErrorList
|
||||
if errors.As(err, &list) {
|
||||
for i, e := range list {
|
||||
if max > 0 && i == max {
|
||||
l.Print("too many errors")
|
||||
return
|
||||
}
|
||||
l.Printf("%s\n", e)
|
||||
}
|
||||
} else if err != nil {
|
||||
l.Printf("%s\n", err)
|
||||
}
|
||||
}
|
163
vendor/github.com/mmcloughlin/avo/build/global.go
generated
vendored
Normal file
163
vendor/github.com/mmcloughlin/avo/build/global.go
generated
vendored
Normal file
@ -0,0 +1,163 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
|
||||
"github.com/mmcloughlin/avo/attr"
|
||||
"github.com/mmcloughlin/avo/buildtags"
|
||||
"github.com/mmcloughlin/avo/gotypes"
|
||||
"github.com/mmcloughlin/avo/ir"
|
||||
"github.com/mmcloughlin/avo/operand"
|
||||
"github.com/mmcloughlin/avo/reg"
|
||||
)
|
||||
|
||||
// ctx provides a global build context.
|
||||
var ctx = NewContext()
|
||||
|
||||
// TEXT starts building a new function called name, with attributes a, and sets its signature (see SignatureExpr).
|
||||
func TEXT(name string, a attr.Attribute, signature string) {
|
||||
ctx.Function(name)
|
||||
ctx.Attributes(a)
|
||||
ctx.SignatureExpr(signature)
|
||||
}
|
||||
|
||||
// GLOBL declares a new static global data section with the given attributes.
|
||||
func GLOBL(name string, a attr.Attribute) operand.Mem {
|
||||
// TODO(mbm): should this be static?
|
||||
g := ctx.StaticGlobal(name)
|
||||
ctx.DataAttributes(a)
|
||||
return g
|
||||
}
|
||||
|
||||
// DATA adds a data value to the active data section.
|
||||
func DATA(offset int, v operand.Constant) {
|
||||
ctx.AddDatum(offset, v)
|
||||
}
|
||||
|
||||
var flags = NewFlags(flag.CommandLine)
|
||||
|
||||
// Generate builds and compiles the avo file built with the global context. This
|
||||
// should be the final line of any avo program. Configuration is determined from command-line flags.
|
||||
func Generate() {
|
||||
if !flag.Parsed() {
|
||||
flag.Parse()
|
||||
}
|
||||
cfg := flags.Config()
|
||||
|
||||
status := Main(cfg, ctx)
|
||||
|
||||
// To record coverage of integration tests we wrap main() functions in a test
|
||||
// functions. In this case we need the main function to terminate, therefore we
|
||||
// only exit for failure status codes.
|
||||
if status != 0 {
|
||||
os.Exit(status)
|
||||
}
|
||||
}
|
||||
|
||||
// Package sets the package the generated file will belong to. Required to be able to reference types in the package.
|
||||
func Package(path string) { ctx.Package(path) }
|
||||
|
||||
// Constraints sets build constraints for the file.
|
||||
func Constraints(t buildtags.ConstraintsConvertable) { ctx.Constraints(t) }
|
||||
|
||||
// Constraint appends a constraint to the file's build constraints.
|
||||
func Constraint(t buildtags.ConstraintConvertable) { ctx.Constraint(t) }
|
||||
|
||||
// ConstraintExpr appends a constraint to the file's build constraints. The
|
||||
// constraint to add is parsed from the given expression. The expression should
|
||||
// look the same as the content following "// +build " in regular build
|
||||
// constraint comments.
|
||||
func ConstraintExpr(expr string) { ctx.ConstraintExpr(expr) }
|
||||
|
||||
// GP8L allocates and returns a general-purpose 8-bit register (low byte).
|
||||
func GP8L() reg.GPVirtual { return ctx.GP8L() }
|
||||
|
||||
// GP8H allocates and returns a general-purpose 8-bit register (high byte).
|
||||
func GP8H() reg.GPVirtual { return ctx.GP8H() }
|
||||
|
||||
// GP8 allocates and returns a general-purpose 8-bit register (low byte).
|
||||
func GP8() reg.GPVirtual { return ctx.GP8() }
|
||||
|
||||
// GP16 allocates and returns a general-purpose 16-bit register.
|
||||
func GP16() reg.GPVirtual { return ctx.GP16() }
|
||||
|
||||
// GP32 allocates and returns a general-purpose 32-bit register.
|
||||
func GP32() reg.GPVirtual { return ctx.GP32() }
|
||||
|
||||
// GP64 allocates and returns a general-purpose 64-bit register.
|
||||
func GP64() reg.GPVirtual { return ctx.GP64() }
|
||||
|
||||
// XMM allocates and returns a 128-bit vector register.
|
||||
func XMM() reg.VecVirtual { return ctx.XMM() }
|
||||
|
||||
// YMM allocates and returns a 256-bit vector register.
|
||||
func YMM() reg.VecVirtual { return ctx.YMM() }
|
||||
|
||||
// ZMM allocates and returns a 512-bit vector register.
|
||||
func ZMM() reg.VecVirtual { return ctx.ZMM() }
|
||||
|
||||
// K allocates and returns an opmask register.
|
||||
func K() reg.OpmaskVirtual { return ctx.K() }
|
||||
|
||||
// Param returns a the named argument of the active function.
|
||||
func Param(name string) gotypes.Component { return ctx.Param(name) }
|
||||
|
||||
// ParamIndex returns the ith argument of the active function.
|
||||
func ParamIndex(i int) gotypes.Component { return ctx.ParamIndex(i) }
|
||||
|
||||
// Return returns a the named return value of the active function.
|
||||
func Return(name string) gotypes.Component { return ctx.Return(name) }
|
||||
|
||||
// ReturnIndex returns the ith argument of the active function.
|
||||
func ReturnIndex(i int) gotypes.Component { return ctx.ReturnIndex(i) }
|
||||
|
||||
// Load the function argument src into register dst. Returns the destination
|
||||
// register. This is syntactic sugar: it will attempt to select the right MOV
|
||||
// instruction based on the types involved.
|
||||
func Load(src gotypes.Component, dst reg.Register) reg.Register { return ctx.Load(src, dst) }
|
||||
|
||||
// Store register src into return value dst. This is syntactic sugar: it will
|
||||
// attempt to select the right MOV instruction based on the types involved.
|
||||
func Store(src reg.Register, dst gotypes.Component) { ctx.Store(src, dst) }
|
||||
|
||||
// Dereference loads a pointer and returns its element type.
|
||||
func Dereference(ptr gotypes.Component) gotypes.Component { return ctx.Dereference(ptr) }
|
||||
|
||||
// Function starts building a new function with the given name.
|
||||
func Function(name string) { ctx.Function(name) }
|
||||
|
||||
// Doc sets documentation comment lines for the currently active function.
|
||||
func Doc(lines ...string) { ctx.Doc(lines...) }
|
||||
|
||||
// Pragma adds a compiler directive to the currently active function.
|
||||
func Pragma(directive string, args ...string) { ctx.Pragma(directive, args...) }
|
||||
|
||||
// Attributes sets function attributes for the currently active function.
|
||||
func Attributes(a attr.Attribute) { ctx.Attributes(a) }
|
||||
|
||||
// SignatureExpr parses the signature expression and sets it as the active function's signature.
|
||||
func SignatureExpr(expr string) { ctx.SignatureExpr(expr) }
|
||||
|
||||
// Implement starts building a function of the given name, whose type is
|
||||
// specified by a stub in the containing package.
|
||||
func Implement(name string) { ctx.Implement(name) }
|
||||
|
||||
// AllocLocal allocates size bytes in the stack of the currently active function.
|
||||
// Returns a reference to the base pointer for the newly allocated region.
|
||||
func AllocLocal(size int) operand.Mem { return ctx.AllocLocal(size) }
|
||||
|
||||
// Label adds a label to the active function.
|
||||
func Label(name string) { ctx.Label(name) }
|
||||
|
||||
// Comment adds comment lines to the active function.
|
||||
func Comment(lines ...string) { ctx.Comment(lines...) }
|
||||
|
||||
// Commentf adds a formtted comment line.
|
||||
func Commentf(format string, a ...any) { ctx.Commentf(format, a...) }
|
||||
|
||||
// ConstData builds a static data section containing just the given constant.
|
||||
func ConstData(name string, v operand.Constant) operand.Mem { return ctx.ConstData(name, v) }
|
||||
|
||||
// Instruction adds an instruction to the active function.
|
||||
func Instruction(i *ir.Instruction) { ctx.Instruction(i) }
|
69
vendor/github.com/mmcloughlin/avo/build/pseudo.go
generated
vendored
Normal file
69
vendor/github.com/mmcloughlin/avo/build/pseudo.go
generated
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"github.com/mmcloughlin/avo/attr"
|
||||
"github.com/mmcloughlin/avo/gotypes"
|
||||
"github.com/mmcloughlin/avo/operand"
|
||||
"github.com/mmcloughlin/avo/reg"
|
||||
)
|
||||
|
||||
//go:generate avogen -output zmov.go mov
|
||||
|
||||
// Param returns a the named argument of the active function.
|
||||
func (c *Context) Param(name string) gotypes.Component {
|
||||
return c.activefunc().Signature.Params().Lookup(name)
|
||||
}
|
||||
|
||||
// ParamIndex returns the ith argument of the active function.
|
||||
func (c *Context) ParamIndex(i int) gotypes.Component {
|
||||
return c.activefunc().Signature.Params().At(i)
|
||||
}
|
||||
|
||||
// Return returns a the named return value of the active function.
|
||||
func (c *Context) Return(name string) gotypes.Component {
|
||||
return c.activefunc().Signature.Results().Lookup(name)
|
||||
}
|
||||
|
||||
// ReturnIndex returns the ith argument of the active function.
|
||||
func (c *Context) ReturnIndex(i int) gotypes.Component {
|
||||
return c.activefunc().Signature.Results().At(i)
|
||||
}
|
||||
|
||||
// Load the function argument src into register dst. Returns the destination
|
||||
// register. This is syntactic sugar: it will attempt to select the right MOV
|
||||
// instruction based on the types involved.
|
||||
func (c *Context) Load(src gotypes.Component, dst reg.Register) reg.Register {
|
||||
b, err := src.Resolve()
|
||||
if err != nil {
|
||||
c.adderror(err)
|
||||
return dst
|
||||
}
|
||||
c.mov(b.Addr, dst, int(gotypes.Sizes.Sizeof(b.Type)), int(dst.Size()), b.Type)
|
||||
return dst
|
||||
}
|
||||
|
||||
// Store register src into return value dst. This is syntactic sugar: it will
|
||||
// attempt to select the right MOV instruction based on the types involved.
|
||||
func (c *Context) Store(src reg.Register, dst gotypes.Component) {
|
||||
b, err := dst.Resolve()
|
||||
if err != nil {
|
||||
c.adderror(err)
|
||||
return
|
||||
}
|
||||
c.mov(src, b.Addr, int(src.Size()), int(gotypes.Sizes.Sizeof(b.Type)), b.Type)
|
||||
}
|
||||
|
||||
// Dereference loads a pointer and returns its element type.
|
||||
func (c *Context) Dereference(ptr gotypes.Component) gotypes.Component {
|
||||
r := c.GP64()
|
||||
c.Load(ptr, r)
|
||||
return ptr.Dereference(r)
|
||||
}
|
||||
|
||||
// ConstData builds a static data section containing just the given constant.
|
||||
func (c *Context) ConstData(name string, v operand.Constant) operand.Mem {
|
||||
g := c.StaticGlobal(name)
|
||||
c.DataAttributes(attr.RODATA | attr.NOPTR)
|
||||
c.AppendDatum(v)
|
||||
return g
|
||||
}
|
86852
vendor/github.com/mmcloughlin/avo/build/zinstructions.go
generated
vendored
Normal file
86852
vendor/github.com/mmcloughlin/avo/build/zinstructions.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
294
vendor/github.com/mmcloughlin/avo/build/zmov.go
generated
vendored
Normal file
294
vendor/github.com/mmcloughlin/avo/build/zmov.go
generated
vendored
Normal file
@ -0,0 +1,294 @@
|
||||
// Code generated by command: avogen -output zmov.go mov. DO NOT EDIT.
|
||||
|
||||
package build
|
||||
|
||||
import (
|
||||
"go/types"
|
||||
|
||||
"github.com/mmcloughlin/avo/operand"
|
||||
)
|
||||
|
||||
func (c *Context) mov(a, b operand.Op, an, bn int, t *types.Basic) {
|
||||
switch {
|
||||
case an == 8 && operand.IsK(a) && bn == 8 && operand.IsK(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.KMOVB(a, b)
|
||||
case an == 8 && operand.IsK(a) && bn == 1 && operand.IsM8(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.KMOVB(a, b)
|
||||
case an == 8 && operand.IsK(a) && bn == 4 && operand.IsR32(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.KMOVB(a, b)
|
||||
case an == 1 && operand.IsM8(a) && bn == 8 && operand.IsK(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.KMOVB(a, b)
|
||||
case an == 4 && operand.IsR32(a) && bn == 8 && operand.IsK(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.KMOVB(a, b)
|
||||
case an == 8 && operand.IsK(a) && bn == 8 && operand.IsK(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.KMOVD(a, b)
|
||||
case an == 8 && operand.IsK(a) && bn == 4 && operand.IsM32(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.KMOVD(a, b)
|
||||
case an == 8 && operand.IsK(a) && bn == 4 && operand.IsR32(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.KMOVD(a, b)
|
||||
case an == 4 && operand.IsM32(a) && bn == 8 && operand.IsK(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.KMOVD(a, b)
|
||||
case an == 4 && operand.IsR32(a) && bn == 8 && operand.IsK(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.KMOVD(a, b)
|
||||
case an == 8 && operand.IsK(a) && bn == 8 && operand.IsK(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.KMOVQ(a, b)
|
||||
case an == 8 && operand.IsK(a) && bn == 8 && operand.IsM64(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.KMOVQ(a, b)
|
||||
case an == 8 && operand.IsK(a) && bn == 8 && operand.IsR64(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.KMOVQ(a, b)
|
||||
case an == 8 && operand.IsM64(a) && bn == 8 && operand.IsK(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.KMOVQ(a, b)
|
||||
case an == 8 && operand.IsR64(a) && bn == 8 && operand.IsK(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.KMOVQ(a, b)
|
||||
case an == 8 && operand.IsK(a) && bn == 8 && operand.IsK(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.KMOVW(a, b)
|
||||
case an == 8 && operand.IsK(a) && bn == 2 && operand.IsM16(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.KMOVW(a, b)
|
||||
case an == 8 && operand.IsK(a) && bn == 4 && operand.IsR32(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.KMOVW(a, b)
|
||||
case an == 2 && operand.IsM16(a) && bn == 8 && operand.IsK(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.KMOVW(a, b)
|
||||
case an == 4 && operand.IsR32(a) && bn == 8 && operand.IsK(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.KMOVW(a, b)
|
||||
case an == 1 && operand.IsM8(a) && bn == 1 && operand.IsR8(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.MOVB(a, b)
|
||||
case an == 1 && operand.IsR8(a) && bn == 1 && operand.IsM8(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.MOVB(a, b)
|
||||
case an == 1 && operand.IsR8(a) && bn == 1 && operand.IsR8(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.MOVB(a, b)
|
||||
case an == 1 && operand.IsM8(a) && bn == 4 && operand.IsR32(b) && (t.Info()&(types.IsInteger|types.IsUnsigned)) == types.IsInteger:
|
||||
c.MOVBLSX(a, b)
|
||||
case an == 1 && operand.IsR8(a) && bn == 4 && operand.IsR32(b) && (t.Info()&(types.IsInteger|types.IsUnsigned)) == types.IsInteger:
|
||||
c.MOVBLSX(a, b)
|
||||
case an == 1 && operand.IsM8(a) && bn == 4 && operand.IsR32(b) && (t.Info()&(types.IsInteger|types.IsUnsigned)) == (types.IsInteger|types.IsUnsigned):
|
||||
c.MOVBLZX(a, b)
|
||||
case an == 1 && operand.IsM8(a) && bn == 4 && operand.IsR32(b) && (t.Info()&types.IsBoolean) != 0:
|
||||
c.MOVBLZX(a, b)
|
||||
case an == 1 && operand.IsR8(a) && bn == 4 && operand.IsR32(b) && (t.Info()&(types.IsInteger|types.IsUnsigned)) == (types.IsInteger|types.IsUnsigned):
|
||||
c.MOVBLZX(a, b)
|
||||
case an == 1 && operand.IsR8(a) && bn == 4 && operand.IsR32(b) && (t.Info()&types.IsBoolean) != 0:
|
||||
c.MOVBLZX(a, b)
|
||||
case an == 1 && operand.IsM8(a) && bn == 8 && operand.IsR64(b) && (t.Info()&(types.IsInteger|types.IsUnsigned)) == types.IsInteger:
|
||||
c.MOVBQSX(a, b)
|
||||
case an == 1 && operand.IsR8(a) && bn == 8 && operand.IsR64(b) && (t.Info()&(types.IsInteger|types.IsUnsigned)) == types.IsInteger:
|
||||
c.MOVBQSX(a, b)
|
||||
case an == 1 && operand.IsM8(a) && bn == 8 && operand.IsR64(b) && (t.Info()&(types.IsInteger|types.IsUnsigned)) == (types.IsInteger|types.IsUnsigned):
|
||||
c.MOVBQZX(a, b)
|
||||
case an == 1 && operand.IsM8(a) && bn == 8 && operand.IsR64(b) && (t.Info()&types.IsBoolean) != 0:
|
||||
c.MOVBQZX(a, b)
|
||||
case an == 1 && operand.IsR8(a) && bn == 8 && operand.IsR64(b) && (t.Info()&(types.IsInteger|types.IsUnsigned)) == (types.IsInteger|types.IsUnsigned):
|
||||
c.MOVBQZX(a, b)
|
||||
case an == 1 && operand.IsR8(a) && bn == 8 && operand.IsR64(b) && (t.Info()&types.IsBoolean) != 0:
|
||||
c.MOVBQZX(a, b)
|
||||
case an == 1 && operand.IsM8(a) && bn == 2 && operand.IsR16(b) && (t.Info()&(types.IsInteger|types.IsUnsigned)) == types.IsInteger:
|
||||
c.MOVBWSX(a, b)
|
||||
case an == 1 && operand.IsR8(a) && bn == 2 && operand.IsR16(b) && (t.Info()&(types.IsInteger|types.IsUnsigned)) == types.IsInteger:
|
||||
c.MOVBWSX(a, b)
|
||||
case an == 1 && operand.IsM8(a) && bn == 2 && operand.IsR16(b) && (t.Info()&(types.IsInteger|types.IsUnsigned)) == (types.IsInteger|types.IsUnsigned):
|
||||
c.MOVBWZX(a, b)
|
||||
case an == 1 && operand.IsM8(a) && bn == 2 && operand.IsR16(b) && (t.Info()&types.IsBoolean) != 0:
|
||||
c.MOVBWZX(a, b)
|
||||
case an == 1 && operand.IsR8(a) && bn == 2 && operand.IsR16(b) && (t.Info()&(types.IsInteger|types.IsUnsigned)) == (types.IsInteger|types.IsUnsigned):
|
||||
c.MOVBWZX(a, b)
|
||||
case an == 1 && operand.IsR8(a) && bn == 2 && operand.IsR16(b) && (t.Info()&types.IsBoolean) != 0:
|
||||
c.MOVBWZX(a, b)
|
||||
case an == 4 && operand.IsM32(a) && bn == 4 && operand.IsR32(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.MOVL(a, b)
|
||||
case an == 4 && operand.IsR32(a) && bn == 4 && operand.IsM32(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.MOVL(a, b)
|
||||
case an == 4 && operand.IsR32(a) && bn == 4 && operand.IsR32(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.MOVL(a, b)
|
||||
case an == 4 && operand.IsM32(a) && bn == 8 && operand.IsR64(b) && (t.Info()&(types.IsInteger|types.IsUnsigned)) == types.IsInteger:
|
||||
c.MOVLQSX(a, b)
|
||||
case an == 4 && operand.IsR32(a) && bn == 8 && operand.IsR64(b) && (t.Info()&(types.IsInteger|types.IsUnsigned)) == types.IsInteger:
|
||||
c.MOVLQSX(a, b)
|
||||
case an == 4 && operand.IsM32(a) && bn == 8 && operand.IsR64(b) && (t.Info()&(types.IsInteger|types.IsUnsigned)) == (types.IsInteger|types.IsUnsigned):
|
||||
c.MOVLQZX(a, b)
|
||||
case an == 4 && operand.IsM32(a) && bn == 8 && operand.IsR64(b) && (t.Info()&types.IsBoolean) != 0:
|
||||
c.MOVLQZX(a, b)
|
||||
case an == 16 && operand.IsM128(a) && bn == 16 && operand.IsXMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.MOVOU(a, b)
|
||||
case an == 16 && operand.IsXMM(a) && bn == 16 && operand.IsM128(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.MOVOU(a, b)
|
||||
case an == 16 && operand.IsXMM(a) && bn == 16 && operand.IsXMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.MOVOU(a, b)
|
||||
case an == 4 && operand.IsM32(a) && bn == 16 && operand.IsXMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.MOVQ(a, b)
|
||||
case an == 8 && operand.IsM64(a) && bn == 16 && operand.IsXMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.MOVQ(a, b)
|
||||
case an == 4 && operand.IsR32(a) && bn == 16 && operand.IsXMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.MOVQ(a, b)
|
||||
case an == 8 && operand.IsR64(a) && bn == 16 && operand.IsXMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.MOVQ(a, b)
|
||||
case an == 16 && operand.IsXMM(a) && bn == 4 && operand.IsM32(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.MOVQ(a, b)
|
||||
case an == 16 && operand.IsXMM(a) && bn == 8 && operand.IsM64(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.MOVQ(a, b)
|
||||
case an == 16 && operand.IsXMM(a) && bn == 4 && operand.IsR32(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.MOVQ(a, b)
|
||||
case an == 16 && operand.IsXMM(a) && bn == 8 && operand.IsR64(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.MOVQ(a, b)
|
||||
case an == 16 && operand.IsXMM(a) && bn == 16 && operand.IsXMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.MOVQ(a, b)
|
||||
case an == 8 && operand.IsM64(a) && bn == 8 && operand.IsR64(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.MOVQ(a, b)
|
||||
case an == 8 && operand.IsR64(a) && bn == 8 && operand.IsM64(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.MOVQ(a, b)
|
||||
case an == 8 && operand.IsR64(a) && bn == 8 && operand.IsR64(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.MOVQ(a, b)
|
||||
case an == 8 && operand.IsM64(a) && bn == 16 && operand.IsXMM(b) && (t.Info()&types.IsFloat) != 0:
|
||||
c.MOVSD(a, b)
|
||||
case an == 16 && operand.IsXMM(a) && bn == 8 && operand.IsM64(b) && (t.Info()&types.IsFloat) != 0:
|
||||
c.MOVSD(a, b)
|
||||
case an == 16 && operand.IsXMM(a) && bn == 16 && operand.IsXMM(b) && (t.Info()&types.IsFloat) != 0:
|
||||
c.MOVSD(a, b)
|
||||
case an == 4 && operand.IsM32(a) && bn == 16 && operand.IsXMM(b) && (t.Info()&types.IsFloat) != 0:
|
||||
c.MOVSS(a, b)
|
||||
case an == 16 && operand.IsXMM(a) && bn == 4 && operand.IsM32(b) && (t.Info()&types.IsFloat) != 0:
|
||||
c.MOVSS(a, b)
|
||||
case an == 16 && operand.IsXMM(a) && bn == 16 && operand.IsXMM(b) && (t.Info()&types.IsFloat) != 0:
|
||||
c.MOVSS(a, b)
|
||||
case an == 2 && operand.IsM16(a) && bn == 2 && operand.IsR16(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.MOVW(a, b)
|
||||
case an == 2 && operand.IsR16(a) && bn == 2 && operand.IsM16(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.MOVW(a, b)
|
||||
case an == 2 && operand.IsR16(a) && bn == 2 && operand.IsR16(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.MOVW(a, b)
|
||||
case an == 2 && operand.IsM16(a) && bn == 4 && operand.IsR32(b) && (t.Info()&(types.IsInteger|types.IsUnsigned)) == types.IsInteger:
|
||||
c.MOVWLSX(a, b)
|
||||
case an == 2 && operand.IsR16(a) && bn == 4 && operand.IsR32(b) && (t.Info()&(types.IsInteger|types.IsUnsigned)) == types.IsInteger:
|
||||
c.MOVWLSX(a, b)
|
||||
case an == 2 && operand.IsM16(a) && bn == 4 && operand.IsR32(b) && (t.Info()&(types.IsInteger|types.IsUnsigned)) == (types.IsInteger|types.IsUnsigned):
|
||||
c.MOVWLZX(a, b)
|
||||
case an == 2 && operand.IsM16(a) && bn == 4 && operand.IsR32(b) && (t.Info()&types.IsBoolean) != 0:
|
||||
c.MOVWLZX(a, b)
|
||||
case an == 2 && operand.IsR16(a) && bn == 4 && operand.IsR32(b) && (t.Info()&(types.IsInteger|types.IsUnsigned)) == (types.IsInteger|types.IsUnsigned):
|
||||
c.MOVWLZX(a, b)
|
||||
case an == 2 && operand.IsR16(a) && bn == 4 && operand.IsR32(b) && (t.Info()&types.IsBoolean) != 0:
|
||||
c.MOVWLZX(a, b)
|
||||
case an == 2 && operand.IsM16(a) && bn == 8 && operand.IsR64(b) && (t.Info()&(types.IsInteger|types.IsUnsigned)) == types.IsInteger:
|
||||
c.MOVWQSX(a, b)
|
||||
case an == 2 && operand.IsR16(a) && bn == 8 && operand.IsR64(b) && (t.Info()&(types.IsInteger|types.IsUnsigned)) == types.IsInteger:
|
||||
c.MOVWQSX(a, b)
|
||||
case an == 2 && operand.IsM16(a) && bn == 8 && operand.IsR64(b) && (t.Info()&(types.IsInteger|types.IsUnsigned)) == (types.IsInteger|types.IsUnsigned):
|
||||
c.MOVWQZX(a, b)
|
||||
case an == 2 && operand.IsM16(a) && bn == 8 && operand.IsR64(b) && (t.Info()&types.IsBoolean) != 0:
|
||||
c.MOVWQZX(a, b)
|
||||
case an == 2 && operand.IsR16(a) && bn == 8 && operand.IsR64(b) && (t.Info()&(types.IsInteger|types.IsUnsigned)) == (types.IsInteger|types.IsUnsigned):
|
||||
c.MOVWQZX(a, b)
|
||||
case an == 2 && operand.IsR16(a) && bn == 8 && operand.IsR64(b) && (t.Info()&types.IsBoolean) != 0:
|
||||
c.MOVWQZX(a, b)
|
||||
case an == 4 && operand.IsM32(a) && bn == 16 && operand.IsXMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVD(a, b)
|
||||
case an == 4 && operand.IsR32(a) && bn == 16 && operand.IsXMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVD(a, b)
|
||||
case an == 16 && operand.IsXMM(a) && bn == 4 && operand.IsM32(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVD(a, b)
|
||||
case an == 16 && operand.IsXMM(a) && bn == 4 && operand.IsR32(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVD(a, b)
|
||||
case an == 16 && operand.IsM128(a) && bn == 16 && operand.IsXMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU(a, b)
|
||||
case an == 32 && operand.IsM256(a) && bn == 32 && operand.IsYMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU(a, b)
|
||||
case an == 16 && operand.IsXMM(a) && bn == 16 && operand.IsM128(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU(a, b)
|
||||
case an == 16 && operand.IsXMM(a) && bn == 16 && operand.IsXMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU(a, b)
|
||||
case an == 32 && operand.IsYMM(a) && bn == 32 && operand.IsM256(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU(a, b)
|
||||
case an == 32 && operand.IsYMM(a) && bn == 32 && operand.IsYMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU(a, b)
|
||||
case an == 16 && operand.IsM128(a) && bn == 16 && operand.IsXMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU16(a, b)
|
||||
case an == 32 && operand.IsM256(a) && bn == 32 && operand.IsYMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU16(a, b)
|
||||
case an == 16 && operand.IsXMM(a) && bn == 16 && operand.IsM128(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU16(a, b)
|
||||
case an == 16 && operand.IsXMM(a) && bn == 16 && operand.IsXMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU16(a, b)
|
||||
case an == 32 && operand.IsYMM(a) && bn == 32 && operand.IsM256(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU16(a, b)
|
||||
case an == 32 && operand.IsYMM(a) && bn == 32 && operand.IsYMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU16(a, b)
|
||||
case an == 64 && operand.IsM512(a) && bn == 64 && operand.IsZMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU16(a, b)
|
||||
case an == 64 && operand.IsZMM(a) && bn == 64 && operand.IsM512(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU16(a, b)
|
||||
case an == 64 && operand.IsZMM(a) && bn == 64 && operand.IsZMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU16(a, b)
|
||||
case an == 16 && operand.IsM128(a) && bn == 16 && operand.IsXMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU32(a, b)
|
||||
case an == 32 && operand.IsM256(a) && bn == 32 && operand.IsYMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU32(a, b)
|
||||
case an == 16 && operand.IsXMM(a) && bn == 16 && operand.IsM128(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU32(a, b)
|
||||
case an == 16 && operand.IsXMM(a) && bn == 16 && operand.IsXMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU32(a, b)
|
||||
case an == 32 && operand.IsYMM(a) && bn == 32 && operand.IsM256(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU32(a, b)
|
||||
case an == 32 && operand.IsYMM(a) && bn == 32 && operand.IsYMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU32(a, b)
|
||||
case an == 64 && operand.IsM512(a) && bn == 64 && operand.IsZMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU32(a, b)
|
||||
case an == 64 && operand.IsZMM(a) && bn == 64 && operand.IsM512(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU32(a, b)
|
||||
case an == 64 && operand.IsZMM(a) && bn == 64 && operand.IsZMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU32(a, b)
|
||||
case an == 16 && operand.IsM128(a) && bn == 16 && operand.IsXMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU64(a, b)
|
||||
case an == 32 && operand.IsM256(a) && bn == 32 && operand.IsYMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU64(a, b)
|
||||
case an == 16 && operand.IsXMM(a) && bn == 16 && operand.IsM128(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU64(a, b)
|
||||
case an == 16 && operand.IsXMM(a) && bn == 16 && operand.IsXMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU64(a, b)
|
||||
case an == 32 && operand.IsYMM(a) && bn == 32 && operand.IsM256(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU64(a, b)
|
||||
case an == 32 && operand.IsYMM(a) && bn == 32 && operand.IsYMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU64(a, b)
|
||||
case an == 64 && operand.IsM512(a) && bn == 64 && operand.IsZMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU64(a, b)
|
||||
case an == 64 && operand.IsZMM(a) && bn == 64 && operand.IsM512(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU64(a, b)
|
||||
case an == 64 && operand.IsZMM(a) && bn == 64 && operand.IsZMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU64(a, b)
|
||||
case an == 16 && operand.IsM128(a) && bn == 16 && operand.IsXMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU8(a, b)
|
||||
case an == 32 && operand.IsM256(a) && bn == 32 && operand.IsYMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU8(a, b)
|
||||
case an == 16 && operand.IsXMM(a) && bn == 16 && operand.IsM128(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU8(a, b)
|
||||
case an == 16 && operand.IsXMM(a) && bn == 16 && operand.IsXMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU8(a, b)
|
||||
case an == 32 && operand.IsYMM(a) && bn == 32 && operand.IsM256(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU8(a, b)
|
||||
case an == 32 && operand.IsYMM(a) && bn == 32 && operand.IsYMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU8(a, b)
|
||||
case an == 64 && operand.IsM512(a) && bn == 64 && operand.IsZMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU8(a, b)
|
||||
case an == 64 && operand.IsZMM(a) && bn == 64 && operand.IsM512(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU8(a, b)
|
||||
case an == 64 && operand.IsZMM(a) && bn == 64 && operand.IsZMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVDQU8(a, b)
|
||||
case an == 8 && operand.IsM64(a) && bn == 16 && operand.IsXMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVQ(a, b)
|
||||
case an == 8 && operand.IsR64(a) && bn == 16 && operand.IsXMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVQ(a, b)
|
||||
case an == 16 && operand.IsXMM(a) && bn == 8 && operand.IsM64(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVQ(a, b)
|
||||
case an == 16 && operand.IsXMM(a) && bn == 8 && operand.IsR64(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVQ(a, b)
|
||||
case an == 16 && operand.IsXMM(a) && bn == 16 && operand.IsXMM(b) && (t.Info()&(types.IsInteger|types.IsBoolean)) != 0:
|
||||
c.VMOVQ(a, b)
|
||||
case an == 8 && operand.IsM64(a) && bn == 16 && operand.IsXMM(b) && (t.Info()&types.IsFloat) != 0:
|
||||
c.VMOVSD(a, b)
|
||||
case an == 16 && operand.IsXMM(a) && bn == 8 && operand.IsM64(b) && (t.Info()&types.IsFloat) != 0:
|
||||
c.VMOVSD(a, b)
|
||||
case an == 4 && operand.IsM32(a) && bn == 16 && operand.IsXMM(b) && (t.Info()&types.IsFloat) != 0:
|
||||
c.VMOVSS(a, b)
|
||||
case an == 16 && operand.IsXMM(a) && bn == 4 && operand.IsM32(b) && (t.Info()&types.IsFloat) != 0:
|
||||
c.VMOVSS(a, b)
|
||||
default:
|
||||
c.adderrormessage("could not deduce mov instruction")
|
||||
}
|
||||
}
|
312
vendor/github.com/mmcloughlin/avo/buildtags/buildtags.go
generated
vendored
Normal file
312
vendor/github.com/mmcloughlin/avo/buildtags/buildtags.go
generated
vendored
Normal file
@ -0,0 +1,312 @@
|
||||
// Package buildtags provides types for representing and manipulating build constraints.
|
||||
//
|
||||
// In Go, build constraints are represented as comments in source code together with file naming conventions. For example
|
||||
//
|
||||
// // +build linux,386 darwin,!cgo
|
||||
// // +build !purego
|
||||
//
|
||||
// Any terms provided in the filename can be thought of as an implicit extra
|
||||
// constraint comment line. Collectively, these are referred to as
|
||||
// “constraints”. Each line is a “constraint”. Within each constraint the
|
||||
// space-separated terms are “options”, and within that the comma-separated
|
||||
// items are “terms” which may be negated with at most one exclaimation mark.
|
||||
//
|
||||
// These represent a boolean formulae. The constraints are evaluated as the AND
|
||||
// of constraint lines; a constraint is evaluated as the OR of its options and
|
||||
// an option is evaluated as the AND of its terms. Overall build constraints are
|
||||
// a boolean formula that is an AND of ORs of ANDs.
|
||||
//
|
||||
// This level of complexity is rarely used in Go programs. Therefore this
|
||||
// package aims to provide access to all these layers of nesting if required,
|
||||
// but make it easy to forget about for basic use cases too.
|
||||
package buildtags
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// Reference: https://github.com/golang/go/blob/204a8f55dc2e0ac8d27a781dab0da609b98560da/src/go/build/doc.go#L73-L92
|
||||
//
|
||||
// // A build constraint is evaluated as the OR of space-separated options;
|
||||
// // each option evaluates as the AND of its comma-separated terms;
|
||||
// // and each term is an alphanumeric word or, preceded by !, its negation.
|
||||
// // That is, the build constraint:
|
||||
// //
|
||||
// // // +build linux,386 darwin,!cgo
|
||||
// //
|
||||
// // corresponds to the boolean formula:
|
||||
// //
|
||||
// // (linux AND 386) OR (darwin AND (NOT cgo))
|
||||
// //
|
||||
// // A file may have multiple build constraints. The overall constraint is the AND
|
||||
// // of the individual constraints. That is, the build constraints:
|
||||
// //
|
||||
// // // +build linux darwin
|
||||
// // // +build 386
|
||||
// //
|
||||
// // corresponds to the boolean formula:
|
||||
// //
|
||||
// // (linux OR darwin) AND 386
|
||||
//
|
||||
|
||||
// Interface represents a build constraint.
|
||||
type Interface interface {
|
||||
ConstraintsConvertable
|
||||
fmt.GoStringer
|
||||
Evaluate(v map[string]bool) bool
|
||||
Validate() error
|
||||
}
|
||||
|
||||
// ConstraintsConvertable can be converted to a Constraints object.
|
||||
type ConstraintsConvertable interface {
|
||||
ToConstraints() Constraints
|
||||
}
|
||||
|
||||
// ConstraintConvertable can be converted to a Constraint.
|
||||
type ConstraintConvertable interface {
|
||||
ToConstraint() Constraint
|
||||
}
|
||||
|
||||
// OptionConvertable can be converted to an Option.
|
||||
type OptionConvertable interface {
|
||||
ToOption() Option
|
||||
}
|
||||
|
||||
// Constraints represents the AND of a list of Constraint lines.
|
||||
type Constraints []Constraint
|
||||
|
||||
// And builds Constraints that will be true if all of its constraints are true.
|
||||
func And(cs ...ConstraintConvertable) Constraints {
|
||||
constraints := Constraints{}
|
||||
for _, c := range cs {
|
||||
constraints = append(constraints, c.ToConstraint())
|
||||
}
|
||||
return constraints
|
||||
}
|
||||
|
||||
// ToConstraints returns cs.
|
||||
func (cs Constraints) ToConstraints() Constraints { return cs }
|
||||
|
||||
// Validate validates the constraints set.
|
||||
func (cs Constraints) Validate() error {
|
||||
for _, c := range cs {
|
||||
if err := c.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Evaluate the boolean formula represented by cs under the given assignment of
|
||||
// tag values. This is the AND of the values of the constituent Constraints.
|
||||
func (cs Constraints) Evaluate(v map[string]bool) bool {
|
||||
r := true
|
||||
for _, c := range cs {
|
||||
r = r && c.Evaluate(v)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// GoString represents Constraints as +build comment lines.
|
||||
func (cs Constraints) GoString() string {
|
||||
s := ""
|
||||
for _, c := range cs {
|
||||
s += c.GoString()
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Constraint represents the OR of a list of Options.
|
||||
type Constraint []Option
|
||||
|
||||
// Any builds a Constraint that will be true if any of its options are true.
|
||||
func Any(opts ...OptionConvertable) Constraint {
|
||||
c := Constraint{}
|
||||
for _, opt := range opts {
|
||||
c = append(c, opt.ToOption())
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// ParseConstraint parses a space-separated list of options.
|
||||
func ParseConstraint(expr string) (Constraint, error) {
|
||||
c := Constraint{}
|
||||
for _, field := range strings.Fields(expr) {
|
||||
opt, err := ParseOption(field)
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
c = append(c, opt)
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// ToConstraints returns the list of constraints containing just c.
|
||||
func (c Constraint) ToConstraints() Constraints { return Constraints{c} }
|
||||
|
||||
// ToConstraint returns c.
|
||||
func (c Constraint) ToConstraint() Constraint { return c }
|
||||
|
||||
// Validate validates the constraint.
|
||||
func (c Constraint) Validate() error {
|
||||
for _, o := range c {
|
||||
if err := o.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Evaluate the boolean formula represented by c under the given assignment of
|
||||
// tag values. This is the OR of the values of the constituent Options.
|
||||
func (c Constraint) Evaluate(v map[string]bool) bool {
|
||||
r := false
|
||||
for _, o := range c {
|
||||
r = r || o.Evaluate(v)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// GoString represents the Constraint as one +build comment line.
|
||||
func (c Constraint) GoString() string {
|
||||
s := "// +build"
|
||||
for _, o := range c {
|
||||
s += " " + o.GoString()
|
||||
}
|
||||
return s + "\n"
|
||||
}
|
||||
|
||||
// Option represents the AND of a list of Terms.
|
||||
type Option []Term
|
||||
|
||||
// Opt builds an Option from the list of Terms.
|
||||
func Opt(terms ...Term) Option {
|
||||
return Option(terms)
|
||||
}
|
||||
|
||||
// ParseOption parses a comma-separated list of terms.
|
||||
func ParseOption(expr string) (Option, error) {
|
||||
opt := Option{}
|
||||
for _, t := range strings.Split(expr, ",") {
|
||||
opt = append(opt, Term(t))
|
||||
}
|
||||
return opt, opt.Validate()
|
||||
}
|
||||
|
||||
// ToConstraints returns Constraints containing just this option.
|
||||
func (o Option) ToConstraints() Constraints { return o.ToConstraint().ToConstraints() }
|
||||
|
||||
// ToConstraint returns a Constraint containing just this option.
|
||||
func (o Option) ToConstraint() Constraint { return Constraint{o} }
|
||||
|
||||
// ToOption returns o.
|
||||
func (o Option) ToOption() Option { return o }
|
||||
|
||||
// Validate validates o.
|
||||
func (o Option) Validate() error {
|
||||
for _, t := range o {
|
||||
if err := t.Validate(); err != nil {
|
||||
return fmt.Errorf("invalid term %q: %w", t, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Evaluate the boolean formula represented by o under the given assignment of
|
||||
// tag values. This is the AND of the values of the constituent Terms.
|
||||
func (o Option) Evaluate(v map[string]bool) bool {
|
||||
r := true
|
||||
for _, t := range o {
|
||||
r = r && t.Evaluate(v)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// GoString represents the Option as a comma-separated list of terms.
|
||||
func (o Option) GoString() string {
|
||||
var ts []string
|
||||
for _, t := range o {
|
||||
ts = append(ts, t.GoString())
|
||||
}
|
||||
return strings.Join(ts, ",")
|
||||
}
|
||||
|
||||
// Term is an atomic term in a build constraint: an identifier or its negation.
|
||||
type Term string
|
||||
|
||||
// Not returns a term for the negation of ident.
|
||||
func Not(ident string) Term {
|
||||
return Term("!" + ident)
|
||||
}
|
||||
|
||||
// ToConstraints returns Constraints containing just this term.
|
||||
func (t Term) ToConstraints() Constraints { return t.ToOption().ToConstraints() }
|
||||
|
||||
// ToConstraint returns a Constraint containing just this term.
|
||||
func (t Term) ToConstraint() Constraint { return t.ToOption().ToConstraint() }
|
||||
|
||||
// ToOption returns an Option containing just this term.
|
||||
func (t Term) ToOption() Option { return Option{t} }
|
||||
|
||||
// IsNegated reports whether t is the negation of an identifier.
|
||||
func (t Term) IsNegated() bool { return strings.HasPrefix(string(t), "!") }
|
||||
|
||||
// Name returns the identifier for this term.
|
||||
func (t Term) Name() string {
|
||||
return strings.TrimPrefix(string(t), "!")
|
||||
}
|
||||
|
||||
// Validate the term.
|
||||
func (t Term) Validate() error {
|
||||
// Reference: https://github.com/golang/go/blob/204a8f55dc2e0ac8d27a781dab0da609b98560da/src/cmd/go/internal/imports/build.go#L110-L112
|
||||
//
|
||||
// if strings.HasPrefix(name, "!!") { // bad syntax, reject always
|
||||
// return false
|
||||
// }
|
||||
//
|
||||
if strings.HasPrefix(string(t), "!!") {
|
||||
return errors.New("at most one '!' allowed")
|
||||
}
|
||||
|
||||
if len(t.Name()) == 0 {
|
||||
return errors.New("empty tag name")
|
||||
}
|
||||
|
||||
// Reference: https://github.com/golang/go/blob/204a8f55dc2e0ac8d27a781dab0da609b98560da/src/cmd/go/internal/imports/build.go#L121-L127
|
||||
//
|
||||
// // Tags must be letters, digits, underscores or dots.
|
||||
// // Unlike in Go identifiers, all digits are fine (e.g., "386").
|
||||
// for _, c := range name {
|
||||
// if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' {
|
||||
// return false
|
||||
// }
|
||||
// }
|
||||
//
|
||||
for _, c := range t.Name() {
|
||||
if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' {
|
||||
return fmt.Errorf("character '%c' disallowed in tags", c)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Evaluate the term under the given set of identifier values.
|
||||
func (t Term) Evaluate(v map[string]bool) bool {
|
||||
return (t.Validate() == nil) && (v[t.Name()] == !t.IsNegated())
|
||||
}
|
||||
|
||||
// GoString returns t.
|
||||
func (t Term) GoString() string { return string(t) }
|
||||
|
||||
// SetTags builds a set where the given list of identifiers are true.
|
||||
func SetTags(idents ...string) map[string]bool {
|
||||
v := map[string]bool{}
|
||||
for _, ident := range idents {
|
||||
v[ident] = true
|
||||
}
|
||||
return v
|
||||
}
|
46
vendor/github.com/mmcloughlin/avo/buildtags/syntax.go
generated
vendored
Normal file
46
vendor/github.com/mmcloughlin/avo/buildtags/syntax.go
generated
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
package buildtags
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// PlusBuildSyntaxSupported reports whether the current Go version supports the
|
||||
// "// +build" constraint syntax.
|
||||
func PlusBuildSyntaxSupported() bool { return plusbuild }
|
||||
|
||||
// GoBuildSyntaxSupported reports whether the current Go version supports the
|
||||
// "//go:build" constraint syntax.
|
||||
func GoBuildSyntaxSupported() bool { return gobuild }
|
||||
|
||||
// Format constraints according to the syntax supported by the current Go version.
|
||||
func Format(t ConstraintsConvertable) (string, error) {
|
||||
// Print build tags to minimal Go source that can be passed to go/format.
|
||||
src := t.ToConstraints().GoString() + "\npackage stub"
|
||||
|
||||
// Format them.
|
||||
formatted, err := format.Source([]byte(src))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("format build constraints: %w", err)
|
||||
}
|
||||
|
||||
// Extract the comment lines.
|
||||
buf := bytes.NewReader(formatted)
|
||||
scanner := bufio.NewScanner(buf)
|
||||
output := ""
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if (PlusBuildSyntaxSupported() && strings.HasPrefix(line, "// +build")) ||
|
||||
(GoBuildSyntaxSupported() && strings.HasPrefix(line, "//go:build")) {
|
||||
output += line + "\n"
|
||||
}
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return "", fmt.Errorf("parse formatted build constraints: %w", err)
|
||||
}
|
||||
|
||||
return output, nil
|
||||
}
|
8
vendor/github.com/mmcloughlin/avo/buildtags/syntax_go116.go
generated
vendored
Normal file
8
vendor/github.com/mmcloughlin/avo/buildtags/syntax_go116.go
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
//go:build !go1.17
|
||||
|
||||
package buildtags
|
||||
|
||||
const (
|
||||
plusbuild = true
|
||||
gobuild = false
|
||||
)
|
8
vendor/github.com/mmcloughlin/avo/buildtags/syntax_go117.go
generated
vendored
Normal file
8
vendor/github.com/mmcloughlin/avo/buildtags/syntax_go117.go
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
//go:build go1.17 && !go1.18
|
||||
|
||||
package buildtags
|
||||
|
||||
const (
|
||||
plusbuild = true
|
||||
gobuild = true
|
||||
)
|
8
vendor/github.com/mmcloughlin/avo/buildtags/syntax_go118.go
generated
vendored
Normal file
8
vendor/github.com/mmcloughlin/avo/buildtags/syntax_go118.go
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
//go:build go1.18
|
||||
|
||||
package buildtags
|
||||
|
||||
const (
|
||||
plusbuild = false
|
||||
gobuild = true
|
||||
)
|
253
vendor/github.com/mmcloughlin/avo/gotypes/components.go
generated
vendored
Normal file
253
vendor/github.com/mmcloughlin/avo/gotypes/components.go
generated
vendored
Normal file
@ -0,0 +1,253 @@
|
||||
package gotypes
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"strconv"
|
||||
|
||||
"github.com/mmcloughlin/avo/operand"
|
||||
"github.com/mmcloughlin/avo/reg"
|
||||
)
|
||||
|
||||
// Sizes provides type sizes used by the standard Go compiler on amd64.
|
||||
var Sizes = types.SizesFor("gc", "amd64")
|
||||
|
||||
// PointerSize is the size of a pointer on amd64.
|
||||
var PointerSize = Sizes.Sizeof(types.Typ[types.UnsafePointer])
|
||||
|
||||
// Basic represents a primitive/basic type at a given memory address.
|
||||
type Basic struct {
|
||||
Addr operand.Mem
|
||||
Type *types.Basic
|
||||
}
|
||||
|
||||
// Component provides access to sub-components of a Go type.
|
||||
type Component interface {
|
||||
// When the component has no further sub-components, Resolve will return a
|
||||
// reference to the components type and memory address. If there was an error
|
||||
// during any previous calls to Component methods, they will be returned at
|
||||
// resolution time.
|
||||
Resolve() (*Basic, error)
|
||||
Dereference(r reg.Register) Component // dereference a pointer
|
||||
Base() Component // base pointer of a string or slice
|
||||
Len() Component // length of a string or slice
|
||||
Cap() Component // capacity of a slice
|
||||
Real() Component // real part of a complex value
|
||||
Imag() Component // imaginary part of a complex value
|
||||
Index(int) Component // index into an array
|
||||
Field(string) Component // access a struct field
|
||||
}
|
||||
|
||||
// componenterr is an error that also provides a null implementation of the
|
||||
// Component interface. This enables us to return an error from Component
|
||||
// methods whilst also allowing method chaining to continue.
|
||||
type componenterr string
|
||||
|
||||
func errorf(format string, args ...any) Component {
|
||||
return componenterr(fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
func (c componenterr) Error() string { return string(c) }
|
||||
func (c componenterr) Resolve() (*Basic, error) { return nil, c }
|
||||
func (c componenterr) Dereference(r reg.Register) Component { return c }
|
||||
func (c componenterr) Base() Component { return c }
|
||||
func (c componenterr) Len() Component { return c }
|
||||
func (c componenterr) Cap() Component { return c }
|
||||
func (c componenterr) Real() Component { return c }
|
||||
func (c componenterr) Imag() Component { return c }
|
||||
func (c componenterr) Index(int) Component { return c }
|
||||
func (c componenterr) Field(string) Component { return c }
|
||||
|
||||
type component struct {
|
||||
typ types.Type
|
||||
addr operand.Mem
|
||||
}
|
||||
|
||||
// NewComponent builds a component for the named type at the given address.
|
||||
func NewComponent(t types.Type, addr operand.Mem) Component {
|
||||
return &component{
|
||||
typ: t,
|
||||
addr: addr,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *component) Resolve() (*Basic, error) {
|
||||
b := toprimitive(c.typ)
|
||||
if b == nil {
|
||||
return nil, errors.New("component is not primitive")
|
||||
}
|
||||
return &Basic{
|
||||
Addr: c.addr,
|
||||
Type: b,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *component) Dereference(r reg.Register) Component {
|
||||
p, ok := c.typ.Underlying().(*types.Pointer)
|
||||
if !ok {
|
||||
return errorf("not pointer type")
|
||||
}
|
||||
return NewComponent(p.Elem(), operand.Mem{Base: r})
|
||||
}
|
||||
|
||||
// Reference: https://github.com/golang/go/blob/50bd1c4d4eb4fac8ddeb5f063c099daccfb71b26/src/reflect/value.go#L1800-L1804
|
||||
//
|
||||
// type SliceHeader struct {
|
||||
// Data uintptr
|
||||
// Len int
|
||||
// Cap int
|
||||
// }
|
||||
var slicehdroffsets = Sizes.Offsetsof([]*types.Var{
|
||||
types.NewField(token.NoPos, nil, "Data", types.Typ[types.Uintptr], false),
|
||||
types.NewField(token.NoPos, nil, "Len", types.Typ[types.Int], false),
|
||||
types.NewField(token.NoPos, nil, "Cap", types.Typ[types.Int], false),
|
||||
})
|
||||
|
||||
func (c *component) Base() Component {
|
||||
if !isslice(c.typ) && !isstring(c.typ) {
|
||||
return errorf("only slices and strings have base pointers")
|
||||
}
|
||||
return c.sub("_base", int(slicehdroffsets[0]), types.Typ[types.Uintptr])
|
||||
}
|
||||
|
||||
func (c *component) Len() Component {
|
||||
if !isslice(c.typ) && !isstring(c.typ) {
|
||||
return errorf("only slices and strings have length fields")
|
||||
}
|
||||
return c.sub("_len", int(slicehdroffsets[1]), types.Typ[types.Int])
|
||||
}
|
||||
|
||||
func (c *component) Cap() Component {
|
||||
if !isslice(c.typ) {
|
||||
return errorf("only slices have capacity fields")
|
||||
}
|
||||
return c.sub("_cap", int(slicehdroffsets[2]), types.Typ[types.Int])
|
||||
}
|
||||
|
||||
func (c *component) Real() Component {
|
||||
if !iscomplex(c.typ) {
|
||||
return errorf("only complex types have real values")
|
||||
}
|
||||
f := complextofloat(c.typ)
|
||||
return c.sub("_real", 0, f)
|
||||
}
|
||||
|
||||
func (c *component) Imag() Component {
|
||||
if !iscomplex(c.typ) {
|
||||
return errorf("only complex types have imaginary values")
|
||||
}
|
||||
f := complextofloat(c.typ)
|
||||
return c.sub("_imag", int(Sizes.Sizeof(f)), f)
|
||||
}
|
||||
|
||||
func (c *component) Index(i int) Component {
|
||||
a, ok := c.typ.Underlying().(*types.Array)
|
||||
if !ok {
|
||||
return errorf("not array type")
|
||||
}
|
||||
if int64(i) >= a.Len() {
|
||||
return errorf("array index out of bounds")
|
||||
}
|
||||
// Reference: https://github.com/golang/tools/blob/bcd4e47d02889ebbc25c9f4bf3d27e4124b0bf9d/go/analysis/passes/asmdecl/asmdecl.go#L482-L494
|
||||
//
|
||||
// case asmArray:
|
||||
// tu := t.Underlying().(*types.Array)
|
||||
// elem := tu.Elem()
|
||||
// // Calculate offset of each element array.
|
||||
// fields := []*types.Var{
|
||||
// types.NewVar(token.NoPos, nil, "fake0", elem),
|
||||
// types.NewVar(token.NoPos, nil, "fake1", elem),
|
||||
// }
|
||||
// offsets := arch.sizes.Offsetsof(fields)
|
||||
// elemoff := int(offsets[1])
|
||||
// for i := 0; i < int(tu.Len()); i++ {
|
||||
// cc = appendComponentsRecursive(arch, elem, cc, suffix+"_"+strconv.Itoa(i), i*elemoff)
|
||||
// }
|
||||
//
|
||||
elem := a.Elem()
|
||||
elemsize := int(Sizes.Sizeof(types.NewArray(elem, 2)) - Sizes.Sizeof(types.NewArray(elem, 1)))
|
||||
return c.sub("_"+strconv.Itoa(i), i*elemsize, elem)
|
||||
}
|
||||
|
||||
func (c *component) Field(n string) Component {
|
||||
s, ok := c.typ.Underlying().(*types.Struct)
|
||||
if !ok {
|
||||
return errorf("not struct type")
|
||||
}
|
||||
// Reference: https://github.com/golang/tools/blob/13ba8ad772dfbf0f451b5dd0679e9c5605afc05d/go/analysis/passes/asmdecl/asmdecl.go#L471-L480
|
||||
//
|
||||
// case asmStruct:
|
||||
// tu := t.Underlying().(*types.Struct)
|
||||
// fields := make([]*types.Var, tu.NumFields())
|
||||
// for i := 0; i < tu.NumFields(); i++ {
|
||||
// fields[i] = tu.Field(i)
|
||||
// }
|
||||
// offsets := arch.sizes.Offsetsof(fields)
|
||||
// for i, f := range fields {
|
||||
// cc = appendComponentsRecursive(arch, f.Type(), cc, suffix+"_"+f.Name(), off+int(offsets[i]))
|
||||
// }
|
||||
//
|
||||
fields := make([]*types.Var, s.NumFields())
|
||||
for i := 0; i < s.NumFields(); i++ {
|
||||
fields[i] = s.Field(i)
|
||||
}
|
||||
offsets := Sizes.Offsetsof(fields)
|
||||
for i, f := range fields {
|
||||
if f.Name() == n {
|
||||
return c.sub("_"+n, int(offsets[i]), f.Type())
|
||||
}
|
||||
}
|
||||
return errorf("struct does not have field '%s'", n)
|
||||
}
|
||||
|
||||
func (c *component) sub(suffix string, offset int, t types.Type) *component {
|
||||
s := *c
|
||||
if s.addr.Symbol.Name != "" {
|
||||
s.addr.Symbol.Name += suffix
|
||||
}
|
||||
s.addr = s.addr.Offset(offset)
|
||||
s.typ = t
|
||||
return &s
|
||||
}
|
||||
|
||||
func isslice(t types.Type) bool {
|
||||
_, ok := t.Underlying().(*types.Slice)
|
||||
return ok
|
||||
}
|
||||
|
||||
func isstring(t types.Type) bool {
|
||||
b, ok := t.Underlying().(*types.Basic)
|
||||
return ok && b.Kind() == types.String
|
||||
}
|
||||
|
||||
func iscomplex(t types.Type) bool {
|
||||
b, ok := t.Underlying().(*types.Basic)
|
||||
return ok && (b.Info()&types.IsComplex) != 0
|
||||
}
|
||||
|
||||
func complextofloat(t types.Type) types.Type {
|
||||
switch Sizes.Sizeof(t) {
|
||||
case 16:
|
||||
return types.Typ[types.Float64]
|
||||
case 8:
|
||||
return types.Typ[types.Float32]
|
||||
}
|
||||
panic("bad")
|
||||
}
|
||||
|
||||
// toprimitive determines whether t is primitive (cannot be reduced into
|
||||
// components). If it is, it returns the basic type for t, otherwise returns
|
||||
// nil.
|
||||
func toprimitive(t types.Type) *types.Basic {
|
||||
switch b := t.(type) {
|
||||
case *types.Basic:
|
||||
if (b.Info() & (types.IsString | types.IsComplex)) == 0 {
|
||||
return b
|
||||
}
|
||||
case *types.Pointer:
|
||||
return types.Typ[types.Uintptr]
|
||||
}
|
||||
return nil
|
||||
}
|
2
vendor/github.com/mmcloughlin/avo/gotypes/doc.go
generated
vendored
Normal file
2
vendor/github.com/mmcloughlin/avo/gotypes/doc.go
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
// Package gotypes provides helpers for interacting with Go types within avo functions.
|
||||
package gotypes
|
193
vendor/github.com/mmcloughlin/avo/gotypes/signature.go
generated
vendored
Normal file
193
vendor/github.com/mmcloughlin/avo/gotypes/signature.go
generated
vendored
Normal file
@ -0,0 +1,193 @@
|
||||
package gotypes
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"strconv"
|
||||
|
||||
"github.com/mmcloughlin/avo/operand"
|
||||
)
|
||||
|
||||
// Signature represents a Go function signature.
|
||||
type Signature struct {
|
||||
pkg *types.Package
|
||||
sig *types.Signature
|
||||
params *Tuple
|
||||
results *Tuple
|
||||
}
|
||||
|
||||
// NewSignature constructs a Signature.
|
||||
func NewSignature(pkg *types.Package, sig *types.Signature) *Signature {
|
||||
s := &Signature{
|
||||
pkg: pkg,
|
||||
sig: sig,
|
||||
}
|
||||
s.init()
|
||||
return s
|
||||
}
|
||||
|
||||
// NewSignatureVoid builds the void signature "func()".
|
||||
func NewSignatureVoid() *Signature {
|
||||
return NewSignature(nil, types.NewSignatureType(nil, nil, nil, nil, nil, false))
|
||||
}
|
||||
|
||||
// LookupSignature returns the signature of the named function in the provided package.
|
||||
func LookupSignature(pkg *types.Package, name string) (*Signature, error) {
|
||||
scope := pkg.Scope()
|
||||
obj := scope.Lookup(name)
|
||||
if obj == nil {
|
||||
return nil, fmt.Errorf("could not find function \"%s\"", name)
|
||||
}
|
||||
s, ok := obj.Type().(*types.Signature)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("object \"%s\" does not have signature type", name)
|
||||
}
|
||||
return NewSignature(pkg, s), nil
|
||||
}
|
||||
|
||||
// ParseSignature builds a Signature by parsing a Go function type expression.
|
||||
// The function type must reference builtin types only; see
|
||||
// ParseSignatureInPackage if custom types are required.
|
||||
func ParseSignature(expr string) (*Signature, error) {
|
||||
return ParseSignatureInPackage(nil, expr)
|
||||
}
|
||||
|
||||
// ParseSignatureInPackage builds a Signature by parsing a Go function type
|
||||
// expression. The expression may reference types in the provided package.
|
||||
func ParseSignatureInPackage(pkg *types.Package, expr string) (*Signature, error) {
|
||||
tv, err := types.Eval(token.NewFileSet(), pkg, token.NoPos, expr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tv.Value != nil {
|
||||
return nil, errors.New("signature expression should have nil value")
|
||||
}
|
||||
s, ok := tv.Type.(*types.Signature)
|
||||
if !ok {
|
||||
return nil, errors.New("provided type is not a function signature")
|
||||
}
|
||||
return NewSignature(pkg, s), nil
|
||||
}
|
||||
|
||||
// Params returns the function signature argument types.
|
||||
func (s *Signature) Params() *Tuple { return s.params }
|
||||
|
||||
// Results returns the function return types.
|
||||
func (s *Signature) Results() *Tuple { return s.results }
|
||||
|
||||
// Bytes returns the total size of the function arguments and return values.
|
||||
func (s *Signature) Bytes() int { return s.Params().Bytes() + s.Results().Bytes() }
|
||||
|
||||
// String writes Signature as a string. This does not include the "func" keyword.
|
||||
func (s *Signature) String() string {
|
||||
var buf bytes.Buffer
|
||||
types.WriteSignature(&buf, s.sig, func(pkg *types.Package) string {
|
||||
if pkg == s.pkg {
|
||||
return ""
|
||||
}
|
||||
return pkg.Name()
|
||||
})
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func (s *Signature) init() {
|
||||
p := s.sig.Params()
|
||||
r := s.sig.Results()
|
||||
|
||||
// Compute parameter offsets. Note that if the function has results,
|
||||
// additional padding up to max align is inserted between parameters and
|
||||
// results.
|
||||
vs := tuplevars(p)
|
||||
vs = append(vs, types.NewParam(token.NoPos, nil, "sentinel", types.Typ[types.Uint64]))
|
||||
paramsoffsets := Sizes.Offsetsof(vs)
|
||||
paramssize := paramsoffsets[p.Len()]
|
||||
if r.Len() == 0 {
|
||||
paramssize = structsize(vs[:p.Len()])
|
||||
}
|
||||
s.params = newTuple(p, paramsoffsets, paramssize, "arg")
|
||||
|
||||
// Result offsets.
|
||||
vs = tuplevars(r)
|
||||
resultsoffsets := Sizes.Offsetsof(vs)
|
||||
resultssize := structsize(vs)
|
||||
for i := range resultsoffsets {
|
||||
resultsoffsets[i] += paramssize
|
||||
}
|
||||
s.results = newTuple(r, resultsoffsets, resultssize, "ret")
|
||||
}
|
||||
|
||||
// Tuple represents a tuple of variables, such as function arguments or results.
|
||||
type Tuple struct {
|
||||
components []Component
|
||||
byname map[string]Component
|
||||
size int
|
||||
}
|
||||
|
||||
func newTuple(t *types.Tuple, offsets []int64, size int64, defaultprefix string) *Tuple {
|
||||
tuple := &Tuple{
|
||||
byname: map[string]Component{},
|
||||
size: int(size),
|
||||
}
|
||||
for i := 0; i < t.Len(); i++ {
|
||||
v := t.At(i)
|
||||
name := v.Name()
|
||||
if name == "" {
|
||||
name = defaultprefix
|
||||
if i > 0 {
|
||||
name += strconv.Itoa(i)
|
||||
}
|
||||
}
|
||||
addr := operand.NewParamAddr(name, int(offsets[i]))
|
||||
c := NewComponent(v.Type(), addr)
|
||||
tuple.components = append(tuple.components, c)
|
||||
if v.Name() != "" {
|
||||
tuple.byname[v.Name()] = c
|
||||
}
|
||||
}
|
||||
return tuple
|
||||
}
|
||||
|
||||
// Lookup returns the variable with the given name.
|
||||
func (t *Tuple) Lookup(name string) Component {
|
||||
e := t.byname[name]
|
||||
if e == nil {
|
||||
return errorf("unknown variable \"%s\"", name)
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
// At returns the variable at index i.
|
||||
func (t *Tuple) At(i int) Component {
|
||||
if i >= len(t.components) {
|
||||
return errorf("index out of range")
|
||||
}
|
||||
return t.components[i]
|
||||
}
|
||||
|
||||
// Bytes returns the size of the Tuple. This may include additional padding.
|
||||
func (t *Tuple) Bytes() int { return t.size }
|
||||
|
||||
func tuplevars(t *types.Tuple) []*types.Var {
|
||||
vs := make([]*types.Var, t.Len())
|
||||
for i := 0; i < t.Len(); i++ {
|
||||
vs[i] = t.At(i)
|
||||
}
|
||||
return vs
|
||||
}
|
||||
|
||||
// structsize computes the size of a struct containing the given variables as
|
||||
// fields. It would be equivalent to calculating the size of types.NewStruct(vs,
|
||||
// nil), apart from the fact that NewStruct panics if multiple fields have the
|
||||
// same name, and this happens for example if the variables represent return
|
||||
// types from a function.
|
||||
func structsize(vs []*types.Var) int64 {
|
||||
n := len(vs)
|
||||
if n == 0 {
|
||||
return 0
|
||||
}
|
||||
offsets := Sizes.Offsetsof(vs)
|
||||
return offsets[n-1] + Sizes.Sizeof(vs[n-1].Type())
|
||||
}
|
101
vendor/github.com/mmcloughlin/avo/internal/prnt/printer.go
generated
vendored
Normal file
101
vendor/github.com/mmcloughlin/avo/internal/prnt/printer.go
generated
vendored
Normal file
@ -0,0 +1,101 @@
|
||||
// Package prnt provides common functionality for code generators.
|
||||
package prnt
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/build/constraint"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Generator provides convenience methods for code generators. In particular it
|
||||
// provides fmt-like methods which print to an internal buffer. It also allows
|
||||
// any errors to be stored so they can be checked at the end, rather than having
|
||||
// error checks obscuring the code generation.
|
||||
type Generator struct {
|
||||
buf bytes.Buffer
|
||||
level int // current indentation level
|
||||
indent string // indentation string
|
||||
pending bool // if there's a pending indentation
|
||||
err error // saved error from printing
|
||||
}
|
||||
|
||||
// Raw provides direct access to the underlying output stream.
|
||||
func (g *Generator) Raw() io.Writer {
|
||||
return &g.buf
|
||||
}
|
||||
|
||||
// SetIndentString sets the string used for one level of indentation. Use
|
||||
// Indent() and Dedent() to control indent level.
|
||||
func (g *Generator) SetIndentString(indent string) {
|
||||
g.indent = indent
|
||||
}
|
||||
|
||||
// Indent increments the indent level.
|
||||
func (g *Generator) Indent() {
|
||||
g.level++
|
||||
}
|
||||
|
||||
// Dedent decrements the indent level.
|
||||
func (g *Generator) Dedent() {
|
||||
g.level--
|
||||
}
|
||||
|
||||
// Linef prints formatted output terminated with a new line.
|
||||
func (g *Generator) Linef(format string, args ...any) {
|
||||
g.Printf(format, args...)
|
||||
g.NL()
|
||||
}
|
||||
|
||||
// Printf prints to the internal buffer.
|
||||
func (g *Generator) Printf(format string, args ...any) {
|
||||
if g.err != nil {
|
||||
return
|
||||
}
|
||||
if g.pending {
|
||||
indent := strings.Repeat(g.indent, g.level)
|
||||
format = indent + format
|
||||
g.pending = false
|
||||
}
|
||||
_, err := fmt.Fprintf(&g.buf, format, args...)
|
||||
g.AddError(err)
|
||||
}
|
||||
|
||||
// NL prints a new line.
|
||||
func (g *Generator) NL() {
|
||||
g.Printf("\n")
|
||||
g.pending = true
|
||||
}
|
||||
|
||||
// Comment writes comment lines prefixed with "// ".
|
||||
func (g *Generator) Comment(lines ...string) {
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace("// " + line)
|
||||
g.Printf("%s\n", line)
|
||||
}
|
||||
}
|
||||
|
||||
// BuildConstraint outputs a build constraint.
|
||||
func (g *Generator) BuildConstraint(expr string) {
|
||||
line := fmt.Sprintf("//go:build %s", expr)
|
||||
if _, err := constraint.Parse(line); err != nil {
|
||||
g.AddError(err)
|
||||
}
|
||||
g.Linef(line)
|
||||
}
|
||||
|
||||
// AddError records an error in code generation. The first non-nil error will
|
||||
// prevent printing operations from writing anything else, and the error will be
|
||||
// returned from Result().
|
||||
func (g *Generator) AddError(err error) {
|
||||
if err != nil && g.err == nil {
|
||||
g.err = err
|
||||
}
|
||||
}
|
||||
|
||||
// Result returns the printed bytes. If any error was recorded with AddError
|
||||
// during code generation, the first such error will be returned here.
|
||||
func (g *Generator) Result() ([]byte, error) {
|
||||
return g.buf.Bytes(), g.err
|
||||
}
|
73
vendor/github.com/mmcloughlin/avo/internal/stack/stack.go
generated
vendored
Normal file
73
vendor/github.com/mmcloughlin/avo/internal/stack/stack.go
generated
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
// Package stack provides helpers for querying the callstack.
|
||||
package stack
|
||||
|
||||
import (
|
||||
"path"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Frames returns at most max callstack Frames, starting with its caller and
|
||||
// skipping skip Frames.
|
||||
func Frames(skip, max int) []runtime.Frame {
|
||||
pc := make([]uintptr, max)
|
||||
n := runtime.Callers(skip+2, pc)
|
||||
if n == 0 {
|
||||
return nil
|
||||
}
|
||||
pc = pc[:n]
|
||||
frames := runtime.CallersFrames(pc)
|
||||
var fs []runtime.Frame
|
||||
for {
|
||||
f, more := frames.Next()
|
||||
fs = append(fs, f)
|
||||
if !more {
|
||||
break
|
||||
}
|
||||
}
|
||||
return fs
|
||||
}
|
||||
|
||||
// Match returns the first stack frame for which the predicate function returns
|
||||
// true. Returns nil if no match is found. Starts matching after skip frames,
|
||||
// starting with its caller.
|
||||
func Match(skip int, predicate func(runtime.Frame) bool) *runtime.Frame {
|
||||
i, n := skip+1, 16
|
||||
for {
|
||||
fs := Frames(i, n)
|
||||
for j, f := range fs {
|
||||
if predicate(f) {
|
||||
return &fs[j]
|
||||
}
|
||||
}
|
||||
if len(fs) < n {
|
||||
break
|
||||
}
|
||||
i += n
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Main returns the main() function Frame.
|
||||
func Main() *runtime.Frame {
|
||||
return Match(1, func(f runtime.Frame) bool {
|
||||
return f.Function == "main.main"
|
||||
})
|
||||
}
|
||||
|
||||
// ExternalCaller returns the first frame outside the callers package.
|
||||
func ExternalCaller() *runtime.Frame {
|
||||
var first *runtime.Frame
|
||||
return Match(1, func(f runtime.Frame) bool {
|
||||
if first == nil {
|
||||
first = &f
|
||||
}
|
||||
return pkg(first.Function) != pkg(f.Function)
|
||||
})
|
||||
}
|
||||
|
||||
func pkg(ident string) string {
|
||||
dir, name := path.Split(ident)
|
||||
parts := strings.Split(name, ".")
|
||||
return dir + parts[0]
|
||||
}
|
2
vendor/github.com/mmcloughlin/avo/ir/doc.go
generated
vendored
Normal file
2
vendor/github.com/mmcloughlin/avo/ir/doc.go
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
// Package ir provides the intermediate representation of avo programs.
|
||||
package ir
|
365
vendor/github.com/mmcloughlin/avo/ir/ir.go
generated
vendored
Normal file
365
vendor/github.com/mmcloughlin/avo/ir/ir.go
generated
vendored
Normal file
@ -0,0 +1,365 @@
|
||||
package ir
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/mmcloughlin/avo/attr"
|
||||
"github.com/mmcloughlin/avo/buildtags"
|
||||
"github.com/mmcloughlin/avo/gotypes"
|
||||
"github.com/mmcloughlin/avo/operand"
|
||||
"github.com/mmcloughlin/avo/reg"
|
||||
)
|
||||
|
||||
// Node is a part of a Function.
|
||||
type Node interface {
|
||||
node()
|
||||
}
|
||||
|
||||
// Label within a function.
|
||||
type Label string
|
||||
|
||||
func (l Label) node() {}
|
||||
|
||||
// Comment represents a multi-line comment.
|
||||
type Comment struct {
|
||||
Lines []string
|
||||
}
|
||||
|
||||
func (c *Comment) node() {}
|
||||
|
||||
// NewComment builds a Comment consisting of the provided lines.
|
||||
func NewComment(lines ...string) *Comment {
|
||||
return &Comment{
|
||||
Lines: lines,
|
||||
}
|
||||
}
|
||||
|
||||
// Instruction is a single instruction in a function.
|
||||
type Instruction struct {
|
||||
Opcode string
|
||||
Suffixes []string
|
||||
Operands []operand.Op
|
||||
|
||||
Inputs []operand.Op
|
||||
Outputs []operand.Op
|
||||
|
||||
IsTerminal bool
|
||||
IsBranch bool
|
||||
IsConditional bool
|
||||
CancellingInputs bool
|
||||
|
||||
// ISA is the list of required instruction set extensions.
|
||||
ISA []string
|
||||
|
||||
// CFG.
|
||||
Pred []*Instruction
|
||||
Succ []*Instruction
|
||||
|
||||
// LiveIn/LiveOut are sets of live register IDs pre/post execution.
|
||||
LiveIn reg.MaskSet
|
||||
LiveOut reg.MaskSet
|
||||
}
|
||||
|
||||
func (i *Instruction) node() {}
|
||||
|
||||
// OpcodeWithSuffixes returns the full opcode, including dot-separated suffixes.
|
||||
func (i *Instruction) OpcodeWithSuffixes() string {
|
||||
opcode := i.Opcode
|
||||
for _, s := range i.Suffixes {
|
||||
opcode += "." + s
|
||||
}
|
||||
return opcode
|
||||
}
|
||||
|
||||
// IsUnconditionalBranch reports whether i is an unconditional branch.
|
||||
func (i Instruction) IsUnconditionalBranch() bool {
|
||||
return i.IsBranch && !i.IsConditional
|
||||
}
|
||||
|
||||
// TargetLabel returns the label referenced by this instruction. Returns nil if
|
||||
// no label is referenced.
|
||||
func (i Instruction) TargetLabel() *Label {
|
||||
if !i.IsBranch {
|
||||
return nil
|
||||
}
|
||||
if len(i.Operands) == 0 {
|
||||
return nil
|
||||
}
|
||||
if ref, ok := i.Operands[0].(operand.LabelRef); ok {
|
||||
lbl := Label(ref)
|
||||
return &lbl
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Registers returns all registers involved in the instruction.
|
||||
func (i Instruction) Registers() []reg.Register {
|
||||
var rs []reg.Register
|
||||
for _, op := range i.Operands {
|
||||
rs = append(rs, operand.Registers(op)...)
|
||||
}
|
||||
return rs
|
||||
}
|
||||
|
||||
// InputRegisters returns all registers read by this instruction.
|
||||
func (i Instruction) InputRegisters() []reg.Register {
|
||||
var rs []reg.Register
|
||||
for _, op := range i.Inputs {
|
||||
rs = append(rs, operand.Registers(op)...)
|
||||
}
|
||||
if i.CancellingInputs && rs[0] == rs[1] {
|
||||
rs = []reg.Register{}
|
||||
}
|
||||
for _, op := range i.Outputs {
|
||||
if operand.IsMem(op) {
|
||||
rs = append(rs, operand.Registers(op)...)
|
||||
}
|
||||
}
|
||||
return rs
|
||||
}
|
||||
|
||||
// OutputRegisters returns all registers written by this instruction.
|
||||
func (i Instruction) OutputRegisters() []reg.Register {
|
||||
var rs []reg.Register
|
||||
for _, op := range i.Outputs {
|
||||
if r, ok := op.(reg.Register); ok {
|
||||
rs = append(rs, r)
|
||||
}
|
||||
}
|
||||
return rs
|
||||
}
|
||||
|
||||
// Section is a part of a file.
|
||||
type Section interface {
|
||||
section()
|
||||
}
|
||||
|
||||
// File represents an assembly file.
|
||||
type File struct {
|
||||
Constraints buildtags.Constraints
|
||||
Includes []string
|
||||
Sections []Section
|
||||
}
|
||||
|
||||
// NewFile initializes an empty file.
|
||||
func NewFile() *File {
|
||||
return &File{}
|
||||
}
|
||||
|
||||
// AddSection appends a Section to the file.
|
||||
func (f *File) AddSection(s Section) {
|
||||
f.Sections = append(f.Sections, s)
|
||||
}
|
||||
|
||||
// Functions returns all functions in the file.
|
||||
func (f *File) Functions() []*Function {
|
||||
var fns []*Function
|
||||
for _, s := range f.Sections {
|
||||
if fn, ok := s.(*Function); ok {
|
||||
fns = append(fns, fn)
|
||||
}
|
||||
}
|
||||
return fns
|
||||
}
|
||||
|
||||
// Pragma represents a function compiler directive.
|
||||
type Pragma struct {
|
||||
Directive string
|
||||
Arguments []string
|
||||
}
|
||||
|
||||
// Function represents an assembly function.
|
||||
type Function struct {
|
||||
Name string
|
||||
Attributes attr.Attribute
|
||||
Pragmas []Pragma
|
||||
Doc []string
|
||||
Signature *gotypes.Signature
|
||||
LocalSize int
|
||||
|
||||
Nodes []Node
|
||||
|
||||
// LabelTarget maps from label name to the following instruction.
|
||||
LabelTarget map[Label]*Instruction
|
||||
|
||||
// Register allocation.
|
||||
Allocation reg.Allocation
|
||||
|
||||
// ISA is the list of required instruction set extensions.
|
||||
ISA []string
|
||||
}
|
||||
|
||||
func (f *Function) section() {}
|
||||
|
||||
// NewFunction builds an empty function of the given name.
|
||||
func NewFunction(name string) *Function {
|
||||
return &Function{
|
||||
Name: name,
|
||||
Signature: gotypes.NewSignatureVoid(),
|
||||
}
|
||||
}
|
||||
|
||||
// AddPragma adds a pragma to this function.
|
||||
func (f *Function) AddPragma(directive string, args ...string) {
|
||||
f.Pragmas = append(f.Pragmas, Pragma{
|
||||
Directive: directive,
|
||||
Arguments: args,
|
||||
})
|
||||
}
|
||||
|
||||
// SetSignature sets the function signature.
|
||||
func (f *Function) SetSignature(s *gotypes.Signature) {
|
||||
f.Signature = s
|
||||
}
|
||||
|
||||
// AllocLocal allocates size bytes in this function's stack.
|
||||
// Returns a reference to the base pointer for the newly allocated region.
|
||||
func (f *Function) AllocLocal(size int) operand.Mem {
|
||||
ptr := operand.NewStackAddr(f.LocalSize)
|
||||
f.LocalSize += size
|
||||
return ptr
|
||||
}
|
||||
|
||||
// AddInstruction appends an instruction to f.
|
||||
func (f *Function) AddInstruction(i *Instruction) {
|
||||
f.AddNode(i)
|
||||
}
|
||||
|
||||
// AddLabel appends a label to f.
|
||||
func (f *Function) AddLabel(l Label) {
|
||||
f.AddNode(l)
|
||||
}
|
||||
|
||||
// AddComment adds comment lines to f.
|
||||
func (f *Function) AddComment(lines ...string) {
|
||||
f.AddNode(NewComment(lines...))
|
||||
}
|
||||
|
||||
// AddNode appends a Node to f.
|
||||
func (f *Function) AddNode(n Node) {
|
||||
f.Nodes = append(f.Nodes, n)
|
||||
}
|
||||
|
||||
// Instructions returns just the list of instruction nodes.
|
||||
func (f *Function) Instructions() []*Instruction {
|
||||
var is []*Instruction
|
||||
for _, n := range f.Nodes {
|
||||
i, ok := n.(*Instruction)
|
||||
if ok {
|
||||
is = append(is, i)
|
||||
}
|
||||
}
|
||||
return is
|
||||
}
|
||||
|
||||
// Labels returns just the list of label nodes.
|
||||
func (f *Function) Labels() []Label {
|
||||
var lbls []Label
|
||||
for _, n := range f.Nodes {
|
||||
lbl, ok := n.(Label)
|
||||
if ok {
|
||||
lbls = append(lbls, lbl)
|
||||
}
|
||||
}
|
||||
return lbls
|
||||
}
|
||||
|
||||
// Stub returns the Go function declaration.
|
||||
func (f *Function) Stub() string {
|
||||
return "func " + f.Name + f.Signature.String()
|
||||
}
|
||||
|
||||
// FrameBytes returns the size of the stack frame in bytes.
|
||||
func (f *Function) FrameBytes() int {
|
||||
return f.LocalSize
|
||||
}
|
||||
|
||||
// ArgumentBytes returns the size of the arguments in bytes.
|
||||
func (f *Function) ArgumentBytes() int {
|
||||
return f.Signature.Bytes()
|
||||
}
|
||||
|
||||
// Datum represents a data element at a particular offset of a data section.
|
||||
type Datum struct {
|
||||
Offset int
|
||||
Value operand.Constant
|
||||
}
|
||||
|
||||
// NewDatum builds a Datum from the given constant.
|
||||
func NewDatum(offset int, v operand.Constant) Datum {
|
||||
return Datum{
|
||||
Offset: offset,
|
||||
Value: v,
|
||||
}
|
||||
}
|
||||
|
||||
// Interval returns the range of bytes this datum will occupy within its section.
|
||||
func (d Datum) Interval() (int, int) {
|
||||
return d.Offset, d.Offset + d.Value.Bytes()
|
||||
}
|
||||
|
||||
// Overlaps returns whether d overlaps with other.
|
||||
func (d Datum) Overlaps(other Datum) bool {
|
||||
s, e := d.Interval()
|
||||
so, eo := other.Interval()
|
||||
return !(eo <= s || e <= so)
|
||||
}
|
||||
|
||||
// Global represents a DATA section.
|
||||
type Global struct {
|
||||
Symbol operand.Symbol
|
||||
Attributes attr.Attribute
|
||||
Data []Datum
|
||||
Size int
|
||||
}
|
||||
|
||||
// NewGlobal constructs an empty DATA section.
|
||||
func NewGlobal(sym operand.Symbol) *Global {
|
||||
return &Global{
|
||||
Symbol: sym,
|
||||
}
|
||||
}
|
||||
|
||||
// NewStaticGlobal is a convenience for building a static DATA section.
|
||||
func NewStaticGlobal(name string) *Global {
|
||||
return NewGlobal(operand.NewStaticSymbol(name))
|
||||
}
|
||||
|
||||
func (g *Global) section() {}
|
||||
|
||||
// Base returns a pointer to the start of the data section.
|
||||
func (g *Global) Base() operand.Mem {
|
||||
return operand.NewDataAddr(g.Symbol, 0)
|
||||
}
|
||||
|
||||
// Grow ensures that the data section has at least the given size.
|
||||
func (g *Global) Grow(size int) {
|
||||
if g.Size < size {
|
||||
g.Size = size
|
||||
}
|
||||
}
|
||||
|
||||
// AddDatum adds d to this data section, growing it if necessary. Errors if the datum overlaps with existing data.
|
||||
func (g *Global) AddDatum(d Datum) error {
|
||||
for _, other := range g.Data {
|
||||
if d.Overlaps(other) {
|
||||
return errors.New("overlaps existing datum")
|
||||
}
|
||||
}
|
||||
g.add(d)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Append the constant to the end of the data section.
|
||||
func (g *Global) Append(v operand.Constant) {
|
||||
g.add(Datum{
|
||||
Offset: g.Size,
|
||||
Value: v,
|
||||
})
|
||||
}
|
||||
|
||||
func (g *Global) add(d Datum) {
|
||||
_, end := d.Interval()
|
||||
g.Grow(end)
|
||||
g.Data = append(g.Data, d)
|
||||
}
|
282
vendor/github.com/mmcloughlin/avo/operand/checks.go
generated
vendored
Normal file
282
vendor/github.com/mmcloughlin/avo/operand/checks.go
generated
vendored
Normal file
@ -0,0 +1,282 @@
|
||||
package operand
|
||||
|
||||
import "github.com/mmcloughlin/avo/reg"
|
||||
|
||||
// Pure type assertion checks:
|
||||
|
||||
// IsRegister returns whether op has type reg.Register.
|
||||
func IsRegister(op Op) bool { _, ok := op.(reg.Register); return ok }
|
||||
|
||||
// IsMem returns whether op has type Mem.
|
||||
func IsMem(op Op) bool { _, ok := op.(Mem); return ok }
|
||||
|
||||
// IsRel returns whether op has type Rel.
|
||||
func IsRel(op Op) bool { _, ok := op.(Rel); return ok }
|
||||
|
||||
// Checks corresponding to specific operand types in the Intel Manual:
|
||||
|
||||
// Is1 returns true if op is the immediate constant 1.
|
||||
func Is1(op Op) bool {
|
||||
i, ok := op.(U8)
|
||||
return ok && i == 1
|
||||
}
|
||||
|
||||
// Is3 returns true if op is the immediate constant 3.
|
||||
func Is3(op Op) bool {
|
||||
i, ok := op.(U8)
|
||||
return ok && i == 3
|
||||
}
|
||||
|
||||
// IsIMM2U returns true if op is a 2-bit unsigned immediate (less than 4).
|
||||
func IsIMM2U(op Op) bool {
|
||||
i, ok := op.(U8)
|
||||
return ok && i < 4
|
||||
}
|
||||
|
||||
// IsIMM8 returns true is op is an 8-bit immediate.
|
||||
func IsIMM8(op Op) bool {
|
||||
_, uok := op.(U8)
|
||||
_, iok := op.(I8)
|
||||
return uok || iok
|
||||
}
|
||||
|
||||
// IsIMM16 returns true is op is a 16-bit immediate.
|
||||
func IsIMM16(op Op) bool {
|
||||
_, uok := op.(U16)
|
||||
_, iok := op.(I16)
|
||||
return uok || iok
|
||||
}
|
||||
|
||||
// IsIMM32 returns true is op is a 32-bit immediate.
|
||||
func IsIMM32(op Op) bool {
|
||||
_, uok := op.(U32)
|
||||
_, iok := op.(I32)
|
||||
return uok || iok
|
||||
}
|
||||
|
||||
// IsIMM64 returns true is op is a 64-bit immediate.
|
||||
func IsIMM64(op Op) bool {
|
||||
_, uok := op.(U64)
|
||||
_, iok := op.(I64)
|
||||
return uok || iok
|
||||
}
|
||||
|
||||
// IsAL returns true if op is the AL register.
|
||||
func IsAL(op Op) bool {
|
||||
return op == reg.AL
|
||||
}
|
||||
|
||||
// IsCL returns true if op is the CL register.
|
||||
func IsCL(op Op) bool {
|
||||
return op == reg.CL
|
||||
}
|
||||
|
||||
// IsAX returns true if op is the 16-bit AX register.
|
||||
func IsAX(op Op) bool {
|
||||
return op == reg.AX
|
||||
}
|
||||
|
||||
// IsEAX returns true if op is the 32-bit EAX register.
|
||||
func IsEAX(op Op) bool {
|
||||
return op == reg.EAX
|
||||
}
|
||||
|
||||
// IsRAX returns true if op is the 64-bit RAX register.
|
||||
func IsRAX(op Op) bool {
|
||||
return op == reg.RAX
|
||||
}
|
||||
|
||||
// IsR8 returns true if op is an 8-bit general-purpose register.
|
||||
func IsR8(op Op) bool {
|
||||
return IsGP(op, 1)
|
||||
}
|
||||
|
||||
// IsR16 returns true if op is a 16-bit general-purpose register.
|
||||
func IsR16(op Op) bool {
|
||||
return IsGP(op, 2)
|
||||
}
|
||||
|
||||
// IsR32 returns true if op is a 32-bit general-purpose register.
|
||||
func IsR32(op Op) bool {
|
||||
return IsGP(op, 4)
|
||||
}
|
||||
|
||||
// IsR64 returns true if op is a 64-bit general-purpose register.
|
||||
func IsR64(op Op) bool {
|
||||
return IsGP(op, 8)
|
||||
}
|
||||
|
||||
// IsPseudo returns true if op is a pseudo register.
|
||||
func IsPseudo(op Op) bool {
|
||||
return IsRegisterKind(op, reg.KindPseudo)
|
||||
}
|
||||
|
||||
// IsGP returns true if op is a general-purpose register of size n bytes.
|
||||
func IsGP(op Op, n uint) bool {
|
||||
return IsRegisterKindSize(op, reg.KindGP, n)
|
||||
}
|
||||
|
||||
// IsXMM0 returns true if op is the X0 register.
|
||||
func IsXMM0(op Op) bool {
|
||||
return op == reg.X0
|
||||
}
|
||||
|
||||
// IsXMM returns true if op is a 128-bit XMM register.
|
||||
func IsXMM(op Op) bool {
|
||||
return IsRegisterKindSize(op, reg.KindVector, 16)
|
||||
}
|
||||
|
||||
// IsYMM returns true if op is a 256-bit YMM register.
|
||||
func IsYMM(op Op) bool {
|
||||
return IsRegisterKindSize(op, reg.KindVector, 32)
|
||||
}
|
||||
|
||||
// IsZMM returns true if op is a 512-bit ZMM register.
|
||||
func IsZMM(op Op) bool {
|
||||
return IsRegisterKindSize(op, reg.KindVector, 64)
|
||||
}
|
||||
|
||||
// IsK returns true if op is an Opmask register.
|
||||
func IsK(op Op) bool {
|
||||
return IsRegisterKind(op, reg.KindOpmask)
|
||||
}
|
||||
|
||||
// IsRegisterKindSize returns true if op is a register of the given kind and size in bytes.
|
||||
func IsRegisterKindSize(op Op, k reg.Kind, n uint) bool {
|
||||
r, ok := op.(reg.Register)
|
||||
return ok && r.Kind() == k && r.Size() == n
|
||||
}
|
||||
|
||||
// IsRegisterKind returns true if op is a register of the given kind.
|
||||
func IsRegisterKind(op Op, k reg.Kind) bool {
|
||||
r, ok := op.(reg.Register)
|
||||
return ok && r.Kind() == k
|
||||
}
|
||||
|
||||
// IsM returns true if op is a 16-, 32- or 64-bit memory operand.
|
||||
func IsM(op Op) bool {
|
||||
// TODO(mbm): confirm "m" check is defined correctly
|
||||
// Intel manual: "A 16-, 32- or 64-bit operand in memory."
|
||||
return IsM16(op) || IsM32(op) || IsM64(op)
|
||||
}
|
||||
|
||||
// IsM8 returns true if op is an 8-bit memory operand.
|
||||
func IsM8(op Op) bool {
|
||||
// TODO(mbm): confirm "m8" check is defined correctly
|
||||
// Intel manual: "A byte operand in memory, usually expressed as a variable or
|
||||
// array name, but pointed to by the DS:(E)SI or ES:(E)DI registers. In 64-bit
|
||||
// mode, it is pointed to by the RSI or RDI registers."
|
||||
return IsMSize(op, 1)
|
||||
}
|
||||
|
||||
// IsM16 returns true if op is a 16-bit memory operand.
|
||||
func IsM16(op Op) bool {
|
||||
return IsMSize(op, 2)
|
||||
}
|
||||
|
||||
// IsM32 returns true if op is a 16-bit memory operand.
|
||||
func IsM32(op Op) bool {
|
||||
return IsMSize(op, 4)
|
||||
}
|
||||
|
||||
// IsM64 returns true if op is a 64-bit memory operand.
|
||||
func IsM64(op Op) bool {
|
||||
return IsMSize(op, 8)
|
||||
}
|
||||
|
||||
// IsMSize returns true if op is a memory operand using general-purpose address
|
||||
// registers of the given size in bytes.
|
||||
func IsMSize(op Op, n uint) bool {
|
||||
// TODO(mbm): should memory operands have a size attribute as well?
|
||||
// TODO(mbm): m8,m16,m32,m64 checks do not actually check size
|
||||
m, ok := op.(Mem)
|
||||
return ok && IsMReg(m.Base) && (m.Index == nil || IsMReg(m.Index))
|
||||
}
|
||||
|
||||
// IsMReg returns true if op is a register that can be used in a memory operand.
|
||||
func IsMReg(op Op) bool {
|
||||
return IsPseudo(op) || IsRegisterKind(op, reg.KindGP)
|
||||
}
|
||||
|
||||
// IsM128 returns true if op is a 128-bit memory operand.
|
||||
func IsM128(op Op) bool {
|
||||
// TODO(mbm): should "m128" be the same as "m64"?
|
||||
return IsM64(op)
|
||||
}
|
||||
|
||||
// IsM256 returns true if op is a 256-bit memory operand.
|
||||
func IsM256(op Op) bool {
|
||||
// TODO(mbm): should "m256" be the same as "m64"?
|
||||
return IsM64(op)
|
||||
}
|
||||
|
||||
// IsM512 returns true if op is a 512-bit memory operand.
|
||||
func IsM512(op Op) bool {
|
||||
// TODO(mbm): should "m512" be the same as "m64"?
|
||||
return IsM64(op)
|
||||
}
|
||||
|
||||
// IsVM32X returns true if op is a vector memory operand with 32-bit XMM index.
|
||||
func IsVM32X(op Op) bool {
|
||||
return IsVmx(op)
|
||||
}
|
||||
|
||||
// IsVM64X returns true if op is a vector memory operand with 64-bit XMM index.
|
||||
func IsVM64X(op Op) bool {
|
||||
return IsVmx(op)
|
||||
}
|
||||
|
||||
// IsVmx returns true if op is a vector memory operand with XMM index.
|
||||
func IsVmx(op Op) bool {
|
||||
return isvm(op, IsXMM)
|
||||
}
|
||||
|
||||
// IsVM32Y returns true if op is a vector memory operand with 32-bit YMM index.
|
||||
func IsVM32Y(op Op) bool {
|
||||
return IsVmy(op)
|
||||
}
|
||||
|
||||
// IsVM64Y returns true if op is a vector memory operand with 64-bit YMM index.
|
||||
func IsVM64Y(op Op) bool {
|
||||
return IsVmy(op)
|
||||
}
|
||||
|
||||
// IsVmy returns true if op is a vector memory operand with YMM index.
|
||||
func IsVmy(op Op) bool {
|
||||
return isvm(op, IsYMM)
|
||||
}
|
||||
|
||||
// IsVM32Z returns true if op is a vector memory operand with 32-bit ZMM index.
|
||||
func IsVM32Z(op Op) bool {
|
||||
return IsVmz(op)
|
||||
}
|
||||
|
||||
// IsVM64Z returns true if op is a vector memory operand with 64-bit ZMM index.
|
||||
func IsVM64Z(op Op) bool {
|
||||
return IsVmz(op)
|
||||
}
|
||||
|
||||
// IsVmz returns true if op is a vector memory operand with ZMM index.
|
||||
func IsVmz(op Op) bool {
|
||||
return isvm(op, IsZMM)
|
||||
}
|
||||
|
||||
func isvm(op Op, idx func(Op) bool) bool {
|
||||
m, ok := op.(Mem)
|
||||
return ok && IsR64(m.Base) && idx(m.Index)
|
||||
}
|
||||
|
||||
// IsREL8 returns true if op is an 8-bit offset relative to instruction pointer.
|
||||
func IsREL8(op Op) bool {
|
||||
r, ok := op.(Rel)
|
||||
return ok && r == Rel(int8(r))
|
||||
}
|
||||
|
||||
// IsREL32 returns true if op is an offset relative to instruction pointer, or a
|
||||
// label reference.
|
||||
func IsREL32(op Op) bool {
|
||||
// TODO(mbm): should labels be considered separately?
|
||||
_, rel := op.(Rel)
|
||||
_, label := op.(LabelRef)
|
||||
return rel || label
|
||||
}
|
64
vendor/github.com/mmcloughlin/avo/operand/const.go
generated
vendored
Normal file
64
vendor/github.com/mmcloughlin/avo/operand/const.go
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
package operand
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Constant represents a constant literal.
|
||||
type Constant interface {
|
||||
Op
|
||||
Bytes() int
|
||||
constant()
|
||||
}
|
||||
|
||||
//go:generate go run make_const.go -output zconst.go
|
||||
|
||||
// Special cases for floating point string representation.
|
||||
//
|
||||
// Issue 387 pointed out that floating point values that happen to be integers
|
||||
// need to have a decimal point to be parsed correctly.
|
||||
|
||||
// String returns a representation the 32-bit float which is guaranteed to be
|
||||
// parsed as a floating point constant by the Go assembler.
|
||||
func (f F32) String() string { return asmfloat(float64(f), 32) }
|
||||
|
||||
// String returns a representation the 64-bit float which is guaranteed to be
|
||||
// parsed as a floating point constant by the Go assembler.
|
||||
func (f F64) String() string { return asmfloat(float64(f), 64) }
|
||||
|
||||
// asmfloat represents x as a string such that the assembler scanner will always
|
||||
// recognize it as a float. Specifically, ensure that when x is an integral
|
||||
// value, the result will still have a decimal point.
|
||||
func asmfloat(x float64, bits int) string {
|
||||
s := strconv.FormatFloat(x, 'f', -1, bits)
|
||||
if !strings.ContainsRune(s, '.') {
|
||||
s += ".0"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// String is a string constant.
|
||||
type String string
|
||||
|
||||
// Asm returns an assembly syntax representation of the string s.
|
||||
func (s String) Asm() string { return fmt.Sprintf("$%q", s) }
|
||||
|
||||
// Bytes returns the length of s.
|
||||
func (s String) Bytes() int { return len(s) }
|
||||
|
||||
func (s String) constant() {}
|
||||
|
||||
// Imm returns an unsigned integer constant with size guessed from x.
|
||||
func Imm(x uint64) Constant {
|
||||
switch {
|
||||
case uint64(uint8(x)) == x:
|
||||
return U8(x)
|
||||
case uint64(uint16(x)) == x:
|
||||
return U16(x)
|
||||
case uint64(uint32(x)) == x:
|
||||
return U32(x)
|
||||
}
|
||||
return U64(x)
|
||||
}
|
2
vendor/github.com/mmcloughlin/avo/operand/doc.go
generated
vendored
Normal file
2
vendor/github.com/mmcloughlin/avo/operand/doc.go
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
// Package operand provides types for instruction operands.
|
||||
package operand
|
151
vendor/github.com/mmcloughlin/avo/operand/types.go
generated
vendored
Normal file
151
vendor/github.com/mmcloughlin/avo/operand/types.go
generated
vendored
Normal file
@ -0,0 +1,151 @@
|
||||
package operand
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/mmcloughlin/avo/reg"
|
||||
)
|
||||
|
||||
// Op is an operand.
|
||||
type Op interface {
|
||||
Asm() string
|
||||
}
|
||||
|
||||
// Symbol represents a symbol name.
|
||||
type Symbol struct {
|
||||
Name string
|
||||
Static bool // only visible in current source file
|
||||
}
|
||||
|
||||
// NewStaticSymbol builds a static Symbol. Static symbols are only visible in the current source file.
|
||||
func NewStaticSymbol(name string) Symbol {
|
||||
return Symbol{Name: name, Static: true}
|
||||
}
|
||||
|
||||
func (s Symbol) String() string {
|
||||
n := s.Name
|
||||
if s.Static {
|
||||
n += "<>"
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// Mem represents a memory reference.
|
||||
type Mem struct {
|
||||
Symbol Symbol
|
||||
Disp int
|
||||
Base reg.Register
|
||||
Index reg.Register
|
||||
Scale uint8
|
||||
}
|
||||
|
||||
// NewParamAddr is a convenience to build a Mem operand pointing to a function
|
||||
// parameter, which is a named offset from the frame pointer pseudo register.
|
||||
func NewParamAddr(name string, offset int) Mem {
|
||||
return Mem{
|
||||
Symbol: Symbol{
|
||||
Name: name,
|
||||
Static: false,
|
||||
},
|
||||
Disp: offset,
|
||||
Base: reg.FramePointer,
|
||||
}
|
||||
}
|
||||
|
||||
// NewStackAddr returns a memory reference relative to the stack pointer.
|
||||
func NewStackAddr(offset int) Mem {
|
||||
return Mem{
|
||||
Disp: offset,
|
||||
Base: reg.StackPointer,
|
||||
}
|
||||
}
|
||||
|
||||
// NewDataAddr returns a memory reference relative to the named data symbol.
|
||||
func NewDataAddr(sym Symbol, offset int) Mem {
|
||||
return Mem{
|
||||
Symbol: sym,
|
||||
Disp: offset,
|
||||
Base: reg.StaticBase,
|
||||
}
|
||||
}
|
||||
|
||||
// Offset returns a reference to m plus idx bytes.
|
||||
func (m Mem) Offset(idx int) Mem {
|
||||
a := m
|
||||
a.Disp += idx
|
||||
return a
|
||||
}
|
||||
|
||||
// Idx returns a new memory reference with (Index, Scale) set to (r, s).
|
||||
func (m Mem) Idx(r reg.Register, s uint8) Mem {
|
||||
a := m
|
||||
a.Index = r
|
||||
a.Scale = s
|
||||
return a
|
||||
}
|
||||
|
||||
// Asm returns an assembly syntax representation of m.
|
||||
func (m Mem) Asm() string {
|
||||
a := m.Symbol.String()
|
||||
if a != "" {
|
||||
a += fmt.Sprintf("%+d", m.Disp)
|
||||
} else if m.Disp != 0 {
|
||||
a += fmt.Sprintf("%d", m.Disp)
|
||||
}
|
||||
if m.Base != nil {
|
||||
a += fmt.Sprintf("(%s)", m.Base.Asm())
|
||||
}
|
||||
if m.Index != nil && m.Scale != 0 {
|
||||
a += fmt.Sprintf("(%s*%d)", m.Index.Asm(), m.Scale)
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// Rel is an offset relative to the instruction pointer.
|
||||
type Rel int32
|
||||
|
||||
// Asm returns an assembly syntax representation of r.
|
||||
func (r Rel) Asm() string {
|
||||
return fmt.Sprintf(".%+d", r)
|
||||
}
|
||||
|
||||
// LabelRef is a reference to a label.
|
||||
type LabelRef string
|
||||
|
||||
// Asm returns an assembly syntax representation of l.
|
||||
func (l LabelRef) Asm() string {
|
||||
return string(l)
|
||||
}
|
||||
|
||||
// Registers returns the list of all operands involved in the given operand.
|
||||
func Registers(op Op) []reg.Register {
|
||||
switch op := op.(type) {
|
||||
case reg.Register:
|
||||
return []reg.Register{op}
|
||||
case Mem:
|
||||
var r []reg.Register
|
||||
if op.Base != nil {
|
||||
r = append(r, op.Base)
|
||||
}
|
||||
if op.Index != nil {
|
||||
r = append(r, op.Index)
|
||||
}
|
||||
return r
|
||||
case Constant, Rel, LabelRef:
|
||||
return nil
|
||||
}
|
||||
panic("unknown operand type")
|
||||
}
|
||||
|
||||
// ApplyAllocation returns an operand with allocated registers replaced. Registers missing from the allocation are left alone.
|
||||
func ApplyAllocation(op Op, a reg.Allocation) Op {
|
||||
switch op := op.(type) {
|
||||
case reg.Register:
|
||||
return a.LookupRegisterDefault(op)
|
||||
case Mem:
|
||||
op.Base = a.LookupRegisterDefault(op.Base)
|
||||
op.Index = a.LookupRegisterDefault(op.Index)
|
||||
return op
|
||||
}
|
||||
return op
|
||||
}
|
75
vendor/github.com/mmcloughlin/avo/operand/zconst.go
generated
vendored
Normal file
75
vendor/github.com/mmcloughlin/avo/operand/zconst.go
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
// Code generated by make_const.go. DO NOT EDIT.
|
||||
|
||||
package operand
|
||||
|
||||
import "fmt"
|
||||
|
||||
// I8 is a 8-bit signed integer constant.
|
||||
type I8 int8
|
||||
|
||||
func (i I8) Asm() string { return fmt.Sprintf("$%+d", i) }
|
||||
func (i I8) Bytes() int { return 1 }
|
||||
func (i I8) constant() {}
|
||||
|
||||
// U8 is a 8-bit unsigned integer constant.
|
||||
type U8 uint8
|
||||
|
||||
func (u U8) Asm() string { return fmt.Sprintf("$%#02x", u) }
|
||||
func (u U8) Bytes() int { return 1 }
|
||||
func (u U8) constant() {}
|
||||
|
||||
// I16 is a 16-bit signed integer constant.
|
||||
type I16 int16
|
||||
|
||||
func (i I16) Asm() string { return fmt.Sprintf("$%+d", i) }
|
||||
func (i I16) Bytes() int { return 2 }
|
||||
func (i I16) constant() {}
|
||||
|
||||
// U16 is a 16-bit unsigned integer constant.
|
||||
type U16 uint16
|
||||
|
||||
func (u U16) Asm() string { return fmt.Sprintf("$%#04x", u) }
|
||||
func (u U16) Bytes() int { return 2 }
|
||||
func (u U16) constant() {}
|
||||
|
||||
// F32 is a 32-bit floating point constant.
|
||||
type F32 float32
|
||||
|
||||
func (f F32) Asm() string { return fmt.Sprintf("$(%s)", f) }
|
||||
func (f F32) Bytes() int { return 4 }
|
||||
func (f F32) constant() {}
|
||||
|
||||
// I32 is a 32-bit signed integer constant.
|
||||
type I32 int32
|
||||
|
||||
func (i I32) Asm() string { return fmt.Sprintf("$%+d", i) }
|
||||
func (i I32) Bytes() int { return 4 }
|
||||
func (i I32) constant() {}
|
||||
|
||||
// U32 is a 32-bit unsigned integer constant.
|
||||
type U32 uint32
|
||||
|
||||
func (u U32) Asm() string { return fmt.Sprintf("$%#08x", u) }
|
||||
func (u U32) Bytes() int { return 4 }
|
||||
func (u U32) constant() {}
|
||||
|
||||
// F64 is a 64-bit floating point constant.
|
||||
type F64 float64
|
||||
|
||||
func (f F64) Asm() string { return fmt.Sprintf("$(%s)", f) }
|
||||
func (f F64) Bytes() int { return 8 }
|
||||
func (f F64) constant() {}
|
||||
|
||||
// I64 is a 64-bit signed integer constant.
|
||||
type I64 int64
|
||||
|
||||
func (i I64) Asm() string { return fmt.Sprintf("$%+d", i) }
|
||||
func (i I64) Bytes() int { return 8 }
|
||||
func (i I64) constant() {}
|
||||
|
||||
// U64 is a 64-bit unsigned integer constant.
|
||||
type U64 uint64
|
||||
|
||||
func (u U64) Asm() string { return fmt.Sprintf("$%#016x", u) }
|
||||
func (u U64) Bytes() int { return 8 }
|
||||
func (u U64) constant() {}
|
213
vendor/github.com/mmcloughlin/avo/pass/alloc.go
generated
vendored
Normal file
213
vendor/github.com/mmcloughlin/avo/pass/alloc.go
generated
vendored
Normal file
@ -0,0 +1,213 @@
|
||||
package pass
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math"
|
||||
"sort"
|
||||
|
||||
"github.com/mmcloughlin/avo/reg"
|
||||
)
|
||||
|
||||
// edge is an edge of the interference graph, indicating that registers X and Y
|
||||
// must be in non-conflicting registers.
|
||||
type edge struct {
|
||||
X, Y reg.ID
|
||||
}
|
||||
|
||||
// Allocator is a graph-coloring register allocator.
|
||||
type Allocator struct {
|
||||
registers []reg.ID
|
||||
priority map[reg.ID]int
|
||||
allocation reg.Allocation
|
||||
edges []*edge
|
||||
possible map[reg.ID][]reg.ID
|
||||
}
|
||||
|
||||
// NewAllocator builds an allocator for the given physical registers.
|
||||
func NewAllocator(rs []reg.Physical) (*Allocator, error) {
|
||||
// Set of IDs, excluding restricted registers.
|
||||
idset := map[reg.ID]bool{}
|
||||
for _, r := range rs {
|
||||
if (r.Info() & reg.Restricted) != 0 {
|
||||
continue
|
||||
}
|
||||
idset[r.ID()] = true
|
||||
}
|
||||
|
||||
if len(idset) == 0 {
|
||||
return nil, errors.New("no allocatable registers")
|
||||
}
|
||||
|
||||
// Produce slice of unique register IDs.
|
||||
var ids []reg.ID
|
||||
for id := range idset {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
|
||||
a := &Allocator{
|
||||
registers: ids,
|
||||
priority: map[reg.ID]int{},
|
||||
allocation: reg.NewEmptyAllocation(),
|
||||
possible: map[reg.ID][]reg.ID{},
|
||||
}
|
||||
a.sortregisters()
|
||||
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// NewAllocatorForKind builds an allocator for the given kind of registers.
|
||||
func NewAllocatorForKind(k reg.Kind) (*Allocator, error) {
|
||||
f := reg.FamilyOfKind(k)
|
||||
if f == nil {
|
||||
return nil, errors.New("unknown register family")
|
||||
}
|
||||
return NewAllocator(f.Registers())
|
||||
}
|
||||
|
||||
// SetPriority sets the priority of the given regiser to p. Higher priority
|
||||
// registers are preferred in allocations. By default all registers have 0
|
||||
// priority. Priority will only apply to subsequent Add() calls, therefore
|
||||
// typically all SetPriority calls should happen at allocator initialization.
|
||||
func (a *Allocator) SetPriority(id reg.ID, p int) {
|
||||
a.priority[id] = p
|
||||
a.sortregisters()
|
||||
}
|
||||
|
||||
// sortregisters sorts the list of available registers: higher priority first,
|
||||
// falling back to sorting by ID.
|
||||
func (a *Allocator) sortregisters() {
|
||||
sort.Slice(a.registers, func(i, j int) bool {
|
||||
ri, rj := a.registers[i], a.registers[j]
|
||||
pi, pj := a.priority[ri], a.priority[rj]
|
||||
return (pi > pj) || (pi == pj && ri < rj)
|
||||
})
|
||||
}
|
||||
|
||||
// AddInterferenceSet records that r interferes with every register in s. Convenience wrapper around AddInterference.
|
||||
func (a *Allocator) AddInterferenceSet(r reg.Register, s reg.MaskSet) {
|
||||
for id, mask := range s {
|
||||
if (r.Mask() & mask) != 0 {
|
||||
a.AddInterference(r.ID(), id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AddInterference records that x and y must be assigned to non-conflicting physical registers.
|
||||
func (a *Allocator) AddInterference(x, y reg.ID) {
|
||||
a.Add(x)
|
||||
a.Add(y)
|
||||
a.edges = append(a.edges, &edge{X: x, Y: y})
|
||||
}
|
||||
|
||||
// Add adds a register to be allocated. Does nothing if the register has already been added.
|
||||
func (a *Allocator) Add(v reg.ID) {
|
||||
if !v.IsVirtual() {
|
||||
return
|
||||
}
|
||||
if _, found := a.possible[v]; found {
|
||||
return
|
||||
}
|
||||
a.possible[v] = a.possibleregisters(v)
|
||||
}
|
||||
|
||||
// Allocate allocates physical registers.
|
||||
func (a *Allocator) Allocate() (reg.Allocation, error) {
|
||||
for {
|
||||
if err := a.update(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if a.remaining() == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
v := a.mostrestricted()
|
||||
if err := a.alloc(v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return a.allocation, nil
|
||||
}
|
||||
|
||||
// update possible allocations based on edges.
|
||||
func (a *Allocator) update() error {
|
||||
var rem []*edge
|
||||
for _, e := range a.edges {
|
||||
x := a.allocation.LookupDefault(e.X)
|
||||
y := a.allocation.LookupDefault(e.Y)
|
||||
switch {
|
||||
case x.IsVirtual() && y.IsVirtual():
|
||||
rem = append(rem, e)
|
||||
continue
|
||||
case x.IsPhysical() && y.IsPhysical():
|
||||
if x == y {
|
||||
return errors.New("impossible register allocation")
|
||||
}
|
||||
case x.IsPhysical() && y.IsVirtual():
|
||||
a.discardconflicting(y, x)
|
||||
case x.IsVirtual() && y.IsPhysical():
|
||||
a.discardconflicting(x, y)
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
||||
a.edges = rem
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// mostrestricted returns the virtual register with the least possibilities.
|
||||
func (a *Allocator) mostrestricted() reg.ID {
|
||||
n := int(math.MaxInt32)
|
||||
var v reg.ID
|
||||
for w, p := range a.possible {
|
||||
// On a tie, choose the smallest ID in numeric order. This avoids
|
||||
// non-deterministic allocations due to map iteration order.
|
||||
if len(p) < n || (len(p) == n && w < v) {
|
||||
n = len(p)
|
||||
v = w
|
||||
}
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// discardconflicting removes registers from vs possible list that conflict with p.
|
||||
func (a *Allocator) discardconflicting(v, p reg.ID) {
|
||||
a.possible[v] = filterregisters(a.possible[v], func(r reg.ID) bool {
|
||||
return r != p
|
||||
})
|
||||
}
|
||||
|
||||
// alloc attempts to allocate a register to v.
|
||||
func (a *Allocator) alloc(v reg.ID) error {
|
||||
ps := a.possible[v]
|
||||
if len(ps) == 0 {
|
||||
return errors.New("failed to allocate registers")
|
||||
}
|
||||
p := ps[0]
|
||||
a.allocation[v] = p
|
||||
delete(a.possible, v)
|
||||
return nil
|
||||
}
|
||||
|
||||
// remaining returns the number of unallocated registers.
|
||||
func (a *Allocator) remaining() int {
|
||||
return len(a.possible)
|
||||
}
|
||||
|
||||
// possibleregisters returns all allocate-able registers for the given virtual.
|
||||
func (a *Allocator) possibleregisters(v reg.ID) []reg.ID {
|
||||
return filterregisters(a.registers, func(r reg.ID) bool {
|
||||
return v.Kind() == r.Kind()
|
||||
})
|
||||
}
|
||||
|
||||
func filterregisters(in []reg.ID, predicate func(reg.ID) bool) []reg.ID {
|
||||
var rs []reg.ID
|
||||
for _, r := range in {
|
||||
if predicate(r) {
|
||||
rs = append(rs, r)
|
||||
}
|
||||
}
|
||||
return rs
|
||||
}
|
81
vendor/github.com/mmcloughlin/avo/pass/cfg.go
generated
vendored
Normal file
81
vendor/github.com/mmcloughlin/avo/pass/cfg.go
generated
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
package pass
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/mmcloughlin/avo/ir"
|
||||
)
|
||||
|
||||
// LabelTarget populates the LabelTarget of the given function. This maps from
|
||||
// label name to the following instruction.
|
||||
func LabelTarget(fn *ir.Function) error {
|
||||
target := map[ir.Label]*ir.Instruction{}
|
||||
var pending []ir.Label
|
||||
for _, node := range fn.Nodes {
|
||||
switch n := node.(type) {
|
||||
case ir.Label:
|
||||
if _, found := target[n]; found {
|
||||
return fmt.Errorf("duplicate label \"%s\"", n)
|
||||
}
|
||||
pending = append(pending, n)
|
||||
case *ir.Instruction:
|
||||
for _, label := range pending {
|
||||
target[label] = n
|
||||
}
|
||||
pending = nil
|
||||
}
|
||||
}
|
||||
if len(pending) != 0 {
|
||||
return errors.New("function ends with label")
|
||||
}
|
||||
fn.LabelTarget = target
|
||||
return nil
|
||||
}
|
||||
|
||||
// CFG constructs the call-flow-graph for the function.
|
||||
func CFG(fn *ir.Function) error {
|
||||
is := fn.Instructions()
|
||||
n := len(is)
|
||||
|
||||
// Populate successors.
|
||||
for i := 0; i < n; i++ {
|
||||
cur := is[i]
|
||||
var nxt *ir.Instruction
|
||||
if i+1 < n {
|
||||
nxt = is[i+1]
|
||||
}
|
||||
|
||||
// If it's a branch, locate the target.
|
||||
if cur.IsBranch {
|
||||
lbl := cur.TargetLabel()
|
||||
if lbl == nil {
|
||||
return errors.New("no label for branch instruction")
|
||||
}
|
||||
target, found := fn.LabelTarget[*lbl]
|
||||
if !found {
|
||||
return fmt.Errorf("unknown label %q", *lbl)
|
||||
}
|
||||
cur.Succ = append(cur.Succ, target)
|
||||
}
|
||||
|
||||
// Otherwise, could continue to the following instruction.
|
||||
switch {
|
||||
case cur.IsTerminal:
|
||||
case cur.IsUnconditionalBranch():
|
||||
default:
|
||||
cur.Succ = append(cur.Succ, nxt)
|
||||
}
|
||||
}
|
||||
|
||||
// Populate predecessors.
|
||||
for _, i := range is {
|
||||
for _, s := range i.Succ {
|
||||
if s != nil {
|
||||
s.Pred = append(s.Pred, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
123
vendor/github.com/mmcloughlin/avo/pass/cleanup.go
generated
vendored
Normal file
123
vendor/github.com/mmcloughlin/avo/pass/cleanup.go
generated
vendored
Normal file
@ -0,0 +1,123 @@
|
||||
package pass
|
||||
|
||||
import (
|
||||
"github.com/mmcloughlin/avo/ir"
|
||||
"github.com/mmcloughlin/avo/operand"
|
||||
)
|
||||
|
||||
// PruneJumpToFollowingLabel removes jump instructions that target an
|
||||
// immediately following label.
|
||||
func PruneJumpToFollowingLabel(fn *ir.Function) error {
|
||||
for i := 0; i+1 < len(fn.Nodes); i++ {
|
||||
node := fn.Nodes[i]
|
||||
next := fn.Nodes[i+1]
|
||||
|
||||
// This node is an unconditional jump.
|
||||
inst, ok := node.(*ir.Instruction)
|
||||
if !ok || !inst.IsBranch || inst.IsConditional {
|
||||
continue
|
||||
}
|
||||
|
||||
target := inst.TargetLabel()
|
||||
if target == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// And the jump target is the immediately following node.
|
||||
lbl, ok := next.(ir.Label)
|
||||
if !ok || lbl != *target {
|
||||
continue
|
||||
}
|
||||
|
||||
// Then the jump is unnecessary and can be removed.
|
||||
fn.Nodes = deletenode(fn.Nodes, i)
|
||||
i--
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PruneDanglingLabels removes labels that are not referenced by any branches.
|
||||
func PruneDanglingLabels(fn *ir.Function) error {
|
||||
// Count label references.
|
||||
count := map[ir.Label]int{}
|
||||
for _, n := range fn.Nodes {
|
||||
i, ok := n.(*ir.Instruction)
|
||||
if !ok || !i.IsBranch {
|
||||
continue
|
||||
}
|
||||
|
||||
target := i.TargetLabel()
|
||||
if target == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
count[*target]++
|
||||
}
|
||||
|
||||
// Look for labels with no references.
|
||||
for i := 0; i < len(fn.Nodes); i++ {
|
||||
node := fn.Nodes[i]
|
||||
lbl, ok := node.(ir.Label)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if count[lbl] == 0 {
|
||||
fn.Nodes = deletenode(fn.Nodes, i)
|
||||
i--
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PruneSelfMoves removes move instructions from one register to itself.
|
||||
func PruneSelfMoves(fn *ir.Function) error {
|
||||
return removeinstructions(fn, func(i *ir.Instruction) bool {
|
||||
switch i.Opcode {
|
||||
case "MOVB", "MOVW", "MOVL", "MOVQ":
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
return operand.IsRegister(i.Operands[0]) && operand.IsRegister(i.Operands[1]) && i.Operands[0] == i.Operands[1]
|
||||
})
|
||||
}
|
||||
|
||||
// removeinstructions deletes instructions from the given function which match predicate.
|
||||
func removeinstructions(fn *ir.Function, predicate func(*ir.Instruction) bool) error {
|
||||
// Removal of instructions has the potential to invalidate CFG structures.
|
||||
// Clear them to prevent accidental use of stale structures after this pass.
|
||||
invalidatecfg(fn)
|
||||
|
||||
for i := 0; i < len(fn.Nodes); i++ {
|
||||
n := fn.Nodes[i]
|
||||
|
||||
inst, ok := n.(*ir.Instruction)
|
||||
if !ok || !predicate(inst) {
|
||||
continue
|
||||
}
|
||||
|
||||
fn.Nodes = deletenode(fn.Nodes, i)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// deletenode deletes node i from nodes and returns the resulting slice.
|
||||
func deletenode(nodes []ir.Node, i int) []ir.Node {
|
||||
n := len(nodes)
|
||||
copy(nodes[i:], nodes[i+1:])
|
||||
nodes[n-1] = nil
|
||||
return nodes[:n-1]
|
||||
}
|
||||
|
||||
// invalidatecfg clears CFG structures.
|
||||
func invalidatecfg(fn *ir.Function) {
|
||||
fn.LabelTarget = nil
|
||||
for _, i := range fn.Instructions() {
|
||||
i.Pred = nil
|
||||
i.Succ = nil
|
||||
}
|
||||
}
|
31
vendor/github.com/mmcloughlin/avo/pass/isa.go
generated
vendored
Normal file
31
vendor/github.com/mmcloughlin/avo/pass/isa.go
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
package pass
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/mmcloughlin/avo/ir"
|
||||
)
|
||||
|
||||
// RequiredISAExtensions determines ISA extensions required for the given
|
||||
// function. Populates the ISA field.
|
||||
func RequiredISAExtensions(fn *ir.Function) error {
|
||||
// Collect ISA set.
|
||||
set := map[string]bool{}
|
||||
for _, i := range fn.Instructions() {
|
||||
for _, isa := range i.ISA {
|
||||
set[isa] = true
|
||||
}
|
||||
}
|
||||
|
||||
if len(set) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Populate the function's ISA field with the unique sorted list.
|
||||
for isa := range set {
|
||||
fn.ISA = append(fn.ISA, isa)
|
||||
}
|
||||
sort.Strings(fn.ISA)
|
||||
|
||||
return nil
|
||||
}
|
101
vendor/github.com/mmcloughlin/avo/pass/pass.go
generated
vendored
Normal file
101
vendor/github.com/mmcloughlin/avo/pass/pass.go
generated
vendored
Normal file
@ -0,0 +1,101 @@
|
||||
// Package pass implements processing passes on avo Files.
|
||||
package pass
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/mmcloughlin/avo/ir"
|
||||
"github.com/mmcloughlin/avo/printer"
|
||||
)
|
||||
|
||||
// Compile pass compiles an avo file. Upon successful completion the avo file
|
||||
// may be printed to Go assembly.
|
||||
var Compile = Concat(
|
||||
Verify,
|
||||
FunctionPass(PruneJumpToFollowingLabel),
|
||||
FunctionPass(PruneDanglingLabels),
|
||||
FunctionPass(LabelTarget),
|
||||
FunctionPass(CFG),
|
||||
InstructionPass(ZeroExtend32BitOutputs),
|
||||
FunctionPass(Liveness),
|
||||
FunctionPass(AllocateRegisters),
|
||||
FunctionPass(BindRegisters),
|
||||
FunctionPass(VerifyAllocation),
|
||||
FunctionPass(EnsureBasePointerCalleeSaved),
|
||||
Func(IncludeTextFlagHeader),
|
||||
FunctionPass(PruneSelfMoves),
|
||||
FunctionPass(RequiredISAExtensions),
|
||||
)
|
||||
|
||||
// Interface for a processing pass.
|
||||
type Interface interface {
|
||||
Execute(*ir.File) error
|
||||
}
|
||||
|
||||
// Func adapts a function to the pass Interface.
|
||||
type Func func(*ir.File) error
|
||||
|
||||
// Execute calls p.
|
||||
func (p Func) Execute(f *ir.File) error {
|
||||
return p(f)
|
||||
}
|
||||
|
||||
// FunctionPass is a convenience for implementing a full file pass with a
|
||||
// function that operates on each avo Function independently.
|
||||
type FunctionPass func(*ir.Function) error
|
||||
|
||||
// Execute calls p on every function in the file. Exits on the first error.
|
||||
func (p FunctionPass) Execute(f *ir.File) error {
|
||||
for _, fn := range f.Functions() {
|
||||
if err := p(fn); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// InstructionPass is a convenience for implementing a full file pass with a
|
||||
// function that operates on each Instruction independently.
|
||||
type InstructionPass func(*ir.Instruction) error
|
||||
|
||||
// Execute calls p on every instruction in the file. Exits on the first error.
|
||||
func (p InstructionPass) Execute(f *ir.File) error {
|
||||
for _, fn := range f.Functions() {
|
||||
for _, i := range fn.Instructions() {
|
||||
if err := p(i); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Concat returns a pass that executes the given passes in order, stopping on the first error.
|
||||
func Concat(passes ...Interface) Interface {
|
||||
return Func(func(f *ir.File) error {
|
||||
for _, p := range passes {
|
||||
if err := p.Execute(f); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Output pass prints a file.
|
||||
type Output struct {
|
||||
Writer io.WriteCloser
|
||||
Printer printer.Printer
|
||||
}
|
||||
|
||||
// Execute prints f with the configured Printer and writes output to Writer.
|
||||
func (o *Output) Execute(f *ir.File) error {
|
||||
b, err := o.Printer.Print(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = o.Writer.Write(b); err != nil {
|
||||
return err
|
||||
}
|
||||
return o.Writer.Close()
|
||||
}
|
223
vendor/github.com/mmcloughlin/avo/pass/reg.go
generated
vendored
Normal file
223
vendor/github.com/mmcloughlin/avo/pass/reg.go
generated
vendored
Normal file
@ -0,0 +1,223 @@
|
||||
package pass
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/mmcloughlin/avo/gotypes"
|
||||
"github.com/mmcloughlin/avo/ir"
|
||||
"github.com/mmcloughlin/avo/operand"
|
||||
"github.com/mmcloughlin/avo/reg"
|
||||
)
|
||||
|
||||
// ZeroExtend32BitOutputs applies the rule that "32-bit operands generate a
|
||||
// 32-bit result, zero-extended to a 64-bit result in the destination
|
||||
// general-purpose register" (Intel Software Developer’s Manual, Volume 1,
|
||||
// 3.4.1.1).
|
||||
func ZeroExtend32BitOutputs(i *ir.Instruction) error {
|
||||
for j, op := range i.Outputs {
|
||||
if !operand.IsR32(op) {
|
||||
continue
|
||||
}
|
||||
r, ok := op.(reg.GP)
|
||||
if !ok {
|
||||
panic("r32 operand should satisfy reg.GP")
|
||||
}
|
||||
i.Outputs[j] = r.As64()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Liveness computes register liveness.
|
||||
func Liveness(fn *ir.Function) error {
|
||||
// Note this implementation is initially naive so as to be "obviously correct".
|
||||
// There are a well-known optimizations we can apply if necessary.
|
||||
|
||||
is := fn.Instructions()
|
||||
|
||||
// Process instructions in reverse: poor approximation to topological sort.
|
||||
// TODO(mbm): process instructions in topological sort order
|
||||
for l, r := 0, len(is)-1; l < r; l, r = l+1, r-1 {
|
||||
is[l], is[r] = is[r], is[l]
|
||||
}
|
||||
|
||||
// Initialize.
|
||||
for _, i := range is {
|
||||
i.LiveIn = reg.NewMaskSetFromRegisters(i.InputRegisters())
|
||||
i.LiveOut = reg.NewEmptyMaskSet()
|
||||
}
|
||||
|
||||
// Iterative dataflow analysis.
|
||||
for {
|
||||
changes := false
|
||||
|
||||
for _, i := range is {
|
||||
// out[n] = UNION[s IN succ[n]] in[s]
|
||||
for _, s := range i.Succ {
|
||||
if s == nil {
|
||||
continue
|
||||
}
|
||||
changes = i.LiveOut.Update(s.LiveIn) || changes
|
||||
}
|
||||
|
||||
// in[n] = use[n] UNION (out[n] - def[n])
|
||||
def := reg.NewMaskSetFromRegisters(i.OutputRegisters())
|
||||
changes = i.LiveIn.Update(i.LiveOut.Difference(def)) || changes
|
||||
}
|
||||
|
||||
if !changes {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AllocateRegisters performs register allocation.
|
||||
func AllocateRegisters(fn *ir.Function) error {
|
||||
// Initialize one allocator per kind.
|
||||
as := map[reg.Kind]*Allocator{}
|
||||
for _, i := range fn.Instructions() {
|
||||
for _, r := range i.Registers() {
|
||||
k := r.Kind()
|
||||
if _, found := as[k]; !found {
|
||||
a, err := NewAllocatorForKind(k)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
as[k] = a
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// De-prioritize the base pointer register. This can be used as a general
|
||||
// purpose register, but it's callee-save so needs to be saved/restored if
|
||||
// it is clobbered. For this reason we prefer to avoid using it unless
|
||||
// forced to by register pressure.
|
||||
for k, a := range as {
|
||||
f := reg.FamilyOfKind(k)
|
||||
for _, r := range f.Registers() {
|
||||
if (r.Info() & reg.BasePointer) != 0 {
|
||||
// Negative priority penalizes this register relative to all
|
||||
// others (having default zero priority).
|
||||
a.SetPriority(r.ID(), -1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Populate registers to be allocated.
|
||||
for _, i := range fn.Instructions() {
|
||||
for _, r := range i.Registers() {
|
||||
as[r.Kind()].Add(r.ID())
|
||||
}
|
||||
}
|
||||
|
||||
// Record register interferences.
|
||||
for _, i := range fn.Instructions() {
|
||||
for _, d := range i.OutputRegisters() {
|
||||
k := d.Kind()
|
||||
out := i.LiveOut.OfKind(k)
|
||||
out.DiscardRegister(d)
|
||||
as[k].AddInterferenceSet(d, out)
|
||||
}
|
||||
}
|
||||
|
||||
// Execute register allocation.
|
||||
fn.Allocation = reg.NewEmptyAllocation()
|
||||
for _, a := range as {
|
||||
al, err := a.Allocate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fn.Allocation.Merge(al); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// BindRegisters applies the result of register allocation, replacing all virtual registers with their assigned physical registers.
|
||||
func BindRegisters(fn *ir.Function) error {
|
||||
for _, i := range fn.Instructions() {
|
||||
for idx := range i.Operands {
|
||||
i.Operands[idx] = operand.ApplyAllocation(i.Operands[idx], fn.Allocation)
|
||||
}
|
||||
for idx := range i.Inputs {
|
||||
i.Inputs[idx] = operand.ApplyAllocation(i.Inputs[idx], fn.Allocation)
|
||||
}
|
||||
for idx := range i.Outputs {
|
||||
i.Outputs[idx] = operand.ApplyAllocation(i.Outputs[idx], fn.Allocation)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// VerifyAllocation performs sanity checks following register allocation.
|
||||
func VerifyAllocation(fn *ir.Function) error {
|
||||
// All registers should be physical.
|
||||
for _, i := range fn.Instructions() {
|
||||
for _, r := range i.Registers() {
|
||||
if reg.ToPhysical(r) == nil {
|
||||
return errors.New("non physical register found")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EnsureBasePointerCalleeSaved ensures that the base pointer register will be
|
||||
// saved and restored if it has been clobbered by the function.
|
||||
func EnsureBasePointerCalleeSaved(fn *ir.Function) error {
|
||||
// Check to see if the base pointer is written to.
|
||||
clobbered := false
|
||||
for _, i := range fn.Instructions() {
|
||||
for _, r := range i.OutputRegisters() {
|
||||
if p := reg.ToPhysical(r); p != nil && (p.Info()®.BasePointer) != 0 {
|
||||
clobbered = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !clobbered {
|
||||
return nil
|
||||
}
|
||||
|
||||
// This function clobbers the base pointer register so we need to ensure it
|
||||
// will be saved and restored. The Go assembler will do this automatically,
|
||||
// with a few exceptions detailed below. In summary, we can usually ensure
|
||||
// this happens by ensuring the function is not frameless (apart from
|
||||
// NOFRAME functions).
|
||||
//
|
||||
// Reference: https://github.com/golang/go/blob/3f4977bd5800beca059defb5de4dc64cd758cbb9/src/cmd/internal/obj/x86/obj6.go#L591-L609
|
||||
//
|
||||
// var bpsize int
|
||||
// if ctxt.Arch.Family == sys.AMD64 &&
|
||||
// !p.From.Sym.NoFrame() && // (1) below
|
||||
// !(autoffset == 0 && p.From.Sym.NoSplit()) && // (2) below
|
||||
// !(autoffset == 0 && !hasCall) { // (3) below
|
||||
// // Make room to save a base pointer.
|
||||
// // There are 2 cases we must avoid:
|
||||
// // 1) If noframe is set (which we do for functions which tail call).
|
||||
// // 2) Scary runtime internals which would be all messed up by frame pointers.
|
||||
// // We detect these using a heuristic: frameless nosplit functions.
|
||||
// // TODO: Maybe someday we label them all with NOFRAME and get rid of this heuristic.
|
||||
// // For performance, we also want to avoid:
|
||||
// // 3) Frameless leaf functions
|
||||
// bpsize = ctxt.Arch.PtrSize
|
||||
// autoffset += int32(bpsize)
|
||||
// p.To.Offset += int64(bpsize)
|
||||
// } else {
|
||||
// bpsize = 0
|
||||
// }
|
||||
//
|
||||
if fn.Attributes.NOFRAME() {
|
||||
return errors.New("NOFRAME function clobbers base pointer register")
|
||||
}
|
||||
|
||||
if fn.LocalSize == 0 {
|
||||
fn.AllocLocal(int(gotypes.PointerSize))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
42
vendor/github.com/mmcloughlin/avo/pass/textflag.go
generated
vendored
Normal file
42
vendor/github.com/mmcloughlin/avo/pass/textflag.go
generated
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
package pass
|
||||
|
||||
import (
|
||||
"github.com/mmcloughlin/avo/attr"
|
||||
"github.com/mmcloughlin/avo/ir"
|
||||
)
|
||||
|
||||
// IncludeTextFlagHeader includes textflag.h if necessary.
|
||||
func IncludeTextFlagHeader(f *ir.File) error {
|
||||
const textflagheader = "textflag.h"
|
||||
|
||||
// Check if we already have it.
|
||||
for _, path := range f.Includes {
|
||||
if path == textflagheader {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Add it if necessary.
|
||||
if requirestextflags(f) {
|
||||
f.Includes = append(f.Includes, textflagheader)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// requirestextflags returns whether the file uses flags in the textflags.h header.
|
||||
func requirestextflags(f *ir.File) bool {
|
||||
for _, s := range f.Sections {
|
||||
var a attr.Attribute
|
||||
switch s := s.(type) {
|
||||
case *ir.Function:
|
||||
a = s.Attributes
|
||||
case *ir.Global:
|
||||
a = s.Attributes
|
||||
}
|
||||
if a.ContainsTextFlags() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
32
vendor/github.com/mmcloughlin/avo/pass/verify.go
generated
vendored
Normal file
32
vendor/github.com/mmcloughlin/avo/pass/verify.go
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
package pass
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/mmcloughlin/avo/ir"
|
||||
"github.com/mmcloughlin/avo/operand"
|
||||
)
|
||||
|
||||
// Verify pass validates an avo file.
|
||||
var Verify = Concat(
|
||||
InstructionPass(VerifyMemOperands),
|
||||
)
|
||||
|
||||
// VerifyMemOperands checks the instruction's memory operands.
|
||||
func VerifyMemOperands(i *ir.Instruction) error {
|
||||
for _, op := range i.Operands {
|
||||
m, ok := op.(operand.Mem)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if m.Base == nil {
|
||||
return errors.New("bad memory operand: missing base register")
|
||||
}
|
||||
|
||||
if m.Index != nil && m.Scale == 0 {
|
||||
return errors.New("bad memory operand: index register with scale 0")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
192
vendor/github.com/mmcloughlin/avo/printer/goasm.go
generated
vendored
Normal file
192
vendor/github.com/mmcloughlin/avo/printer/goasm.go
generated
vendored
Normal file
@ -0,0 +1,192 @@
|
||||
package printer
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/mmcloughlin/avo/buildtags"
|
||||
"github.com/mmcloughlin/avo/internal/prnt"
|
||||
"github.com/mmcloughlin/avo/ir"
|
||||
"github.com/mmcloughlin/avo/operand"
|
||||
)
|
||||
|
||||
// dot is the pesky unicode dot used in Go assembly.
|
||||
const dot = "\u00b7"
|
||||
|
||||
type goasm struct {
|
||||
cfg Config
|
||||
prnt.Generator
|
||||
|
||||
instructions []*ir.Instruction
|
||||
clear bool
|
||||
}
|
||||
|
||||
// NewGoAsm constructs a printer for writing Go assembly files.
|
||||
func NewGoAsm(cfg Config) Printer {
|
||||
return &goasm{cfg: cfg}
|
||||
}
|
||||
|
||||
func (p *goasm) Print(f *ir.File) ([]byte, error) {
|
||||
p.header(f)
|
||||
for _, s := range f.Sections {
|
||||
switch s := s.(type) {
|
||||
case *ir.Function:
|
||||
p.function(s)
|
||||
case *ir.Global:
|
||||
p.global(s)
|
||||
default:
|
||||
panic("unknown section type")
|
||||
}
|
||||
}
|
||||
return p.Result()
|
||||
}
|
||||
|
||||
func (p *goasm) header(f *ir.File) {
|
||||
p.Comment(p.cfg.GeneratedWarning())
|
||||
|
||||
if len(f.Constraints) > 0 {
|
||||
constraints, err := buildtags.Format(f.Constraints)
|
||||
if err != nil {
|
||||
p.AddError(err)
|
||||
}
|
||||
p.NL()
|
||||
p.Printf(constraints)
|
||||
}
|
||||
|
||||
if len(f.Includes) > 0 {
|
||||
p.NL()
|
||||
p.includes(f.Includes)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *goasm) includes(paths []string) {
|
||||
for _, path := range paths {
|
||||
p.Printf("#include \"%s\"\n", path)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *goasm) function(f *ir.Function) {
|
||||
p.NL()
|
||||
p.Comment(f.Stub())
|
||||
|
||||
if len(f.ISA) > 0 {
|
||||
p.Comment("Requires: " + strings.Join(f.ISA, ", "))
|
||||
}
|
||||
|
||||
// Reference: https://github.com/golang/go/blob/b115207baf6c2decc3820ada4574ef4e5ad940ec/src/cmd/internal/obj/util.go#L166-L176
|
||||
//
|
||||
// if p.As == ATEXT {
|
||||
// // If there are attributes, print them. Otherwise, skip the comma.
|
||||
// // In short, print one of these two:
|
||||
// // TEXT foo(SB), DUPOK|NOSPLIT, $0
|
||||
// // TEXT foo(SB), $0
|
||||
// s := p.From.Sym.Attribute.TextAttrString()
|
||||
// if s != "" {
|
||||
// fmt.Fprintf(&buf, "%s%s", sep, s)
|
||||
// sep = ", "
|
||||
// }
|
||||
// }
|
||||
//
|
||||
p.Printf("TEXT %s%s(SB)", dot, f.Name)
|
||||
if f.Attributes != 0 {
|
||||
p.Printf(", %s", f.Attributes.Asm())
|
||||
}
|
||||
p.Printf(", %s\n", textsize(f))
|
||||
|
||||
p.clear = true
|
||||
for _, node := range f.Nodes {
|
||||
switch n := node.(type) {
|
||||
case *ir.Instruction:
|
||||
p.instruction(n)
|
||||
if n.IsTerminal || n.IsUnconditionalBranch() {
|
||||
p.flush()
|
||||
}
|
||||
case ir.Label:
|
||||
p.flush()
|
||||
p.ensureclear()
|
||||
p.Printf("%s:\n", n)
|
||||
case *ir.Comment:
|
||||
p.flush()
|
||||
p.ensureclear()
|
||||
for _, line := range n.Lines {
|
||||
p.Printf("\t// %s\n", line)
|
||||
}
|
||||
default:
|
||||
panic("unexpected node type")
|
||||
}
|
||||
}
|
||||
p.flush()
|
||||
}
|
||||
|
||||
func (p *goasm) instruction(i *ir.Instruction) {
|
||||
p.instructions = append(p.instructions, i)
|
||||
p.clear = false
|
||||
}
|
||||
|
||||
func (p *goasm) flush() {
|
||||
if len(p.instructions) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// Determine instruction width. Instructions with no operands are not
|
||||
// considered in this calculation.
|
||||
width := 0
|
||||
for _, i := range p.instructions {
|
||||
opcode := i.OpcodeWithSuffixes()
|
||||
if len(i.Operands) > 0 && len(opcode) > width {
|
||||
width = len(opcode)
|
||||
}
|
||||
}
|
||||
|
||||
// Output instruction block.
|
||||
for _, i := range p.instructions {
|
||||
if len(i.Operands) > 0 {
|
||||
p.Printf("\t%-*s%s\n", width+1, i.OpcodeWithSuffixes(), joinOperands(i.Operands))
|
||||
} else {
|
||||
p.Printf("\t%s\n", i.OpcodeWithSuffixes())
|
||||
}
|
||||
}
|
||||
|
||||
p.instructions = nil
|
||||
}
|
||||
|
||||
func (p *goasm) ensureclear() {
|
||||
if !p.clear {
|
||||
p.NL()
|
||||
p.clear = true
|
||||
}
|
||||
}
|
||||
|
||||
func (p *goasm) global(g *ir.Global) {
|
||||
p.NL()
|
||||
for _, d := range g.Data {
|
||||
a := operand.NewDataAddr(g.Symbol, d.Offset)
|
||||
p.Printf("DATA %s/%d, %s\n", a.Asm(), d.Value.Bytes(), d.Value.Asm())
|
||||
}
|
||||
p.Printf("GLOBL %s(SB), %s, $%d\n", g.Symbol, g.Attributes.Asm(), g.Size)
|
||||
}
|
||||
|
||||
func textsize(f *ir.Function) string {
|
||||
// Reference: https://github.com/golang/go/blob/b115207baf6c2decc3820ada4574ef4e5ad940ec/src/cmd/internal/obj/util.go#L260-L265
|
||||
//
|
||||
// case TYPE_TEXTSIZE:
|
||||
// if a.Val.(int32) == objabi.ArgsSizeUnknown {
|
||||
// str = fmt.Sprintf("$%d", a.Offset)
|
||||
// } else {
|
||||
// str = fmt.Sprintf("$%d-%d", a.Offset, a.Val.(int32))
|
||||
// }
|
||||
//
|
||||
s := "$" + strconv.Itoa(f.FrameBytes())
|
||||
if argsize := f.ArgumentBytes(); argsize > 0 {
|
||||
return s + "-" + strconv.Itoa(argsize)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func joinOperands(operands []operand.Op) string {
|
||||
asm := make([]string, len(operands))
|
||||
for i, op := range operands {
|
||||
asm[i] = op.Asm()
|
||||
}
|
||||
return strings.Join(asm, ", ")
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user