From f6661675729bcd9d2dd0149bbcbfccd3facb22f6 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sun, 9 Nov 2014 18:55:36 -0800 Subject: [PATCH 01/68] cmd/5g: fix bit mask for div/mod routines clobbering R12 This patch is based only on reading the code. I have not tried to construct a test case. Fixes #9077. LGTM=minux R=minux CC=golang-codereviews https://golang.org/cl/172110043 --- src/cmd/5g/reg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c index 27d9d3e8be..b78c268df5 100644 --- a/src/cmd/5g/reg.c +++ b/src/cmd/5g/reg.c @@ -230,7 +230,7 @@ regopt(Prog *firstp) /* the mod/div runtime routines smash R12 */ if(p->as == ADIV || p->as == ADIVU || p->as == AMOD || p->as == AMODU) - r->set.b[z] |= RtoB(12); + r->set.b[0] |= RtoB(12); } if(firstr == R) return; From cea69d687732be20e0ca245b162b59eba26fff54 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sun, 9 Nov 2014 20:57:44 -0800 Subject: [PATCH 02/68] crypto/x509: add Solaris certificate file location Fixes #9078. LGTM=adg R=golang-codereviews, adg CC=golang-codereviews https://golang.org/cl/172920043 --- src/crypto/x509/root_unix.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/crypto/x509/root_unix.go b/src/crypto/x509/root_unix.go index c65f626ac8..f77d6c0c57 100644 --- a/src/crypto/x509/root_unix.go +++ b/src/crypto/x509/root_unix.go @@ -16,6 +16,7 @@ var certFiles = []string{ "/etc/ssl/cert.pem", // OpenBSD "/usr/local/share/certs/ca-root-nss.crt", // FreeBSD/DragonFly "/etc/pki/tls/cacert.pem", // OpenELEC + "/etc/certs/ca-certificates.crt", // Solaris 11.2+ } // Possible directories with certificate files; stop after successfully From 63fe9efb90a076422c67d34426b0076c2af1d8ab Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 10 Nov 2014 08:12:43 -0800 Subject: [PATCH 03/68] cmd/cgo: tweak doc to not show example of passing Go pointer LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/171360043 --- src/cmd/cgo/doc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go index 69c7ce893c..6179c7afd1 100644 --- a/src/cmd/cgo/doc.go +++ b/src/cmd/cgo/doc.go @@ -152,7 +152,7 @@ In C, a function argument written as a fixed size array actually requires a pointer to the first element of the array. C compilers are aware of this calling convention and adjust the call accordingly, but Go cannot. In Go, you must pass -the pointer to the first element explicitly: C.f(&x[0]). +the pointer to the first element explicitly: C.f(&C.x[0]). A few special functions convert between Go and C types by making copies of the data. In pseudo-Go definitions: From e522a477c298dac1e26e8bbd6ac262911d7ed8f9 Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Tue, 11 Nov 2014 16:06:47 +1100 Subject: [PATCH 04/68] doc: update go1.4.html's minor library changes. LGTM=r R=r CC=golang-codereviews https://golang.org/cl/173920043 --- doc/go1.4.html | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/doc/go1.4.html b/doc/go1.4.html index ac63ade60a..d96440708d 100644 --- a/doc/go1.4.html +++ b/doc/go1.4.html @@ -637,12 +637,29 @@ See the relevant package documentation for more information about each change.
    +
  • +The archive/zip package's +Writer now supports a +Flush method. +
  • +
  • The compress/flate, compress/gzip, and compress/zlib packages now support a Reset method for the decompressors, allowing them to reuse buffers and improve performance. +The compress/gzip package also has a +Multistream method to control support +for multistream files. +
  • + +
  • +The crypto package now has a +Signer interface, implemented by the +PrivateKey types in +crypto/ecdsa and +crypto/rsa.
  • @@ -665,6 +682,16 @@ to help clients detect fallback attacks. those attacks.)
  • +
  • +The database/sql package can now list all registered +Drivers. +
  • + +
  • +The debug/dwarf package now supports +UnspecifiedTypes. +
  • +
  • In the encoding/asn1 package, optional elements with a default value will now only be omitted if they have that value. @@ -685,6 +712,11 @@ in some cases, especially involving arrays, it can be faster. There is no functional change.
  • +
  • +The encoding/xml package's +Decoder can now report its input offset. +
  • +
  • In the fmt package, formatting of pointers to maps has changed to be consistent with that of pointers @@ -693,6 +725,28 @@ For instance, &map[string]int{"one": 1} now prints &map[one: 1] rather than as a hexadecimal pointer value.
  • +
  • +The image package's +Image +implementations like +RGBA and +Gray have specialized +RGBAAt and +GrayAt methods alongside the general +At method. +
  • + +
  • +The image/png package now has an +Encoder +type to control the compression level used for encoding. +
  • + +
  • +The math package now has a +Nextafter32 function. +
  • +
  • The net/http package's Request type @@ -721,6 +775,7 @@ The os package now implements symbolic links on the Windows operating system through the Symlink function. Other operating systems already have this functionality. +There is also a new Unsetenv function.
  • From 0f8cd1438d46ecf7393305e8981857b940f50ef4 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Tue, 11 Nov 2014 23:46:20 +1100 Subject: [PATCH 05/68] doc/gopher: add jpgs of the 5th anniversary image LGTM=adg R=golang-codereviews, adg CC=golang-codereviews https://golang.org/cl/172980043 --- doc/gopher/fiveyears.jpg | Bin 0 -> 220526 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/gopher/fiveyears.jpg diff --git a/doc/gopher/fiveyears.jpg b/doc/gopher/fiveyears.jpg new file mode 100644 index 0000000000000000000000000000000000000000..df1064868ef8fac1d0b3d66617e470266d70e7f1 GIT binary patch literal 220526 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

    e5?& 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 BCjNIF&}v`+@W|!a4HR1}acu&_xHa24&#r zmZlOBK4>RJCp|MN@L6H7=;mc_?_WgIYmHAqZN8Ld_$n>K<`!t3ZEKnqGO7E)o4Mvv`}GGm;m1z*`d z%R#%TL4482(XEx3T-v)1HHos(SILN8ds6h?dZhohO@J8;*te^UiPRJA{e*W# z;6JNpPxab|&BD!Hd)zy?Ot=Kr71(%XXUHH5O;yS5f&1w=H>&R)&(OR*)MoUE&nfzw z)bp?kD>kxX&hq_@HhJ89K|2~uPB3xsOtEZD(Sd584I?(u7+$7PR-9qbg$qvRGOjV0 zj+dh_E;4g-!_0}epK*CjEPQt48g^YVmhHz$iF4HhE2XqtesBn*0}otah@Ptce)0P8 zU(=^Q!~z(1aqnN&Bq_(myH8?l7b{b3vo<@xT1WPN;J+Xbx%3=i6*3N;inH|iNTzh) z_DpY<7YL8p;Mf()W$3-zn1xfux;19>|kl$Q+bXEyTdt%dxg6Z+pu||B)5v4<<%(}P_y3Xs_ zU}Ym4u;dc%u=Sl3A?A;bW$;^AH(%nn_u69rgoH`LGI|xW%}cL*xa_mJ zJ*4drA`lJYz*V&3LqF6rDE#KqArOQN*osqEcCxNZWvZV&+ii}rvfLyQ`yB1sfGO*B zn3U@YPY9`$lyUlZn3mRbaAxxvWGu#tl@+iZ;NUdY=XGz-SYzCa_hk%kX!RkBSflf6 z1&fldB}@`To{Vj0%Q3+_nc))ms^q;@KbnGhD4anf6B`tz$^>!3p3+9i$X7a!J(8CP z4*&PVV)Ai8irn}i=o|i}3!$$Xhia**;m6p-o%_;VO^B9w)ingGs->7ebR1R_$Of~2}hOvbS-a^={n0hgB-x5S60R) zl)-_o=ok0oXc*Q$ZoGJq_?f4|hX%(T;>|Rn%Z1ZyM3@?q8}2X=$hJWH;e~WAZ?Bfd zISnV*A8*S=fK{?=MY+o8UW3&HTN2#+L>s2mVTCSd1d(^HTXAyxwM}hJ(O(T!DypJO zs;O^Ny~OLSEwZd)bEizD&6}2oR&mVb#h5O*(UPwxyw=V3HQW9icI1z3V=3ur*g!IG zMn7JPN1*EP3@xFjSB4!vmr8bim%|mKMmU!I*QWAdK(D0h2AT+-2rr(UF{xF`tG07p zH` z^IM>1=WNjD&8ath#RMIhDId{)`VHylpPp*l79}$NdEad)C?o;EcQ{fkCB$DHao?w! z0qJKDLPF3&m>b1e#}1h-CH;Y*=ht}SMu8#u3e}Rfv^XZ8KgWW|TM{h%^v%&!`p#n- zN_i7Xfy{*DHi%7EfgNFX+c~h4(aE<5Rwn4DQR}y4!`hI(>p@@rQ#5&q1)G+nEsk^E zq|Bb{>Mj`f$H7;U8>)FsW|M(V9)6qrNmSvw3wx1fLgo*kIZEkiPu5XL! zm3wx!6N^)5aGlfzlV>xrDiodm@Iy`Dd_F}gy7l|+P#WB5e=%)z@7eisKo*A-CZ)4; zRUklZ;htpy?qEK=E@6{41EcN9lfshpl$Tqie9r9gVN7AYpZJqfvaW=9@bu3w_!L>W z{9Z(B6hSjN>AQo9j25-DOA33XCsC zJ5-Nl`Tm$A*;d}JOZuW$6jDszRpwjq@RJPH8{q%qUsuBI_fZ90DGebNco~z@@Q@3C zMxT5>%U3ua4Q%oDKLAU;lS1zg01oUdW1-Eo63Pa;7D{)^8#!>{pPd(Y`*Adr$PH4= z=y6l#p65m1=~GEqa2KqFPp^Rf#;qEc#Z3!0pNez^(;bIBJ}Kjzhyp+{4WDCPH*{Qp5esJ>pw{nh+?G_eB4?PGTQikpDgv;UC;41%uWn<)m1O@ zjj>o@3)2m+MryQ6fpw0wy|p{Wh~zyE#TK(2&P>wAK4qRn0^oZuC>K1F?-q^YCiPys zcQxP1M+}`W|3SMYO;mRWy!uI`=5(~OyA^hh&{#ERbvaJCoV7TWBu{wPS71i@`&wo& z0LOputR0ttu9AN-eK@=(5wQ;(ur46hw) z&$|-AQ@}pQj3;)T&Q=}z^*{JlYwh;8w2VTgAE*urf7?DD6{OH;OQt-*54EC}BC(^` zY|s6tu(n;4`mJyuhH?_pEJ-F-_R5YH&G1=|xIBNB#T%nPLhvM)BE;8mO{POk z$cZoqXHUv~J_jbB8CU*%NaWSitCwIt=u@H~4KsOKooU&>2s&o$ZlVrqy!aPh;rqH`k{8F!8 z0>M!*J&kX@`+X~frjeTUD!_J#l^zC)WS6D|{UKj{mo;Xdq!JTEmc%}5aToW7^y}l1 zt?r0lT4_4b^J|e~!I1zMM-5Gt2=_=Aq*@`DSF~zB2F2Sf1A5}O_gfYDHdeeU)Lyjx zP7H7gY$A^rPh;@o1mX)bUeCF>PKW6)`g03)@eaMrSoBlV21^W5dsv-K&O|5JE{lJc3HU$4W_9XD zc1ua&XnW8>`R7>4ZZ3XKAcUzR|K~Fz(zMOk{{TUSI?1r{-^pHQuycQ%W)a0Nb8NY{ z5kgR(@y&>atz{QZdiB?JtjB3KR1>?yJu%D0{I~#gP2ryLGmWl2%K>i;&Ae@rK zsN~J0J!1oxm2rxF&H?~NCQ0l!QG)0gzO)AG^d-4E@6$LKpcnm04 zgGWoenI*N8gx0?;!0euD8NZ5-#aJiFoR#vPK)k@!bwcEvBQ=V3xxm#->B)F;wIzB_ zWau?DQ6r=3w7Wy#NSWo;9_r0(gauSLv!mG2k_4&B{ROXie#666==#1 z^uCzPa#~qo#YI#HHMMG?C7wPTzLqvN;>**DZo%j%5f|JiCY-j8s$muj{) zfc@3a5sXF=lPqcj$%<%gdgY2}g@GH<=aC^C!H%q%msxBU$@r{dYZG$re*E7#Qij*L zInbNSwA)hzJZX5*L>lvkKY2@1I10c#+%7C!vg?aXGC%O1BT zpguO^Kycs8z;B{|yp2;?ztQ4~mwwrECeP z!UsOgT{=VlFZGFt1M_~H<~P;XjmFjK=PvT*V?y)*YY!X-!FCUUK4C)(ybf@;rN-8w zcbx@qcFrCOXtS`F>BK~LfWuV|1MAetC`8~c2V%b4rjSjmVCuasAWexNQI2?(+uD=f zA-;-*=jy;>7uPG`!50w7Cq@3@*1vsv~H-MD8vWbPa8EVWgJX zEc+EiinidjZDl;bIVD~C;+xYnN zmMUMP8s|z@2&mWMZ6PgT+OO8soPZ+VUmJDcR?x>Ze)PJmVUosPbiSENMtEj`)lbQ??k#W0?uG#l61&%6xI5 zuTA48uOo+itiUOCGB#6I)+U<0kaF;Y-q^zDI=+3G`L;S*#J-kt!Poy<`9OAmzEggR zq#bRU-=#k)JA&nRou7V7?B%`InWT4?3nXIi`~m>PU>ua*1GskGqn-(7IN0uUjixjE0$=zP#2)y`>SL>~ zcw&W5DgwLI_T~R-HFY^rD@uHW)G>3(hgW-fx%@sn2*?2 zW?(9KahlgxBloTTvNjw*d_>Z$zP+jf1}?CAz38pPm@{t55vM!fUI3JJA?OQ~(7w9k z;DzOJ5KUn>`}N$TjKc^O+rR;|V67uJGY!l#AMs-WR&kFSDBLnMxUe}uz6-^#4h z7EeAz@L%RMKCm1vPb3dI+?-0vkFziDFo*4}dLgEA@;j}NtT&u>aN_pIyuYUQwI-Ao z8@ESKZo&B^sW0mr-O=H%`x*DCJer@f+`~}sGI;dlvOt~>edWul4nLq-*VRi;7r60` z(vH)8na?L^EO7XT_+)P;aqYKH0`ZX#{ZDU9ja9m)^D;PpR?R0VCyc!sR(Hdg^f}Pg z5JlTIs4K7nU<|EA69sHp7UU~Q$~s@c3zF3Dkr0G&AF1jdp3_*|JZ$3f18<_sz^P@Y zqWgMV9N`lIHiETJe8&};+kY7+Gfpa)>1)t3q#B;!MP0oPEc7!+vDQ$H#EB3`uw*>Z z{s`ay6d*>a(vTz&%h918w)F-@Dbu?g|Az-`TBc~{7V%^x$O!|4(g1tUD!0aMIG@lf2nbX-%+rL=<1zK?8v%VzQKcYYv57*F2mrp3d zxh|jssXZfs(5aQGaQ`l*D~pJB6vl42Yf^5NLseH9nR2sKsr4 zA>vhu{Yzli_*v}ZStG*sx(N|1?@Fk8^$4r$qX zmp0-|)L9SxVl_hjRh=)3MGe9vNIR|e zOV~0Oj4400mub0=6=JldB;T75-;((nv;sX9zU5!D>n5obQQaN8s9as*`a={JETDl! z8t-t*%QY+SjQ5UM2jg;KBp0rh035M`kD%m&oYHP{xY`0#OavZ>*#2;oZl;9I2wguW zF1-lW_(<|wzcZxpq_n_yaWrQ--=>7P$E#*@|5tt>22oGA=;V<pFQ(EU^7E zI}uj;1HrvLpT4;!Zg_pX$U9B5toP;>7R&WFKN6!mR+GoBYiM-a0Gj-*-%DO-^LYJ_ zUftnm{2E+olz+r2I|8}D{a}7f-3@x;=-rATT&i^RIG7IjqQoZJvaXThWb)eU3_Fsc ze9&v17(SV~B}1}uxD3+l#jg9It3|QjiWaD)WNf7>s~t=hkIBET7->SzAmWGg9o2*I zH{@TG`&!y*{@wxE{0cksfi?Px^q;T9pMUI(UV**-;hl$*YH55>@SvMyDHApIg?T0o z;6C3PAlr`%75sTPl1TK#Ub-@R(=2euvp*rm{M#{*zq#0i;ODB>7j^JT{z(v?&&|w$ zu;xUOiTqo^&#BX(k{rx@Bd{WCS50F{mKxV`eQVV$L{%Fy*~ zu>8r>ng%g!wWfWCe;{q8IUG1#-Wmd|qPdp-iQLs4BD9iOr^gmQ(h%KhWAM9ha3k_x zsdevmu&&ZS_t#GY`@nSq+2N^=`LzkB&pV96E(%KNB4)&@Kew#xY|-o|2Yya5@s2;y zgQFfl$6+c&|74 zqzlGiU_4TKf1*~S(eoxS^==OCG>AfzMcC}KTdK+P>pbuywVlko$fEF%R0JA&xU@h3 zamRM|2b7ox>x|X6M0z<6m*FZEd&unO(Sw0u#yiPje5_a)5a$;m=zAU@CrtE_OOWXc zS`rG%+FvMC1;%2;6}Se&qGyje?Qb03s+%K6Xx32ZV4b_5o1DialDO+*XG#?BtP@xY z*2z0??}#GX`cQ_4BhMvAXBYxYbaCT8Y9C*vqGhYXB^E2w_tVd&Wg~?!3fpsFGfA@E z*rS2nP>~4mXB)Kf|NM{)K5`kxGI?4cvy=fh{UcN{feI4g7si9oV(Blw5Q%iWHqbLx z&i8P7&%G~n`D>s$xQ%*n11)ofWxrm~Z2I!@LxEFV1cH?$oo=cWr$Z2pDid}I1diMn zSZ%(EWgS%dX-q!v*dN7(pH482e5YS)SU3EIb1&uS7qL2T3Xu2YA6RVcLLks+BmFRHB?&M zA8!9)B!(dd%=-o+*zb@>|22hh=g8_tbh5!v5-j1xv7d+k@|fDxnM*+`K|!iNX# z7b7<4d|hI+pMCwJbQ!XoBZU0nU_;(G5S;|c@xHDeHAixupORNRtp<_tN&}uowd3CF zQ@h$rziNNhHlth@E&l~=cT7vO`5lzq0u!Q!1W4SZ{{O;Ov{9uvZ)^N`p|eG{w_Bax zq`}!wg;!gz%t`ld-_6!_({}e><_Z4}jbL7&1s!6WxwS~U{kg_Yx$kXh)!y}|B6XWY zwZOAjB1~nPon&{Dl(M4}KZ9?CMdz&3-Cxj$(CfzPBJ~OC7Z4Qw%Dvhykn#7<#Hogpru4_n%rCMxgm^AifH2z0EEEE4##HB z_J05@LDRnIde=aZlvB9wJa#qcM`Pk;Ynf8d+wIi^M9P$q* zaLB6he)3P8kO9Zu2NfW-L=t>~&s_1tb@r&Y27CeoW3yF@t?b1^?NSeZLH0FO19{K6 zm;etO$6Aq)T#`=J+IMyN>Yc=)NdSR?kG)r>CBpNZ@P2BedZkMY^&EWMRI#Fzwb8j{t5woSg0%teIvl?nIz7aguYplT@xq z&s^l^JF80Qmfi+P9dN>_Tr$M1pW!&h;q4neTvdIclLgk1OZK>}T&*h2~gg z`ugtts)g$it%5=5K5nNqjExbOD=zbs&uq7Pqj0;9Ny!JHYS6g{lKp%9!l>VH6e%R0 zK-@X3nMlpLJD7lTli9jeHaTo?c>eWhUHr!fAQ6Me;;8bj-(T-mZ*ka}GI5NN>BlCn z+OsJb=Z|X5N%w$Nc>|m%=C0Y2$fpE)e50jp6IpI<>GFKTt_b$6yBGORNyz$FKVapU zC>b6299HFq7^o_F9WXhq;$dTI!FMPmo<}`6tw;}=aoGJUF4=b??HDJo%UU*LJPvWw zfm=j|Ux+gd1>+!diqe4YP!y0q3eJTI+Av55y4H*c6n)d4gXI;fA(mnEIpgV9E#$+7 zImf02RDphObMAJEw29EF{nO|w(IvPTx&lLW^c5l@Ju-91;8QK)^EU&KGyTz1z=k(G z64~ptR)QQ@gR`EP9XY3=!exQuuTHerT+5xL_f?vL~7NKJtRlgYt8)gZ>fftKgen9&n}dISB@ z#SNT%pyYqDIi`W?Or#JpPfj=$BraXfe!Z#&VgT*ipr^#RIKeI7j+E08VHnBso}-@B zsCF^zbLc8K+i5u+c>AN8ddttq2**EkezXXE!6^K0JPtU`J3CMllFiOI;+Z0mhkWIa zJP%rP0AJ<@k435iIJ3C!$o0q^RHrPbsK?Tof?wtb8^60#FA@BpjGyj`0C8>HInU+! zRI8Fs;Bvm0;;Y66;2CqyPs%F8p=B(&=Rd=m0Ca3yh3HSUPZ1-A2lT43Nda$s052&~Zv5-sfmP_sHu^@`#h>1mu5oRWTw+n}QC1 zO1B$iU=RjByf~^*6368{pQTuVhzBLJpK1^>=4>zoo!vWCT}YoNjGX-{S&z-YJa^-o zgHp-2AP$2gA=au}Wf<7$?Xn|DPc01R`VYV87V5x@c$fZKItARsV}b)<9E^k0 zjGPbKzgQjzv+(WY%<;wjsc##Qfa5LGlhE`(TJzn~k?+y8xfhZ2U+n(?rAMZCBS^Ql zLLr9L7q?&rKMVn0sRU&qP)^)O!y(9D3~)p_x-wy!$*R zKu=yeSID2XckKv#HFNe2E_Yd3C6ael3}8e6lefDZg;Cs}YWl;)0IiFRVBqnzSLZ*( z>jm+b?OUtqx~z8h5n3wha{Q!7flk;I^M+l*M*5DNS0*M+StF|tWSeIrq<9BTp27T0 z@lZ`Q<-qgL+ND3Zi+1!z8Tp9naxt8M1#I|7;}?g#Pk6SlYI=LE$nw(J1h=|nj)!F{Tf?p0t+UJ&28l|NanDx4QRrJW#e7xxLE#UEULVqburx~$Jk^SA zu>&NLi11`5uJN@_{O5|~*tEIUr>pq$;C_v(c!nKv!qu$r;=q#T&Ah4D0tygUsSSh3 zJY-kV-|$Tz+5=PgrQpq5Mfig(udn!8`RuMtv8-}S5hTMQ1B|j`k&NK*E9URne_pup zPr+R_<4}2IkSjvoV&vr*u6G`}0DiU8{=?eU*M>iC4-?v3pnE-cM7OwiRUagfyDkYG zavzNP8q%D(WSJVZD87g2v{>@hRA6<-6(Vv#P->Fq24Rz)2Lh7>e1-dLvGD%2plWeF z+#)?jD4g4bXT+IYg*|Y^P6s?!zxXFm-vS94h$;^uM&pia!oP1DpRjl~OPI)MttE;` zfx->KMcPXryNr%|SE76w)+N-mO*!u5jpR1*?xt*`&)BH7Sak0!nBqWXuDna>A$}-%78`rNDdfdHFO9_YPcY79mP4TP7zqMYy zac84mMJ9~0vdbF}^l0`tA2R?9$Eg5ec)=~rYxq<4Uej%`d}VicugtHxQsgRI!On3U zNrhgX{p-^_DdCGx4e1bA=$7%@T0o#ii5OfDe04tcu(ly`$ebTxUS#UIGuDlwtc;B# z!_aAwELL#G1S|JaG*waT0OF;)D`XCHkHWNWBPkI$BOb!M^W#s%SbPWJJDdBR=gAmU zKnqC3;3)Sbfmv=+)Xw;^@p{9+T0=>BDU#w-vfkb@470iDsJ%%f;<%p!`~ucIb+10V z@u7t9yDYYvN-%49IN_XQ<~ThMeov)g{>`2Zy!eyjE6*8t>O*^XZ#%(YfpHDEzz$;v zlg?KsxF)`$(d^V)F7cKF7z@&=`??~V zx3?&yFeg1Sqmfgl5d7KCeg_pKH*v`jQ@|&&=}#yE0{I@?QzVok9Cz=EczwzKsK*l->k}_R-9zCc5B|8_6y*pDkU=82WoK9rVu6qiI zoy39I_1Y)_?Iz=%x%yDxsRy2ZoKpx0qmI7RJA8v~N8vyUSZ&}Eay=q6&YD8b&XWQDN^9Pxq z=}PaoF5KrnooE5*H?~JX^r4RS;BlOGrWXpQZ}Oz`m$x|{f`BHFe1os)Oo(oBGI5T) zaY)a;JY?k0c5a9vz?ZsA-76hJtY;ngmJgz+62VY@GvV7l9VL%Oq zSfCRFl0CSo5-rPx2R@up96;wF{{Y`LBp{Sx!|t9qpa!rA;0~Z4PH7Lxi~>I@4jI8C zueDdXyAd{AoQ~K7ngFoiV4hE}N|2)M0kfQ7bgBbVKmjCjJq1k_(!P57X99pOi);?L zO@f%kzY83Pmn^QXtJh1WXWl&|5tr_;4NLbKZ3 zN5NJ`3%j(zLnzl}c_H80r{_MFrFMc~_6?-Nyv$+@;g3MY`Z)XQ`oNjWvshMQ8d z6>4g2KWptRFMcR^&i??xS{2Ifi$~G+JII+OeA#n`$RPV;9P^(`_;33$ zd@cQyv^j6>taQs+qD!UCBg2N_AP@N9kt z_*tOo7Ez>Wrr1RSsv@ckC>a2B=bU@ju2}-A3FIjD=DgeBPNH>>259$J9$QT{tTIjI zMX`4j1c0QHqbC?Aj8~*t?vNd;z|KBVUrR}7j}C6^yBxrUTo6Fcc&I{od-J)Ox(+Gv z?O&Lw1Y~{D#XWv0Vj!zg2xZLAiCxDk&!H zVBTy|Z;ePie80KC>-T<@-+s{l02*WXE#VWXOAB2{jM1b@Kr%MdwQ@NbZKFKbmj29o zRlmZ&iaNK24*Pj@+v%cM%tz*ow5*5Gcp*XdBN@rA)Ap?RPj&HAz;{;KKJj#+Wru2w z!GZ0Qj(T9^5KVAjO%9pGdtZBF&2^6oc>BlD+v+;kjbKA{0GI5|rpIw_Y{dZ{SY{a@ z;O_6w9P!qE&Yu%?od?F&{tEGB*wv#*w?%O*fKLjlj=T-vmH+{g0VJC8dq0kTF7TDD zu8ZS822K5-o2`^VAdLu60yoY+>EL7&?Ou`lGkiDk2BYyt>&E^$u#-%-YawrAZ0eh` z&GWN&$P0jbf(%E=i7_Q3gb&d@W?Yv#||8(x#c-Uz;XMrOT{ zUMpDKfRfxyJgCDQaGdI#O?COpLDXdsEeab{H=U&Nh!qgp`JL+z#d#`-87v z=xey=BfH3Bw{}R*IIe5O;2Q#19Al6+*F||c#5YTo1midu&!uwSFj6$x1_? zH(Y$96wr#2!Q{lmZY+5N|eqIRL zDRSH!vBTYbKDN1cA7?`C$SkYIM`2Ej;gyUMmRn)w91=)gxX0&RjPbA92GlHDBn^X{ zclM-9X8YLhk@Ai@as29B5c!#brg%Qm83);*L68sKTpG4?WsZEtr8*vqS}X)vF@v0v zMif(#8G&qkz+*TZ{b|`DU6fLPDS?qr^7*jMmAL1{{*4oRFj+Z>4m4?dHgvXxyxS zx(`a_uI`1!;`x7ZSLPcB=~+$Ov~%7ixEf}V=3UAHlep~%*9ZLeuYx~hyGZ^oe%e12 z{C#Y)c`I<99=B$LVKLjc@RN|rT(QW@QKjB&lINybA;C3gE^TlK7%PyI3iCCy%^s9Po z#iniNIUteKk6Q0t50I9(B)uMW$^|8kI3tnx=kcj7B?Pu|TkhwNN=8iFmKnh5-lLIO z3k|$upOkPtX|hm?<}eEaNaK(=6xVU)WV3Elf_Upw`8%V-DcyoNOmyo|h{GuxbN>JV z8O<$&K^=ChaKw@ARqc_slPBIicpWO%(#kdhdJOFx{{Wt96+`Boysk5yqp$fCn3ly! z8_QAm@!Rg^tIp;zl~U!78vt-Wty+`jE|IO1mJKgmB1o$B+dZ# z;MSzj=PJPa@mbet=99tPG7rntR5H<#bT+vQ(2RDhyY0-Uf*79o#s45K#AhL=C_H9 z+~{oZK;t0s_j#>5Tx}aM^xA70#j^dg+pjgNYx~CI3xV4;yiD1tY`Fl80!Lk@udWey zs*}ck>E^SoR3e2SbL?wE5x5P-agTb{6C&M`hE)hVcUrv?g&+~bciU7g&z9Y|J+oR7 zVnhXT$2h^}v_vw^qa{ok0!ofKKPM)uTVOESK{(@sfmT!k{{SFfdFX1z)RG~b zf(Nbw^r8gAoUVB!lC*(#jASn1&jy?n#UaMuPKJOVg_vPSAMVg_TRTA??)9kAHnAfc zi1akz4tNXG1mMsi%*C6bBmLTF3U_ZE4_r`*un@!!G2e<}9L5LAFnQqfKx{~gJj^f$ zAMDhdhFG^>_i8QsPVbZh>~lzD4Kr@W(Z@s00w+fE9|UvQZ8a(<0q`(R56Ws6P^<|c zoDRmEj%98N;PZ?cU|j=x@&-W3`D!-nz&RZK-n7(^OMsZ;?_)IbyeT_yIpi955Y=si zo(bob;-4hgP`xmJyTPd7fRoP90nbClN-a#1f-%A4gG~Uai@zjrF_X0W)r1+05;*o# zRpkOxvMgYF1I;a~P$xvXv2i_SOUWS%L-L$aiFn(HMfXp%j5ISJ-~={Tn z$QkH)scfqsHT-j*{t-`)z7N&@%%C;gwyeV=<&rL0xdVb1j%zRW?(lWbjD8y0Poy%% zC7sN7MZCSh1qV3?j)e8D>-M?uyxOj~jEoMT*Eis; zX#8sZoHYGL{wQ4DTltR@DPSoGiWA%eIH6{>VNhkHjAcyghLO zfYMnYa2M{fjii2H*RC(PS{fB%?+F;eZH!?vB=r_`+Mce|$@4Ydexes4f z*t*FGanyQ)T{IvzfggykKGc6_UlaJ&L1E*KOHX|`<~e7I7yDP1 zK;bfWhB!HHJ%x4h_=m;c0WF4$;@tyO@g1(5gssi92`-&Ez}U@}+AuSoYd6E6we6pZ z=6JME1o-^ljP10WM3N^s^(=Oep*i-hJs#$qwIiZB+3hs%gnthnEjBf^v(oLz3aNmK zqp#QblS}^q1jqP&srcXGFNl65>#^TkS?VY)G>dDSc8*W8;APkx5xIdpj(YU0zYKgO z_=EdLYxdLpM9>F>d>Iogt*6Z}mr&H)HdQ9tHpGC1I1EYY#eK=}tKsxM4A5bU-YDb3 z@}LkaT5#rMHsGz*o%WG$i)F|M3xo3at1}IlE6z?&%hsdQ(51gYf;|YS9S;QU+l(F! zcl0^IaJT?--vbp-#8Q~750(bw)8*+_V)?i3+nn>k=~;d$Wm{r$xlx`$r6-`)=fVa+I-xCbW06%qP z8Q|j?uQmSwf~MHtd_vRgyf5JKAKSINl(t2E!B{h8i({N^R?oI+{{RfXV+}H24QXe^ zYQt5qw@3xmoYKNTQQQND86CkD=Q%Yt(c4lmbdr(x29M*bT~^<8av^T{Q(V`MJX;;K zGGP6|*?U*dqv2nS{2^?O;4c(T%89qjy^GEbf_cvb9&zc#VR*a7zY(;%S(jMRwEOrr z5@oiyk~eRZ@D;~g&d(w<2#L0_Jr{lh(0T6 z`j(R{cJb+UHuBoa=$nf>6CfK4U;s`?;B#Fy_w6;KXsaR6mThE0%jSKIZ}QcN8_6dC z3}p8ojc``xn>}h#@cAckBFbkE)CUU8uOVuMt+5?)$QZx5H|wCH^3 zqZu7a@;Z*#8RXYrpzAi;#fn|&6T@|HFWr_V-mim$f<3_>g>$&IxmUR^vv=jfa50be zYvhmH2jVTo=ZY-!Ju)Vp!1J~!JDOI?MbP#;kNgMeUs8Cg@WpKH76v_ye1m79+x$`e zt}cJISj!%nDwPADx}lX>Pdjp7pIlR?Yu%bdL+PJ^J_k<+_&ZFpfj~C!sDG0gaz1W5 zbDH$nArTDYIsX7=vHUS%_G>f*FDJM)t93ZFk8sJyzAi`L?IuQMJKXF=P)T+@02T8_zog#XTtlk(+aKwFZYvX-);WfnCUfcQNvJP?N!5J)owgEZs=m$M&8-Lk9;sgmL z{{X^>t*x#V)@;ckiKTJ;cpr52$ohA!RRsE(N~{-C@4J0aPML&;<0k^G!*Cf!Mlw2M zrF_BgGvjB7d^_TY@bAV8JBu6H$XhAh7{fCv{L%TC19{|*#8=R|HnH~Tci?3@^{izF z5vOx%X?A3gJ%-w){iC!J+du~&cd7pX3T~w~%TpmBZ5xI&&3wE2LH^M`Ak_R;-W&K= zEv2-uy2U%Xypm4Lak4c|co`(*bjQ6Yu4iOgjnAi-UxsXybzlw-2LSq17rraDvX3`X zA}AcQabGt02jK6CbBIt$*O1_nsq!w~xGE zuUw|^%z}0s{{Y$NJaK{bKDDx;CPb=Jj_mY3SK}v#bU4fEdd8h@q!ate)o=$>*0~9P zZ9j)eJkgI5*hwTR3yAW>1JmpHR;PnM;F_NdJT-F-#-XJBy5cjr8s=#v^3E_Z&taaq z>TA-xHTy68Kk$92i$L(+kpjrYn-FBVJQ7Ld=K{8l8Fe}3ih|hi_!?pPTOjzc1Z9pHb^yN!lC<7foDk1PUhLwEFdmT4xa&Z_S;-A%#KU|Mv<}FY5?(pTT-{^K4{nS{< zk{vzDoNnAR>NcGF)Hffur-viGiVr{{W+v`GS`2M^Xy?Ml0&8&jILHmP)T- zXXUm@8vqCY0IgZGd^qrxg|U0hKS)Ge?q`ia9r~I+tr4tbdmlMi{@q>_)KC^0lm~H- z5?Zh%jAUSQ{8;*fR^$D&yd(BMI%}!mRg=mqEDo%vo}iAL8u!QWzl82$A7YP2aTah> zVG4Nk>C&Q~!X6dBXyN-djUnKL^3}GUnFH~u`mtYIgXnlwukE?ueL^&7HBv$O_=Snv zkG;oH?lV>g?VsRCHne^tvUOpTwONYu#^455(~(~1AHjbL+l-ALNFj&(`ldSP)7Gi# zAG0@tb-C5GEdxcD<=gYwq2nimk;vrH^6Qt@ypp4{m&;I~gyX#NcTflHKm^?G#{{Y;^ zV~mRw$}da~I3G&o{7?S?1pN4Ot3xa4z8UtWwMflF%M< z@81Kt7{JCwd+bt=vMB@=>yeY1=A0ZJr%Gw7qOPy3$7Kr>)N_Ef8GK_Og!D_x%Z34Ah{=v~$7=b9R@dk7?|^Q#-C<<& zFUwqAI;k%y#|j5vqY41`^`#i|8YGgtJtqGE_L0L3Rx}4Q9bmO`7 zUx5BB>0Ub1V7>6Y^}Xe_$}6M9!GQ!1e}0wNB!XNO9eeHmRr3wM{1f);;i^5~z`qk} z8Wrult#K3*?v~Qvu;pe>I47wXHSQk;{vaP4cz#=bVj*j-X!8A!QG=XEFaYI$*kD0Y zdWz1a9!*g+@e!-=vv0)k{D9-2&r10#_W1B5+TVoM^GgI?*vch^#AF>}}W#;tOTMg~>Q93F)4d!T$ik8Fa|>KMr`0OqG6X4PIEjY@BdA`1;rA zJXUeR43ceAk;Vb)E7zq3C3DHe)^z6M9S#ph_*bL&FG!BZ!y09sjif;BiVI;Hf_j`U z739$9U+|v(-hT`HHKoazbcDL`72IY#p^ha8hp*l);16uq(4Hd+XJs?7%9!_9fl8u7eGr71!e?AHW&iajwd z?!9+rzPQsH&I+hO7|(ykzMBm-I3{>lh;mJ$^npvT0|SnWPZ(JKWdkRisiT!tuApe++m=4=-QUtzd9D zhyx_q>+;5#W5>07Ubp`M1n&5Iu3fyBdMW~WDw9lzf8Z*>eifzRAJ`w^_K~VJ{jZ1Z z<-N$=Jg+OU!N>%bJv};hsP=LiQ0m#>-vWPUi~j(RpA&3+QR5qRZw)~r&7|5DCCR|u zb2#)M6-DYd^_y7;co@m_J!`AfmwZ1n44-4gaGw&CE|%CUyPWWN z<297thLBpH9{AJ1Gki?{0D^{mEr}#ZlSpf=Nz^Km;TJjDdE|@&Jq|h(U!aj{eniOw z<#xsh#Ah6wbK5AeU;-F(j`2!8lhr`AOt->t3__ zZGO~xm%@LCk8|J&?V!|dE>guOd=DhPRY(qYlemt)hPXM@ZqKT~Le$e|*qUyjphmH_ z+yS4L2P41fT9!JDaDvhp&PW(sgO8`4^7Xk1*z zs0mVe;PNr=TCk5YB2`-?`U>E_7U(*jkKz43-^V(dYdXcWWiBq3-^f|pC*}wV1B?#6 zv);RSB=VKA4%IpPmDvehTzWE6+n0gzmLI|?l1Ia;4o^e0@F^j<3`i;$oa1IHRZpCp z0metlPAaz%TH4)KMlHw7$H`7@s}~prhB;10<4u|(j~IvoI`m_jWR~a5UExW_dN(%G)!`*XdK~2NvR7n+^}^UR2-ZhKgOe;AVU@h0Aq;w1L;TwRt&qD za#xJ)&TBValthGpJjFQ}PJ*skA$X)v0_`{$PM=!D*CZ*qXF1?!Ak@j|HMxP}3)O-q zbAY^-`8dy~706xc@mZvj%IFn9UkQIFc?eh>H_ zO(VkTbE)`?UvIP7Sy+h;%;1o_Q)neiGb-;RXxvF770oAiWI0JfE=CWNBeRc5fL`w)E^CAFX1;SU)->^^Y z%|F3Eg;v(u^j5KJ8jPQB)D{LVhIu(<1pfecg(r;TpyIxw(5zC{*$d+v-nDLL^X#+G4mtym&Z*h%hF!qql26vU z9_aH4?a~Mo7UJ^rT3)WA5a1>(8|(s|F%CU%b7)x_PJ>1h19h zUpxdn3Vfj{Mb2;s{6szD7q%&bUz=r*i%ntxJ$5U>pFrT3qU_b4Tff8O9$-kmRU-1Ym_Q8Z^krg81~o|U_&FkW~k z(5cV0+K=J)Yd+kDGD-3Kkrt( zl*NDy#5eoZ(6uvWtWyLSByu~GS8e45LC$g4<~5ZJpDzcF-!*AjXJE?!82E7NP}E6Z}V*~~xHeZJM zham2z7c41IjB+<)uH#Hxlj)wnG2)2HRLE?SIm=VT-eEazN2^d55>tdy4@1uX`^k_m_^a0eYuY05}#+yZ#&Y6$1^I7T_${qEIrCmVAk7UPef6v!P6 zY*doKcjb*ph+P{8Bcb_?J|YT&%ueBh^LME&<@?>Tyq(oR7H28AFu*;DwunH$j1t6y$^7bXD>Cg&p7{jeQ>^ymb2lu% z-|1FWhV?n%=Z*a;k_N{8kojP#1J{$0OnYXH&g?MSGxHj~BmV4?+&4detu(d)F5O2> z)mA3#s~COXHZnRL#+8VS7WsW-) zNZ-)z_NamL1_}Gz<99<+G;tpiv`IBP8N^ITWgwwrhOeA|Wet7&53TEd2G@e7`SEa#w4DI3qRncC!}Uqa>(qK5XFE%|Ep_fp5GG;w?Mk2Z0rh=7%qvdu$F( z{k{lfBy>EJo_NUbT-9S|%z79}{fE@!YdSejqsHNtfCG|x^sk0LXbm<$j~@nXJZbRO9BMFyyGW!Vm~3y}Mt-=ZMl^9Y-6|c#bH)_sMeG&&zZg@ zYntE1KiXyQyc1<-s$2MKGaCzu-aJT14Y7v=;IQO&#zlK)fc`Pu+q_o3Jn-JJq)GQg z>lvQjPCAxM?HzbE-u}%00I|)N!e0qXbE`CRYZ{~dqVd(fR+REjBc8*zO7zP=0^2;L zWQ-{P0Dq-(#*DWWd{iX)Qo2W)Y2G-}wVQPQ%)GXl%I_*9JHqtIUZba_Htk@Z-I2mJ z?!=n4@yp;oiQ-uN>#Hc@x`+`K%unS{7IVtF;PNj@x z@<HOJ4m;m8~eWS)9dRJ=C|6xDx)>U~?|pNBeS^m0hBKp$>dnGr@n@~iwxm(F@1WbO;p#9kprc*nU4UwJM z2aa;OmZq-!<=EACfq&V>gl^o#Pw%!6zK>YsvK)VY~S6 zu3cHUV`Zm9YbgXAvokgc+t_1(d-6D9Uq2U}J+`1^X&^J#RJ5 zYhQ9DeNO&XR(z8hq=i*ReSti1E7$%i>t{&th5g3=0QC?%lb=N=wP60odILr9cSO3s zB+WgrxNuluOOo4H1MZCA9^)CV6|+4g?2litgscE@*SR#^SZ;*##yw3-6q{Tw2{Y03@HoT0$Ag4BN-n`)#sWO~YoFY#1+? zeqF}|k&gcW(!F=%UYKosy+YAZzV-DVhdeoNr&);1 zYNrEn+;d+g+I&H8fu9;9)UK0ukE{OfcMrSClmb=HU=Kol#d~ajwJwo0yUq5PRPE3D zz&Q2Ac15MR;$mskn_RmQe$rYNk^cY)z3iH|lN(09d{P(M(MY2ql=d|*!JTk;ufVn! z@G`nxMhPK_$?y8+zFGaK{yl1cAADJB;ID^P&37H-fZpCLfW>7HBP{;_UW&cX9<}vv z!H*4(34A`&tRXG7))2olTUeDsb>p>r!V<5LDjJFvJw7X3Lkwm*fCgInB2YUI} z_KE$oVE9uP*mPk9=B*+5Al}TwImT5%WAp;Or{kZDBk*s5H4FQv*tXC!u;14M{{Yor zF8=_*I{yG>n~&N*;?>`dJ}IxAYX!)a0Fk!OFp!m0ECCUyQJiBu1IBC6lh(-dDJZDA zli3}2!as(88U8g{S!(wBiL_l&9&AWtwu&geV1O@{Tt7pP)YqfwpYTmDi5@Ii503sM zUfN}tvT33~a6sU^tbID|9M|2R7Vzbcm#4=Cs)))j-4Ddkulx~j z!?Ly5yYW|yl1zRuI4^X(Mh;RCVSzG=e_+4TPa z>s9M$<8%9?wQ0)byL(=nf}RMBpxC7AEiXoM>Lv2eJznw!*TOA84HdMI}?HU*CqQ$cz)7td%>DD zr=9joon|f>5&35|-G0~lJ@wCmTI)iICznsSitxn8JH%`lh5rC+jE`_D z$G$E2^!SIv@ap~;mP304(CRj%N)Vg@le-)q$J|s=YR64PAogO z8%ljbBQhf}0arUoBeI>R@UN&e0}aNN36EytpmpiRd~>UK=S=;gyc)MQcPnM8TO#?e zw7^ecKMXiMMtUBGrucXJa!c@@>eod0@b+4Bv-wc!M(DM@&>U`d+lb#Bka+Yp*B#Fe zwFyosEz$N4sL5|?&$wVOBXO?}_*Z_%_Mq{#wW}7lxYMmCkwM@}tm~egN|E_jn*4eH z0D_+QS3Mcv@$Xxo5;b4!&kNj5aOV+5%-DRK0iWb5FZd+Qu>SytW;(>N zJTmx~T))&oEJ0w?Hs7bpqw=m?#jZ;mW$Si&FYT4CHi7VWS-Ayq1+23ivwXo&o@?O$ z0QeyvizN7sr1+HG2qaxP&f35_vA{lT?&uGE7E|lZeR=-?1v~Mqeii+c{BLjYfSgTxY5-vCneq}um_}}oOQtSR8GKc}Me*0exrK$wOE>SY?LZz?$OMwXhBDryXOmuzSBU=rmu%q2 zQoL0~^FGRwP132zE3{{mOfFI%l!2dfQQKauz!Jv;q2Jb)?(6qw=I`D6SGl?6q(vd~ zA2Kl7JE0gmus712* zL(D3F;6|=2>m|WoFq|A8o|aV+02R3Z0DrHqYLS_DR!T9z80YUAv8GvtjAH~gKZx;9 zneuRsdT>OYOe%d%?WBd=sG(kh+$3+IXjx2w`%i(K^++LQoP`x9E_Y} ze>D=_rfOCuK`B7v64`d5GA zZD;KE(vZae0CbneO?=h+N?%=g;@eN~HjQ#*)O<~JAf7eDy4vn7BanClqVwB0&2!b2 zk@b^6~DNNX}N;1$J0tRUi;HjmOltHPn25{gQk= z@wZ8zOZbVWMSrK=BQ4Bq?eqF$>B06OSHJih!xsJ>&~2?Wq>dP%iDN{M2!H{=P&fj# zZZz2B-{uU+I~VEi(z(5!ht|?ukWoKAv@h6G$KMAo;{O1Kc=*NR-8#w!U-S)j@B3QR zC}k&Ll?yIV6~G{T+3GP}#+#u2(cWF8QhZMEvlRJmW={{46LdT&kc8-S&wPw@udgn= z3k}39$ayD#WaIq*0F5%&;l;c&Bg$CtK2YF-eKCs7(Nf%g&YS2z;M}_8)-WFyU)x{L z<%X4^g`!>EPTZ5n*P8Uf3bF4!0i|mi&laK+<{+9i< z3timmQY0}&9`fwW02s+9(!MVJntTxd0JMkgMdI&>z9NaFvGD1ONYIR>@ozR9+(@WE z!)$ohJpJN9$sl{b{1ivWH+l!`<*a|gIkWp({{R-2O7n>0GP?y`?A$2NQg|4vKe9)` zi9QAV711;eLB!gc#@9NWrclOfxtPg2792Ou>@&_nj%ylm=8@#*IG<-tL2l1Z@Mnj= zvh3C*Y>39t3m!rD{Ohdp0$Hexub4UEjZxE=E(ZJnf4#`7=V??MfcM?s@~+se50I0) zC4qy+RY>Wc26>?(K6>C|AMEi=c}LyjIPTfaPq%qZxGmFwaaVFjUMUF}?a4i}Oa!b- zA0IC#<}|klZNl~#?U6{Erw&6m%0^E9zSJ=c5f*_}m}HTTPfBCC802M7KQZr88Fo46 zB#a!tPr{>;OiEXAB%F_)qy{iPURj0%9_N~2!#)=P5$bYiS+_A8@&-sH`kEnS`OC2c zbvwBqN*E#;8|U0W04@dz;M8}DJd*FhZ}yKhJIFG{m~qqR^ZC^o$yl3neeRz>YRW|!cU*4!y*{;%bskVC!ROMpZyPF0F~I5b zR#nIa$vw}lVIxEUPC>E0W?iA=ai3gttoxyv7-RvCIW?tvqBqDVk6hMl;H1aqBzkVF zWLcSZHWCQ{bn0r1s0ZC6cYaB$x3UEccVzzny;;{x$_COh+~mDxS~*QP;AM+*?kjsw zY$El?1E}V?`wX@>XC1f|zhc`}fBMx((VJFIPTqUxsIG@he4qfI%vUw1510Xy)3B}W zI#Pp3boD8WW zu>g)LgmMPy)be;0W+w{#X9tXsD$^vqgoogq0DFp*%d%xBJdc>Zodthd*F&AKvw2X33AKny_vEXH~y9DG^F)?HE7RUr12lA=oaW3F@1_uWq9MdG3 zpDI;JIrkLRpUPvB$7uBx4opPt$j7J@rBp}z(%YA>0)Y~|nPAMv0D6v<9FqrN0XQR! z5y7OAQo%t7p1cleg@1O~SEmPC#d$W6XFl;0i^sqvzA?6XLej| ziWLnb9>4+k(Bz^x)0EwkJyrE2j0MlPQBYj#NgS9j&l%)?HS}fr*QY_FXwlfJp)xeHMpQR!3}=zo(yj`1J_xt+J89*$ zs&qb{PY}YAf#(i-ki&|!o*+hG%Eafs;a?*+fxl=SLU{(8t!Nfe2O(NmR#Fi0xxfSF z{w@wV$GvnX!QUNpWoVOE&~MQQ#E);C>w}!G206w#>E5qf!Nx~JQsYvdvx{FN3Yk@S^ggSG@JivMZUYTOo$)v(@#bqDKReYU?8sI310E_vq|G$|Yt zr6@Z|8`lFoGja75M(szL^Kr+hsG!xu@D51!6=N%Qg}A{yoCtp1$pJwe4r*P|Rv^Apa0fZ`M<73vmycuGaE* z2OpvCFl*5yxiiLa-AAbPugiOXiQXaojWmA_c*o#ohpYIf!M-Q4H%V(4-y#BctZKxJ zV=NbU-RX{TUugc#zqV(Ezi2NDSn56)zf_*(0c$zHj^^3%^Tz1dA(VrWTH*03tU|sS z(|725pq0eHAp{@1GAiw~zH~pkB%JY*E10$M1Mp&9`8*Mi!nAEQMUdeeZZWtJ2Q}2B zb6J{FP9w?f^%YWCPUD>LGt_4lGTp}^Z1o%w#WLbV5e~UM@G7?=%#Ko9W*e^{k_|5M zR0VDZdN8P-br>LRUrsovP2f;@=Lb9ro0eHyfgFrC9pLgZIQ(iW%}6c3%=lr~<{Z`+ zh&)pkl?ycPssPVyp7^hwek^|6*8UsT{{XS{ODn7WPG(rGZQxDsD>=u_v>l7nllTq| zXDX^YmkMrs9<%XZ;&fUigTju}U0fe72x1|mmCt2f{{UWty>mYVJ_t#s>xaaiI3iyV zYAO5F-maF4d05cnow*}$>yztOJ`{W^y0o}`cgO6vn)TykfB}xh5B#%_JqP!XbDyPp zt&OLV4nX7RDpYyjG>j`(vgC<%A;qW(k8VfnQTba`G01FSjE+8)G(@UnpMIQDmGfMT z_VvwfaNOd)BakdziRDH|BEK>}Xp7nWSNm(;MJjpLdM1>LGbkHmb|)&h!OHQwwms|g z=i($E@hOynkO2VT8vMKQ9ES7uxbdXZtjc7%7QwjN@+uqv4n}h4u<7ewel`22t(L7> z)cC8xiQ=CIUfM_-H!!jfm~cqr^~E0rhKu4|L4V;Sx0gooPLmo(bawed^dj)XA1k2a zgPeX9-Dp~B{{Uww+C4`Cs_GsNvb(rvxVBdkjjT$H;Mbc@e2nzwxs{Ebf5a)ESsRP3 zNm522Dn`o8M?rvkp7qQ4E5p}19k!u)tOA!>#mTsM#KJ=o;|L253CARX-lmV?Zjoaq z>l;@`$UMr#aCjV^2e(6$>sz-llW(|_$7~9^m3g!?rAv_WKabK#ej000+v9)PnMQDW z;9!Hte)Zn`HPeQl;Tt%B3KAp$C{<84j+o$A1@ZFPFZ?WQ=Z|vU-9ZN3!8c|_<2XK@ z`t+|w@VtfXV@UJ0aHE0JvA%}#)f;w^mUU-7pbU@JrUP)v=kXNC0S6rM>?%Tb2IH?z zl!!Tx9e7H!C@#M^!+R6kBDChuQV?-UO_&wVt#TLZ`xoZBs6_8bMKn^mf=IA z1Cm?VR(<}B4eFJWHGB@>8mP;Zchbkkel3aC&}q7Vi1kBo@Zu{=n-8?en8z*hf_o05 z`qmbU`!;xk$5)B=i>vEhFfrUFM2dMkU__h_$1Hl|iu-O)0odJuE^VTGobrlmM^5my zt&8H$2;u{t5Dc2v+rEZs32bm-{Gc=Bhlbj&OD!;=JGf3EO?D-~3DX zg#I8hh!*Z4Xsia%xsVbM@nnPfSD|>%D`6&i!jp^-O7s5!_$K|^YC7kQ?$4Ofz4}EN zZUjL=$^d`bEZOgx+Yj*(U-(it{{Y~p8kO?=0=~A;ZVkP~?2*8YyBxEq!S?38^Zp6* z;1Td+;3tRd{6jLW%ocIWcIASHk-m06hH>~;fd2r&NOc&r?}P&8_A@MSUPS&^mapgF z=gZ{ry8vgkdQI1fF8odK=i&EXybF+ARgm5ABA*2B>3^Ecr(Gz;g1dJ za_TTzK$;XnYI=3uoz!+I2#z5XcH}FvFU|7-&U#jEa=SYy;b}^rGgp47 z{XG4jzi6!w4SR;fc@6FvB9VZ1w1!8D!6($XyaLGd?9j%h?%j-3VK!T=HE3>E|X$G==)dg8g} ztt8K10QsrTKQpQQv$Xm3&w?7wt$}fIC9~iH2SK0dUQ7ECYpdc9*~i1r6ZwMKWwmC{ z3{qzVjP~@eefZ;IF1!h-iFajfpP(5(DX*Bn;GEKv@H*xQ$uV1Nm(j)YfHwKNxE+Q| zb*^kmx;?BOuxGM(!^81wb}~aU?pFjJMsd=$@SRx6jFK_m1oh^=;+w*- z$iOsef8ZjL*TN84%bR$|Cntf{wT)>`vPiu1;eZBoAUau7AdG`MOgNo2RI*lHoIGNg4LQtPd70?J>a_&(ff4bH%@5 zEh=;W00ltRE-w^G8fXo+LgV*X+Pn_g$mf&6?O&;{I;0VWCn_;zv@QO>)5BbM^;$MZ(I-yj_1| zC?m4{le}gB01JQNO{LA&qPN!f5C)CN3h=*lBirAuYvtegDTnO&;(vzPmYeZw-~+vv zk31SndGUdbPQi&X+e)i}BDMkNkXJpc&GgTSJ}&y`otHmaGRc`H={Pr{L1>t;w%AE7ub6(LM`rSsm z80}&G;a>y((toj!jz44XiSv9>{fI@?#244AKZv{{w?F7Qjkq7YduUI}laY=A0PW+r zKKc7De%c-w{h>4<`X$fUHH%-8`$@TFTdOHMt0$&G8R^A)IBaBVt@S+m_*qhSTOUBe zLX0DjTc5l#X|mmkmC+f#QOOQC`c_OD__~A`TjpbcNE}tWd6Y)s2JXiSIW^gPoYpN{ zMpi=Sf<^({GxYsww_v(qi6j%zhv`j{M~z&t>C^x*^`tYFZJ-iJ^py7yL5S^=}jEzYu;W+d?&O5(FAtYbwk38ys#$RtFg%@<&t7a7BDW z@pHjmDgB^64S1j8KgCHdwCS$2*)9AzrY1Jnte65x2|qC`Lv-vo-~;+a`w{rT{CoQ^ zcnicAv8SJ^XjXGf5kL^j5@KC zj{gA9HE!jixKXi#1D&UE{vHA_!vE@KX>AXXf1Pzv+bu9ReQ#2!Gw zz~|nr6MGR##1+Ba&-Z}MAac7)vv4u@#}qo^ML9c^alriQINZz#Y=OrZU(fka9S5by zmk=!6=bW&on}%bA-_N)|x{zbifs# zb1{+}qn+oF3sw88Q7Z0bJ#u&zQhQy@LT}neI0pyxq{db^URA!wbz|$lKVEAK#Frtg z?gUIXvi!XN09w-2r#80x2JQ|rnsirFG!6Pb92a0Vit= z9I&U`w%PXa!Qk>~zw2QS&Ie8hYKl3}+A_J$J#ml9p28-UQ|72qfuF~(y;z8C$Wy`T z$oy(Bo@9WrCmnEe$Ky`REQFE3$EPNp#6>J*oy^DP>NgIw$%$D5DQ(1b$f+k{tXq-~ z9S8HMm=iE0kfV$M4k|&B!kAD?6UjKpq@0q#E0xH{-W2GQD%@dDYzmJX(1`)yk_ZEe zLnE3}Ndq`ubCFf2W@H6elZ>2^R>Evj92Ge^I3MTIt9dWERzTQ1a0MVBX!4J^o!vns zeQGZ}A}B}Uf$j}hk~Z_(%*o?{f!8%&c)%luTpva2Pz7tv%(!F8;0%mbZNVX3AE^f! zApSL{bsH0s7#tFMb*%e7ZjLY)D_ii{N7&tYRc;R1z!1t|71NYNB-SUGNf@&5OE&z*^KNhcjS9M$WN7-MlA@&!@3a*RrjbHL-8#g=5< zpfQxm89t)3?*?V$oP9-U&I`%!>w%h~A{LZ}&)@}SS~%T5ovcS*`)gv*?&JfGpLVe< z#~X3UK8K3ev-x)LdSmXMDWgMoPn5H%=OY|#t^F_-A2{pR<>_4hmcS?>bLsN*t<5=e zz{w}R)7G_#oQ;bzz~gBnkKy&Ly8*T?R|J2u1!P$v1Z`8>_;{^LKyknaJYxr%=!p#1 zwU7V_QbFL2wWk9B2g*)4`?Zg1+avqE`T0$0M8S{%ojPC|)fuw%2ZGGJ`t9vjVgvz% z$NU6UJ2n3RSi5t()lFSgDS~mk(*~^&%Mna`-HbZpKP^eSY5myF4?itdNW*eJhmX2y zR72(v2g(OL9GamPQbI`~ai8`@SivqfCj?-8pj9XzY@;~zCkHsIaDgf_1?oEB(@Y+O zs{U9iK{z~Rcoe>7(aPXA`#o_?-l#@Ul6d7#KMFS_jCT$Q=jAn56@@Rb=LZ5Z=4eNH>pf9-|)Na|h?wbXR)g)+kiwWS#4 zc;$eyNg2Vw8R?9Sj+m~BP^6&h)!83Ug2PdT6;ep`zkq)l^<7R|jT7Q;+1FIHa~e#E zx6axDWsyMIj-`h}Ln%@_f#|*|_@AcuPfz|_)KoPz|0RDcp@mGU?Xn*)wQ+RX4 z-Wc+iQIhUEE9le|63F1HhCTMN#(f*DeL?Vl;LO^j_WIY3H3ij!NY^&7h{=u}#~>DO znBbGg0CC3@>0zEF{_A5o<&dvGX$S7GUx*$n_`7Yl;ijK1ooy!~_WA;<6p_lKV4Q+* zKQb#r!GE#zbKgmM@fQB`UAvujx1KhpF^p{ozaLI<*1eO%nlv`bN+8KxACT7UFem)8 zPzM}^HSgiFnozTztnZ_Pr$JgM#_*5Bt1k~)$7iS8M-(wARaA@xLFrutJ{^d$FAx|w z7(q&~&n40r!icvG-!D;GQ7Bd?AMbE|YuTqtFjh$FO4|`z=uxx$v5a^522D#ggaV%| z4WMz985MTgW%EuER|Brzl^wRZ8D@`0P!~Xz{S|7xH5-nT7x{bD>V<7-Z77o*ngdSA-f-_t4d{5JKxPt0; zmbTlQ0Lsd$#QG9?*UlfbC+vT%_#W2(09E~-wR_DcRA>xBHCB?{mjvL$kfih(>MPFw z0B29xgTddmlHO=P8g(xaU3ia7d`o9>akkaepTBP&TYyLL65~9Y`Fuqxm`Nzj9xY6n zLEXzk?Y%$88g92cE}wa8a!><^onHg7;Pf?eJJBF4Im!O*cvY|b5wF0y7l$3b6<&CQ z!rma>E+N%4``IFpOr)~3i=DDAa!N2NbJDQ&--$mGe`5PsihD_UCU~Fx68lTj{wDs;5_nU@5Us;_HvUUU)>uGbg9I=n+d*ahWqa`S= z$L06zZTo2W@4@~Vy|DPTrD|R#T_X6|PHh)`{+_`>K4513^8CY`?gu?bPp3Q!`*rve z#&Jq?{c_gT?cd3`is*fwOL;i?WJxeo^u}?Jc&{bXeimB%4*j$|Vz&Y-Z9B$#WO|Y# z?mlJ2GL)2nc+S_0IP}kY_Pt~FVDOj3u^rcl^gS;6RX{|tT7vlJ19wsePX~(kFx4ei z3Q3+uEy9&XnmT(w+84v^Yb@6KorI_cS&~&Dea}2p1NNEl-Qqi2-@zgP)-Pua(X4VsX(L9U0fF-8Y2X2jcB?J>3V3D8e&X?<7>pxaNw*vk zkfdiA9G=`(_o>*yRHfYLykYxk_(#FId7oO;p|@1Ye=`ZUoN^fFt_FQgdDgf800kP+ zZ>DIx31z8kQsChsw<(tX>a$=m$EJE$X{Y|f{t?se%*ml?(mNl$ENvk?f`0KnmFT_{ z_&1|?U&>88O|pl}ZOE~}7jGWaa@3Heh@_T^=Ysf$O8Bku$>CcFExa+N&V$UBQRdCD zhf#tyk)N%0U$c+wTc!LUyZ+SF=AT;DSeI+Nm{U85!72yc^zA=+e*wUM;i6p@J)CXA8aL*YlE(SU- zYxPg#HPTpkdgeeCRydfFLB;^heo}lT)9tliiQn4x(ZaG{TTOngc@a>Un#rP z?a&-xU_SGo!A*J>g#b2@J@qdNwZH^u9{N@`8+^CGr{(bAxG&B&# zilZ3hWlcVXy^YoV-Z%0800E^u@<(6xYAxHCXYUVcnG|FUcK+=nF&;17@-j$2!_uio zZpm_Xf>*yBRp&SuBlPP{Snx7H&-=6hM-dpx@<;b-WP^e7;Qc9xF@kV$?NUVBnDN2y zw9o@&Y>~8bf7z&}iJ0!m811*MN@5E6#~uDt(wj2ioDZi4fH@C{Qkb-9&H!K!@b#`I z{t2Y(ai(~tMfsiec>~}dkdNW#+Xn-In(Y1|KpRT9<2X`!A4=i>0N|Psy`8U&BDsz* zMzbV=mnY0u85zmyIUNTk}1t?o~_z!<3pua3Gj-&34*}x>{r#0&d z@Vi{`m%z^m>mCPK2Z(e#STzeZm=OfbVG7Z{IST5;anrAA@xS;fz9jf4@W{e5J>)2a z#t!z~m0S`5$pB#S&wBfl_IJ{jKZaUGw9)0_w243|oDhmL!N;w3Npom;^=9eQi(T3C z&w>8{X5DY%mxp{&t9(k+Zu~i{_=@H+YXprP@>s_JQxO|U1n&&^{{U+g&w(GZkB)SY ziaLh5@uGby^GlBUOZy9J7@P;4lrNnow>g}e1 zx@K1k<>QZ(@z?(VuTrTand2p9kDPon;I9V6>b{F+XM;gyE8}@#nIQpzA4skE+J=ArfE$&AOoW|K*=4sug}jP{6p2e zLGYvEmxnJrCGiJN)BItpokG?tj}GL*(-aP>+qRstbUwBE@2UJQ({+ou?k*rhG!5n} z7|usg`EyNggxXZXF>_@DGZ4%SJBj=aOsUFF=T!`4Ix5O1hW`M;GJk0ZelmO{(tI-y zhWuNi-S}F{D;tS5J0Kz^B~$~>Rw`JA1S!EIC!nvP{A*=%r0J~MLp*bZZJsin2Zd z@sEmsYm5C(_D>FvhL$$b$g67$M{z3@+}oMlrv+%qTp?|YOxv|HW z$shi#RH|(~&83QrqT|TE;hN6L^eNr}xk_h+1U7ru<=4dQ_+S1CyQC~JN*h`5<-*Fu zVPz=z01o5=f1hgoRn|1%GaYk7Zd$Sp2oluo)HQ}-aF5hh75>M}lFcsa#>f?3>)T^KScE))#y z99QQrfUdu=e{KH&3(ap7Xxhe`HLsduB!^d4Tpyb|m)ee{v0C02 zmAK;pPpx{mXJ}mWana_SPc8Thr7!IR{{RIkX_cV4(*7ISd5)qW%$HJh%YP5be;WM< z@g3*cG?`fk3cG&j1XsqN@J2s{Utsuc;y)kj>%Uj={;f6RxrLOZVTe>aj(8X!%D$ET zp!{JMgFYSWH`B0=8#`GhW(nw|lloVSimA^w&r*#(M526GqTVOP{{Y)_UcZ$sWrxD{ zzh;V2DQO~k9ll+kbOsx zY7Kg^xXVKb`4L;(fJr>(BEGD(x7gVnVEm(Pdzdj(DqPI~k_lIYQn@veovdgp_qm|u< z9S%D5KYq^wBx=sPcJfJ6So+U~A=fRWONf!9ZU`t&?v=FZDHu`2N}r+TpR$kq6qCSz zwLOW_^`@7@-X@7ipGnlA@@5z$5`nS3ax;w2z8vrI zbBg2qfAFWkUM{$8f8frs4}^6&B{Ru+qgRL~Bz8 z8lLnS_lz3s7m2kQanz70?Wm(}AxFwF_d)z?^Y26Wlks!mHLQ?L;(rTxxd@IsGjkle zbE(NLT$1~S%#e3=$6;M>!|&VU#1{IYvG|qXe-T@=02c2|hxP zPHxvY<%6jOdmm@Xsc(=5U8{_iDk!+R%v}LJ6z%AL$*+fXzxXPKkEY+>#&mBK@3NB& zCDLbyE6#AtxEu`n^V2n%r+>j<^e+`@PX7Q7{3GM95nZ$SX$^*w@&}VRBh350ob>%G zRarfZ{fv?KZPomCktmH7NZ>BsI{j-OTk*xNn`R#7bPl|Mw0>C4d`UO$Y4N|}#~w)n^UOUtNT{{UiqC)4Ng2C;O{8F(WNYp1XS=AJ{q z!7K8NpG=-B&AcP~1X}p7;%q)J{h%)HJW;AZrEOxk1Y6sNIb|rM2?4+uVbB0`UqSpd z_+O>?V@z9pF4Em&Va^qc6V#R@6yaQbz` zhDaGXB&gkhc*b_)jGX4JBzoB`OSvX}vE-QT#>K|djuQj<)26a^hyZ|`i~_s?-kB7_ zOI0N~IXDVW^{bXhS`gPmaSV2ir;$}_pFmFbm@LR0cib4S>n?j$M>>Sjda;g9mE&k`BO~HyvB3S zO{X7U%7C#P>EuPYf_HU01~FCs)U6T;3We%qGwdtC zAmWAw7l|bEk(i7X{{UkltBlv&+gOqnHzF3~3}f4x>^0bmfx14RgYupQaDFt5{gs(f zSb#^|JXR8AHFaa+9}Q}A>R<3!OO-_P5OIZ>#tkIblH_Ro*L-taH_PW5-S_?R!l9;DG1lA1UDD zu4`Ib9~+vkTJ0i8Wo_&kFmgxT?OIR_E?IjHHs-T@u-6#cI*k0aei=Yw6asn?wE9-a z^4Vn=ZDLp)@IeEbipCO>mSy|hPQm(9VV#_^F8(>;c>L;U4p@K#U}NqPie#1{9#Wmd zJYami>A7Z*V0^uf!JazOHX0$n8D66Y(w06U4T7Y4E&wzLYp!A$1h*f;IjH3f`~>6u z+*HvJ((P_Y<2lVmHz4i6-Ny)M2FTTzL!G3yf4kC~Zs&RP06b)pojIU=@(2ns{nPV) zG?6YRI6<@z?wUcMmuPn#fS&o=)}mA@pt|zEDEWA)?qmj13h)O6DfOl~RxB8CfxuJ6 zCNi@p@52BN<>c(^Ri7b%Do7b5l@%+J%I9D^asb+Ss^NDNo`Ua*>E@|iF5&*yT5Jn0$jBv9`0X7=Xa8G1KL%_mdAW>`*#& zQaP;quw_OAf=@p!VIxFl+~ATF9zCl*@Rs|E+z#vSSMC)AF614gWPGQCS@%hh!vOC8 z0A%r4%R@qy$zd?Uec{IypE)Y+wMog(0<>j+FPHSkO3k>!NrxExD<)Dn>lFdV11IZR z_KUfGL!NMXHH%>fC3`P#0pdS&lG{|bF0ZuC8;3_dc^T&;BEL&M82B~3AEJvtv>D+- zSsB6HySjov=jO@j-xaT=_&U!_l(nQ0As_-*f`897t!V&NJFo#c>T_R1fXmhrI=i#J zjXz}@T%H98yEp{)=coAe@{{Z&T{imS#6Y$>iP?$WI0}(+Q zZf1EHg-`$l^27>NtH%!qIdmFVJzK_~8MN;VK_qic6I>$iDZgn|^*QJ>-o9V)kL};$ z--zBO)HF}ov%*^c0F3W!nGx z)hzU#MVehd!_nTzfx#@TCChDD7Xu2h=Z;Qm^sC`t!3_)HpNA~;p9kr7T6Ujj5Q++Z&cw*I^ zuAz%P3~)jbTO9|OYZW8&C6fAB_oYi|k9cmDtt29y-6 z2qZZBQh~w{#YRKK4x4O>H_ILQt zqeGp7TpA#heq_nZXbnoUOVs|r;PNOZFNXuo-2sVZmguM1CfFa zdFmPK6h8PuWLIO9IG`U~LC6x(Y$G*?zG zB)6S+Mhl;pzANJz<&&o^(c)q#x)bs~1Ng7-G5-KyABpG3o(Y{|_x%CJ4b1RCuB0BApkns>zC z0qR;$i7n!~vcH9+ksZklhqyh6>JLyrBECrdfOY*#!~PD|{0HMH%(tEf)n>A^k>zHR zO9o>0<%@FLL1^>S@@b>Wx$;kg^&j|EU+`1U3(VP6@lKU@XOEj`kpjrL zKI$7I+mCP1pR*R#mgJQv(S^a!75U-&SziAD!oK~bz7qJBSo001iY+arb0JklpL8cD zr}6aTJawONeM1_faM0KrUj+e`ld*_*{< zP}->#n_M#zNJAgbyB^zXL*NJ5?miW0lWDGxX?JNH@Q~aTbPPY8cV$w%S~#;<=@}iB zl;mLLEEk8&uE$7G@60|ev($BsWrRFH4lNDIlv<6gPq3X?`;K5~Ki z)UOaK4&~{N{L(rrhWVEy_hZPa*9`lRHyIp!$20+YDNrJAWj&5_%}XmrvK$b14%x}7 z_BL`!ZMIOy132Wic^~aRtNoYZzO+zbR?bp-4er0~lHUsTXaU)1t3pgzSbB1JH%n1Xh z-snjVF<1Wp zv|0&{7#w5xj}_;gja<~52d@qI)oZp<8NvK{=BrDqCO~$<&6{WSr z%v&U}J68kKjQ(}&`a6SdkU;+cff{VNY-+}x3uAUM#%g`LKK3{s^DrB=prM+4rYEw~-WpZAS5ZU)i4hVH+3o+ts&CI}>s=f5>#7x@Np z^L60Wb&xce1##E!8kJvY9OUQw#(*W^UmS7Qtu{msxi}qtX-j83j(T!w91^{bN2#C= zTgGv$nslImM$$X;UU~lj1oFFqJVoPpAapF6!xss=tJZ(unf^7G#$U4MgI?{=nz~dGI*D85WI&9hob#1A z=dE{jJbXgtqMv4cE2qKc-Umbg9zY?me;U{p-~dAdwQ@6@DfRw!pQOpKZUqQa({bbT ztL9cS9j}!mINo?BtnwvrOF+&aDp-8j`G5n~uUj!F;oM=4a=GKyqqUR}0mwMR633rv zzOt&u0u?#V-<1=kuE04W$H7NUz$I(4zq2mf5BD!BV#(FKAYjqN_aAi z%*_5;vuC1!I6kF@JJ;xMk8cgNvGe3*hiO*Bu+JTc>0g=>YPP=37CDb&DcMk~Y z5ZJ3LoxWu9F?BiXg;AVz$gC#yN2`~^SwAD&z9tCa@P*Fe2-w8(dSbpC{{Vt->k(c{ zO?{>Dr&IeU!~ITa8CPYql6Ra8DX)sZ;F*?c`ah0t znkeIU*JO;cO6&^(mLD(&g5HDLx$!>>J-ipf&#g}bZv>yMITv!S?*9N*bU*3uW8Chk+NSo50tc&=0CB>9_cwR3JSibWt+QV2Y^9@wi!FaT7*1FsFn zDo7P$MO7d$8@Xf0y+VxAN=RXc;E?95%#PzsisggK0mFZ_`PMeG;r%V+KibNhU*-A9 z62SsXj*TVC@9JyATZ~yKDF*&U=9cY0XgIoO_mTDhslg%@0y27FLY?D z&O0;Y-CzC*!{MvB+xs$0>k}aR&|c1f9i=h`>>reo$TZCh{t3~e_&-f+J z!<%h(_fYXpmoB?;Jgp)&rFT8v-QRoVb}9fPjC2+3{u1~Rp?D`oTVD-n*0xrW0I3u) z2-QI2001k|2Bd!n3dQ^fGD!cKH<8i8uD92(dVrNt0XP;a62_c-dv?~~4kjku2 zYSq*HB^+)}roBq7zVVV$#SBb;plIgcfX`B>oB*xHIM z;vrUCt8??7orQT%?IG}j*W&kpwQUnz0btbaq=1!juNFrRt&D;j1RkRml~~={V#;W2i-2oJb z%m9pZ%V+%YNfWHGA1Sv1^#`Rg;_uBEl!70FmOU!CxgJUKz*PqaE_2e0fpwWoi{;=k z=NWEksOqXzsOgeMYP?s1OO+~DEH>adIsAX6NM;f+c+o5bUj8LPyP!tVDQ|q@;oIo zuo6jwvg3sS^v?Fk#t&bw=p~iXwXpKAcc>!_aaz!NA0wS5?er&>*?2LK2dd|-Neqac|3f_`F<6-;}+swk%GizXNrby)q_Ut}g%Gf8Kl*p6_+Za1Z0WyBRJf6_n-#OM2^L} zk)Hfi1;^c8ps2~td8L#CAZ9%V2hL4L^6eqd%tm=)IH_Y9BZiFefZs2C3asi(s$&4C z;PPrfcTD+gt^osa>r8GDO0XiAteeFO3FDAQd=Xj~2;O6I0Aax-^I6)2 z!^`>DdVTZ7VIxFPx?owimE*rWR%OhpKu`wacN}M$w|vFH`Mc*EjZwJ4&pfH)41FsZ z8bqO~Orb!^`ku8w&a$(DrFN+Kxxx0UH^(e+LB|-$=BdktharbNj4|n0NV^p80cBQf zW2bu0y?n`l7xB$rxRe#ckU`HGJXU4I!DZ`^Mt+q+iHgrvw+G2@@T z)K)c)S7-$OW18NwOsU(~9f;F_QUJf(vGg>H4%w@887$Ucc1?x$F zbMn64al=)+X>)R=q~K(XJy5hI2hF=4xfP>o!bce=kg&w=aUkdit#=bY?#lvp_XLkh`S14a@e$I#3hK#j@+6nb_DISy23C;m;GR3w zNt@x}?Ixmg-|$X<3*317!`kn}KNAo1-xuG=(5Ko2s~xmXQal`gy}&sAN&1gP@VT?p z!=M{uV(Q!dYmxn#d$Qdt#(lk_TxX^=quuX8|e}L z)PL|&4+Hov_w5o`=@H#)GN{auV%?%uXX9u)q>)!RA&4OHUu5{Q=*MX0GJfuQit!Kl zCr^itvHN#;<6677W>nB(iq>%Ct1I2f=44}TOCT7@KPfx|&xM@Se6f#4%DeTLKs^TPucoK&(N`yrQCn7tggNRt=Df%) z51Er~l*N~n+>_J$)YXaYPUX%UzUsdr+}ZT{Q*R{#A~G<2NUE@|XUd`QdXjs!aK9aV z1#9sWz*?4*tV12mwd^envAznrkU<1@7_P#5#kpohk=JSd76b6AceesvB1WIC(~wBb zM77Y;Eybpf%ir0%PQCaa@z-4N2C+QeUV@6Yl1U+EmdV-L*yR1=7)c|~rr!O2s$12T z(`=2F+5P^#zY6)=_V~UZ4S#CS32XiyMQuk>({Al$jnof0A!w&u5srsCjxoTS4>fgzcTb^Aqpc<~YOYb2UShHj+N?W|-~Wkbg47%c3}logLZ8;FaaCAL3T^goL_C&iBirl;W@LMzKF zm_x-PNUR0IqXdygSLXz>uqs=ellOq7{hNG0d;3cM z(l)*~ztXjxDJ*r#b%@^mB~+d>5rIS@{zAVl?ZX@u#z8gD&f84ps|5;D=Gw>KdSu&e zQ*p^-pS|l--;Jxu`B-**;-RpOwhXa29-^n6i$5df9Aj{7O& z?4_D1v?(IhBa$ci(8D6hl^8iVQ(tKOEAh-8DDW1WscF)N7nX3%ksvrOfxq@@`BV1k zyZ+4mpL}049#cxVz-^=x<(v$CNUv@Eiu9TE@7Z_3(Q9hr`ShDcnLNPd7(}4+o_PoB zULI(@=(F9+o$0%lKWps`{7>+2S+#8MlEz>NkYJL8ayyFSzhn(SUjEMB4`|%D{>+GE zxH-b$XY#Jk_OHB_4}^N~Nla`kCfaulkC5~4^sgWP0D^E`+}-}j-VpxLnWngg)uJ*S zZhfx65<3zxPbq%%iOpB;qWsUG;d1B;AC!N!LA6$8^AA09zmICOY=B#ZAcDktQ{>1h zpzsG=j%(ks^R1ZovAiId8wyWCXFGwm*4`C^*L_ z{3%;e+*Uc}JO({^HHqSX5JRTI5!`)u5J9cCZ!QNaKqMS7bH#i?`)q#EzBT^S zzi0R%xz{I)%)7ml1}!!sN6gvp-@ntEQg1|-th#YhyKc!JQLl|7NX{-mZt7eNRm~&D zQOuw-D>rSj4h4RB-26KD*?D0sRzDX0KP=)#r=@fgNFP|U@EJ8_ZFlf`oSSM9O! zFZNuSH80vk#jSXH>U6ai@cB_(KzD`SBU83T=O+P91ytx&rmo^Db*R^Tu$pZBJ)gws z3I=Dw=e&cZWNSYVEp+QSE-$VTQ2}NxAORQDn)w#X_VknERiqX_v&E(MxNZ|{+OohK zPOv=lEB84V!js7r*l6Fe+@BM)&$Rq>@m9U!Dd#?EwvOlQwvhrq)vQtA6(8+n`qsF7 z9eh)@G+~OzVX!LorSj@|7yJ~H_TlgqzrsHdXwYl6*Sdw>jLMN)OXje^$MAOqiupI- zFUPGhyg4qT;cXkmn$q66krvL$<#*%)r0oQq!OnRY$2`~RkA;6=e}^6sx`^qX7}DEf zunQzgzys6(M^EuJ>YfbvIiYxRB#%SVtSr?N3L$|ICu|H3J6CeyiPrukk3I3F96IHt zO}|!tZ`piL@%FKA3+NvSd}@5$VBCd=VzD3>><<8uoZyP9r~FI!jM|FBu6#4`R-g8V zD;r4*x<;X~myrPjCz0*%#eSvP_%hjNEU+g40mAhBs$t-}JEH3>2-|tj99HXuX*Kbj zkB=(f_)G6UF(UEriA|y(5cn^}HsroM%Xs|Na1UU>5%~IyR;-^C&6S4h?I*;L@JZcb zSb#V`aG$O^*XalRD~&y)9&NgF>^gs(RBiCfN@5FIL~sI*7Nzif9@8mt(E=fYEF^j|x zf-(*X&3(@&!Mzr1x1Jp~*=`E?es7kW!sj>#8SBk)zYu?8PY3)+D*h_){+D|se{tlu zk8+NO3NF<`KCvf(G}b7w<>pJ5$tK7+l7b&E6*o)O7#6x z{t3mPX>qvlF0bMb4nO>{TU+*cqHO0PDG5W#=toN9{7w5b`1`=j8rJ7Y@qLm5y=Gsq zU5pN@$+|Wq#FA+L01q_(01^1lQ;oz@#h}?6gn*VS`^lKBN;0jVo3X6#j=F`-_lk5)8&|Z~ zd@H3~%^=ohxPxrWk&O9JGMq4cADK^1cj zHqvk=u!38-<+>^XB4EltcP~Pq9p0o@oqo>VDZlY2!=e8G2^`bhO{ZVnY0%tC0DGvR zeTgF;U&MJ@7pb zuj^g+iLz{@EJ(_n^v!u+?0Kw1Vez-d)-pcJo2^a>0x@5?0U_>=fgtHRV4Qe`l>f;uPsNpeKUn6)7C>GOUWE=hM^z4R*~v z(dJWelw2jVKH$*2O>ci`7`1e8+!5vspZ>jS+1~F5Ym<}N!2B!o&qDa6@mt^pqDP`g zo-xy{NJY20ltXffj0O^%@5js3WcAH@u8;o!1qhbUPGRDI40w{#^4b-W=tpd_#TI&n zb!;&i91d|!Pr1QU1vT*MkFgU{5dfjtlRc&D{&80<^)y%+%Mb%?=1k_kLePKUq<#|C zV=Z%Ya*PSwlG~IV0(y`Jc<<8{&=2@1PlT;(<9q3KNM3S0ls0TyO!V7;N2gkR=)vJC ze<}4FY6t{z$0!AU=-xR#^>)hqu`MKvmEhsVa(J(kV8&NCUYaUz_7 z_jdHpe{7n!rGLRh{55k7PAq&`D$lqOx?F^#E`IRGLyiwhYN93J>VGNqg`TM!6#eke zIr+v&6{9YytpF;(m0W+U_RfDw`1$_;;G|w3)4~m|??M2!J^QA2Hk;f_PRj%4f2um{_uTq zipkeJTW_PIOM56)UI8)=2e0d26Z~8M0D_5l-pNc~4?Y-plIr2Mh=t6t!-gjxJ_!JG z>T%w@Z{l9F`$PWImaP_{tlD@BOOe1>?c@z{v|#-5DbFNh<>~8E>fd8(d32t$X)jaO zKj5Li@KYZQ{15QHqh;Y;PTO1YOM`7^q}pCAlf2A8Q0loTxjeDJ736=gzwF<4@S{Q0 zJYDfFNpC!JmxsO$c;$Ra<0rK77N*mi zqb!!uqa>x3yv97VtQkQCkMpmnZqXS5g`Yl|ADszbQ@utMVaZSC&p!C!0Mz^?s9HRv zB=+ow4mi&h@`vmJ7`4%SXu5xvw(a6eob5PoFfk5KJ#ZB9>t9EH(^}M?81OEos!Jge zT3eD=Bj!03^C$chX}`5R8RD%@$dd)%h_2W#8OR_L{{Ysmd{4s8{2KRJ^&Pj*7#okb z&r+^jH_d^c?@?kmL`xHq^r-;Kp1^hKTnA99er``s_PW!NgE`!OpEW8c2a}GysSuMP z$9{WI0=wXjcmtEVm7nFuuTPqq#DaMwgU$%29thled(Z?oD&AIe#&P$np7A0GtfZ4U za5(w;S4VdHQyq`L_}4q)B2A;OIP2Hb2L``v{sZWio)7qCrfK>-No{Rs0>vC^KvYnmU<&+f_?xar;7^Et4%9EV zzmu-pZUw+n3vv&y9lO`+wuAdiXnq;^DxM+N^$UAD2q0%?c^3hfjC=Iy-lDs0MA<8r zziY4BD@XVt;CZh+S#-%BHY`Zno_PrQ5D$L-mEpg!wvVda=-R)C{B--ZPZM3W+nntY zN1xrsJ(W%~-n^?%@g}4DcYJBJ@jr?!ZmoP3;j8A8OWz*f?E%1J)Zh;ZD?gWm-X>{}} zXC86@T=g00KodOM!6m+9$-|B+z0@J*R@}f2IC_!8G{j|wdFrB>Bs+?>PUc*8=}a~T zVH*OZ@&4Tr#B=R`zRqrPdzwb{coPs-0G*Hz)c^)GrNEzl#XWFwZCzYRL64?YU zWal-bc{iOO?%a+#k}EpeN#K#htO|~IZXDKSqG=e$2I)y-)QJU9)|bzTw>JPBVaF8x zTUn0Y2Aeo=q>u=%YX1P@4YjB-O>>ZWEaiVHnMp0pAqMt7M*X$E6YKsJ_>rM}R`?#0 zKZ!goa3!AF-c}E(+X8n+!9gv-`=D|O=YgNAKVpB|x5GcR$HP?DJP{?`oRF}$yRg0e z)z+Ud1AKAip$@b{1PXlA{;o;$H|Z*wH1AKnGvfK^6zoPm#e;Hg$L-O=?~ZCR+= zdmpG)ej{t;%Sd-8983Lcpt01HM1;tsXF2nEIsR4o5Agf`3tQr!fL{{z9}520eiy#I zi$N8jriyk(=_GdML=EB+p&^C!(%>R92%iNi(%8`4Rbn#aurFGedF4= zgYg;{w+@plDNy@^DIUk^UpW5J-?g8J{3G$J;r{@IJ`!8$`lh4e-Fh85Ww~w3X%Wnl zToqo)9CBci2JNFf(JH*9KXqN7X|||t3LtVb{@C=-wFU_`es%PYexq-asuSnn+eKRJ2T|42(wwf#BklD@LQT zGlbOjN26M-o^mPz6*7MKqUuR4QH#DY(Ttr%7rOj5vw3l6kV!u%$@2L5BOT2!8+hxU*u`vk zm&LQiDKQ2J0VsDa7^B(=i8k7$=qE+*QD>94a%F+mXoTx)J19n99aHf^ta4AE2qA zVy~Q*P`@zqDyrOUiC2(LM>}|@!8!LuGaTWI^c3Sh(~$h0pFJ=u zAR!1L#?#2oX`xwID-zxFk;nMb5ci##PV#n+`}*-r^Fr>BIc@mV z{7C#MJrE^v>vUKW7>wkP-gf^0CZjG^W%>EZ<9}LCvVdEJ0AnJXI*}=!(0bpHUo``x(tt4`@~fGK17R%O(KdCB@5iiT0mSY&Mr$OF(;?T|0gPBV^z zur%?!=NQNPHNB>dq>?!6_bQg{{R5#Tg1%Kf+E8w zcRY`jb64O+iN-@@^*cpSOzas`ljyxGM%@&JI3=(KcGieY(Ss@v8P84yTYw)df(ZJk z=BPq9I+8v9?@H0OazOccAMEw55t}SQ8Ce*(CwE>3D%3HNHUKyyBjp@bP@iZZ?Ksc( zYS;ytNF0v8Em9?x1ZQfJ8>c)9TU7b>usAu#$}lQ29NZAVU}G3x=T;D9cpl$&sURH6 zcqCwS=qef1K1l~XxE$uDWeR@obK7r9i|n8~7E*D>Ht;F5BvQJ7x;Sk8+zcqMng0N9 z>qofwSGGmCXj=B)%@MMr72TEu(e*`mlcG0xdQEKo;Vb~O@QaHvtV-?W( zOsY1FG2n1Gu0PW|T?{cvZ#+_j}ff*a@Q~f;kJ+U<$Pd z%rg1Hj+h+P7h{2y!C{}f#Y_&>BW@H7oTpwXr)CCEje|>LGeiywkPgvaP5Tgdkvuv3 ze0ZNpW|$k#4#jY>vM$x~?lzJRI-f9iJvt7j*>CMW*=SUcs42;>7Mj}E;E(M!;cpvi z_XfjDxDsg>^A;%)X^N~n)1v_W_#-*!E6L4ixl>YI39BA@Qi=LepiB0gFb9waZYyEj z!5JeYeJhFhdE!Xtwol>=0R%4```2YWt2{s`&V8%MgStLmO3X-Zx5ttQ&#3c@cvcF{S_%27m zAKKsIknop+{7CwDi0%*iC61+TZJSXTEPl?-^2vawARO`1zQlcHuC&bj*z^iH;=hp= z_=PuyzA{T^@cw4lJ;1m+Z?U|Qz#kZe%;v51d*DE&8-=uf_on~f5Bfb{J$CeJQ{RYFR9+@ zHQj*(=OQUz2JA*~bT=>0T}S zLwLU5_MiQ-d^=-d0^Mo85Lxvbhw`@~74spCt8xQ0j5z87n%n)g^o_r>rTv3RvOP!2 zx4V=n0WID|60u--0ychY(aR+&bZXUK)sJ@z7aD0Z!MqXsC~Lp9zlvq}kKw&{Q}D*8 z;um+*g_WuZ4xWv*4eV?-%+6Jra(Gknu*oOW?0?{t_d3nom!B3qTdV3e#r(vzwM4gv zgPv4pJaK|gu01}m_;sOJ_6Tn}x)~6@JZ6+NjRq(Zp zmpW71sD+D0r1>n$cQkGRMj6fz7$6bspRwM*H^dKvJ{;F{`w1*lQPZH6qVjes6B?7W z5=a@&GINUapNPIVxc#%W^zg@nztQ|DB&ID+_C(ty;*91PQ#+S9`I)iuw*cog^$&zR zIb-nm!j^h&kqX6cYZAtRSFjiyS8fh6wdJwo=CxC_FR81ig0T}P1mpNcNp~=cB6;=B z2Q^II?ov^HUin@>3azYNAF`H|3;<8v>0Q^c;#m3f{t64K{iEQHuWSsV@62|HsH?b_ zkyK+K`uZCB)8IFR{xSKK=FpW0y|)G_FCoEq?N+A~4Z=g=-9@ePfg<&=SvWuDwP3RHqHdk{#ejc13N zsJa&DM-xs|WwSm___Oi4>-JHx)GVAytZ2H7(!Q4@WHh$Y%5owk1C-oO)7$VhKf~|Y zhf4V4;6>CwX`8pdxVTK*0V1ufn*HM(StMh#KRG$Z2Q~9PtMK02#y_+b++PH=ol4_L z(Jq=BO+MKqo+qAFP|X}=hyhPv00iefkLcIz+y4Lrv+*y*JqJ#Ij@MWEexDpss%fzh zWn{-IEQ^4rc2CL=UfnCMIMp|-Zn`dpKiKk$N)xl{`u_l3&NJbc#*c%)vaf=yJT>sp z$l6VV9jR?(_YS1DQo(ruoDAfJUuy2OpZF+G!);SgXtaG`%E~$N?Ig}JMsOEA;P&Re z&hRJf0pQOBX|ciK?+J{|bd>+O2)gY-L#sEBl& zSfWaf2_b{77#x$|y?4hnt4b+BFH3*HIA09YuO{lY-+S-)9vkrA_MGs4#C>jkJHuMS zHlY|h;gJk&5g5o|;1Ev)1JrUW)AYOl06l>~2yu>s^skG5ZEyG_#;@S-5Xs_ifcmz* z;rqK0CDa#Me2u=+UN9twA!UaEg1tvxYl8ipe`}u}{>Teu;osXH%T&4W_#3VKP?7oS zxjTqxlP<^$VnvYS+CZk9BR@B7Cok;XXB zYSe-Dur0xJgYtK+;?#~=E>Y0hD#l69-}gpow=ygcHbDw_KPag0u7n8es@<{*bgv%$ zp}%Q88{qbn9G)bd%-2ulTiV;i(%f9OGlY$D%zcGrh{V&wMapi+Mi&QH88r$~yE~14 zRJOUfRG)Y$!j)jS{c9swmfn5J9e`dkRAgqpYw%C(X8 zY3Xe7YB#CZ3>yVU3-b~I-N56YT+=_`hMpLT8SXCpU*qd-X6JtUn{8@UF^9m;-i~kp z$pCr|mGgCT__;M0U3b{~Tt5cYaZaT~pKD+BCh@<+O%ujCG}fBMy4|d~+_E4!&VMTS z)Aob^0D@O|XI7H`08;p4rs=wNuFJV3n%QSk$~X*-!B15fKTt?NRNjBVD?TguKgBBl z00@3E&1|Md_Sy&lkZg$AHAgKg! zMRH%WZ^btFhv7&eyuw~-#jP$QG3<0GcByFccIO0O{{VKrdpN1h7{)H~TOUc1&~WFS zNZN0Ik?ZkDr*;9r?SV@o@r4JI=qeP9ARuF&za>47$nQ z`D4L8Ea$0a<>e$LP8hL2C=!2tEGDa)1WQnZzs_0NZVO>eGQM=TBqWCx(@T5lwC zhX)>=1%7w<7sh`dz8OxIqT5Z@bjTy}$C(z{lLrb%&Nt+B=ZtZh>gN5eel>V@AN0=v z#i^+Uw^_4p$IJ5V=bxCL_zAA{Rd+n;V5NNzwQqFGW+cdnNdEv~YP{M_xZV4>fQ)r0 zwee4he{3I%*H>~wY4HC5Q?oYXCPECUHzV%tUU)gibHV&*+y2o%8ud3vJ{P`*7iKau z6;@QoUAsvB#HtLPu(sC zJAW$pW&S&SX_D#fpTpXs#^@a;k7yCG$tuA004W@IBcDm^el2`_ZOLh*d4;58SDE8Q z3-Xm?gU)hSpvEbCc$M`jcRuTmG>r?>kcQt+YlaY$98dvMJBr9;1vA z=||QgPt;}ApJctmTumd~HgSWD4oy!cw6@AYlNdN1IQFlOtb7UaPTX3@FOROKc$LJi zwxI-|gN);$2M0X#tlR$pgWnT%E7cc&5N`g=j%C`G?6149-@iD)IUNrazOfPgMgIUX z_A=ci-Nx(Lz>JZ#Mn1gNi9AnfU}H(tC2ELJusoN{$ zf_eTddgG2b>&|IM`v>3Z(D_~^@#l(fm5JV7Uzp{T{H^zw?g5 zw10ziJ>T0NC(x~Yuf4wZAVv=(?|WAz;(yzpz#2uYO=sd8EB^pJw#W8H5{AY*jxosm z>%hD({{RHz@Gg#J{@AmdRe5JymV2zbnE(J1#PidP*P-}V_E+#J5U zg2A}wC!WHlSf$XVgM!_hC+%1JMc#a2@N~Kdfi2~XUy&2MkZvGnraEUh=RNX0Yqb53 zz7NUpTi~vhqiSM5x8bg@nj!Ku@;3J)Jom@pU36a!>}`~_rKAzK!5_IC4{yr43o9*< z{Gjp2-L7fXb5>_mV;Dx!MaX18#9;maRQs}rZ+~IUR*EpHa=f4Rdeo`%MoW%^`?Zi3 zV;{Qj)2;a+l$V4RMg!+yuzQ?6&j4TamV|$ zBw&zRs6S4$0S(zDGIDwE&0%X$86tm_@I3`?-6%Y5&Oh0#ZBS%5Rp<_WS_Y4ne{Z{q zbT5XO;YLJjG(P zDdjEvf!pU$PC^~Qhi*#ruQ>kzf`Bc(=fh}WyI9LMqi?f%=jPwr*YdBtf8d<{6go%j z<>6>`6b(4ECS&B|YnCLgJ+qA0ejW;GCX8`aWl9%Ev-k_Z7G4h0Ei80PG`6&|MUE)r zj0HsvmNXy_Fml5!i2n6UpP89K0DwQ$_WuAs&a8`w zVEe2G%0_drf1b5^)%?X^fa9Jvjtx|lh}1?Dk~7B2wQ6x90=Ui(-0Mve$Zi@;0E^s) z`A4NoX&VcDt_f@b_eW}u?nOx$6g=eep0zEbe&`onq@Hq}r~#5I70w85-zegE5s3h_nC+_^jjSe6aQ#~@&uuXzWUMiiZ=BPza>mbbg@ zRU{c;Mo*WHzvuL#>4UT3Nj*4^y&y(K)uYEb^EY{9aq^Fryr=en{iHlM@E1UnQStV# zW2IWD3X)thuHtyW9a!hE1lOf_?^azuOO{nuEU0+d)Ys<^gS?sx!~2U z{28hJlETK}M2Tt&BOyr1!v6ph7V1t1MIyN|6}^mGJMdV4tV+*gU&kM}w~szIYF}Xe zojfshh>$o?hx$#wRh+84&!{;dhioi|RD+1jp2 z`B{?;-~tCh(>?3xTW<+l#cWISfq+1wKJs1(MKAL4XUIZfCp|*=U-F4gmnu*Wmx>iCk!Lo`TmsKe+dXk zH!;ThxFgHvx&F0L=-tkqNUf3bZLh%)Vd?!=n;Z*0p)wSgabQHJFqKR?q>$Hr;Djg^CnE839B>Y&kcUk{{S4nW*e(JZ|xD|4-4ZZBr5kiiXL6u zgMfDOINR3*bM){06Ej`B`1$cZ`{FmmZ6ZqzQpPq|Qg`zj+2jB&)&~R_@-g_4(;hkd zPk4TR1N=SJuC(h`Y2vnjDOS|V3!a!x=boMVS7G}v{?MKp{hxnlO|$AyzN2;#`LA0*|Tp`zW*IPY3SSc?n z;C;|?LgcZ>V0u@p`~&d4m%%TDnh%D&Dvn^%?UEAC!QI=IW-fVRSg|DXb6=5P5H%m# z2gUyY6NklL0bAQyK9rtjjiX(}S!9oHTXbZ7<{&RsAQC|p>%Rzp;G@4CHL0z%)bMwN zJWHuXKb3Zt_l>8?Wy5X_49r;apavW^PaJdGK`85V*%a$So{arYyYXC5#?r{ga2%Wr zo;lCwTkihcU(f00~csY^~&zd5Rs%(#^Dh*g=!Q zARar{&b}P|kv=c@^s)H4@ly8M3y2v^8hj@)NwgqjZ;@A{Il|zVDnS5aW59p#NPRE3!_74;N2?EOtpvu(;C74Xr1E}Mz~u9qRA@SG>F8sN#>TxqTWV{` z2?)3co(T##t4M?#FdTQls<)?Xc^MvA&)huG4582x4n{NkzMrji9$x62MX;UWk0+g@ znv=aX;IwwkcCzn3`xNkzd4{v$|OrLc@2eOSXMhT=mRLAL>zX9LedH`+ZvD{k(7C0DDOn5(bSjc6AP{-L{{TLu5eLgWqy%TUWXEj(V6V`O=LeeH zu#scsxd3y3d96{Lk+;pRVYPrqBG%n$T6Iz{u42Mfj0GcN<$zE=1Ht55Lb_K?@SJ9{8qFIkCi z?2-2kvJM$gbRdFB=yTUK^(CyrL>qC*=YwBcmDcvO7j>cbbZUEAYDjp6Tjn7A!_tug z#`sm^K9sXyFC)Jk8jOGl1a$=THRu}dOV(f*XFTU=sa=ljV4iwonvIBO2al9`8hVd3 z1IBZ~!KQ>y6dQ-m4&mDdv3yzJTR#(NlS8XpCBzab42*=1o}Zm>#}R2&PC52GnzC*G z0MXlc@BP!o6Qruf%nl#+efa+Xs{9S{WF8gx&2#ph2JUY!N7iMHfq);mZ*=6~xA3d* zPXLbf_LqjdMHTc&$lHM#&szBF$KMVte08HuW30fFK{}Nol$;z9k?46popZkp{v!ND z{hh3nNVkeF7U&SW{h4Hu;=Q#)lB?!1B1H!SCj@7q>0dpHz)pm@sjH)d6@m7?{5L-Q zzq^j=)t5W7(!MDF0D^^o!6`fm`)f-2mb%)GiLV=Ww*Jx6rf6iAG6>lC``~UT{6`h1 z2krBH1*~7&9tZJ-tnA9NgA{T{2qy%WSL6=8Gmh0uRQU0obs+|D|9TGZZ%{N~bs;Myy10(?uc)o;9UCEkT+IJkRf(t)1g z&O-*2%Z;CLg6$lG)MCEI__gCpPlg`_tv(%mAedY0GTMEEO}Do{HH<1YdCm@Y#(?A! zIXF?xNAUy4zZU)~%CSQ}i{V=*ZL$awORIn}jH|X2InN||aaTSU{?EF1gdu5e1ozsN z=?{5-cbRT(Ph2zOI0v8{4Dnk~%PLlvzoPR!IygREXZIq9?DOzO4~JeAhfcCXJc+sG zx!Z=im6)?Tuw$ezz1QE@BMLH3UK3iyZxmfvUO!#Tz{{VvC3mO-Pylr`Vr&>zQ zZgm?$bv!T};uVlGlBvL5z>qjOuA}x9@Pr>3{vX}yKN@dud`ql&Q&+gt;hOSA@<)}8 zvKYV$ALq_-kVhRddtZr`(?y_OJki61Qp#T-6X{=_9w_~wJZ1Yjd_wUzhkgud(TDNI zqb9EU;p@nKx<8I~^qs<#fMtb+`)8e~72>faI z%W0&f*7HH*Yph1=mPIPRFl_J`f+)nV5DC-|dY)U|&R-K?@{np&)WbjNTdnC|<);lk|%^z^NLH^iS1b#D{t zns0%A9!q0);v0sJ+}|p}F7-z(=1S)$3WWTHihwcH3h|?g_iasI`tv;6*a~x(Jx62g z4IlmraiBJq@26=R=B)%@Fg8{VA(4BsgN%SVsQg#|00lnqj;U(U+FEOtrAFs#oi13s zv4V1PIt`~JXBFgr5B-xrXc=uxelFF#2cQU?s4ziuaU}7U-Ma@KU#8r@Cpqn0{qMs6 z0FFKi@gRco+eGo5sgN*x2&6`iJae7gZXJhydSeWsIO;RnxN9zXH+whH{*PvLMxQEH+sO8R+e+e3iyt5S4dB~! zX)V0>)U^d%=)gB#;+FHi3a1?XFuWv4;?CIU^&jU27 zs#N7qL~pEP7-5b&?KIe}@XV^b4{Cfdqr;Zq=g{*`ScGJOgOS}$dV8Kl$E^A(PugYq9A94alNbCW@to!Vc2m^!YdeFv|%*|>~E(R>E^xIz$f5Az< zEZoJQ*?2p`OFL_xD!EHY{G}nGM&Q14?l}B+^lSLS^Wpg-W1AMi~}KY@M# zwAFl53A^zQr5d%=@*(+qkO3zLJzJ@-zchaY+i2FxA&pmOJt^M}d@&A%N^e80>VpU72DfE<&y`$4Zjo)mkh%{sdL~TLBzZ#C-A4lF9_XQYMMk7M%$kO3YBBdRE|gCUsmd5 zM;R^D^x)SisoSmfywTh!+CdzH`qw>5X`4c9{Big(HOK5j`)J*KD!NPQ{3GJ4H`es4 zw^HBP*GS%6k+=s6vLIfaSu>22Uvy}zD5nHf| z&Q-dJ)E5mitdKGQ6cXEVTW_(?8LzQ^0Qi=F6!;%T)Go&wjiSoHgOzXcE9iKC6)DD4 zWzhWhjI#L9s|-Xw*8ZoXMQesFjf#e4C0_MZ4_ z-~(*;nmzoo>NhaL%q5aoiikkkz=6Gk9-xJ6;~B5kKYF zbY*9;)GdKlw>^Gh2;8~GS3L>FGhdVc00l2Ke}zA_wzuJbipXvC>&Y9r1KVw%0N6 zCXHQrCm9*5!tr7xo)6<*Ib`n`+IFvQII2@v3CZ&YN2bzqQ#JB|)DzR8s<)Gdg@j}P z!>>G0GOzYrPX7RKe=Jpqw9p0ycpcALWLNu? zkVqtY9%=1(0qPEU=y8ezQP5e4&!8jLnf3^#d~C*jk2K`F0dc$ZH08RC^4zfR%>vX& zbj65a0U(_8H081g`Nx0m&@~8$5uQNro@uYDEP2M#KNZBfXgHitgZ$zv^k(_(b7G{esazg%xtv`szPEWOEj}btK6tbSY`qK}IEzb=i z&=zLEY_Py2XPzog^@>IhZq|~z7>b227M~&0gw!Qqu9_QWL&o&%9V-6FmcoF^HHpTFv#!dXafzC z&Uic;0FFWOHyr&9W$N*Tk7*r2&lRaL01`)T1`TFwTUsN5&(P2{x$-ak6jh?O_-P%~ zj~%eGxfcRiVlE>qk`CPRNx&ZDSLrY8Q>6v?E8(c)iPqd$MCTy<*-?{_dCyw>?)|yE zD84DsY_#e20X(fH_W(vgxxP|kQmdbsV<(>8xUbUx0NF!N{>S(?;q5qhw6WjPuUY03V$?)y3Vgl}0!G zz%sBPRe=Jq&KDW!gT;DBhjItg+GTIDmQjzCgyBf*R;{8B77AeFfwb{cLI;|6bUg;s zP0W6N&gwZBGzqd4u`O^Va8FTrExoXYLf!F^!K5-#Y#cBO!zYiHqLoz>l`a1O z0YBqY+_1Ms0N|6H?L8`#&*m^GgU6wu2(DFJ0~jE60gq+9R34%o8TAie087Mf5a18>pJO{ zd&@0B4A!&7xUor9a6%RwcLd~P9R8_%Vevd34)Bf5-RrD&_R$hf4*&}If8iaR{ygz# zh`e*HhA?Wg2<*d>%^XqW5IZP5AE`Cu<`|z~thYVA)1r+nwVfRpYC1xoIXBRc`1^<{z$2#wgI;sXALN=Z2j*ILTP;gyS`IeF3X@zS(wp)2vRpz+yoDb;J0Z_K@(ehhz}z`tFZwF8pnl z=@FQF0@*y*6({@?qru-0Cyw{xe475Na2Jtvt6UyI&vYl+u`ljcZSx-swGt}&w4vVV8{AJCae#psVc_^tbSd?B=!OAiq1))&&s zr~Mw<2fAqp^bv!e-{e;p;qTgGzVF459C({pzPC_eTYnDC46-@wvPuBl26@j; zJJ-^dpR*T)tY!O0hcs<2!brx|Xl=p}pko;WpcSvD{3X+EhWn;w3Nx^l+x+>eRcS$4 zC-?sV!2L&QOLzDmJKFx$UOU$zYkOaU{wxyD^26uN3~P*#S=hJAKIs_AAoSqZH{!1h zd{+3Ee9|YvZ68aK_PSobh!zXADj2TkhBj;l3&wlb*_PTKpQYRW>_7;{I5kgN*L1xC zE%%Z`93$@&@{D&m>?ubR%I^p-$Na(5=2ma={{SQ6-w*!SzqBXpl5DMhEO-d`&eq}G z5-V%rE&D2*mWW3gEULWafH~lvg#GjTCVtZ%5&f?IA6n~v0ckTEmAbaMh{bbfGLgL` zOz_H1550IV#UI)`!CoD(S#I@P3(4+P#k_W>?GwrsOE5)DlYlaN4)s6$68`|<)~~5+ z`k%y4v8IdR&k?oTTG}#5w|9usf|5#@*oq1{QlysOl6zOZg2hg@l7){CF~ZZQ9%U_0 zx$NxGCE_!Y!1)ia9qU%xPKgP*0J-<2u>PM=wm>j4B<-jFR zCmeD4)mv!GTYRaHmprND(&}<6Iw&iGN3T!vDe%sS31XxX&&p|aA41Kmxk2Wr-P3?g z7f=auO7et|3ZAF&sI6ub%IgRma8A-QQ%1nXd;LMCnE+!80<(kj40JqmRp&xw%PC+w z4W}lhY&hCT!(a}*C}I>S+sWV^r-}wkkkOtofsyi)gGpubL6%%`kGgm@1E@rOr|

      +3+;E^iKaUPvFpYBtP|xq;+#+tc2nTr?`lg#?^r8fV%R$+sOB zo)0G!5`uW}gze;VM#GLNH!&%IaC!Tuk6MfE0nmjQ#|%h3Qp+gV-4FZ(^r>U8lK>?p z)w#w_(^*$1=OqCHuiZ6j;^290jC{iw!Om)&n|HIg80*mf6%1&pbml;Cyyu^k^HeTh z57QXqIO$eeKv=f~_u$}F3+a|Khahel&JQ(|o`#7OuFlZo9Fxxnt!FS2A^CI0az{$L zJm^Uz43mzAv*wLZvFADD5O6=vYbi2{T7!fD?c|IAN8YU2N615|BxeU{tJgq0yN4ut z15_`ZE^&YlUb*J5k!Ynd=0FHI{{VKguULsUD9$@z)#=Dm*&RA?b5w3|j)OS#HIpqe zh0^7ZAA6I*sy81ipDlCr2O_TAk%9+K#|E?I$!6XFAom33q@$Fva3tW2{Y`AxN;hY} zPrP}o3n?(!RyiGhYTDD}9DK(B=NtJH%^AO8E(-E9oDNSFuV;{VAq4tvHH~D!(MECy zLRz-1-9j$bh@_jw@==jh`mc8Gl4X=(AZV}3F9HGTnxQkVlhvsG-5JQI=A4O%J!qJVzCKU&!m*=p5Q7keJ3 zj!zYK)wVeRgMpLD=BmU-!W{4qW~pM3so{tNpTAZ{<>;6g!6kY3JXQNvU59yIIvkqK zws7EKx^tcNZaJ_R2J8OSS|qt{cQ;YTp*3kT0VkpDlT~#0`@|kPV|QA#>;mLAbN=67 z!mSd=ETFGYd!9~BLn{MIo;+FkUdRi z-KluU!muOMiq^bl3dI}dQh$rBX52363n|L=<@!|0%(Ty&{{U(&E?)=uo5MaV(h(%N z(6t35ZX>3?H?6|TMTM?`4fdO-=dSquH;jhPgYfr57D9jn*LYB3^I1s2Tyx2!-ZBP9UsJ^ahVPJ&pmp6t1@k~W0zbW9NP2{bSCYKv z+|=ZRXlQW*)i8;;*ZD`*)GZ#&;UbNdQ7R zdi>RX)?%o4bpt=ZmuctJ($Awq6a`sTf{bL7{JU1UwFxPG!12$`)1JTmYA#+Ua8sxl z``vx&9TfKw$A4iwm+i13rhj&T9Ao;L=(LRqZLO3$ZehtAj}sa0<)E3gxNf_WSAQ?IesU(mle9ilCe0+a~9tV~UF6I{3uh>ChZ`89l_f(O%j!!4G zdTw2bavIUk>Dx&HtJ{P3on-Z1e`#ovle6X{wxYdto5f?LRF ziTgy6jDL6)1oBAZ9Z%;ul-_5JbeF*$$3J#DZhJ@U?fVqzpR<3%_;t^ZTD7lpZag(w87x+eR+7sd}{{Y6VQBde%CDVK-Z7_8oW(*cf zu(;sJ>Oeo-1J;k)!%(^XpshR+;I9ll<)w#?@1r`JyO?H8Ef>w4NT&>&&@6cBJj(aY zXT(}>!ao8>Wu+`OI&PU{RaP^$I3kUD3=Aj$ewF3p>MCEmf##&=ElKr{vfO#Cc+sk$ z!6nEi*9R5gJ_-G={2Q$P()OPY^s9S`ZzZ}qd7dx~2{=ZRVCN?aIX#IL^H0Q2+tA6OnM(lze~TxQB^I3|t}1lYqXGP)`CL!1%)-)j2% z{t1uqn&aXZz=&)-RdYPPAn=9L==z_W#51}Kq=VEvY>l5%Yumt0!Maj@o`;p0(NmAM zit>J^*J&=;z{nlXCZ1dd`N+mUym+k0Z;ZCUhWVQV1^dq+};D4M{4!&V+#d><0d=iyb4#a|Z`MOafggGa7zWQ708ytVc=Mi{*c2k|I z*yQ?GoBsg87&O=MR<+};Q&U))=TX<@{o0Lu_$=q`{{ZnXSN*NDuY_L)brsRY;-Q~y z!$mF2O65^YsLDnN$s?&CWOc4wMQ>)b-07oFo$7wepNjfcqd%2vc?67mESWV&Rq-N- zk5QNG^P@7AMTEKggr8qb^Uw6Z z;h&02eej=8)isG#B%aDS<;=fyvIaOk`kKSq%k3KbB(^^{f8gLe=@R5%PdaQAhV_-yux!r77|OOsW z;JtVL3L)Y<-BRLThnh(?@rQ8NQJE587v(uuQlPgSZsBu^^*`Ag_VIt(D_p{bxSGQlNj3ZUeCxg_#B_vkD38^GFhGHH+qm=sh108bV8z461r z8sCIJZ?A`5Ht@abS=(O;G>t|{=43>TTuiE@bavze>;-*TfmVn)c{pZR^4ZehQ}WD3hM!5%VUlS&q}F% ztoefofAQ{WC9&$o*`7oDQv71J_!01@T=5pKAWMBF)=P#ZyDE}@m3}OK(|_<+Z;k#D zItPlhQ>AEr8u4YqojA3$mvWnJg}m0!0AK^0W1ix_WWQ}cfhqe%dl%?H&6De$zhaO`zm7C*2?eKzHCr((vBhdxjv3K%xCAc8 zB#y@&Je*HAGVFSIbr%PH&(>e~C71jZE`QsDz&8EkWrUdJMCNu$r* z3_;-fan`)Q{tHZyLGYJXyq-H**4b@lSlBbPtS%RgszEu@%$X#{U2V zZ|C@q5*>TQHw!b{iTuy7TcTkgEzd?Sag&VoHS?eR7MJ6L>)L$Y7So$EYZ`=cDl-z& zELa&|mpJnseK-f2#-y(Vq-jnInY3~K5BQDte*jwFYYHv=yLB=t`8JR+eq8*cj+w7A z@rV2r2gBYUy_qgH>_S4j+^Q=P+d1!=XYC(heWHHP7dB~d&v6BZmeL2^lee$Ed@JCu z*}ud;7_?}$+ncLPc_*K0G|X91GqfKs7(0Mm5J3l;;iEDeQP@EohN0fq$A9)W5*Nrx4Dl`7sJ9HC~G1xB^qp@ zq~v|YJh8zC9c!U~j@rK1p3}jeDU@77W{CZUMcfA5tABNXY~cDD{Tb0d9O)O)!zGQi ztdX`Eh+qTv&Oqm-bqVm_OtxYpx3?JNVY8FQdsZClu`W?Z<&57PyiX>9_RSl>9xR`8 z03!PvhUx)7PD%9O)`0Q1#2eiPJL^9JYcSiqd)(YcBG?93Ic6MWXPg{!iv3Nt_hryj@TW}Wem;y$;ii+wA@ z+HO`tjpphx#LRFos*Qq4$vNx?y>?n}g+4a;hIrde@V%4@%uAVd6a`m2cIoajpGy0l zfA}Yt!rN~WTWbs8%@wb#W)j;z%m`luZ&mxC;E|kHv-o?#7B*IJTfr1d97q8GfHCyP zK}pZDDb6cn^5WOvPwgqHMG*Tpg)N#+gY9o2jOTz(!MG9s0PCsszuDjRlaeXZMYiy& z%wt&N^Dm#|Z2ZzbBjk75Iqk<<{b055&7^sCSg=qP`MXmh@ZGn}te~hJcl-S*^FG9T zW!U_s)4yY{+Cuslo?jFAZUG_@v&xhAO@s3&F_PIJe7Wd))`g$!ar;QcVqa46SA!YI z$uL<;+=S!+ai5zWoLA~%_-Y9NH$a@8N14FIT2BsJ!xIQ0j1AlX+*9Ua_P$5twYTiI z`$GM;LfW>8C=w>!){-tq@dMk}7^LwB?1lSEzL_!8HQx-Q<(d&4i@ip7pc%Jve zI$f$r+inX6mQ^|1fD;29dR6Uv{t4UrP1eRj=T}4YknUy zUFn*#iEW%h!JK5^lw}2f9925f-plSOHo6~=A05A7pW1if7lx(r4~G0o{wRvp0`l8i z+`7#p4ogIZ04EvwPhLGa@f`tvIQY`dHNOq`n&x|XphT^*csp{q)QwvILA_K?fZNd=c+n#Xs!<;-89M zVthK%-|bp(jyw3|P(sYyyjydXDax@w#0_wMKW$=NYTsB-4PNO!AhmSaJ*@cdatJH) z43crqa4U5!(~3-Kb-C}KvPP-m9UtNi#+l=P6U@CoNGH11EL|VZZdLl4z9t&4PL5`d6fQrH&F&xrQ;*Cz@ky5;o=@hm%mX z*lZH{#~*)zOc#45e7NLe9%sD(TWLTff-p}!npqt6$jJWyXz@^epdlx4Cm6?>Qrq3A zTo%tb`~Lt+0B!Eqw&d&755sc2a{Ya(wD)PSvpzOp9Le5-k}XFtXz$BB466 z$B~o4z|5T0SJl>68=Dy;{#tt)S3^j-=BZD-ym9xBTFTZhk{Az|!CQfl$ML2?t;HB% zW!K8A zC9?hVp4sX2&wBaK;-|$s9|dXpcY%BnGPj6slv-NtE&Gx3g3iPEuy{Y4GpC8hwqDskuR! z+_MubhZ~sZ^7>b(U-%N+RJUmE5eR&oazOg#zFqh&`(NICHMa79X@9cmjcJfI6q9AW z$_5LP4+_L(_UD1erF~bT`2PS+)hr;M()I~qop+;&fdqCr?~%@H*~8R@NPDM&i=|eK z{o~_L+Ry$8m8AIBPS)=}4C(akld|R*SR{DF(e|>8ZBLKa? zP&3~qzdQad_!mI^p+DfEnogOcT-j;)&8nKm zbE^SXa+*tXw7>rVg0%c5&@ZiB{7Ua{a-({EhTt{6dKMc#U!lce{6PNzg2sF>(G9=+ zBNFP`rg?_L_{z#pDtKMm zB)KcsV3U$|?L1_2U08fRAC~F~zNx$0@;R|pD?#Y={=H8I@o&Yy+S$B4a?fF5YZ1d@ z#iM7oRLeOdEJ$I%=OeJmuQm8hqkLlhvix~@qIieKtD-iSYxapmo@K&M6A%jk4#(u+ zbH^jKeyAUV`c|Q7blxAimfjoGB!!nFBx5{|c=}h!`e(v>ui4M`tnf_t>lAiZ`lQ-I zO9BYeXzn++%mFTMpE3Uccs#WGs6!S5Kf{dI?l;01^!vXH+6@3f4XkJ*MSyKZRp12!fI4ws z4}RVM0J8*N9sUe!77$@B;)G3ZJj?+q9m;xojAp$P{t2b~X83PX{h0JfJa??x>Dum= z$4JyIt|!?fcMyPw<>dUp2G4w&&jpP7%v7iGEg$LnlbPXM7rD3fbM0#c2`UBPDC6dD z=Ti%jlgfjVIb+Atyt7LEsk|+zOg_P=&2+2*^C7mGmjng}AvzJ?>sEC?+C#(fMkKVJ z^583sw03j2PTb)u(e{zfI`v1(2l*Nf0Grt{4#aXtFEs7Dc zd#TBYI4-hBq};r4+>Nh{oOL3c`h;r0D~yxRC!Q->1<)-P| zx$J9+)W2pg3|`33e-@=F$$Yl0a(5HSBzcvcXZs-hKDWB_{{Z0{uz7ZE-6J!w1f23u zT=(lkl)Dwn4z2y)@J~d%@y4I0Y5TPc+eo89!^tpEe-d$22gQ8?65I8iC^{f!2JLf< zah`atdN0|R!Fo-iq&^$c8aMzc8>g5P9-FgUzwoMjI|N9nqUi)ce49zm4>|R$x&HuYuLr{*FXCMr_neRPp|yr_!OuU1ZNI{= z54l-eN7C{#+50+Vb~yQZ)a~HiK0T-{Edtw&t`UAg*bX?Q?*-}koXdQ4@Xgbek5+>U zNHP&1kMMkLKc8MJHva(jf$+i|mb$EWB(~LCbe3Yob{iDr*KcuQ0-;q@+Pq*MDx8)v z#V#RTqX!^1Fh44Xai* zQdn(!VS$0yaBa9fxvt*+B~9B1Jme7B#ZSy{IjXw9#a6MA)$~6RN>GFQt0sN<$3vfg(AQ}s3h`wK$l(0-QsM~9 z0$B0fzgo&e=8t2CUy6%1^7=-<0EO`WZHuaoyoTsN^#-fj{9w?vJILToMkuG3DzV%K zg`D~T;AH(XU3JPv>ex6L?%ws4b88BaU1Q+;aDT@Ylian+`UT9Z$X>&aO;DZ0fq*>c z)YIj=2>ThqW7C?aaXW9|^S7?F&oT+2R2OFzC z=x+O`ocC&$QO8-i&+hZc{_w4xHdB$$1Yq(j2F_wwV`z^hBIz=#Brs`1>Y2DMC!8wqj4ZzKcmDpX>ioyXASg>&EVm|90L zSDqDTAwsjDB>DhPUYu3+*P`AFI%D{`6=~c#S-WodOg2X0>MGm~yzO(y?U7h5u0mOX zmn)nuHt|-hb+l$De3aTawscsH|1jA!x?g5NsUhZ_8F; z*CH#B;ehnTT9Gzpv3;mQ@yGXtAbr@*M*jd-6^*HQs@G2d-dsfyJqx;w{${Gr@iRzR z1HPkX6rGApsmUFOJo8VP3z5Et+=^aK80`Kc7;{ywRfg_BQ`Bx1%#V#a3O>`RK&Tu+p^}(*Q#vc^)No;37+Ez!%C1m~L z{D&P5PrZ51{1f9`dG(JOM5HyOn#|In+_`ecJA!pZ>@&f^BD-?Qa^hlp`90H;XV#Ih z4YxdT+#Jx{$(HAyGDc}3S5cSTNX|GM)SF7iSoJ)N;Mdrm=a`P(xxnCj!_uaJGB|9U zjz=Py5G=q+^zFr1NEk`;WPp7I2nk}0nE+G4^C1B=bG+pbqXR&Iu;hE3fzP#9zu&N>vof}F2*(4` zt6((kr2AUr9DsSt4u8)S*+Gd;LH7BFO3$&pc;y0MFsJ*V6Iv483D5+|$Q_3jN!wiG4d52xVo!$IJ&EyL~IhKWy78xIPGKGT2knc2&3cam9h%>~R{gSkQLV~jZ6Cl^DWgD9l`QEZ9sbBC#hU2`@5Fy;@ipYAs(isQG5`;J zAXU#^E9E<1iBtHe%JGMa?b}@Vt>b8Az0h=Ij{Z9Ejm`Fvccxo-OInM>@ah_c+!qqS*~(kkc|dH1myN`I+=2@n zkBGlwtp`r{{r><323sE&-nWP}SdH0dxVAvLg#J^5BZe7NG6(Y4pO!K8ufKm_UxL=( z1%GK@5cp43it_5?L9koh2T+>gQte|avNgP`zhfBNU{>3mtTV{T+YseWo#OpW>Cc(H zeGj+={mJ=EIe@9$-eQ8^L0>!n0Kr1PXf^md@T%bG@y&g#-A2*b+gpJ&?#K9+Jc7Y^ zBz~g4gx0k)X{608tF$V5FBq@Qy>sGjtNTm-+1lz)WS3qU@NpJVy0VrnkY6YL@tk@E zuR4V{R%#&Rsm0CoJS)b&4!r%I^lu63*TNC4UFtGTd2=ZXBYmgLkOQ3UZ9I#n`cFLf1Z=H^PtJ9O@#75np z=wVHJY%K4)KU{RX@M4MgF$DGAIM1zW#eO`YwSnODVP8I2{?T za}eYfEBA;5V}YM)+|$2l&ky;&RQjX`c0x!nV`IiZVUe6NoM)jG>#DKteC()8vFxj; z11=r0&-aHlEcai!JeMKX9cB?DtOLtImci7mt(g0kEn*yCk44Ge~5ZlqZQNQ$U6gNXGXcFC&rq;=3lQVc#uPV_ZHijxs7#rE~NvQMwwPxl^+w zV~YH^{{Vu+{{X=hWc{0KZG z3JaiLPK~2#)_RO(OJd$dkeqeo8g{q)e)vZ6H&3@_Sw3Bhu#$P{f^*RH=ZeCl<5Se` zrrkYmeqH{;{{Zkp?-BSvkQu2*q6L&@3!$@HwRgFmv&ejU{0@fXBrn^o~UJI;orCHu4EE+^!n8{YeAAGwN!!kG zk4pD%+Sc~(!=DeDJsRl2dwo1wZLwT@l1#xveQ;~&57_hImxsO`d?eCz$W|H5Faa#i zv6q?7OR+ujNjdMubZ1z#gN$&L*F(wSoDcSeNn`7~yXoqFS`XS&L9p%$_vtO<^KMK4t1fOiS(sbWHoXhrTw;c7$V~$TZov3QZdAc>ca=PuB-kD=lfT-lj4u~LB1eObr*=^Pc<5Cin^34Hj9+Nz$5@2 za!78#8sL9sUmmB#d;b6uYMKKq{uk8my!|TTFrq2bm3LA8(*SaM`&1tqe`iad5^GUv zehRs`(lyOJy!$KrR6#69IoNZUD5tXbR2;Clz{6Y-Zt_%GpW`|l8H5nEW>seR2duH1GXTKrY<-^D#U_K*Fu?=JMW zl3Pejm$vHY7idz8j1!C!`5a`O$EGXR{B(XKe&5Y+tN6CpQ`5XXJNfYB{hl))LHn}X zj`eKxBad)v$-XB1A+h*N`(pSXOz_2(%Uas$r6=ARG#$G;H19e8%u!@*u7(=ILG z3L}G1u?^*&<(n>#&)z)ay?vQs7;9x9a7Uo0E}kVNT|0HauOc&XR!4Qufj&Ea&i?=w zwOumW^y+>elKV@zOS>uUE#3=@X%i$An<@bceVG;&4=Bc>L-3*y(neOJQ%JF)TC!AaLn@m7$; zfYB>OsX@05Z!qqpbo4l@bv>kcWo6m_09^`$<##^G{eZt}nSLO|{tNMZ^ICYf!!e@j zHq)KFmB}!Zo$=(Ir~9N=+8SJ5ZK!SRM57}tq!Z{X^CQ7JvVPNk6|nKY!EoLd_>J$M4{{Rwch$Gar*-H7g&(V$n z<#G-WwR1JChgLV$9{nYoHMsJmKQQCw2L#o4t?rWn7@j#HlxOM1ELzG4k**HGoB&Gm zQm(fg(T^m8#Al+D{{YsemCkKZCCjn4k(8DP(buo#UpxNMKele6@LR>_M)2o@JXhk4 zN?Rtni|jB1Y;bTD!+(^$x7^_zEmOu+0 z2?ypLyj4|CE;5VMfz&S^`Ky-7ZIl8_WZ-bT3Zo&#SntVff=+h|uYDJv1Ft)K{KJ~L zE0rKHIXoY_a%&$}*Nuc5qy(rq94;_uV0_K{R*x5W7hR6y;Ge?nBgNCSZz#FA)h+A< zQg#P1mTa74j>o-r{{R8}f2sJdz*gKB9E$P(0EPbmu%E(D2zapTdOw9^n)>GB?Ivr> ztBJ{d#D*eC4|ifS>rtW5wU4}X-?T66iQxYLjC#Zx?~i;nX|G=B@JhB2-0gVNAmvpL z%a-U#9V_Io08RT(YabG)S!y3> zORY;&v=PH=u~~y;0=rvo+>*TDb5#ETY0udg#9s%zbEy15{hlEg>3V_noeoW*E>!{f z?a%N?bHM0NTG{h2a(k3A&qRr~g;n`^>Nu@?W4;ii5yn37t{dR5#%(L(M}#5O{4eJ~ z=jFMvxm8Q689T=^XDY(GdufBO0H0n3LsoWXY@RdwtP*lR+7vtf?Cd8e+*4x7f17vB z$>~di!)^&bK}bU#nMuzh861kKsVR{-&po#eD)qvYE1cl<7!^wWkCWVI=|Iu*2kq6Z z&EYSFSGRWYiDZiE2_g+3P#8$NPEVzM>-#%=NAZ>4!p#zGJHuXbwW>3hzKl2?T9JXC zN#tiDz9#*&wAeL22iQTWoaMhN ziM2l-PdIhcv{;X1Yobekz<~apYtbcyG9gvK87GC~npk06=LF-Ba58A+^ABjdBhBv9 z;w97K(C9Ydm~L{+?4tx=4u`SpPX5#QgA8fEPSF@2yb}0^Pn!d(;PKCIPkQvT04#wN zj^`k8Nh~|q0=Z@Fh31Z5HXhT-9$Ox#@eCF^t(J(27a*OJrTVp1mmK^B=U+;YSG!zB`)a{iZz< zDE96L&URstcf=jv)3jTgq|Kq1t0q!~H+3l`3CocrUa=U#})0mcq7jDRVQq^Wq* zzaW9qhaWL}Pb7J>=^i)^qJ2wBEBtJbo!QS}pG@*k;Z^Lu9{8@~QQfHcs!##+=#xsFp{ z>Uw(cDwKZ+bz3qcgT>n9qhKyep<=_hBysewUDRVJ$TsCy{gK5`y0i;8@`gcQMHu&~ z_Gqrs+8gd5~8zy(kSPxY^h{3qgBekc4=)_hxk z3#0}^Z(_}YrX}tNPC?u;{qA|L9CcNPr+%lWms54>Yq4|15nOyd_*T~XGEH}P3Gr2hc$ zx<6<;T?*UHI%a^$ady$L9%JxINIMU?_~yQ>z3{wxwx02_F$C>pA$yK%ivxyLDK{tg;b-^_`l)bi+nx%O?WR-({-y>#dq$5Lyt{i=Us-Alt-)z6K8XFZx{ivujX zSnRjE*u>&Mr>PkkAcLF`MRQ*Pe{1CUmwPvcJ~(Lq0Pu=Z4p-xE9#x}SpdT^3&`w0M#z+E|F;fzEN$ z@vokLVlNHFs(fMir{hZ~?P9RJ)mul>R@|b*kXtcX2vrFb+Y|TF!)blTYIC-zCQSQ{xyEv-VyNC+_x}k_NgWO(?KtnGI>DYEQ6KH zI`s6Xcsszcc%SyG@l}*JT7~VtjcI9Qv)$d9q#%}ZU7Nm0A3!Td_ITFY;`i;z;;mja zZ?gDO*X+gie4&_bBX>;TuO0dHtDm!uw`Dhuz9;yB2xzYSLo7l}j1-L(1_3l)?!?p1iwcdxKe8zwB-CU-m)q66(LQ9-(us_-^8D*B%tqMJ|rU+s6{zl)v?)3q-K>UQm`Szp5}N*PMQGCo&wwhA1Lr#&-TJ{|u6f`fQ7 z#5W^F_}giJ@bkrR$ZguoShv`sPCo3o+EkOlIIJ()SN0+Bx5r%<{t`a`I_R4F#>PEI zPbee2$T(R5;l_E-TDamRP4Z$>UVRMS9us`@UHp%=bg5UxJ`aNCQyh(VZnGV(7zQc{ z0QVf%gZ|ArhM(|1_UYF=HLlv)EtkYgWz=j7>>f?!xFS^<>ST?ThB-c2&1HYVEdDy{ zKN3C)UHE6>ip0Jk@LkJkQ%k%txsEbbT!YSX2q&S&d)4pTx52lXHi@Np_rmtAKC$2% z*!7qZRBxU%;%I>c5xO$N>y8b1^c%wBoi_Zx$m*>htWfzMpt=>UtdJpzLVz*|Wf>nz z)`r3;Bo2V!`;KePe`bG;o*(%2@T)=bFM#fn>rU1z(&`dIhd{t(Ty|wSQace|rtocF zx)*2|#@uu3UsDInkBq3CB-0+S38P)Cpm!UG9`zv8l0_myPEJS6GgXxgvPQ0fv4S!O zU-7LVxnG+gV~z(W>slEyv)Cy@7j`=J6y;APmxF*hWL1)d)wi;Qi5o{zVOTN~tlDt;on6P$A)80YNwiIV?Fe z>!&Lg)ncb_T#9b_6`KG7fHQ$jxZF-(E_?7XKq9A=A(fh02@1S`M?Js7hT4ELZYQ@Q zud3z}9Amc%yj4rtLK>+=l%0G=yGW>$y*GDmC- zRT*D$o%t;OpnBAaGd}7m7%=lX;E$MbRAq`-q{B;`@-RkmS~mo&rI<0?I$%{>k`yQz zECvq(vt`81og4yKoyV{usa$V3+Wcpnu*n0hUb&E%&Nq6F22EzkCiwg09Atr$SxZ97 zHw4BA-P8S{S(n!i3o5pD{{XZ(tqbdc8~*U}+yHUSX58(PM{p@5`@@r34>GEJ-A4z3#}!8HmuqpYX;05fsFIc6xO|q0Ko140LN%X zjOZ*U`7%M;I{duW{e-1RIO&hz70u~wxqeaq0FL#oy*@zF41s~rZ8f4~$mz7_45}V7 zNavLt*F~l)$gCZHTwzY$YnsxOd0BDKrqf+EnnK1DfJ>bH+TI2%r{ezrhPFQtZJ>); zH;RzR9ZV7!jzI^KImSS&hW(nnEqN(>iyM~4MjGx?Fnzb;yNe(dLEDTB<7unuY65aN z;N&T-tbtUNbWGxG{{Uv+30udDeIg)BmfTAh$pB|@Z0F@1{xsGdCPp<`sS=@{{XX&gQv`7vyV|$FT9a;CK>xN0N|0(WN}^k+IgEi)fqmBd8-k? zI0~TP{{VKWL3S6lmvfMd;9iJfi53a=!ok=XTlbCr-#;y08w2eF=U;}JwXaaYW29u`=IBax@y!{VqHmh075~%zB%iEgqj>VKiRhB zcI;xwyDC3~Ikff*{{i|711a44s{=unPF}Ntn{{VE= zsH8_bd$S%-3fPu)7LXNj^A9CJJXH&y25E$;T|U$Z{UBeLjB)8*0Ecpr7e2o!;-I{P zGMp&E7$a$=WG-ji;Ji`bEjI4mg!+B6fJwo(Txa^%k$%Xxsb}%a;ysKO_VJ~?{4$b( zL$fqv?kNa}Xttwn4l+7x3Pj4e^q0B95-7*W(G zHF`DLnNiPf4Sl3_N6|DQL^l$EwntF4YS$06FgZO&-jy6sg=Qs3Bc{_++dvV96c!lA z%6O_;0Z#H6q`g?zaxbpV2(5iC-|YLhlEHiJAB{OJmj`fN++^)IsIG1nJ7!hJTwwgB zsV-eba~sB=6ZHQ830>I5t4xs#>!h`ak;}@*{_=Z-(3zqWI z<&=3~7TNPY|4d~Wyyt!dsC zoo#hd3q8E0Tjt2+2^@e&866G|4@&tz_DKH#f~4s`4t^5YcvHn%2aC0z6=)JmrOy;L zAQ9xai~?klK*BV9^dN2=bk8f#-FD-MvbRw}YD-h};^R|WW&P4KgUA6o^F;c>p%OmK z1O3tKUl@3U_Vw|%iY%A@6_3N)m3K_7#;10W#Dmm?$v=g0`nSa2jNUtem&HCO(Y!RW z9EkLLCY9q~LoBBRbJpY;2; zC`oPHs*!<^IP~I{_SeB)0Py727B>1GlLDbaA&FxkdV1H1iQ?$iPBh@%%1XzMEvtCT z_G{HsNLcj??JDKkB-yY#u1-6ieRaht=k3-Sx~t6zjr^A0ND_49;BkXiJV__~D2pwAJIH2} zLGcQ;+f31ig3@5W#I4Z^sQUB4uM-1{cv_Q#R_D1D9irL#z2T3B@#$X#G!G8gS(}?H zT{asDqhJd(A|QvqCj!1`{ieTWPYV9Zzq6l-f8kE)^4s2Pq*22NC3)4cl>_dhzbmt#i-kc6QwS*!_?G2I>%eTh*=p9%{Npp0}aJ zr(Nmxw^4?;y_yx5a7N&b*$UVMkb76?KkU;!zwtZvou9=XAn^91;kk5e0rZ>LXSd9E zGs!q0B%KIR9`WqM(AN?F00iy*l67wlc#p-NBlyju+FQNd-M98_yvgQC2a=?jKp+J> zj|>lL`$I~yNSZ>bxn=x19QQ725n2_*Jg_ z9{6kGO=rYcZ+YS$7EShpCCM)9yaAJtK4Qo2^aB8N$*JJ)hQm_*t9~2l7EC0U!&Vbs z3s_K;dzp`xB`Qw=OG_qCa4VhERq+p(`nUWO(TzW=(ATm0E8wq&S{>e(8cU?<VuR>y=qHT{>N+oYR}sEVbEV73Qw zTb6LJA3igaleF<)O&BX`kBps1eHqG6@UujY1h+a(gTjD-jcSd6c|Ao%cktIpx`q7R zCd?tikoL)ggPxfDYp|Nng5^O2gYwjEY$moFlnuo7Q^&nmD(p`??s?v^@b<$`vkhqm z7TrjRNXo_AI*+{E6Wb$$Url(T z(M_wPfL)a1XM6ALKibRUPM>~ZS@kBhyoNo27{;*#EdT{SOb$HOSHV?&U#dQyk3f$1O&jA@=rQGtgVX$L55!*xbdM6Z{7&@STcii1w(9(m zj{d_H*LZ&o0`5>$;PDynSA~j2{;@$0dBPvkzd?9-Rgb)`epwte_yT>k*sczg45BeVN+8OzG*J9?azkHgzdFdwj5M2tw@ zRw22MsXb|$zJuf|Do3yp$p{DKkH?zpVzL(oN5>h*2zdkinu}4={?w$DU8Lh1Pc_u2 z#wyWA1H?*lyq($M{{R(!3fufg@Wt(hwQg@M?^J~VY$!$wuwlxuBO$wSUpYsl{B-@E zl<8gz)^sl!cz)DeOK!UK4Grb9yBAgS;pLPP<0NyH-~e;?dT9~cz_Fxj@{Pah&-m8~ z@gL#(Yc{h8BVGFl&y;J%%(8k|#myzD^jS9%VlvmuPG0Nie68@W_VM`dQOHK;Db5H4NoM!$1)rugex zdlRAQ)<;f;1yawrvdBz`1Yi*4?%qJ;VET80{wdr3%N`*3hoJb@JE)I}F3r}NJ6p_S zWif?l!>C}GAn}ajCkGX&`z3fzZ;bvs@SWAgmDE}6$IHP+MAn5+sj> z=O-CHq}NwMPB>efuVOW5+K$YPNzY=0h9J3W()!d+%O% zb>tlKeQVh*Er#AfY=5w73(F*tm_~;OCxki9Yb-_zmLYrbI&hhtd?c?vm^bCXsxCPg2ML414Fk26|SdpX`0$Zwp=-bdL|%yx~|hvPKKIAPg2g zyH~pF9vhBXx4OG3l6p5D{c4Q*d~n-_iX{$4KH=oo1Twl5wt_u6+4e6H@l}zO_T4)I*c@jZAC|9LjmLJ}k=Ul&j+Oycx&Y^TWZ_(V-1q58#^&&! zbL!vtO2_Sk@Q!UhORp06Z&uRWrlV=5-is@=m@Y(Y=*5DzLF?NGrEwp#EZ-FV3;bLf zb@zfiW36a2EEe%^Sp$>Tvik!s~xDo^;nOq(Ent^PSBh zUB{k!*QeC{0aWr#aK1D?DO%lX%ae0b5Uz9)E2Z89x#^F_FRm(~)9 zr-8je=zfPF*Nl7v{hs_Y`!4v3Epz@8?RQpa<1oCs#;ND5q>N(vf1Z`hc(+uw)%4rD8KihV(;16$03C7&B~N3|2E4CQ{jz)q;ky_9 z((zA+qX=-)wd8mQJ3v1+dYpch@+a*@@dM$H?J43mmfPbdzoz+xRb$YvCXHg-)BRZE zC5K+P6z_4ulW$Y%UxDAS{{Vpg4S2d;Z^E`W*ILZZ@*At`xo)Laa!U|oat3!1$7=RH zatL&t8f%$@1dR*0C^`inS!5Vgzrfc3K@hH>d5XEzG4D-(5w$LPU zqbxZ9o=6ysDqXY39AmylMNZ|qa&J=9 zKk!&Dg;IP=vG9k7-^5y`uYGzfMV+RPEV70#faP|KL=Rarf!`S!`nvY!%U9DptMpBb zxG3ltA8Pno=f=Mj?p}RI!=4oIMu)0QrX`+N^QMSnyQl!+hDhjhR3q_!#zfO@8^(S+ z@Ku)KwLftG04Cr@NDMZd-~b!9J!!ji{=Wj9B>J7#?c?EJijrLDmfx~=rTu|uJkzK> zjfK0(A5cnTV#YG91NCnS3LT473E$w(Eb?s@5XleuZjLL z>elxV&i4_ezNh5}42KF7KR^!P0PUJJdKJp8W^Ml8J`2(R0A|k?L-8}<&EA)5aU`Yn zts$jIhOrqP5R>vgLi3CgMtTfh_%ZRjMflg@D7Bvi$kJN5^4t{}ib400h$Lk2TkrfHaah%RU!@lh{_)T)t#ZC%Q#)8HNGfpYGI)AYq0hNkv&3b-AKAOBs>u{=2EoQuSLcWAU8BK$ z;E1KvATvR2s9MPDh8O}tl5j^H{{W4Ci2MP&x4-aRxv)SZ3KWklfPPSNKRWbqM-F4~ zqtarJbpHS{@!RDety*Lfo>PH?_c=9M-T>RT4i9~Xtqc$lCqezgUYX+DY=C)qBLw;< zYFH)MS90|rACyyWB2`r(c=XtLG~XzY7F1FPC*(8;o-@7kw1RWa!NmpqsR?A{f3P{I z*Ac=2P<=i_%{WFGOBDp*V<>o_3fi1rYU6HCVX$*j+Q<8}O{W>>$Xz-qQaHg;|}zyV00 z37GKhf--(wpr~YU(l|vUuq6jP^%U9UD?hcs$02@!8rsS%t6BXD`$%He;nUg{3G~P zJ;W#?w$p8ks91-{sJYMPGwV|gs#YTpCCDeCv1w55cjL-BJh=8vyM12RP!a6G$(8S?pMIr>-WE`j2UJ$p~JxznYN zYkRoEtdXd7kyvF|Fg)Z}#$Exo&^|2uI671|<$l8mu)MXFEs|QgC@TMiK=cU(eKj?2vyG#dpdoc4w7J zr0BEq%i~wYpBwx%_-QwQJ~u~kd8q0#E}dnqNT8(n+A!=B8GhO6$UQQC(eYlmpAP;7 zT-=1(H2pg}RR&ptcKY#NE&EdZKC$@S`&f8W!djJz-f7m1`isN=3ggN0#3$CZq;U_7<)REcCkDH-2}UqY?REERa%K0ONk8kMh5JAJJ@HS# z{{Ru)c#q(|wQa6j>aq*=x4VT3YHUz^-fHrsfH7ZZd;tBfd^ho~{^P^`E3>)q&x)+@ zvRGflsAME(bTWO}SLkv(fnN*w5B6~Qhw!IIlUn_h^?QA9Ot!gudyfxaf^B!N-VwQC z&^S2Ye4sXctE^9tx;KoqTYm}u(s~x7;GJUcKV>(F(2+1W9#zWxySNM)TkBb=)}!yQ zdN1$!uj|yRw5Z~rE7C~&Gxn7Ii@X*4N_b_gz9eY2SGmc8VF*cKZ|_GUoyvXl+P^!z zd;1IgZvBTmYMQs~{{X4#J~Qyd49hl|A{KOn<+ijNfP7`XWFYgJ`nO2^sJwUkJL!#a z;u~}E55U&&{{XMELfXxs9Z4D4Z~*7{TaNYb{{RO*Jop#(k?`8z{4mvY{Zb}R-l$S0 zfw{kQ%q_7w#EslHRo-6c|#@aLD-ARwt753WUc@B9=q_HWaC zN#T1PbHaLcls+f$?ec1RdzdiJ=yw%X$QdIfXN=&GYtw!V_`W}hzYjF6YSt%)JyO+V zXjwUiOktGZ^$ZBFBQ~UzqgD#tAIoFc%j>$4vuDj8@J^45a(>FcwN|_ES5~-abeZp4 zQ1Ii+A6VrjrGR!gBoGHqYxPdb{9VJGe8mSlM-}+@{{RIV_+54I+v6vK{wer+N4A$i z)FNr!E!oKmz^-sd@RuENk^vmo>Zibu8`=2(0O6jCtmz|k8kL-P5#(gylo8H)*RO-F zt3ooqt!wMo{LdRS!}~ekq29r64CwnXRPst^txoa+;7Sg2^8A>{?~05{ilLAwXU=e( zXWo`#C3wJP9XZ+8*1L})#E{%#=&22bz{4j)R-8szbF>4_O82S_5KD$Ter$Evdww-? zGV;Qlo|*fn7@(KjmgUeUK3(n81E;+;qyGR#EWiRf4Wq3^GwxDJCmf%Y(-;}$D(VQw z_YDFW8i^R4rz|n|MLH{OvTl$PdIPjmUOkJQqm#$VXjwN#zbM8?z(YWbGDb%Xq@KTY zQzwa9B_U6s1xF^30?WG{1`o)2rxeU1<;m&y3C#djb#N2~<&Hk+=ApWa=L*Vq4*Nzx zt5Zfc^!bM)lRTB z`YSrSjJLYg3&+VVwByrgskKQl3h+C1Q(3ak7%(5+=jF|1CR|F=zwf?aao6tk_NsSM z?IdF=KiM5>Td5UfB(8b>?`orUAe0@Wo~J9)vTV^Jz02+`kVwY^Z(64_WE_K${?A&m za>s5?IsX7=s7?dPyRr3CS&XkVo?3jP40!2OXUnkwW1Qz`sqdGe>@s>)Qp708=l$B2 z2O(>MK|j{Ct($Ihk6fJbSr(6ga@|fo@vR#fL*;TZ2P1LmLNzyZnTAI89X$h%xLf?BB?~rR+*oIX+5IFC^tQ#508QePm0C?8D zl>87+UVibd;>?+;Y~0}o3VGnwfCP%XjQ%{;NKQWC&Q5;u=B9>Te(=V4`HgCXUWQc) zGEQ^H2BeNavK;Ua)~iN$wlmlLqgK#_Dp>pHCan@!gACcm3HCe+pKy*tw;b`%@m10H zJ8}U30C@9L#tyrnBIpDY@AL5AEJxgOc9F;kprw@qDwwa=M6Vf#$@ z-{P&QJ`&NaG@UZ$Hc|beWNBms5V%GAqq)yo@XrQ(FZhq}Tg5HnUxs?7mj(3Mdz%=b znk!r9B}v{1ZJ^<~9O0|zyZ-=!UlW%6$KlN%N0Jcv^RBNRFh+U#Lj6r^X@9dH#65oI zIJK=`Les{~Ft&zCSaj~#AKo21*XQ+V=J?5b(9_J(*vGZ~yyVop8780cPr{o0mZl&- zyMh(Bb7Sj^aliHyl>#g!+#HW3&eW=0E&E7Yo}@Y*NLxM?ol-5j35EE04E#3 z#z+~@&{xzJzwl0oZ&EpYapIp4YSSzEj27$c@#p)XMhD70Gxe_j0K;Fg$AWw)BQ`oE zgED1{zGZeKcQ2FJepS6L8^qVTtM2-BAx0}ye8j&MwCjmL@Z=hS+6B*r=Vm5gI`}*{4mn=7((gRHu0wi2sVMwrYh>_0b|5S ztDp9bdiZ`A!_ePWUot)}y#0{8edEHT#$GgsNwj#>$qtofQbOPC$i(BR2P4v(qJP0O zydj{xx0;jQ>$=0n16^t|yrXa!&fb7?(0bR{H@X8LbuPId?GgTYtecH7A-8v9oD-j% zpI}9I$1I^wXob^1Fn%L^J%{1n#y0S;i>zR^(zQ1K0EvCYx|o*IUQR*iH)Gd1z!kfs z>I>q@o5DX965TJR+$^PaCM`lW!32ZG@$%$*@n25<*B=cu--vz!y|dM0wq&<;B;4j;A!k#YDmOm3M z=7)5O3)|`z&lm)rivIw0x^_ODEA!jK{{R*|XYkigyPo=MZxncT5?&jq9i)*X%8xDC zc^&XTZjGMR+-X0y2ZePwH(cD!X)bVMxryU-1a-k2uLqIG72?UxTD5;em)S$6hu;1d z{i!@9sCbq1?K@V}C6S^s10BHJKsb{k9M7Dd8K>2K+A3?lp6$N^K^d zH(?#WCzoN6pb#<%&$W5KgT5czd?vh;#6KH#$MG(@Eu*!z-kWW-xRCA%1Y`J#0F%k! zdRHN?e0lLMzOASJ&wdfP(yauHsd;w@h);mLs*)Bzy~DOi#|lRx$AdgK4}@-K*M2{1 zcDI_0rHV$kFDhDtfw2@QEP3RC>48_zH6B>$ew|BHptYAn)Ob{1d0(LhBwP*M21Un#3*UxhS^N9#qRmWg39Hc{tqJ&rY24TsOim zg&MEz53WMKC$W7e!0<9jW053hRT2G1W;2oErO|!8%R8gQuicD;#Km1ywjz z0AOGag1ua~1?;`~Zg_dFKbds4;=6^i`%IO)98E$;{i zV}0L7HSOH_>l)iflHBLFem@GP>=9VAE;2y-)RABBJg~rS?0V5UEzD&cDGa=@-v>NPq%=u&XX2=Aiy2v1$1ov>p&ur2c;Ft?Q>pB# z#(kP9RMmP@ruwG81MSZW>KSzQjY$dE z&9sBNzVpR&Bbc+iLRD8E-amVqXi(DSF@v5?>WXQzjJIy?X<9;xrA|p7-aOS@n;F`g zjzQayaC-Ax_O!uf8;Im#a2u^|>X!y=f!y|E!K^J_TuL^cgbrMc*F8pbQ#h}QI)d2f zQ^|H?B_m>3=Z-7$@Ahqm9a3)->(;_hb*)lYW_{R@hi*sb-=N~Yvi-UKA+LeH3V4R* zE2NHbWa%DdDnk*pW8W+*=dXr3AN(TU5A<6Wj6(5RtIC0o%Om{l@70Lrz6XixsY*20 zL-igE!#Gl%SJdrbkQB(l$JVUHA;8W9el<}h0Tdws5B7~%`$&WWPH;NzJXgq{Y|Ae? zpur>4p`;RzC}fTgq3KxqkBDKjLS>Ou0iIab6XP%1J3;W4=$`NG`jeH8-%hj4*SBun zBZ?LIn4hKxd{arwVOaEOu1D7#_pDp}Zo=nK7Lr|Bo0kNLJi+ET9dNnN71I0{{fPW! z`$gWxtbBOYZ@d@bS)o&F;oUm#%D=nMC9f_N5}6!%ao~<}-K%5vyZ-=!cz9pnXTrqs zH^5yXG~HvvC9k~nk))dCN)>SuY41x$34tzB){30GL?@bels8*pl%t> zb@$#L`0I6}v{rsT(RBD#8B%z(ZPT+H6hAbDat=Y`1Oe-s`Qh}>+7nX|+g^M~@a~%g zNC10nG3It|>{ZAfry1j=ZE1fBej)0!hVkdct$ymzB99`{1h!D)lHrFr&N0@93w2-D z$b9iVAbczFjlQ$??;U($@j;cBY>*|&THBCV5<&sN;~DG?Yij-r@FtsLZoGBl9a`Z_ zD0i1%n8m+tFfikiI*$FT%kF<>%@bG4_@`0VwOf|L$vpS(=195D(}B?Ek=~Zq_FV9V zqLznFbByFQ%!ON=^w0UlPcL>J(HdSM)jj~}(B8?aYmnS9&iLO{obC)V0RWCU`F%GK zI@g@ue0lwyG>uA6Bg4_%EYd{ith31svaVG=MtlxQ`G^4S&Q5F4t^NS`W++?B(rpIp zlaxjGu@Zq4il+Jk1X%^80 zQGw_WuX?!_ks2^6pcOd##L~2T3)&uQsQ%Jl7<@~lv>qMPH0vvaw+%gzi84;&IcDGv zIu3AaAH|x7#*ZAwZiB?OT1FLGO_7&7hJH{LKnu=2P6tZ%matvK@IMns)?;WV*BwnY zWze5!eDf#4pNcxQ!#1PwJ5xp2$dSWsg-}lf_bdiRK^d-c@BRtx{{RUs!%O2o8u+I9 z-#%$s%syc!JZ&5fPv&dt!)l{E0k_=pDnV|o%MJkN<~-FZl8(f=T=}a+{{Vt;cq%!j zlf(_H>c->!al5{e{NI>2&4N3Ce*s;Whd*J@hQ1lTj^|DArkrjfP^mPbG$IH$?GsQrhn+5=`8yOhST49iF_dWUMqn703=59|< znACDz1_wR4&f~zKLzd_ma>RA#tya6n&{U7srIevhlar2qV^!r1aHUCal=_+qN11-q z9$cRbH3&>^Ik?#p#)`y}SarwLSKR*qvXVIXJ)%QUv??ml8cAaT#Nd>{Kw>vujD z@HCh3M)IT*B!yQb;4n4zf9z4?Sv+a*k4n49Fx)_|8!HwhU}LR!;N`83EW$qGerM2j zt>r>CZ7+o5-|9v`&lMs|At3REIOWZHmpmfuq$=Z%bB+y1 z!?#=m-wo^1qBjHu%M+2=k2Ls*bVAI$XE<|;U`Zy`CvhHt5ZroFLoNse4l&2gM2-u5 zt;oUUk4lAS8;IO9w?BB~Py_D|`brUkLFD1M;+8pgPtFGiBj)c+mQ`6kLP^O7<|KV; z7_T-nV;?t0-f017%%eVyk%PO6sL};&HgLq}0Gv`a*5kWy$3gQNXppp@I|3W0%y^{O z$rbjt9N>e-L88&KDGWx>qjSwLOeKBMup@vn#*oZZADCbh{6~&xxCQ%&i*H~6=KvmS zYM7%}R_0laOP~=DvjwCDVg(uUmTKZR5oXc#?7-WJ6%zp~}&-l?L z_4oV~55y-}mT5HI7fM^)%%xTHw`@_dJcK!O$5tMKxiOU;I&GuS%c!cgQf&1901CZ_ zfcztGWEwaiwTNTpAPjO(|qm=kc!? z@t4M^JW=91eK$|l{Fq-pb0msTjP2Qyaq}?>a5^5My_eyKifp_mrCQs?EYdo`xz!_l zz7Nbm$0LKsQU-ai8v#d^`&n+!e=w-+?BYxNO#aMQT9&D8;@^Uo*4jUbG^T07wZEBf zeUL`UMnh!s0S(4STvl(wZ;BuAwLCw4rueSLO)FZ{r)aM2CCKwah0Lfsp(nk1m6wc; zzTan0HC4vt^A(T<{{U+v->2hTXT^Wn_x=-K4qa-#0iE2$L!p9J_+~dPyNU$)er6RmZ97vepT(EMAV?OVHGNsi|+?(-t<6yW@)k;QSo8u-PiXxh*G zBj2N8yQYt*47PPfUOwQ$t&E1I6?p?=GnrLV;w+9$_eC&-oISgq73U?SW( z1y3QrcaFIEdUKP3{{RIR*J9S9(=-W;PTHN_y|0$w?QtZ?Fnb*IKU(cSU_B}uFM!hP zaRyoS+xwfTBxzZmWLDURk-);_4EOi1D%P)Cmv6hl3>opmO)b{vud+aV~t zj2y^Eg?uTd$Em{pWHUQSC)vsBV-848r=S?kdU%W*#B!$e zM~#KdVTOyk)ttBNi||^12mCFwwbwkEukPMU%l1Ibt#vE2$O8}wP+Mw~&eavx{BHe? zydm+s!xL$~JJIbm2xJ?-c^hS09YYRO_2gHv={^pFNPwl1q-gmhD-bhV5m_(U-C44K z-anmo#+pjUn><9E`IA2?el7mZzZJh?=x=U*2*&<3@Otl?`zGMCT-gj0wHWg0+o^7N z>4V~*4SpkdGvfaM#FMFfKGgL;g&z@v6a^pb-)WR8vm>ebCdUJ7u5(|r{v_~pdZaBB z$QTj8ENkUI+I#*9Z{UBA_P5e_w!#>708EzJjiB=Gt=RLOzc=J;5r-m;6)#2S#i~R=SSjiq)H%S^1(0ruhu?NxBp7#F$ z5d1S_Uu+T=H;E4<51Tv!Hu0PTp4hJp(EcF!UrxL_&%*6a`@)+3k$oM^Fw2TIH!uq~PIEU(J52b@?8JCravcoxG3G-`Z#4dVEp%QLAa?K%QtD z$Ze#wat>60c;JEctiSjp$Hlw(^qpJ4{x6-4&V>XQR`5#f^1~aJiPgIR9zF;AUiI1h zD)G&~#qWmNZm(*LhfuZ>Ix!%|-^2*^A*+G-F$4S@{kXJ&p;=Dwc)ls^ZeBJeVntIf zSQ0;s9(f}p1DuWwwzsmV>9btMm$jnV`Uj7+ATjU&+CKN^RW%DXlEsl5GNC0H=OERM zHt2at^A144+)1e~pL=|a7qJ_SeLm>;@_Tdp#Af4o2LLx8TApVSMip>L?gLdDE5AB7 z1%N7cgS?z$tz9kVCsD`*;fTdFCO3BVVaLnI0jWIB`BDc20Nm1GrzOT%WPrz-Y=>d_ z2;^giG|6PVNDctTa51`=s0x6+IR}R3h_MUdN{-)nnztJ6eZ_}8PUAr%1`4W$9P!Z8 z%KGgd{{S$+rIadz^8m-D81YaR5{wocj(&4M#FYeclg2Th;;MHFHw=uN+^HlEnCHD>4(Q_cEX%#KoMWH9dsH(p zC<4C+Im>=k1q^A#X|+n@Z$X}FwDOdZx1M@n=9_VH#gEK84DK}@^o8+;8@rOmqT?HI z>nIp2yB>#{&AoD)v5lkdj2gEzn}*emUcb8D zF`OR5CbMLbl#HG_ZQa-2vXQFOLY$DPB)Q1PQ=XMld@JRM;QQ74sXkWA0k@1~ky$tL zmxY!xGCE|O6IsZj3x_f%Cy~#3qdWfWh40g?TFDmqm4R@)kVqN&RV$;1%O1TxWBJx& zDcw121|XlttGv6(RlorC=B2wM%*bGH4t`_JQk3m{mcj4y9%@QjoUN{9;5Jkb?^czp z;x-t-IP1EzEZKn@n*-A#v?3tj25vpYG-%D68Tw@4pI7Ny78e=7Eyh2;ST<99!*+6g z#}%t;-PDuLI*uyQ4C!?F)mU#Q{`;j27aW|Aaa+ZiGk(h8 zDEXW5FIHrn`J-uWfN=Gl1pfdsoyYSWRke_@BX%*rCwLg-in|kXxO0$wMQL(cEZfRdovc`n56{!yu17J)3@~y0bxINdV2<3A z&P81fWybJbEzqZl;0Bo;_4|{QLqVrCL z;{n3uRmaVqtbS}B!)U2|Bl{*^{6f+q)qXR0&s_Ul=*}Uq)V!!wTcVX5AC!T>>yi&j z^UoRR-WUCpJ~L?EAn?+|b)<-!PuAm-=rhLzk|`H17?R5yC_6>~1fJD6Ol&FFgKMeu znSK}Q@@`D~?JiaARn(FhNnA@ZJdSC}7=};X91ccu zITUhr3z0iyw&pk|`~50NAxV^E;1WNKQ{FX=GR%ER1XG~ISi@v7&UY?8m39k{yNnoz zX6^I${HlzSEw#8R=W#d#ek$`!8bVpm1o4&WSlYGdiKO}2NXKw-?@CVEf<+Bl>uiq2 zf`%C+zfW4@d_|~vQh9rb$jKr=Gx%2Kud84mo2R<-TrZ2Y)CS+_fF;1Ta#2kf`|FxvPZ;kjQDC)#f{Mib2xsuV+o z3aS^7FaYj(t|LR!B>3y``7Wf5j*HK`qN9SKzcv9Q#RyjgIA0~GW zf62{!mM*8Zs{0-WZ;NVP&Mf&$;&<$Fnnu5KseCBBlSiKAi_dCLn`8-8IVX^N zn(;4+{{RSlN8uY=tFIL3_Lo-hY>_TiQ#j8?Ty*~cXd3+*)_gt~mW_L3IUJnV6Y+1r zHhv=Th3&4d2bm4bB_EN<_OCXs4iopRa#74`#>)C1n_d!ud~3bLn2rWQg; zRkYo510l%34HT{qT!4BWYxGycb}@@pF`SY&0!YR^je2-WaGVsZk1H~-ILnnwLN5vU zTl+dCiqbzQFQWnJ?d@HLpKbPd6i7yP4IAAL{Z6dHz`ad8dShpAg?Ftieda>*dVfN}&O52VrQzq7Z*c)lb2H_^4bNn>Qxtss~}Dj?vBpnI!hba{eIIL}=0%Y@osY=NZOpXI;E7@A=O?_X_4^v$*jk zh0Jyg&fJDOmkM!QSentL7b!a=dKf%BtIa|R?es^$f448jNIok3e(-mMG|RM-$lf)^ zp%K9$tj-+iLwx)bvQ{8i!pHSio7Z|(cyNmZU$?QMS5Zz!2u30;g* zpa6WkN}P=U01(eXUd3U21-RP8vX10e<$0ZVh^*&x_WZ93u$X95O4dfez7QevTOaU0 zYT|w_e0b9S9O=#dseJ@@GJ;`*$(NM+DvHDLcaJrnh&u7`ufR)bHSZD6nB;qWNd`EC4D@yR3c4~s4pWM-TRQp}N(h**5YWxiwYfGdeb zEo67OD4#C;AN`enDSp^9+s)!@o1Y7KVpkFuh?TmUJn@2YjE*smGo1SU!TTit0Kqvt zGy6D6dvm78_N)Cwsrz-%NiQKlpcwq!x!Oo41HNnN4GY4ynlTXRmg^Kr_d=)}ewY=~ zS=bYS7y-NS*Yv1za`Ylq4s%KHU8a?4QaE^GtVxq3kaE2JdsLn~@YH@I@ZH2$KQc)X zLc7N~9V>SBGSjNYc#vUE5BOC70Atx=R#rIZJ%3sjhE3f3mDap7ar-=cchP@9SSr{{X>2zh!$ri~j%)Zm%?yXf^#X z8=DKLuqBE`83QAd4?;ctYvHefe--Y0XW_Zv@pMaJujv;LW2oAe0LLn0<^!(M2q5(9 zRNpqJ-a5wTqxoV?W3T)4{euU2>HgPR&pO;-f2>h~pS&rf#1KgqOn~IzVTUy#X3ZpF zy}8dH-lY@#i~%Hny;?ibAJNp45aSohv0NHLe?hXZh`{{ZlkGvmkyapUg}C<`45U2Yi% zlh@{_HQv_R{08gubgpf+>0%{_{{Y8 zsa4BxNB67GCitDFTRAtHouDHiX5l+^&ozU4`&f7)()xQ@d{LzRrqKkF#rCA!i`d|v znd6G389k8fdl9_>aI8nEE!K~=E_o-BpS@ljpSEv;=DC_UHF<6x9PaXMo!29%+!q=D z0PEDJ_Ra8PMI4b`>P)UPkz+0tdXu;Lb5GgJu#abw=~Xuu{M)5fmrz^~WIaE>Uq5QU zw~vP!K^})~tKPe?j0A^n8MABKB1dh5bZB00ebxPl{b!-8IKA^aB||lA^5ZVQv6c3*L3R$bf`3GHCa|G za`U92+j^-|N8S75ob>6F#d?;5`!sxY_=r)pPZ3#Y=m=!;BJ-VxsVqSE>G)MVG?lK+ zBT_A1=c4}8emb+&ejZ%fPbi5eA}^J|X9a*b?s)BAZ~nr*AB)4^0em=?pelWh0*(0N zsNj#rzDD>1{{RHm)b4y$rfWYMJV~f{itkQwCdUgDBb@CDyx@_O&u?>IpuY?B2)sMt zt9wgx^4p+a;REoltTir2bI-?CjH06!c6PI!xO0Mg2{<)uK4Cjp^V9d0MP)560XQQg z=32C~7=oiYS5r_5T2Ad8Kd$o8>#nIVAr8tf<~sjzj^nanH~G zeQ0;;H=JPOEI%rRu9*C)%y2zdk9tE$mfulhA&3&JI-UOj{cdVQal1b;UBfu@IjTkc z$rvj(FEmX&flS0wh$QARmltPwGpO~r12A*)to5!b7qG!hGL+o!}aT))jijRE#tKNG(ZqW z2;b7Wi-s2Eik3M&GC8U@5--|!z|7Jx3_)RmPRO2i&lUK$@B>2eR+&6rC$oy?->wV) z0IN77Dn}smk?)H9^!=%PFROewj^j?zyzNiIaa&7wZbK}OWh-PPM>rxNNWjk=j+n>l zZ^UOwG<$`S$^wM3%JKED&X3xL?oSi=)Oc6JbBLvu_R_*7RztWng{00;&GIQY_O47q zidv)9%jY*MCVIDmWV857`!{LOT1Z41ZkVNu5T%aHu^~n?pGxyz_$8K;ZShC;xADJ> zWR>pb(6q~4E-Aj^@40rFz)~^@R8D*D{JXE(s${hIUpAYkIEk+R0C1o<7+(23hBM7| zAMi-uhfw%e;0(Ifo@8_4Emq?0X(b9B!Z(tmkPa1N!1nK6W>*y{N^JGBN%B##_MV&; z6aY4P9EmGM2oI9nlY&H@1!P-Zh|yVFBd#*MR*1QK#a|@+gyfye{(Woc6Fy0z^@cY% zX6Qe^)}k{XKc8F!=2F|P!i!5^BaIV7Fx*HtYW&1;Fc%v zV6A5;T;82&Lu2!s_FdOz{hod&%kbmGmsc{_>JmycsU~Dr^HA@2$p?}{5;z7Nn42n}b#m+;&mNOd?JUvL{3NHEFIVmS1# z3cVFW5emH<*VOuY6<#KTkCFN(;hkJxY5xE#1_&@QCVrKmZyZQj&SN7xyw0`azq4=0 zYfl^aCr!PYPbl2l$1H%A1z3)9KhLdteBLj$ng{ad=Ny2;oL9XWCa!#};Nd2kHmxtb zo3~|dB>A!CbnX2sN*kfH5ZGhuCl$z9_{!RNm&%c|7&*=|J*#1SMHH}xgUoH*j#u;d zs#3WQEYf?X6W|hdoPVtAQ%RW-N;&z456{xGEj4Jq&_rd~h|V_yj8>I}*tp2tbB;k} z2c=ca+8-GG`8$c@v(>2Oz{5XQ7#r#+!G()CI2_|E>rxZBMoGcwGPKDVb3Voen2--$ z{duVFE<%B@^clwfl>3P{Dyck=_LiG3BLtpDKQhoVv7Zi0u_K@!XG*1cGkKgj_51aB zI3a)}?LRLfsmOORW;i{*VNk}mAoKpyg^hyuKR+U>-LUgE$05i2{c6Rc7@OvDbI_7F zrImI9dE)~Bik4N(nU3djNgIbv{c5?F%ureR#yOKe(yZPwS0i&A9+_IKNg=SrZ5isd zo6w>kGd9h%Ie0;4B=`O0TAZFTdUAOcpMQ8R6cs#nAda<^n9{kKdVkVGZ#fwN@2WE01Cm(a z4$oHRCRu**=hTX!bfhW6V*>;R7_45VsI7N%^8ByQ``v3Y=H!<+&jb72>fG{|4f7oI z9Ezs01#+_5SNJ0*;-MO z_#=;^bgM+Oq0!~Q8Q^*VE2Pt$?9K@M1#&t^3^>kD_bZ~)*sOpNocbpfqGU6A*5HO4 zbNHyOy*lK)dB;wlFEz}=0g$dS*PoP*KML8?n8wPbK?LK4HLOTz>U8Ohg-<{C#cNs~ zTL9;$3M-$}?iG50f_eE(YgybMGmtqy-8H;flQmFe0fUe~x;d+`hGKlcK*8)QGC2Wp zz~Fyy@mDRU=WC7+L$b9*vgB(1SI8R#alp-5id>b>NykhIp&M;2mFd^y%};K3lYxRq z%Y>>#mxDJM9G_uJlE(xv9+(wf#^6sm9rpC62HXx591c#(pdi1GD#}A{1QWo)73W_V zeiT~#PS7W?*A?0+Rg@I~GLjD<`tx3gEM?emIXL^Dd-bR;H1go!WP|;{X+2FLHwScl zzjON{>M_W+tKxlr9X<$*aYG%$00CTodjlL}00EAbP7m0J!+K5o%Xz1NXwNu1=D7LU zvO{-0cMcC~`i1ndvpYsx{feP`rzDah$rvP_F&M|=QOJ?m_3E$fA2|F6yr1?u@$5Pd zr#$yQ3-Kl7l0`k$$zh^Rvv7n6I;R4Ph^00Thr%K^uAZuNC-%@XFW4 z`Yp|-p$f82jJPpp0FSM3z61E%sQ%7ctU4#flXrRH^-#8Y$+s+F>=JOGg;B@Oa5?AJ zy{xw|RDX9V1Q5cSH*V->|9CkIVq+>^fI5;V&0Muh?5pX(UpltGQY{ zI!vo~&ioRs@8do)}t_8{t8+I~2QO!A>qTpono`R~`m5ISZFmu38 zl;;9j0YBc(3UsEWadjqn@fJ?*di2dLp>MMTD8b3-0U%X7!5gyy+;u6MifgfLY&I}E zMhWuz(B)^S>{^!ZWCY4cIOO10HLB{Y<;Dp;Gqhr))%AoCox}pmoD|J@-;TZ~T4*XF zm4TW-N+PH%KpdXDeQTbrRUO%CH#9s`;w7`Tc4h-S5<=tr;=XSEp}sTECB$AI@QHTS z^+s6LV?{q_MmRE&p4{=&n&tlhXb;+6{yY z4~TqItLi>JlkGkwj!5FYj#LgU-{x@1gNz)IFh7Kv`P_CrO7Md+#MSl`+`6Ale$Sr> zWq`I`PZZBPw=1q3U~HPyGV_Pi);jsCcq3b#!9b2leqA5ansVj zQ~Wf~bKwhe%5w0p7#&FKn*722y}T=X;opuv6Y)2NqhGYF?F6y}!Bx&z9=|p|T#SzO z`jznZz{%j713I5FOGwzMkD(|y>+4@Tj*Y4xPeNSOqR-9W_$(iWuKWqC_;1CQcB?JD zwxtxejpZlEs&Wb4$Drqd*1o&=H>^$KzXWNw%?n$b$W~QGDCGkTj#S|B+;Po$kNg#% z!BF_0;PuoJ`GKQ?SxH!dCkRe4pKjz=dHXGxU*NxmzQg{dbjT7iR2-;{aB>b0)K_j+ z?*@(>*HspJeU+=o$`}$G0~<#br5&=8M?9ZFQR(rIB}p9tKXaO}tF>9Maop^$VI#u5 zz}l)t1Z(x-X^N!9`@qEHpSq)(bcke$%M5|g?4}3V!;C2IW8iz!5mxRmF~-%&_EE)E zzqfK3)G_0x)#-}5s9z*5IsWGj?^U%lVQVLslEi;=r9jg;Ti^}qs7Bf|AUju|#=bEB z0D_x%#CYFO@YlmlGwr75#dm<-wW(EWYdFDaWZZgVE00Qr8u zjeH6FMEqdz@9h5o`(${B#a|ut>zOorO%Br2Nx2peaGrdVNY5A{NJ4zHIV27SdsjVH z)O1>&js_}K7dJ!e&k1}$)4mn_53-v}fZAAC+5)OT7(`x4I2bq_@z%WW_DuNCto&H< zuZg@@t1Zl0Mz8{wN6JdfKrKd;scvW%E z-hNJ*tDCpRLXH5zJ1g{f?0!Kl^b`=PLI&h>l@!*9i1UJT#xNq+@q?#N? z+30`R^r|M~CixdC4hAwv6KxD@-LmCRtBqd3`2jvt#iz&vATT0n!#JDWK; z=rB2@k${f@NgjblYCD)2l;my6{{WtO#SubwCgI88{_n5(=A@ywFrO&-N^;zflvNu| zGIIP9tWPIs!Q|q!*#tyHOO4r4c10;|WsjJ1o{jRYL3>j9x68!x}>pKFOxSjd^f)WlK&tjd74r2G2a=zPA0f zv>2^z{3)*sVIk3V`!d*P581E5km(*4(=9FhrOQYn3ncDNOS^Srl6u#^MP#87S8hjO*u_xN zm@KNp>mv{d82lD*^u5>rjcY2@dBQ zv&@5~No_Ef05ITV0zpN<`0^l4pej;C4tj!Ju!#&e8w(kw>>g*fLDR} z*QeTeO4?|K>v-{wKXqP(Dp9E$qn@@U(U&cc%H1=@pA@dOYj`gHANYdL&0jg=i%c)& zDv!F(SyZtYz!|Qi!;}17@hm&EKZl+owrMgEu9`T4VE+IZW0lCk1OwO9SLs{$3fIg9 zZP0_?%d56t5P(Jii2%nxx)rC@ljvmg3v@p?CGZEwE6H9B7s4_^q=hovUqiSqIb{G4 zPDgxo>FGX&@CW1V^^DJ`X*ytigd}gMqO%+xjIr=@fzKW5^nNc1#3aJR0bYOAaB6?} zM&a`mtZEUtIFGG0hKUa`mqdPU+J4SI9<>;xfi&$h3DlAn_l?UlVFJ=0anO>~KY~dBW}=G5Ytfwk)*u5f9yumyh*zG*&s7a0?TT zBk5P{V{MGyHm7sr3-9ZN1G@AlSKGdOS8Oh3k0PEVh9aH`Y{{U^SYfxNk zo-grr^ia%XSZBE*8|KP}2;dMhdkpvKU!c+HBWc|j=l+@VP_~qgKy(CWk>w6)`xLek z#?OQB<(f+}{7J#|5 zO-2v_3M07K0mcadam{&e?LYe_Xg&b=L95?sQ0jM6+1be=G?V#~3@%PR_|1K`Y`{2F z>;A_|;C?lDMRorG4P3z_Tb0nRJiepSl&K}qaKz5)?EIenpY%&>-wDfkByqN)zDD_$ z6i{;>{+S?s_V=#x;>q1JxZv~9X1K{Lm-cP=$*p)#;sak>L8(j*nRhk3g3eGGjA*hF zR5r&|Aa_dG)I4i$QJTtFWsQ`PB9K?UaC7Ww3lOC#-=XIp9JP4#&lu<`uszDe;L3{% z$%PX`*FSfW_pot;U#4FOwYyzIM7P=qb=n8Wrz0Kn_*dm!uZ?t%9(-J5uHHcfg`}~9 z^C%I@Qb55}k=*h|atK=c2jTDSRpHGy15Vbh=Xk*mu*S|1h3arHJ9`|ARLSz4F{LLI zkGb?an|pN393F&#zb{(qbX{r))c}!Bc|UiW_*x&^Qrhcd=++wL;xa48BG?p)P<>g5 z#~k3}p*7R^clM={@k(3TUwqqHSRmvdQQNV{)7FxzkrKkmpK7m(?cPwaIN)a(TGEGA zitFZA$;LB*Unc1v7WGYD7kI6wkAmQo+{`+BpnID1Z-*Wr)b&?a@}~$#8H;Go8OY6P z8n-#;hvip2$m;6rw1NTWqSNBM1Mdv?2LqbqE$nXgWrhggf}@(ZZG2@?Nk1vu_cMyu zn8C#8#LT2*XK=?sig1_Y9eLz@ql&{@j-Y^Z(Cz4bY43OukB~QU{m$Oh`HAHA~$!eq58ip7QEQWT$*6ZZvDxkA#N!GIV8018nznBiG*yOV_+ ze!S95rb%0J;3(%Y_oDY28qM--3P~rjuRPMc;x=Hxx(wk*6&pjbMmmr7Dx9JGqOMdH z@8#zmarLEfmI^G~01ieofx)Wsui1$66p{fM!t+pz87w0#PwrgqKfCFgBZGRg%HCjR z`G0qg-8$5ik>@`fH7C=2Cw(HFr^`EXtAq9ZYx9fYXNs&oC;rrWRB$t2Nu*zDH+K>_ z1X~!@V*um~^1u&Gr>|Q51pTTcHopzESs_LqU9_$MizMJ4oY&;%?0Mp^_(c98c&}74 zSVEG|H=7pL^A|HSWG-;3c;dLRiuC7g?fIVGR=wnXP5W2){>M+Xu+rfMZBJF3?6xX_ z3wf?YV2t&~;!pdv_D{es3u*rV4Zap=8V-#on{TDrM{KV9OFk5Q#~sPZ;CHXi9|jn{ zG5*qV>$;_^vg!U7f-_+#iMF)Tla^J;&Lb`K-|8#vPYC#qT|HukV<2?^97Zt?7dh+K zn#Tc8*g-$r0VNeJ~+fc6zne3z_Ka~sb0AO+zSP{^HkzcGjhlkfvR`bqzk`&H^I1bDhY+LF=53Yt=NLgt{J+ zV;#M&k7XQi& zD~<*T1KT3H?E>xAC>Cwx6A@XEj81 z7?7RJTrne)z@?G5wp<*aWuoK*8Q!3ApSe|S%S#d5InIC8(Q)snw{P-hAV35Xc8Y=1 z%)nL1`VJ{&LU61&$Uo}ob{w290B7!0feDApL6zsPLB&CKa(?L_KswXz-y{qXlaKXv zT0`>v&bj{pmUS)IWnDmdbFd>h86#-ov+gpGwgyS#psSY+z4Nz_dHFF}_X9DKM;^&p zNVHMC8{$214@?TrXY$nK9FdNKr@200A^86QfOe{reDjR1RE|DSD=8LLxtOrYQgXJf0Pxd-iZQJ9X{{Ze*Qgq2*KM_<_yIAy?@#3QpPsr$#4iK1JG4cbKH!2 zfl^Dz`G@{H-k^~QIURr9q*=<^I0R&HM;|GxMEPx;bnmqDS@9emxg>YZU$$>CS9;)W z$?MnCG#WDXoS!)0V0#{GVgd@O!T0%1V%u7!nkqyvsy$xGo15OjM=TG z#$r3LGoC(Ez^;o+oI2#F&VRaVoQQ-0kc^Y>#cgQv?jv?H*aC4@nJnrpBoe0`bLeYI z(oMd@rg`G9Y_4{rz}Nl6E<{KbK*7SaC?$-TDDgrL-OEb+}As6 zb;A7JJ!GvrT|`2F?jt;poZ_}jhK=~=1+qf^Ijc)LyL`KO>(;WZ?sE#2U`afYCtAI1 z+fWkx5_fa(3XKQfomn@R?NP zfN*)jlh&B(B6nahfzYYJH4;ht&A0$(BN?j*Jk|LK&VBf*OqJM;V-dH^x%wgCRN^Jr zFrc2_Dd|y4zC@TMN&2-f+EhY$QO*zE{3(U3Hc*&gp-w;9HA3Rd@ZmuKe{|K)F8){Z@k>S2v{$uUwaj+X-C9Zq1gwa=hB5p~IOeh2g&xKD8R$ zY2I5zSLGo|RtKR6@$25K>b^Su&A3Im0U4NuR|FDz@$1G;J*&-sW^FO`AKCB1PoH-)yM$*aVI!G`9!i<7fc1iRV z#SS5=s`B!#Tl~(oRXutiTR)GZX%NWB6@eMrMhCw?N~NfLL4qi;z9aJhM$$MR=e2x% zbw7%CP%=TN**caVHawcBRJz3!0KyTO#Pp{Pw@>^ylvv!+mAhzl}C~!RnATp zGPpU&>x=+#+Px`f3H&I|SlTgHay$P3jNi4MmEp9yv(fHS>sE#%FWI05NjCogx;p10 z0={YZspD@Mc#FjPBlw2g=^Az3qLw#u2=O8FN(2T%aHHmY@J2uc4m0&%fj?)z4)_8Q z_8T>pU-|1IvBAkdE_!u8hkDHT-@zBwHZZ`mOodQL9}3yXIUI}-4o6H1@^M(o zwXdn?%Qn2N1)*=@f9%!akB1se_s~IaHSEO6B<&w8PgeImv)33Mg?JB#CbRIL?P22E zyC!6}yS9Kbc`dXs1eYWn1Jl?1cPt|Kt)N*oh279w`&@W>0@wr%8)oGAbEMlKngkP7QBd4ahEgPn%J*uoLfGU@K=tl zH9Jk-WNwN93=r}?e_HJ$)uO!lAZ2D@f_AVY@vjE(--jmC?LtCihDAWA0BrU4kHk56;!_gK`Koypv~m6vV5g~x^tSu@a(d! zyiGRHLB>9AN5AP;b*)XU?A_DLI0u4Q0)D-#Tj+AzQ{`XU>%kNF@5X)_v$BE9N2}X0 zRR?xV%AjC{D{iv0rCd_cNHOCj5W4&@uNJ?rPO(&noCkEFxF#*7zp z<{$VeCWzXP!7mnE+p_tV+I*%k@%*IhBOQD0HHZ5-c*0v>hu#*`=C@mU;?v;sQ6t1? zb`BRDVW0p!=c-d4<~_&+5Mh0jA&M3 z;Z>T_6o9wPS1O~SBaT6?ytOqJ`?H@hwUTGidTh-ts%`;^`Hoc8#*_Db23zj@r>$pb zFXr2l;P7$ZrUguAN4X**9HGa{o;a^==g+mNYwbHA3ROpZ?LBk<0PCvq$kR>%2WO_! z%{nMN!d~Q!y+WPXp`{48V!Qx*^zA^2K^{oL46okGoYgzdKmd2a`A;8Oky~gakV_tZ z_c*Am)6bmes`J$R)G?yH)rk8U+y@`*8u@qj#Q1$>sr)+eY?`D{;^M``h2h=8p}-w; zj!#bY^>y-viIrGpXNIc2OQ$FoNr@lQ{{I! zU)is~wthAE8Q{6^ErNL(WvVa%vfB^>0Uf#-018J0lg)kZSxGukmy$m+&a2DY&OU6? zwu@|J1RH?Q-8|FGWJFW}k%E3h%`Wh+#O=>aeB2LjN_OSg8Sr!d_X53?eDQWNn|mC9GPvs56z&!U0j>T)ka!;3H)8Cd|A^cwS7ZL@s6Ww;_W`d?XHaW4!|nNs>CF* ze(ko92pKi=oI{VPgQT1m=hpD1S4T0eFKYJK`+MQ1?3bW;15bck+lgULV?-m7nEJnh2auHcn?av^Q>6-fI!4?9_-W4(K z*ti6t^y+h4AK6j)f#!&|Is1cft427KAp`xl^;G3Yw2W7(!MTdzFsOQ&d zspE(o41M1FP7PMFx>=N{>P`-Kb*nr4xeBOJpZBZSPUnZznIhdF;1SdAp0v|!8S%7d z{lim6$@iN8gZ|L%O!ETCledwN;-(>w9w1^D3yf!J;-lDE8MXoc001>Q5CO*1{{Vec zP!PE|KBMO5fCxwTR|DNmPqaqMu|`;Oc9V*S&REA)bIwf{0$sb;h2S23Ls|OHogMwNEP#F}YTS2VunIvRjWOIw z(66snq{Cz9-`X4YR?xmK=y#fbinREy?QayTqr^^g=tc3bt7 z3J`7j(&dOc)9BAWoAyx93#o=AMp1y?PEXS(wMd_`?u@%bNaaxO+vJYFO7w{4K1dvM z^`-N6pb8K+bKajMdlT)a+~u?nf*MYa@yQsHO{b$K7p6EB*W1`zX|S)^V2w78qAU?m zhcdAzX~E!gQpXB`mctN#+Nwz{jO8aS*y%2xdHF!&ynXRh4w53vD(w;;LZKg}X~cq8 z&&qmdmg`TK3~<=U1G`h)lG+Us9B0tv{{Z!>*V+My?Z#B(ADfCm z!-K%b``Dm&A$ZQ^5U%aqoT;f5RnUB+ILY}B$wMcfqpyq}ojmB3RWByQd?bI=;IG{Jzt zz+U?gHJ@&VTaTEo)m_Am+|)=D&~Bl0U9u@sJhDLt*1tbIU;h9Ek<`3N@dH)VJTc=t zj|}OWw8BYkEcE4I%oq^akdPZAumhU?G1Y9xlIS*&+B530;#s^HdH4Zx6 z9W=2HlF<2g;Sc;1UN41S6oXIjw}>wnXfE$Hx?DVx6P9*oC5b0JPkQuiH}+7zf@f(p zxuj#1!&)F+r;f*uujyXVrs;2LR3TPVfHDq8<61FVg4h6O@xi32#2zN2>Uo!je`kp_ z{ew`rN!3}19#145+0Q*cI_s={5oy-5#!>)EazI=h`t{Dq3<}_5kQbcQ$W>Xg0-e2n_Y}kj z&Lwu?v6Gg~U5LHMNf1J=S2-WtJXBJsitTy;f7v{mxg!$4GKC;wTZATpm13$%6VUb)x<$tRR*d0n7)Db4oKpbZy zv)bk`y-RovB`iz*FBJ z#m#3a6p+iA2Hrs2KiNFhON0BONXAF^PZa5HL6BsR*R58)xXfEd-+#T$WhOEWLC=;p zfs%i^d91sZ%92Js_MBC_tFTGjK*!dyZtj&4wvo@)v6C$#D~WK7I3Ms6%}}0vi~uwK z>8al3Ok{ky2OaqO)_ugGTocprteY&Ya>s62Kc)fzANW_f1xs zKnVaG=Q-MHc6^~8`R`R94>2+m&tOg|4CSCx#t!40^{s0`xm5h4+jmOKx0`Z;8#p*$ zoOP``Nf-s{Pk)+%%SJyoWZuMWIT&+_(6%5*GEPVPd{rnE$<+QEs=~g;L%8F=%}o$% z!EgovY=%8IX0~+s_5p_D*L`!g(iqh?1|t|Jc*w15Irtlo2mP+~XiXgzmB?opZcqDt zD^pLrEaWEw=C{*yq|H%tzztE&6`V&n^$@3f%6VHtqXgTfC(gyr+DO6MVHQ; zl5zB_ma~y22|nF8ty3kVYB|Y3Hy#J~#aW7Rj4N^9=d9@E`EUvPAKAhHx zl4%CsaIP1gyU92;Jae0M-S?lKH=3nv>_X(6j>Ukhk==Qq>|=q!`M~G$szMfPrA0Ym z$-kjjxKqQN{{XxxEgDZWD?c2NcMg53t|Y}|V=%)Vg?St5 zcrC_v91wWGlc1)=3`cCNNGB&QD$)b90kR0=_k)^Ydl0r14tNIx5_F`xL@qvTZS-@} zrHq*Z`LExoaYWH?+(UFcfZ~|$HVDCC^8=2bygXFCP8crWPDT#?)e=r3l~kNDJY~nt zR)}LVGG_;`&M+to>Sk)1f7%1A4Y8X5e8lnSYm)eb;V89z4tR#qy$a{dBN^*m-PD3I zaL4}s4o~G-SCTBT$h*c^WCG%cuI0viGs6D>XRq244}iLD--7-uU0G@CrnAYW+)HwH zO9L??GUNqPy#n@KzLn;m9)D{s8^`|u7qmMq4QIc$(t+}g2tgMiAAhTt<2OA(#| z``5mB@8L$9;}8>Cf*XYl9Ylp#D-MV7$*dTD1bAZF$sxGYEPryL7dT_}$r<#nS4#5c zJuj|ZYI(h<#WAU|T{7D&<8*=N*u{9{01i*&I#-~01IC(#pTJ_WpW;4`q1zL2e`{`x56t%{qd$#PwfNhh zYI7L0{Z7tyOg7ZGQ<2n>k6~Kfb!R(_yB!hGVwx9u)idAbCy)OCT}?NFtz`?e0ze85 z{-2nvLGd$A^JDVwqZwSNGLAs+?^DC^S5383HRaqHEXS;a6?EH*abbqkzf59% z_JqV+TcXGdODmizqMy9kz{kHe#A?5_mxz8fUAB+=H0U?_z17hOx`fBcvVb4sc07yd+>Bo9`ZYt~^FI6xEZvJFxf( zHl)qjeA7p%M)rAX3TqDHIopEv@?9R++N`$+!NSHBc>+5A7? z3#*CsTa+m46Oy*8f-=QN-p)ok*M^j1XfDZt41o7YOzlAzD(c?>aWM3sdeEEkg-AOg%f3nBHwD1pvZIe|2wHd&Y zc?*Um$OM3WzpZ@%pxMJ~F5@bxC#RSO5B~tDSJ2_^!>GhMe!spd4zTcW6+ zDBQ>8{{UEctog3Njz(r62Ebt^dJ2}_`_2bpY@TzxWANkBi0mWI_iUVz_s2?mlC&Vx z?psr5Y_7m?2!6l)YPhgxa6$tfgMUHm`cm4!EEKqMLw~kEK9y;rZ!0{WI+q`e!B4f zt>;>gG=s)S^9dt0@F&5mtABuB@KPTUY5J2#4Tr?-IyvAiBxnuf8OXtGvoh~F3)}*D zue&rW&?5~WLBRRPHTHQOe`!H0?VeL zaWgSdztoH{{{SMSORbm%xb*V}Kcy$BQL+;9Wr{4j0lOc@e=4BTm%90g!NKA~$F)CF zlgyB2M!@uO%`(kTlv#<$^>M{VQ%mSvEx8p{fIWGC(voRIe4(;WTsi$I%ue0R!vS!9 zanI>dyuMQ@4o>b*?*@LgqcYr8kIa#Gvf%#!wn?cXeq!*b#{`0V?;K{B z?!smTi!nWS1N`Xo0=4u5P_~t3JTSl>V6TV1KX^C(8GH7NpU0XFqc?>7V4}mua3h5g zAXf5k_)ci&A($GAE&_&i_-iz*DuA#hV^?`?|dn6@8(B5Ojx`NCNRu51N3F< zn)_m$?vAJ@i&96rPe$pa%ST0(Huyz7h#D6 zWziX1KfrK6ufBg{zuH4h{i8k;Y1+-Cs<)CrW4*Q@Z?~Q{DC$RVnOeUn#bM=!sNm1q zsNy4xq^n2fdSq7R9o9r3hBzmTkHV-;VYHI2Hk>k_Gm-0B!cDE)BL&JW=?kF z{b2n1P>`8o+APhJhdJryAJU|m{FmBWmN+qyxw2la$BJWLH-l~myfbS zLx6Gz-#?v0I)}qH2?uZb!_zfA%!AC3D=`Ff`@v8otfU}(vh^Nd=cNEeuE4Es22|&O z1ctnC_LulAZ}FGmwxgt8ZCALAn55mf#USNaXQ9qH?bz3}UlTY87>xA&;H=GB5N-DN z1O9pgllf4~jJaNi%0IHd#2N2&DZD4+DJ32y@RUgv&z&poo+3)4<%U>|yBUT?;n$k= z=;q1YxD(g!n)6@UKjDt8;SU(w`0L@sa?gKe-|2R7&dN0e2vjSDRxN>n(;#GyMQ!{o z_@`s>E5i}$8Z3<*fNZ+9k?}Q@+d*ig1Pl;PGtl)J73yJY^T(C$k3SnjmHSBS&g$6j z-b*h}?@~(WP<+ejkmjpdUTuePVoU!3(@{$IxycMb2M6aE`qyFSlR?z(ZuvhwD^1;4 zf8TwpI_Fkc+=Cz=Sp`wK@q{+vgUgI$XUr6@Vw72|*Fgcp41>?kf0b98R!GAWBInc0 zHRirO{h@SU3q=0_Yt$kxr{-9s5ZW;doS-{8(>bb^v%5~!n&YE~x)aZMEh&*>^pg^yxUE5p6$7pG0+6n9iYs_^| z+ICMAT?;RRx;CTYyQToETY|Ri5Ak`-0u{zaLmVCmuEXKC>}GFu7uG&DYF9oe)aKY@ zj#)NY*yB0!A?Il%^4ZD4`g89-8t_G~g=itMM2;{ps;mNmj=&FU;hr(SgzSbEoIWjC z@*b*xX$>z}(IxP&hdv)_x_r*59!_sv}22l=q3?KMB8SKLq?^M?VTYU*Yc%GGlypT7t+ z>LJ~jK2Q7Sn&Q4T{{X=|J{A09)uhz?S>an-Ep5<89Yv+WFdZjpv#plX8O02|a##@!cQxsne`A#nOH=XW4dOHIzHrXjIsh7=xe4mqdl3&Qx7_OqU@NHB(@3T?;a^cOA6tcNyqok z7^tGW3Ws^x-i5^=z4Jm7M9cGn7=Q;;zk^b=rI+P!2{^{{Rie6L&4ZqJ8^=GTO&!PY zFwM#T0BmziL*jBDf;Qu?nbgurF6O{|bIIO$s9sYXgl_GhzBu-$NimWfhdgoquzpks zc_3~X1atgntwyht^NJ`w=LJF&-|zi7=T-m&IE>)_#o~lCj;jc zjVS|r9D;I3m^x4b0IMJF*lq`@bHK;{0Ir+3?oLMFGt7r4H669aB6GV0oZ!emO0^4j zV}>Und4hr7!^TvC8FrD^c^RmYfX-ZeoqluI6y)4w0puhxJzQ{VOIu(ZvvOEqo#Q-H z5VrB7?jeE5|&V0eeG$JUMdoV0; z2Tw57*pq&8z%l+E=9rOfxZcE$Hjmy4kqJ^fvT>YbxTcU5+5lxBwm>}m=Zb_WNpa>b z)&Br&=ku*Mh&doPBzAFC1-T9LIOF}X&*?)zn24%D`G5nQ?=>Z=7k4gt;~zQZpq@Re z!xOmw0M9|qT!q}desR)-3`K{Y9COFtIjJKc9jd?)#y6UB0PLie+D}6uq;gVb z+QbGw^U!fkAh@>RMZ3#jK|KEO@l(ebm7R$M0fFBAmI2k!+0kj?@ODaam< zX$)jJ%K$&?q2SZfU)|?%Bmhnvb*41A17q+{IFL};L>B~r2qPT_&s5oo-RBXEU;yU^ zwHN~%WGj@K$yxlh9i;H#}twRFgXTB9QP6$u;=9nn92VDY=KQ?-1}9z9G~6}w2d)2JDWZK z0C*|fL)Dp6EX#s8JJ0J%d0d7WJpJ=g++1c}812CRF;QII7?A9852oRYSFqA1lIS`R z7<`-oywoY1MJ+4*$2|Fmim0s2Tms9E<;PlXFz18XU5#Bs}xDK-`(Y0P<2*dvd=e@dw|p<*L;SoiY@ zspYvF@>`beyj2-)PUgd45J>sQH4LOjJ;7kyfsUU!&MJ-N!BiP;G1R{`E$!1P@JTrS z{{SYkukQ=E8;*M&;~$R|n`PSKUrxJrf&mMh?mX6A-20G}U`X_HQ(WE_AyJOgoSovR z$uId!EK}#!5udo)RK&!m~aQ7s+TSmd*|qRtmMi_ zt8p~L+|>8dZHzJX$K5>EOz)TW9>%e3w1(YFw6Wxo*OOGPuFG{N z+|y@oF`Ix1&tqBTg1!%LV^GG0xt*9CJq`s}Ib;QgAb)gFQ{1%- zq)E+CB2p2TE;aDUmWPUM?bPJE&;*eAFZp>1=#?b?1{_C;jckPcKHIQz9~-)?st zfuHWxrb*J;%)nPSfhXX(XbsV=HW$EVB9U$>Z| zkOog|D9vb@EVm@Yw(ODzB$Bl>5`EJkAdcA;Sr3>7M{n+mniebv2d`bCs7wGILE^r= zKY7<9@-(0oKR!kWsOFm#MQ~0){{VDS$tKbW1nocF6=;$1!duN^0Ia<5Vu&{9 z2cB3jV_8nTAg?BGPY*flj-SOJ5G*tpB$HITwzZBW+*(N$R1PwE?Or>te%pQ)Yu~YW zMC!gIy=KD0q}V;kX3hW(1`j^x*QI-Ih5H0}b5*ov_|ErUF}pLm>lpdSjaNs%B|BK^~1PzA0X8`8!3Q<9EeR zvrpiU0^0a~&RHAHeR}LgDn)~WsK3N`;|IQR-sIo1SH@ox>elk>zAn>rt1?HQ6`0E} z%AoAvah>0Ip5IFQNu;*Z5fPEGfG{Ekn-;&x`+G|E5KTuNF~z*IF!sDC(MY%1dH%xy~K+ytKyl{ zYV8x>2|Ta~$mC-loPRp{b5Q-Dd^c_gZC_6e0V6X<^ga6;;CyZSa{NBf3;n;u+A5bD zcYUTJKA8>2<5sIwS|-Di{SOs`{s{j7;F~G@$hAKc8+FI}IMhgmxWLMe8-w39(EL3A z0D@cmD)40SHO`SG^IPpGx0fZ*h3UC7wYr?-9Mm2t{{Vujcn3`;KMdYat+4~;)9sAh zXKxIn8QuBUpLpN?3Q4YOtvo*sJQu3m+$=!H_K3t`^T!y^Bd!iV3fB0FirSNCMctoO zL2sn^2GuOIC~a*mE&fQ7Ad0K>0CA7&UOoFme%byW_&4EuyN?p;QAY726@^`1SqK>$ zQF%NM*1l=+X0`Fpj?uFhXP4s85maB+@J4!*yoQ^kEDLXR`22;w)mRk zRM+laG9B-v60au(LYyu+@1H_y>EI;wn?A`l5+x$PY^KGo97g9(Jl9?6WM(o2S78^rFveG@XYDbsfO8BB0wxrK_8b|^(kT0J`{QQjB}}_ z&R@g68oz|bbAU4AEWaruq54-;z8)s_Hj-xx*J`4j-(P%JU#0jxBYnm)HjlfobH*!L z4-CZ}xFH)Ekx{o`@J?2p z9C#Z_FwQvIywkjcCex1iCt%{K8Ml2#-LO_7M)`4qc*h+n@=LZ5tj7)1g1sskqyGR& zO}msUeBUCR)Uvl2hj$%*Md?%o5-6LgKQB&4J?ksPFo|uXARG?3+ml+dte6`~`TbRT z)?T|aMP~UKY=3kd)U-6&@W1>NC*fYZ9;2f8{{Z0Xq@F79Jm&h`SE{n-zfpoR2(Cx=kMU-o z;2#Oz>b@cefzBD&9Z6d6hC&o_^m(4{d2au2k#aePI5}} zD?%AdMud{g2PZ3rube&${@#BN{x(8wd@HSsePR?}wCMNI3vEitv&zW>ox=x$%eit6 z39o$6HRv@sQQ~0A$_{Y6SKm;?LbAMF&&zQ*O1Noq)r(Kf8uDjo$!?g>6qjFfF#=q0 zI&)D=co~>32dKr;-rC!gTE{=dXdK!9lVtC~TyQ&@*&m-NztvOqPA&+YC=`7NMF>cVLDc@HnbcU9wyZsKLkZiX7|; z4Vo!;^6n!8IL^^rPsdv|lSYn3SIcq2u1T(`uI)qv%w<41KPVjjb>ja3wV&-7q5M7Y zh+CVuq`3|E7a7ku9eBy_T-d76g(l?AoE-|4Yeq1Rr_7(WZlO2B{TKcc?+EGxPw^jz z(WbH8w5{er&9sUJN=bkS2O!{%mAU@_1e*AVt7!f^miNWqXF7ky$Xi^nc%%%L(jut) zI+Ck}19{|Rm+EVS@&5qq;o@J~o5L60BJrn_0;Q_Yq1na=2{;?XhnzkbW99=soC?bQ zf_!;4w_^s4scGM0mg7>my3v`j9C|*lYD&v&k@7-0%zz9GJAwuUeqEbl;ftGVbm(UU*LYZ6cffW#~9#(qdn?*e|aM9CumSkO4pkH&%YgPzAJcq98GPg*s+5C z(rCg?Q50UmB#61bzR#?+#4(TRhU^r zZrpHtWqQo66+@t2@d94fUgRwUQmg5^&n$022 zyQ-_@du&{q3PsnLG=ZBffsx9Zh^TiYf_HS~c&0oo@kJ*pO5lx(K>E~hU1fJ%Bj+VX zBNPbC@g{_tj4~vHA;({oW4(O2@z>!_tMIE{9x(VfZ4+F0DxeAJX4I^9no>Lmn+!wKLC7P z)4X?~3+)1J!CT3mCM)J!OSCbK$7TVC9^#wgZ;IAF9=3CTI*fX{jo*cQdHX_qb6)~{ zVe|h0XFH8kS=Z%rHn*Ya*2z3KC`kR~#Ds-~)N(#xNj<;{cRm>W9{9ieQb!)8TkT(&ihI&}6&%wG)u0N|c_E|^33uIl?yD;QRd-B35rzXgZR!*)&! z9<}segMJ)o-W0Tk-^2EhTfo1;5+W$)B;Z$1296dT#dsValvCl4$cz}#u;1)1Yn{99 zQR?j0i!soAQs@hfq z2$&7t>VGQUn%#?xqYMsyLB&>H`?#)`{U0Wd^Xi?*<_J4+u?DiOv-XM+0069^$WK(_4`=w zX2@VV1F?DUOp{Co)-^=sj(+0Mn~SA%ixbFw$>T zRdT1xlX6JxbCHk+2dTt1pSInPgsvcq;4n7x$vg4 z#YfvTNBc35FGYCA$Vax?;PtQB)8ik*nQfQhmyagY?CscM4Pphm6KxIh$Z#Y8@DA1| zjPOCvR57b*9Mix>{15Lwh5K570uVUJ8DGwkE_OCsC9%|%ubAyWYA=ZY01LE$e`sHa zS65e1F%n$(V2SP70r^-Y%p4qGka5Yt>6-Nqh2ONdg#Iwt!h9pE+qL1qlFH#kH&C_% z6lmKAa16P|dW!3fSj%Q{&ka(Z==A2f-orgPIpU^@`CcC^cI189&zAl*QIuhxgh!G2 z)2yws<rKb#QLZdmk;x02N~mm zPT~@2NM#G3rys2(ZMm0rPELBSN@c9VcPy&dA1KO>PJ2}GkYpzvG6%{iKtFb40B1Si zWL0@X^;3dL$=or;S#Ot|e527vHCk6@lWKx+IQdt%T3}RrQ*(D8CnyUL2m!y&D@G;T z9`E8kPDMv4VmFnUaCjuIBBs2TC~&R2 z{lQf(5UjDsh5!)Q+Pn_5Uc*JCRtIzT;BvhUNwg_FeZeEGH77G1NB2SGVRCA9jF%ve z*dHjW3wI)0Y{WNbk9DD9#Am7Z$l|7pfZLSgKiw3KZd?+Zx#RAN2XaejN}@9YN7PYs z9_QVHa(~&)8;<-HZU^@TNFRHWat1%R2?ByQArOzfj(Z%fB+SLQV&913mzh~u1_1Mr zgXQ|wp%`O`l;;`7&~ZQ&rdDh?<8Qk4rTa+{V*@Sjyj6xm0Z9SePDjWpvnKc92--27 zqJTtu%A+Ui)23D`1evc;BH5uMo2ak+6- zrE?}3azhMfjmz6tRmS z5uf%&7Y&C`FP8>m<&PajB$8$@!#s@VB7ncT$pq~_gN%xSZUifr1D?zP#U{gX%P=u> zo<~k7-XG?3o^#TxT)yH2E%J_XAFT#f35N3k^v*%4xY;C^M<;2(BaTI9&2k|^!zG(I z`?QnH*&$W4j=M)Dpt@|t!a&2*fz3-}NMzGuOsUTua=g`hi3m)FAP)IoT1S+{Aiz6M z11d9Bu5O4;q!W%Yv{r4DLw|5~k)6C_sI0rWa7zMD9F8i@$=oo&jP>9e%)FGDFgE~y z*%g~*BDK}YSczkTJMqO=jmFSasU-TEZN!AX$Os+&QO#7A@WKhnz~>pPoQp))mq01Y z4E;PAVV=M3^r}xk zm`}~eQ}cDGxkG2h^Mj0!Q&i=XIplHfYQxL&HcuzM>ZV_J-ah{TdXUh0o0OdUccwNl zM+Bd9N*`h1k8hibXPP$e;s3jkCsnEZ`R4=>0A{sL$%lUpVb0H^->tHDF#EB^qF)hKYS z@?+DGYG~x!o(IjxLqP?w0Z=f1@0z=9I6@bx>@aGAvFZT!`Au231AchVOyJW%Y}(x9 zlfcihtqXVFaNup}(DPVPN##B{>F8?xrS~H}GlFnVD#>W*ZKN?M!t@veZED)cH!m5- zKX<)z_LKhrc!TMMJXWo&>yQBd0LM*QWSiETTN^>oP7<{3w@ z(zSLh3W3wm)~T7ZTGfiNE6D!|#Kf4=$^d6Ok47eE>#(EVsa@t_Z0OK7#Q(7iV zHtnP>g2Sh=tEfW*fzSK3j}*Ik#(VTNZW(@D06Fdy{*`Hp#;v=2rwjD?IIH&Qz+yY+ z8!H|ucH=n7Jpepbm9)xKhU$OWHEEK~6n)G0cy7NZH66@AjD^lQ18qedn+{hP{{VE; zqzxdzBc3y~@mF$84;FZV^!sVr)+Z|hl37!e$3gF2WAO7u@u%$_5q$>g4GTvTc{f)9 zGjkc?ilFBw4Ycwwe=7D{&kx(`dVG*yByuaMQ^{O|*NXDJBG<&fvp%^k&%@&utKm6h zGEbz)j%2mT$!lg_dXjdKbIo&NeXlL)o!B=@_L=l2!Y|p!!(R)n5O{x1gx(x9w-U#` zd5G@JdG1f*Ytr=lK?`gNjB)<2+PvT3_s8!Jd|=TM_re!w(kKf(w6U~z7Voz^UNgub z5NkumKOHo+i}v`xx=NeZ#ClM_lBQ=xfOQTk)q=_^xD!;cdcLY2+#X)so%L z@<;r#MjZ7YF$5k*9cz!i{gym2;@gk5d_c9E#5Z9CW=%p_Wf&PF3%dY($Mnu|T@)~N zD{E^b8km}NJ}0kaXn5Q9{k7Lc&6mJE3iHN#tR$vlK^?qgU~Xn7J3(dS413oXJbxIz zEKIi^Iq@Z*hV=WGj8bWuRgq~F5HdX1&&}7KdYog5^?wQcE780mY#{KynPp`gjIu#* z<&Vc5e;Vm6Y~i$GWJDPlI79kZsY@@X6{@-CRLrLS4G$92zh&DkQYVkZ?W*eP%jL4& zO6rJCGROhQ&d@WSoOGqX{fhJ%(O}bUg^jQTyl|mDWvmcZI0P3faU6G*(t0Zzu6;^KUN6Z($ux6Dt#`e|xMx?T{Bv(%wKGB5*RE_`` z^{U#B>>HwL(X^f*yw|VF{K}UXvq>K#rq*M}w@Uh)=}OE-7uW8$6xnoW%vhB{U^;DX z1s=jX*lQP6bv`QAzhI37Uq^2;Y7<(`Ly=iG}r6$v&8+>{ZM9+}hmv@4}z5 z-KLos5ZGE<#k2)j?ShOBgO9?y9UtJFHdCK2*;7335ajdepP;W@gTv^ouYhp80*%tH zMW&=q3o5VG5A*ufs%aTI^LV)DerQ*^{JbNo0UBC{UvqPL;0}n#pgLi~y&PlY>-V)$Pb-18@6= zt=c;>;DOhVl<`)qL+)5xa8Js(z`;8z#G6q{=HO!+#x%{@z8BNjPjGd=7$$UUrF0B=92uU~_ww$dgGT^SykH2o~bMY(2z7OzK zwBj%Ay+_QRFO?oxlLdxbIU9Ez0i5HJ*1n1G^j;nPpMDSql`VArA4;-mi4g@|*glECpJO)d+qj}cm_UCdGM%)6Jfes3C7!X^G3iB(%QMk%zl49_th$_< zqgr_D;g^XmmN^+DywfLw{sh9SZa*?G1UGS>F^ty6oBsd>hVWFkQ(J3VPmA<-LIIZR zLy@9#M(!FS-H&{8Ow;@uWcyUp~by~%huOD-pBTb z&_#is<;K+OfDc|heQQ5n{jq!p;pwAYYg(|jmu}*+%NjO0>{~sn%Cx`uCm({e9Wm{6 zCDpAhW^K(9Y8Ng!7{D&%jxo}xX@BrbAB72aE;Vfh@7+`+PkB7Ev?vKXBQ8l*B(WfM zB+_}_DVoEF^7!i8J1-r7!AQOo_$}ju#6BRmiORF!MqIW!@V!qXfyvJm=eps|imqTbae21!h zX!!Z@(ZguI5?=>sa^WQN8~ri2N6ASEDgwFc0VfCAyo*-&AL9>)pB%g~sC-0tHOn1t z^(`jzqjyUw+?S7N$t(-*P!GxrjN_dCl;7wvO66un3y+s5a0YA1KWM*$aQO4UnuV2= zrqcbB%(J+S7`3&+FnFZk{{RcBoOiA|^{Q4)PFFkdl<48)ohT%9z8~=XH+~IB+$zc= z$UaU180(Ds3iwN3@Z?$_$A5{Q6YzU7U#-=*jdbToUNyJ4LXpV3)wvC~1$fCPJXc&GhxU=Ox$(Z6<6Q<(6YG)3 zWvxKur`V;y!pM!nkaDLyf>#_G`?tUzGK<981QP8599zx*JY)V>$^je0}*%C<7dOEmG2p-B3Z zj12O9>zONP!o4>o%@gip1Buc^P7hJ#^```6BaT$#{a3AL_&da7Te1fMn;2uUhCj}0 zO%O&{J}{i*BXdckk+CJUB4$)ft8ze(pRG7C+Evh#-}gPedeEwkD`x|aen!CSQSlti z2vVese2t&yQWqTYpDeE25^z6vOtplV#^oO%wy0g~H+|No!o(A~S9Wp^ z#?B}Zw^4o4(Qq-3-S__hII3`3Zo4fagPsrW`ubJ-hZ`7yg##lf+?r%a1*a;xZ}wX` zpbB#);L4#!a!%;*KT5;#XO6UghuTcnUM#w|wv80H-bmvaC+Wp*ZTlNDNXn{l$IP|) z-TwduC^lcTFUL7N8{!WT>RunUu+yV4BRj)ueIw2H9z_FkkbrI6GnV3xrnI5$9gkk| z*ZdVL!rG6C6T^Q5ZS@Zr>(YnWZ>8I{!pFB6GPwC;A29pnb6j(L1@Z6gJ#{vz`$y{6 zI$od8*}OTVOv@RKhfCRk23O}BBVdCEm(LFUl$?mNMl0$a8|=#f7RrIb0iBJHOqy5hZqlW)Ja6I0?1^LGn@f8=Cr`4m z(rrFytnDp?aYi$qK+fjsde^vkL%@(}Hc1_wyl^CA97WI9>svOOaxfeM$0V-9jC)qb zmWyi;jW;r$!B_!8Ml-178eW>v0IZ>d4lx(?tLEFtw^Z`-807xzAJ&pd@j4NLtHR_q zaZ^hulq*QPMt{20%tR0u3>W~QV1XB3#-f7QEX%n!4?`bXo=4hIHgZM}%GB7x$spik zIN=*PpaFup84JMAC~48cHYqB-JsXOAiUQWN1XYEMEF``*8^-t5W0);B@}uQyc>r-?RhHLYe@F$uja(@;~RDR+`+#`CxK61gH7; ztFGlj;Xxz}e67t#Bn8+!fdc0w1V5Kr0AaKQDB5yPPwuJSNF-qn)d!C&tu|lW$b7J* zXCviqDeemtP?#9V%A8OG8rRKY6*vPw>hV!erKr!ya(e#nrCcgQuHe5nQL(yIat|^; zl|qxiJ6eD#-DoK#xKuz7QTx7?mc9#$edb8H=tz(Gb6qr1suQ_Jcpr7CB)1R#rBr(1 zT8+k?k3R7)!ut(YCywsUDUps!v=!sO6~AFG2mD32OSG_;P1WtjZM7RT@~&-2V8EmH zK)iJ5F<2CTd#vg+=ZynSY zUl6q0SHh78*tI8zaq4#zl0Z9QbB^6>pwPc)&kanX+r+n@@Q!L|yXCRfqZX4!0Lecw z!vHgu1db0pSJL;I8eB&wn1C1PN-+c8yszUw?D^r3j5<@={7dlmk*!;ijhA-5W;^_+ zsQfE>c$vd&OGkyNexQ5DU}Sql7wXZLvI@sE1> zOZKtwhMD_2O?9l59)(SQZCV;0JVB2pvHlU`&pk>#m+7+U$&Hm$<8@ex5;czDlwo`=DZuJNvmm)mkIN(jko~n19Ya4Tw_`pt=D>BmCFs8 z-RwWcq_8ZqvoeKHHva&t_dWCMIH}B0h>ruOWol#*Di?V^>}`-XFdzMTV!uMpp-imN@>>L{3|MgY$NyHn6MDO_6ziwzn1$>7JH zDVFLaxgpdN6B*l#4Asl99F4nwx*G>L@BHbukVhPhWl#%r`3cA8MYR|hh==ABM+P(tTDHk@LZu1Nwj(iui z01UZcKe~CPMOe!#09b*MhT@QHNS5JY`==~NMExpge2mOY*S!SEhdJR5PYr779}sAfcpE zDoOKPU@kDdcKcJ|VQ`?Tk&a0*)HBDnLx4VG!P=J@_>v387Il;c^^x+08VZE;i>q_H?N30=s9wZV1gZ zkKN)t6Wc1-_oN~FLlz9V&T=+YE27MVfWrrjE-Ge}BLT)oJgKN>+AugIkM5dHjIX{$ zZ015S$Ru^9nM*ktT!GIbl2;yKVgVpyJ5M!UOOGi|-U;+tf`qx3Hvp&IPerJ1CG#IH zm;NN$0>}XXWM}U4QOh{w zuHRhkHJ5*Tw&ioP@CTZQA*FKF^xKEZxXI7l>sgmB7ECbXC#q3*dDmxLXYQUVjI)_T zbSKb%_3J4}w1-?wq7c6>IV9tyXIxAfjtC!!6thl4VaHR)PHLUR-cIjERT0~cO zyO#)lgK(-hHy8=U+eq){w0;x|sZ6xHLxZ{e=vWV{PcBlaJ{_v_Z-hmm* z`;VAY=8$=0$bRwdip`zK&tKA|vXGM9WzN7~zLBNhxOUk6t>|a<6tLABS27H75-r&prO|;+Z>R zp(p9dpr+z6k+l0%Zhv=y>*+uabJ%b({o04f4##Te9DUkC!A3ARCjf)>pf(tjfuCbQ z8PWX1B#t`rY0BV$3H?nm8_OWGcIW1&M&X;59-n@K%PQj;7|HiMRG^HEk@=o#xPF5_ z`2ARo#s|&s_vj?Dj!J+C2Og%UMht*uPB_L-6%29%oM3zJsTV3aZaV$`w9t#9;Sccu zaq4R2y~3id2pn|DthJXcyIb)sR-l(?%dp77;p&qEa>nHJ`F|2|T6Xs%Z_0kWn!~iX zzz1;So?fq6-4f>nWBvM~8PeF@T6Ec^JhXmdYa~JC;jt}_sh6~MtcmkTDHC` zAOqJKB;u&TR3JNtzwau{FrhoQ0)OB1t4`vvtsUri$OLeGPc>#a@-j#n?US0#iHd+* z86Wi1tzEX0%t6i%f1jmjnJs8pw|6g)N8nF275GUaB48Xh7~N7vr{2!DUNDU{ z{Y!2h?)aG*{q~YoeK@Y&6_ ziUa`wTmUk71F)-NMUAlASbAjDVRX|;lKg+aik>hwg6A0=e(>k%TCT<<@LT}c1aseU zsQk=11;*Z(+-cE_oT(*S)$xjZLd~AoJRdWIR0W$0($ZuwJ9zFY)K_ID`O4(=Ic_SX z7P}BJ19IaZKkHH?r7|7Ycp3iyS<;=!G!k%6$U(sMCyHR3%(%fS0O`wAFiayswYlW~ z0IcauH^03naL4_0s<|eENEryq!F&7S z3CA3AYAA2jK_G%Llk=YR)wvR>F_1tx`{y*SI~q-Vn?cTZ4spAK>rWbq@;kt?Zu0yz84(x!^!ESX|9oaAMymzY@P2-?RP z4u4vjH*AFrMo$CGG+dJ4ydF}CS#n9|<{VTv5~jeaM%~}uVT!Bfm6^Q4PUbjaCr{Fz zv0!d?!0Jhtui-_(771CUP;fveyBdQVX3GT_2OoPFpiENZe*S$t%5Z(BhRM$-%D$j}&}5wwY#FAyU&E5tbnOe=}Z#AU5TX%5ro5u+(zGvq$C^=yE@J zYFtw^jM_Yge}g_;oJSr);c{CG-_zIesu!ONB!4YkLaH46yN6?+#=W6o560}|H{PDp~41u}Tu zoM)gl(`oidfU^wl<+Cw4{{ZV&j-O_b5^^z&W6U%vYoMi7wW*68xsA!VVe;}0=HoS` zVI*;Y&QycI<+$~$I)$>ju~Wu6d7WyIP=f)6M{_s-09vlrW_P)2O+q)13d0`6{{WuV z9QW|PSy*HoV=aMM{#gK=;k%zQmT$TOH_Q(oz3ci?xLC9Ou&WpWa#4ZYSc+u2n-7qX1NWGrjWdqdya{WnTRL6C1ghK=IV#-xV!3;-gVxd) zhSuH-c$WkS_bz_{UarxjN0%zwxX+u?sQCe<21g6^kpBRMLygTNQb_U75q{1ZUy3Yl zVAidmnP-ioY_nxDI)Z!juOqP0L|!q6!M_nMBGP70!5UhSvq2T-8f zRgU%*Kq4%~4h}o=0k5Mz9sb(${64--FZPqPO$jCg$k(BmzLj=yoHGphM{W*J%g<5L zy!Umv**Z#I^maa?`DArT9|ewhErK|uxRiM#e%0rUGjZ))?}dIPX+Aj7VZHEXr)8>G z$`6-wX?U|l%s%iAxfvf`^{@88y@$T;V>Jw*a107?;agZ}e##X2Gv{cbV{7~I_P z{vxA_P{tKpB^o8VuH{3Y=v z{v!AvPPFlLj2e2{-uP}^>n+iaMtJ3dOyEd2GT@Gkc{~dH*_1SFH)Osr1gG=qSe`2I zyn4;Ni6+Jell#n`pGplW)Z}+RFTNK1Sn!9%-41)-hgb9JLrIY?FFY%F^QN<)Gd3Lr zc_n~gaku3gNf|iDw)_eGv90_z%cJfkdx7}OKr0dqL=2`0+ZR1+rS~lRpmDd3BGIO8OzFYCv!hejP048|6 zL8M%KW6-7F6nFMl&8PT+2nZk~vMU9-05SQBk_Xo``Bb)lfBBt?N}{trOgtmv+bwR+ zDYUDY=8obqBySvyRmM2{Fl(#R3cD-Lz~}v@{XMJl=k{s+t93mJD}?w(e|xD|=$DIO ztZ3T#lHXU++z=0$3W7Fm!4fWabtIhE*&Uw;nRDBK%Zluc5s8T@Xx@Z3YuUak^QMGpMApZb*xji$*cKWOe7HHXI zKQURqz*kSF-z>3=$QZcC`re+@7&T%;2bmVt+7G)oPpu`on9*6ky@B_=IjJC+nUzZb zd#{<-^reQ{!;(I3xl_Gv;R%3^VL3 z!Ny41KYPLV=}2P=1dwebb~DR1DQ01{cK|Ti>eTj`H*c0f!k_tSeukTF>E#m>?%Z;7 zA;|qG0h13f4DG{noVQw*6%K@{83T`*xTZ}ZiNtK`7>+Y80q5yS=KY;U93Ab~&HJbF zpaq>rmUiPkKJ!!J9%>&j00swEvk&M@j`ukl+~ z)jW6c164*bLax^r7bT8ZLjsMcp^qK#21&&&-I3D@Dmu-a*X>KDYG1W>fp-m_j`QjE z(uTBqxnxUOTpSjWMmGV$0Pt~NJp5qNej9$z-U`&bE8#e8d{^Ty5#1~5O$^|*yvPAb zWQ+o^Eg*V4W(_;K-P_L9*dw(%skpAI}XaU%J)F-hm@azYtjnG}VIn*j*t z05)@w2Yukb*u%h{7tms`(>yn)#b*`LTs(Ott{oqGypDO0?)koAd9K)p;7<@l3T4JBE~swP$oq% z#EL##Hy?Sp9`^@b$AQ8$6p1<_a{!{=W?jYx$gDl)s zR|HDxP5|%oH(y$wSww2=t@X^6URi=S%-}b0WW_P0Nx0>TmCissw<43x2_Ohioa3uh za!=C?GmPiW#}yH{JIBtsAd-B;)AFUT6U{hmmplWL%W^5NapuNEyLs)F6{ER^<1nZY4nbmx9A+0h!b{+6M%A4G)6Fk8X7|0;!Jg~u_5Y5Ii22aex98@1_47`wX4?br>>ruya zptj}%XwUk}R~c?OS9>vGfHVA9sNP|}3PC+{ma5|K_hc&oSZDob^u;8XL^sOgC#dr} zQE;}RnZvmQsU6F4QOiEZA|f{9<;gtLMbJ#U9!DHVYP^>N8;f9*{{THYRNO6b%{CN_ z=eJfE`cp1kb}RHO)mmHUXZzgs8Iq%#{{ZhC_sIF`ZdHZ4xz2Hno_d<0J=XGmWjy+t zC%Zc_xL}?#{VIdp1X6mj^nSjzoTM^Y?*gz0-O1sHKb=#!n{$`X%)73 zozn!*8#d(z9%2(@tJ5pK-?+9Y0FUyi(ICj31Y;C;VwHuYe=&5I@?^Dw|#h z$R#j6D>+ECx{EruCoFj8=)C!2Uz(B|7d8S7uMsb1kr5v#9^K;sPjWV3^jydg2 zE_ZYJZ3mi?LKu9%k4`G1fVsvp+~$BD^B=n80(1N|8#rE=C$}e>aseX_fS%;i%YZUY z4te?L0>0+P4jAV>O*EennY`mjf(tI()*af?SN`{#9n$O{bjxlnIuTJZ@q? z;8ij|$~iyx(Bi8s#5Pwyr9E7O&TxK|5?GDMf4!W4v^l9_kfU+=0Mtt(rs9E^;8D$xf+Z*&MBG2nCa3bk)B-U(yv^9sba zyelm7sH3cGJ|RztP^L3f@(IUJ4$HK7c- zRbX56ts^2DH!SW-oy^}c82iJeXjt8lFwA=QVOTL;Wq?wB`c=z&vz^?Z%Zkx5e9n?7 z#F#3_ulI#$+K|y;Hgo>iu5#Aws*RhDPy0P;{8z>@GFvB~;jI$`bywscHV=Q8Q_Oy1 zXFWLO#biUNGMt8Efu1qVUANW=``P?9^Hiie6D0e?1Duxr@S+=H>eyhvHz#nYXT1I5 zx&{M0@Vx~)`#`IfMq&Q|eABpC(YCQjn4Rb5#|4KJvTTY#GH`#}svp{9i~`>=t06D6; zEWP%(UzLwjo*Yu{Qp^d-C$8a&tsU4bGEb&(DnGQ5FFU#a0C&=hlev2X8$rMvaN?Zf z<>ZsV{vlOTe<);bIUg|je@dDe#F34}k`6J2=}bkK7tCBUU}q!d6*y58S$y(w%Z$}% zF1AJi2d7LeO)c4NglBJ4!qp)%coz;>9$SoW9Exnx7iJ-k909mhPq%DkSc`MX;b<2H z*fN$ZGoQOf!o+gS@;2ryeYXy2v+`GIIPI1cJcI%WVc$6%(r+QpUB5-*mBu|jSn>($ z{o$Na*%RhAcL1lB-acwcPB1cdk)GUA+RWtgcpbh|_|OHEk){3G6Tr_7GCiuwO3*mu zvg41ORck}O7XjE3Mo#gZ(DI;(d-bM!|}kU;?d0Ct|`B8Z{{RCV zaZR?=6|$`7Et~?wim$9kf*LTx@LshHWsHo?xSZqobN+a!zN0kYRUC#rah>DVhCpLG z^MWy*!0}YpSrPt5Z2N8bs=>Hzsz`H#pW($c?kkOk+(y!19g0Q{@q?b(YpUbZ?skXZXfyc~}gF1a}AJsG?)` zjoD$?kC&hG%_8nbEz3wky9{ynhkx>E&{;8$0hx&8eB+O5l@;;4ZUK+V4%%p$ll@se zf7zryVmF1909lV2EF5N_mJ-tN%s9q(jz7*TLRVl3&PFma7NC|;95U`Zv!A+iK(At) zrKK1`N{>bdidMBCN7QVX2ljQkm=_}jymT2G1Xqr9=b8zzQQ z86+O#@E?_Uzl}ZwYTf|w-OGGCo_`Z)cFd+v3F`C5Ev&Es%y#lR6B`By;I>D~Mh0_V zL(YMq7|wHoK3~qOU0azDk-H>gfVIz7glZjhadV^Sco)IX0_ol_u)fznWuFmiUI5kO zxp?(0D9*E6t;+BDXSHW4s#&*XF}Xm;99OOQEB3~@@P@1Xk^4z$AbHvTEmFLjR$c$&;Arlq9Jkx4SC&e>3cl6M&+ za0K9r<~&95AIBaE(jP5s>4j^{+ z_#Clne+u<^{BiK%yw15{{RR+J$QfO=7AmGg7pNu zTq{Wl!p&?*2W*IN$lQ#A1z~cfPTq&CSj~)WFSK$pi&@z2()Ti*o& zL%TWq*j$flNv^^>Z6}Z7J7^0OwS6rv!z`zr*#~&yxs89qFx<(A-a+PbT~ zT>v6!G0)0Q%vU4hABj3Ihi%#XL8x0=C{jt9Xw#tTGJ6Ugi;day{{ZbX`w4hw<0azi z_7dE9bHz4nCA8MGxl#+rm<%rG$L|-D^0q~MWAP(Y@vrRBtGqw7CWUc-Wf9*Wi?mq9 z?X}Jv;cx5^D=!VW%NEm|@xUkTKZ-xJt+$Cxwq63$Z?&mo`Qa*d!!cYC$jkSKJxLuq z*UmmRn$7${aDQlj9e-qJW3HQ}+_TCVqy-GZ%{3RX-)GYPC4h96=>2v+A8NmC_(7E$d1Q1gJz`?^B`j7U0{kn8NiI%1+ouHEwNQztxjGSh(BTNC*l`|JX?1nPc7Y~e__+E zLXY`*j$#qP3`PL;#w%M^_=)4MhI$yb{jz)qG?uX9LE{e&GEY1^cvqg>3>Nv0Pfub+ zXy{7Z(IQi)H)px}!=m`w9YWqWhTuL%LwSSd$Mf%6mb&UmHdL>ug(7e zgx?W-U*Vkw$5i+g;y8R&;drBtMQH8>&*g<7x4_>#Y%%_?*QVZ;>s}210D^S!8Z@YopkXAz66Rbwe{6H(2mo*#)5LTweMGY*;Q#0qx4@hdGgUM z7I3|clIX^+v2vCjYIlj1srMB;U&6YjnLm;bvC2c7z@74Qr;;t(kL6%lewC%9B%DzNoaFK3W3!hxEB%odAa>(K&FqhRR`T4 zdF%4LeV}K-DdNXl-xqrK?*`yn{aN&V-?HSX>l5m^QGG$dQgEY4VkOwb&$WJ{e!M2C zc|$5cv}e#kob)+Cy}>UgoWeo*@1adY14f)uTuP{#V(SP3%0-SghpZTFR|cKy{>i)n z*_zAD{$BW6?PqyMyadry?ax=W0Dcn4m9ux%D%o>!Pd`E3YX9Hg)|0}0wX(|hf{){j zkbKFkG0ES_M3eHdmzQ1@ijSXZr^Gi86_^0G_*EeBq@@wte{%ol?(Mqw_=W`3G3{)3 zQM{Y3OjC{-?%XM zimP9|{LTA=mvsr~>#1`7#mO$)F*SnJH;fDYM_I!n;g!p=X(yK2&yoHgKONni3|D!Q z$Ng!nbMcGMHMJ!M*_$4{X1yalS(^> zX0DbAzcto{MQLFyN&Pv>kj0-em>v6;{T0sN=5BQtv$-zO!XiOOBi|oV|LEWcGD*?3 z804U2^+AW>hEA#@m)N)4EO!l{TvQ8F{5x!$PnG+%g%c4=)hl%cy!HY(=^12V=FP(C zCT=njo^Z#*iElp0L-yMr;S4x(>C-rQq2!l|Po!4?x>Ag#q>FT&cTr8^iII2w1XyTm zxOqo~DRaZHqtRANMsa5;3u0YwE7GgkJatTE|KVux?B+D zpOaqSfpEcRHEigR_?8#AYr{jz5lWv!L|qu+WDn=*CmCo#VCJPuX--W{W0No z6F+p9Fa7@E^#FH|VIO??$OB8+jK{3*{&z`<4{S=N*ys}p<77OW9KGn%pmSn&AOhp( zIxHeVMQMf)C$CVWBdOnEhxNZgh^#r#%pQh$*;l=6TMj6LLtrF!L%ohi+iz;IfylEP zPR&!T0toe;ePga0qI5U+?7niu8${nPU-Q+60R7LvZm-WUSypH+GH2;=MX%616)BNj ze?$qFbtu6w5VCVzhVRgi^L#Bi$E&?;@U2m~rZu-UH26iak*pRhIb--7UmhFUJ^O|N z3+Zn!^9e~AhU++H<)tyTAmknFzHnD@GVR94KS_$e=PSghw##m)AGh%EeeKBQ+&F^r z?X~`OXS%STsfSpkP3FOMj1)3zuDZl=p&6M%CP5{AaM)!WGUCGh7CqvOQl}jx6zZwu zYv{9VMrz0#RM`~#@CkOi=!E3$6(x5#5eCAWLM-(AJL|S?58vy0JgrBAgtO%865$IB zra)@!YRq3|(M&~#Ui+hsC<}MI59T^V6^VVK(61ZztIhHZYpA(;qe!UnybZk-SiER> z*HuWGSXSP^5t2lX%q_Y3p$3z4(UPTd80lR%N`k}INgoPxotr?>(qkgo6-anDdV747 zv)9@!IZ4&u`_*ialPhmCurejd_(UmAR)5jGlWGlVC@b^vVxDj5Qby)|D3|TZII}7l4^1ie~7SyFnDqcvt!St3fkW;nA#OO{fu&v6E_cDDu zauCt<;F`z>Qp*g55kvQ?5OCreN?Xstzv`jZQKpI4>U)Jyag}$OjuU9?-Kt~l9d{$~ zw0;w_Ui5-P#zQ|ASp1PfUTv!hE4Sd7GNP_KW%+hK+dhbI@Kex${s&qVtQ~hg2vpzs zRT>-YA#$0UHU>7F(QLdMg^75Ew6a_k70~<-)S@GwPXAsiiQh?x5j$sKt~Bq1UA6T(CL?m49pVYTMIxAQ-wDQEQ%+(4?QyMz|Qa#3@eAfG!l` z+rMPhWjW`C<%nxvpV9u=_8;hRrL;WScVbUh(e<|iZ3E@h9ju00x%iERu)?Q9M(11= zNQHHgR07{K%d#ZDnTK=-kk&r2mHAy5Kk|z3NnAgglb$z(z2d~|y047h=E1KLXY29U z-`)A!L+Vpd^SyaM9+lStv0`Pw{$7}x8YCI zj59Q0MmnKh_kPCq8b4v_WJ>G_>eDn&Na)9k4Azf%emi5!ah|<%va@~L)irJ1OxfHsoTQeu#j_b_D2m0F#b!f;i7kPNgI5K2`p}b zyw>$RVNp_5=3|K-TX(?e=0W0tSb8(J9t6Hh^sr60LF0JwFpme46tR!CM-p;QuwMIl z@8Ru8z)Nh=8kCC)4*g!{idt^XX^KAJ*&{6!&hr#pBV!e`{|Qtb~0 z4{)<-SD{z+UYxPCH0}R^oFWn|V%E}Dp}Yu(bm#YwVDJG3$oai1{4U*m zyWMqijgP1+EQX@e06yw*HqO6(uSSnQ!k^dc59@*;(?0LUXryaxW4JFsDbUgpioL#2 z-c^(Ol8|S?j zFo^+zO#krbhAQH&>s%WL&p%X4JnCHUV4wUN{=2uFYO&vkU4?IlvA)z_aQ@JZEUMZ9 zktKH@G`)Fx%k^O_yPxvyT*xyv-7`$qB4TaE2;o#p8cROkX{#BA@5K5&#H;PUa?0<2B4ZaH-XgKP_~T1XZ3S zwQgBFOYFzw6up73g&4QXiS+`>4om2S$m2rH+R$?9Mm5u>Vc-{?{x+D`^tc&H@CAj( z6-fPtX2{$1OjGhCj?1XjO_PTT%MWm$9h3aUtgoJTl+95EX^y6ttyef3IT#MOs+N*h zM~c&vYol~E&yLI7XbCcKa8>*8cb3GggpxJrMcR5CP&vSf+_$(KY^0iuS(zM@kOr^x z2uUa-cPPF2mu?Ujg$LfSj-Q4_q9kT`XM>C{{Sb=Ph3#Oys?2+0jg^pf=zF4)52MnX z+(Uv#`{LPFo&EzgPA>P;IC_`LN&!m62pMT znZ+B@XGMvpM~(?fm~h#@;EF`XzY}eok~i)6xu&iC8d@4$in@(UM8?bD>|2vxz5M@9 zM`4XJ0mbwR-_~?tV2^E>*#nMmH@`#OUB-_l6%H^-sPn*Zjq|qsdB8{WW`8DYE;L%Pe2JJH=#o#AD6Z z7=A9Y-}v_9k|WgtJ12F>#u_-_$~T1Pd&^h%HEQo*QYm3^#&`X4{(H`+yEZ#Qzu7G! zUgsjZLK`c?$N%;8c>1mEeR&3%2M0p^s0!!%TN zG_+ea?#UQI-h93jF1T5p!TWHe@?v01a|&i(e$XnG zBAvSV$ngRQq_}vbAG0sw@KoIJo3Po#(G_riBD7*4=rLjyL(ll`v+m!Zy%4Rx5k);- z%VBEV_eDZ6HPNGAr89j$`75P9N~_MC(7Ejsj7`2^qHNgX`0+X6TUtfwLPW>cy-rbU ziMrXqmbnY!vzO6q?8D&Xq@d4Mf9=li1X?XWZMe{TcGTFEw3~6Y&1x6t+gt;sPwiMj zJG^^Z#NRtR3|EGz9V<@jyTZiV!5$B`Ur~2{AdPno6=#kNzwP{a_V&A`80bHcr8LIe zwjrkSx$+DB(iB~s>y!J`Dwcn`TDiL+hOFt%L*Wk1mwhvY^>vTlJXU}WlXJsIO(!VH+7SXE?UY7lw-ti0hr*~dHFBLj;8Gi=P z7((+?fCWs>+lTxY(udSvsv$zTe!4o6|IIY~8|A@9FBJ1bigQ<3z{*$nUMzxMN|#eL z3@)}T%=hwWgXnBw)7tzGvh1;4yX?p5Jy`Nbw&i^Ujq(1xHoLwWZRFyMoXto8DH6at zSrqtXW@V6fupmhn^^#H`iU`YlI7v#F+*VyS@H2TNe)4HgvU2a#I$MCH6|8_^q?tx@ zQIrbn3{dx05jz}ce}#%WdzFRvtEuQ;Dn9-z;U`JChUp7-(V8Qcsj&3&NDs?m3JSEV zSTY9AvsGSo*KFxzdt6Pd>2MXVb9w;H3K&^}dxt7qprxsH|#uXsfpx9mvg%{n`C zncu9JmSLgmir;ytaWT3a)K^Br)*lYV?8&Yq_B;x>ZMriw+pa(#AFZb|b4U1Y5as(F zDKG_wH_*5KclMojrkK{6g=~4h_?d)+iG1?LZxik|CGUDD(>XIxHcjMuVi4~aTID9# zb;{vw*!kV7pWntx+HbRt>FjMaFt7!80g2QLjoQGqo9Y{>@{qKRs8*Td?&)2kL!WYX=HA)+ zJ)}PteQ3o^;TFA}?vT$0%`3A0nxOWyFPL0S^WGf^4Z`eY`vYdaG!h^nh=CX1+|h&G z(Q+^ciYkBaTL)Fv(S_(!4%~Qh_YJf5-$tUi(K^`LT;Z+?18#&eq?GZXUFlgLxzcz| zzU7YsG5?5P*pPqYnV!02=6P9A3aF_jr)=zO^PPt!-+8p~gfU*%^kLNiT5sLaAx7G5 z1b=>6QljcOmb>hrTTJ;CLr$q4-xj0Zg;$i!S8C6HQUJEfJmexn*?1{essO8GmT&M9 zRtEKWwQJzi$j?v+J$Sbg^)Zn7IzzPPp9i#-N#yt$MFr{V@N_m)0hn+Nj@j(OtCw>g zc$=K!N_0t(SSb_l*S(B$v$0;y6hug`IKuf!hblj#m*TvDk&Q^ zNiC-6zpt<~)%`zGO_1~pZt^pu zu}xy!_}-SWdQE=Th$(glFBy_k+wqJTf;3yVv>eDMQg79mmi8!Sm*s-}cBK77?(z%( z9DM7-8qF(v}MnJ zJ!y&(Tw;v$5EHE>6uogx-l(H3-%$wPog6n;c=WQlkv=#oH5cDynr+f5;?-l6ohQ*{ zm4d$7TQ9Sp!$J8j0w33Y@4Fs!TH(rPEcWVGCt0NRm5^CUo(nDm!J8jnhPrZz48}IH z(d$X-yEmYKR{V=och_$8qVmSBv_Mlxq<8wyxj1fYM9w{@sH!&2Lwb4-QhCZFE^fdI z(DQ9PMN|w>$ON0SR80!)2%SGKv|&rBWde{n&~c{5e_#w&;m}k?(8>qgJ3L>6*Qgjv zQg6~=A7A^@KX#cssB5=&W>v!X%ouh#4O3Tyt!+GfohM5fZtov3LV;?ox;=0ZOfCbyQFr@)>(vDCu6$|$_x0Pa#qC46iOk~KBjPL6Qgi|zD9%d;KQ}h&css#X+ihi zIcvsu4!H4J91aT23-)x7PL5RlEqCL$ySn(((^*qN=OAF%k=d@!8eqtt+}}A?NO(yl zxv(almu&c4PT*jU2p)?u(K`Lx25yi$Mfe14E@o5MMqPA)B7Wa2#_Yg*48u3d6}F7` z0yo=LET*!gh@dN#5q%*Oyc1Rr2>Da0rR?SVyHWn9Ek&>Q!fOQ?O~VuRn|#!uK8~xW zrownGBQ>|Pc+951=OOs-_=qk?F3t8tHrR5;o(!|}V&=)+2~x>j$ob7L0y#D)$$aR9S5DhC)x-E#S4{-;>L63NGY1lohPO^eWo*$dmQmk?hF|B17~L|RkjaGl%@Z!mr2V# zv2D?&O?3R`ZK&y_jS7AxZ#qNtSom%9-3Xf3JnT4Bn&M0#tBJbmT`AES5W(V@k`65< z+$=jI(VIPw+LCSsTFL4^RAQ{Db2lC|!`-;M+6q~c8E zbfyFK)kZ0=mbQZi5%)L-#WPJqalG5592G!=VuI$*8j%cwq?inwbKv%CmJpF&WyLoWBEFJ?dYq`tapuWz z*6U>cItFp^{qbQbQcpi<3>gNG?+t`5zITG;t*lpM<(g>;Gr?*l1F%$My%h#hu?iq? zQ|iHue!KL9d*o!U*kkxNOJjf8-{?W*H<_$XZ*Go|sU#-t-!Bp4={O?Y@=hDFcl)ZU zbX-PH?49NshLS}1NZBvwIQSbulv;$1oZ{>)R+1Aq??kVBf6k|SyS&ZgFMd5~@G!%v zRf<@t=6t(;z0$%G@$o?!IeteItXP;7q)`vr&W49ZkfzEcTt+&YluHz`w0J6p-r`yHt&^ z$2o_abxC}ofcUEU2G`&9y{;fk03I;)y@krD-=eMuU|bW^4lPCmFx%~F@AcZsT-~39 zYtXfc-29kGBS_-pyLCSI&v?FLiI0V$Q)vIxKu6MvV6nitsj5(?N@Mz7_ZI6vr$)1kk~5nlu4elLMCm_Tp`?vX2WvzIin%l4wTi1 zDw15`}b2Q+f5rqKC2*&>pt{2ykxBGEu3P&-y30Mk_g}x zql?a8E$snwGc9Ll2bs7$!Y>$|JFfnEl6jUm-`n0ZfQ(N`rohnRN{1N3O~t-d2O#T! zyHSlaYogMiv2TS?AMg#SKX#oa65g??c3muu$2Pvkq^-nXpRm*Fzb;r!zh~&HR*ml#pKgzwSGg?qC zmQvun*a?fYVvco^`i>xDFiHDZda$1o1pSpL&CKv!`f5_%3%6@J(Iy2AS7w00bwnQP z_@%8E*d=iYMJgx0mz&5ORMh|{V~z(ce!Qi<@0|A89$B})YxtOwhUXhkY(=k>2QSiC zIz`R5PJZOzq|BsE^*6qEq>S4bfTNB-W)o;|I)G0hv%Pgo(Okx89PZHINo0Yfd0B5a z0|(jTS00G&7r{VB6dE<`@QY56pp%V9^llD5UV2xra(`oMIIdZ1Uy;bSwOQ0t z9O^W(w!iRN&~xqAk@f7h!aiA|jD=rTa<2#k`!abrH+oZCpi_q2sFwQlL8s7{TT*BgVfFqY{kI8LRnk+#%>GiRgW6W-tDRJ`ig5Sek^y?XK!>|R&7OUc4TlSpukT}qT8;e zP^l*Pe0;57?i;SNK)P7ZVupDD2khnY=c#%P@}(eu@ujRA?yHnML+C*=mw`hclWrZyZxLcXR?ZEPc#CeClI$qod#O0~ zZcWlb;X)y4Z6jB9H1bZ}pCJxV%?F`$WS+lE~&me6wCu=TqJv(P5={AW&R6mW>ROw0`6p0abfv=Jd1K_6 zuIpIpL%Vj`3{*?jdTd8mH~vRRKqQCCQ+e{mWut5|PSTpnFV_H}v#1kQZ;@}5phu1E z$HeT6jxKy>#(--(@x@wX$smxcZ(KkZuiKF;kl)qisSxvls zXU*fCH6s%T;?2;P#^6jVq=qqSK$<2au=iyx{)sF0PUkhz3Py?h=K`)LW2_+SLZi?c0 zYc}t9*Zv%3VD+S?nk-T_B_KB)JQ)2jZVgI*?V%#k&unrWsDJg7gw#UPO*O=r?4Qch z&G`bJmFL}KqZN#*(i*f71pyQiAr`+QQHgZJF0LgtqI3vwZSNb}-wK7XFzr-+j8 zZ8RAjr@LL|jcL+-#MaO93~8@@eU<3Lqd&-|fCS=rqu(P5!>xR`tuhSZkj*-@3G(G6 z=i@0x>EQ>%IsFEQz8l+S!#6dFp8;&BX|8PbtN-mc4mAin&+Er2YW<%6?W8}zw z9?6h$TGwCiH*%r;`pl2R6y#}yQbrFxQ+A7@R8=+ZxIFQB%n0%F4?6L^uzy$p=0=6g zVI+d<>PAY^SutU=C)_~WI+d`!kzJ{z55wA+qZ7V+dyY6aEFq)X^Ia%FF;RrxGlRQ! zK~7Y~B7q>ySQU>sI#Tv9-M>ly3Jzy|~nTDu#FNxcI@M zXb;cfFdJwr`t1fb+-xG3(QF;cbYh^L<@X(PE%z9P=b9gZp5{}eIV&-l9Asl*FMGf$ zB(E|lAr)-gLUeq|+Gbw(Eixua>TX^24zHik&-36ba5fsGt;d&K>efhZPbon?+@Gq! zwz|>IclxvR-cw_)FCiD*pY#r*?L=muTamq!nWk)=Sv7t{80SE^fcUm=r17&v0&_kYQN-qKO-t)K`!4ZHwZBM;b`bm3?mluA6{GI z8opBTHcut^+95U%Z(zQzDAWM=#XIwbQ*cDR#&zdZv=d7^aDfV}o{GnLcYZ@w9P~2W zJ6my%kqL5HPVr!r-WeOQq+Pgp5UC5aBRzkGe!=%6M=pMerqW@6zC3w8owP1{kWb!e zg6E8VbTgmPihMHLd~NdV`ljVFt_&O?g*YoK)|X$#k)1|?(1$k~DJL#Mr`mcJNFr_`r|7TlUdd;^z)5wUX`zd0@UQauN+MZr zkMrTLo3L>1Xg5w@^+ov)e*SRaD&5t${gj+rTIC&M_gWMbf+KirT^Q<;bv zdF!DrD~h9@MYf~NkgpR6NY%1dS0n5Jua+q)?8OZlNP(+rLvB6yoUi}13S(1`Eezc* zL~Iz=YRh=?q4o)Lm{fO>qTu~MV3tdwg;1&t>z3i}$;R7&1wG}aB_^4-@m+6T|FM4x zfvqFTCnkkoT!&F4sk!P-7Nv3n-71xKiv<^sb=S${by_Pff4y3g<&e@cVbHcd$DN;C zHs^=0%7kMsx=wl+ICVcR@A|ZCoQBR_Y~C=Ca^F`I5}3l_qVN~>qTl8;C21T_hNR60 zds%i|^hEeJsTg!?-9Uv)ho?PkJ9_>PjI`&pb~B z)LgnxV=qr9kzMcg)RQ&loFbbyTRrg>ITkH{dp8ex#bpo!Zm~~$%FcRhQ|LaV=#%9( z2ESlW5Ox2<9;>^$D>s4fyM`xc0yVCesZQG~T$E#?TC#k(@C)I-1rbKUq3y1KH&yCI zxD}i-QLfA4(B|Di4_`NcVrU8H%vEnj$k{viq@78;@TiS{!JtPGmFnrlmK1*0ejz$G zoJns;OXQQ@u;3+8FzdAuxX;&%GFF*66$1IX0Vi0E@UM}ygpwU#I)vTgOapO>is!YU zv!mvcKtA*&<&B4=0a`;QvqNl}z1wC$bxZ~baNZuE4MNgE=`gIuLJ&LKm)Mt1dG9&7 z{{!Xduutn^>Dh*jp?6hwfKTIn$1-9 z@}=O!s((}ug{Xt0$*%Ux0Kzu+7hU2yynJNf;eA;JR77HtwUv0ib#m_czla3oNRPqg z*MxR;#D5?}kxW4a=1O_UtHX?ML5Nr~y!apJmvLPID|4W#TDa~%V*v%fr)~SQ>vEVD zCs0n$C9#X<*>I;UGkkf&IjiYnFr}cD$eY$cX3ORRi7sNJQJjAU7nuV)+7)feRKsTXAQoGyT)5~S%H3+cns-XX;suZNqj!CamAx*0_i z{R7HtR)IMqugIA~pzl8f9~{jA!-p5YBZpq^2G$GM{`#XIM4W4ciRnGWg1(dpl>AcE zzJjG+jggF}`$cZVzhhRi#y2i#LjR3t0~RmD*@t1I4P8lvn{MHADL_tis;gj9IgwLk zABbUO{;^HApJ=HPuDUVF!RvZ+lAlrU_Mq%G{|Cx9+X)>-HE)@%-*d-m?(}4*=qDAV zP#LL9uat9-2%F!22SSjYos_vh9ZZ;NBb@cf+0%3l**_KetS-G|J~9`V1yPQbVmxdw zH+jTJ=EFW@cqRID=LPeY0K{1n|JDeHkCq3Qu-fpG=w9Wn^GWtiits=Fia7H(QcE1|P>}sE z*faV-rrm^<_s`3gWiy0`1xLWyjipFPV%AP-11xAILqF-Id!&R+IQs7|Sb&3u$(7}1 z#-;(j<#Oqaz@zrJXh8XfCLpSdl8{XxeXgW=_E7@D1uH(ZIr)br>r9Oq3sd#YP!Ouw z%xj^#g>Tfq@^#amlQN{H4=fW-=V^Hib;`?{2pqR&yhAXvq zW*6RY(qjV761`*fW?_iknC5+pu6`{puI`|7;Iv@nb+K@o?tli!4d45bXnTWs_{-fQ zJnWow6X(~#lON5Ue3<=#q_*w{geRi2opR!1GE}afp((38E0;C2^=|hps2z==TwTm@ z0cQ!8lG|cu?_;%f*ePaD`J_UdNp!=9AD7)6pTxmun^Ho?USg}*GT}U7{HH845r`bz5Sa}lYnsPyZye%Xvy0?xwd7h|oy(Jf-RVI1JZTOyE?_<>k z?;Krv6^q}Xe8=hG|L?SP{kDWEXKqZCv5tDyYg$ZH5+Le1{-fwp3T8x4KII@^nllGc zgFp9)GLkU)mYkr=_6)A_R9WCcCF&yg&PMB+cc=?s=go-|Z(qF~TDd=6z2gwRw35^h z(2I;UCMgR7&6qMT(9A4KL-JRAzztg12e+mPz1jgTI)j3@; zOIv)ECb_Gh8rxJ{1<;q?Tz-mV^&rAl9fC5!5B_>Q=|`^G($e?~#TMJd?*Iy3+UDkV zp%b3(beQX6Bk_6cnt3o!GXU!XW?Cc9M)H}@OVTb&wom5!NwjXOqEXhr3H8~5CkF^F z=*7IJfpIDK8~$h9Jye-e))OiJf%-Ho_Pf>gkINT*X?2sk=UkPC9c>4{{i0^*JzD-# z{mZ|}CK7nL8;}(ZT$jK3y`LQVY-vZu+|*k@vwxKliC?m`^Hv_;35~&o?}gX1O%8BS zB=w}cI4WD`d3&(Pe8I~IkqAaVOf{xba9SXdaP4<1AR~9&nZ-pAw=mK-p%v{AU-2vehyr}qq;8O zi1Xm&Ll76r?dKy)o?x@q5-T-MqjlREA|dMV^0B$yZadJmw%|Cyl-qix;&-LmJn~us zi@B@!-Kys?OO54WxNNR)$D-iMT>>p4V5Bnq{H$=wI`?1|^udlNaVShw?dMnZ?|pf@yxwVzczuMMfcEz%ujT`J=eVpliIE>P_|f`j)f zSO*($d+IagthtSkdo*K*D8VeN^xvt1Ps$-nAkGUDW$9OvF_29!IMdrD}C=KxX z>TzLP)slPsQq(Z5cioyR35+ci9W;8jC{6)BkhdthcU@a)3CbH-^yIol#@)F+1ZhqF z(VXm8e=1$D*Lulg2@`oM?6*sl!U}K zu75}|ZhJLjwAF&L=a_49_y=&O$lzZh6gp&a~Zz=+91^m6K;^NNEBu#|Eaar z)3e^;3)*ZqN|4BA?+5pV9+92nv$FeHq1QLZByO?rEp`T9>pmP*vb;t~9XOD61yQsIDGdwzyc?TknBl{ytT(wU@g>@;m-owr@iV~<%)G8sgAQY5TrHm5OFjUGL zKpM1}Z=8{7xEO*|fKU<&U1;@?k&%g^hmTw8S$w>p1saG%3dMTsE{YR&f8Qe4or+2d zJQe&zLmO$H8`fneM53kvcB}E(HziS;7q38%;w=dhM$ls*d)8&D9dS(fbmXE*3*Q(q z2O^e#D=|Xk#)N-+2NmK4un>F&(mu419HrXjR#+58{9FpCY!!YDF@4swKyoWsl|XCG z!gMS49GEqGFS?wx&<*)O0rkuRU-b^hTyg-Et@E+JtGM2}n_?%cXi}#glVbU zp`@L7o14O~X%`<=XtmXHXFkLc|J;(zq#)OUqQoe|%3|`e0!&QaX_($kQVuPs1Qb|} zPWfxqdc%Tg56uuFklcb~3!$(^vz%!PKn@) zFLhf8d&@ZdTYzOga;+u<_ zgSkib>M#6F%D`bj6ZpI!ivjXY0z`pDk0Xr~eTua8hDDO2Y~G?CWkn*f?{#diuQv2= zygDz)4(+Jx@YLd;0ZUGq-n?Ze+shm z24p^vc;fm*=d`l=6-_lw@|v4RZr<|0_q=V@pTW$lPgemGW)Ud23(v~}6svrGCBZ8 zulZ9Pmut$R*r6`QycCpYQfG?aa)>7?@+s)}xCfoe!wd)vc-*ydr1>w$Xc;}8^kB2B z>oflPZlqNQG{8RewTtx!Nl57+AF|>DW(L9?8ri`JLtP=pR{oV7PT_;uM80`8d&_G> z{Gwc>)V`IHpcDGl7~C;f{$U@l)}xY<(1N29a^r1*x48ZKz>h?clz^Zh5fJ?Wya#}w zyc6!8Rv-@~@!e57ighrSI-lc9LW$M&b>(y~Atya|yvU)#f{$ua>j{5!DupH?Fkfvw z$T~ZnUfew9IiOPiF6x~0W!hXOh5Z`4|!na{bQ zYWP=^tfB~m(!zAN?0Hpnhvj;Gb)C$4-@!bO%R4L+dP7r(;p{4Hx}&>uozX_+d&=X2 z`?*VgB6K|qKOc9HafN_YDY zhq+sR6Zx*bsgNw;!+nUpcza+ktY5J1At5CVWH9PKYuBJi9Y-PLagzE3>#{atI&`E# zNP3Q`p-<)(3jFZV*Wp77yEAF<9H z1>ZbGkm`y&TDlEf&ds?H9&yzwsh6d2zY{I(ObNrWvBYIIH2sv_$EkiOiIY&6u?yt6 zcnt-yr}7YCJkuNFw>I@o+FREt5`iUxrtPk?+7W^XEjb;0zh$?bjA2zJ6RagRPQB7y z(|PnUF3X75h)1dXxMYATZsx&({pz)m_|OK3*UXR9Xb5z|$82>qW)eOly8Zln`&$)8 zs-HSi*FUzXJw_k5J9t}tUqCjs4xp4C*J||)XPi$7E$gsVDxj?RQzt!vX9m~jT7gd1 z5LS&c*!KmDqYz_=r4()lP-L9w$P0gOKcogUrv+k^&^DjS-Wj?EA9@x;{pfOi-nnP$ zeP2dH(;at6)$8f?3}3+5%W<=H@S`0v6Fm73^g*tyNnEFxQexHEpj%Z*&9GPqGJpkPC#@MHNUQRxm&I^~hSbTt!?{uJpAw&5IPDA} z*0F#k#O8++<0qq22DOmNp+L^vgIsY*xeCR9xuwmXKG-G$lJY}ei zq!Lrwc*Qg7`Fd?_wPgTKQ^DXDI)xgdRy_!+pbMtp2M|dMSZ6tJy0(|h<BVuUG?F{KsZz*Kfr zWT0s%rA^IGugKQeArtm9+1-%{2##ElSMTJsv~Zl; za~i8w2aIlbhU#Zz^Yb$Ut=l^Yf#Be0pNg9gxf%{aP(g+IUyS+~m7Z+^?E-n$v*xdJ zMuv=9cW0ttyD5vtRNgPYMLoo#F-&O|Xp{>iJj9h&6iu#OF(+-R&#d&EN38U_AL46G z`|2uItZ=eu*|#9K&7461gu8~to5VxoTy-BkrAR^N%4ka)KXOPF?PMk6=`xF7%Iv2n zMc$2n-H*q%bF+1#xfpH$>I{f zA>g|Gg#XqXCFlzvv_+vug7zQIV@)Z~Ar@(bKta6%7E-focmX5Z?ygNu*J zi^?@k0kWrBl1>u!y~e@YzBGhQle$kIBH=?y$%7VNH0@lR2!zQX<@6gB9DPh3`oXeG zFRnNMw?jg(gCE>uT}_z}VjJA9iG-|^l(p{qQV|dG&R5Y7h}9db%25=njM`e-qd6tF z|6xTxn(mM>41bJ&_2y4!?i?+Zo={`ES+o)kD<%@k_dRtqP3?jnt17Mgl4=PXW>*B# zxwRCjDY9w8X&(IptJae4{vPBW2g}Q=)RsZXs9t#o;Mp)XtFFfz7CSCeQ~}Qrs}nC{ zyacdRh_mv_4vsW849ooQ>Rnf{z$iZ0oz3hb8L?IX8KDPOvBZsti<4ond5ChE*)5?m zRh0HWt(zuEXQCfX`V{id~47I%jM`|DtI5FyB_U+Df zC@=NQEpoQ^ZurLtM`Y^Jaq(-FgSBu=5&mdO@%DO|wmhRWwB8fyH!-1GP$!TKq#k78 zb3>>zr*oWTqR74n!y3VI_dYvHn_4ZVQcQAU^*L{JB>TI!xy{cIY|M7b5m`muvgsnN zn%beYgvW%d-}zc18k{L5u*>XN<9o~n|ABZm%=!ujRPH>8inU8pGV}ZhdGy1L?|dB> z!$cVNYtsD3 zNEWnWeP^|N#%d00XT=J`>+m83WuU2-qqJb;9=AqVoA>kVP+y@!;`hJl-- zIfBbQ4*+@5kMixY3S_w2GIxv#R)4)%+plAG%1u91s z#*J>qcMs5`Wzsx6X^T=4GJqni;$%_?f2Kh^uOGBA9ECC$I1?*9?};LDWHDG-^Q>$o zmT)e%bO>*m5r>B#tukMeb;c-;**~yCVU#rl8DB3bkwBx z;Y#PiqBsH6qT_yr!XaNKE$*CezkHoNA+3>>HB5(3_(7(?Yl`5!ChPq^oA_n_lEn)z zr)E@-KoESxA|%z-<}q#7{{_?uEB0b|Ki%t0`%gf?;D52!sl;*ADZ%&u02&+|pS$vm zjz9YJa|pRStL7^z@D4aiib*`g+k^NeRdQZ@5Wc++_|!&1qaZJHKo+E%5QG5j#~5B} z5X(9ojB}5<%|K=>#BEFuWBxRg{_Xx%Urzr3<5O{@Pv&fxgm zqZ7kp3!GGih*oiojwro{V?f>Q1Tg13VQD_ml1m`~azI+5#H-^AgY8YWCw?0TjL~pP z=BT+Ups?Y&A16wG+JuM{2#ILJ&zil#>$5BSo?zFH8Wcs)q}0PEAZjd*7RoMZk0 zQo}GQxUPBr=UT{)W|BZYQO7)0h)EIWgYDb3QerfuxJNsVK70;Rrt{G(>}h`D;7XlDJ`DVTn#k1B$gwu`!#wgK~LT7ApZcdn#Pmlegg2I^rALS?4>efk1P&2IZDrF%P88vKh~daOKdn?gX!({qT@6S`vyXskM=ua zhq=sS<=fm4o$8>Fm&Ox;=zqqP41>aB=zqqY#93GU+1LqV)a>a^d#&<$Vm1YP?Bo3O zs8xysfTL;b4?nFkFvfMsTmVVquj}nj<21a|pa3zR5AOO@@X8T}RGi@RA6n0L{myW? z1Ft{hPMJ!4$$`he_|v-)ZfVrM6%WnN-2VXU(%QZpY)t1Me(tHK%Z34RNF5JMXV#wt zn-t+!DZo7O`qRH~=v{IS(t7eZkD#jJ2U;hAAO~93$5&;|@2nkWj22abt z9N~TGth)j@0R% zhx}@=UD9BM`Gz_kIQrB!0?ObfAA^Di$&6JSi8F>pInF-kOjPr(>43uY2dDo4Ua4Jt zjzJ1|=Z?IedX~yo9p`Uy8F=gWDhrkcc7dFnkCUZGKgd2n0U0@}w{sPTDr~T zk}S(P9k8v(-0w`5+eS}Skp5Yf{qWlN?*3^1P~76f%5VzJ>PIp z!A^Pa$LmqF+vUMk??*5tb5XDMrqB*Mp+H^MtW@4c8zy>%1qb1JiFv@X({2eN9wB<74bKB&ssOB=D+^feO{{Y69 z0!YYUFh+a&(abvHWPBz)nI9+j9SVLFeO4cCMIG%Ju_?)q;=iw{H1B$27TvkeWN@ zl%4JX>G#j!N^Y^0+%j-8yzx-0ff*n-2R&*vA=OS?WN!P^a|a6y+;b>^$KOsY;k?J=L{ ze1$tn>z_}p9Kz)-2OEjxu{;93DXBR!HtY^K8#~nzDUw+R6l3e`X|;!D)7)WO4iypJ_5i+;B(t zI@Bl&1Dtd}=dDCW3jh}iJr6&vP0Fz|NxgQcAm{tEo3rw`&JJ_4zpX^eyx;`{V~{%j zw2CtPh55MY)Aglru)k>i;t~#6@$z)VN#^8dY466)wFAS3KX;FBT4+tNGyK0yQsx3l zn7Xk&cmoO0(#a_i^0_Q}Z04ic!!rPIDUl}VNjU6r^`&x>C3z0a%y{+NibkB_fCmGR zHdSdPGDdP23VM3=qyV>Eax>rS>+L{tl8k~!B=yN!iO-eT@^klUML-{*B zrEn+aLx8;pO}#0u#Kgsc0DrUAmQ}%1^8Du=55K)bD8~Q{1Mf@%Np}6gm2SZ~rAao% za-`t@0CTk>!oEmsFRc)b$h-l#{{UJ58Hh}`C#m^*)ID1yeGbZek>IfTdiqk^+J`Tk zVN`aY2*f9V0qLK)%{0bT@CY5gTxP6@b`1Qv9@OWx3V`v)_?x}QDuW>CdB+u{_9Ym`IrgSYYydd} z7|%|%T%x(0${CoG)bsOos<%+?LxwrW_lFf@RAX!tW;uLxrog6jV)*KNdKyDBF5=oU zfc58^&$*25-ScGn8r^6C4V-XCYRkH?Nn&WF0hUaL>NB6Asc2}&x`~kq8;H$j%WJsi zP2qFt(zhjnWMY_56Q>=2&T6@VOk|Z@=B4UY%ti(>t^)y{>DHg+w8NnRxZ!Yf{zX}u z5uSsurAH_u1#mEZJ*pZV#Ek3%<<39Z>q?38WjQ(i?@EekT0MXT%X6H2fl3dOpeRxg z9Ou%I4GJE{Aj7TG9&7mM{YFGyebqq{qw9b?&suAISp%91uCDs_rZtDFE@uu%KI?|Jg>ber5mw literal 0 HcmV?d00001 From 40818cfe1c3601a8b88d6935e255064aab07679b Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 11 Nov 2014 13:19:47 -0800 Subject: [PATCH 06/68] spec: method selectors don't auto-deref named pointer types Language clarification. The existing rules for selector expressions imply automatic dereferencing of pointers to struct fields. They also implied automatic dereferencing of selectors denoting methods. In almost all cases, such automatic dereferencing does indeed take place for methods but the reason is not the selector rules but the fact that method sets include both methods with T and *T receivers; so for a *T actual receiver, a method expecting a formal T receiver, also accepts a *T (and the invocation or method value expression is the reason for the auto-derefering). However, the rules as stated so far implied that even in case of a variable p of named pointer type P, a selector expression p.f would always be shorthand for (*p).f. This is true for field selectors f, but cannot be true for method selectors since a named pointer type always has an empty method set. Named pointer types may never appear as anonymous field types (and method receivers, for that matter), so this only applies to variables declared of a named pointer type. This is exceedingly rare and perhaps shouldn't be permitted in the first place (but we cannot change that). Amended the selector rules to make auto-deref of values of named pointer types an exception to the general rules and added corresponding examples with explanations. Both gc and gccgo have a bug where they do auto-deref pointers of named types in method selectors where they should not: See http://play.golang.org/p/c6VhjcIVdM , line 45. Fixes #5769. Fixes #8989. LGTM=r, rsc R=r, rsc, iant, ken CC=golang-codereviews https://golang.org/cl/168790043 --- doc/go_spec.html | 68 ++++++++++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 26 deletions(-) diff --git a/doc/go_spec.html b/doc/go_spec.html index 050c06465d..ca0deb56a3 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ @@ -2521,30 +2521,40 @@ The following rules apply to selectors:
      1. For a value x of type T or *T -where T is not an interface type, +where T is not a pointer or interface type, x.f denotes the field or method at the shallowest depth in T where there is such an f. If there is not exactly one f with shallowest depth, the selector expression is illegal.
      2. +
      3. -For a variable x of type I where I +For a value x of type I where I is an interface type, x.f denotes the actual method with name -f of the value assigned to x. +f of the dynamic value of x. If there is no method with name f in the method set of I, the selector expression is illegal.
      4. + +
      5. +As an exception, if the type of x is a named pointer type +and (*x).f is a valid selector expression denoting a field +(but not a method), x.f is shorthand for (*x).f. +
      6. +
      7. In all other cases, x.f is illegal.
      8. +
      9. If x is of pointer type and has the value nil and x.f denotes a struct field, assigning to or evaluating x.f causes a run-time panic.
      10. +
      11. If x is of interface type and has the value nil, calling or @@ -2553,18 +2563,6 @@ causes a run-time panic.
      -

      -Selectors automatically dereference -pointers to structs. -If x is a pointer to a struct, x.y -is shorthand for (*x).y; if the field y -is also a pointer to a struct, x.y.z is shorthand -for (*(*x).y).z, and so on. -If x contains an anonymous field of type *A, -where A is also a struct type, -x.f is shorthand for (*x.A).f. -

      -

      For example, given the declarations:

      @@ -2574,13 +2572,13 @@ type T0 struct { x int } -func (recv *T0) M0() +func (*T0) M0() type T1 struct { y int } -func (recv T1) M1() +func (T1) M1() type T2 struct { z int @@ -2588,9 +2586,13 @@ type T2 struct { *T0 } -func (recv *T2) M2() +func (*T2) M2() -var p *T2 // with p != nil and p.T0 != nil +type Q *T2 + +var t T2 // with t.T0 != nil +var p *T2 // with p != nil and (*p).T0 != nil +var q Q = p

      @@ -2598,13 +2600,27 @@ one may write:

      -p.z   // (*p).z
      -p.y   // ((*p).T1).y
      -p.x   // (*(*p).T0).x
      +t.z          // t.z
      +t.y          // t.T1.y
      +t.x          // (*t.TO).x
       
      -p.M2()  // (*p).M2()
      -p.M1()  // ((*p).T1).M1()
      -p.M0()  // ((*p).T0).M0()
      +p.z          // (*p).z
      +p.y          // (*p).T1.y
      +p.x          // (*(*p).T0).x
      +
      +q.x          // (*(*q).T0).x        (*q).x is a valid field selector
      +
      +p.M2()       // p.M2()              M2 expects *T2 receiver
      +p.M1()       // ((*p).T1).M1()      M1 expects T1 receiver
      +p.M0()       // ((&(*p).T0)).M0()   M0 expects *T0 receiver, see section on Calls
      +
      + +

      +but the following is invalid: +

      + +
      +q.M0()       // (*q).M0 is valid but not a field selector
       
      From 04c7b68b4a0394405c5a927f639902965663f1a2 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Tue, 11 Nov 2014 18:52:07 -0800 Subject: [PATCH 07/68] regexp/syntax: Clarify comment of OpAnyCharNotNL. LGTM=iant R=golang-codereviews, iant CC=golang-codereviews https://golang.org/cl/171560043 --- src/regexp/syntax/regexp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/regexp/syntax/regexp.go b/src/regexp/syntax/regexp.go index 329a90e012..cea7d9e04f 100644 --- a/src/regexp/syntax/regexp.go +++ b/src/regexp/syntax/regexp.go @@ -39,7 +39,7 @@ const ( OpEmptyMatch // matches empty string OpLiteral // matches Runes sequence OpCharClass // matches Runes interpreted as range pair list - OpAnyCharNotNL // matches any character + OpAnyCharNotNL // matches any character except newline OpAnyChar // matches any character OpBeginLine // matches empty string at beginning of line OpEndLine // matches empty string at end of line From de7d1c409474f0fe5cf88e5d106da683ea79f12e Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Wed, 12 Nov 2014 18:48:00 +1100 Subject: [PATCH 08/68] hash/crc32: fix comment that the IEEE polynomial applies to MPEG-2. LGTM=minux R=adg, minux CC=golang-codereviews https://golang.org/cl/170520043 --- src/hash/crc32/crc32.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hash/crc32/crc32.go b/src/hash/crc32/crc32.go index a2a21a06f9..6a6b9473be 100644 --- a/src/hash/crc32/crc32.go +++ b/src/hash/crc32/crc32.go @@ -17,8 +17,8 @@ const Size = 4 // Predefined polynomials. const ( - // Far and away the most common CRC-32 polynomial. - // Used by ethernet (IEEE 802.3), v.42, fddi, gzip, zip, png, mpeg-2, ... + // IEEE is by far and away the most common CRC-32 polynomial. + // Used by ethernet (IEEE 802.3), v.42, fddi, gzip, zip, png, ... IEEE = 0xedb88320 // Castagnoli's polynomial, used in iSCSI. From 1a60ea1c01a627f4a0852fd0f4a37ba2c0eabc3c Mon Sep 17 00:00:00 2001 From: Emil Hessman Date: Wed, 12 Nov 2014 10:01:23 -0800 Subject: [PATCH 09/68] A+C: add another email address for Emil Hessman LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews https://golang.org/cl/143470043 --- AUTHORS | 2 +- CONTRIBUTORS | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index 48a262bbd7..46fd9fd295 100644 --- a/AUTHORS +++ b/AUTHORS @@ -145,7 +145,7 @@ Egon Elbre Ehren Kret Eivind Uggedal Elias Naur -Emil Hessman +Emil Hessman Eoghan Sherry Eric Clark Eric Milliken diff --git a/CONTRIBUTORS b/CONTRIBUTORS index ec69858b60..a0566745f2 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -214,7 +214,7 @@ Egon Elbre Ehren Kret Eivind Uggedal Elias Naur -Emil Hessman +Emil Hessman Eoghan Sherry Eric Clark Eric Milliken From 38ea0ae05f1f2839949ca491a3541ada0e4c1211 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 12 Nov 2014 14:27:27 -0800 Subject: [PATCH 10/68] net/url: add example of using URL.Opaque with http.Request Per private thread soliciting help. I realized part of this is documented in several places, but we lacked a unifying example. LGTM=rsc R=golang-codereviews CC=adg, golang-codereviews, iant, rsc https://golang.org/cl/171620043 --- src/net/url/example_test.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/net/url/example_test.go b/src/net/url/example_test.go index 56c5dc696a..e55c1aa166 100644 --- a/src/net/url/example_test.go +++ b/src/net/url/example_test.go @@ -7,7 +7,10 @@ package url_test import ( "fmt" "log" + "net/http" + "net/http/httputil" "net/url" + "strings" ) func ExampleValues() { @@ -39,3 +42,30 @@ func ExampleURL() { fmt.Println(u) // Output: https://google.com/search?q=golang } + +func ExampleURL_opaque() { + // Sending a literal '%' in an HTTP request's Path + req := &http.Request{ + Method: "GET", + Host: "example.com", // takes precendence over URL.Host + URL: &url.URL{ + Host: "ignored", + Scheme: "https", + Opaque: "/%2f/", + }, + Header: http.Header{ + "User-Agent": {"godoc-example/0.1"}, + }, + } + out, err := httputil.DumpRequestOut(req, true) + if err != nil { + log.Fatal(err) + } + fmt.Println(strings.Replace(string(out), "\r", "", -1)) + // Output: + // GET /%2f/ HTTP/1.1 + // Host: example.com + // User-Agent: godoc-example/0.1 + // Accept-Encoding: gzip + // +} From 891abf9cc7c9c33e6afccbc3f6cbd5ef17a223b5 Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Fri, 14 Nov 2014 11:43:01 +1100 Subject: [PATCH 11/68] net/http: add comment to clarify whether Dir is '/' or '\'. LGTM=bradfitz R=bradfitz, alex.brainman CC=golang-codereviews https://golang.org/cl/168600044 --- src/net/http/fs.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/net/http/fs.go b/src/net/http/fs.go index 7bd777b712..e322f710a5 100644 --- a/src/net/http/fs.go +++ b/src/net/http/fs.go @@ -22,8 +22,12 @@ import ( "time" ) -// A Dir implements http.FileSystem using the native file -// system restricted to a specific directory tree. +// A Dir implements FileSystem using the native file system restricted to a +// specific directory tree. +// +// While the FileSystem.Open method takes '/'-separated paths, a Dir's string +// value is a filename on the native file system, not a URL, so it is separated +// by filepath.Separator, which isn't necessarily '/'. // // An empty Dir is treated as ".". type Dir string From 59439f8ea343ad79f289910d71d98dd6e6af8661 Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Fri, 14 Nov 2014 14:05:14 +1100 Subject: [PATCH 12/68] doc: fix small typo in doc LGTM=adg R=golang-codereviews, adg CC=golang-codereviews https://golang.org/cl/170660043 --- doc/install.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/install.html b/doc/install.html index d6984c2447..9561fdde21 100644 --- a/doc/install.html +++ b/doc/install.html @@ -47,7 +47,7 @@ proceeding. If your OS or architecture is not on the list, it's possible that FreeBSD 8 or later amd64, 386, arm Debian GNU/kFreeBSD not supported; FreeBSD/ARM needs FreeBSD 10 or later Linux 2.6.23 or later with glibc amd64, 386, arm CentOS/RHEL 5.x not supported; no binary distribution for ARM yet Mac OS X 10.6 or later amd64, 386 use the gcc that comes with Xcode -Windows XP or later amd64, 386 use MinGW gcc. No need for cgywin or msys. +Windows XP or later amd64, 386 use MinGW gcc. No need for cygwin or msys.

      From f9d56543f1b3fe3b8da9dbda8892c4a9d2b8a312 Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Fri, 14 Nov 2014 17:03:17 +1100 Subject: [PATCH 13/68] C: add Nick Cooper (Google CLA). LGTM=dsymonds R=dsymonds CC=golang-codereviews, nmvc https://golang.org/cl/169580043 --- CONTRIBUTORS | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index a0566745f2..b5e709ed6e 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -452,6 +452,7 @@ Nicholas Katsaros Nicholas Presta Nicholas Sullivan Nicholas Waples +Nick Cooper Nick Craig-Wood Nicolas Kaiser Nicolas Owens From 9e7bed88cde087726ad097442ee9b36f4f4021bc Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 14 Nov 2014 11:07:33 -0500 Subject: [PATCH 14/68] [dev.power64] 5g,6g,8g: synchronize documentation for regopt structures I added several comments to the regopt-related structures when porting it to 9g. Synchronize those comments back in to the other compilers. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/175720043 --- src/cmd/5g/opt.h | 28 ++++++++++++++++++++++------ src/cmd/6g/opt.h | 30 +++++++++++++++++++++++------- src/cmd/8g/opt.h | 30 +++++++++++++++++++++++------- 3 files changed, 68 insertions(+), 20 deletions(-) diff --git a/src/cmd/5g/opt.h b/src/cmd/5g/opt.h index 5016d1cc83..01edeb84d8 100644 --- a/src/cmd/5g/opt.h +++ b/src/cmd/5g/opt.h @@ -75,12 +75,18 @@ struct Reg { Flow f; - Bits set; // variables written by this instruction. - Bits use1; // variables read by prog->from. - Bits use2; // variables read by prog->to. + Bits set; // regopt variables written by this instruction. + Bits use1; // regopt variables read by prog->from. + Bits use2; // regopt variables read by prog->to. + // refahead/refbehind are the regopt variables whose current + // value may be used in the following/preceding instructions + // up to a CALL (or the value is clobbered). Bits refbehind; Bits refahead; + // calahead/calbehind are similar, but for variables in + // instructions that are reachable after hitting at least one + // CALL. Bits calbehind; Bits calahead; Bits regdiff; @@ -93,6 +99,16 @@ struct Reg #define NRGN 600 /*c2go enum { NRGN = 600 }; */ + +// A Rgn represents a single regopt variable over a region of code +// where a register could potentially be dedicated to that variable. +// The code encompassed by a Rgn is defined by the flow graph, +// starting at enter, flood-filling forward while varno is refahead +// and backward while varno is refbehind, and following branches. A +// single variable may be represented by multiple disjoint Rgns and +// each Rgn may choose a different register for that variable. +// Registers are allocated to regions greedily in order of descending +// cost. struct Rgn { Reg* enter; @@ -187,16 +203,16 @@ enum SizeF = 1<<7, // float aka float32 SizeD = 1<<8, // double aka float64 - // Left side: address taken, read, write. + // Left side (Prog.from): address taken, read, write. LeftAddr = 1<<9, LeftRead = 1<<10, LeftWrite = 1<<11, - // Register in middle; never written. + // Register in middle (Prog.reg); only ever read. RegRead = 1<<12, CanRegRead = 1<<13, - // Right side: address taken, read, write. + // Right side (Prog.to): address taken, read, write. RightAddr = 1<<14, RightRead = 1<<15, RightWrite = 1<<16, diff --git a/src/cmd/6g/opt.h b/src/cmd/6g/opt.h index 4c9bb89fc8..08486a04a0 100644 --- a/src/cmd/6g/opt.h +++ b/src/cmd/6g/opt.h @@ -75,12 +75,18 @@ struct Reg { Flow f; - Bits set; // variables written by this instruction. - Bits use1; // variables read by prog->from. - Bits use2; // variables read by prog->to. + Bits set; // regopt variables written by this instruction. + Bits use1; // regopt variables read by prog->from. + Bits use2; // regopt variables read by prog->to. + // refahead/refbehind are the regopt variables whose current + // value may be used in the following/preceding instructions + // up to a CALL (or the value is clobbered). Bits refbehind; Bits refahead; + // calahead/calbehind are similar, but for variables in + // instructions that are reachable after hitting at least one + // CALL. Bits calbehind; Bits calahead; Bits regdiff; @@ -93,6 +99,16 @@ struct Reg #define NRGN 600 /*c2go enum { NRGN = 600 }; */ + +// A Rgn represents a single regopt variable over a region of code +// where a register could potentially be dedicated to that variable. +// The code encompassed by a Rgn is defined by the flow graph, +// starting at enter, flood-filling forward while varno is refahead +// and backward while varno is refbehind, and following branches. A +// single variable may be represented by multiple disjoint Rgns and +// each Rgn may choose a different register for that variable. +// Registers are allocated to regions greedily in order of descending +// cost. struct Rgn { Reg* enter; @@ -165,8 +181,8 @@ typedef struct ProgInfo ProgInfo; struct ProgInfo { uint32 flags; // the bits below - uint32 reguse; // required registers used by this instruction - uint32 regset; // required registers set by this instruction + uint32 reguse; // registers implicitly used by this instruction + uint32 regset; // registers implicitly set by this instruction uint32 regindex; // registers used by addressing mode }; @@ -187,12 +203,12 @@ enum SizeF = 1<<7, // float aka float32 SizeD = 1<<8, // double aka float64 - // Left side: address taken, read, write. + // Left side (Prog.from): address taken, read, write. LeftAddr = 1<<9, LeftRead = 1<<10, LeftWrite = 1<<11, - // Right side: address taken, read, write. + // Right side (Prog.to): address taken, read, write. RightAddr = 1<<12, RightRead = 1<<13, RightWrite = 1<<14, diff --git a/src/cmd/8g/opt.h b/src/cmd/8g/opt.h index 0e2d165b17..11ee66e081 100644 --- a/src/cmd/8g/opt.h +++ b/src/cmd/8g/opt.h @@ -75,12 +75,18 @@ struct Reg { Flow f; - Bits set; // variables written by this instruction. - Bits use1; // variables read by prog->from. - Bits use2; // variables read by prog->to. + Bits set; // regopt variables written by this instruction. + Bits use1; // regopt variables read by prog->from. + Bits use2; // regopt variables read by prog->to. + // refahead/refbehind are the regopt variables whose current + // value may be used in the following/preceding instructions + // up to a CALL (or the value is clobbered). Bits refbehind; Bits refahead; + // calahead/calbehind are similar, but for variables in + // instructions that are reachable after hitting at least one + // CALL. Bits calbehind; Bits calahead; Bits regdiff; @@ -106,6 +112,16 @@ struct Reg #define NRGN 600 /*c2go enum { NRGN = 600 }; */ + +// A Rgn represents a single regopt variable over a region of code +// where a register could potentially be dedicated to that variable. +// The code encompassed by a Rgn is defined by the flow graph, +// starting at enter, flood-filling forward while varno is refahead +// and backward while varno is refbehind, and following branches. A +// single variable may be represented by multiple disjoint Rgns and +// each Rgn may choose a different register for that variable. +// Registers are allocated to regions greedily in order of descending +// cost. struct Rgn { Reg* enter; @@ -183,8 +199,8 @@ typedef struct ProgInfo ProgInfo; struct ProgInfo { uint32 flags; // the bits below - uint32 reguse; // required registers used by this instruction - uint32 regset; // required registers set by this instruction + uint32 reguse; // registers implicitly used by this instruction + uint32 regset; // registers implicitly set by this instruction uint32 regindex; // registers used by addressing mode }; @@ -205,12 +221,12 @@ enum SizeF = 1<<7, // float aka float32 SizeD = 1<<8, // double aka float64 - // Left side: address taken, read, write. + // Left side (Prog.from): address taken, read, write. LeftAddr = 1<<9, LeftRead = 1<<10, LeftWrite = 1<<11, - // Right side: address taken, read, write. + // Right side (Prog.to): address taken, read, write. RightAddr = 1<<12, RightRead = 1<<13, RightWrite = 1<<14, From 5b38501a4f56a4c325c3992b608fb095b3b2e1e5 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 14 Nov 2014 11:56:31 -0500 Subject: [PATCH 15/68] [dev.power64] 5g,6g,8g,9g: debug prints for regopt pass 6 and paint2 Theses were very helpful in understanding the regions and register selection when porting regopt to 9g. Add them to the other compilers (and improve 9g's successor debug print). LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/174130043 --- src/cmd/5g/opt.h | 2 +- src/cmd/5g/reg.c | 45 +++++++++++++++++++++++++++++++-------------- src/cmd/6g/opt.h | 2 +- src/cmd/6g/reg.c | 43 +++++++++++++++++++++++++++++-------------- src/cmd/8g/opt.h | 2 +- src/cmd/8g/reg.c | 43 +++++++++++++++++++++++++++++-------------- src/cmd/9g/reg.c | 7 ++----- 7 files changed, 94 insertions(+), 50 deletions(-) diff --git a/src/cmd/5g/opt.h b/src/cmd/5g/opt.h index 01edeb84d8..a606f1d310 100644 --- a/src/cmd/5g/opt.h +++ b/src/cmd/5g/opt.h @@ -160,7 +160,7 @@ void prop(Reg*, Bits, Bits); void synch(Reg*, Bits); uint32 allreg(uint32, Rgn*); void paint1(Reg*, int); -uint32 paint2(Reg*, int); +uint32 paint2(Reg*, int, int); void paint3(Reg*, int, uint32, int); void addreg(Adr*, int); void dumpit(char *str, Flow *r0, int); diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c index 712841329e..86a1f7efb1 100644 --- a/src/cmd/5g/reg.c +++ b/src/cmd/5g/reg.c @@ -454,9 +454,13 @@ brk: * replace code (paint3) */ rgp = region; + if(debug['R'] && debug['v']) + print("\nregisterizing\n"); for(i=0; icost, rgp->varno, rgp->enter->f.prog->pc); bit = blsh(rgp->varno); - vreg = paint2(rgp->enter, rgp->varno); + vreg = paint2(rgp->enter, rgp->varno, 0); vreg = allreg(vreg, rgp); if(debug['R']) { if(rgp->regno >= NREG) @@ -477,9 +481,6 @@ brk: rgp++; } - if(debug['R'] && debug['v']) - dumpit("pass6", &firstr->f, 1); - /* * free aux structures. peep allocates new ones. */ @@ -488,6 +489,15 @@ brk: flowend(g); firstr = R; + if(debug['R'] && debug['v']) { + // Rebuild flow graph, since we inserted instructions + g = flowstart(firstp, sizeof(Reg)); + firstr = (Reg*)g->start; + dumpit("pass6", &firstr->f, 1); + flowend(g); + firstr = R; + } + /* * pass 7 * peep-hole on basic block @@ -1189,7 +1199,7 @@ paint1(Reg *r, int bn) } uint32 -paint2(Reg *r, int bn) +paint2(Reg *r, int bn, int depth) { Reg *r1; int z; @@ -1213,6 +1223,9 @@ paint2(Reg *r, int bn) r = r1; } for(;;) { + if(debug['R'] && debug['v']) + print(" paint2 %d %P\n", depth, r->f.prog); + r->act.b[z] &= ~bb; vreg |= r->regu; @@ -1220,14 +1233,14 @@ paint2(Reg *r, int bn) if(r->refbehind.b[z] & bb) for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link) if(r1->refahead.b[z] & bb) - vreg |= paint2(r1, bn); + vreg |= paint2(r1, bn, depth+1); if(!(r->refahead.b[z] & bb)) break; r1 = (Reg*)r->f.s2; if(r1 != R) if(r1->refbehind.b[z] & bb) - vreg |= paint2(r1, bn); + vreg |= paint2(r1, bn, depth+1); r = (Reg*)r->f.s1; if(r == R) break; @@ -1344,6 +1357,8 @@ RtoB(int r) int BtoR(uint32 b) { + // TODO Allow R0 and R1, but be careful with a 0 return + // TODO Allow R9. Only R10 is reserved now (just g, not m). b &= 0x11fcL; // excluded R9 and R10 for m and g, but not R12 if(b == 0) return 0; @@ -1442,12 +1457,14 @@ dumpit(char *str, Flow *r0, int isreg) print(" (only)"); print("\n"); } -// r1 = r->s1; -// if(r1 != nil) { -// print(" succ:"); -// for(; r1 != R; r1 = r1->s1) -// print(" %.4ud", (int)r1->prog->pc); -// print("\n"); -// } + // Print successors if it's not just the next one + if(r->s1 != r->link || r->s2 != nil) { + print(" succ:"); + if(r->s1 != nil) + print(" %.4ud", (int)r->s1->prog->pc); + if(r->s2 != nil) + print(" %.4ud", (int)r->s2->prog->pc); + print("\n"); + } } } diff --git a/src/cmd/6g/opt.h b/src/cmd/6g/opt.h index 08486a04a0..493171ef82 100644 --- a/src/cmd/6g/opt.h +++ b/src/cmd/6g/opt.h @@ -156,7 +156,7 @@ void prop(Reg*, Bits, Bits); void synch(Reg*, Bits); uint32 allreg(uint32, Rgn*); void paint1(Reg*, int); -uint32 paint2(Reg*, int); +uint32 paint2(Reg*, int, int); void paint3(Reg*, int, uint32, int); void addreg(Adr*, int); void dumpone(Flow*, int); diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c index 4ce2f4db00..75f9573b2e 100644 --- a/src/cmd/6g/reg.c +++ b/src/cmd/6g/reg.c @@ -389,9 +389,13 @@ brk: * replace code (paint3) */ rgp = region; + if(debug['R'] && debug['v']) + print("\nregisterizing\n"); for(i=0; icost, rgp->varno, rgp->enter->f.prog->pc); bit = blsh(rgp->varno); - vreg = paint2(rgp->enter, rgp->varno); + vreg = paint2(rgp->enter, rgp->varno, 0); vreg = allreg(vreg, rgp); if(rgp->regno != 0) { if(debug['R'] && debug['v']) { @@ -406,9 +410,6 @@ brk: rgp++; } - if(debug['R'] && debug['v']) - dumpit("pass6", &firstr->f, 1); - /* * free aux structures. peep allocates new ones. */ @@ -417,6 +418,15 @@ brk: flowend(g); firstr = R; + if(debug['R'] && debug['v']) { + // Rebuild flow graph, since we inserted instructions + g = flowstart(firstp, sizeof(Reg)); + firstr = (Reg*)g->start; + dumpit("pass6", &firstr->f, 1); + flowend(g); + firstr = R; + } + /* * pass 7 * peep-hole on basic block @@ -1020,7 +1030,7 @@ paint1(Reg *r, int bn) } uint32 -paint2(Reg *r, int bn) +paint2(Reg *r, int bn, int depth) { Reg *r1; int z; @@ -1044,6 +1054,9 @@ paint2(Reg *r, int bn) r = r1; } for(;;) { + if(debug['R'] && debug['v']) + print(" paint2 %d %P\n", depth, r->f.prog); + r->act.b[z] &= ~bb; vreg |= r->regu; @@ -1051,14 +1064,14 @@ paint2(Reg *r, int bn) if(r->refbehind.b[z] & bb) for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link) if(r1->refahead.b[z] & bb) - vreg |= paint2(r1, bn); + vreg |= paint2(r1, bn, depth+1); if(!(r->refahead.b[z] & bb)) break; r1 = (Reg*)r->f.s2; if(r1 != R) if(r1->refbehind.b[z] & bb) - vreg |= paint2(r1, bn); + vreg |= paint2(r1, bn, depth+1); r = (Reg*)r->f.s1; if(r == R) break; @@ -1259,12 +1272,14 @@ dumpit(char *str, Flow *r0, int isreg) print(" %.4ud", (int)r1->prog->pc); print("\n"); } -// r1 = r->s1; -// if(r1 != R) { -// print(" succ:"); -// for(; r1 != R; r1 = r1->s1) -// print(" %.4ud", (int)r1->prog->pc); -// print("\n"); -// } + // Print successors if it's not just the next one + if(r->s1 != r->link || r->s2 != nil) { + print(" succ:"); + if(r->s1 != nil) + print(" %.4ud", (int)r->s1->prog->pc); + if(r->s2 != nil) + print(" %.4ud", (int)r->s2->prog->pc); + print("\n"); + } } } diff --git a/src/cmd/8g/opt.h b/src/cmd/8g/opt.h index 11ee66e081..5445f91275 100644 --- a/src/cmd/8g/opt.h +++ b/src/cmd/8g/opt.h @@ -174,7 +174,7 @@ void loopit(Reg*, int32); void synch(Reg*, Bits); uint32 allreg(uint32, Rgn*); void paint1(Reg*, int); -uint32 paint2(Reg*, int); +uint32 paint2(Reg*, int, int); void paint3(Reg*, int, uint32, int); void addreg(Adr*, int); void dumpone(Flow*, int); diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c index 79d60bed55..45aea2c337 100644 --- a/src/cmd/8g/reg.c +++ b/src/cmd/8g/reg.c @@ -358,18 +358,19 @@ brk: * replace code (paint3) */ rgp = region; + if(debug['R'] && debug['v']) + print("\nregisterizing\n"); for(i=0; icost, rgp->varno, rgp->enter->f.prog->pc); bit = blsh(rgp->varno); - vreg = paint2(rgp->enter, rgp->varno); + vreg = paint2(rgp->enter, rgp->varno, 0); vreg = allreg(vreg, rgp); if(rgp->regno != 0) paint3(rgp->enter, rgp->varno, vreg, rgp->regno); rgp++; } - if(debug['R'] && debug['v']) - dumpit("pass6", &firstr->f, 1); - /* * free aux structures. peep allocates new ones. */ @@ -378,6 +379,15 @@ brk: flowend(g); firstr = R; + if(debug['R'] && debug['v']) { + // Rebuild flow graph, since we inserted instructions + g = flowstart(firstp, sizeof(Reg)); + firstr = (Reg*)g->start; + dumpit("pass6", &firstr->f, 1); + flowend(g); + firstr = R; + } + /* * pass 7 * peep-hole on basic block @@ -996,7 +1006,7 @@ paint1(Reg *r, int bn) } uint32 -paint2(Reg *r, int bn) +paint2(Reg *r, int bn, int depth) { Reg *r1; int z; @@ -1020,6 +1030,9 @@ paint2(Reg *r, int bn) r = r1; } for(;;) { + if(debug['R'] && debug['v']) + print(" paint2 %d %P\n", depth, r->f.prog); + r->act.b[z] &= ~bb; vreg |= r->regu; @@ -1027,14 +1040,14 @@ paint2(Reg *r, int bn) if(r->refbehind.b[z] & bb) for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link) if(r1->refahead.b[z] & bb) - vreg |= paint2(r1, bn); + vreg |= paint2(r1, bn, depth+1); if(!(r->refahead.b[z] & bb)) break; r1 = (Reg*)r->f.s2; if(r1 != R) if(r1->refbehind.b[z] & bb) - vreg |= paint2(r1, bn); + vreg |= paint2(r1, bn, depth+1); r = (Reg*)r->f.s1; if(r == R) break; @@ -1227,12 +1240,14 @@ dumpit(char *str, Flow *r0, int isreg) print(" %.4ud", (int)r1->prog->pc); print("\n"); } -// r1 = r->s1; -// if(r1 != nil) { -// print(" succ:"); -// for(; r1 != R; r1 = r1->s1) -// print(" %.4ud", (int)r1->prog->pc); -// print("\n"); -// } + // Print successors if it's not just the next one + if(r->s1 != r->link || r->s2 != nil) { + print(" succ:"); + if(r->s1 != nil) + print(" %.4ud", (int)r->s1->prog->pc); + if(r->s2 != nil) + print(" %.4ud", (int)r->s2->prog->pc); + print("\n"); + } } } diff --git a/src/cmd/9g/reg.c b/src/cmd/9g/reg.c index b911a23998..2e546a95bb 100644 --- a/src/cmd/9g/reg.c +++ b/src/cmd/9g/reg.c @@ -1322,7 +1322,6 @@ void dumpit(char *str, Flow *r0, int isreg) { Flow *r, *r1; - int s1v, s2v; print("\n%s\n", str); for(r = r0; r != nil; r = r->link) { @@ -1334,10 +1333,8 @@ dumpit(char *str, Flow *r0, int isreg) print(" %.4ud", (int)r1->prog->pc); print("\n"); } - // If at least one successor is "interesting", print both - s1v = (r->s1 != nil) && (r->s1->prog != r->prog->link); - s2v = (r->s2 != nil) && (r->s2->prog != r->prog->link); - if(s1v || s2v) { + // Print successors if it's not just the next one + if(r->s1 != r->link || r->s2 != nil) { print(" succ:"); if(r->s1 != nil) print(" %.4ud", (int)r->s1->prog->pc); From a11f256436a386c81e3a34378b37bc51fb2d5f61 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 14 Nov 2014 12:08:46 -0500 Subject: [PATCH 16/68] [dev.power64] liblink: generate dnames[5689] for D_* constants This is more complicated than the other enums because the D_* enums are full of explicit initializers and repeated values. This tries its best. (This will get much cleaner once we tease these constants apart better.) LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/166700043 --- include/link.h | 5 +++ src/cmd/dist/buildgc.c | 85 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 87 insertions(+), 3 deletions(-) diff --git a/include/link.h b/include/link.h index 06f3ebb489..225c6f95df 100644 --- a/include/link.h +++ b/include/link.h @@ -626,6 +626,11 @@ extern char* anames9[]; extern char* cnames5[]; extern char* cnames9[]; +extern char* dnames5[]; +extern char* dnames6[]; +extern char* dnames8[]; +extern char* dnames9[]; + extern LinkArch link386; extern LinkArch linkamd64; extern LinkArch linkamd64p32; diff --git a/src/cmd/dist/buildgc.c b/src/cmd/dist/buildgc.c index 1c33297587..39679fb724 100644 --- a/src/cmd/dist/buildgc.c +++ b/src/cmd/dist/buildgc.c @@ -63,22 +63,36 @@ gcopnames(char *dir, char *file) vfree(&fields); } +static int +xatoi(char *s, char **end) +{ + int val = 0; + for(; *s && *s >= '0' && *s <= '9'; ++s) + val = val * 10 + (*s - '0'); + *end = s; + return val; +} + // mkanames reads [5689].out.h and writes anames[5689].c // The format is much the same as the Go opcodes above. -// it also writes out cnames array for C_* constants. +// It also writes out cnames array for C_* constants and the dnames +// array for D_* constants. void mkanames(char *dir, char *file) { - int i, j, ch; + int i, j, ch, n, unknown; Buf in, b, out, out2; Vec lines; - char *p; + char *p, *p2; + Vec dnames[128]; binit(&b); binit(&in); binit(&out); binit(&out2); vinit(&lines); + for(i=0; i\n")); bwritestr(&out, bprintf(&b, "#include \n")); bwritestr(&out, bprintf(&b, "#include \n")); bwritestr(&out, bprintf(&b, "#include \n")); + bwritestr(&out, bprintf(&b, "#include \"../cmd/%cl/%c.out.h\"\n", ch, ch)); bwritestr(&out, bprintf(&b, "\n")); bwritestr(&out, bprintf(&b, "char* anames%c[] = {\n", ch)); @@ -127,6 +143,67 @@ mkanames(char *dir, char *file) if(j>0) bwriteb(&out, &out2); + j=unknown=0; + n=-1; + for(i=0; i Date: Fri, 14 Nov 2014 13:58:31 -0500 Subject: [PATCH 17/68] [dev.power64] 6g,9g: formatters for Prog and Addr details The pretty printers for these make it hard to understand what's actually in the fields of these structures. These "ugly printers" show exactly what's in each field, which can be useful for understanding and debugging code. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/175780043 --- src/cmd/5l/5.out.h | 2 ++ src/cmd/6l/6.out.h | 2 ++ src/cmd/8l/8.out.h | 2 ++ src/cmd/9l/9.out.h | 2 ++ src/cmd/dist/buildgc.c | 4 +++- src/liblink/list6.c | 38 ++++++++++++++++++++++++++++++++++++++ src/liblink/list9.c | 41 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 90 insertions(+), 1 deletion(-) diff --git a/src/cmd/5l/5.out.h b/src/cmd/5l/5.out.h index 7b16ac4468..38a33db642 100644 --- a/src/cmd/5l/5.out.h +++ b/src/cmd/5l/5.out.h @@ -338,6 +338,8 @@ enum D_STATIC = (D_NONE+4), D_AUTO = (D_NONE+5), D_PARAM = (D_NONE+6), + + D_LAST = (D_NONE+26), }; /* diff --git a/src/cmd/6l/6.out.h b/src/cmd/6l/6.out.h index af72784e84..c09ac28242 100644 --- a/src/cmd/6l/6.out.h +++ b/src/cmd/6l/6.out.h @@ -865,6 +865,8 @@ enum D_INDIR, /* additive */ + D_LAST, + T_TYPE = 1<<0, T_INDEX = 1<<1, T_OFFSET = 1<<2, diff --git a/src/cmd/8l/8.out.h b/src/cmd/8l/8.out.h index ed54f6744a..596c5f61a8 100644 --- a/src/cmd/8l/8.out.h +++ b/src/cmd/8l/8.out.h @@ -654,6 +654,8 @@ enum D_CONST2 = D_INDIR+D_INDIR, + D_LAST, + T_TYPE = 1<<0, T_INDEX = 1<<1, T_OFFSET = 1<<2, diff --git a/src/cmd/9l/9.out.h b/src/cmd/9l/9.out.h index 08a339318d..87917f88ac 100644 --- a/src/cmd/9l/9.out.h +++ b/src/cmd/9l/9.out.h @@ -497,6 +497,8 @@ enum D_DCONST, D_ADDR, // not used, use D_CONST with non-empty sym. + D_LAST, + /* reg names for 9g OREGISTER */ D_R0 = 0, // type is D_REG D_F0 = D_R0+NREG, // type is D_FREG diff --git a/src/cmd/dist/buildgc.c b/src/cmd/dist/buildgc.c index 39679fb724..64434d51e1 100644 --- a/src/cmd/dist/buildgc.c +++ b/src/cmd/dist/buildgc.c @@ -184,12 +184,14 @@ mkanames(char *dir, char *file) continue; p = lines.p[i] + 3; + if(xstrcmp(p, "LAST") == 0) + continue; vadd(&dnames[n], p); j++; } } if(j>0){ - bwritestr(&out, bprintf(&b, "char* dnames%c[] = {\n", ch)); + bwritestr(&out, bprintf(&b, "char* dnames%c[D_LAST] = {\n", ch)); for(i=0; iargs, Prog*); bigP = p; + + if(fp->flags & FmtSharp) { + char *s = str; + s += sprint(s, "%.5lld (%L) %A", p->pc, p->lineno, p->as); + if(p->from.type != D_NONE) + s += sprint(s, " from={%#D}", &p->from); + if(p->reg) + s += sprint(s, " reg=%d", p->reg); + if(p->to.type != D_NONE) + s += sprint(s, " to={%#D}", &p->to); + return fmtstrcpy(fp, str); + } + switch(p->as) { case ADATA: sprint(str, "%.5lld (%L) %A %D/%d,%D", @@ -126,6 +139,31 @@ Dconv(Fmt *fp) a = va_arg(fp->args, Addr*); i = a->type; + if(fp->flags & FmtSharp) { + char *s = str; + s += sprint(s, "type="); + if(i == D_NONE) { + sprint(s, "NONE"); + goto brk; + } + if(i >= D_INDIR) { + i -= D_INDIR; + s += sprint(s, "INDIR+"); + } + if(i >= 0 && i < D_LAST && dnames6[i] != nil) + s += sprint(s, "%s ", dnames6[i]); + else + s += sprint(s, "%d ", i); + s += sprint(s, "offset=%ld etype=%E width=%d", a->offset, a->etype, a->width); + if(a->class != 0) + s += sprint(s, " class=%s", cnames9[a->class]); + if(a->sym != nil) + s += sprint(s, " sym=%s", a->sym->name); + if(a->type == D_BRANCH && a->u.branch != nil) + s += sprint(s, " branch=%.5lld", a->u.branch->pc); + goto brk; + } + if(fp->flags & FmtLong) { if(i == D_CONST) sprint(str, "$%lld-%lld", a->offset&0xffffffffLL, a->offset>>32); diff --git a/src/liblink/list9.c b/src/liblink/list9.c index c9190d8940..2bf86d85be 100644 --- a/src/liblink/list9.c +++ b/src/liblink/list9.c @@ -91,6 +91,21 @@ Pconv(Fmt *fp) p = va_arg(fp->args, Prog*); bigP = p; a = p->as; + + if(fp->flags & FmtSharp) { + s = str; + s += sprint(s, "%.5lld (%L) %A", p->pc, p->lineno, a); + if(p->from.type != D_NONE) + s += sprint(s, " from={%#D}", &p->from); + if(p->reg) + s += sprint(s, " reg=%d", p->reg); + if(p->from3.type != D_NONE) + s += sprint(s, " from3={%#D}", &p->from3); + if(p->to.type != D_NONE) + s += sprint(s, " to={%#D}", &p->to); + return fmtstrcpy(fp, str); + } + if(a == ADATA || a == AINIT || a == ADYNT) sprint(str, "%.5lld (%L) %A %D/%d,%D", p->pc, p->lineno, a, &p->from, p->reg, &p->to); else if(a == ATEXT) { @@ -153,6 +168,32 @@ Dconv(Fmt *fp) a = va_arg(fp->args, Addr*); + if(fp->flags & FmtSharp) { + char *s = str; + if(a->type == D_NONE) { + sprint(s, "type=NONE"); + goto ret; + } + if(a->type >= 0 && a->type < D_LAST && dnames9[a->type] != nil) + s += sprint(s, "type=%s ", dnames9[a->type]); + else + s += sprint(s, "type=%d ", a->type); + if(a->name >= 0 && a->name < D_LAST && dnames9[a->name] != nil) + s += sprint(s, "name=%s ", dnames9[a->name]); + else + s += sprint(s, "name=%d ", a->name); + s += sprint(s, "offset=%ld etype=%E width=%d", a->offset, a->etype, a->width); + if(a->class != 0) + s += sprint(s, " class=%s", cnames9[a->class]); + if(a->reg != NREG) + s += sprint(s, " reg=%d", a->reg); + if(a->sym != nil) + s += sprint(s, " sym=%s", a->sym->name); + if(a->type == D_BRANCH && a->u.branch != nil) + s += sprint(s, " branch=%.5lld", a->u.branch->pc); + goto ret; + } + if(fp->flags & FmtLong) { if(a->type == D_CONST) sprint(str, "$%d-%d", (int32)a->offset, (int32)(a->offset>>32)); From 7904e951d4efd3dd82afcebf5856eeb78217d86d Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 14 Nov 2014 15:53:15 -0500 Subject: [PATCH 18/68] [dev.power64] liblink: fix Solaris build a->class is a char. Boo hoo. LGTM=minux R=rsc, minux CC=golang-codereviews https://golang.org/cl/169630043 --- src/liblink/list6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liblink/list6.c b/src/liblink/list6.c index d6b91c72b0..54cce4aa4b 100644 --- a/src/liblink/list6.c +++ b/src/liblink/list6.c @@ -156,7 +156,7 @@ Dconv(Fmt *fp) s += sprint(s, "%d ", i); s += sprint(s, "offset=%ld etype=%E width=%d", a->offset, a->etype, a->width); if(a->class != 0) - s += sprint(s, " class=%s", cnames9[a->class]); + s += sprint(s, " class=%s", cnames9[(int)a->class]); if(a->sym != nil) s += sprint(s, " sym=%s", a->sym->name); if(a->type == D_BRANCH && a->u.branch != nil) From 6150414cb8819ab9f054298ec7f8006a43ab8eea Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Sun, 16 Nov 2014 14:25:33 -0500 Subject: [PATCH 19/68] runtime: update URL for heap dump format I just created that redirect, so we can change it once the wiki moves. LGTM=bradfitz, khr R=khr, bradfitz CC=golang-codereviews https://golang.org/cl/177780043 --- src/runtime/heapdump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/heapdump.c b/src/runtime/heapdump.c index eddbc1d1c9..7eba8c0057 100644 --- a/src/runtime/heapdump.c +++ b/src/runtime/heapdump.c @@ -7,7 +7,7 @@ // finalizers, etc.) to a file. // The format of the dumped file is described at -// http://code.google.com/p/go-wiki/wiki/heapdump14 +// http://golang.org/s/go14heapdump. #include "runtime.h" #include "arch_GOARCH.h" From b3932baba4e15e175e8f0e040d5e8bbd357a60d8 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Sun, 16 Nov 2014 16:44:45 -0500 Subject: [PATCH 20/68] runtime: fix sudog leak The SudoG used to sit on the stack, so it was cheap to allocated and didn't need to be cleaned up when finished. For the conversion to Go, we had to move sudog off the stack for a few reasons, so we added a cache of recently used sudogs to keep allocation cheap. But we didn't add any of the necessary cleanup before adding a SudoG to the new cache, and so the cached SudoGs had stale pointers inside them that have caused all sorts of awful, hard to debug problems. CL 155760043 made sure SudoG.elem is cleaned up. CL 150520043 made sure SudoG.selectdone is cleaned up. This CL makes sure SudoG.next, SudoG.prev, and SudoG.waitlink are cleaned up. I should have done this when I did the other two fields; instead I wasted a week tracking down a leak they caused. A dangling SudoG.waitlink can point into a sudogcache list that has been "forgotten" in order to let the GC collect it, but that dangling .waitlink keeps the list from being collected. And then the list holding the SudoG with the dangling waitlink can find itself in the same situation, and so on. We end up with lists of lists of unusable SudoGs that are still linked into the object graph and never collected (given the right mix of non-trivial selects and non-channel synchronization). More details in golang.org/issue/9110. Fixes #9110. LGTM=r R=r CC=dvyukov, golang-codereviews, iant, khr https://golang.org/cl/177870043 --- src/runtime/chan.go | 1 + src/runtime/mgc0.go | 16 +++++++ src/runtime/proc.go | 10 +++++ src/runtime/select.go | 2 + src/runtime/sema.go | 2 + test/fixedbugs/issue9110.go | 90 +++++++++++++++++++++++++++++++++++++ 6 files changed, 121 insertions(+) create mode 100644 test/fixedbugs/issue9110.go diff --git a/src/runtime/chan.go b/src/runtime/chan.go index 0049701826..0eb87df74f 100644 --- a/src/runtime/chan.go +++ b/src/runtime/chan.go @@ -630,6 +630,7 @@ func (q *waitq) dequeue() *sudog { return nil } q.first = sgp.next + sgp.next = nil if q.last == sgp { q.last = nil } diff --git a/src/runtime/mgc0.go b/src/runtime/mgc0.go index 3a7204b54f..cbf5e9cfde 100644 --- a/src/runtime/mgc0.go +++ b/src/runtime/mgc0.go @@ -51,10 +51,26 @@ func clearpools() { if c := p.mcache; c != nil { c.tiny = nil c.tinysize = 0 + + // disconnect cached list before dropping it on the floor, + // so that a dangling ref to one entry does not pin all of them. + var sg, sgnext *sudog + for sg = c.sudogcache; sg != nil; sg = sgnext { + sgnext = sg.next + sg.next = nil + } c.sudogcache = nil } + // clear defer pools for i := range p.deferpool { + // disconnect cached list before dropping it on the floor, + // so that a dangling ref to one entry does not pin all of them. + var d, dlink *_defer + for d = p.deferpool[i]; d != nil; d = dlink { + dlink = d.link + d.link = nil + } p.deferpool[i] = nil } } diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 5b8c7d8ae9..517ca03df6 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -152,6 +152,7 @@ func acquireSudog() *sudog { gothrow("acquireSudog: found s.elem != nil in cache") } c.sudogcache = s.next + s.next = nil return s } @@ -177,6 +178,15 @@ func releaseSudog(s *sudog) { if s.selectdone != nil { gothrow("runtime: sudog with non-nil selectdone") } + if s.next != nil { + gothrow("runtime: sudog with non-nil next") + } + if s.prev != nil { + gothrow("runtime: sudog with non-nil prev") + } + if s.waitlink != nil { + gothrow("runtime: sudog with non-nil waitlink") + } gp := getg() if gp.param != nil { gothrow("runtime: releaseSudog with non-nil gp.param") diff --git a/src/runtime/select.go b/src/runtime/select.go index efe68c1f5c..f735a71e2f 100644 --- a/src/runtime/select.go +++ b/src/runtime/select.go @@ -404,6 +404,7 @@ loop: } } sgnext = sglist.waitlink + sglist.waitlink = nil releaseSudog(sglist) sglist = sgnext } @@ -641,6 +642,7 @@ func (q *waitq) dequeueSudoG(s *sudog) { if q.last == sgp { q.last = prevsgp } + s.next = nil return } l = &sgp.next diff --git a/src/runtime/sema.go b/src/runtime/sema.go index d2a028c01b..26dbd30ea3 100644 --- a/src/runtime/sema.go +++ b/src/runtime/sema.go @@ -201,6 +201,7 @@ func syncsemacquire(s *syncSema) { } unlock(&s.lock) if wake != nil { + wake.next = nil goready(wake.g) } } else { @@ -242,6 +243,7 @@ func syncsemrelease(s *syncSema, n uint32) { if wake.releasetime != 0 { wake.releasetime = cputicks() } + wake.next = nil goready(wake.g) n-- } diff --git a/test/fixedbugs/issue9110.go b/test/fixedbugs/issue9110.go new file mode 100644 index 0000000000..729463305e --- /dev/null +++ b/test/fixedbugs/issue9110.go @@ -0,0 +1,90 @@ +// run + +// Copyright 2014 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. + +// Scenario that used to leak arbitrarily many SudoG structs. +// See golang.org/issue/9110. + +package main + +import ( + "runtime" + "runtime/debug" + "sync" + "time" +) + +func main() { + debug.SetGCPercent(1000000) // only GC when we ask for GC + + var stats, stats1, stats2 runtime.MemStats + + release := func() {} + for i := 0; i < 20; i++ { + if i == 10 { + // Should be warmed up by now. + runtime.ReadMemStats(&stats1) + } + + c := make(chan int) + for i := 0; i < 10; i++ { + go func() { + select { + case <-c: + case <-c: + case <-c: + } + }() + } + time.Sleep(1 * time.Millisecond) + release() + + close(c) // let select put its sudog's into the cache + time.Sleep(1 * time.Millisecond) + + // pick up top sudog + var cond1 sync.Cond + var mu1 sync.Mutex + cond1.L = &mu1 + go func() { + mu1.Lock() + cond1.Wait() + mu1.Unlock() + }() + time.Sleep(1 * time.Millisecond) + + // pick up next sudog + var cond2 sync.Cond + var mu2 sync.Mutex + cond2.L = &mu2 + go func() { + mu2.Lock() + cond2.Wait() + mu2.Unlock() + }() + time.Sleep(1 * time.Millisecond) + + // put top sudog back + cond1.Broadcast() + time.Sleep(1 * time.Millisecond) + + // drop cache on floor + runtime.GC() + + // release cond2 after select has gotten to run + release = func() { + cond2.Broadcast() + time.Sleep(1 * time.Millisecond) + } + } + + runtime.GC() + + runtime.ReadMemStats(&stats2) + + if int(stats2.HeapObjects)-int(stats1.HeapObjects) > 20 { // normally at most 1 or 2; was 300 with leak + print("BUG: object leak: ", stats.HeapObjects, " -> ", stats1.HeapObjects, " -> ", stats2.HeapObjects, "\n") + } +} From 7aa89ea79835cfb3d144407b3721761a9640ce13 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Sun, 16 Nov 2014 22:55:07 +0100 Subject: [PATCH 21/68] [dev.cc] cmd/8g: work around "out of fixed registers" on Plan 9 This change works around the "out of fixed registers" issue with the Plan 9 C compiler on 386, introduced by the Bits change to uint64 in CL 169060043. The purpose of this CL is to be able to properly follow the conversion of the Plan 9 runtime to Go on the Plan 9 builders. This CL could be reverted once the Go compilers will be converted to Go. Thanks to Nick Owens for investigating this issue. LGTM=rsc R=rsc CC=austin, golang-codereviews, mischief https://golang.org/cl/177860043 --- src/cmd/8g/reg.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c index 79d60bed55..aa39dbd43f 100644 --- a/src/cmd/8g/reg.c +++ b/src/cmd/8g/reg.c @@ -926,7 +926,7 @@ paint1(Reg *r, int bn) Reg *r1; Prog *p; int z; - uint64 bb; + uint64 bb, rbz; z = bn/64; bb = 1LL<<(bn%64); @@ -945,7 +945,8 @@ paint1(Reg *r, int bn) r = r1; } - if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) { + rbz = ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])); + if(LOAD(r) & rbz & bb) { change -= CLOAD * r->f.loop; } for(;;) { @@ -1053,7 +1054,7 @@ paint3(Reg *r, int bn, uint32 rb, int rn) Reg *r1; Prog *p; int z; - uint64 bb; + uint64 bb, rbz; z = bn/64; bb = 1LL << (bn%64); @@ -1072,7 +1073,8 @@ paint3(Reg *r, int bn, uint32 rb, int rn) r = r1; } - if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) + rbz = ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])); + if(LOAD(r) & rbz & bb) addmove(r, bn, rn, 0); for(;;) { r->act.b[z] |= bb; From 7001fad55bdb27aed039ceead10fd54dc4b248aa Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Mon, 17 Nov 2014 11:20:53 +1100 Subject: [PATCH 22/68] tag go1.4rc1 LGTM=dsymonds R=rsc, dsymonds CC=golang-codereviews https://golang.org/cl/175840043 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index edd2163f70..78252b15cc 100644 --- a/.hgtags +++ b/.hgtags @@ -136,3 +136,4 @@ f8b50ad4cac4d4c4ecf48324b4f512f65e82cc1c go1.3beta1 f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 go1.3.3 f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 release 1fdfd7dfaedb1b7702141617e621ab7328a236a1 go1.4beta1 +122dcdd033354e3208878c428783906ca7588964 go1.4rc1 From f07ea227eec5fb99d8b6b22ac099692474126831 Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Mon, 17 Nov 2014 11:27:53 +1100 Subject: [PATCH 23/68] misc/makerelease: use release-branch.go1.4 for tools and tour TBR=rsc R=rsc CC=golang-codereviews https://golang.org/cl/175870043 --- misc/makerelease/makerelease.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/misc/makerelease/makerelease.go b/misc/makerelease/makerelease.go index e94efdbcee..8cf6be2a43 100644 --- a/misc/makerelease/makerelease.go +++ b/misc/makerelease/makerelease.go @@ -56,8 +56,8 @@ const ( blogPath = "golang.org/x/blog" toolPath = "golang.org/x/tools" tourPath = "code.google.com/p/go-tour" - defaultToolTag = "release-branch.go1.3" - defaultTourTag = "release-branch.go1.3" + defaultToolTag = "release-branch.go1.4" + defaultTourTag = "release-branch.go1.4" ) // Import paths for tool commands. From 3e7d4f11c054507198fc796a461b6e88f5c8e57d Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Sun, 16 Nov 2014 20:52:45 -0500 Subject: [PATCH 24/68] debug/goobj: move to cmd/internal/goobj debug/goobj is not ready to be published but it is needed for the various binary-reading commands. Move to cmd/internal/goobj. (The Go 1.3 release branch deleted it, but that's not an option anymore due to the command dependencies. The API is still not vetted nor terribly well designed.) LGTM=adg, dsymonds R=adg, dsymonds CC=golang-codereviews https://golang.org/cl/174250043 --- src/{debug => cmd/internal}/goobj/read.go | 0 src/{debug => cmd/internal}/goobj/read_test.go | 0 src/cmd/internal/objfile/goobj.go | 2 +- src/cmd/link/auto.go | 2 +- src/cmd/link/auto_test.go | 2 +- src/cmd/link/dead.go | 2 +- src/cmd/link/dead_test.go | 2 +- src/cmd/link/layout.go | 2 +- src/cmd/link/link_test.go | 2 +- src/cmd/link/pclntab.go | 2 +- src/cmd/link/pclntab_test.go | 2 +- src/cmd/link/prog.go | 2 +- src/cmd/link/runtime.go | 2 +- src/cmd/link/scan.go | 4 ++-- 14 files changed, 13 insertions(+), 13 deletions(-) rename src/{debug => cmd/internal}/goobj/read.go (100%) rename src/{debug => cmd/internal}/goobj/read_test.go (100%) diff --git a/src/debug/goobj/read.go b/src/cmd/internal/goobj/read.go similarity index 100% rename from src/debug/goobj/read.go rename to src/cmd/internal/goobj/read.go diff --git a/src/debug/goobj/read_test.go b/src/cmd/internal/goobj/read_test.go similarity index 100% rename from src/debug/goobj/read_test.go rename to src/cmd/internal/goobj/read_test.go diff --git a/src/cmd/internal/objfile/goobj.go b/src/cmd/internal/objfile/goobj.go index a1d773023d..6b1607a172 100644 --- a/src/cmd/internal/objfile/goobj.go +++ b/src/cmd/internal/objfile/goobj.go @@ -7,7 +7,7 @@ package objfile import ( - "debug/goobj" + "cmd/internal/goobj" "fmt" "os" ) diff --git a/src/cmd/link/auto.go b/src/cmd/link/auto.go index f9228e8cab..21f6d60827 100644 --- a/src/cmd/link/auto.go +++ b/src/cmd/link/auto.go @@ -10,7 +10,7 @@ package main import ( - "debug/goobj" + "cmd/internal/goobj" "strconv" "strings" ) diff --git a/src/cmd/link/auto_test.go b/src/cmd/link/auto_test.go index 27f8e2b96d..f99e097a9c 100644 --- a/src/cmd/link/auto_test.go +++ b/src/cmd/link/auto_test.go @@ -13,7 +13,7 @@ package main import ( "bytes" - "debug/goobj" + "cmd/internal/goobj" "testing" ) diff --git a/src/cmd/link/dead.go b/src/cmd/link/dead.go index e1e775eb3b..ee23a61f81 100644 --- a/src/cmd/link/dead.go +++ b/src/cmd/link/dead.go @@ -6,7 +6,7 @@ package main -import "debug/goobj" +import "cmd/internal/goobj" // dead removes unreachable code and data from the program. // It is basically a mark-sweep garbage collection: traverse all the diff --git a/src/cmd/link/dead_test.go b/src/cmd/link/dead_test.go index 2e179b453b..eb34d0580d 100644 --- a/src/cmd/link/dead_test.go +++ b/src/cmd/link/dead_test.go @@ -5,7 +5,7 @@ package main import ( - "debug/goobj" + "cmd/internal/goobj" "reflect" "strings" "testing" diff --git a/src/cmd/link/layout.go b/src/cmd/link/layout.go index 149ebced0f..d5c291e255 100644 --- a/src/cmd/link/layout.go +++ b/src/cmd/link/layout.go @@ -7,7 +7,7 @@ package main import ( - "debug/goobj" + "cmd/internal/goobj" ) // A layoutSection describes a single section to add to the diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go index 984796784e..b5ae15fc71 100644 --- a/src/cmd/link/link_test.go +++ b/src/cmd/link/link_test.go @@ -6,7 +6,7 @@ package main import ( "bytes" - "debug/goobj" + "cmd/internal/goobj" "io/ioutil" "testing" ) diff --git a/src/cmd/link/pclntab.go b/src/cmd/link/pclntab.go index 232d586bf2..2d131781f2 100644 --- a/src/cmd/link/pclntab.go +++ b/src/cmd/link/pclntab.go @@ -7,7 +7,7 @@ package main import ( - "debug/goobj" + "cmd/internal/goobj" "encoding/binary" "os" "sort" diff --git a/src/cmd/link/pclntab_test.go b/src/cmd/link/pclntab_test.go index 19953f5797..ea80806742 100644 --- a/src/cmd/link/pclntab_test.go +++ b/src/cmd/link/pclntab_test.go @@ -6,7 +6,7 @@ package main import ( "bytes" - "debug/goobj" + "cmd/internal/goobj" "fmt" "math/rand" "sort" diff --git a/src/cmd/link/prog.go b/src/cmd/link/prog.go index a52b5ff9b2..77fb1ece5b 100644 --- a/src/cmd/link/prog.go +++ b/src/cmd/link/prog.go @@ -5,7 +5,7 @@ package main import ( - "debug/goobj" + "cmd/internal/goobj" "encoding/binary" "fmt" "go/build" diff --git a/src/cmd/link/runtime.go b/src/cmd/link/runtime.go index b0c1ac98a6..acda2d24d6 100644 --- a/src/cmd/link/runtime.go +++ b/src/cmd/link/runtime.go @@ -7,7 +7,7 @@ package main -import "debug/goobj" +import "cmd/internal/goobj" func (p *Prog) runtime() { p.pclntab() diff --git a/src/cmd/link/scan.go b/src/cmd/link/scan.go index 0720e039b8..7feb0d8900 100644 --- a/src/cmd/link/scan.go +++ b/src/cmd/link/scan.go @@ -11,7 +11,7 @@ package main import ( - "debug/goobj" + "cmd/internal/goobj" "os" "sort" "strings" @@ -69,7 +69,7 @@ func (p *Prog) scanFile(pkgpath string, file string) { return } - // TODO(rsc): Change debug/goobj to record package name as gp.Name. + // TODO(rsc): Change cmd/internal/goobj to record package name as gp.Name. // TODO(rsc): If pkgpath == "main", check that gp.Name == "main". pkg.Package = gp From bc949b5c20d09510dba954b67d15ff04fa97b1a8 Mon Sep 17 00:00:00 2001 From: David Symonds Date: Mon, 17 Nov 2014 14:04:43 +1100 Subject: [PATCH 25/68] misc/nacl: exclude cmd/link from the test zip. It does not appear to be necessary, and cmd/link does not appear in release branches. LGTM=rsc R=adg, rsc CC=golang-codereviews https://golang.org/cl/176900044 --- misc/nacl/testzip.proto | 3 --- 1 file changed, 3 deletions(-) diff --git a/misc/nacl/testzip.proto b/misc/nacl/testzip.proto index fd0c6a035b..07d4a1db02 100644 --- a/misc/nacl/testzip.proto +++ b/misc/nacl/testzip.proto @@ -18,9 +18,6 @@ go src=.. gofmt_test.go testdata + - link - testdata - + archive tar testdata From 44ab8d95d36819c9115388153deff3ef224c0691 Mon Sep 17 00:00:00 2001 From: David Symonds Date: Mon, 17 Nov 2014 14:21:29 +1100 Subject: [PATCH 26/68] undo CL 176900044 / 561398621ba7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Turns out it *is* needed because the cmd/link tests expect to find their own files. ««« original CL description misc/nacl: exclude cmd/link from the test zip. It does not appear to be necessary, and cmd/link does not appear in release branches. LGTM=rsc R=adg, rsc CC=golang-codereviews https://golang.org/cl/176900044 »»» TBR=rsc R=adg, rsc CC=golang-codereviews https://golang.org/cl/175870045 --- misc/nacl/testzip.proto | 3 +++ 1 file changed, 3 insertions(+) diff --git a/misc/nacl/testzip.proto b/misc/nacl/testzip.proto index 07d4a1db02..fd0c6a035b 100644 --- a/misc/nacl/testzip.proto +++ b/misc/nacl/testzip.proto @@ -18,6 +18,9 @@ go src=.. gofmt_test.go testdata + + link + testdata + + archive tar testdata From b30d2a856ad7805a35b1642a553effef545c8879 Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Mon, 17 Nov 2014 14:41:18 +1100 Subject: [PATCH 27/68] bump go1.4rc1 tag Now that the build and builders are fixed, we're good to go. LGTM=dsymonds R=rsc, dsymonds CC=golang-codereviews https://golang.org/cl/177900043 --- .hgtags | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.hgtags b/.hgtags index 78252b15cc..9867bc339f 100644 --- a/.hgtags +++ b/.hgtags @@ -136,4 +136,4 @@ f8b50ad4cac4d4c4ecf48324b4f512f65e82cc1c go1.3beta1 f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 go1.3.3 f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 release 1fdfd7dfaedb1b7702141617e621ab7328a236a1 go1.4beta1 -122dcdd033354e3208878c428783906ca7588964 go1.4rc1 +bffdd0cae380ce1ccf3e98ed6b6cd53fece7ba72 go1.4rc1 From fc288681cf5ac27bb3478cadf8a3e60f4b654082 Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Mon, 17 Nov 2014 17:18:21 +1100 Subject: [PATCH 28/68] [dev.cc] runtime: replace deleted netpollfd function LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/169710043 --- src/runtime/netpoll_windows.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/netpoll_windows.go b/src/runtime/netpoll_windows.go index 88e8781376..8a15f182cd 100644 --- a/src/runtime/netpoll_windows.go +++ b/src/runtime/netpoll_windows.go @@ -108,7 +108,7 @@ retry: op = entries[i].op errno = 0 qty = 0 - if stdcall5(_WSAGetOverlappedResult, netpollfd(op.pd), uintptr(unsafe.Pointer(op)), uintptr(unsafe.Pointer(&qty)), 0, uintptr(unsafe.Pointer(&flags))) == 0 { + if stdcall5(_WSAGetOverlappedResult, op.pd.fd, uintptr(unsafe.Pointer(op)), uintptr(unsafe.Pointer(&qty)), 0, uintptr(unsafe.Pointer(&flags))) == 0 { errno = int32(getlasterror()) } handlecompletion(&gp, op, errno, qty) From 38fef031e16f819a3f1f6e14e3e7d70ac4ccfebb Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Mon, 17 Nov 2014 14:44:41 -0500 Subject: [PATCH 29/68] cmd/pprof: fix EOF handling when getting function source getFunctionSource gathers five lines of "margin" around every requested sample line. However, if this margin went past the end of the source file, getFunctionSource would encounter an io.EOF error and abort with this error, resulting in listings like (pprof) list main.main ROUTINE ======================== main.main in ... 0 8.33s (flat, cum) 99.17% of Total Error: EOF (pprof) Modify the error handling in getFunctionSource so io.EOF is always considered non-fatal. If it reaches EOF, it simply returns the lines it has. LGTM=bradfitz R=rsc, bradfitz CC=golang-codereviews https://golang.org/cl/172600043 --- src/cmd/pprof/internal/report/source.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cmd/pprof/internal/report/source.go b/src/cmd/pprof/internal/report/source.go index 57300dd91a..73ae1b4ea2 100644 --- a/src/cmd/pprof/internal/report/source.go +++ b/src/cmd/pprof/internal/report/source.go @@ -358,9 +358,13 @@ func getFunctionSource(fun, file string, fns nodes, start, end int) (nodes, stri for { line, err := buf.ReadString('\n') if err != nil { - if line == "" || err != io.EOF { + if err != io.EOF { return nil, file, err } + if line == "" { + // end was at or past EOF; that's okay + break + } } if lineno >= start { flat, cum := sumNodes(lineNodes[lineno]) From 2c2a6df4e9bfc5fc81a05cac8298a61049be5b07 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Mon, 17 Nov 2014 20:46:42 +0100 Subject: [PATCH 30/68] [dev.cc] cmd/gc: fix warning on Plan 9 warning: src/cmd/gc/walk.c:1769 set and not used: on LGTM=rsc R=rsc, minux CC=golang-codereviews https://golang.org/cl/175850043 --- src/cmd/gc/walk.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index d4d0f449c3..77f9c80f91 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -1766,7 +1766,6 @@ walkprint(Node *nn, NodeList **init) int notfirst, et, op; NodeList *calls; - on = nil; op = nn->op; all = nn->list; calls = nil; From 55f19ed866d55ebfdbed59893ff93fb00a7c35fe Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Tue, 18 Nov 2014 09:55:15 +1100 Subject: [PATCH 31/68] runtime: fix getcallersp documentation LGTM=bradfitz R=rsc, bradfitz CC=golang-codereviews https://golang.org/cl/180760043 --- src/runtime/stubs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index fe8f9c9222..1282397adb 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -231,7 +231,7 @@ func setcallerpc(argp unsafe.Pointer, pc uintptr) // // func f(arg1, arg2, arg3 int) { // pc := getcallerpc(unsafe.Pointer(&arg1)) -// sp := getcallerpc(unsafe.Pointer(&arg2)) +// sp := getcallersp(unsafe.Pointer(&arg1)) // } // // These two lines find the PC and SP immediately following From f03f0cba2ba03d5e0ddb88c7b1f98d7bbbabb9ce Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Tue, 18 Nov 2014 13:32:00 +1100 Subject: [PATCH 32/68] doc/go1.4.html: rewrite first sentence to make it clearer The grammar was atrocious, probably the victim of an editing error. LGTM=bradfitz R=bradfitz CC=golang-codereviews https://golang.org/cl/178910043 --- doc/go1.4.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/go1.4.html b/doc/go1.4.html index d96440708d..883352e34f 100644 --- a/doc/go1.4.html +++ b/doc/go1.4.html @@ -7,10 +7,10 @@

      Introduction to Go 1.4

      -The latest Go release, version 1.4, arrives as scheduled six months after 1.3 -and contains only one tiny language change, -a possibly breaking change to the compiler, -a backwards-compatible simple form of for-range loop. +The latest Go release, version 1.4, arrives as scheduled six months after 1.3. +It contains only one tiny language change, +in the form of a backwards-compatible simple variant of for-range loop, +and a possibly breaking change to the compiler involving methods on pointers-to-pointers. The release focuses primarily on implementation work, improving the garbage collector and preparing the ground for a fully concurrent collector to be rolled out in the next few releases. @@ -20,7 +20,7 @@ this release therefore eliminates the notorious "hot stack split" problem. There are some new tools available including support in the go command for build-time source code generation. The release also adds support for ARM processors on Android and Native Client (NaCl) -and AMD64 on Plan 9. +and for AMD64 on Plan 9. As always, Go 1.4 keeps the promise of compatibility, and almost everything From 0e8fed098c164a832fbe9541a6d3c7bb952c9b0c Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 18 Nov 2014 09:54:50 -0500 Subject: [PATCH 33/68] [dev.cc] runtime: two missed references to "M stack" LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/177940043 --- src/runtime/asm_amd64p32.s | 2 +- src/runtime/panic.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/asm_amd64p32.s b/src/runtime/asm_amd64p32.s index cead3cd075..b8370efd36 100644 --- a/src/runtime/asm_amd64p32.s +++ b/src/runtime/asm_amd64p32.s @@ -169,7 +169,7 @@ TEXT runtime·mcall(SB), NOSPLIT, $0-4 // of the G stack. We need to distinguish the routine that // lives at the bottom of the G stack from the one that lives // at the top of the system stack because the one at the top of -// the M stack terminates the stack walk (see topofstack()). +// the system stack terminates the stack walk (see topofstack()). TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0 RET diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 8929467025..95e780b1d9 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -162,7 +162,7 @@ func init() { // Allocate a Defer, usually using per-P pool. // Each defer must be released with freedefer. -// Note: runs on M stack +// Note: runs on g0 stack func newdefer(siz int32) *_defer { var d *_defer sc := deferclass(uintptr(siz)) From 312a64ec4eb3e0fdb6ab6b23deb99699abc7f54e Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 18 Nov 2014 11:38:23 -0500 Subject: [PATCH 34/68] [dev.cc] runtime: convert defs_linux_power64*.h to go LGTM=austin R=austin CC=golang-codereviews https://golang.org/cl/176990043 --- src/runtime/defs_linux_power64.go | 186 +++++++++++++++++++++++++ src/runtime/defs_linux_power64.h | 204 ---------------------------- src/runtime/defs_linux_power64le.go | 186 +++++++++++++++++++++++++ src/runtime/defs_linux_power64le.h | 204 ---------------------------- 4 files changed, 372 insertions(+), 408 deletions(-) create mode 100644 src/runtime/defs_linux_power64.go delete mode 100644 src/runtime/defs_linux_power64.h create mode 100644 src/runtime/defs_linux_power64le.go delete mode 100644 src/runtime/defs_linux_power64le.h diff --git a/src/runtime/defs_linux_power64.go b/src/runtime/defs_linux_power64.go new file mode 100644 index 0000000000..df877a67f7 --- /dev/null +++ b/src/runtime/defs_linux_power64.go @@ -0,0 +1,186 @@ +// created by cgo -cdefs and then converted to Go +// cgo -cdefs defs_linux.go defs3_linux.go + +package runtime + +const ( + _EINTR = 0x4 + _EAGAIN = 0xb + _ENOMEM = 0xc + + _PROT_NONE = 0x0 + _PROT_READ = 0x1 + _PROT_WRITE = 0x2 + _PROT_EXEC = 0x4 + + _MAP_ANON = 0x20 + _MAP_PRIVATE = 0x2 + _MAP_FIXED = 0x10 + + _MADV_DONTNEED = 0x4 + + _SA_RESTART = 0x10000000 + _SA_ONSTACK = 0x8000000 + _SA_SIGINFO = 0x4 + + _SIGHUP = 0x1 + _SIGINT = 0x2 + _SIGQUIT = 0x3 + _SIGILL = 0x4 + _SIGTRAP = 0x5 + _SIGABRT = 0x6 + _SIGBUS = 0x7 + _SIGFPE = 0x8 + _SIGKILL = 0x9 + _SIGUSR1 = 0xa + _SIGSEGV = 0xb + _SIGUSR2 = 0xc + _SIGPIPE = 0xd + _SIGALRM = 0xe + _SIGSTKFLT = 0x10 + _SIGCHLD = 0x11 + _SIGCONT = 0x12 + _SIGSTOP = 0x13 + _SIGTSTP = 0x14 + _SIGTTIN = 0x15 + _SIGTTOU = 0x16 + _SIGURG = 0x17 + _SIGXCPU = 0x18 + _SIGXFSZ = 0x19 + _SIGVTALRM = 0x1a + _SIGPROF = 0x1b + _SIGWINCH = 0x1c + _SIGIO = 0x1d + _SIGPWR = 0x1e + _SIGSYS = 0x1f + + _FPE_INTDIV = 0x1 + _FPE_INTOVF = 0x2 + _FPE_FLTDIV = 0x3 + _FPE_FLTOVF = 0x4 + _FPE_FLTUND = 0x5 + _FPE_FLTRES = 0x6 + _FPE_FLTINV = 0x7 + _FPE_FLTSUB = 0x8 + + _BUS_ADRALN = 0x1 + _BUS_ADRERR = 0x2 + _BUS_OBJERR = 0x3 + + _SEGV_MAPERR = 0x1 + _SEGV_ACCERR = 0x2 + + _ITIMER_REAL = 0x0 + _ITIMER_VIRTUAL = 0x1 + _ITIMER_PROF = 0x2 + + _EPOLLIN = 0x1 + _EPOLLOUT = 0x4 + _EPOLLERR = 0x8 + _EPOLLHUP = 0x10 + _EPOLLRDHUP = 0x2000 + _EPOLLET = -0x80000000 + _EPOLL_CLOEXEC = 0x80000 + _EPOLL_CTL_ADD = 0x1 + _EPOLL_CTL_DEL = 0x2 + _EPOLL_CTL_MOD = 0x3 +) + +//struct Sigset { +// uint64 sig[1]; +//}; +//typedef uint64 Sigset; + +type timespec struct { + tv_sec int64 + tv_nsec int64 +} + +type timeval struct { + tv_sec int64 + tv_usec int64 +} + +type sigactiont struct { + sa_handler uintptr + sa_flags uint64 + sa_restorer uintptr + sa_mask uint64 +} + +type siginfo struct { + si_signo int32 + si_errno int32 + si_code int32 + pad_cgo_0 [4]byte + _sifields [112]byte +} + +type itimerval struct { + it_interval timeval + it_value timeval +} + +type epollevent struct { + events uint32 + pad_cgo_0 [4]byte + data [8]byte // unaligned uintptr +} + +// created by cgo -cdefs and then converted to Go +// cgo -cdefs defs_linux.go defs3_linux.go + +const ( + _O_RDONLY = 0x0 + _O_CLOEXEC = 0x80000 + _SA_RESTORER = 0 +) + +type ptregs struct { + gpr [32]uint64 + nip uint64 + msr uint64 + orig_gpr3 uint64 + ctr uint64 + link uint64 + xer uint64 + ccr uint64 + softe uint64 + trap uint64 + dar uint64 + dsisr uint64 + result uint64 +} + +type vreg struct { + u [4]uint32 +} + +type sigaltstackt struct { + ss_sp *byte + ss_flags int32 + pad_cgo_0 [4]byte + ss_size uint64 +} + +type sigcontext struct { + _unused [4]uint64 + signal int32 + _pad0 int32 + handler uint64 + oldmask uint64 + regs *ptregs + gp_regs [48]uint64 + fp_regs [33]float64 + v_regs *vreg + vmx_reserve [101]int64 +} + +type ucontext struct { + uc_flags uint64 + uc_link *ucontext + uc_stack sigaltstackt + uc_sigmask uint64 + __unused [15]uint64 + uc_mcontext sigcontext +} diff --git a/src/runtime/defs_linux_power64.h b/src/runtime/defs_linux_power64.h deleted file mode 100644 index 93742fa346..0000000000 --- a/src/runtime/defs_linux_power64.h +++ /dev/null @@ -1,204 +0,0 @@ -// Created by cgo -cdefs - DO NOT EDIT -// cgo -cdefs defs_linux.go defs3_linux.go - - -enum { - EINTR = 0x4, - EAGAIN = 0xb, - ENOMEM = 0xc, - - PROT_NONE = 0x0, - PROT_READ = 0x1, - PROT_WRITE = 0x2, - PROT_EXEC = 0x4, - - MAP_ANON = 0x20, - MAP_PRIVATE = 0x2, - MAP_FIXED = 0x10, - - MADV_DONTNEED = 0x4, - - SA_RESTART = 0x10000000, - SA_ONSTACK = 0x8000000, - SA_SIGINFO = 0x4, - - SIGHUP = 0x1, - SIGINT = 0x2, - SIGQUIT = 0x3, - SIGILL = 0x4, - SIGTRAP = 0x5, - SIGABRT = 0x6, - SIGBUS = 0x7, - SIGFPE = 0x8, - SIGKILL = 0x9, - SIGUSR1 = 0xa, - SIGSEGV = 0xb, - SIGUSR2 = 0xc, - SIGPIPE = 0xd, - SIGALRM = 0xe, - SIGSTKFLT = 0x10, - SIGCHLD = 0x11, - SIGCONT = 0x12, - SIGSTOP = 0x13, - SIGTSTP = 0x14, - SIGTTIN = 0x15, - SIGTTOU = 0x16, - SIGURG = 0x17, - SIGXCPU = 0x18, - SIGXFSZ = 0x19, - SIGVTALRM = 0x1a, - SIGPROF = 0x1b, - SIGWINCH = 0x1c, - SIGIO = 0x1d, - SIGPWR = 0x1e, - SIGSYS = 0x1f, - - FPE_INTDIV = 0x1, - FPE_INTOVF = 0x2, - FPE_FLTDIV = 0x3, - FPE_FLTOVF = 0x4, - FPE_FLTUND = 0x5, - FPE_FLTRES = 0x6, - FPE_FLTINV = 0x7, - FPE_FLTSUB = 0x8, - - BUS_ADRALN = 0x1, - BUS_ADRERR = 0x2, - BUS_OBJERR = 0x3, - - SEGV_MAPERR = 0x1, - SEGV_ACCERR = 0x2, - - ITIMER_REAL = 0x0, - ITIMER_VIRTUAL = 0x1, - ITIMER_PROF = 0x2, - - EPOLLIN = 0x1, - EPOLLOUT = 0x4, - EPOLLERR = 0x8, - EPOLLHUP = 0x10, - EPOLLRDHUP = 0x2000, - EPOLLET = -0x80000000, - EPOLL_CLOEXEC = 0x80000, - EPOLL_CTL_ADD = 0x1, - EPOLL_CTL_DEL = 0x2, - EPOLL_CTL_MOD = 0x3, -}; - -typedef struct Sigset Sigset; -typedef struct Timespec Timespec; -typedef struct Timeval Timeval; -typedef struct SigactionT SigactionT; -typedef struct Siginfo Siginfo; -typedef struct Itimerval Itimerval; -typedef struct EpollEvent EpollEvent; - -#pragma pack on - -//struct Sigset { -// uint64 sig[1]; -//}; -//typedef uint64 Sigset; - -struct Timespec { - int64 tv_sec; - int64 tv_nsec; -}; -struct Timeval { - int64 tv_sec; - int64 tv_usec; -}; -struct SigactionT { - void *sa_handler; - uint64 sa_flags; - void *sa_restorer; - uint64 sa_mask; -}; -struct Siginfo { - int32 si_signo; - int32 si_errno; - int32 si_code; - byte Pad_cgo_0[4]; - byte _sifields[112]; -}; -struct Itimerval { - Timeval it_interval; - Timeval it_value; -}; -struct EpollEvent { - uint32 events; - byte Pad_cgo_0[4]; - byte data[8]; // unaligned uintptr -}; - - -#pragma pack off -// Created by cgo -cdefs - DO NOT EDIT -// cgo -cdefs defs_linux.go defs3_linux.go - - -enum { - O_RDONLY = 0x0, - O_CLOEXEC = 0x80000, - SA_RESTORER = 0, -}; - -typedef struct Ptregs Ptregs; -typedef struct Vreg Vreg; -typedef struct SigaltstackT SigaltstackT; -typedef struct Sigcontext Sigcontext; -typedef struct Ucontext Ucontext; - -#pragma pack on - -struct Ptregs { - uint64 gpr[32]; - uint64 nip; - uint64 msr; - uint64 orig_gpr3; - uint64 ctr; - uint64 link; - uint64 xer; - uint64 ccr; - uint64 softe; - uint64 trap; - uint64 dar; - uint64 dsisr; - uint64 result; -}; -typedef uint64 Gregset[48]; -typedef float64 FPregset[33]; -struct Vreg { - uint32 u[4]; -}; - -struct SigaltstackT { - byte *ss_sp; - int32 ss_flags; - byte Pad_cgo_0[4]; - uint64 ss_size; -}; - -struct Sigcontext { - uint64 _unused[4]; - int32 signal; - int32 _pad0; - uint64 handler; - uint64 oldmask; - Ptregs *regs; - uint64 gp_regs[48]; - float64 fp_regs[33]; - Vreg *v_regs; - int64 vmx_reserve[101]; -}; -struct Ucontext { - uint64 uc_flags; - Ucontext *uc_link; - SigaltstackT uc_stack; - uint64 uc_sigmask; - uint64 __unused[15]; - Sigcontext uc_mcontext; -}; - - -#pragma pack off diff --git a/src/runtime/defs_linux_power64le.go b/src/runtime/defs_linux_power64le.go new file mode 100644 index 0000000000..df877a67f7 --- /dev/null +++ b/src/runtime/defs_linux_power64le.go @@ -0,0 +1,186 @@ +// created by cgo -cdefs and then converted to Go +// cgo -cdefs defs_linux.go defs3_linux.go + +package runtime + +const ( + _EINTR = 0x4 + _EAGAIN = 0xb + _ENOMEM = 0xc + + _PROT_NONE = 0x0 + _PROT_READ = 0x1 + _PROT_WRITE = 0x2 + _PROT_EXEC = 0x4 + + _MAP_ANON = 0x20 + _MAP_PRIVATE = 0x2 + _MAP_FIXED = 0x10 + + _MADV_DONTNEED = 0x4 + + _SA_RESTART = 0x10000000 + _SA_ONSTACK = 0x8000000 + _SA_SIGINFO = 0x4 + + _SIGHUP = 0x1 + _SIGINT = 0x2 + _SIGQUIT = 0x3 + _SIGILL = 0x4 + _SIGTRAP = 0x5 + _SIGABRT = 0x6 + _SIGBUS = 0x7 + _SIGFPE = 0x8 + _SIGKILL = 0x9 + _SIGUSR1 = 0xa + _SIGSEGV = 0xb + _SIGUSR2 = 0xc + _SIGPIPE = 0xd + _SIGALRM = 0xe + _SIGSTKFLT = 0x10 + _SIGCHLD = 0x11 + _SIGCONT = 0x12 + _SIGSTOP = 0x13 + _SIGTSTP = 0x14 + _SIGTTIN = 0x15 + _SIGTTOU = 0x16 + _SIGURG = 0x17 + _SIGXCPU = 0x18 + _SIGXFSZ = 0x19 + _SIGVTALRM = 0x1a + _SIGPROF = 0x1b + _SIGWINCH = 0x1c + _SIGIO = 0x1d + _SIGPWR = 0x1e + _SIGSYS = 0x1f + + _FPE_INTDIV = 0x1 + _FPE_INTOVF = 0x2 + _FPE_FLTDIV = 0x3 + _FPE_FLTOVF = 0x4 + _FPE_FLTUND = 0x5 + _FPE_FLTRES = 0x6 + _FPE_FLTINV = 0x7 + _FPE_FLTSUB = 0x8 + + _BUS_ADRALN = 0x1 + _BUS_ADRERR = 0x2 + _BUS_OBJERR = 0x3 + + _SEGV_MAPERR = 0x1 + _SEGV_ACCERR = 0x2 + + _ITIMER_REAL = 0x0 + _ITIMER_VIRTUAL = 0x1 + _ITIMER_PROF = 0x2 + + _EPOLLIN = 0x1 + _EPOLLOUT = 0x4 + _EPOLLERR = 0x8 + _EPOLLHUP = 0x10 + _EPOLLRDHUP = 0x2000 + _EPOLLET = -0x80000000 + _EPOLL_CLOEXEC = 0x80000 + _EPOLL_CTL_ADD = 0x1 + _EPOLL_CTL_DEL = 0x2 + _EPOLL_CTL_MOD = 0x3 +) + +//struct Sigset { +// uint64 sig[1]; +//}; +//typedef uint64 Sigset; + +type timespec struct { + tv_sec int64 + tv_nsec int64 +} + +type timeval struct { + tv_sec int64 + tv_usec int64 +} + +type sigactiont struct { + sa_handler uintptr + sa_flags uint64 + sa_restorer uintptr + sa_mask uint64 +} + +type siginfo struct { + si_signo int32 + si_errno int32 + si_code int32 + pad_cgo_0 [4]byte + _sifields [112]byte +} + +type itimerval struct { + it_interval timeval + it_value timeval +} + +type epollevent struct { + events uint32 + pad_cgo_0 [4]byte + data [8]byte // unaligned uintptr +} + +// created by cgo -cdefs and then converted to Go +// cgo -cdefs defs_linux.go defs3_linux.go + +const ( + _O_RDONLY = 0x0 + _O_CLOEXEC = 0x80000 + _SA_RESTORER = 0 +) + +type ptregs struct { + gpr [32]uint64 + nip uint64 + msr uint64 + orig_gpr3 uint64 + ctr uint64 + link uint64 + xer uint64 + ccr uint64 + softe uint64 + trap uint64 + dar uint64 + dsisr uint64 + result uint64 +} + +type vreg struct { + u [4]uint32 +} + +type sigaltstackt struct { + ss_sp *byte + ss_flags int32 + pad_cgo_0 [4]byte + ss_size uint64 +} + +type sigcontext struct { + _unused [4]uint64 + signal int32 + _pad0 int32 + handler uint64 + oldmask uint64 + regs *ptregs + gp_regs [48]uint64 + fp_regs [33]float64 + v_regs *vreg + vmx_reserve [101]int64 +} + +type ucontext struct { + uc_flags uint64 + uc_link *ucontext + uc_stack sigaltstackt + uc_sigmask uint64 + __unused [15]uint64 + uc_mcontext sigcontext +} diff --git a/src/runtime/defs_linux_power64le.h b/src/runtime/defs_linux_power64le.h deleted file mode 100644 index 93742fa346..0000000000 --- a/src/runtime/defs_linux_power64le.h +++ /dev/null @@ -1,204 +0,0 @@ -// Created by cgo -cdefs - DO NOT EDIT -// cgo -cdefs defs_linux.go defs3_linux.go - - -enum { - EINTR = 0x4, - EAGAIN = 0xb, - ENOMEM = 0xc, - - PROT_NONE = 0x0, - PROT_READ = 0x1, - PROT_WRITE = 0x2, - PROT_EXEC = 0x4, - - MAP_ANON = 0x20, - MAP_PRIVATE = 0x2, - MAP_FIXED = 0x10, - - MADV_DONTNEED = 0x4, - - SA_RESTART = 0x10000000, - SA_ONSTACK = 0x8000000, - SA_SIGINFO = 0x4, - - SIGHUP = 0x1, - SIGINT = 0x2, - SIGQUIT = 0x3, - SIGILL = 0x4, - SIGTRAP = 0x5, - SIGABRT = 0x6, - SIGBUS = 0x7, - SIGFPE = 0x8, - SIGKILL = 0x9, - SIGUSR1 = 0xa, - SIGSEGV = 0xb, - SIGUSR2 = 0xc, - SIGPIPE = 0xd, - SIGALRM = 0xe, - SIGSTKFLT = 0x10, - SIGCHLD = 0x11, - SIGCONT = 0x12, - SIGSTOP = 0x13, - SIGTSTP = 0x14, - SIGTTIN = 0x15, - SIGTTOU = 0x16, - SIGURG = 0x17, - SIGXCPU = 0x18, - SIGXFSZ = 0x19, - SIGVTALRM = 0x1a, - SIGPROF = 0x1b, - SIGWINCH = 0x1c, - SIGIO = 0x1d, - SIGPWR = 0x1e, - SIGSYS = 0x1f, - - FPE_INTDIV = 0x1, - FPE_INTOVF = 0x2, - FPE_FLTDIV = 0x3, - FPE_FLTOVF = 0x4, - FPE_FLTUND = 0x5, - FPE_FLTRES = 0x6, - FPE_FLTINV = 0x7, - FPE_FLTSUB = 0x8, - - BUS_ADRALN = 0x1, - BUS_ADRERR = 0x2, - BUS_OBJERR = 0x3, - - SEGV_MAPERR = 0x1, - SEGV_ACCERR = 0x2, - - ITIMER_REAL = 0x0, - ITIMER_VIRTUAL = 0x1, - ITIMER_PROF = 0x2, - - EPOLLIN = 0x1, - EPOLLOUT = 0x4, - EPOLLERR = 0x8, - EPOLLHUP = 0x10, - EPOLLRDHUP = 0x2000, - EPOLLET = -0x80000000, - EPOLL_CLOEXEC = 0x80000, - EPOLL_CTL_ADD = 0x1, - EPOLL_CTL_DEL = 0x2, - EPOLL_CTL_MOD = 0x3, -}; - -typedef struct Sigset Sigset; -typedef struct Timespec Timespec; -typedef struct Timeval Timeval; -typedef struct SigactionT SigactionT; -typedef struct Siginfo Siginfo; -typedef struct Itimerval Itimerval; -typedef struct EpollEvent EpollEvent; - -#pragma pack on - -//struct Sigset { -// uint64 sig[1]; -//}; -//typedef uint64 Sigset; - -struct Timespec { - int64 tv_sec; - int64 tv_nsec; -}; -struct Timeval { - int64 tv_sec; - int64 tv_usec; -}; -struct SigactionT { - void *sa_handler; - uint64 sa_flags; - void *sa_restorer; - uint64 sa_mask; -}; -struct Siginfo { - int32 si_signo; - int32 si_errno; - int32 si_code; - byte Pad_cgo_0[4]; - byte _sifields[112]; -}; -struct Itimerval { - Timeval it_interval; - Timeval it_value; -}; -struct EpollEvent { - uint32 events; - byte Pad_cgo_0[4]; - byte data[8]; // unaligned uintptr -}; - - -#pragma pack off -// Created by cgo -cdefs - DO NOT EDIT -// cgo -cdefs defs_linux.go defs3_linux.go - - -enum { - O_RDONLY = 0x0, - O_CLOEXEC = 0x80000, - SA_RESTORER = 0, -}; - -typedef struct Ptregs Ptregs; -typedef struct Vreg Vreg; -typedef struct SigaltstackT SigaltstackT; -typedef struct Sigcontext Sigcontext; -typedef struct Ucontext Ucontext; - -#pragma pack on - -struct Ptregs { - uint64 gpr[32]; - uint64 nip; - uint64 msr; - uint64 orig_gpr3; - uint64 ctr; - uint64 link; - uint64 xer; - uint64 ccr; - uint64 softe; - uint64 trap; - uint64 dar; - uint64 dsisr; - uint64 result; -}; -typedef uint64 Gregset[48]; -typedef float64 FPregset[33]; -struct Vreg { - uint32 u[4]; -}; - -struct SigaltstackT { - byte *ss_sp; - int32 ss_flags; - byte Pad_cgo_0[4]; - uint64 ss_size; -}; - -struct Sigcontext { - uint64 _unused[4]; - int32 signal; - int32 _pad0; - uint64 handler; - uint64 oldmask; - Ptregs *regs; - uint64 gp_regs[48]; - float64 fp_regs[33]; - Vreg *v_regs; - int64 vmx_reserve[101]; -}; -struct Ucontext { - uint64 uc_flags; - Ucontext *uc_link; - SigaltstackT uc_stack; - uint64 uc_sigmask; - uint64 __unused[15]; - Sigcontext uc_mcontext; -}; - - -#pragma pack off From 0fe444d3e81d890ce496b6a260494473948b060a Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 18 Nov 2014 12:07:50 -0500 Subject: [PATCH 35/68] [dev.cc] runtime: generate GOOS- and GOARCH-specific files with go generate Eventually I'd like almost everything cmd/dist generates to be done with 'go generate' and checked in, to simplify the bootstrap process. The only thing cmd/dist really needs to do is write things like the current experiment info and the current version. This is a first step toward that. It replaces the _NaCl etc constants with generated ones goos_nacl, goos_darwin, goarch_386, and so on. LGTM=dave, austin R=austin, dave, bradfitz CC=golang-codereviews, iant, r https://golang.org/cl/174290043 --- src/cmd/dist/build.c | 7 ++- src/cmd/dist/buildruntime.c | 60 ----------------------- src/runtime/arch1_386.go | 2 +- src/runtime/arch1_amd64.go | 2 +- src/runtime/arch1_arm.go | 2 +- src/runtime/gengoos.go | 82 ++++++++++++++++++++++++++++++++ src/runtime/malloc2.go | 2 +- src/runtime/runtime2.go | 16 +++---- src/runtime/stack1.go | 2 +- src/runtime/stack2.go | 2 +- src/runtime/zgoarch_386.go | 12 +++++ src/runtime/zgoarch_amd64.go | 12 +++++ src/runtime/zgoarch_amd64p32.go | 12 +++++ src/runtime/zgoarch_arm.go | 12 +++++ src/runtime/zgoarch_power64.go | 12 +++++ src/runtime/zgoarch_power64le.go | 12 +++++ src/runtime/zgoos_android.go | 19 ++++++++ src/runtime/zgoos_darwin.go | 19 ++++++++ src/runtime/zgoos_dragonfly.go | 19 ++++++++ src/runtime/zgoos_freebsd.go | 19 ++++++++ src/runtime/zgoos_linux.go | 19 ++++++++ src/runtime/zgoos_nacl.go | 19 ++++++++ src/runtime/zgoos_netbsd.go | 19 ++++++++ src/runtime/zgoos_openbsd.go | 19 ++++++++ src/runtime/zgoos_plan9.go | 19 ++++++++ src/runtime/zgoos_solaris.go | 19 ++++++++ src/runtime/zgoos_windows.go | 19 ++++++++ 27 files changed, 379 insertions(+), 79 deletions(-) create mode 100644 src/runtime/gengoos.go create mode 100644 src/runtime/zgoarch_386.go create mode 100644 src/runtime/zgoarch_amd64.go create mode 100644 src/runtime/zgoarch_amd64p32.go create mode 100644 src/runtime/zgoarch_arm.go create mode 100644 src/runtime/zgoarch_power64.go create mode 100644 src/runtime/zgoarch_power64le.go create mode 100644 src/runtime/zgoos_android.go create mode 100644 src/runtime/zgoos_darwin.go create mode 100644 src/runtime/zgoos_dragonfly.go create mode 100644 src/runtime/zgoos_freebsd.go create mode 100644 src/runtime/zgoos_linux.go create mode 100644 src/runtime/zgoos_nacl.go create mode 100644 src/runtime/zgoos_netbsd.go create mode 100644 src/runtime/zgoos_openbsd.go create mode 100644 src/runtime/zgoos_plan9.go create mode 100644 src/runtime/zgoos_solaris.go create mode 100644 src/runtime/zgoos_windows.go diff --git a/src/cmd/dist/build.c b/src/cmd/dist/build.c index e4f307bee5..bfb3d15b82 100644 --- a/src/cmd/dist/build.c +++ b/src/cmd/dist/build.c @@ -615,8 +615,6 @@ static struct { {"anames9.c", mkanames}, {"zdefaultcc.go", mkzdefaultcc}, {"zsys_", mkzsys}, - {"zgoarch_", mkzgoarch}, - {"zgoos_", mkzgoos}, {"zversion.go", mkzversion}, {"zaexperiment.h", mkzexperiment}, @@ -1419,12 +1417,13 @@ clean(void) xremove(bpathf(&b, "%s/%s", bstr(&path), cleantab[i]+4)); } - // remove src/runtime/z* unconditionally + // remove src/runtime/z* unconditionally, + // except leave zgoos and zgoarch, now maintained with go generate. vreset(&dir); bpathf(&path, "%s/src/runtime", goroot); xreaddir(&dir, bstr(&path)); for(j=0; j -// -void -mkzgoarch(char *dir, char *file) -{ - Buf b, out; - - USED(dir); - - binit(&b); - binit(&out); - - bwritestr(&out, bprintf(&b, - "// auto generated by go tool dist\n" - "\n" - "package runtime\n" - "\n" - "const theGoarch = `%s`\n", goarch)); - - writefile(&out, file, 0); - - bfree(&b); - bfree(&out); -} - -// mkzgoos writes zgoos_$GOOS.go: -// -// package runtime -// const theGoos = -// -void -mkzgoos(char *dir, char *file) -{ - Buf b, out; - - USED(dir); - - binit(&b); - binit(&out); - - bwritestr(&out, "// auto generated by go tool dist\n\n"); - - if(streq(goos, "linux")) { - bwritestr(&out, "// +build !android\n\n"); - } - - bwritestr(&out, bprintf(&b, - "package runtime\n" - "\n" - "const theGoos = `%s`\n", goos)); - - writefile(&out, file, 0); - - bfree(&b); - bfree(&out); -} - #define MAXWINCB 2000 /* maximum number of windows callbacks allowed */ // mkzsys writes zsys_$GOOS_$GOARCH.s, diff --git a/src/runtime/arch1_386.go b/src/runtime/arch1_386.go index 7746dfbf06..a73e207edd 100644 --- a/src/runtime/arch1_386.go +++ b/src/runtime/arch1_386.go @@ -9,7 +9,7 @@ const ( _BigEndian = 0 _CacheLineSize = 64 _RuntimeGogoBytes = 64 - _PhysPageSize = _NaCl*65536 + (1-_NaCl)*4096 // 4k normally; 64k on NaCl + _PhysPageSize = goos_nacl*65536 + (1-goos_nacl)*4096 // 4k normally; 64k on NaCl _PCQuantum = 1 _Int64Align = 4 ) diff --git a/src/runtime/arch1_amd64.go b/src/runtime/arch1_amd64.go index 83c9c2dc9c..794b7f65c4 100644 --- a/src/runtime/arch1_amd64.go +++ b/src/runtime/arch1_amd64.go @@ -8,7 +8,7 @@ const ( thechar = '6' _BigEndian = 0 _CacheLineSize = 64 - _RuntimeGogoBytes = 64 + (_Plan9|_Solaris|_Windows)*16 + _RuntimeGogoBytes = 64 + (goos_plan9|goos_solaris|goos_windows)*16 _PhysPageSize = 4096 _PCQuantum = 1 _Int64Align = 8 diff --git a/src/runtime/arch1_arm.go b/src/runtime/arch1_arm.go index 5cb79fd686..6662eaeac3 100644 --- a/src/runtime/arch1_arm.go +++ b/src/runtime/arch1_arm.go @@ -9,7 +9,7 @@ const ( _BigEndian = 0 _CacheLineSize = 32 _RuntimeGogoBytes = 60 - _PhysPageSize = 65536*_NaCl + 4096*(1-_NaCl) + _PhysPageSize = 65536*goos_nacl + 4096*(1-goos_nacl) _PCQuantum = 4 _Int64Align = 4 ) diff --git a/src/runtime/gengoos.go b/src/runtime/gengoos.go new file mode 100644 index 0000000000..029575bee2 --- /dev/null +++ b/src/runtime/gengoos.go @@ -0,0 +1,82 @@ +// Copyright 2014 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. + +// +build ignore + +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "log" + "strconv" + "strings" +) + +var gooses, goarches []string + +func main() { + data, err := ioutil.ReadFile("../go/build/syslist.go") + if err != nil { + log.Fatal(err) + } + const ( + goosPrefix = `const goosList = ` + goarchPrefix = `const goarchList = ` + ) + for _, line := range strings.Split(string(data), "\n") { + if strings.HasPrefix(line, goosPrefix) { + text, err := strconv.Unquote(strings.TrimPrefix(line, goosPrefix)) + if err != nil { + log.Fatalf("parsing goosList %#q: %v", strings.TrimPrefix(line, goosPrefix), err) + } + gooses = strings.Fields(text) + } + if strings.HasPrefix(line, goarchPrefix) { + text, err := strconv.Unquote(strings.TrimPrefix(line, goarchPrefix)) + if err != nil { + log.Fatal("parsing goarchList: %v", err) + } + goarches = strings.Fields(text) + } + } + + for _, target := range gooses { + var buf bytes.Buffer + fmt.Fprintf(&buf, "// generated by gengoos.go using 'go generate'\n\n") + fmt.Fprintf(&buf, "// +build %s\n\n", target) // usually redundant, but not always; see linux vs android + fmt.Fprintf(&buf, "package runtime\n\n") + fmt.Fprintf(&buf, "const theGoos = `%s`\n\n", target) + for _, goos := range gooses { + value := 0 + if goos == target { + value = 1 + } + fmt.Fprintf(&buf, "const goos_%s = %d\n", goos, value) + } + err := ioutil.WriteFile("zgoos_"+target+".go", buf.Bytes(), 0666) + if err != nil { + log.Fatal(err) + } + } + + for _, target := range goarches { + var buf bytes.Buffer + fmt.Fprintf(&buf, "// generated by gengoos.go using 'go generate'\n\n") + fmt.Fprintf(&buf, "package runtime\n\n") + fmt.Fprintf(&buf, "const theGoarch = `%s`\n\n", target) + for _, goarch := range goarches { + value := 0 + if goarch == target { + value = 1 + } + fmt.Fprintf(&buf, "const goarch_%s = %d\n", goarch, value) + } + err := ioutil.WriteFile("zgoarch_"+target+".go", buf.Bytes(), 0666) + if err != nil { + log.Fatal(err) + } + } +} diff --git a/src/runtime/malloc2.go b/src/runtime/malloc2.go index e4bd963d30..c175c2aec7 100644 --- a/src/runtime/malloc2.go +++ b/src/runtime/malloc2.go @@ -126,7 +126,7 @@ const ( // See http://golang.org/issue/5402 and http://golang.org/issue/5236. // On other 64-bit platforms, we limit the arena to 128GB, or 37 bits. // On 32-bit, we don't bother limiting anything, so we use the full 32-bit address. - _MHeapMap_TotalBits = (_64bit*_Windows)*35 + (_64bit*(1-_Windows))*37 + (1-_64bit)*32 + _MHeapMap_TotalBits = (_64bit*goos_windows)*35 + (_64bit*(1-goos_windows))*37 + (1-_64bit)*32 _MHeapMap_Bits = _MHeapMap_TotalBits - _PageShift _MaxMem = uintptr(1<<_MHeapMap_TotalBits - 1) diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go index c999b3072d..7987a73730 100644 --- a/src/runtime/runtime2.go +++ b/src/runtime/runtime2.go @@ -45,7 +45,13 @@ const ( _Pdead ) -// XXX inserting below here +// The next line makes 'go generate' write the zgen_*.go files with +// per-OS and per-arch information, including constants +// named goos_$GOOS and goarch_$GOARCH for every +// known GOOS and GOARCH. The constant is 1 on the +// current system, 0 otherwise; multiplying by them is +// useful for defining GOOS- or GOARCH-specific constants. +//go:generate go run gengoos.go type mutex struct { // Futex-based impl treats it as uint32 key, @@ -395,14 +401,6 @@ type itab struct { fun [0]uintptr } -const ( - // TODO: Generate in cmd/dist. - _NaCl = 0 - _Windows = 0 - _Solaris = 0 - _Plan9 = 0 -) - // Lock-free stack node. type lfnode struct { next *lfnode diff --git a/src/runtime/stack1.go b/src/runtime/stack1.go index 40dfc76a6d..ad83e58951 100644 --- a/src/runtime/stack1.go +++ b/src/runtime/stack1.go @@ -775,7 +775,7 @@ func shrinkstack(gp *g) { } /* TODO - if _Windows && gp.m != nil && gp.m.libcallsp != 0 { + if goos_windows && gp.m != nil && gp.m.libcallsp != 0 { return } */ diff --git a/src/runtime/stack2.go b/src/runtime/stack2.go index c3718c205e..e50b32c784 100644 --- a/src/runtime/stack2.go +++ b/src/runtime/stack2.go @@ -59,7 +59,7 @@ const ( // to each stack below the usual guard area for OS-specific // purposes like signal handling. Used on Windows and on // Plan 9 because they do not use a separate stack. - _StackSystem = _Windows*512*ptrSize + _Plan9*512 + _StackSystem = goos_windows*512*ptrSize + goos_plan9*512 // The minimum size of stack used by Go code _StackMin = 2048 diff --git a/src/runtime/zgoarch_386.go b/src/runtime/zgoarch_386.go new file mode 100644 index 0000000000..057a746bb5 --- /dev/null +++ b/src/runtime/zgoarch_386.go @@ -0,0 +1,12 @@ +// generated by gengoos.go using 'go generate' + +package runtime + +const theGoarch = `386` + +const goarch_386 = 1 +const goarch_amd64 = 0 +const goarch_amd64p32 = 0 +const goarch_arm = 0 +const goarch_power64 = 0 +const goarch_power64le = 0 diff --git a/src/runtime/zgoarch_amd64.go b/src/runtime/zgoarch_amd64.go new file mode 100644 index 0000000000..a712407269 --- /dev/null +++ b/src/runtime/zgoarch_amd64.go @@ -0,0 +1,12 @@ +// generated by gengoos.go using 'go generate' + +package runtime + +const theGoarch = `amd64` + +const goarch_386 = 0 +const goarch_amd64 = 1 +const goarch_amd64p32 = 0 +const goarch_arm = 0 +const goarch_power64 = 0 +const goarch_power64le = 0 diff --git a/src/runtime/zgoarch_amd64p32.go b/src/runtime/zgoarch_amd64p32.go new file mode 100644 index 0000000000..2b6a142bb7 --- /dev/null +++ b/src/runtime/zgoarch_amd64p32.go @@ -0,0 +1,12 @@ +// generated by gengoos.go using 'go generate' + +package runtime + +const theGoarch = `amd64p32` + +const goarch_386 = 0 +const goarch_amd64 = 0 +const goarch_amd64p32 = 1 +const goarch_arm = 0 +const goarch_power64 = 0 +const goarch_power64le = 0 diff --git a/src/runtime/zgoarch_arm.go b/src/runtime/zgoarch_arm.go new file mode 100644 index 0000000000..4030210050 --- /dev/null +++ b/src/runtime/zgoarch_arm.go @@ -0,0 +1,12 @@ +// generated by gengoos.go using 'go generate' + +package runtime + +const theGoarch = `arm` + +const goarch_386 = 0 +const goarch_amd64 = 0 +const goarch_amd64p32 = 0 +const goarch_arm = 1 +const goarch_power64 = 0 +const goarch_power64le = 0 diff --git a/src/runtime/zgoarch_power64.go b/src/runtime/zgoarch_power64.go new file mode 100644 index 0000000000..cc361f0505 --- /dev/null +++ b/src/runtime/zgoarch_power64.go @@ -0,0 +1,12 @@ +// generated by gengoos.go using 'go generate' + +package runtime + +const theGoarch = `power64` + +const goarch_386 = 0 +const goarch_amd64 = 0 +const goarch_amd64p32 = 0 +const goarch_arm = 0 +const goarch_power64 = 1 +const goarch_power64le = 0 diff --git a/src/runtime/zgoarch_power64le.go b/src/runtime/zgoarch_power64le.go new file mode 100644 index 0000000000..41294e61b9 --- /dev/null +++ b/src/runtime/zgoarch_power64le.go @@ -0,0 +1,12 @@ +// generated by gengoos.go using 'go generate' + +package runtime + +const theGoarch = `power64le` + +const goarch_386 = 0 +const goarch_amd64 = 0 +const goarch_amd64p32 = 0 +const goarch_arm = 0 +const goarch_power64 = 0 +const goarch_power64le = 1 diff --git a/src/runtime/zgoos_android.go b/src/runtime/zgoos_android.go new file mode 100644 index 0000000000..abfba808ba --- /dev/null +++ b/src/runtime/zgoos_android.go @@ -0,0 +1,19 @@ +// generated by gengoos.go using 'go generate' + +// +build android + +package runtime + +const theGoos = `android` + +const goos_android = 1 +const goos_darwin = 0 +const goos_dragonfly = 0 +const goos_freebsd = 0 +const goos_linux = 0 +const goos_nacl = 0 +const goos_netbsd = 0 +const goos_openbsd = 0 +const goos_plan9 = 0 +const goos_solaris = 0 +const goos_windows = 0 diff --git a/src/runtime/zgoos_darwin.go b/src/runtime/zgoos_darwin.go new file mode 100644 index 0000000000..eb39b53dd4 --- /dev/null +++ b/src/runtime/zgoos_darwin.go @@ -0,0 +1,19 @@ +// generated by gengoos.go using 'go generate' + +// +build darwin + +package runtime + +const theGoos = `darwin` + +const goos_android = 0 +const goos_darwin = 1 +const goos_dragonfly = 0 +const goos_freebsd = 0 +const goos_linux = 0 +const goos_nacl = 0 +const goos_netbsd = 0 +const goos_openbsd = 0 +const goos_plan9 = 0 +const goos_solaris = 0 +const goos_windows = 0 diff --git a/src/runtime/zgoos_dragonfly.go b/src/runtime/zgoos_dragonfly.go new file mode 100644 index 0000000000..f6e839d3d8 --- /dev/null +++ b/src/runtime/zgoos_dragonfly.go @@ -0,0 +1,19 @@ +// generated by gengoos.go using 'go generate' + +// +build dragonfly + +package runtime + +const theGoos = `dragonfly` + +const goos_android = 0 +const goos_darwin = 0 +const goos_dragonfly = 1 +const goos_freebsd = 0 +const goos_linux = 0 +const goos_nacl = 0 +const goos_netbsd = 0 +const goos_openbsd = 0 +const goos_plan9 = 0 +const goos_solaris = 0 +const goos_windows = 0 diff --git a/src/runtime/zgoos_freebsd.go b/src/runtime/zgoos_freebsd.go new file mode 100644 index 0000000000..3c47aef2ab --- /dev/null +++ b/src/runtime/zgoos_freebsd.go @@ -0,0 +1,19 @@ +// generated by gengoos.go using 'go generate' + +// +build freebsd + +package runtime + +const theGoos = `freebsd` + +const goos_android = 0 +const goos_darwin = 0 +const goos_dragonfly = 0 +const goos_freebsd = 1 +const goos_linux = 0 +const goos_nacl = 0 +const goos_netbsd = 0 +const goos_openbsd = 0 +const goos_plan9 = 0 +const goos_solaris = 0 +const goos_windows = 0 diff --git a/src/runtime/zgoos_linux.go b/src/runtime/zgoos_linux.go new file mode 100644 index 0000000000..5d899e3db6 --- /dev/null +++ b/src/runtime/zgoos_linux.go @@ -0,0 +1,19 @@ +// generated by gengoos.go using 'go generate' + +// +build linux + +package runtime + +const theGoos = `linux` + +const goos_android = 0 +const goos_darwin = 0 +const goos_dragonfly = 0 +const goos_freebsd = 0 +const goos_linux = 1 +const goos_nacl = 0 +const goos_netbsd = 0 +const goos_openbsd = 0 +const goos_plan9 = 0 +const goos_solaris = 0 +const goos_windows = 0 diff --git a/src/runtime/zgoos_nacl.go b/src/runtime/zgoos_nacl.go new file mode 100644 index 0000000000..b5c4281fb5 --- /dev/null +++ b/src/runtime/zgoos_nacl.go @@ -0,0 +1,19 @@ +// generated by gengoos.go using 'go generate' + +// +build nacl + +package runtime + +const theGoos = `nacl` + +const goos_android = 0 +const goos_darwin = 0 +const goos_dragonfly = 0 +const goos_freebsd = 0 +const goos_linux = 0 +const goos_nacl = 1 +const goos_netbsd = 0 +const goos_openbsd = 0 +const goos_plan9 = 0 +const goos_solaris = 0 +const goos_windows = 0 diff --git a/src/runtime/zgoos_netbsd.go b/src/runtime/zgoos_netbsd.go new file mode 100644 index 0000000000..b2e45222ae --- /dev/null +++ b/src/runtime/zgoos_netbsd.go @@ -0,0 +1,19 @@ +// generated by gengoos.go using 'go generate' + +// +build netbsd + +package runtime + +const theGoos = `netbsd` + +const goos_android = 0 +const goos_darwin = 0 +const goos_dragonfly = 0 +const goos_freebsd = 0 +const goos_linux = 0 +const goos_nacl = 0 +const goos_netbsd = 1 +const goos_openbsd = 0 +const goos_plan9 = 0 +const goos_solaris = 0 +const goos_windows = 0 diff --git a/src/runtime/zgoos_openbsd.go b/src/runtime/zgoos_openbsd.go new file mode 100644 index 0000000000..331c96dd66 --- /dev/null +++ b/src/runtime/zgoos_openbsd.go @@ -0,0 +1,19 @@ +// generated by gengoos.go using 'go generate' + +// +build openbsd + +package runtime + +const theGoos = `openbsd` + +const goos_android = 0 +const goos_darwin = 0 +const goos_dragonfly = 0 +const goos_freebsd = 0 +const goos_linux = 0 +const goos_nacl = 0 +const goos_netbsd = 0 +const goos_openbsd = 1 +const goos_plan9 = 0 +const goos_solaris = 0 +const goos_windows = 0 diff --git a/src/runtime/zgoos_plan9.go b/src/runtime/zgoos_plan9.go new file mode 100644 index 0000000000..f29eb45230 --- /dev/null +++ b/src/runtime/zgoos_plan9.go @@ -0,0 +1,19 @@ +// generated by gengoos.go using 'go generate' + +// +build plan9 + +package runtime + +const theGoos = `plan9` + +const goos_android = 0 +const goos_darwin = 0 +const goos_dragonfly = 0 +const goos_freebsd = 0 +const goos_linux = 0 +const goos_nacl = 0 +const goos_netbsd = 0 +const goos_openbsd = 0 +const goos_plan9 = 1 +const goos_solaris = 0 +const goos_windows = 0 diff --git a/src/runtime/zgoos_solaris.go b/src/runtime/zgoos_solaris.go new file mode 100644 index 0000000000..ac613db33c --- /dev/null +++ b/src/runtime/zgoos_solaris.go @@ -0,0 +1,19 @@ +// generated by gengoos.go using 'go generate' + +// +build solaris + +package runtime + +const theGoos = `solaris` + +const goos_android = 0 +const goos_darwin = 0 +const goos_dragonfly = 0 +const goos_freebsd = 0 +const goos_linux = 0 +const goos_nacl = 0 +const goos_netbsd = 0 +const goos_openbsd = 0 +const goos_plan9 = 0 +const goos_solaris = 1 +const goos_windows = 0 diff --git a/src/runtime/zgoos_windows.go b/src/runtime/zgoos_windows.go new file mode 100644 index 0000000000..43710d862f --- /dev/null +++ b/src/runtime/zgoos_windows.go @@ -0,0 +1,19 @@ +// generated by gengoos.go using 'go generate' + +// +build windows + +package runtime + +const theGoos = `windows` + +const goos_android = 0 +const goos_darwin = 0 +const goos_dragonfly = 0 +const goos_freebsd = 0 +const goos_linux = 0 +const goos_nacl = 0 +const goos_netbsd = 0 +const goos_openbsd = 0 +const goos_plan9 = 0 +const goos_solaris = 0 +const goos_windows = 1 From 1a68ac2538da55f1a130e30ad074fd074ef9e7de Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 18 Nov 2014 15:18:42 -0500 Subject: [PATCH 36/68] [dev.cc] cmd/9c: remove LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/175940043 --- src/cmd/9c/Makefile | 5 - src/cmd/9c/Notes | 14 - src/cmd/9c/cgen.c | 1147 ------------------------------- src/cmd/9c/doc.go | 17 - src/cmd/9c/gc.h | 350 ---------- src/cmd/9c/list.c | 37 - src/cmd/9c/machcap.c | 105 --- src/cmd/9c/mul.c | 638 ------------------ src/cmd/9c/peep.c | 1076 ----------------------------- src/cmd/9c/reg.c | 1163 -------------------------------- src/cmd/9c/sgen.c | 291 -------- src/cmd/9c/swt.c | 407 ----------- src/cmd/9c/txt.c | 1537 ------------------------------------------ 13 files changed, 6787 deletions(-) delete mode 100644 src/cmd/9c/Makefile delete mode 100644 src/cmd/9c/Notes delete mode 100644 src/cmd/9c/cgen.c delete mode 100644 src/cmd/9c/doc.go delete mode 100644 src/cmd/9c/gc.h delete mode 100644 src/cmd/9c/list.c delete mode 100644 src/cmd/9c/machcap.c delete mode 100644 src/cmd/9c/mul.c delete mode 100644 src/cmd/9c/peep.c delete mode 100644 src/cmd/9c/reg.c delete mode 100644 src/cmd/9c/sgen.c delete mode 100644 src/cmd/9c/swt.c delete mode 100644 src/cmd/9c/txt.c diff --git a/src/cmd/9c/Makefile b/src/cmd/9c/Makefile deleted file mode 100644 index 3f528d7517..0000000000 --- a/src/cmd/9c/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright 2012 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. - -include ../../Make.dist diff --git a/src/cmd/9c/Notes b/src/cmd/9c/Notes deleted file mode 100644 index 92dd9deb3a..0000000000 --- a/src/cmd/9c/Notes +++ /dev/null @@ -1,14 +0,0 @@ -- effect of register expansion on 32-bit shifts and masks etc -9c -- multab -- floating-point conversions -- conversions of constants -- nodtype for loads -- sign-extension instruction (32-64) when in register? -- double indexing -- SLW (eg, in cat) -- scheduling - -9l -- D_QCONST, DWORD -- maskgen diff --git a/src/cmd/9c/cgen.c b/src/cmd/9c/cgen.c deleted file mode 100644 index bd1f7b28f6..0000000000 --- a/src/cmd/9c/cgen.c +++ /dev/null @@ -1,1147 +0,0 @@ -// cmd/9c/cgen.c from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "gc.h" -#include "../../runtime/funcdata.h" - -void -cgen(Node *n, Node *nn) -{ - Node *l, *r; - Prog *p1; - Node nod, nod1, nod2, nod3, nod4; - int o; - int32 v, curs; - - if(debug['g']) { - prtree(nn, "cgen lhs"); - prtree(n, "cgen"); - } - if(n == Z || n->type == T) - return; - if(typesu[n->type->etype] && (n->op != OFUNC || nn != Z)) { - sugen(n, nn, n->type->width); - return; - } - l = n->left; - r = n->right; - o = n->op; - if(n->addable >= INDEXED) { - if(nn == Z) { - switch(o) { - default: - nullwarn(Z, Z); - break; - case OINDEX: - nullwarn(l, r); - break; - } - return; - } - gmove(n, nn); - return; - } - curs = cursafe; - - if(n->complex >= FNX) - if(l->complex >= FNX) - if(r != Z && r->complex >= FNX) - switch(o) { - default: - regret(&nod, r, 0, 0); - cgen(r, &nod); - - regsalloc(&nod1, r); - gopcode(OAS, &nod, Z, &nod1); - - regfree(&nod); - nod = *n; - nod.right = &nod1; - cgen(&nod, nn); - return; - - case OFUNC: - case OCOMMA: - case OANDAND: - case OOROR: - case OCOND: - case ODOT: - break; - } - - switch(o) { - default: - diag(n, "unknown op in cgen: %O", o); - break; - - case OAS: - if(l->op == OBIT) - goto bitas; - if(l->addable >= INDEXED) { - if(nn != Z || r->addable < INDEXED) { - regalloc(&nod, r, nn); - cgen(r, &nod); - gmove(&nod, l); - regfree(&nod); - } else - gmove(r, l); - break; - } - if(l->complex >= r->complex) { - reglcgen(&nod1, l, Z); - if(r->addable >= INDEXED) { - gmove(r, &nod1); - if(nn != Z) - gmove(r, nn); - regfree(&nod1); - break; - } - regalloc(&nod, r, nn); - cgen(r, &nod); - } else { - regalloc(&nod, r, nn); - cgen(r, &nod); - reglcgen(&nod1, l, Z); - } - gmove(&nod, &nod1); - regfree(&nod); - regfree(&nod1); - break; - - bitas: - n = l->left; - regalloc(&nod, r, nn); - if(l->complex >= r->complex) { - reglcgen(&nod1, n, Z); - cgen(r, &nod); - } else { - cgen(r, &nod); - reglcgen(&nod1, n, Z); - } - regalloc(&nod2, n, Z); - gopcode(OAS, &nod1, Z, &nod2); - bitstore(l, &nod, &nod1, &nod2, nn); - break; - - case OBIT: - if(nn == Z) { - nullwarn(l, Z); - break; - } - bitload(n, &nod, Z, Z, nn); - gopcode(OAS, &nod, Z, nn); - regfree(&nod); - break; - - case OXOR: - if(nn != Z) - if(r->op == OCONST && r->vconst == -1){ - cgen(l, nn); - gopcode(OCOM, nn, Z, nn); - break; - } - - case OADD: - case OSUB: - case OAND: - case OOR: - case OLSHR: - case OASHL: - case OASHR: - /* - * immediate operands - */ - if(nn != Z && - r->op == OCONST && - !typefd[n->type->etype] && - immconst(r)) { - cgen(l, nn); - if(r->vconst == 0) - if(o != OAND) - break; - if(nn != Z) - gopcode(o, r, Z, nn); - break; - } - - case OMUL: - case OLMUL: - case OLDIV: - case OLMOD: - case ODIV: - case OMOD: - if(nn == Z) { - nullwarn(l, r); - break; - } - if(o == OMUL || o == OLMUL) { - if(mulcon(n, nn)) - break; - if(debug['M']) - print("%L multiply\n", n->lineno); - } - if(l->complex >= r->complex) { - regalloc(&nod, l, nn); - cgen(l, &nod); - regalloc(&nod1, l, Z); /* note: l used for type, so shifts work! */ - cgen(r, &nod1); - gopcode(o, &nod1, Z, &nod); - } else { - regalloc(&nod, l, nn); /* note: l used for type, so shifts work! */ - cgen(r, &nod); - regalloc(&nod1, l, Z); - cgen(l, &nod1); - gopcode(o, &nod, &nod1, &nod); - } - gopcode(OAS, &nod, Z, nn); - regfree(&nod); - regfree(&nod1); - break; - - case OASLSHR: - case OASASHL: - case OASASHR: - case OASAND: - case OASADD: - case OASSUB: - case OASXOR: - case OASOR: - if(l->op == OBIT) - goto asbitop; - if(r->op == OCONST && - !typefd[n->type->etype] && - immconst(r)) { - if(l->addable < INDEXED) - reglcgen(&nod2, l, Z); - else - nod2 = *l; - regalloc(&nod, l, nn); /* note: l used for type, so shifts work! */ - gopcode(OAS, &nod2, Z, &nod); - gopcode(o, r, Z, &nod); - gopcode(OAS, &nod, Z, &nod2); - - regfree(&nod); - if(l->addable < INDEXED) - regfree(&nod2); - break; - } - - case OASLMUL: - case OASLDIV: - case OASLMOD: - case OASMUL: - case OASDIV: - case OASMOD: - if(l->op == OBIT) - goto asbitop; - if(l->complex >= r->complex) { - if(l->addable < INDEXED) - reglcgen(&nod2, l, Z); - else - nod2 = *l; - regalloc(&nod, n, nn); - cgen(r, &nod); - } else { - regalloc(&nod, n, nn); - cgen(r, &nod); - if(l->addable < INDEXED) - reglcgen(&nod2, l, Z); - else - nod2 = *l; - } - regalloc(&nod1, n, Z); - gopcode(OAS, &nod2, Z, &nod1); - if(nod1.type->etype != nod.type->etype){ - regalloc(&nod3, &nod, Z); - gmove(&nod1, &nod3); - regfree(&nod1); - nod1 = nod3; - } - gopcode(o, &nod, &nod1, &nod); - gmove(&nod, &nod2); - if(nn != Z) - gmove(&nod, nn); - regfree(&nod); - regfree(&nod1); - if(l->addable < INDEXED) - regfree(&nod2); - break; - - asbitop: - regalloc(&nod4, n, nn); - regalloc(&nod3, r, Z); - if(l->complex >= r->complex) { - bitload(l, &nod, &nod1, &nod2, &nod4); - cgen(r, &nod3); - } else { - cgen(r, &nod3); - bitload(l, &nod, &nod1, &nod2, &nod4); - } - gmove(&nod, &nod4); - gopcode(n->op, &nod3, Z, &nod4); - regfree(&nod3); - gmove(&nod4, &nod); - regfree(&nod4); - bitstore(l, &nod, &nod1, &nod2, nn); - break; - - case OADDR: - if(nn == Z) { - nullwarn(l, Z); - break; - } - lcgen(l, nn); - break; - - case OFUNC: - if(l->complex >= FNX) { - if(l->op != OIND) - diag(n, "bad function call"); - - regret(&nod, l->left, 0, 0); - cgen(l->left, &nod); - regsalloc(&nod1, l->left); - gopcode(OAS, &nod, Z, &nod1); - regfree(&nod); - - nod = *n; - nod.left = &nod2; - nod2 = *l; - nod2.left = &nod1; - nod2.complex = 1; - cgen(&nod, nn); - - return; - } - if(REGARG >= 0) - o = reg[REGARG]; - gargs(r, &nod, &nod1); - if(l->addable < INDEXED) { - reglcgen(&nod, l, Z); - gopcode(OFUNC, Z, Z, &nod); - regfree(&nod); - } else - gopcode(OFUNC, Z, Z, l); - if(REGARG>=0) - if(o != reg[REGARG]) - reg[REGARG]--; - regret(&nod, n, l->type, 1); // update maxarg if nothing else - if(nn != Z) - gopcode(OAS, &nod, Z, nn); - if(nod.op == OREGISTER) - regfree(&nod); - break; - - case OIND: - if(nn == Z) { - cgen(l, nn); - break; - } - regialloc(&nod, n, nn); - r = l; - while(r->op == OADD) - r = r->right; - if(sconst(r)) { - v = r->vconst; - r->vconst = 0; - cgen(l, &nod); - nod.xoffset += v; - r->vconst = v; - } else - cgen(l, &nod); - regind(&nod, n); - gopcode(OAS, &nod, Z, nn); - regfree(&nod); - break; - - case OEQ: - case ONE: - case OLE: - case OLT: - case OGE: - case OGT: - case OLO: - case OLS: - case OHI: - case OHS: - if(nn == Z) { - nullwarn(l, r); - break; - } - boolgen(n, 1, nn); - break; - - case OANDAND: - case OOROR: - boolgen(n, 1, nn); - if(nn == Z) - patch(p, pc); - break; - - case ONOT: - if(nn == Z) { - nullwarn(l, Z); - break; - } - boolgen(n, 1, nn); - break; - - case OCOMMA: - cgen(l, Z); - cgen(r, nn); - break; - - case OCAST: - if(nn == Z) { - nullwarn(l, Z); - break; - } - /* - * convert from types l->n->nn - */ - if(nocast(l->type, n->type) && nocast(n->type, nn->type)) { - /* both null, gen l->nn */ - cgen(l, nn); - break; - } - regalloc(&nod, l, nn); - cgen(l, &nod); - regalloc(&nod1, n, &nod); - gopcode(OAS, &nod, Z, &nod1); - gopcode(OAS, &nod1, Z, nn); - regfree(&nod1); - regfree(&nod); - break; - - case ODOT: - sugen(l, nodrat, l->type->width); - if(nn != Z) { - warn(n, "non-interruptable temporary"); - nod = *nodrat; - if(!r || r->op != OCONST) { - diag(n, "DOT and no offset"); - break; - } - nod.xoffset += (int32)r->vconst; - nod.type = n->type; - cgen(&nod, nn); - } - break; - - case OCOND: - bcgen(l, 1); - p1 = p; - cgen(r->left, nn); - gbranch(OGOTO); - patch(p1, pc); - p1 = p; - cgen(r->right, nn); - patch(p1, pc); - break; - - case OPOSTINC: - case OPOSTDEC: - v = 1; - if(l->type->etype == TIND) - v = l->type->link->width; - if(o == OPOSTDEC) - v = -v; - if(l->op == OBIT) - goto bitinc; - if(nn == Z) - goto pre; - - if(l->addable < INDEXED) - reglcgen(&nod2, l, Z); - else - nod2 = *l; - - regalloc(&nod, l, nn); - gopcode(OAS, &nod2, Z, &nod); - regalloc(&nod1, l, Z); - if(typefd[l->type->etype]) { - regalloc(&nod3, l, Z); - if(v < 0) { - gopcode(OAS, nodfconst(-v), Z, &nod3); - gopcode(OSUB, &nod3, &nod, &nod1); - } else { - gopcode(OAS, nodfconst(v), Z, &nod3); - gopcode(OADD, &nod3, &nod, &nod1); - } - regfree(&nod3); - } else - gopcode(OADD, nodconst(v), &nod, &nod1); - gopcode(OAS, &nod1, Z, &nod2); - - regfree(&nod); - regfree(&nod1); - if(l->addable < INDEXED) - regfree(&nod2); - break; - - case OPREINC: - case OPREDEC: - v = 1; - if(l->type->etype == TIND) - v = l->type->link->width; - if(o == OPREDEC) - v = -v; - if(l->op == OBIT) - goto bitinc; - - pre: - if(l->addable < INDEXED) - reglcgen(&nod2, l, Z); - else - nod2 = *l; - - regalloc(&nod, l, nn); - gopcode(OAS, &nod2, Z, &nod); - if(typefd[l->type->etype]) { - regalloc(&nod3, l, Z); - if(v < 0) { - gopcode(OAS, nodfconst(-v), Z, &nod3); - gopcode(OSUB, &nod3, Z, &nod); - } else { - gopcode(OAS, nodfconst(v), Z, &nod3); - gopcode(OADD, &nod3, Z, &nod); - } - regfree(&nod3); - } else - gopcode(OADD, nodconst(v), Z, &nod); - gopcode(OAS, &nod, Z, &nod2); - if(nn && l->op == ONAME) /* in x=++i, emit USED(i) */ - gins(ANOP, l, Z); - - regfree(&nod); - if(l->addable < INDEXED) - regfree(&nod2); - break; - - bitinc: - if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) { - bitload(l, &nod, &nod1, &nod2, Z); - gopcode(OAS, &nod, Z, nn); - gopcode(OADD, nodconst(v), Z, &nod); - bitstore(l, &nod, &nod1, &nod2, Z); - break; - } - bitload(l, &nod, &nod1, &nod2, nn); - gopcode(OADD, nodconst(v), Z, &nod); - bitstore(l, &nod, &nod1, &nod2, nn); - break; - } - cursafe = curs; -} - -void -reglcgen(Node *t, Node *n, Node *nn) -{ - Node *r; - int32 v; - - regialloc(t, n, nn); - if(n->op == OIND) { - r = n->left; - while(r->op == OADD) - r = r->right; - if(sconst(r)) { - v = r->vconst; - r->vconst = 0; - lcgen(n, t); - t->xoffset += v; - r->vconst = v; - regind(t, n); - return; - } - } - lcgen(n, t); - regind(t, n); -} - -void -lcgen(Node *n, Node *nn) -{ - Prog *p1; - Node nod; - - if(debug['g']) { - prtree(nn, "lcgen lhs"); - prtree(n, "lcgen"); - } - if(n == Z || n->type == T) - return; - if(nn == Z) { - nn = &nod; - regalloc(&nod, n, Z); - } - switch(n->op) { - default: - if(n->addable < INDEXED) { - diag(n, "unknown op in lcgen: %O", n->op); - break; - } - nod = *n; - nod.op = OADDR; - nod.left = n; - nod.right = Z; - nod.type = types[TIND]; - gopcode(OAS, &nod, Z, nn); - break; - - case OCOMMA: - cgen(n->left, n->left); - lcgen(n->right, nn); - break; - - case OIND: - cgen(n->left, nn); - break; - - case OCOND: - bcgen(n->left, 1); - p1 = p; - lcgen(n->right->left, nn); - gbranch(OGOTO); - patch(p1, pc); - p1 = p; - lcgen(n->right->right, nn); - patch(p1, pc); - break; - } -} - -void -bcgen(Node *n, int true) -{ - - if(n->type == T) - gbranch(OGOTO); - else - boolgen(n, true, Z); -} - -void -boolgen(Node *n, int true, Node *nn) -{ - int o; - Prog *p1, *p2; - Node *l, *r, nod, nod1; - int32 curs; - - if(debug['g']) { - prtree(nn, "boolgen lhs"); - prtree(n, "boolgen"); - } - curs = cursafe; - l = n->left; - r = n->right; - switch(n->op) { - - default: - if(n->op == OCONST) { - o = vconst(n); - if(!true) - o = !o; - gbranch(OGOTO); - if(o) { - p1 = p; - gbranch(OGOTO); - patch(p1, pc); - } - goto com; - } - regalloc(&nod, n, nn); - cgen(n, &nod); - o = ONE; - if(true) - o = comrel[relindex(o)]; - if(typefd[n->type->etype]) { - nodreg(&nod1, n, NREG+FREGZERO); - gopcode(o, &nod, Z, &nod1); - } else - gopcode(o, &nod, Z, nodconst(0)); - regfree(&nod); - goto com; - - case OCOMMA: - cgen(l, Z); - boolgen(r, true, nn); - break; - - case ONOT: - boolgen(l, !true, nn); - break; - - case OCOND: - bcgen(l, 1); - p1 = p; - bcgen(r->left, true); - p2 = p; - gbranch(OGOTO); - patch(p1, pc); - p1 = p; - bcgen(r->right, !true); - patch(p2, pc); - p2 = p; - gbranch(OGOTO); - patch(p1, pc); - patch(p2, pc); - goto com; - - case OANDAND: - if(!true) - goto caseor; - - caseand: - bcgen(l, true); - p1 = p; - bcgen(r, !true); - p2 = p; - patch(p1, pc); - gbranch(OGOTO); - patch(p2, pc); - goto com; - - case OOROR: - if(!true) - goto caseand; - - caseor: - bcgen(l, !true); - p1 = p; - bcgen(r, !true); - p2 = p; - gbranch(OGOTO); - patch(p1, pc); - patch(p2, pc); - goto com; - - case OEQ: - case ONE: - case OLE: - case OLT: - case OGE: - case OGT: - case OHI: - case OHS: - case OLO: - case OLS: - o = n->op; - if(true) - o = comrel[relindex(o)]; - if(l->complex >= FNX && r->complex >= FNX) { - regret(&nod, r, 0, 0); - cgen(r, &nod); - regsalloc(&nod1, r); - gopcode(OAS, &nod, Z, &nod1); - regfree(&nod); - nod = *n; - nod.right = &nod1; - boolgen(&nod, true, nn); - break; - } - if(sconst(r)) { - regalloc(&nod, l, nn); - cgen(l, &nod); - gopcode(o, &nod, Z, r); - regfree(&nod); - goto com; - } - if(l->complex >= r->complex) { - regalloc(&nod1, l, nn); - cgen(l, &nod1); - regalloc(&nod, r, Z); - cgen(r, &nod); - } else { - regalloc(&nod, r, nn); - cgen(r, &nod); - regalloc(&nod1, l, Z); - cgen(l, &nod1); - } - gopcode(o, &nod1, Z, &nod); - regfree(&nod); - regfree(&nod1); - - com: - if(nn != Z) { - p1 = p; - gopcode(OAS, nodconst(1L), Z, nn); - gbranch(OGOTO); - p2 = p; - patch(p1, pc); - gopcode(OAS, nodconst(0L), Z, nn); - patch(p2, pc); - } - break; - } - cursafe = curs; -} - -void -sugen(Node *n, Node *nn, int32 w) -{ - Prog *p1; - Node nod0, nod1, nod2, nod3, nod4, *l, *r; - Type *t; - int32 pc1; - int i, m, c; - - if(n == Z || n->type == T) - return; - if(debug['g']) { - prtree(nn, "sugen lhs"); - prtree(n, "sugen"); - } - if(nn == nodrat) - if(w > nrathole) - nrathole = w; - switch(n->op) { - case OIND: - if(nn == Z) { - nullwarn(n->left, Z); - break; - } - - default: - goto copy; - - case OCONST: - if(n->type && typev[n->type->etype]) { - if(nn == Z) { - nullwarn(n->left, Z); - break; - } - - t = nn->type; - nn->type = types[TLONG]; - reglcgen(&nod1, nn, Z); - nn->type = t; - - if(align(0, types[TCHAR], Aarg1, nil)) /* isbigendian */ - gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1); - else - gopcode(OAS, nod32const(n->vconst), Z, &nod1); - nod1.xoffset += SZ_LONG; - if(align(0, types[TCHAR], Aarg1, nil)) /* isbigendian */ - gopcode(OAS, nod32const(n->vconst), Z, &nod1); - else - gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1); - - regfree(&nod1); - break; - } - goto copy; - - case ODOT: - l = n->left; - sugen(l, nodrat, l->type->width); - if(nn != Z) { - warn(n, "non-interruptable temporary"); - nod1 = *nodrat; - r = n->right; - if(!r || r->op != OCONST) { - diag(n, "DOT and no offset"); - break; - } - nod1.xoffset += (int32)r->vconst; - nod1.type = n->type; - sugen(&nod1, nn, w); - } - break; - - case OSTRUCT: - /* - * rewrite so lhs has no side effects - */ - if(nn != Z && side(nn)) { - nod1 = *n; - nod1.type = typ(TIND, n->type); - regalloc(&nod2, &nod1, Z); - lcgen(nn, &nod2); - regsalloc(&nod0, &nod1); - gopcode(OAS, &nod2, Z, &nod0); - regfree(&nod2); - - nod1 = *n; - nod1.op = OIND; - nod1.left = &nod0; - nod1.right = Z; - nod1.complex = 1; - - sugen(n, &nod1, w); - return; - } - - r = n->left; - for(t = n->type->link; t != T; t = t->down) { - l = r; - if(r->op == OLIST) { - l = r->left; - r = r->right; - } - if(nn == Z) { - cgen(l, nn); - continue; - } - /* - * hand craft *(&nn + o) = l - */ - nod0 = znode; - nod0.op = OAS; - nod0.type = t; - nod0.left = &nod1; - nod0.right = l; - - nod1 = znode; - nod1.op = OIND; - nod1.type = t; - nod1.left = &nod2; - - nod2 = znode; - nod2.op = OADD; - nod2.type = typ(TIND, t); - nod2.left = &nod3; - nod2.right = &nod4; - - nod3 = znode; - nod3.op = OADDR; - nod3.type = nod2.type; - nod3.left = nn; - - nod4 = znode; - nod4.op = OCONST; - nod4.type = nod2.type; - nod4.vconst = t->offset; - - ccom(&nod0); - acom(&nod0); - xcom(&nod0); - nod0.addable = 0; - - /* prtree(&nod0, "hand craft"); /* */ - cgen(&nod0, Z); - } - break; - - case OAS: - if(nn == Z) { - if(n->addable < INDEXED) - sugen(n->right, n->left, w); - break; - } - /* BOTCH -- functions can clobber rathole */ - sugen(n->right, nodrat, w); - warn(n, "non-interruptable temporary"); - sugen(nodrat, n->left, w); - sugen(nodrat, nn, w); - break; - - case OFUNC: - if(!hasdotdotdot(n->left->type)) { - cgen(n, Z); - if(nn != Z) { - curarg -= n->type->width; - regret(&nod1, n, n->left->type, 1); - if(nn->complex >= FNX) { - regsalloc(&nod2, n); - cgen(&nod1, &nod2); - nod1 = nod2; - } - cgen(&nod1, nn); - } - break; - } - if(nn == Z) { - sugen(n, nodrat, w); - break; - } - if(nn->op != OIND) { - nn = new1(OADDR, nn, Z); - nn->type = types[TIND]; - nn->addable = 0; - } else - nn = nn->left; - n = new(OFUNC, n->left, new(OLIST, nn, n->right)); - n->type = types[TVOID]; - n->left->type = types[TVOID]; - cgen(n, Z); - break; - - case OCOND: - bcgen(n->left, 1); - p1 = p; - sugen(n->right->left, nn, w); - gbranch(OGOTO); - patch(p1, pc); - p1 = p; - sugen(n->right->right, nn, w); - patch(p1, pc); - break; - - case OCOMMA: - cgen(n->left, Z); - sugen(n->right, nn, w); - break; - } - return; - -copy: - if(nn == Z) - return; - if(n->complex >= FNX && nn->complex >= FNX) { - t = nn->type; - nn->type = types[TLONG]; - regialloc(&nod1, nn, Z); - lcgen(nn, &nod1); - regsalloc(&nod2, nn); - nn->type = t; - - gopcode(OAS, &nod1, Z, &nod2); - regfree(&nod1); - - nod2.type = typ(TIND, t); - - nod1 = nod2; - nod1.op = OIND; - nod1.left = &nod2; - nod1.right = Z; - nod1.complex = 1; - nod1.type = t; - - sugen(n, &nod1, w); - return; - } - - if(n->complex > nn->complex) { - t = n->type; - n->type = types[TLONG]; - reglcgen(&nod1, n, Z); - n->type = t; - - t = nn->type; - nn->type = types[TLONG]; - reglcgen(&nod2, nn, Z); - nn->type = t; - } else { - t = nn->type; - nn->type = types[TLONG]; - reglcgen(&nod2, nn, Z); - nn->type = t; - - t = n->type; - n->type = types[TLONG]; - reglcgen(&nod1, n, Z); - n->type = t; - } - - w /= SZ_LONG; - if(w <= 5) { - layout(&nod1, &nod2, w, 0, Z); - goto out; - } - - /* - * minimize space for unrolling loop - * 3,4,5 times. (6 or more is never minimum) - * if small structure, try 2 also. - */ - c = 0; /* set */ - m = 100; - i = 3; - if(w <= 15) - i = 2; - for(; i<=5; i++) - if(i + w%i <= m) { - c = i; - m = c + w%c; - } - - regalloc(&nod3, ®node, Z); - layout(&nod1, &nod2, w%c, w/c, &nod3); - - pc1 = pc; - layout(&nod1, &nod2, c, 0, Z); - - gopcode(OSUB, nodconst(1L), Z, &nod3); - nod1.op = OREGISTER; - gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod1); - nod2.op = OREGISTER; - gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod2); - - gopcode(OGT, &nod3, Z, nodconst(0)); - patch(p, pc1); - - regfree(&nod3); -out: - regfree(&nod1); - regfree(&nod2); -} - -void -layout(Node *f, Node *t, int c, int cv, Node *cn) -{ - Node t1, t2; - - while(c > 3) { - layout(f, t, 2, 0, Z); - c -= 2; - } - - regalloc(&t1, ®node, Z); - regalloc(&t2, ®node, Z); - if(c > 0) { - gopcode(OAS, f, Z, &t1); - f->xoffset += SZ_LONG; - } - if(cn != Z) - gopcode(OAS, nodconst(cv), Z, cn); - if(c > 1) { - gopcode(OAS, f, Z, &t2); - f->xoffset += SZ_LONG; - } - if(c > 0) { - gopcode(OAS, &t1, Z, t); - t->xoffset += SZ_LONG; - } - if(c > 2) { - gopcode(OAS, f, Z, &t1); - f->xoffset += SZ_LONG; - } - if(c > 1) { - gopcode(OAS, &t2, Z, t); - t->xoffset += SZ_LONG; - } - if(c > 2) { - gopcode(OAS, &t1, Z, t); - t->xoffset += SZ_LONG; - } - regfree(&t1); - regfree(&t2); -} diff --git a/src/cmd/9c/doc.go b/src/cmd/9c/doc.go deleted file mode 100644 index 6c9b4762d8..0000000000 --- a/src/cmd/9c/doc.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2009 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. - -// +build ignore - -/* - -9c is a version of the Plan 9 C compiler. The original is documented at - - http://plan9.bell-labs.com/magic/man2html/1/8c - -Its target architecture is the Power64, referred to by these tools as -power64 (big endian) or power64le (little endian). - -*/ -package main diff --git a/src/cmd/9c/gc.h b/src/cmd/9c/gc.h deleted file mode 100644 index fbe5099fe8..0000000000 --- a/src/cmd/9c/gc.h +++ /dev/null @@ -1,350 +0,0 @@ -// cmd/9c/gc.h from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include -#include "../cc/cc.h" -#include "../9l/9.out.h" - -/* - * 9c/powerpc64 - */ -#define SZ_CHAR 1 -#define SZ_SHORT 2 -#define SZ_INT 4 -#define SZ_LONG 4 -#define SZ_IND 8 -#define SZ_FLOAT 4 -#define SZ_VLONG 8 -#define SZ_DOUBLE 8 -#define FNX 100 - -typedef struct Case Case; -typedef struct C1 C1; -typedef struct Multab Multab; -typedef struct Hintab Hintab; -typedef struct Reg Reg; -typedef struct Rgn Rgn; - -#define A ((Adr*)0) - -#define INDEXED 9 -#define P ((Prog*)0) - -struct Case -{ - Case* link; - vlong val; - int32 label; - char def; - char isv; -}; -#define C ((Case*)0) - -struct C1 -{ - vlong val; - int32 label; -}; - -struct Multab -{ - int32 val; - char code[20]; -}; - -struct Hintab -{ - ushort val; - char hint[10]; -}; - -struct Reg -{ - int32 pc; - int32 rpo; /* reverse post ordering */ - - Bits set; - Bits use1; - Bits use2; - - Bits refbehind; - Bits refahead; - Bits calbehind; - Bits calahead; - Bits regdiff; - Bits act; - - int32 regu; - int32 loop; /* could be shorter */ - - union - { - Reg* log5; - int32 active; - }; - Reg* p1; - Reg* p2; - Reg* p2link; - Reg* s1; - Reg* s2; - Reg* link; - Prog* prog; -}; -#define R ((Reg*)0) - -#define NRGN 600 -struct Rgn -{ - Reg* enter; - short cost; - short varno; - short regno; -}; - -EXTERN int32 breakpc; -EXTERN int32 nbreak; -EXTERN Case* cases; -EXTERN Node constnode; -EXTERN Node fconstnode; -EXTERN Node vconstnode; -EXTERN int32 continpc; -EXTERN int32 curarg; -EXTERN int32 cursafe; -EXTERN Prog* lastp; -extern int hintabsize; -EXTERN int32 maxargsafe; -EXTERN Multab multab[20]; -EXTERN int mnstring; -EXTERN Node* nodrat; -EXTERN Node* nodret; -EXTERN Node* nodsafe; -EXTERN int32 nrathole; -EXTERN int32 nstring; -EXTERN Prog* p; -EXTERN int32 pc; -EXTERN Node regnode; -EXTERN Node qregnode; -EXTERN char string[NSNAME]; -EXTERN Sym* symrathole; -EXTERN Node znode; -EXTERN Prog zprog; -EXTERN int reg[NREG+NREG]; -EXTERN int32 exregoffset; -EXTERN int32 exfregoffset; -EXTERN uchar typechlpv[NTYPE]; - -#define BLOAD(r) band(bnot(r->refbehind), r->refahead) -#define BSTORE(r) band(bnot(r->calbehind), r->calahead) -#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z]) -#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z]) - -#define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32)) - -#define CLOAD 5 -#define CREF 5 -#define CINF 1000 -#define LOOP 3 - -EXTERN Rgn region[NRGN]; -EXTERN Rgn* rgp; -EXTERN int nregion; -EXTERN int nvar; - -EXTERN Bits externs; -EXTERN Bits params; -EXTERN Bits consts; -EXTERN Bits addrs; - -EXTERN int32 regbits; -EXTERN int32 exregbits; - -EXTERN int change; -EXTERN int suppress; - -EXTERN Reg* firstr; -EXTERN Reg* lastr; -EXTERN Reg zreg; -EXTERN Reg* freer; -EXTERN Var var[NVAR]; -EXTERN int32* idom; -EXTERN Reg** rpo2r; -EXTERN int32 maxnr; - -#define R0ISZERO (debug['0']==0) - -extern char* anames[]; -extern Hintab hintab[]; - -/* - * sgen.c - */ -void codgen(Node*, Node*); -void gen(Node*); -void usedset(Node*, int); -void noretval(int); -void xcom(Node*); -int bcomplex(Node*, Node*); -Prog* gtext(Sym*, int32); -vlong argsize(int); - -/* - * cgen.c - */ -void cgen(Node*, Node*); -void reglcgen(Node*, Node*, Node*); -void lcgen(Node*, Node*); -void bcgen(Node*, int); -void boolgen(Node*, int, Node*); -void sugen(Node*, Node*, int32); -void layout(Node*, Node*, int, int, Node*); - -/* - * txt.c - */ -void ginit(void); -void gclean(void); -void nextpc(void); -void gargs(Node*, Node*, Node*); -void garg1(Node*, Node*, Node*, int, Node**); -Node* nodconst(int32); -Node* nod32const(vlong); -Node* nodfconst(double); -Node* nodgconst(vlong v, Type *t); -void nodreg(Node*, Node*, int); -void regret(Node*, Node*, Type*, int); -void regalloc(Node*, Node*, Node*); -void regfree(Node*); -void regialloc(Node*, Node*, Node*); -void regsalloc(Node*, Node*); -void regaalloc1(Node*, Node*); -void regaalloc(Node*, Node*); -void regind(Node*, Node*); -void gprep(Node*, Node*); -void raddr(Node*, Prog*); -void naddr(Node*, Addr*); -void gmove(Node*, Node*); -void gins(int a, Node*, Node*); -void gopcode(int, Node*, Node*, Node*); -int samaddr(Node*, Node*); -void gbranch(int); -int immconst(Node*); -void patch(Prog*, int32); -int sconst(Node*); -int sval(int32); -int uconst(Node*); -void gpseudo(int, Sym*, Node*); -void gprefetch(Node*); -void gpcdata(int, int); - -/* - * swt.c - */ -int swcmp(const void*, const void*); -void doswit(Node*); -void swit1(C1*, int, int32, Node*); -void swit2(C1*, int, int32, Node*, Node*); -void newcase(void); -void bitload(Node*, Node*, Node*, Node*, Node*); -void bitstore(Node*, Node*, Node*, Node*, Node*); -int32 outstring(char*, int32); -int mulcon(Node*, Node*); -Multab* mulcon0(Node*, int32); -int mulcon1(Node*, int32, Node*); -void nullwarn(Node*, Node*); -void sextern(Sym*, Node*, int32, int32); -void gextern(Sym*, Node*, int32, int32); -void outcode(void); - -/* - * list - */ -void listinit(void); -int Pconv(Fmt*); -int Aconv(Fmt*); -int Dconv(Fmt*); -int Sconv(Fmt*); -int Nconv(Fmt*); -int Bconv(Fmt*); - -/* - * reg.c - */ -Reg* rega(void); -int rcmp(const void*, const void*); -void regopt(Prog*); -void addmove(Reg*, int, int, int); -Bits mkvar(Addr*, int); -void prop(Reg*, Bits, Bits); -void loopit(Reg*, int32); -void synch(Reg*, Bits); -uint32 allreg(uint32, Rgn*); -void paint1(Reg*, int); -uint32 paint2(Reg*, int); -void paint3(Reg*, int, int32, int); -void addreg(Addr*, int); - -/* - * peep.c - */ -void peep(void); -void excise(Reg*); -Reg* uniqp(Reg*); -Reg* uniqs(Reg*); -int regtyp(Addr*); -int regzer(Addr*); -int anyvar(Addr*); -int subprop(Reg*); -int copyprop(Reg*); -int copy1(Addr*, Addr*, Reg*, int); -int copyu(Prog*, Addr*, Addr*); - -int copyas(Addr*, Addr*); -int copyau(Addr*, Addr*); -int copyau1(Prog*, Addr*); -int copysub(Addr*, Addr*, Addr*, int); -int copysub1(Prog*, Addr*, Addr*, int); - -int32 RtoB(int); -int32 FtoB(int); -int BtoR(int32); -int BtoF(int32); - -/* - * com64.c - */ -int com64(Node*); -void com64init(void); -void bool64(Node*); - -#pragma varargck type "A" int -#pragma varargck type "B" Bits -#pragma varargck type "D" Addr* -#pragma varargck type "N" Addr* -#pragma varargck type "P" Prog* -#pragma varargck type "S" char* diff --git a/src/cmd/9c/list.c b/src/cmd/9c/list.c deleted file mode 100644 index 5cfc442cb9..0000000000 --- a/src/cmd/9c/list.c +++ /dev/null @@ -1,37 +0,0 @@ -// cmd/9c/list.c from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#define EXTERN -#include "gc.h" - -void -listinit(void) -{ - listinit9(); -} diff --git a/src/cmd/9c/machcap.c b/src/cmd/9c/machcap.c deleted file mode 100644 index af44bc8204..0000000000 --- a/src/cmd/9c/machcap.c +++ /dev/null @@ -1,105 +0,0 @@ -// cmd/9c/machcap.c from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "gc.h" - -int -machcap(Node *n) -{ - - if(n == Z) - return 1; /* test */ - - switch(n->op) { - case OMUL: - case OLMUL: - case OASMUL: - case OASLMUL: - if(typechlv[n->type->etype]) - return 1; - break; - - case OADD: - case OAND: - case OOR: - case OSUB: - case OXOR: - case OASHL: - case OLSHR: - case OASHR: - if(typechlv[n->left->type->etype]) - return 1; - break; - - case OCAST: - return 1; - - case OCOND: - case OCOMMA: - case OLIST: - case OANDAND: - case OOROR: - case ONOT: - return 1; - - case OASADD: - case OASSUB: - case OASAND: - case OASOR: - case OASXOR: - return 1; - - case OASASHL: - case OASASHR: - case OASLSHR: - return 1; - - case OPOSTINC: - case OPOSTDEC: - case OPREINC: - case OPREDEC: - return 1; - - case OEQ: - case ONE: - case OLE: - case OGT: - case OLT: - case OGE: - case OHI: - case OHS: - case OLO: - case OLS: - return 1; - case ONEG: - case OCOM: - break; - } - return 0; -} diff --git a/src/cmd/9c/mul.c b/src/cmd/9c/mul.c deleted file mode 100644 index 353376f15d..0000000000 --- a/src/cmd/9c/mul.c +++ /dev/null @@ -1,638 +0,0 @@ -// cmd/9c/mul.c from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "gc.h" - -/* - * code sequences for multiply by constant. - * [a-l][0-3] - * lsl $(A-'a'),r0,r1 - * [+][0-7] - * add r0,r1,r2 - * [-][0-7] - * sub r0,r1,r2 - */ - -static int multabp; -static int32 mulval; -static char* mulcp; -static int32 valmax; -static int shmax; - -static int docode(char *hp, char *cp, int r0, int r1); -static int gen1(int len); -static int gen2(int len, int32 r1); -static int gen3(int len, int32 r0, int32 r1, int flag); -enum -{ - SR1 = 1<<0, /* r1 has been shifted */ - SR0 = 1<<1, /* r0 has been shifted */ - UR1 = 1<<2, /* r1 has not been used */ - UR0 = 1<<3, /* r0 has not been used */ -}; - -Multab* -mulcon0(Node *n, int32 v) -{ - int a1, a2, g; - Multab *m, *m1; - char hint[10]; - - if(v < 0) - v = -v; - - /* - * look in cache - */ - m = multab; - for(g=0; gval == v) { - if(m->code[0] == 0) - return 0; - return m; - } - m++; - } - - /* - * select a spot in cache to overwrite - */ - multabp++; - if(multabp < 0 || multabp >= nelem(multab)) - multabp = 0; - m = multab+multabp; - m->val = v; - mulval = v; - - /* - * look in execption hint table - */ - a1 = 0; - a2 = hintabsize; - for(;;) { - if(a1 >= a2) - goto no; - g = (a2 + a1)/2; - if(v < hintab[g].val) { - a2 = g; - continue; - } - if(v > hintab[g].val) { - a1 = g+1; - continue; - } - break; - } - - if(docode(hintab[g].hint, m->code, 1, 0)) - return m; - print("%L: multiply table failure %ld\n", n->lineno, v); - m->code[0] = 0; - return 0; - -no: - /* - * try to search - */ - hint[0] = 0; - for(g=1; g<=6; g++) { - if(g >= 6 && v >= 65535) - break; - mulcp = hint+g; - *mulcp = 0; - if(gen1(g)) { - if(docode(hint, m->code, 1, 0)) - return m; - print("%L: multiply table failure (g=%d h=%s) %ld\n", - n->lineno, g, hint, v); - break; - } - } - - /* - * try a recur followed by a shift - */ - g = 0; - while(!(v & 1)) { - g++; - v >>= 1; - } - if(g) { - m1 = mulcon0(n, v); - if(m1) { - strcpy(m->code, m1->code); - sprint(strchr(m->code, 0), "%c0", g+'a'); - return m; - } - } - m->code[0] = 0; - return 0; -} - -static int -docode(char *hp, char *cp, int r0, int r1) -{ - int c, i; - - c = *hp++; - *cp = c; - cp += 2; - switch(c) { - default: - c -= 'a'; - if(c < 1 || c >= 30) - break; - for(i=0; i<4; i++) { - switch(i) { - case 0: - if(docode(hp, cp, r0<= mulval) - break; - } - if(mulval == 1) - return 1; - - len--; - for(i=1; i<=shmax; i++) - if(gen2(len, 1<= r1 || - r1 > valmax) - return 0; - - len--; - if(len == 0) - goto calcr0; - - if(!(flag & UR1)) { - f1 = UR1|SR1; - for(i=1; i<=shmax; i++) { - x = r0< valmax) - break; - if(gen3(len, r0, x, f1)) { - i += 'a'; - goto out; - } - } - } - - if(!(flag & UR0)) { - f1 = UR1|SR1; - for(i=1; i<=shmax; i++) { - x = r1< valmax) - break; - if(gen3(len, r1, x, f1)) { - i += 'a'; - goto out; - } - } - } - - if(!(flag & SR1)) { - f1 = UR1|SR1|(flag&UR0); - for(i=1; i<=shmax; i++) { - x = r1< valmax) - break; - if(gen3(len, r0, x, f1)) { - i += 'a'; - goto out; - } - } - } - - if(!(flag & SR0)) { - f1 = UR0|SR0|(flag&(SR1|UR1)); - - f2 = UR1|SR1; - if(flag & UR1) - f2 |= UR0; - if(flag & SR1) - f2 |= SR0; - - for(i=1; i<=shmax; i++) { - x = r0< valmax) - break; - if(x > r1) { - if(gen3(len, r1, x, f2)) { - i += 'a'; - goto out; - } - } else - if(gen3(len, x, r1, f1)) { - i += 'a'; - goto out; - } - } - } - - x = r1+r0; - if(gen3(len, r0, x, UR1)) { - i = '+'; - goto out; - } - - if(gen3(len, r1, x, UR1)) { - i = '+'; - goto out; - } - - x = r1-r0; - if(gen3(len, x, r1, UR0)) { - i = '-'; - goto out; - } - - if(x > r0) { - if(gen3(len, r0, x, UR1)) { - i = '-'; - goto out; - } - } else - if(gen3(len, x, r0, UR0)) { - i = '-'; - goto out; - } - - return 0; - -calcr0: - f1 = flag & (UR0|UR1); - if(f1 == UR1) { - for(i=1; i<=shmax; i++) { - x = r1<= mulval) { - if(x == mulval) { - i += 'a'; - goto out; - } - break; - } - } - } - - if(mulval == r1+r0) { - i = '+'; - goto out; - } - if(mulval == r1-r0) { - i = '-'; - goto out; - } - - return 0; - -out: - *--mulcp = i; - return 1; -} - -/* - * hint table has numbers that - * the search algorithm fails on. - * <1000: - * all numbers - * <5000: - * ÷ by 5 - * <10000: - * ÷ by 50 - * <65536: - * ÷ by 250 - */ -Hintab hintab[] = -{ - 683, "b++d+e+", - 687, "b+e++e-", - 691, "b++d+e+", - 731, "b++d+e+", - 811, "b++d+i+", - 821, "b++e+e+", - 843, "b+d++e+", - 851, "b+f-+e-", - 853, "b++e+e+", - 877, "c++++g-", - 933, "b+c++g-", - 981, "c-+e-d+", - 1375, "b+c+b+h-", - 1675, "d+b++h+", - 2425, "c++f-e+", - 2675, "c+d++f-", - 2750, "b+d-b+h-", - 2775, "c-+g-e-", - 3125, "b++e+g+", - 3275, "b+c+g+e+", - 3350, "c++++i+", - 3475, "c-+e-f-", - 3525, "c-+d+g-", - 3625, "c-+e-j+", - 3675, "b+d+d+e+", - 3725, "b+d-+h+", - 3925, "b+d+f-d-", - 4275, "b+g++e+", - 4325, "b+h-+d+", - 4425, "b+b+g-j-", - 4525, "b+d-d+f+", - 4675, "c++d-g+", - 4775, "b+d+b+g-", - 4825, "c+c-+i-", - 4850, "c++++i-", - 4925, "b++e-g-", - 4975, "c+f++e-", - 5500, "b+g-c+d+", - 6700, "d+b++i+", - 9700, "d++++j-", - 11000, "b+f-c-h-", - 11750, "b+d+g+j-", - 12500, "b+c+e-k+", - 13250, "b+d+e-f+", - 13750, "b+h-c-d+", - 14250, "b+g-c+e-", - 14500, "c+f+j-d-", - 14750, "d-g--f+", - 16750, "b+e-d-n+", - 17750, "c+h-b+e+", - 18250, "d+b+h-d+", - 18750, "b+g-++f+", - 19250, "b+e+b+h+", - 19750, "b++h--f-", - 20250, "b+e-l-c+", - 20750, "c++bi+e-", - 21250, "b+i+l+c+", - 22000, "b+e+d-g-", - 22250, "b+d-h+k-", - 22750, "b+d-e-g+", - 23250, "b+c+h+e-", - 23500, "b+g-c-g-", - 23750, "b+g-b+h-", - 24250, "c++g+m-", - 24750, "b+e+e+j-", - 25000, "b++dh+g+", - 25250, "b+e+d-g-", - 25750, "b+e+b+j+", - 26250, "b+h+c+e+", - 26500, "b+h+c+g+", - 26750, "b+d+e+g-", - 27250, "b+e+e+f+", - 27500, "c-i-c-d+", - 27750, "b+bd++j+", - 28250, "d-d-++i-", - 28500, "c+c-h-e-", - 29000, "b+g-d-f+", - 29500, "c+h+++e-", - 29750, "b+g+f-c+", - 30250, "b+f-g-c+", - 33500, "c-f-d-n+", - 33750, "b+d-b+j-", - 34250, "c+e+++i+", - 35250, "e+b+d+k+", - 35500, "c+e+d-g-", - 35750, "c+i-++e+", - 36250, "b+bh-d+e+", - 36500, "c+c-h-e-", - 36750, "d+e--i+", - 37250, "b+g+g+b+", - 37500, "b+h-b+f+", - 37750, "c+be++j-", - 38500, "b+e+b+i+", - 38750, "d+i-b+d+", - 39250, "b+g-l-+d+", - 39500, "b+g-c+g-", - 39750, "b+bh-c+f-", - 40250, "b+bf+d+g-", - 40500, "b+g-c+g+", - 40750, "c+b+i-e+", - 41250, "d++bf+h+", - 41500, "b+j+c+d-", - 41750, "c+f+b+h-", - 42500, "c+h++g+", - 42750, "b+g+d-f-", - 43250, "b+l-e+d-", - 43750, "c+bd+h+f-", - 44000, "b+f+g-d-", - 44250, "b+d-g--f+", - 44500, "c+e+c+h+", - 44750, "b+e+d-h-", - 45250, "b++g+j-g+", - 45500, "c+d+e-g+", - 45750, "b+d-h-e-", - 46250, "c+bd++j+", - 46500, "b+d-c-j-", - 46750, "e-e-b+g-", - 47000, "b+c+d-j-", - 47250, "b+e+e-g-", - 47500, "b+g-c-h-", - 47750, "b+f-c+h-", - 48250, "d--h+n-", - 48500, "b+c-g+m-", - 48750, "b+e+e-g+", - 49500, "c-f+e+j-", - 49750, "c+c+g++f-", - 50000, "b+e+e+k+", - 50250, "b++i++g+", - 50500, "c+g+f-i+", - 50750, "b+e+d+k-", - 51500, "b+i+c-f+", - 51750, "b+bd+g-e-", - 52250, "b+d+g-j+", - 52500, "c+c+f+g+", - 52750, "b+c+e+i+", - 53000, "b+i+c+g+", - 53500, "c+g+g-n+", - 53750, "b+j+d-c+", - 54250, "b+d-g-j-", - 54500, "c-f+e+f+", - 54750, "b+f-+c+g+", - 55000, "b+g-d-g-", - 55250, "b+e+e+g+", - 55500, "b+cd++j+", - 55750, "b+bh-d-f-", - 56250, "c+d-b+j-", - 56500, "c+d+c+i+", - 56750, "b+e+d++h-", - 57000, "b+d+g-f+", - 57250, "b+f-m+d-", - 57750, "b+i+c+e-", - 58000, "b+e+d+h+", - 58250, "c+b+g+g+", - 58750, "d-e-j--e+", - 59000, "d-i-+e+", - 59250, "e--h-m+", - 59500, "c+c-h+f-", - 59750, "b+bh-e+i-", - 60250, "b+bh-e-e-", - 60500, "c+c-g-g-", - 60750, "b+e-l-e-", - 61250, "b+g-g-c+", - 61750, "b+g-c+g+", - 62250, "f--+c-i-", - 62750, "e+f--+g+", - 64750, "b+f+d+p-", -}; -int hintabsize = nelem(hintab); diff --git a/src/cmd/9c/peep.c b/src/cmd/9c/peep.c deleted file mode 100644 index 2e8e2adcc9..0000000000 --- a/src/cmd/9c/peep.c +++ /dev/null @@ -1,1076 +0,0 @@ -// cmd/9c/peep.c from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "gc.h" - -/* -static Reg* -rnops(Reg *r) -{ - Prog *p; - Reg *r1; - - if(r != R) - for(;;){ - p = r->prog; - if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE) - break; - r1 = uniqs(r); - if(r1 == R) - break; - r = r1; - } - return r; -} -*/ - -void -peep(void) -{ - Reg *r, *r1, *r2; - Prog *p, *p1; - int t; -/* - * complete R structure - */ - t = 0; - for(r=firstr; r!=R; r=r1) { - r1 = r->link; - if(r1 == R) - break; - p = r->prog->link; - while(p != r1->prog) - switch(p->as) { - default: - r2 = rega(); - r->link = r2; - r2->link = r1; - - r2->prog = p; - r2->p1 = r; - r->s1 = r2; - r2->s1 = r1; - r1->p1 = r2; - - r = r2; - t++; - - case ADATA: - case AGLOBL: - case ANAME: - case ASIGNAME: - p = p->link; - } - } - -loop1: - t = 0; - for(r=firstr; r!=R; r=r->link) { - p = r->prog; - if(p->as == AMOVW || p->as == AMOVD || p->as == AFMOVS || p->as == AFMOVD) - if(regtyp(&p->to)) { - if(regtyp(&p->from)) - if(p->from.type == p->to.type) { - if(copyprop(r)) { - excise(r); - t++; - } else - if(subprop(r) && copyprop(r)) { - excise(r); - t++; - } - } - if(regzer(&p->from)) - if(p->to.type == D_REG) { - p->from.type = D_REG; - p->from.reg = REGZERO; - if(copyprop(r)) { - excise(r); - t++; - } else - if(subprop(r) && copyprop(r)) { - excise(r); - t++; - } - } - } - } - if(t) - goto loop1; - /* - * look for MOVB x,R; MOVB R,R - */ - for(r=firstr; r!=R; r=r->link) { - p = r->prog; - switch(p->as) { - default: - continue; - case AMOVH: - case AMOVHZ: - case AMOVB: - case AMOVBZ: - case AMOVW: - case AMOVWZ: - if(p->to.type != D_REG) - continue; - break; - } - r1 = r->link; - if(r1 == R) - continue; - p1 = r1->prog; - if(p1->as != p->as) - continue; - if(p1->from.type != D_REG || p1->from.reg != p->to.reg) - continue; - if(p1->to.type != D_REG || p1->to.reg != p->to.reg) - continue; - excise(r1); - } - - if(debug['D'] > 1) - return; /* allow following code improvement to be suppressed */ - - /* - * look for OP x,y,R; CMP R, $0 -> OPCC x,y,R - * when OP can set condition codes correctly - */ - for(r=firstr; r!=R; r=r->link) { - p = r->prog; - switch(p->as) { - case ACMP: - case ACMPW: /* always safe? */ - if(!regzer(&p->to)) - continue; - r1 = r->s1; - if(r1 == R) - continue; - switch(r1->prog->as) { - default: - continue; - case ABCL: - case ABC: - /* the conditions can be complex and these are currently little used */ - continue; - case ABEQ: - case ABGE: - case ABGT: - case ABLE: - case ABLT: - case ABNE: - case ABVC: - case ABVS: - break; - } - r1 = r; - do - r1 = uniqp(r1); - while (r1 != R && r1->prog->as == ANOP); - if(r1 == R) - continue; - p1 = r1->prog; - if(p1->to.type != D_REG || p1->to.reg != p->from.reg) - continue; - switch(p1->as) { - case ASUB: - case AADD: - case AXOR: - case AOR: - /* irregular instructions */ - if(p1->from.type == D_CONST) - continue; - break; - } - switch(p1->as) { - default: - continue; - case AMOVW: - case AMOVD: - if(p1->from.type != D_REG) - continue; - continue; - case AANDCC: - case AANDNCC: - case AORCC: - case AORNCC: - case AXORCC: - case ASUBCC: - case ASUBECC: - case ASUBMECC: - case ASUBZECC: - case AADDCC: - case AADDCCC: - case AADDECC: - case AADDMECC: - case AADDZECC: - case ARLWMICC: - case ARLWNMCC: - t = p1->as; - break; - /* don't deal with floating point instructions for now */ -/* - case AFABS: t = AFABSCC; break; - case AFADD: t = AFADDCC; break; - case AFADDS: t = AFADDSCC; break; - case AFCTIW: t = AFCTIWCC; break; - case AFCTIWZ: t = AFCTIWZCC; break; - case AFDIV: t = AFDIVCC; break; - case AFDIVS: t = AFDIVSCC; break; - case AFMADD: t = AFMADDCC; break; - case AFMADDS: t = AFMADDSCC; break; - case AFMOVD: t = AFMOVDCC; break; - case AFMSUB: t = AFMSUBCC; break; - case AFMSUBS: t = AFMSUBSCC; break; - case AFMUL: t = AFMULCC; break; - case AFMULS: t = AFMULSCC; break; - case AFNABS: t = AFNABSCC; break; - case AFNEG: t = AFNEGCC; break; - case AFNMADD: t = AFNMADDCC; break; - case AFNMADDS: t = AFNMADDSCC; break; - case AFNMSUB: t = AFNMSUBCC; break; - case AFNMSUBS: t = AFNMSUBSCC; break; - case AFRSP: t = AFRSPCC; break; - case AFSUB: t = AFSUBCC; break; - case AFSUBS: t = AFSUBSCC; break; - case ACNTLZW: t = ACNTLZWCC; break; - case AMTFSB0: t = AMTFSB0CC; break; - case AMTFSB1: t = AMTFSB1CC; break; -*/ - case AADD: t = AADDCC; break; - case AADDV: t = AADDVCC; break; - case AADDC: t = AADDCCC; break; - case AADDCV: t = AADDCVCC; break; - case AADDME: t = AADDMECC; break; - case AADDMEV: t = AADDMEVCC; break; - case AADDE: t = AADDECC; break; - case AADDEV: t = AADDEVCC; break; - case AADDZE: t = AADDZECC; break; - case AADDZEV: t = AADDZEVCC; break; - case AAND: t = AANDCC; break; - case AANDN: t = AANDNCC; break; - case ADIVW: t = ADIVWCC; break; - case ADIVWV: t = ADIVWVCC; break; - case ADIVWU: t = ADIVWUCC; break; - case ADIVWUV: t = ADIVWUVCC; break; - case ADIVD: t = ADIVDCC; break; - case ADIVDV: t = ADIVDVCC; break; - case ADIVDU: t = ADIVDUCC; break; - case ADIVDUV: t = ADIVDUVCC; break; - case AEQV: t = AEQVCC; break; - case AEXTSB: t = AEXTSBCC; break; - case AEXTSH: t = AEXTSHCC; break; - case AEXTSW: t = AEXTSWCC; break; - case AMULHW: t = AMULHWCC; break; - case AMULHWU: t = AMULHWUCC; break; - case AMULLW: t = AMULLWCC; break; - case AMULLWV: t = AMULLWVCC; break; - case AMULHD: t = AMULHDCC; break; - case AMULHDU: t = AMULHDUCC; break; - case AMULLD: t = AMULLDCC; break; - case AMULLDV: t = AMULLDVCC; break; - case ANAND: t = ANANDCC; break; - case ANEG: t = ANEGCC; break; - case ANEGV: t = ANEGVCC; break; - case ANOR: t = ANORCC; break; - case AOR: t = AORCC; break; - case AORN: t = AORNCC; break; - case AREM: t = AREMCC; break; - case AREMV: t = AREMVCC; break; - case AREMU: t = AREMUCC; break; - case AREMUV: t = AREMUVCC; break; - case AREMD: t = AREMDCC; break; - case AREMDV: t = AREMDVCC; break; - case AREMDU: t = AREMDUCC; break; - case AREMDUV: t = AREMDUVCC; break; - case ARLWMI: t = ARLWMICC; break; - case ARLWNM: t = ARLWNMCC; break; - case ASLW: t = ASLWCC; break; - case ASRAW: t = ASRAWCC; break; - case ASRW: t = ASRWCC; break; - case ASLD: t = ASLDCC; break; - case ASRAD: t = ASRADCC; break; - case ASRD: t = ASRDCC; break; - case ASUB: t = ASUBCC; break; - case ASUBV: t = ASUBVCC; break; - case ASUBC: t = ASUBCCC; break; - case ASUBCV: t = ASUBCVCC; break; - case ASUBME: t = ASUBMECC; break; - case ASUBMEV: t = ASUBMEVCC; break; - case ASUBE: t = ASUBECC; break; - case ASUBEV: t = ASUBEVCC; break; - case ASUBZE: t = ASUBZECC; break; - case ASUBZEV: t = ASUBZEVCC; break; - case AXOR: t = AXORCC; break; - break; - } - if(debug['D']) - print("cmp %P; %P -> ", p1, p); - p1->as = t; - if(debug['D']) - print("%P\n", p1); - excise(r); - continue; - } - } -} - -void -excise(Reg *r) -{ - Prog *p; - - p = r->prog; - p->as = ANOP; - p->from = zprog.from; - p->from3 = zprog.from3; - p->to = zprog.to; - p->reg = zprog.reg; /**/ -} - -Reg* -uniqp(Reg *r) -{ - Reg *r1; - - r1 = r->p1; - if(r1 == R) { - r1 = r->p2; - if(r1 == R || r1->p2link != R) - return R; - } else - if(r->p2 != R) - return R; - return r1; -} - -Reg* -uniqs(Reg *r) -{ - Reg *r1; - - r1 = r->s1; - if(r1 == R) { - r1 = r->s2; - if(r1 == R) - return R; - } else - if(r->s2 != R) - return R; - return r1; -} - -/* - * if the system forces R0 to be zero, - * convert references to $0 to references to R0. - */ -int -regzer(Addr *a) -{ - if(R0ISZERO) { - if(a->type == D_CONST) - if(a->sym == nil) - if(a->offset == 0) - return 1; - if(a->type == D_REG) - if(a->reg == REGZERO) - return 1; - } - return 0; -} - -int -regtyp(Addr *a) -{ - - if(a->type == D_REG) { - if(!R0ISZERO || a->reg != REGZERO) - return 1; - return 0; - } - if(a->type == D_FREG) - return 1; - return 0; -} - -/* - * the idea is to substitute - * one register for another - * from one MOV to another - * MOV a, R0 - * ADD b, R0 / no use of R1 - * MOV R0, R1 - * would be converted to - * MOV a, R1 - * ADD b, R1 - * MOV R1, R0 - * hopefully, then the former or latter MOV - * will be eliminated by copy propagation. - */ -int -subprop(Reg *r0) -{ - Prog *p; - Addr *v1, *v2; - Reg *r; - int t; - - p = r0->prog; - v1 = &p->from; - if(!regtyp(v1)) - return 0; - v2 = &p->to; - if(!regtyp(v2)) - return 0; - for(r=uniqp(r0); r!=R; r=uniqp(r)) { - if(uniqs(r) == R) - break; - p = r->prog; - switch(p->as) { - case ABL: - return 0; - - case AADD: - case AADDC: - case AADDCC: - case AADDE: - case AADDECC: - case ASUB: - case ASUBCC: - case ASUBC: - case ASUBCCC: - case ASUBE: - case ASUBECC: - case ASLW: - case ASRW: - case ASRWCC: - case ASRAW: - case ASRAWCC: - case ASLD: - case ASRD: - case ASRAD: - case AOR: - case AORCC: - case AORN: - case AORNCC: - case AAND: - case AANDCC: - case AANDN: - case AANDNCC: - case ANAND: - case ANANDCC: - case ANOR: - case ANORCC: - case AXOR: - case AXORCC: - case AMULHW: - case AMULHWU: - case AMULLW: - case AMULLD: - case ADIVW: - case ADIVWU: - case ADIVD: - case ADIVDU: - case AREM: - case AREMU: - case AREMD: - case AREMDU: - case ARLWNM: - case ARLWNMCC: - - case AFADD: - case AFADDS: - case AFSUB: - case AFSUBS: - case AFMUL: - case AFMULS: - case AFDIV: - case AFDIVS: - if(p->to.type == v1->type) - if(p->to.reg == v1->reg) { - if(p->reg == NREG) - p->reg = p->to.reg; - goto gotit; - } - break; - - case AADDME: - case AADDMECC: - case AADDZE: - case AADDZECC: - case ASUBME: - case ASUBMECC: - case ASUBZE: - case ASUBZECC: - case ANEG: - case ANEGCC: - case AFNEG: - case AFNEGCC: - case AFMOVS: - case AFMOVD: - case AMOVW: - case AMOVD: - if(p->to.type == v1->type) - if(p->to.reg == v1->reg) - goto gotit; - break; - } - if(copyau(&p->from, v2) || - copyau1(p, v2) || - copyau(&p->to, v2)) - break; - if(copysub(&p->from, v1, v2, 0) || - copysub1(p, v1, v2, 0) || - copysub(&p->to, v1, v2, 0)) - break; - } - return 0; - -gotit: - copysub(&p->to, v1, v2, 1); - if(debug['P']) { - print("gotit: %D->%D\n%P", v1, v2, r->prog); - if(p->from.type == v2->type) - print(" excise"); - print("\n"); - } - for(r=uniqs(r); r!=r0; r=uniqs(r)) { - p = r->prog; - copysub(&p->from, v1, v2, 1); - copysub1(p, v1, v2, 1); - copysub(&p->to, v1, v2, 1); - if(debug['P']) - print("%P\n", r->prog); - } - t = v1->reg; - v1->reg = v2->reg; - v2->reg = t; - if(debug['P']) - print("%P last\n", r->prog); - return 1; -} - -/* - * The idea is to remove redundant copies. - * v1->v2 F=0 - * (use v2 s/v2/v1/)* - * set v1 F=1 - * use v2 return fail - * ----------------- - * v1->v2 F=0 - * (use v2 s/v2/v1/)* - * set v1 F=1 - * set v2 return success - */ -int -copyprop(Reg *r0) -{ - Prog *p; - Addr *v1, *v2; - Reg *r; - - p = r0->prog; - v1 = &p->from; - v2 = &p->to; - if(copyas(v1, v2)) - return 1; - for(r=firstr; r!=R; r=r->link) - r->active = 0; - return copy1(v1, v2, r0->s1, 0); -} - -int -copy1(Addr *v1, Addr *v2, Reg *r, int f) -{ - int t; - Prog *p; - - if(r->active) { - if(debug['P']) - print("act set; return 1\n"); - return 1; - } - r->active = 1; - if(debug['P']) - print("copy %D->%D f=%d\n", v1, v2, f); - for(; r != R; r = r->s1) { - p = r->prog; - if(debug['P']) - print("%P", p); - if(!f && uniqp(r) == R) { - f = 1; - if(debug['P']) - print("; merge; f=%d", f); - } - t = copyu(p, v2, nil); - switch(t) { - case 2: /* rar, cant split */ - if(debug['P']) - print("; %Drar; return 0\n", v2); - return 0; - - case 3: /* set */ - if(debug['P']) - print("; %Dset; return 1\n", v2); - return 1; - - case 1: /* used, substitute */ - case 4: /* use and set */ - if(f) { - if(!debug['P']) - return 0; - if(t == 4) - print("; %Dused+set and f=%d; return 0\n", v2, f); - else - print("; %Dused and f=%d; return 0\n", v2, f); - return 0; - } - if(copyu(p, v2, v1)) { - if(debug['P']) - print("; sub fail; return 0\n"); - return 0; - } - if(debug['P']) - print("; sub%D/%D", v2, v1); - if(t == 4) { - if(debug['P']) - print("; %Dused+set; return 1\n", v2); - return 1; - } - break; - } - if(!f) { - t = copyu(p, v1, nil); - if(!f && (t == 2 || t == 3 || t == 4)) { - f = 1; - if(debug['P']) - print("; %Dset and !f; f=%d", v1, f); - } - } - if(debug['P']) - print("\n"); - if(r->s2) - if(!copy1(v1, v2, r->s2, f)) - return 0; - } - return 1; -} - -/* - * return - * 1 if v only used (and substitute), - * 2 if read-alter-rewrite - * 3 if set - * 4 if set and used - * 0 otherwise (not touched) - */ -int -copyu(Prog *p, Addr *v, Addr *s) -{ - - switch(p->as) { - - default: - if(debug['P']) - print(" (\?\?\?)"); - return 2; - - - case ANOP: /* read, write */ - case AMOVH: - case AMOVHZ: - case AMOVB: - case AMOVBZ: - case AMOVW: - case AMOVWZ: - case AMOVD: - - case ANEG: - case ANEGCC: - case AADDME: - case AADDMECC: - case AADDZE: - case AADDZECC: - case ASUBME: - case ASUBMECC: - case ASUBZE: - case ASUBZECC: - - case AFCTIW: - case AFCTIWZ: - case AFMOVS: - case AFMOVD: - case AFRSP: - case AFNEG: - case AFNEGCC: - if(s != nil) { - if(copysub(&p->from, v, s, 1)) - return 1; - if(!copyas(&p->to, v)) - if(copysub(&p->to, v, s, 1)) - return 1; - return 0; - } - if(copyas(&p->to, v)) { - if(copyau(&p->from, v)) - return 4; - return 3; - } - if(copyau(&p->from, v)) - return 1; - if(copyau(&p->to, v)) - return 1; - return 0; - - case ARLWMI: /* read read rar */ - case ARLWMICC: - if(copyas(&p->to, v)) - return 2; - /* fall through */ - - case AADD: /* read read write */ - case AADDC: - case AADDE: - case ASUB: - case ASLW: - case ASRW: - case ASRAW: - case ASLD: - case ASRD: - case ASRAD: - case AOR: - case AORCC: - case AORN: - case AORNCC: - case AAND: - case AANDCC: - case AANDN: - case AANDNCC: - case ANAND: - case ANANDCC: - case ANOR: - case ANORCC: - case AXOR: - case AMULHW: - case AMULHWU: - case AMULLW: - case AMULLD: - case ADIVW: - case ADIVD: - case ADIVWU: - case ADIVDU: - case AREM: - case AREMU: - case AREMD: - case AREMDU: - case ARLWNM: - case ARLWNMCC: - - case AFADDS: - case AFADD: - case AFSUBS: - case AFSUB: - case AFMULS: - case AFMUL: - case AFDIVS: - case AFDIV: - if(s != nil) { - if(copysub(&p->from, v, s, 1)) - return 1; - if(copysub1(p, v, s, 1)) - return 1; - if(!copyas(&p->to, v)) - if(copysub(&p->to, v, s, 1)) - return 1; - return 0; - } - if(copyas(&p->to, v)) { - if(p->reg == NREG) - p->reg = p->to.reg; - if(copyau(&p->from, v)) - return 4; - if(copyau1(p, v)) - return 4; - return 3; - } - if(copyau(&p->from, v)) - return 1; - if(copyau1(p, v)) - return 1; - if(copyau(&p->to, v)) - return 1; - return 0; - - case ABEQ: - case ABGT: - case ABGE: - case ABLT: - case ABLE: - case ABNE: - case ABVC: - case ABVS: - break; - - case ACMP: /* read read */ - case ACMPU: - case ACMPW: - case ACMPWU: - case AFCMPO: - case AFCMPU: - if(s != nil) { - if(copysub(&p->from, v, s, 1)) - return 1; - return copysub(&p->to, v, s, 1); - } - if(copyau(&p->from, v)) - return 1; - if(copyau(&p->to, v)) - return 1; - break; - - case ABR: /* funny */ - if(s != nil) { - if(copysub(&p->to, v, s, 1)) - return 1; - return 0; - } - if(copyau(&p->to, v)) - return 1; - return 0; - - case ARETURN: /* funny */ - if(v->type == D_REG) - if(v->reg == REGRET) - return 2; - if(v->type == D_FREG) - if(v->reg == FREGRET) - return 2; - - case ABL: /* funny */ - if(v->type == D_REG) { - if(v->reg <= REGEXT && v->reg > exregoffset) - return 2; - if(v->reg == REGARG) - return 2; - } - if(v->type == D_FREG) { - if(v->reg <= FREGEXT && v->reg > exfregoffset) - return 2; - } - - if(s != nil) { - if(copysub(&p->to, v, s, 1)) - return 1; - return 0; - } - if(copyau(&p->to, v)) - return 4; - return 3; - - case ATEXT: /* funny */ - if(v->type == D_REG) - if(v->reg == REGARG) - return 3; - return 0; - } - return 0; -} - -int -a2type(Prog *p) -{ - - switch(p->as) { - case AADD: - case AADDC: - case AADDCC: - case AADDCCC: - case AADDE: - case AADDECC: - case AADDME: - case AADDMECC: - case AADDZE: - case AADDZECC: - case ASUB: - case ASUBC: - case ASUBCC: - case ASUBCCC: - case ASUBE: - case ASUBECC: - case ASUBME: - case ASUBMECC: - case ASUBZE: - case ASUBZECC: - case ASLW: - case ASLWCC: - case ASRW: - case ASRWCC: - case ASRAW: - case ASRAWCC: - case ASLD: - case ASLDCC: - case ASRD: - case ASRDCC: - case ASRAD: - case ASRADCC: - case AOR: - case AORCC: - case AORN: - case AORNCC: - case AAND: - case AANDCC: - case AANDN: - case AANDNCC: - case AXOR: - case AXORCC: - case ANEG: - case ANEGCC: - case AMULHW: - case AMULHWU: - case AMULLW: - case AMULLWCC: - case ADIVW: - case ADIVWCC: - case ADIVWU: - case ADIVWUCC: - case AREM: - case AREMCC: - case AREMU: - case AREMUCC: - case AMULLD: - case AMULLDCC: - case ADIVD: - case ADIVDCC: - case ADIVDU: - case ADIVDUCC: - case AREMD: - case AREMDCC: - case AREMDU: - case AREMDUCC: - case ANAND: - case ANANDCC: - case ANOR: - case ANORCC: - case ARLWMI: - case ARLWMICC: - case ARLWNM: - case ARLWNMCC: - return D_REG; - - case AFADDS: - case AFADDSCC: - case AFADD: - case AFADDCC: - case AFSUBS: - case AFSUBSCC: - case AFSUB: - case AFSUBCC: - case AFMULS: - case AFMULSCC: - case AFMUL: - case AFMULCC: - case AFDIVS: - case AFDIVSCC: - case AFDIV: - case AFDIVCC: - case AFNEG: - case AFNEGCC: - return D_FREG; - } - return D_NONE; -} - -/* - * direct reference, - * could be set/use depending on - * semantics - */ -int -copyas(Addr *a, Addr *v) -{ - - if(regtyp(v)) - if(a->type == v->type) - if(a->reg == v->reg) - return 1; - return 0; -} - -/* - * either direct or indirect - */ -int -copyau(Addr *a, Addr *v) -{ - - if(copyas(a, v)) - return 1; - if(v->type == D_REG) - if(a->type == D_OREG) - if(v->reg == a->reg) - return 1; - return 0; -} - -int -copyau1(Prog *p, Addr *v) -{ - - if(regtyp(v)) - if(p->from.type == v->type || p->to.type == v->type) - if(p->reg == v->reg) { - if(a2type(p) != v->type) - print("botch a2type %P\n", p); - return 1; - } - return 0; -} - -/* - * substitute s for v in a - * return failure to substitute - */ -int -copysub(Addr *a, Addr *v, Addr *s, int f) -{ - - if(f) - if(copyau(a, v)) - a->reg = s->reg; - return 0; -} - -int -copysub1(Prog *p1, Addr *v, Addr *s, int f) -{ - - if(f) - if(copyau1(p1, v)) - p1->reg = s->reg; - return 0; -} diff --git a/src/cmd/9c/reg.c b/src/cmd/9c/reg.c deleted file mode 100644 index 81a7c7fe4a..0000000000 --- a/src/cmd/9c/reg.c +++ /dev/null @@ -1,1163 +0,0 @@ -// cmd/9c/reg.c from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "gc.h" - -Reg* -rega(void) -{ - Reg *r; - - r = freer; - if(r == R) { - r = alloc(sizeof(*r)); - } else - freer = r->link; - - *r = zreg; - return r; -} - -int -rcmp(const void *a1, const void *a2) -{ - const Rgn *p1, *p2; - int c1, c2; - - p1 = a1; - p2 = a2; - c1 = p2->cost; - c2 = p1->cost; - if(c1 -= c2) - return c1; - return p2->varno - p1->varno; -} - -void -regopt(Prog *p) -{ - Reg *r, *r1, *r2; - Prog *p1; - int i, z; - int32 initpc, val, npc; - uint32 vreg; - Bits bit; - struct - { - int32 m; - int32 c; - Reg* p; - } log5[6], *lp; - - firstr = R; - lastr = R; - nvar = 0; - regbits = 0; - for(z=0; zm = val; - lp->c = 0; - lp->p = R; - val /= 5L; - lp++; - } - val = 0; - for(; p != P; p = p->link) { - switch(p->as) { - case ADATA: - case AGLOBL: - case ANAME: - case ASIGNAME: - case AFUNCDATA: - continue; - } - r = rega(); - if(firstr == R) { - firstr = r; - lastr = r; - } else { - lastr->link = r; - r->p1 = lastr; - lastr->s1 = r; - lastr = r; - } - r->prog = p; - r->pc = val; - val++; - - lp = log5; - for(i=0; i<5; i++) { - lp->c--; - if(lp->c <= 0) { - lp->c = lp->m; - if(lp->p != R) - lp->p->log5 = r; - lp->p = r; - (lp+1)->c = 0; - break; - } - lp++; - } - - r1 = r->p1; - if(r1 != R) - switch(r1->prog->as) { - case ARETURN: - case ABR: - case ARFI: - case ARFCI: - case ARFID: - r->p1 = R; - r1->s1 = R; - } - - /* - * left side always read - */ - bit = mkvar(&p->from, p->as==AMOVW || p->as == AMOVWZ || p->as == AMOVD); - for(z=0; zuse1.b[z] |= bit.b[z]; - - /* - * right side depends on opcode - */ - bit = mkvar(&p->to, 0); - if(bany(&bit)) - switch(p->as) { - default: - diag(Z, "reg: unknown asop: %A", p->as); - break; - - /* - * right side write - */ - case ANOP: - case AMOVB: - case AMOVBU: - case AMOVBZ: - case AMOVBZU: - case AMOVH: - case AMOVHBR: - case AMOVWBR: - case AMOVHU: - case AMOVHZ: - case AMOVHZU: - case AMOVW: - case AMOVWU: - case AMOVWZ: - case AMOVWZU: - case AMOVD: - case AMOVDU: - case AFMOVD: - case AFMOVDCC: - case AFMOVDU: - case AFMOVS: - case AFMOVSU: - case AFRSP: - for(z=0; zset.b[z] |= bit.b[z]; - break; - - /* - * funny - */ - case ABL: - for(z=0; zlink) { - p = r->prog; - if(p->to.type == D_BRANCH) { - val = p->to.offset - initpc; - r1 = firstr; - while(r1 != R) { - r2 = r1->log5; - if(r2 != R && val >= r2->pc) { - r1 = r2; - continue; - } - if(r1->pc == val) - break; - r1 = r1->link; - } - if(r1 == R) { - nearln = p->lineno; - diag(Z, "ref not found\n%P", p); - continue; - } - if(r1 == r) { - nearln = p->lineno; - diag(Z, "ref to self\n%P", p); - continue; - } - r->s2 = r1; - r->p2link = r1->p2; - r1->p2 = r; - } - } - if(debug['R']) { - p = firstr->prog; - print("\n%L %D\n", p->lineno, &p->from); - } - - /* - * pass 2.5 - * find looping structure - */ - for(r = firstr; r != R; r = r->link) - r->active = 0; - change = 0; - loopit(firstr, npc); - if(debug['R'] && debug['v']) { - print("\nlooping structure:\n"); - for(r = firstr; r != R; r = r->link) { - print("%ld:%P", r->loop, r->prog); - for(z=0; zuse1.b[z] | - r->use2.b[z] | r->set.b[z]; - if(bany(&bit)) { - print("\t"); - if(bany(&r->use1)) - print(" u1=%B", r->use1); - if(bany(&r->use2)) - print(" u2=%B", r->use2); - if(bany(&r->set)) - print(" st=%B", r->set); - } - print("\n"); - } - } - - /* - * pass 3 - * iterate propagating usage - * back until flow graph is complete - */ -loop1: - change = 0; - for(r = firstr; r != R; r = r->link) - r->active = 0; - for(r = firstr; r != R; r = r->link) - if(r->prog->as == ARETURN) - prop(r, zbits, zbits); -loop11: - /* pick up unreachable code */ - i = 0; - for(r = firstr; r != R; r = r1) { - r1 = r->link; - if(r1 && r1->active && !r->active) { - prop(r, zbits, zbits); - i = 1; - } - } - if(i) - goto loop11; - if(change) - goto loop1; - - - /* - * pass 4 - * iterate propagating register/variable synchrony - * forward until graph is complete - */ -loop2: - change = 0; - for(r = firstr; r != R; r = r->link) - r->active = 0; - synch(firstr, zbits); - if(change) - goto loop2; - - - /* - * pass 5 - * isolate regions - * calculate costs (paint1) - */ - r = firstr; - if(r) { - for(z=0; zrefahead.b[z] | r->calahead.b[z]) & - ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]); - if(bany(&bit)) { - nearln = r->prog->lineno; - warn(Z, "used and not set: %B", bit); - if(debug['R'] && !debug['w']) - print("used and not set: %B\n", bit); - } - } - if(debug['R'] && debug['v']) - print("\nprop structure:\n"); - for(r = firstr; r != R; r = r->link) - r->act = zbits; - rgp = region; - nregion = 0; - for(r = firstr; r != R; r = r->link) { - if(debug['R'] && debug['v']) - print("%P\n set = %B; rah = %B; cal = %B\n", - r->prog, r->set, r->refahead, r->calahead); - for(z=0; zset.b[z] & - ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]); - if(bany(&bit)) { - nearln = r->prog->lineno; - warn(Z, "set and not used: %B", bit); - if(debug['R']) - print("set an not used: %B\n", bit); - excise(r); - } - for(z=0; zact.b[z] | addrs.b[z]); - while(bany(&bit)) { - i = bnum(bit); - rgp->enter = r; - rgp->varno = i; - change = 0; - if(debug['R'] && debug['v']) - print("\n"); - paint1(r, i); - bit.b[i/32] &= ~(1L<<(i%32)); - if(change <= 0) { - if(debug['R']) - print("%L$%d: %B\n", - r->prog->lineno, change, blsh(i)); - continue; - } - rgp->cost = change; - nregion++; - if(nregion >= NRGN) - fatal(Z, "too many regions"); - rgp++; - } - } - qsort(region, nregion, sizeof(region[0]), rcmp); - - /* - * pass 6 - * determine used registers (paint2) - * replace code (paint3) - */ - rgp = region; - for(i=0; ivarno); - vreg = paint2(rgp->enter, rgp->varno); - vreg = allreg(vreg, rgp); - if(debug['R']) { - if(rgp->regno >= NREG) - print("%L$%d F%d: %B\n", - rgp->enter->prog->lineno, - rgp->cost, - rgp->regno-NREG, - bit); - else - print("%L$%d R%d: %B\n", - rgp->enter->prog->lineno, - rgp->cost, - rgp->regno, - bit); - } - if(rgp->regno != 0) - paint3(rgp->enter, rgp->varno, vreg, rgp->regno); - rgp++; - } - /* - * pass 7 - * peep-hole on basic block - */ - if(!debug['R'] || debug['P']) - peep(); - - /* - * pass 8 - * recalculate pc - */ - val = initpc; - for(r = firstr; r != R; r = r1) { - r->pc = val; - p = r->prog; - p1 = P; - r1 = r->link; - if(r1 != R) - p1 = r1->prog; - for(; p != p1; p = p->link) { - switch(p->as) { - default: - val++; - break; - - case ANOP: - case ADATA: - case AGLOBL: - case ANAME: - case ASIGNAME: - case AFUNCDATA: - break; - } - } - } - pc = val; - - /* - * fix up branches - */ - if(debug['R']) - if(bany(&addrs)) - print("addrs: %B\n", addrs); - - r1 = 0; /* set */ - for(r = firstr; r != R; r = r->link) { - p = r->prog; - if(p->to.type == D_BRANCH) { - p->to.offset = r->s2->pc; - p->to.u.branch = r->s2->prog; - } - r1 = r; - } - - /* - * last pass - * eliminate nops - * free aux structures - */ - for(p = firstr->prog; p != P; p = p->link){ - while(p->link && p->link->as == ANOP) - p->link = p->link->link; - } - if(r1 != R) { - r1->link = freer; - freer = firstr; - } -} - -/* - * add mov b,rn - * just after r - */ -void -addmove(Reg *r, int bn, int rn, int f) -{ - Prog *p, *p1; - Addr *a; - Var *v; - - p1 = alloc(sizeof(*p1)); - *p1 = zprog; - p = r->prog; - - p1->link = p->link; - p->link = p1; - p1->lineno = p->lineno; - - v = var + bn; - - a = &p1->to; - a->sym = v->sym; - a->name = v->name; - a->offset = v->offset; - a->etype = v->etype; - a->type = D_OREG; - if(a->etype == TARRAY || a->sym == nil) - a->type = D_CONST; - - p1->as = AMOVW; - if(v->etype == TCHAR || v->etype == TUCHAR) - p1->as = AMOVB; - if(v->etype == TSHORT || v->etype == TUSHORT) - p1->as = AMOVH; - if(v->etype == TVLONG || v->etype == TUVLONG || v->etype == TIND) - p1->as = AMOVD; - if(v->etype == TFLOAT) - p1->as = AFMOVS; - if(v->etype == TDOUBLE) - p1->as = AFMOVD; - - p1->from.type = D_REG; - p1->from.reg = rn; - if(rn >= NREG) { - p1->from.type = D_FREG; - p1->from.reg = rn-NREG; - } - if(!f) { - p1->from = *a; - *a = zprog.from; - a->type = D_REG; - a->reg = rn; - if(rn >= NREG) { - a->type = D_FREG; - a->reg = rn-NREG; - } - if(v->etype == TUCHAR) - p1->as = AMOVBZ; - if(v->etype == TUSHORT) - p1->as = AMOVHZ; - if(v->etype == TUINT || v->etype == TULONG) - p1->as = AMOVWZ; - } - if(debug['R']) - print("%P\t.a%P\n", p, p1); -} - -Bits -mkvar(Addr *a, int docon) -{ - Var *v; - int i, t, n, et, z; - int64 o; - Bits bit; - LSym *s; - - t = a->type; - if(t == D_REG && a->reg != NREG) - regbits |= RtoB(a->reg); - if(t == D_FREG && a->reg != NREG) - regbits |= FtoB(a->reg); - s = a->sym; - o = a->offset; - et = a->etype; - if(s == nil) { - if(t != D_CONST || !docon || a->reg != NREG) - goto none; - et = TLONG; - } - if(t == D_CONST) { - if(s == nil && sval(o)) - goto none; - } - n = a->name; - v = var; - for(i=0; isym) - if(n == v->name) - if(o == v->offset) - goto out; - v++; - } - if(s) - if(s->name[0] == '.') - goto none; - if(nvar >= NVAR) - fatal(Z, "variable not optimized: %s", s->name); - i = nvar; - nvar++; - v = &var[i]; - v->sym = s; - v->offset = o; - v->etype = et; - v->name = n; - if(debug['R']) - print("bit=%2d et=%2d %D\n", i, et, a); -out: - bit = blsh(i); - if(n == D_EXTERN || n == D_STATIC) - for(z=0; zetype != et || !(typechlpfd[et] || typev[et])) /* funny punning */ - for(z=0; zetype = TVLONG; - if(s == nil) { - for(z=0; zp1) { - for(z=0; zrefahead.b[z]; - if(ref.b[z] != r1->refahead.b[z]) { - r1->refahead.b[z] = ref.b[z]; - change++; - } - cal.b[z] |= r1->calahead.b[z]; - if(cal.b[z] != r1->calahead.b[z]) { - r1->calahead.b[z] = cal.b[z]; - change++; - } - } - switch(r1->prog->as) { - case ABL: - for(z=0; zset.b[z]) | - r1->use1.b[z] | r1->use2.b[z]; - cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]); - r1->refbehind.b[z] = ref.b[z]; - r1->calbehind.b[z] = cal.b[z]; - } - if(r1->active) - break; - r1->active = 1; - } - for(; r != r1; r = r->p1) - for(r2 = r->p2; r2 != R; r2 = r2->p2link) - prop(r2, r->refbehind, r->calbehind); -} - -/* - * find looping structure - * - * 1) find reverse postordering - * 2) find approximate dominators, - * the actual dominators if the flow graph is reducible - * otherwise, dominators plus some other non-dominators. - * See Matthew S. Hecht and Jeffrey D. Ullman, - * "Analysis of a Simple Algorithm for Global Data Flow Problems", - * Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts, - * Oct. 1-3, 1973, pp. 207-217. - * 3) find all nodes with a predecessor dominated by the current node. - * such a node is a loop head. - * recursively, all preds with a greater rpo number are in the loop - */ -int32 -postorder(Reg *r, Reg **rpo2r, int32 n) -{ - Reg *r1; - - r->rpo = 1; - r1 = r->s1; - if(r1 && !r1->rpo) - n = postorder(r1, rpo2r, n); - r1 = r->s2; - if(r1 && !r1->rpo) - n = postorder(r1, rpo2r, n); - rpo2r[n] = r; - n++; - return n; -} - -int32 -rpolca(int32 *idom, int32 rpo1, int32 rpo2) -{ - int32 t; - - if(rpo1 == -1) - return rpo2; - while(rpo1 != rpo2){ - if(rpo1 > rpo2){ - t = rpo2; - rpo2 = rpo1; - rpo1 = t; - } - while(rpo1 < rpo2){ - t = idom[rpo2]; - if(t >= rpo2) - fatal(Z, "bad idom"); - rpo2 = t; - } - } - return rpo1; -} - -int -doms(int32 *idom, int32 r, int32 s) -{ - while(s > r) - s = idom[s]; - return s == r; -} - -int -loophead(int32 *idom, Reg *r) -{ - int32 src; - - src = r->rpo; - if(r->p1 != R && doms(idom, src, r->p1->rpo)) - return 1; - for(r = r->p2; r != R; r = r->p2link) - if(doms(idom, src, r->rpo)) - return 1; - return 0; -} - -void -loopmark(Reg **rpo2r, int32 head, Reg *r) -{ - if(r->rpo < head || r->active == head) - return; - r->active = head; - r->loop += LOOP; - if(r->p1 != R) - loopmark(rpo2r, head, r->p1); - for(r = r->p2; r != R; r = r->p2link) - loopmark(rpo2r, head, r); -} - -void -loopit(Reg *r, int32 nr) -{ - Reg *r1; - int32 i, d, me; - - if(nr > maxnr) { - rpo2r = alloc(nr * sizeof(Reg*)); - idom = alloc(nr * sizeof(int32)); - maxnr = nr; - } - - d = postorder(r, rpo2r, 0); - if(d > nr) - fatal(Z, "too many reg nodes"); - nr = d; - for(i = 0; i < nr / 2; i++){ - r1 = rpo2r[i]; - rpo2r[i] = rpo2r[nr - 1 - i]; - rpo2r[nr - 1 - i] = r1; - } - for(i = 0; i < nr; i++) - rpo2r[i]->rpo = i; - - idom[0] = 0; - for(i = 0; i < nr; i++){ - r1 = rpo2r[i]; - me = r1->rpo; - d = -1; - if(r1->p1 != R && r1->p1->rpo < me) - d = r1->p1->rpo; - for(r1 = r1->p2; r1 != nil; r1 = r1->p2link) - if(r1->rpo < me) - d = rpolca(idom, d, r1->rpo); - idom[i] = d; - } - - for(i = 0; i < nr; i++){ - r1 = rpo2r[i]; - r1->loop++; - if(r1->p2 != R && loophead(idom, r1)) - loopmark(rpo2r, i, r1); - } -} - -void -synch(Reg *r, Bits dif) -{ - Reg *r1; - int z; - - for(r1 = r; r1 != R; r1 = r1->s1) { - for(z=0; zrefbehind.b[z] & r1->refahead.b[z])) | - r1->set.b[z] | r1->regdiff.b[z]; - if(dif.b[z] != r1->regdiff.b[z]) { - r1->regdiff.b[z] = dif.b[z]; - change++; - } - } - if(r1->active) - break; - r1->active = 1; - for(z=0; zcalbehind.b[z] & r1->calahead.b[z]); - if(r1->s2 != R) - synch(r1->s2, dif); - } -} - -uint32 -allreg(uint32 b, Rgn *r) -{ - Var *v; - int i; - - v = var + r->varno; - r->regno = 0; - switch(v->etype) { - - default: - diag(Z, "unknown etype %d/%d", bitno(b), v->etype); - break; - - case TCHAR: - case TUCHAR: - case TSHORT: - case TUSHORT: - case TINT: - case TUINT: - case TLONG: - case TULONG: - case TIND: - case TVLONG: - case TUVLONG: - case TARRAY: - i = BtoR(~b); - if(i && r->cost > 0) { - r->regno = i; - return RtoB(i); - } - break; - - case TDOUBLE: - case TFLOAT: - i = BtoF(~b); - if(i && r->cost > 0) { - r->regno = i+NREG; - return FtoB(i); - } - break; - } - return 0; -} - -void -paint1(Reg *r, int bn) -{ - Reg *r1; - Prog *p; - int z; - uint32 bb; - - z = bn/32; - bb = 1L<<(bn%32); - if(r->act.b[z] & bb) - return; - for(;;) { - if(!(r->refbehind.b[z] & bb)) - break; - r1 = r->p1; - if(r1 == R) - break; - if(!(r1->refahead.b[z] & bb)) - break; - if(r1->act.b[z] & bb) - break; - r = r1; - } - - if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) { - change -= CLOAD * r->loop; - if(debug['R'] && debug['v']) - print("%ld%P\tld %B $%d\n", r->loop, - r->prog, blsh(bn), change); - } - for(;;) { - r->act.b[z] |= bb; - p = r->prog; - - if(r->use1.b[z] & bb) { - change += CREF * r->loop; - if(p->to.type == D_FREG && (p->as == AMOVW || p->as == AMOVD)) - change = -CINF; /* cant go Rreg to Freg */ - if(debug['R'] && debug['v']) - print("%ld%P\tu1 %B $%d\n", r->loop, - p, blsh(bn), change); - } - - if((r->use2.b[z]|r->set.b[z]) & bb) { - change += CREF * r->loop; - if(p->from.type == D_FREG && (p->as == AMOVW || p->as == AMOVD)) - change = -CINF; /* cant go Rreg to Freg */ - if(debug['R'] && debug['v']) - print("%ld%P\tu2 %B $%d\n", r->loop, - p, blsh(bn), change); - } - - if(STORE(r) & r->regdiff.b[z] & bb) { - change -= CLOAD * r->loop; - if(debug['R'] && debug['v']) - print("%ld%P\tst %B $%d\n", r->loop, - p, blsh(bn), change); - } - - if(r->refbehind.b[z] & bb) - for(r1 = r->p2; r1 != R; r1 = r1->p2link) - if(r1->refahead.b[z] & bb) - paint1(r1, bn); - - if(!(r->refahead.b[z] & bb)) - break; - r1 = r->s2; - if(r1 != R) - if(r1->refbehind.b[z] & bb) - paint1(r1, bn); - r = r->s1; - if(r == R) - break; - if(r->act.b[z] & bb) - break; - if(!(r->refbehind.b[z] & bb)) - break; - } -} - -uint32 -paint2(Reg *r, int bn) -{ - Reg *r1; - int z; - uint32 bb, vreg; - - z = bn/32; - bb = 1L << (bn%32); - vreg = regbits; - if(!(r->act.b[z] & bb)) - return vreg; - for(;;) { - if(!(r->refbehind.b[z] & bb)) - break; - r1 = r->p1; - if(r1 == R) - break; - if(!(r1->refahead.b[z] & bb)) - break; - if(!(r1->act.b[z] & bb)) - break; - r = r1; - } - for(;;) { - r->act.b[z] &= ~bb; - - vreg |= r->regu; - - if(r->refbehind.b[z] & bb) - for(r1 = r->p2; r1 != R; r1 = r1->p2link) - if(r1->refahead.b[z] & bb) - vreg |= paint2(r1, bn); - - if(!(r->refahead.b[z] & bb)) - break; - r1 = r->s2; - if(r1 != R) - if(r1->refbehind.b[z] & bb) - vreg |= paint2(r1, bn); - r = r->s1; - if(r == R) - break; - if(!(r->act.b[z] & bb)) - break; - if(!(r->refbehind.b[z] & bb)) - break; - } - return vreg; -} - -void -paint3(Reg *r, int bn, int32 rb, int rn) -{ - Reg *r1; - Prog *p; - int z; - uint32 bb; - - z = bn/32; - bb = 1L << (bn%32); - if(r->act.b[z] & bb) - return; - for(;;) { - if(!(r->refbehind.b[z] & bb)) - break; - r1 = r->p1; - if(r1 == R) - break; - if(!(r1->refahead.b[z] & bb)) - break; - if(r1->act.b[z] & bb) - break; - r = r1; - } - - if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) - addmove(r, bn, rn, 0); - for(;;) { - r->act.b[z] |= bb; - p = r->prog; - - if(r->use1.b[z] & bb) { - if(debug['R']) - print("%P", p); - addreg(&p->from, rn); - if(debug['R']) - print("\t.c%P\n", p); - } - if((r->use2.b[z]|r->set.b[z]) & bb) { - if(debug['R']) - print("%P", p); - addreg(&p->to, rn); - if(debug['R']) - print("\t.c%P\n", p); - } - - if(STORE(r) & r->regdiff.b[z] & bb) - addmove(r, bn, rn, 1); - r->regu |= rb; - - if(r->refbehind.b[z] & bb) - for(r1 = r->p2; r1 != R; r1 = r1->p2link) - if(r1->refahead.b[z] & bb) - paint3(r1, bn, rb, rn); - - if(!(r->refahead.b[z] & bb)) - break; - r1 = r->s2; - if(r1 != R) - if(r1->refbehind.b[z] & bb) - paint3(r1, bn, rb, rn); - r = r->s1; - if(r == R) - break; - if(r->act.b[z] & bb) - break; - if(!(r->refbehind.b[z] & bb)) - break; - } -} - -void -addreg(Addr *a, int rn) -{ - - a->sym = 0; - a->name = D_NONE; - a->type = D_REG; - a->reg = rn; - if(rn >= NREG) { - a->type = D_FREG; - a->reg = rn-NREG; - } -} - -/* - * track register variables including external registers: - * bit reg - * 0 R7 - * 1 R8 - * ... ... - * 21 R28 - */ -int32 -RtoB(int r) -{ - - if(r >= REGMIN && r <= REGMAX) - return 1L << (r-REGMIN); - return 0; -} - -int -BtoR(int32 b) -{ - b &= 0x001fffffL; - if(b == 0) - return 0; - return bitno(b) + REGMIN; -} - -/* - * bit reg - * 22 F17 - * 23 F18 - * ... ... - * 31 F26 - */ -int32 -FtoB(int f) -{ - if(f < FREGMIN || f > FREGEXT) - return 0; - return 1L << (f - FREGMIN + 22); -} - -int -BtoF(int32 b) -{ - - b &= 0xffc00000L; - if(b == 0) - return 0; - return bitno(b) - 22 + FREGMIN; -} diff --git a/src/cmd/9c/sgen.c b/src/cmd/9c/sgen.c deleted file mode 100644 index b03c17267d..0000000000 --- a/src/cmd/9c/sgen.c +++ /dev/null @@ -1,291 +0,0 @@ -// cmd/9c/sgen.c from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "gc.h" - -Prog* -gtext(Sym *s, int32 stkoff) -{ - vlong v; - - v = ((uvlong)argsize(1) << 32) | (stkoff & 0xffffffff); - if((textflag & NOSPLIT) && stkoff >= 128) - yyerror("stack frame too large for NOSPLIT function"); - - gpseudo(ATEXT, s, nodgconst(v, types[TVLONG])); - return p; -} - - -void -noretval(int n) -{ - - if(n & 1) { - gins(ANOP, Z, Z); - p->to.type = D_REG; - p->to.reg = REGRET; - } - if(n & 2) { - gins(ANOP, Z, Z); - p->to.type = D_FREG; - p->to.reg = FREGRET; - } -} - -/* - * calculate addressability as follows - * CONST ==> 20 $value - * NAME ==> 10 name - * REGISTER ==> 11 register - * INDREG ==> 12 *[(reg)+offset] - * &10 ==> 2 $name - * ADD(2, 20) ==> 2 $name+offset - * ADD(3, 20) ==> 3 $(reg)+offset - * &12 ==> 3 $(reg)+offset - * *11 ==> 11 ?? - * *2 ==> 10 name - * *3 ==> 12 *(reg)+offset - * calculate complexity (number of registers) - */ -void -xcom(Node *n) -{ - Node *l, *r; - int v; - - if(n == Z) - return; - l = n->left; - r = n->right; - n->addable = 0; - n->complex = 0; - switch(n->op) { - case OCONST: - n->addable = 20; - return; - - case OREGISTER: - n->addable = 11; - return; - - case OINDREG: - n->addable = 12; - return; - - case ONAME: - n->addable = 10; - return; - - case OADDR: - xcom(l); - if(l->addable == 10) - n->addable = 2; - if(l->addable == 12) - n->addable = 3; - break; - - case OIND: - xcom(l); - if(l->addable == 11) - n->addable = 12; - if(l->addable == 3) - n->addable = 12; - if(l->addable == 2) - n->addable = 10; - break; - - case OADD: - xcom(l); - xcom(r); - if(l->addable == 20) { - if(r->addable == 2) - n->addable = 2; - if(r->addable == 3) - n->addable = 3; - } - if(r->addable == 20) { - if(l->addable == 2) - n->addable = 2; - if(l->addable == 3) - n->addable = 3; - } - break; - - case OASMUL: - case OASLMUL: - xcom(l); - xcom(r); - v = vlog(r); - if(v >= 0) { - n->op = OASASHL; - r->vconst = v; - r->type = types[TINT]; - } - break; - - case OMUL: - case OLMUL: - xcom(l); - xcom(r); - v = vlog(r); - if(v >= 0) { - n->op = OASHL; - r->vconst = v; - r->type = types[TINT]; - } - v = vlog(l); - if(v >= 0) { - n->op = OASHL; - n->left = r; - n->right = l; - r = l; - l = n->left; - r->vconst = v; - r->type = types[TINT]; - simplifyshift(n); - } - break; - - case OASLDIV: - xcom(l); - xcom(r); - v = vlog(r); - if(v >= 0) { - n->op = OASLSHR; - r->vconst = v; - r->type = types[TINT]; - } - break; - - case OLDIV: - xcom(l); - xcom(r); - v = vlog(r); - if(v >= 0) { - n->op = OLSHR; - r->vconst = v; - r->type = types[TINT]; - simplifyshift(n); - } - break; - - case OASLMOD: - xcom(l); - xcom(r); - v = vlog(r); - if(v >= 0) { - n->op = OASAND; - r->vconst--; - } - break; - - case OLMOD: - xcom(l); - xcom(r); - v = vlog(r); - if(v >= 0) { - n->op = OAND; - r->vconst--; - } - break; - - case OLSHR: - case OASHL: - case OASHR: - xcom(l); - xcom(r); - simplifyshift(n); - break; - - default: - if(l != Z) - xcom(l); - if(r != Z) - xcom(r); - break; - } - if(n->addable >= 10) - return; - if(l != Z) - n->complex = l->complex; - if(r != Z) { - if(r->complex == n->complex) - n->complex = r->complex+1; - else - if(r->complex > n->complex) - n->complex = r->complex; - } - if(n->complex == 0) - n->complex++; - -// if(com64(n)) -// return; - - switch(n->op) { - - case OFUNC: - n->complex = FNX; - break; - - case OEQ: - case ONE: - case OLE: - case OLT: - case OGE: - case OGT: - case OHI: - case OHS: - case OLO: - case OLS: - /* - * immediate operators, make const on right - */ - if(l->op == OCONST) { - n->left = r; - n->right = l; - n->op = invrel[relindex(n->op)]; - } - break; - - case OADD: - case OXOR: - case OAND: - case OOR: - /* - * immediate operators, make const on right - */ - if(l->op == OCONST) { - n->left = r; - n->right = l; - } - break; - } -} - diff --git a/src/cmd/9c/swt.c b/src/cmd/9c/swt.c deleted file mode 100644 index a63db60b27..0000000000 --- a/src/cmd/9c/swt.c +++ /dev/null @@ -1,407 +0,0 @@ -// cmd/9c/swt.c from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "gc.h" - -void -swit1(C1 *q, int nc, int32 def, Node *n) -{ - Node tn, nod; - - regalloc(&nod, n, Z); - /* always signed */ - if(typev[n->type->etype]) - nod.type = types[TVLONG]; - else - nod.type = types[TLONG]; - cgen(n, &nod); - regalloc(&tn, ®node, Z); - swit2(q, nc, def, &nod, &tn); - regfree(&tn); - regfree(&nod); -} - -void -swit2(C1 *q, int nc, int32 def, Node *n, Node *tn) -{ - C1 *r; - int i; - Prog *sp; - - if(nc < 5) { - for(i=0; ival)) { - gopcode(OEQ, n, Z, nodconst(q->val)); - } else { - gopcode(OSUB, nodconst(q->val), n, tn); - gopcode(OEQ, tn, Z, nodconst(0)); - } - patch(p, q->label); - q++; - } - gbranch(OGOTO); - patch(p, def); - return; - } - i = nc / 2; - r = q+i; - if(sval(r->val)) { - gopcode(OGT, n, Z, nodconst(r->val)); - sp = p; - } else { - gopcode(OSUB, nodconst(r->val), n, tn); - gopcode(OGT, tn, Z, nodconst(0)); - sp = p; - } - gbranch(OGOTO); - p->as = ABEQ; - patch(p, r->label); - swit2(q, i, def, n, tn); - - patch(sp, pc); - swit2(r+1, nc-i-1, def, n, tn); -} - -void -bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn) -{ - int sh; - int32 v; - Node *l; - - /* - * n1 gets adjusted/masked value - * n2 gets address of cell - * n3 gets contents of cell - */ - l = b->left; - if(n2 != Z) { - regalloc(n1, l, nn); - reglcgen(n2, l, Z); - regalloc(n3, l, Z); - gopcode(OAS, n2, Z, n3); - gopcode(OAS, n3, Z, n1); - } else { - regalloc(n1, l, nn); - cgen(l, n1); - } - if(b->type->shift == 0 && typeu[b->type->etype]) { - v = ~0 + (1L << b->type->nbits); - gopcode(OAND, nodconst(v), Z, n1); - } else { - sh = 32 - b->type->shift - b->type->nbits; - if(sh > 0) - gopcode(OASHL, nodconst(sh), Z, n1); - sh += b->type->shift; - if(sh > 0) - if(typeu[b->type->etype]) - gopcode(OLSHR, nodconst(sh), Z, n1); - else - gopcode(OASHR, nodconst(sh), Z, n1); - } -} - -void -bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn) -{ - int32 v; - Node nod, *l; - int sh; - - /* - * n1 has adjusted/masked value - * n2 has address of cell - * n3 has contents of cell - */ - l = b->left; - regalloc(&nod, l, Z); - v = ~0 + (1L << b->type->nbits); - gopcode(OAND, nodconst(v), Z, n1); - gopcode(OAS, n1, Z, &nod); - if(nn != Z) - gopcode(OAS, n1, Z, nn); - sh = b->type->shift; - if(sh > 0) - gopcode(OASHL, nodconst(sh), Z, &nod); - v <<= sh; - gopcode(OAND, nodconst(~v), Z, n3); - gopcode(OOR, n3, Z, &nod); - gopcode(OAS, &nod, Z, n2); - - regfree(&nod); - regfree(n1); - regfree(n2); - regfree(n3); -} - -int32 -outstring(char *s, int32 n) -{ - int32 r; - - if(suppress) - return nstring; - r = nstring; - while(n) { - string[mnstring] = *s++; - mnstring++; - nstring++; - if(mnstring >= NSNAME) { - gpseudo(ADATA, symstring, nodconst(0L)); - p->from.offset += nstring - NSNAME; - p->reg = NSNAME; - p->to.type = D_SCONST; - memmove(p->to.u.sval, string, NSNAME); - mnstring = 0; - } - n--; - } - return r; -} - -int -mulcon(Node *n, Node *nn) -{ - Node *l, *r, nod1, nod2; - Multab *m; - int32 v; - int o; - char code[sizeof(m->code)+2], *p; - - if(typefd[n->type->etype]) - return 0; - l = n->left; - r = n->right; - if(l->op == OCONST) { - l = r; - r = n->left; - } - if(r->op != OCONST) - return 0; - v = convvtox(r->vconst, n->type->etype); - if(v != r->vconst) { - if(debug['M']) - print("%L multiply conv: %lld\n", n->lineno, r->vconst); - return 0; - } - m = mulcon0(n, v); - if(!m) { - if(debug['M']) - print("%L multiply table: %lld\n", n->lineno, r->vconst); - return 0; - } - - memmove(code, m->code, sizeof(m->code)); - code[sizeof(m->code)] = 0; - - p = code; - if(p[1] == 'i') - p += 2; - regalloc(&nod1, n, nn); - cgen(l, &nod1); - if(v < 0) - gopcode(ONEG, &nod1, Z, &nod1); - regalloc(&nod2, n, Z); - -loop: - switch(*p) { - case 0: - regfree(&nod2); - gopcode(OAS, &nod1, Z, nn); - regfree(&nod1); - return 1; - case '+': - o = OADD; - goto addsub; - case '-': - o = OSUB; - addsub: /* number is r,n,l */ - v = p[1] - '0'; - r = &nod1; - if(v&4) - r = &nod2; - n = &nod1; - if(v&2) - n = &nod2; - l = &nod1; - if(v&1) - l = &nod2; - gopcode(o, l, n, r); - break; - default: /* op is shiftcount, number is r,l */ - v = p[1] - '0'; - r = &nod1; - if(v&2) - r = &nod2; - l = &nod1; - if(v&1) - l = &nod2; - v = *p - 'a'; - if(v < 0 || v >= 32) { - diag(n, "mulcon unknown op: %c%c", p[0], p[1]); - break; - } - gopcode(OASHL, nodconst(v), l, r); - break; - } - p += 2; - goto loop; -} - -void -sextern(Sym *s, Node *a, int32 o, int32 w) -{ - int32 e, lw; - - for(e=0; efrom.offset += o+e; - p->reg = lw; - p->to.type = D_SCONST; - memmove(p->to.u.sval, a->cstring+e, lw); - } -} - -void -gextern(Sym *s, Node *a, int32 o, int32 w) -{ - gpseudo(ADATA, s, a); - p->from.offset += o; - p->reg = w; - if(p->to.type == D_OREG) - p->to.type = D_CONST; -} - -void -outcode(void) -{ - Bprint(&outbuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion()); - if(pragcgobuf.to > pragcgobuf.start) { - Bprint(&outbuf, "\n"); - Bprint(&outbuf, "$$ // exports\n\n"); - Bprint(&outbuf, "$$ // local types\n\n"); - Bprint(&outbuf, "$$ // cgo\n"); - Bprint(&outbuf, "%s", fmtstrflush(&pragcgobuf)); - Bprint(&outbuf, "\n$$\n\n"); - } - Bprint(&outbuf, "!\n"); - - writeobj(ctxt, &outbuf); - lastp = nil; -} - -int32 -align(int32 i, Type *t, int op, int32 *maxalign) -{ - int32 o; - Type *v; - int w, packw; - - o = i; - w = 1; - packw = 0; - switch(op) { - default: - diag(Z, "unknown align opcode %d", op); - break; - - case Asu2: /* padding at end of a struct */ - w = *maxalign; - if(w < 1) - w = 1; - if(packflg) - packw = packflg; - break; - - case Ael1: /* initial allign of struct element */ - for(v=t; v->etype==TARRAY; v=v->link) - ; - if(v->etype == TSTRUCT || v->etype == TUNION) - w = v->align; - else - w = ewidth[v->etype]; - if(w < 1 || w > SZ_VLONG) - fatal(Z, "align"); - if(packflg) - packw = packflg; - break; - - case Ael2: /* width of a struct element */ - o += t->width; - break; - - case Aarg0: /* initial passbyptr argument in arg list */ - if(typesu[t->etype]) { - o = align(o, types[TIND], Aarg1, nil); - o = align(o, types[TIND], Aarg2, nil); - } - break; - - case Aarg1: /* initial align of parameter */ - w = ewidth[t->etype]; - if(w <= 0 || w >= SZ_VLONG) { - w = SZ_VLONG; - break; - } - w = 1; - break; - - case Aarg2: /* width of a parameter */ - o += t->width; - w = t->width; - if(w > SZ_VLONG) - w = SZ_VLONG; - break; - - case Aaut3: /* total align of automatic */ - o = align(o, t, Ael1, nil); - o = align(o, t, Ael2, nil); - break; - } - if(packw != 0 && xround(o, w) != xround(o, packw)) - diag(Z, "#pragma pack changes offset of %T", t); - o = xround(o, w); - if(maxalign && *maxalign < w) - *maxalign = w; - if(debug['A']) - print("align %s %ld %T = %ld\n", bnames[op], i, t, o); - return o; -} - -int32 -maxround(int32 max, int32 v) -{ - v = xround(v, SZ_VLONG); - if(v > max) - return v; - return max; -} diff --git a/src/cmd/9c/txt.c b/src/cmd/9c/txt.c deleted file mode 100644 index e46aba84e7..0000000000 --- a/src/cmd/9c/txt.c +++ /dev/null @@ -1,1537 +0,0 @@ -// cmd/9c/txt.c from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "gc.h" - -static int resvreg[nelem(reg)]; - -#define isv(et) ((et) == TVLONG || (et) == TUVLONG || (et) == TIND) - -int thechar = '9'; -char *thestring = "power64"; - -LinkArch *thelinkarch; - -void -linkarchinit(void) -{ - thestring = getgoarch(); - if(strcmp(thestring, "power64le") == 0) - thelinkarch = &linkpower64le; - else - thelinkarch = &linkpower64; -} - - -void -ginit(void) -{ - Type *t; - - dodefine("_64BITREG"); - dodefine("_64BIT"); - exregoffset = REGEXT; - exfregoffset = FREGEXT; - listinit(); - nstring = 0; - mnstring = 0; - nrathole = 0; - pc = 0; - breakpc = -1; - continpc = -1; - cases = C; - lastp = P; - tfield = types[TLONG]; - - typeword = typechlvp; - typecmplx = typesu; - /* TO DO */ - memmove(typechlpv, typechlp, sizeof(typechlpv)); - typechlpv[TVLONG] = 1; - typechlpv[TUVLONG] = 1; - - zprog.link = P; - zprog.as = AGOK; - zprog.reg = NREG; - zprog.from.type = D_NONE; - zprog.from.name = D_NONE; - zprog.from.reg = NREG; - zprog.from3 = zprog.from; - zprog.to = zprog.from; - - regnode.op = OREGISTER; - regnode.class = CEXREG; - regnode.reg = 0; - regnode.complex = 0; - regnode.addable = 11; - regnode.type = types[TLONG]; - - qregnode = regnode; - qregnode.type = types[TVLONG]; - - constnode.op = OCONST; - constnode.class = CXXX; - constnode.complex = 0; - constnode.addable = 20; - constnode.type = types[TLONG]; - - vconstnode = constnode; - vconstnode.type = types[TVLONG]; - - fconstnode.op = OCONST; - fconstnode.class = CXXX; - fconstnode.complex = 0; - fconstnode.addable = 20; - fconstnode.type = types[TDOUBLE]; - - nodsafe = new(ONAME, Z, Z); - nodsafe->sym = slookup(".safe"); - nodsafe->type = types[TINT]; - nodsafe->etype = types[TINT]->etype; - nodsafe->class = CAUTO; - complex(nodsafe); - - t = typ(TARRAY, types[TCHAR]); - symrathole = slookup(".rathole"); - symrathole->class = CGLOBL; - symrathole->type = t; - - nodrat = new(ONAME, Z, Z); - nodrat->sym = symrathole; - nodrat->type = types[TIND]; - nodrat->etype = TVOID; - nodrat->class = CGLOBL; - complex(nodrat); - nodrat->type = t; - - nodret = new(ONAME, Z, Z); - nodret->sym = slookup(".ret"); - nodret->type = types[TIND]; - nodret->etype = TIND; - nodret->class = CPARAM; - nodret = new(OIND, nodret, Z); - complex(nodret); - - com64init(); - - memset(reg, 0, sizeof(reg)); - reg[REGZERO] = 1; /* don't use */ - reg[REGTMP] = 1; - reg[FREGCVI+NREG] = 1; - reg[FREGZERO+NREG] = 1; - reg[FREGHALF+NREG] = 1; - reg[FREGONE+NREG] = 1; - reg[FREGTWO+NREG] = 1; - memmove(resvreg, reg, sizeof(reg)); -} - -void -gclean(void) -{ - int i; - Sym *s; - - for(i=0; itype->width = nstring; - symrathole->type->width = nrathole; - for(i=0; ilink) { - if(s->type == T) - continue; - if(s->type->width == 0) - continue; - if(s->class != CGLOBL && s->class != CSTATIC) - continue; - if(s->type == types[TENUM]) - continue; - gpseudo(AGLOBL, s, nodconst(s->type->width)); - } - nextpc(); - p->as = AEND; - outcode(); -} - -void -nextpc(void) -{ - Plist *pl; - - p = alloc(sizeof(*p)); - *p = zprog; - p->lineno = nearln; - p->pc = pc; - pc++; - if(lastp == P) { - pl = linknewplist(ctxt); - pl->firstpc = p; - } else - lastp->link = p; - lastp = p; -} - -void -gargs(Node *n, Node *tn1, Node *tn2) -{ - int32 regs; - Node fnxargs[20], *fnxp; - - regs = cursafe; - - fnxp = fnxargs; - garg1(n, tn1, tn2, 0, &fnxp); /* compile fns to temps */ - - curarg = 0; - fnxp = fnxargs; - garg1(n, tn1, tn2, 1, &fnxp); /* compile normal args and temps */ - - cursafe = regs; -} - -void -garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp) -{ - Node nod; - - if(n == Z) - return; - if(n->op == OLIST) { - garg1(n->left, tn1, tn2, f, fnxp); - garg1(n->right, tn1, tn2, f, fnxp); - return; - } - if(f == 0) { - if(n->complex >= FNX) { - regsalloc(*fnxp, n); - nod = znode; - nod.op = OAS; - nod.left = *fnxp; - nod.right = n; - nod.type = n->type; - cgen(&nod, Z); - (*fnxp)++; - } - return; - } - if(typesu[n->type->etype]) { - regaalloc(tn2, n); - if(n->complex >= FNX) { - sugen(*fnxp, tn2, n->type->width); - (*fnxp)++; - } else - sugen(n, tn2, n->type->width); - return; - } - if(REGARG>=0 && curarg == 0 && typechlpv[n->type->etype]) { - regaalloc1(tn1, n); - if(n->complex >= FNX) { - cgen(*fnxp, tn1); - (*fnxp)++; - } else - cgen(n, tn1); - return; - } - if(vconst(n) == 0) { - regaalloc(tn2, n); - gopcode(OAS, n, Z, tn2); - return; - } - regalloc(tn1, n, Z); - if(n->complex >= FNX) { - cgen(*fnxp, tn1); - (*fnxp)++; - } else - cgen(n, tn1); - regaalloc(tn2, n); - gopcode(OAS, tn1, Z, tn2); - regfree(tn1); -} - -Node* -nod32const(vlong v) -{ - constnode.vconst = v & MASK(32); - return &constnode; -} - -Node* -nodgconst(vlong v, Type *t) -{ - if(!typev[t->etype]) - return nodconst((int32)v); - vconstnode.vconst = v; - return &vconstnode; -} - -Node* -nodconst(int32 v) -{ - constnode.vconst = v; - return &constnode; -} - -Node* -nodfconst(double d) -{ - fconstnode.fconst = d; - return &fconstnode; -} - -void -nodreg(Node *n, Node *nn, int reg) -{ - *n = qregnode; - n->reg = reg; - n->type = nn->type; - n->lineno = nn->lineno; -} - -void -regret(Node *n, Node *nn, Type *t, int mode) -{ - int r; - - if(mode == 0 || hasdotdotdot(t) || nn->type->width == 0) { - r = REGRET; - if(typefd[nn->type->etype]) - r = FREGRET+NREG; - nodreg(n, nn, r); - reg[r]++; - return; - } - - if(mode == 1) { - // fetch returned value after call. - // already called gargs, so curarg is set. - curarg = (curarg+7) & ~7; - regaalloc(n, nn); - return; - } - - if(mode == 2) { - // store value to be returned. - // must compute arg offset. - if(t->etype != TFUNC) - fatal(Z, "bad regret func %T", t); - *n = *nn; - n->op = ONAME; - n->class = CPARAM; - n->sym = slookup(".ret"); - n->complex = nodret->complex; - n->addable = 20; - n->xoffset = argsize(0); - return; - } - - fatal(Z, "bad regret"); -} - -void -regalloc(Node *n, Node *tn, Node *o) -{ - int i, j; - static int lasti; - - switch(tn->type->etype) { - case TCHAR: - case TUCHAR: - case TSHORT: - case TUSHORT: - case TINT: - case TUINT: - case TLONG: - case TULONG: - case TVLONG: - case TUVLONG: - case TIND: - if(o != Z && o->op == OREGISTER) { - i = o->reg; - if(i > 0 && i < NREG) - goto out; - } - j = lasti + REGRET+1; - for(i=REGRET+1; i= NREG) - j = REGRET+1; - if(reg[j] == 0) { - i = j; - goto out; - } - j++; - } - diag(tn, "out of fixed registers"); - goto err; - - case TFLOAT: - case TDOUBLE: - if(o != Z && o->op == OREGISTER) { - i = o->reg; - if(i >= NREG && i < NREG+NREG) - goto out; - } - j = lasti + NREG; - for(i=NREG; i= NREG+NREG) - j = NREG; - if(reg[j] == 0) { - i = j; - goto out; - } - j++; - } - diag(tn, "out of float registers"); - goto err; - } - diag(tn, "unknown type in regalloc: %T", tn->type); -err: - i = 0; -out: - if(i) - reg[i]++; - lasti++; - if(lasti >= 5) - lasti = 0; - nodreg(n, tn, i); -} - -void -regialloc(Node *n, Node *tn, Node *o) -{ - Node nod; - - nod = *tn; - nod.type = types[TIND]; - regalloc(n, &nod, o); -} - -void -regfree(Node *n) -{ - int i; - - i = 0; - if(n->op != OREGISTER && n->op != OINDREG) - goto err; - i = n->reg; - if(i < 0 || i >= sizeof(reg)) - goto err; - if(reg[i] <= 0) - goto err; - reg[i]--; - return; -err: - diag(n, "error in regfree: %d", i); -} - -void -regsalloc(Node *n, Node *nn) -{ - cursafe = align(cursafe, nn->type, Aaut3, nil); - maxargsafe = maxround(maxargsafe, cursafe+curarg); - *n = *nodsafe; - n->xoffset = -(stkoff + cursafe); - n->type = nn->type; - n->etype = nn->type->etype; - n->lineno = nn->lineno; -} - -void -regaalloc1(Node *n, Node *nn) -{ - if(REGARG < 0) - return; - nodreg(n, nn, REGARG); - reg[REGARG]++; - curarg = align(curarg, nn->type, Aarg1, nil); - curarg = align(curarg, nn->type, Aarg2, nil); - maxargsafe = maxround(maxargsafe, cursafe+curarg); -} - -void -regaalloc(Node *n, Node *nn) -{ - curarg = align(curarg, nn->type, Aarg1, nil); - *n = *nn; - n->op = OINDREG; - n->reg = REGSP; - n->xoffset = curarg + SZ_VLONG; - n->complex = 0; - n->addable = 20; - curarg = align(curarg, nn->type, Aarg2, nil); - maxargsafe = maxround(maxargsafe, cursafe+curarg); -} - -void -regind(Node *n, Node *nn) -{ - - if(n->op != OREGISTER) { - diag(n, "regind not OREGISTER"); - return; - } - n->op = OINDREG; - n->type = nn->type; -} - -void -raddr(Node *n, Prog *p) -{ - Addr a; - - naddr(n, &a); - if(R0ISZERO && a.type == D_CONST && a.offset == 0) { - a.type = D_REG; - a.reg = REGZERO; - } - if(a.type != D_REG && a.type != D_FREG) { - if(n) - diag(n, "bad in raddr: %O", n->op); - else - diag(n, "bad in raddr: "); - p->reg = NREG; - } else - p->reg = a.reg; -} - -void -naddr(Node *n, Addr *a) -{ - int32 v; - - a->type = D_NONE; - if(n == Z) - return; - switch(n->op) { - default: - bad: - prtree(n, "naddr"); - diag(n, "%L: !bad in naddr: %O", n->lineno, n->op); - break; - - case OREGISTER: - a->type = D_REG; - a->sym = nil; - a->reg = n->reg; - if(a->reg >= NREG) { - a->type = D_FREG; - a->reg -= NREG; - } - break; - - case OIND: - naddr(n->left, a); - if(a->type == D_REG) { - a->type = D_OREG; - break; - } - if(a->type == D_CONST) { - a->type = D_OREG; - break; - } - goto bad; - - case OINDREG: - a->type = D_OREG; - a->sym = nil; - a->offset = n->xoffset; - a->reg = n->reg; - break; - - case ONAME: - a->etype = n->etype; - a->type = D_OREG; - a->name = D_STATIC; - a->sym = linksym(n->sym); - a->offset = n->xoffset; - if(n->class == CSTATIC) - break; - if(n->class == CEXTERN || n->class == CGLOBL) { - a->name = D_EXTERN; - break; - } - if(n->class == CAUTO) { - a->name = D_AUTO; - break; - } - if(n->class == CPARAM) { - a->name = D_PARAM; - break; - } - goto bad; - - case OCONST: - a->sym = nil; - a->reg = NREG; - if(typefd[n->type->etype]) { - a->type = D_FCONST; - a->u.dval = n->fconst; - } else { - a->type = D_CONST; - a->offset = n->vconst; - } - break; - - case OADDR: - naddr(n->left, a); - if(a->type == D_OREG) { - a->type = D_CONST; - break; - } - goto bad; - - case OADD: - if(n->left->op == OCONST) { - naddr(n->left, a); - v = a->offset; - naddr(n->right, a); - } else { - naddr(n->right, a); - v = a->offset; - naddr(n->left, a); - } - a->offset += v; - break; - - } -} - -void -fop(int as, int f1, int f2, Node *t) -{ - Node nod1, nod2, nod3; - - nodreg(&nod1, t, NREG+f1); - nodreg(&nod2, t, NREG+f2); - regalloc(&nod3, t, t); - gopcode(as, &nod1, &nod2, &nod3); - gmove(&nod3, t); - regfree(&nod3); -} - -void -gmove(Node *f, Node *t) -{ - int ft, tt, a; - Node nod, fxc0, fxc1, fxc2, fxrat; - Prog *p1; - double d; - - ft = f->type->etype; - tt = t->type->etype; - - if(ft == TDOUBLE && f->op == OCONST) { - d = f->fconst; - if(d == 0.0) { - a = FREGZERO; - goto ffreg; - } - if(d == 0.5) { - a = FREGHALF; - goto ffreg; - } - if(d == 1.0) { - a = FREGONE; - goto ffreg; - } - if(d == 2.0) { - a = FREGTWO; - goto ffreg; - } - if(d == -.5) { - fop(OSUB, FREGHALF, FREGZERO, t); - return; - } - if(d == -1.0) { - fop(OSUB, FREGONE, FREGZERO, t); - return; - } - if(d == -2.0) { - fop(OSUB, FREGTWO, FREGZERO, t); - return; - } - if(d == 1.5) { - fop(OADD, FREGONE, FREGHALF, t); - return; - } - if(d == 2.5) { - fop(OADD, FREGTWO, FREGHALF, t); - return; - } - if(d == 3.0) { - fop(OADD, FREGTWO, FREGONE, t); - return; - } - } - if(ft == TFLOAT && f->op == OCONST) { - d = f->fconst; - if(d == 0) { - a = FREGZERO; - ffreg: - nodreg(&nod, f, NREG+a); - gmove(&nod, t); - return; - } - } - /* - * a load -- - * put it into a register then - * worry what to do with it. - */ - if(f->op == ONAME || f->op == OINDREG || f->op == OIND) { - switch(ft) { - default: - if(ewidth[ft] == 4){ - if(typeu[ft]) - a = AMOVWZ; - else - a = AMOVW; - }else - a = AMOVD; - break; - case TINT: - a = AMOVW; - break; - case TUINT: - a = AMOVWZ; - break; - case TFLOAT: - a = AFMOVS; - break; - case TDOUBLE: - a = AFMOVD; - break; - case TCHAR: - a = AMOVB; - break; - case TUCHAR: - a = AMOVBZ; - break; - case TSHORT: - a = AMOVH; - break; - case TUSHORT: - a = AMOVHZ; - break; - } - regalloc(&nod, f, t); - gins(a, f, &nod); - gmove(&nod, t); - regfree(&nod); - return; - } - - /* - * a store -- - * put it into a register then - * store it. - */ - if(t->op == ONAME || t->op == OINDREG || t->op == OIND) { - switch(tt) { - default: - if(ewidth[tt] == 4) - a = AMOVW; - else - a = AMOVD; - break; - case TINT: - a = AMOVW; - break; - case TUINT: - a = AMOVWZ; - break; - case TUCHAR: - a = AMOVBZ; - break; - case TCHAR: - a = AMOVB; - break; - case TUSHORT: - a = AMOVHZ; - break; - case TSHORT: - a = AMOVH; - break; - case TFLOAT: - a = AFMOVS; - break; - case TDOUBLE: - a = AFMOVD; - break; - } - if(!typefd[ft] && vconst(f) == 0) { - gins(a, f, t); - return; - } - if(ft == tt) - regalloc(&nod, t, f); - else - regalloc(&nod, t, Z); - gmove(f, &nod); - gins(a, &nod, t); - regfree(&nod); - return; - } - - /* - * type x type cross table - */ - a = AGOK; - switch(ft) { - case TDOUBLE: - case TFLOAT: - switch(tt) { - case TDOUBLE: - a = AFMOVD; - if(ft == TFLOAT) - a = AFMOVS; /* AFMOVSD */ - break; - case TFLOAT: - a = AFRSP; - if(ft == TFLOAT) - a = AFMOVS; - break; - case TINT: - case TUINT: - case TLONG: - case TULONG: - case TIND: - case TSHORT: - case TUSHORT: - case TCHAR: - case TUCHAR: - /* BUG: not right for unsigned int32 */ - regalloc(&nod, f, Z); /* should be type float */ - regsalloc(&fxrat, f); - gins(AFCTIWZ, f, &nod); - gins(AFMOVD, &nod, &fxrat); - regfree(&nod); - fxrat.type = nodrat->type; - fxrat.etype = nodrat->etype; - fxrat.xoffset += 4; - gins(AMOVW, &fxrat, t); /* TO DO */ - gmove(t, t); - return; - case TVLONG: - case TUVLONG: - /* BUG: not right for unsigned int32 */ - regalloc(&nod, f, Z); /* should be type float */ - regsalloc(&fxrat, f); - gins(AFCTIDZ, f, &nod); - gins(AFMOVD, &nod, &fxrat); - regfree(&nod); - fxrat.type = nodrat->type; - fxrat.etype = nodrat->etype; - gins(AMOVD, &fxrat, t); - gmove(t, t); - return; - } - break; - case TINT: - case TUINT: - case TLONG: - case TULONG: - switch(tt) { - case TDOUBLE: - case TFLOAT: - goto fxtofl; - case TINT: - case TUINT: - case TLONG: - case TULONG: - case TSHORT: - case TUSHORT: - case TCHAR: - case TUCHAR: - if(typeu[tt]) - a = AMOVWZ; - else - a = AMOVW; - break; - case TVLONG: - case TUVLONG: - case TIND: - a = AMOVD; - break; - } - break; - case TVLONG: - case TUVLONG: - case TIND: - switch(tt) { - case TDOUBLE: - case TFLOAT: - goto fxtofl; - case TINT: - case TUINT: - case TLONG: - case TULONG: - case TVLONG: - case TUVLONG: - case TIND: - case TSHORT: - case TUSHORT: - case TCHAR: - case TUCHAR: - a = AMOVD; /* TO DO: conversion done? */ - break; - } - break; - case TSHORT: - switch(tt) { - case TDOUBLE: - case TFLOAT: - goto fxtofl; - case TINT: - case TUINT: - case TLONG: - case TULONG: - case TVLONG: - case TUVLONG: - case TIND: - a = AMOVH; - break; - case TSHORT: - case TUSHORT: - case TCHAR: - case TUCHAR: - a = AMOVD; - break; - } - break; - case TUSHORT: - switch(tt) { - case TDOUBLE: - case TFLOAT: - goto fxtofl; - case TINT: - case TUINT: - case TLONG: - case TULONG: - case TVLONG: - case TUVLONG: - case TIND: - a = AMOVHZ; - break; - case TSHORT: - case TUSHORT: - case TCHAR: - case TUCHAR: - a = AMOVD; - break; - } - break; - case TCHAR: - switch(tt) { - case TDOUBLE: - case TFLOAT: - goto fxtofl; - case TINT: - case TUINT: - case TLONG: - case TULONG: - case TVLONG: - case TUVLONG: - case TIND: - case TSHORT: - case TUSHORT: - a = AMOVB; - break; - case TCHAR: - case TUCHAR: - a = AMOVD; - break; - } - break; - case TUCHAR: - switch(tt) { - case TDOUBLE: - case TFLOAT: - fxtofl: - /* - * rat[0] = 0x43300000; rat[1] = f^0x80000000; - * t = *(double*)rat - FREGCVI; - * is-unsigned(t) => if(t<0) t += 2^32; - * could be streamlined for int-to-float - */ - regalloc(&fxc0, f, Z); - regalloc(&fxc2, f, Z); - regsalloc(&fxrat, t); /* should be type float */ - gins(AMOVW, nodconst(0x43300000L), &fxc0); - gins(AMOVW, f, &fxc2); - gins(AXOR, nodconst(0x80000000L), &fxc2); - if(ctxt->arch->endian == BigEndian) { - gins(AMOVW, &fxc0, &fxrat); - fxc1 = fxrat; - fxc1.type = nodrat->type; - fxc1.etype = nodrat->etype; - fxc1.xoffset += SZ_LONG; - gins(AMOVW, &fxc2, &fxc1); - } else { - gins(AMOVW, &fxc2, &fxrat); - fxc1 = fxrat; - fxc1.type = nodrat->type; - fxc1.etype = nodrat->etype; - fxc1.xoffset += SZ_LONG; - gins(AMOVW, &fxc0, &fxc1); - } - regfree(&fxc2); - regfree(&fxc0); - regalloc(&nod, t, t); /* should be type float */ - gins(AFMOVD, &fxrat, &nod); - nodreg(&fxc1, t, NREG+FREGCVI); - gins(AFSUB, &fxc1, &nod); - a = AFMOVD; - if(tt == TFLOAT) - a = AFRSP; - gins(a, &nod, t); - regfree(&nod); - if(ft == TULONG) { - regalloc(&nod, t, Z); - if(tt == TFLOAT) { - gins(AFCMPU, t, Z); - p->to.type = D_FREG; - p->to.reg = FREGZERO; - gins(ABGE, Z, Z); - p1 = p; - gins(AFMOVS, nodfconst(4294967296.), &nod); - gins(AFADDS, &nod, t); - } else { - gins(AFCMPU, t, Z); - p->to.type = D_FREG; - p->to.reg = FREGZERO; - gins(ABGE, Z, Z); - p1 = p; - gins(AFMOVD, nodfconst(4294967296.), &nod); - gins(AFADD, &nod, t); - } - patch(p1, pc); - regfree(&nod); - } - return; - case TINT: - case TUINT: - case TLONG: - case TULONG: - case TVLONG: - case TUVLONG: - case TIND: - case TSHORT: - case TUSHORT: - a = AMOVBZ; - break; - case TCHAR: - case TUCHAR: - a = AMOVD; - break; - } - break; - } - if(a == AGOK) - diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type); - if(a == AMOVD || (a == AMOVW || a == AMOVWZ) && ewidth[ft] == ewidth[tt] || a == AFMOVS || a == AFMOVD) - if(samaddr(f, t)) - return; - gins(a, f, t); -} - -void -gins(int a, Node *f, Node *t) -{ - - nextpc(); - p->as = a; - if(f != Z) - naddr(f, &p->from); - if(t != Z) - naddr(t, &p->to); - if(debug['g']) - print("%P\n", p); -} - -void -gopcode(int o, Node *f1, Node *f2, Node *t) -{ - int a, et; - Addr ta; - int uns; - - uns = 0; - et = TLONG; - if(f1 != Z && f1->type != T) { - if(f1->op == OCONST && t != Z && t->type != T) - et = t->type->etype; - else - et = f1->type->etype; - } - a = AGOK; - switch(o) { - case OAS: - gmove(f1, t); - return; - - case OASADD: - case OADD: - a = AADD; - if(et == TFLOAT) - a = AFADDS; - else - if(et == TDOUBLE) - a = AFADD; - break; - - case OASSUB: - case OSUB: - a = ASUB; - if(et == TFLOAT) - a = AFSUBS; - else - if(et == TDOUBLE) - a = AFSUB; - break; - - case OASOR: - case OOR: - a = AOR; - break; - - case OASAND: - case OAND: - a = AAND; - if(f1->op == OCONST) - a = AANDCC; - break; - - case OASXOR: - case OXOR: - a = AXOR; - break; - - case OASLSHR: - case OLSHR: - a = ASRW; - if(isv(et)) - a = ASRD; - break; - - case OASASHR: - case OASHR: - a = ASRAW; - if(isv(et)) - a = ASRAD; - break; - - case OASASHL: - case OASHL: - a = ASLW; - if(isv(et)) - a = ASLD; - break; - - case OFUNC: - a = ABL; - break; - - case OASLMUL: - case OLMUL: - case OASMUL: - case OMUL: - if(et == TFLOAT) { - a = AFMULS; - break; - } else - if(et == TDOUBLE) { - a = AFMUL; - break; - } - a = AMULLW; - if(isv(et)) - a = AMULLD; - break; - - case OASDIV: - case ODIV: - if(et == TFLOAT) { - a = AFDIVS; - break; - } else - if(et == TDOUBLE) { - a = AFDIV; - break; - } else - a = ADIVW; - if(isv(et)) - a = ADIVD; - break; - - case OASMOD: - case OMOD: - a = AREM; - if(isv(et)) - a = AREMD; - break; - - case OASLMOD: - case OLMOD: - a = AREMU; - if(isv(et)) - a = AREMDU; - break; - - case OASLDIV: - case OLDIV: - a = ADIVWU; - if(isv(et)) - a = ADIVDU; - break; - - case OCOM: - a = ANOR; - break; - - case ONEG: - a = ANEG; - if(et == TFLOAT || et == TDOUBLE) - a = AFNEG; - break; - - case OEQ: - a = ABEQ; - goto cmp; - - case ONE: - a = ABNE; - goto cmp; - - case OLT: - a = ABLT; - goto cmp; - - case OLE: - a = ABLE; - goto cmp; - - case OGE: - a = ABGE; - goto cmp; - - case OGT: - a = ABGT; - goto cmp; - - case OLO: - a = ABLT; - goto cmpu; - - case OLS: - a = ABLE; - goto cmpu; - - case OHS: - a = ABGE; - goto cmpu; - - case OHI: - a = ABGT; - goto cmpu; - - cmpu: - uns = 1; - cmp: - nextpc(); - switch(et){ - case TINT: - case TLONG: - p->as = ACMPW; - break; - case TUINT: - case TULONG: - p->as = ACMPWU; - break; - case TFLOAT: - case TDOUBLE: - p->as = AFCMPU; - break; - default: - p->as = uns? ACMPU: ACMP; - break; - } - if(f1 != Z) - naddr(f1, &p->from); - if(t != Z) - naddr(t, &p->to); - if(f1 == Z || t == Z || f2 != Z) - diag(Z, "bad cmp in gopcode %O", o); - if(debug['g']) - print("%P\n", p); - f1 = Z; - f2 = Z; - t = Z; - break; - } - if(a == AGOK) - diag(Z, "bad in gopcode %O", o); - nextpc(); - p->as = a; - if(f1 != Z) - naddr(f1, &p->from); - if(f2 != Z) { - naddr(f2, &ta); - p->reg = ta.reg; - if(ta.type == D_CONST && ta.offset == 0) { - if(R0ISZERO) - p->reg = REGZERO; - else - diag(Z, "REGZERO in gopcode %O", o); - } - } - if(t != Z) - naddr(t, &p->to); - if(debug['g']) - print("%P\n", p); -} - -int -samaddr(Node *f, Node *t) -{ - return f->op == OREGISTER && t->op == OREGISTER && f->reg == t->reg; -} - -void -gbranch(int o) -{ - int a; - - a = AGOK; - switch(o) { - case ORETURN: - a = ARETURN; - break; - case OGOTO: - a = ABR; - break; - } - nextpc(); - if(a == AGOK) { - diag(Z, "bad in gbranch %O", o); - nextpc(); - } - p->as = a; -} - -void -patch(Prog *op, int32 pc) -{ - - op->to.offset = pc; - op->to.type = D_BRANCH; -} - -void -gpseudo(int a, Sym *s, Node *n) -{ - - nextpc(); - p->as = a; - p->from.type = D_OREG; - p->from.sym = linksym(s); - - switch(a) { - case ATEXT: - p->reg = textflag; - textflag = 0; - break; - case AGLOBL: - p->reg = s->dataflag; - break; - } - - p->from.name = D_EXTERN; - if(s->class == CSTATIC) - p->from.name = D_STATIC; - naddr(n, &p->to); - if(a == ADATA || a == AGLOBL) - pc--; -} - -int -sval(int32 v) -{ - - if(v >= -(1<<15) && v < (1<<15)) - return 1; - return 0; -} - -void -gpcdata(int index, int value) -{ - Node n1; - - n1 = *nodconst(index); - gins(APCDATA, &n1, nodconst(value)); -} - -void -gprefetch(Node *n) -{ - // TODO(minux) - USED(n); - /* - Node n1; - - regalloc(&n1, n, Z); - gmove(n, &n1); - n1.op = OINDREG; - gins(ADCBT, &n1, Z); - regfree(&n1); - */ -} - - -int -sconst(Node *n) -{ - vlong vv; - - if(n->op == OCONST) { - if(!typefd[n->type->etype]) { - vv = n->vconst; - if(vv >= -(((vlong)1)<<15) && vv < (((vlong)1)<<15)) - return 1; - } - } - return 0; -} - -int -uconst(Node *n) -{ - vlong vv; - - if(n->op == OCONST) { - if(!typefd[n->type->etype]) { - vv = n->vconst; - if(vv >= 0 && vv < (((vlong)1)<<16)) - return 1; - } - } - return 0; -} - -int -immconst(Node *n) -{ - vlong v; - - if(n->op != OCONST || typefd[n->type->etype]) - return 0; - v = n->vconst; - if((v & 0xFFFF) == 0) - v >>= 16; - if(v >= 0 && v < ((vlong)1<<16)) - return 1; - if(v >= -((vlong)1<<15) && v <= ((vlong)1<<15)) - return 1; - return 0; -} - -int32 -exreg(Type *t) -{ - int32 o; - - if(typechlpv[t->etype]) { - if(exregoffset <= 3) - return 0; - o = exregoffset; - exregoffset--; - return o; - } - if(typefd[t->etype]) { - if(exfregoffset <= 16) - return 0; - o = exfregoffset + NREG; - exfregoffset--; - return o; - } - return 0; -} - -schar ewidth[NTYPE] = -{ - -1, /* [TXXX] */ - SZ_CHAR, /* [TCHAR] */ - SZ_CHAR, /* [TUCHAR] */ - SZ_SHORT, /* [TSHORT] */ - SZ_SHORT, /* [TUSHORT] */ - SZ_INT, /* [TINT] */ - SZ_INT, /* [TUINT] */ - SZ_LONG, /* [TLONG] */ - SZ_LONG, /* [TULONG] */ - SZ_VLONG, /* [TVLONG] */ - SZ_VLONG, /* [TUVLONG] */ - SZ_FLOAT, /* [TFLOAT] */ - SZ_DOUBLE, /* [TDOUBLE] */ - SZ_IND, /* [TIND] */ - 0, /* [TFUNC] */ - -1, /* [TARRAY] */ - 0, /* [TVOID] */ - -1, /* [TSTRUCT] */ - -1, /* [TUNION] */ - SZ_INT, /* [TENUM] */ -}; -int32 ncast[NTYPE] = -{ - 0, /* [TXXX] */ - BCHAR|BUCHAR, /* [TCHAR] */ - BCHAR|BUCHAR, /* [TUCHAR] */ - BSHORT|BUSHORT, /* [TSHORT] */ - BSHORT|BUSHORT, /* [TUSHORT] */ - BINT|BUINT|BLONG|BULONG, /* [TINT] */ - BINT|BUINT|BLONG|BULONG, /* [TUINT] */ - BINT|BUINT|BLONG|BULONG, /* [TLONG] */ - BINT|BUINT|BLONG|BULONG, /* [TULONG] */ - BVLONG|BUVLONG|BIND, /* [TVLONG] */ - BVLONG|BUVLONG|BIND, /* [TUVLONG] */ - BFLOAT, /* [TFLOAT] */ - BDOUBLE, /* [TDOUBLE] */ - BVLONG|BUVLONG|BIND, /* [TIND] */ - 0, /* [TFUNC] */ - 0, /* [TARRAY] */ - 0, /* [TVOID] */ - BSTRUCT, /* [TSTRUCT] */ - BUNION, /* [TUNION] */ - 0, /* [TENUM] */ -}; From cf06ea68d5eb53937c315baaa80d32e4e7ebe047 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 18 Nov 2014 15:18:52 -0500 Subject: [PATCH 37/68] [dev.cc] 9a: make RET a synonym for RETURN; use "g" instead of "R30" Previously, 9a was the only assembler that had a different name for RET, causing unnecessary friction in simple files that otherwise assembled on all architectures. Add RET so these work on 9a. This also renames "R30" to "g" to avoid unintentionally clobbering g in assembly code. This parallels a change made to 5a. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/178030043 --- src/cmd/9a/lex.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cmd/9a/lex.c b/src/cmd/9a/lex.c index 26f21f7436..e2945ef89d 100644 --- a/src/cmd/9a/lex.c +++ b/src/cmd/9a/lex.c @@ -250,7 +250,7 @@ struct "R27", LREG, 27, "R28", LREG, 28, "R29", LREG, 29, - "R30", LREG, 30, + "g", LREG, 30, // avoid unintentionally clobbering g using R30 "R31", LREG, 31, "F", LF, 0, @@ -488,6 +488,7 @@ struct "SYSCALL", LNOP, ASYSCALL, "UNDEF", LNOP, AUNDEF, + "RET", LRETRN, ARETURN, "RETURN", LRETRN, ARETURN, "RFI", LRETRN, ARFI, "RFCI", LRETRN, ARFCI, From 54d731452d0e06ccbf211ac0893a9739ad08bd75 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 18 Nov 2014 15:19:09 -0500 Subject: [PATCH 38/68] [dev.cc] runtime: convert power64 signal handlers from C to Go The power64 equivalent of CL 168500044 LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/175280043 --- src/runtime/signal_linux_power64.h | 49 --------- src/runtime/signal_linux_power64le.h | 49 --------- src/runtime/signal_linux_power64x.go | 71 +++++++++++++ src/runtime/signal_power64x.c | 137 ------------------------- src/runtime/signal_power64x.go | 144 +++++++++++++++++++++++++++ 5 files changed, 215 insertions(+), 235 deletions(-) delete mode 100644 src/runtime/signal_linux_power64.h delete mode 100644 src/runtime/signal_linux_power64le.h create mode 100644 src/runtime/signal_linux_power64x.go delete mode 100644 src/runtime/signal_power64x.c create mode 100644 src/runtime/signal_power64x.go diff --git a/src/runtime/signal_linux_power64.h b/src/runtime/signal_linux_power64.h deleted file mode 100644 index 8406489209..0000000000 --- a/src/runtime/signal_linux_power64.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2014 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. - -#define SIG_REGS(ctxt) (*((Sigcontext*)&((Ucontext*)(ctxt))->uc_mcontext)->regs) - -#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).gpr[0]) -#define SIG_R1(info, ctxt) (SIG_REGS(ctxt).gpr[1]) -#define SIG_R2(info, ctxt) (SIG_REGS(ctxt).gpr[2]) -#define SIG_R3(info, ctxt) (SIG_REGS(ctxt).gpr[3]) -#define SIG_R4(info, ctxt) (SIG_REGS(ctxt).gpr[4]) -#define SIG_R5(info, ctxt) (SIG_REGS(ctxt).gpr[5]) -#define SIG_R6(info, ctxt) (SIG_REGS(ctxt).gpr[6]) -#define SIG_R7(info, ctxt) (SIG_REGS(ctxt).gpr[7]) -#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).gpr[8]) -#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).gpr[9]) -#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).gpr[10]) -#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).gpr[11]) -#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).gpr[12]) -#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).gpr[13]) -#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).gpr[14]) -#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).gpr[15]) -#define SIG_R16(info, ctxt) (SIG_REGS(ctxt).gpr[16]) -#define SIG_R17(info, ctxt) (SIG_REGS(ctxt).gpr[17]) -#define SIG_R18(info, ctxt) (SIG_REGS(ctxt).gpr[18]) -#define SIG_R19(info, ctxt) (SIG_REGS(ctxt).gpr[19]) -#define SIG_R20(info, ctxt) (SIG_REGS(ctxt).gpr[20]) -#define SIG_R21(info, ctxt) (SIG_REGS(ctxt).gpr[21]) -#define SIG_R22(info, ctxt) (SIG_REGS(ctxt).gpr[22]) -#define SIG_R23(info, ctxt) (SIG_REGS(ctxt).gpr[23]) -#define SIG_R24(info, ctxt) (SIG_REGS(ctxt).gpr[24]) -#define SIG_R25(info, ctxt) (SIG_REGS(ctxt).gpr[25]) -#define SIG_R26(info, ctxt) (SIG_REGS(ctxt).gpr[26]) -#define SIG_R27(info, ctxt) (SIG_REGS(ctxt).gpr[27]) -#define SIG_R28(info, ctxt) (SIG_REGS(ctxt).gpr[28]) -#define SIG_R29(info, ctxt) (SIG_REGS(ctxt).gpr[29]) -#define SIG_R30(info, ctxt) (SIG_REGS(ctxt).gpr[30]) -#define SIG_R31(info, ctxt) (SIG_REGS(ctxt).gpr[31]) - -#define SIG_SP(info, ctxt) (SIG_REGS(ctxt).gpr[1]) -#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).nip) -#define SIG_TRAP(info, ctxt) (SIG_REGS(ctxt).trap) -#define SIG_CTR(info, ctxt) (SIG_REGS(ctxt).ctr) -#define SIG_LINK(info, ctxt) (SIG_REGS(ctxt).link) -#define SIG_XER(info, ctxt) (SIG_REGS(ctxt).xer) -#define SIG_CCR(info, ctxt) (SIG_REGS(ctxt).ccr) - -#define SIG_CODE0(info, ctxt) ((uintptr)(info)->si_code) -#define SIG_FAULT(info, ctxt) (SIG_REGS(ctxt).dar) diff --git a/src/runtime/signal_linux_power64le.h b/src/runtime/signal_linux_power64le.h deleted file mode 100644 index 8406489209..0000000000 --- a/src/runtime/signal_linux_power64le.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2014 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. - -#define SIG_REGS(ctxt) (*((Sigcontext*)&((Ucontext*)(ctxt))->uc_mcontext)->regs) - -#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).gpr[0]) -#define SIG_R1(info, ctxt) (SIG_REGS(ctxt).gpr[1]) -#define SIG_R2(info, ctxt) (SIG_REGS(ctxt).gpr[2]) -#define SIG_R3(info, ctxt) (SIG_REGS(ctxt).gpr[3]) -#define SIG_R4(info, ctxt) (SIG_REGS(ctxt).gpr[4]) -#define SIG_R5(info, ctxt) (SIG_REGS(ctxt).gpr[5]) -#define SIG_R6(info, ctxt) (SIG_REGS(ctxt).gpr[6]) -#define SIG_R7(info, ctxt) (SIG_REGS(ctxt).gpr[7]) -#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).gpr[8]) -#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).gpr[9]) -#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).gpr[10]) -#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).gpr[11]) -#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).gpr[12]) -#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).gpr[13]) -#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).gpr[14]) -#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).gpr[15]) -#define SIG_R16(info, ctxt) (SIG_REGS(ctxt).gpr[16]) -#define SIG_R17(info, ctxt) (SIG_REGS(ctxt).gpr[17]) -#define SIG_R18(info, ctxt) (SIG_REGS(ctxt).gpr[18]) -#define SIG_R19(info, ctxt) (SIG_REGS(ctxt).gpr[19]) -#define SIG_R20(info, ctxt) (SIG_REGS(ctxt).gpr[20]) -#define SIG_R21(info, ctxt) (SIG_REGS(ctxt).gpr[21]) -#define SIG_R22(info, ctxt) (SIG_REGS(ctxt).gpr[22]) -#define SIG_R23(info, ctxt) (SIG_REGS(ctxt).gpr[23]) -#define SIG_R24(info, ctxt) (SIG_REGS(ctxt).gpr[24]) -#define SIG_R25(info, ctxt) (SIG_REGS(ctxt).gpr[25]) -#define SIG_R26(info, ctxt) (SIG_REGS(ctxt).gpr[26]) -#define SIG_R27(info, ctxt) (SIG_REGS(ctxt).gpr[27]) -#define SIG_R28(info, ctxt) (SIG_REGS(ctxt).gpr[28]) -#define SIG_R29(info, ctxt) (SIG_REGS(ctxt).gpr[29]) -#define SIG_R30(info, ctxt) (SIG_REGS(ctxt).gpr[30]) -#define SIG_R31(info, ctxt) (SIG_REGS(ctxt).gpr[31]) - -#define SIG_SP(info, ctxt) (SIG_REGS(ctxt).gpr[1]) -#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).nip) -#define SIG_TRAP(info, ctxt) (SIG_REGS(ctxt).trap) -#define SIG_CTR(info, ctxt) (SIG_REGS(ctxt).ctr) -#define SIG_LINK(info, ctxt) (SIG_REGS(ctxt).link) -#define SIG_XER(info, ctxt) (SIG_REGS(ctxt).xer) -#define SIG_CCR(info, ctxt) (SIG_REGS(ctxt).ccr) - -#define SIG_CODE0(info, ctxt) ((uintptr)(info)->si_code) -#define SIG_FAULT(info, ctxt) (SIG_REGS(ctxt).dar) diff --git a/src/runtime/signal_linux_power64x.go b/src/runtime/signal_linux_power64x.go new file mode 100644 index 0000000000..8f357033bf --- /dev/null +++ b/src/runtime/signal_linux_power64x.go @@ -0,0 +1,71 @@ +// Copyright 2014 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. + +// +build linux +// +build power64 power64le + +package runtime + +import "unsafe" + +type sigctxt struct { + info *siginfo + ctxt unsafe.Pointer +} + +func (c *sigctxt) regs() *ptregs { return (*ucontext)(c.ctxt).uc_mcontext.regs } +func (c *sigctxt) r0() uint64 { return c.regs().gpr[0] } +func (c *sigctxt) r1() uint64 { return c.regs().gpr[1] } +func (c *sigctxt) r2() uint64 { return c.regs().gpr[2] } +func (c *sigctxt) r3() uint64 { return c.regs().gpr[3] } +func (c *sigctxt) r4() uint64 { return c.regs().gpr[4] } +func (c *sigctxt) r5() uint64 { return c.regs().gpr[5] } +func (c *sigctxt) r6() uint64 { return c.regs().gpr[6] } +func (c *sigctxt) r7() uint64 { return c.regs().gpr[7] } +func (c *sigctxt) r8() uint64 { return c.regs().gpr[8] } +func (c *sigctxt) r9() uint64 { return c.regs().gpr[9] } +func (c *sigctxt) r10() uint64 { return c.regs().gpr[10] } +func (c *sigctxt) r11() uint64 { return c.regs().gpr[11] } +func (c *sigctxt) r12() uint64 { return c.regs().gpr[12] } +func (c *sigctxt) r13() uint64 { return c.regs().gpr[13] } +func (c *sigctxt) r14() uint64 { return c.regs().gpr[14] } +func (c *sigctxt) r15() uint64 { return c.regs().gpr[15] } +func (c *sigctxt) r16() uint64 { return c.regs().gpr[16] } +func (c *sigctxt) r17() uint64 { return c.regs().gpr[17] } +func (c *sigctxt) r18() uint64 { return c.regs().gpr[18] } +func (c *sigctxt) r19() uint64 { return c.regs().gpr[19] } +func (c *sigctxt) r20() uint64 { return c.regs().gpr[20] } +func (c *sigctxt) r21() uint64 { return c.regs().gpr[21] } +func (c *sigctxt) r22() uint64 { return c.regs().gpr[22] } +func (c *sigctxt) r23() uint64 { return c.regs().gpr[23] } +func (c *sigctxt) r24() uint64 { return c.regs().gpr[24] } +func (c *sigctxt) r25() uint64 { return c.regs().gpr[25] } +func (c *sigctxt) r26() uint64 { return c.regs().gpr[26] } +func (c *sigctxt) r27() uint64 { return c.regs().gpr[27] } +func (c *sigctxt) r28() uint64 { return c.regs().gpr[28] } +func (c *sigctxt) r29() uint64 { return c.regs().gpr[29] } +func (c *sigctxt) r30() uint64 { return c.regs().gpr[30] } +func (c *sigctxt) r31() uint64 { return c.regs().gpr[31] } +func (c *sigctxt) sp() uint64 { return c.regs().gpr[1] } +func (c *sigctxt) pc() uint64 { return c.regs().nip } +func (c *sigctxt) trap() uint64 { return c.regs().trap } +func (c *sigctxt) ctr() uint64 { return c.regs().ctr } +func (c *sigctxt) link() uint64 { return c.regs().link } +func (c *sigctxt) xer() uint64 { return c.regs().xer } +func (c *sigctxt) ccr() uint64 { return c.regs().ccr } + +func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) } +func (c *sigctxt) sigaddr() uint64 { return uint64(*(*uintptr)(add(unsafe.Pointer(c.info), 2*ptrSize))) } +func (c *sigctxt) fault() uint64 { return c.regs().dar } + +func (c *sigctxt) set_r0(x uint64) { c.regs().gpr[0] = x } +func (c *sigctxt) set_r30(x uint64) { c.regs().gpr[30] = x } +func (c *sigctxt) set_pc(x uint64) { c.regs().nip = x } +func (c *sigctxt) set_sp(x uint64) { c.regs().gpr[1] = x } +func (c *sigctxt) set_link(x uint64) { c.regs().link = x } + +func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) } +func (c *sigctxt) set_sigaddr(x uint64) { + *(*uintptr)(add(unsafe.Pointer(c.info), 2*ptrSize)) = uintptr(x) +} diff --git a/src/runtime/signal_power64x.c b/src/runtime/signal_power64x.c deleted file mode 100644 index c0bf1c4a51..0000000000 --- a/src/runtime/signal_power64x.c +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright 2014 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. - -// +build linux -// +build power64 power64le - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "signal_GOOS_GOARCH.h" -#include "signals_GOOS.h" - -void -runtime·dumpregs(Siginfo *info, void *ctxt) -{ - USED(info); USED(ctxt); - runtime·printf("r0 %X\t", SIG_R0(info, ctxt)); - runtime·printf("r1 %X\n", SIG_R1(info, ctxt)); - runtime·printf("r2 %X\t", SIG_R2(info, ctxt)); - runtime·printf("r3 %X\n", SIG_R3(info, ctxt)); - runtime·printf("r4 %X\t", SIG_R4(info, ctxt)); - runtime·printf("r5 %X\n", SIG_R5(info, ctxt)); - runtime·printf("r6 %X\t", SIG_R6(info, ctxt)); - runtime·printf("r7 %X\n", SIG_R7(info, ctxt)); - runtime·printf("r8 %X\t", SIG_R8(info, ctxt)); - runtime·printf("r9 %X\n", SIG_R9(info, ctxt)); - runtime·printf("r10 %X\t", SIG_R10(info, ctxt)); - runtime·printf("r11 %X\n", SIG_R11(info, ctxt)); - runtime·printf("r12 %X\t", SIG_R12(info, ctxt)); - runtime·printf("r13 %X\n", SIG_R13(info, ctxt)); - runtime·printf("r14 %X\t", SIG_R14(info, ctxt)); - runtime·printf("r15 %X\n", SIG_R15(info, ctxt)); - runtime·printf("r16 %X\t", SIG_R16(info, ctxt)); - runtime·printf("r17 %X\n", SIG_R17(info, ctxt)); - runtime·printf("r18 %X\t", SIG_R18(info, ctxt)); - runtime·printf("r19 %X\n", SIG_R19(info, ctxt)); - runtime·printf("r20 %X\t", SIG_R20(info, ctxt)); - runtime·printf("r21 %X\n", SIG_R21(info, ctxt)); - runtime·printf("r22 %X\t", SIG_R22(info, ctxt)); - runtime·printf("r23 %X\n", SIG_R23(info, ctxt)); - runtime·printf("r24 %X\t", SIG_R24(info, ctxt)); - runtime·printf("r25 %X\n", SIG_R25(info, ctxt)); - runtime·printf("r26 %X\t", SIG_R26(info, ctxt)); - runtime·printf("r27 %X\n", SIG_R27(info, ctxt)); - runtime·printf("r28 %X\t", SIG_R28(info, ctxt)); - runtime·printf("r29 %X\n", SIG_R29(info, ctxt)); - runtime·printf("r30 %X\t", SIG_R30(info, ctxt)); - runtime·printf("r31 %X\n", SIG_R31(info, ctxt)); - runtime·printf("pc %X\t", SIG_PC(info, ctxt)); - runtime·printf("ctr %X\n", SIG_CTR(info, ctxt)); - runtime·printf("link %X\t", SIG_LINK(info, ctxt)); - runtime·printf("xer %X\n", SIG_XER(info, ctxt)); - runtime·printf("ccr %X\t", SIG_CCR(info, ctxt)); - runtime·printf("trap %X\n", SIG_TRAP(info, ctxt)); -} - -void -runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp) -{ - SigTab *t; - bool crash; - - if(sig == SIGPROF) { - runtime·sigprof((uint8*)SIG_PC(info, ctxt), (uint8*)SIG_SP(info, ctxt), (uint8*)SIG_LINK(info, ctxt), gp, g->m); - return; - } - t = &runtime·sigtab[sig]; - if(SIG_CODE0(info, ctxt) != SI_USER && (t->flags & SigPanic)) { - // Make it look like a call to the signal func. - // Have to pass arguments out of band since - // augmenting the stack frame would break - // the unwinding code. - gp->sig = sig; - gp->sigcode0 = SIG_CODE0(info, ctxt); - gp->sigcode1 = SIG_FAULT(info, ctxt); - gp->sigpc = SIG_PC(info, ctxt); - - // We arrange link, and pc to pretend the panicking - // function calls sigpanic directly. - // Always save LINK to stack so that panics in leaf - // functions are correctly handled. This smashes - // the stack frame but we're not going back there - // anyway. - SIG_SP(info, ctxt) -= sizeof(uintptr); - *(uintptr*)SIG_SP(info, ctxt) = SIG_LINK(info, ctxt); - // Don't bother saving PC if it's zero, which is - // probably a call to a nil func: the old link register - // is more useful in the stack trace. - if(gp->sigpc != 0) - SIG_LINK(info, ctxt) = gp->sigpc; - // In case we are panicking from external C code - SIG_R0(info, ctxt) = 0; - SIG_R30(info, ctxt) = (uintptr)gp; - SIG_PC(info, ctxt) = (uintptr)runtime·sigpanic; - return; - } - - if(SIG_CODE0(info, ctxt) == SI_USER || (t->flags & SigNotify)) - if(runtime·sigsend(sig)) - return; - if(t->flags & SigKill) - runtime·exit(2); - if(!(t->flags & SigThrow)) - return; - - g->m->throwing = 1; - g->m->caughtsig = gp; - if(runtime·panicking) // traceback already printed - runtime·exit(2); - runtime·panicking = 1; - - if(sig < 0 || sig >= NSIG) - runtime·printf("Signal %d\n", sig); - else - runtime·printf("%s\n", runtime·sigtab[sig].name); - - runtime·printf("PC=%x\n", SIG_PC(info, ctxt)); - if(g->m->lockedg != nil && g->m->ncgo > 0 && gp == g->m->g0) { - runtime·printf("signal arrived during cgo execution\n"); - gp = g->m->lockedg; - } - runtime·printf("\n"); - - if(runtime·gotraceback(&crash)){ - runtime·goroutineheader(gp); - runtime·tracebacktrap(SIG_PC(info, ctxt), SIG_SP(info, ctxt), SIG_LINK(info, ctxt), gp); - runtime·tracebackothers(gp); - runtime·printf("\n"); - runtime·dumpregs(info, ctxt); - } - - if(crash) - runtime·crash(); - - runtime·exit(2); -} diff --git a/src/runtime/signal_power64x.go b/src/runtime/signal_power64x.go new file mode 100644 index 0000000000..fc83beb1b6 --- /dev/null +++ b/src/runtime/signal_power64x.go @@ -0,0 +1,144 @@ +// Copyright 2014 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. + +// +build linux +// +build power64 power64le + +package runtime + +import "unsafe" + +func dumpregs(c *sigctxt) { + print("r0 ", hex(c.r0()), "\t") + print("r1 ", hex(c.r1()), "\n") + print("r2 ", hex(c.r2()), "\t") + print("r3 ", hex(c.r3()), "\n") + print("r4 ", hex(c.r4()), "\t") + print("r5 ", hex(c.r5()), "\n") + print("r6 ", hex(c.r6()), "\t") + print("r7 ", hex(c.r7()), "\n") + print("r8 ", hex(c.r8()), "\t") + print("r9 ", hex(c.r9()), "\n") + print("r10 ", hex(c.r10()), "\t") + print("r11 ", hex(c.r11()), "\n") + print("r12 ", hex(c.r12()), "\t") + print("r13 ", hex(c.r13()), "\n") + print("r14 ", hex(c.r14()), "\t") + print("r15 ", hex(c.r15()), "\n") + print("r16 ", hex(c.r16()), "\t") + print("r17 ", hex(c.r17()), "\n") + print("r18 ", hex(c.r18()), "\t") + print("r19 ", hex(c.r19()), "\n") + print("r20 ", hex(c.r20()), "\t") + print("r21 ", hex(c.r21()), "\n") + print("r22 ", hex(c.r22()), "\t") + print("r23 ", hex(c.r23()), "\n") + print("r24 ", hex(c.r24()), "\t") + print("r25 ", hex(c.r25()), "\n") + print("r26 ", hex(c.r26()), "\t") + print("r27 ", hex(c.r27()), "\n") + print("r28 ", hex(c.r28()), "\t") + print("r29 ", hex(c.r29()), "\n") + print("r30 ", hex(c.r30()), "\t") + print("r31 ", hex(c.r31()), "\n") + print("pc ", hex(c.pc()), "\t") + print("ctr ", hex(c.ctr()), "\n") + print("link ", hex(c.link()), "\t") + print("xer ", hex(c.xer()), "\n") + print("ccr ", hex(c.ccr()), "\t") + print("trap ", hex(c.trap()), "\n") +} + +func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) { + _g_ := getg() + c := &sigctxt{info, ctxt} + + if sig == _SIGPROF { + sigprof((*byte)(unsafe.Pointer(uintptr(c.pc()))), (*byte)(unsafe.Pointer(uintptr(c.sp()))), (*byte)(unsafe.Pointer(uintptr(c.link()))), gp, _g_.m) + return + } + flags := int32(_SigThrow) + if sig < uint32(len(sigtable)) { + flags = sigtable[sig].flags + } + if c.sigcode() != _SI_USER && flags&_SigPanic != 0 { + // Make it look like a call to the signal func. + // Have to pass arguments out of band since + // augmenting the stack frame would break + // the unwinding code. + gp.sig = sig + gp.sigcode0 = uintptr(c.sigcode()) + gp.sigcode1 = uintptr(c.fault()) + gp.sigpc = uintptr(c.pc()) + + // We arrange link, and pc to pretend the panicking + // function calls sigpanic directly. + // Always save LINK to stack so that panics in leaf + // functions are correctly handled. This smashes + // the stack frame but we're not going back there + // anyway. + sp := c.sp() - ptrSize + c.set_sp(sp) + *(*uint64)(unsafe.Pointer(uintptr(sp))) = c.link() + + // Don't bother saving PC if it's zero, which is + // probably a call to a nil func: the old link register + // is more useful in the stack trace. + if gp.sigpc != 0 { + c.set_link(uint64(gp.sigpc)) + } + + // In case we are panicking from external C code + c.set_r0(0) + c.set_r30(uint64(uintptr(unsafe.Pointer(gp)))) + c.set_pc(uint64(funcPC(sigpanic))) + return + } + + if c.sigcode() == _SI_USER || flags&_SigNotify != 0 { + if sigsend(sig) { + return + } + } + + if flags&_SigKill != 0 { + exit(2) + } + + if flags&_SigThrow == 0 { + return + } + + _g_.m.throwing = 1 + _g_.m.caughtsig = gp + startpanic() + + if sig < uint32(len(sigtable)) { + print(sigtable[sig].name, "\n") + } else { + print("Signal ", sig, "\n") + } + + print("PC=", hex(c.pc()), "\n") + if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 { + print("signal arrived during cgo execution\n") + gp = _g_.m.lockedg + } + print("\n") + + var docrash bool + if gotraceback(&docrash) > 0 { + goroutineheader(gp) + tracebacktrap(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.link()), gp) + tracebackothers(gp) + print("\n") + dumpregs(c) + } + + if docrash { + crash() + } + + exit(2) +} From 3f27c3ae373fb32f55739c8695e7baaa33e2b2e3 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 18 Nov 2014 15:19:26 -0500 Subject: [PATCH 39/68] [dev.cc] runtime: convert power64 assembly files for C to Go transition The power64 equivalent of CL 168510043 LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/178940043 --- src/runtime/asm_power64x.s | 13 +++++++++---- src/runtime/sys_linux_power64x.s | 3 ++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/runtime/asm_power64x.s b/src/runtime/asm_power64x.s index a75bb8ce1e..901dedbe59 100644 --- a/src/runtime/asm_power64x.s +++ b/src/runtime/asm_power64x.s @@ -4,7 +4,8 @@ // +build power64 power64le -#include "zasm_GOOS_GOARCH.h" +#include "go_asm.h" +#include "go_tls.h" #include "funcdata.h" #include "textflag.h" @@ -472,7 +473,7 @@ TEXT runtime·atomicstoreuintptr(SB), NOSPLIT, $0-16 // return 1; // } else // return 0; -TEXT runtime·casp(SB), NOSPLIT, $0-25 +TEXT runtime·casp1(SB), NOSPLIT, $0-25 BR runtime·cas64(SB) // uint32 xadd(uint32 volatile *ptr, int32 delta) @@ -529,7 +530,7 @@ TEXT runtime·xchg64(SB), NOSPLIT, $0-24 MOVD R3, ret+16(FP) RETURN -TEXT runtime·xchgp(SB), NOSPLIT, $0-24 +TEXT runtime·xchgp1(SB), NOSPLIT, $0-24 BR runtime·xchg64(SB) TEXT runtime·xchguintptr(SB), NOSPLIT, $0-24 @@ -538,7 +539,7 @@ TEXT runtime·xchguintptr(SB), NOSPLIT, $0-24 TEXT runtime·procyield(SB),NOSPLIT,$0-0 RETURN -TEXT runtime·atomicstorep(SB), NOSPLIT, $0-16 +TEXT runtime·atomicstorep1(SB), NOSPLIT, $0-16 BR runtime·atomicstore64(SB) TEXT runtime·atomicstore(SB), NOSPLIT, $0-12 @@ -986,3 +987,7 @@ TEXT _cgo_topofstack(SB),NOSPLIT,$0 TEXT runtime·goexit(SB),NOSPLIT,$-8-0 MOVD R0, R0 // NOP BL runtime·goexit1(SB) // does not return + +TEXT runtime·getg(SB),NOSPLIT,$-8-8 + MOVD g, ret+0(FP) + RETURN diff --git a/src/runtime/sys_linux_power64x.s b/src/runtime/sys_linux_power64x.s index fb24d3e795..395f657bf7 100644 --- a/src/runtime/sys_linux_power64x.s +++ b/src/runtime/sys_linux_power64x.s @@ -9,7 +9,8 @@ // System calls and other sys.stuff for Power64, Linux // -#include "zasm_GOOS_GOARCH.h" +#include "go_asm.h" +#include "go_tls.h" #include "textflag.h" #define SYS_exit 1 From 0da27cb8b0e82d429a9c3ee591208327e3e7a8c9 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 18 Nov 2014 15:19:37 -0500 Subject: [PATCH 40/68] [dev.cc] runtime: convert power64-specific .c and .h files to Go The power64 equivalent of CL 174860043 LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/179890043 --- src/runtime/arch1_power64.go | 15 ++++++++ src/runtime/arch1_power64le.go | 15 ++++++++ src/runtime/arch_power64.h | 14 ------- src/runtime/arch_power64le.h | 14 ------- src/runtime/atomic_power64x.go | 69 ++++++++++++++++++++++++++++++++++ src/runtime/sys_power64x.c | 38 ------------------- src/runtime/sys_power64x.go | 37 ++++++++++++++++++ 7 files changed, 136 insertions(+), 66 deletions(-) create mode 100644 src/runtime/arch1_power64.go create mode 100644 src/runtime/arch1_power64le.go delete mode 100644 src/runtime/arch_power64.h delete mode 100644 src/runtime/arch_power64le.h create mode 100644 src/runtime/atomic_power64x.go delete mode 100644 src/runtime/sys_power64x.c create mode 100644 src/runtime/sys_power64x.go diff --git a/src/runtime/arch1_power64.go b/src/runtime/arch1_power64.go new file mode 100644 index 0000000000..01e2b70f95 --- /dev/null +++ b/src/runtime/arch1_power64.go @@ -0,0 +1,15 @@ +// Copyright 2014 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. + +package runtime + +const ( + thechar = '9' + _BigEndian = 1 + _CacheLineSize = 64 + _RuntimeGogoBytes = 64 + _PhysPageSize = 65536 + _PCQuantum = 4 + _Int64Align = 8 +) diff --git a/src/runtime/arch1_power64le.go b/src/runtime/arch1_power64le.go new file mode 100644 index 0000000000..6580732a37 --- /dev/null +++ b/src/runtime/arch1_power64le.go @@ -0,0 +1,15 @@ +// Copyright 2014 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. + +package runtime + +const ( + thechar = '9' + _BigEndian = 0 + _CacheLineSize = 64 + _RuntimeGogoBytes = 64 + _PhysPageSize = 65536 + _PCQuantum = 4 + _Int64Align = 8 +) diff --git a/src/runtime/arch_power64.h b/src/runtime/arch_power64.h deleted file mode 100644 index 7cfb9da2fc..0000000000 --- a/src/runtime/arch_power64.h +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2014 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. - -enum { - thechar = '9', - BigEndian = 1, - CacheLineSize = 64, - RuntimeGogoBytes = 64, - PhysPageSize = 65536, - PCQuantum = 4, - Int64Align = 8 -}; - diff --git a/src/runtime/arch_power64le.h b/src/runtime/arch_power64le.h deleted file mode 100644 index 684ac9953b..0000000000 --- a/src/runtime/arch_power64le.h +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2014 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. - -enum { - thechar = '9', - BigEndian = 0, - CacheLineSize = 64, - RuntimeGogoBytes = 64, - PhysPageSize = 65536, - PCQuantum = 4, - Int64Align = 8 -}; - diff --git a/src/runtime/atomic_power64x.go b/src/runtime/atomic_power64x.go new file mode 100644 index 0000000000..a0dcf514b5 --- /dev/null +++ b/src/runtime/atomic_power64x.go @@ -0,0 +1,69 @@ +// Copyright 2014 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. + +// +build power64 power64le + +package runtime + +import "unsafe" + +//go:noescape +func xadd(ptr *uint32, delta int32) uint32 + +//go:noescape +func xadd64(ptr *uint64, delta int64) uint64 + +//go:noescape +func xchg(ptr *uint32, new uint32) uint32 + +//go:noescape +func xchg64(ptr *uint64, new uint64) uint64 + +// xchgp cannot have a go:noescape annotation, because +// while ptr does not escape, new does. If new is marked as +// not escaping, the compiler will make incorrect escape analysis +// decisions about the value being xchg'ed. +// Instead, make xchgp a wrapper around the actual atomic. +// When calling the wrapper we mark ptr as noescape explicitly. + +//go:nosplit +func xchgp(ptr unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer { + return xchgp1(noescape(ptr), new) +} + +func xchgp1(ptr unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer + +//go:noescape +func xchguintptr(ptr *uintptr, new uintptr) uintptr + +//go:noescape +func atomicload(ptr *uint32) uint32 + +//go:noescape +func atomicload64(ptr *uint64) uint64 + +//go:noescape +func atomicloadp(ptr unsafe.Pointer) unsafe.Pointer + +//go:noescape +func atomicor8(ptr *uint8, val uint8) + +//go:noescape +func cas64(ptr *uint64, old, new uint64) bool + +//go:noescape +func atomicstore(ptr *uint32, val uint32) + +//go:noescape +func atomicstore64(ptr *uint64, val uint64) + +// atomicstorep cannot have a go:noescape annotation. +// See comment above for xchgp. + +//go:nosplit +func atomicstorep(ptr unsafe.Pointer, new unsafe.Pointer) { + atomicstorep1(noescape(ptr), new) +} + +func atomicstorep1(ptr unsafe.Pointer, val unsafe.Pointer) diff --git a/src/runtime/sys_power64x.c b/src/runtime/sys_power64x.c deleted file mode 100644 index 79d976255f..0000000000 --- a/src/runtime/sys_power64x.c +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2014 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. - -// +build power64 power64le - -#include "runtime.h" - -// adjust Gobuf as if it executed a call to fn with context ctxt -// and then did an immediate Gosave. -void -runtime·gostartcall(Gobuf *gobuf, void (*fn)(void), void *ctxt) -{ - if(gobuf->lr != 0) - runtime·throw("invalid use of gostartcall"); - gobuf->lr = gobuf->pc; - gobuf->pc = (uintptr)fn; - gobuf->ctxt = ctxt; -} - -// Called to rewind context saved during morestack back to beginning of function. -// To help us, the linker emits a jmp back to the beginning right after the -// call to morestack. We just have to decode and apply that jump. -void -runtime·rewindmorestack(Gobuf *gobuf) -{ - uint32 inst; - - inst = *(uint32*)gobuf->pc; - if((gobuf->pc&3) == 0 && (inst>>24) == 0x4b && (inst&3) == 0) { - //runtime·printf("runtime: rewind pc=%p to pc=%p\n", gobuf->pc, gobuf->pc + ((int32)(inst<<8)>>8)); - gobuf->pc += (int32)(inst<<8)>>8; - return; - } - runtime·printf("runtime: pc=%p %x\n", gobuf->pc, inst); - runtime·throw("runtime: misuse of rewindmorestack"); -} - diff --git a/src/runtime/sys_power64x.go b/src/runtime/sys_power64x.go new file mode 100644 index 0000000000..f32d1a44f1 --- /dev/null +++ b/src/runtime/sys_power64x.go @@ -0,0 +1,37 @@ +// Copyright 2014 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. + +// +build power64 power64le + +package runtime + +import "unsafe" + +// adjust Gobuf as if it executed a call to fn with context ctxt +// and then did an immediate Gosave. +func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) { + if buf.lr != 0 { + gothrow("invalid use of gostartcall") + } + buf.lr = buf.pc + buf.pc = uintptr(fn) + buf.ctxt = ctxt +} + +// Called to rewind context saved during morestack back to beginning of function. +// To help us, the linker emits a jmp back to the beginning right after the +// call to morestack. We just have to decode and apply that jump. +func rewindmorestack(buf *gobuf) { + var inst uint32 + if buf.pc&3 == 0 && buf.pc != 0 { + inst = *(*uint32)(unsafe.Pointer(buf.pc)) + if inst>>24 == 0x4b && inst&3 == 0 { + //print("runtime: rewind pc=", hex(buf.pc), " to pc=", hex(uintptr(buf.pc + int32(inst<<8)>>8)), "\n"); + buf.pc += uintptr(int32(inst<<8) >> 8) + return + } + } + print("runtime: pc=", hex(buf.pc), " ", hex(inst), "\n") + gothrow("runtime: misuse of rewindmorestack") +} From 70f6769b60de9759f1c74f453f544767574898bc Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 18 Nov 2014 15:19:48 -0500 Subject: [PATCH 41/68] [dev.cc] runtime: catch defs_linux_power64*.go up to other archs Fix a constant conversion error. Add set_{sec,nsec} for timespec and set_usec for timeval. Fix type of sigaltstackt.ss_size. LGTM=rsc R=rsc, bradfitz CC=golang-codereviews https://golang.org/cl/180840043 --- src/runtime/defs_linux_power64.go | 16 ++++++++++++++-- src/runtime/defs_linux_power64le.go | 16 ++++++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/runtime/defs_linux_power64.go b/src/runtime/defs_linux_power64.go index df877a67f7..0dfc09caa4 100644 --- a/src/runtime/defs_linux_power64.go +++ b/src/runtime/defs_linux_power64.go @@ -79,7 +79,7 @@ const ( _EPOLLERR = 0x8 _EPOLLHUP = 0x10 _EPOLLRDHUP = 0x2000 - _EPOLLET = -0x80000000 + _EPOLLET = 0x80000000 _EPOLL_CLOEXEC = 0x80000 _EPOLL_CTL_ADD = 0x1 _EPOLL_CTL_DEL = 0x2 @@ -96,11 +96,23 @@ type timespec struct { tv_nsec int64 } +func (ts *timespec) set_sec(x int64) { + ts.tv_sec = x +} + +func (ts *timespec) set_nsec(x int32) { + ts.tv_nsec = int64(x) +} + type timeval struct { tv_sec int64 tv_usec int64 } +func (tv *timeval) set_usec(x int32) { + tv.tv_usec = int64(x) +} + type sigactiont struct { sa_handler uintptr sa_flags uint64 @@ -160,7 +172,7 @@ type sigaltstackt struct { ss_sp *byte ss_flags int32 pad_cgo_0 [4]byte - ss_size uint64 + ss_size uintptr } type sigcontext struct { diff --git a/src/runtime/defs_linux_power64le.go b/src/runtime/defs_linux_power64le.go index df877a67f7..0dfc09caa4 100644 --- a/src/runtime/defs_linux_power64le.go +++ b/src/runtime/defs_linux_power64le.go @@ -79,7 +79,7 @@ const ( _EPOLLERR = 0x8 _EPOLLHUP = 0x10 _EPOLLRDHUP = 0x2000 - _EPOLLET = -0x80000000 + _EPOLLET = 0x80000000 _EPOLL_CLOEXEC = 0x80000 _EPOLL_CTL_ADD = 0x1 _EPOLL_CTL_DEL = 0x2 @@ -96,11 +96,23 @@ type timespec struct { tv_nsec int64 } +func (ts *timespec) set_sec(x int64) { + ts.tv_sec = x +} + +func (ts *timespec) set_nsec(x int32) { + ts.tv_nsec = int64(x) +} + type timeval struct { tv_sec int64 tv_usec int64 } +func (tv *timeval) set_usec(x int32) { + tv.tv_usec = int64(x) +} + type sigactiont struct { sa_handler uintptr sa_flags uint64 @@ -160,7 +172,7 @@ type sigaltstackt struct { ss_sp *byte ss_flags int32 pad_cgo_0 [4]byte - ss_size uint64 + ss_size uintptr } type sigcontext struct { From f4627d1b05cdc0b9401f6582423f1cbbeadd705a Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 18 Nov 2014 15:50:36 -0500 Subject: [PATCH 42/68] [dev.cc] runtime: merge power64 onM/onM_signalok into systemstack This is the power64 component of CL 174950043. With this, dev.cc compiles on power64 and power64le and passes most tests if GOGC=off (but crashes in go_bootstrap if GC is on). LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/175290043 --- src/runtime/asm_power64x.s | 52 ++++++++++++++------------------------ 1 file changed, 19 insertions(+), 33 deletions(-) diff --git a/src/runtime/asm_power64x.s b/src/runtime/asm_power64x.s index 901dedbe59..3f2ab6d0e6 100644 --- a/src/runtime/asm_power64x.s +++ b/src/runtime/asm_power64x.s @@ -145,58 +145,44 @@ TEXT runtime·mcall(SB), NOSPLIT, $-8-8 BL (CTR) BR runtime·badmcall2(SB) -// switchtoM is a dummy routine that onM leaves at the bottom +// systemstack_switch is a dummy routine that systemstack leaves at the bottom // of the G stack. We need to distinguish the routine that // lives at the bottom of the G stack from the one that lives -// at the top of the M stack because the one at the top of -// the M stack terminates the stack walk (see topofstack()). -TEXT runtime·switchtoM(SB), NOSPLIT, $0-0 +// at the top of the system stack because the one at the top of +// the system stack terminates the stack walk (see topofstack()). +TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0 UNDEF BL (LR) // make sure this function is not leaf RETURN -// func onM_signalok(fn func()) -TEXT runtime·onM_signalok(SB), NOSPLIT, $8-8 - MOVD g, R3 // R3 = g - MOVD g_m(R3), R4 // R4 = g->m - MOVD m_gsignal(R4), R4 // R4 = g->m->gsignal - MOVD fn+0(FP), R11 // context for call below - CMP R3, R4 - BEQ onsignal - MOVD R11, 8(R1) - BL runtime·onM(SB) - RETURN - -onsignal: - MOVD 0(R11), R3 // code pointer - MOVD R3, CTR - BL (CTR) - RETURN - -// void onM(fn func()) -TEXT runtime·onM(SB), NOSPLIT, $0-8 +// func systemstack(fn func()) +TEXT runtime·systemstack(SB), NOSPLIT, $0-8 MOVD fn+0(FP), R3 // R3 = fn MOVD R3, R11 // context MOVD g_m(g), R4 // R4 = m + MOVD m_gsignal(R4), R5 // R5 = gsignal + CMP g, R5 + BEQ noswitch + MOVD m_g0(R4), R5 // R5 = g0 CMP g, R5 - BEQ onm + BEQ noswitch MOVD m_curg(R4), R6 CMP g, R6 - BEQ oncurg + BEQ switch - // Not g0, not curg. Must be gsignal, but that's not allowed. + // Bad: g is not gsignal, not g0, not curg. What is it? // Hide call from linker nosplit analysis. - MOVD $runtime·badonm(SB), R3 + MOVD $runtime·badsystemstack(SB), R3 MOVD R3, CTR BL (CTR) -oncurg: +switch: // save our state in g->sched. Pretend to - // be switchtoM if the G stack is scanned. - MOVD $runtime·switchtoM(SB), R6 + // be systemstack_switch if the G stack is scanned. + MOVD $runtime·systemstack_switch(SB), R6 ADD $8, R6 // get past prologue MOVD R6, (g_sched+gobuf_pc)(g) MOVD R1, (g_sched+gobuf_sp)(g) @@ -206,7 +192,7 @@ oncurg: // switch to g0 MOVD R5, g MOVD (g_sched+gobuf_sp)(g), R3 - // make it look like mstart called onM on g0, to stop traceback + // make it look like mstart called systemstack on g0, to stop traceback SUB $8, R3 MOVD $runtime·mstart(SB), R4 MOVD R4, 0(R3) @@ -224,7 +210,7 @@ oncurg: MOVD R0, (g_sched+gobuf_sp)(g) RETURN -onm: +noswitch: // already on m stack, just call directly MOVD 0(R11), R3 // code pointer MOVD R3, CTR From b27c0618eb468d9ac322a65bd40db6e829694907 Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Wed, 19 Nov 2014 11:55:15 +1100 Subject: [PATCH 43/68] [dev.cc] runtime: update sys_windows_386.s and sys_windows_amd64.s for Go conversion LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/176970043 --- src/runtime/sys_windows_386.s | 16 ++++++++-------- src/runtime/sys_windows_amd64.s | 14 +++++++------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/runtime/sys_windows_386.s b/src/runtime/sys_windows_386.s index 2793e52216..c8a830cdf8 100644 --- a/src/runtime/sys_windows_386.s +++ b/src/runtime/sys_windows_386.s @@ -44,7 +44,7 @@ TEXT runtime·badsignal2(SB),NOSPLIT,$24 // stderr MOVL $-12, 0(SP) MOVL SP, BP - CALL *runtime·GetStdHandle(SB) + CALL *runtime·_GetStdHandle(SB) MOVL BP, SP MOVL AX, 0(SP) // handle @@ -56,7 +56,7 @@ TEXT runtime·badsignal2(SB),NOSPLIT,$24 MOVL $0, 0(DX) MOVL DX, 12(SP) MOVL $0, 16(SP) // overlapped - CALL *runtime·WriteFile(SB) + CALL *runtime·_WriteFile(SB) MOVL BP, SI RET @@ -208,7 +208,7 @@ TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0 MOVL BX, g_m(SP) LEAL -8192(SP), CX MOVL CX, (g_stack+stack_lo)(SP) - ADDL $const_StackGuard, CX + ADDL $const__StackGuard, CX MOVL CX, g_stackguard0(SP) MOVL CX, g_stackguard1(SP) MOVL DX, (g_stack+stack_hi)(SP) @@ -255,8 +255,8 @@ TEXT runtime·callbackasm1+0(SB),NOSPLIT,$0 MOVL -4(BX)(AX*4), BX // extract callback context - MOVL cbctxt_gobody(BX), AX - MOVL cbctxt_argsize(BX), DX + MOVL wincallbackcontext_gobody(BX), AX + MOVL wincallbackcontext_argsize(BX), DX // preserve whatever's at the memory location that // the callback will use to store the return value @@ -266,7 +266,7 @@ TEXT runtime·callbackasm1+0(SB),NOSPLIT,$0 ADDL $4, DX // remember how to restore stack on return - MOVL cbctxt_restorestack(BX), BX + MOVL wincallbackcontext_restorestack(BX), BX PUSHL BX // call target Go function @@ -314,7 +314,7 @@ TEXT runtime·tstart(SB),NOSPLIT,$0 MOVL AX, (g_stack+stack_hi)(DX) SUBL $(64*1024), AX // stack size MOVL AX, (g_stack+stack_lo)(DX) - ADDL $const_StackGuard, AX + ADDL $const__StackGuard, AX MOVL AX, g_stackguard0(DX) MOVL AX, g_stackguard1(DX) @@ -415,7 +415,7 @@ TEXT runtime·usleep2(SB),NOSPLIT,$20 MOVL $0, alertable-16(SP) MOVL $-1, handle-20(SP) MOVL SP, BP - MOVL runtime·NtWaitForSingleObject(SB), AX + MOVL runtime·_NtWaitForSingleObject(SB), AX CALL AX MOVL BP, SP RET diff --git a/src/runtime/sys_windows_amd64.s b/src/runtime/sys_windows_amd64.s index 5e5c2e7f5a..68f7cd3924 100644 --- a/src/runtime/sys_windows_amd64.s +++ b/src/runtime/sys_windows_amd64.s @@ -66,7 +66,7 @@ TEXT runtime·badsignal2(SB),NOSPLIT,$48 // stderr MOVQ $-12, CX // stderr MOVQ CX, 0(SP) - MOVQ runtime·GetStdHandle(SB), AX + MOVQ runtime·_GetStdHandle(SB), AX CALL AX MOVQ AX, CX // handle @@ -79,7 +79,7 @@ TEXT runtime·badsignal2(SB),NOSPLIT,$48 MOVQ $0, 0(R9) MOVQ R9, 24(SP) MOVQ $0, 32(SP) // overlapped - MOVQ runtime·WriteFile(SB), AX + MOVQ runtime·_WriteFile(SB), AX CALL AX RET @@ -245,7 +245,7 @@ TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0 LEAQ -8192(SP), CX MOVQ CX, (g_stack+stack_lo)(SP) - ADDQ $const_StackGuard, CX + ADDQ $const__StackGuard, CX MOVQ CX, g_stackguard0(SP) MOVQ CX, g_stackguard1(SP) MOVQ DX, (g_stack+stack_hi)(SP) @@ -294,8 +294,8 @@ TEXT runtime·callbackasm1(SB),NOSPLIT,$0 MOVQ -8(CX)(AX*8), AX // extract callback context - MOVQ cbctxt_argsize(AX), DX - MOVQ cbctxt_gobody(AX), AX + MOVQ wincallbackcontext_argsize(AX), DX + MOVQ wincallbackcontext_gobody(AX), AX // preserve whatever's at the memory location that // the callback will use to store the return value @@ -355,7 +355,7 @@ TEXT runtime·tstart_stdcall(SB),NOSPLIT,$0 MOVQ AX, (g_stack+stack_hi)(DX) SUBQ $(64*1024), AX // stack size MOVQ AX, (g_stack+stack_lo)(DX) - ADDQ $const_StackGuard, AX + ADDQ $const__StackGuard, AX MOVQ AX, g_stackguard0(DX) MOVQ AX, g_stackguard1(DX) @@ -436,7 +436,7 @@ TEXT runtime·usleep2(SB),NOSPLIT,$16 MOVQ BX, (R8) MOVQ $-1, CX // handle MOVQ $0, DX // alertable - MOVQ runtime·NtWaitForSingleObject(SB), AX + MOVQ runtime·_NtWaitForSingleObject(SB), AX CALL AX MOVQ 8(SP), SP RET From b76e836042dd65b39cfe7af0f8ff5f73f12142a2 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Wed, 19 Nov 2014 11:30:58 -0500 Subject: [PATCH 44/68] [dev.cc] runtime: allow more address bits in lfstack on Power64 Previously, lfstack assumed Linux limited user space addresses to 43 bits on Power64 based on a paper from 2001. It turns out the limit is now 46 bits, so lfstack was truncating pointers. Raise the limit to 48 bits (for some future proofing and to make it match amd64) and add a self-test that will fail in a useful way if ever unpack(pack(x)) != x. With this change, dev.cc passes all.bash on power64le. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/174430043 --- src/runtime/lfstack.go | 4 ++++ src/runtime/lfstack_linux_power64x.go | 20 +++++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/runtime/lfstack.go b/src/runtime/lfstack.go index 4a20fff9d8..8a36a67b35 100644 --- a/src/runtime/lfstack.go +++ b/src/runtime/lfstack.go @@ -12,6 +12,10 @@ import "unsafe" func lfstackpush(head *uint64, node *lfnode) { node.pushcnt++ new := lfstackPack(node, node.pushcnt) + if node1, _ := lfstackUnpack(new); node1 != node { + println("runtime: lfstackpush invalid packing: node=", node, " cnt=", hex(node.pushcnt), " packed=", hex(new), " -> node=", node1, "\n") + gothrow("lfstackpush") + } for { old := atomicload64(head) node.next, _ = lfstackUnpack(old) diff --git a/src/runtime/lfstack_linux_power64x.go b/src/runtime/lfstack_linux_power64x.go index 7a122bf92c..89e389fc72 100644 --- a/src/runtime/lfstack_linux_power64x.go +++ b/src/runtime/lfstack_linux_power64x.go @@ -9,18 +9,24 @@ package runtime import "unsafe" -// On Power64, Linux limits the user address space to 43 bits. -// (https://www.kernel.org/doc/ols/2001/ppc64.pdf) -// In addition to the 21 bits taken from the top, we can take 3 from the -// bottom, because node must be pointer-aligned, giving a total of 24 bits +// On Power64, Linux limits the user address space to 46 bits (see +// TASK_SIZE_USER64 in the Linux kernel). This has grown over time, +// so here we allow 48 bit addresses. +// +// In addition to the 16 bits taken from the top, we can take 3 from the +// bottom, because node must be pointer-aligned, giving a total of 19 bits // of count. +const ( + addrBits = 48 + cntBits = 64 - addrBits + 3 +) func lfstackPack(node *lfnode, cnt uintptr) uint64 { - return uint64(uintptr(unsafe.Pointer(node)))<<21 | uint64(cnt&(1<<24-1)) + return uint64(uintptr(unsafe.Pointer(node)))<<(64-addrBits) | uint64(cnt&(1<> 24 << 3))) - cnt = uintptr(val & (1<<24 - 1)) + node = (*lfnode)(unsafe.Pointer(uintptr(val >> cntBits << 3))) + cnt = uintptr(val & (1< Date: Wed, 19 Nov 2014 14:16:12 -0500 Subject: [PATCH 45/68] undo CL 131750044 / 2d6d44ceb80e MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Breaks reading from stdin in parent after exec with SysProcAttr{Setpgid: true}. package main import ( "fmt" "os" "os/exec" "syscall" ) func main() { cmd := exec.Command("true") cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} cmd.Run() fmt.Printf("Hit enter:") os.Stdin.Read(make([]byte, 100)) fmt.Printf("Bye\n") } In go1.3, I type enter at the prompt and the program exits. With the CL being rolled back, the program wedges at the prompt. ««« original CL description syscall: SysProcAttr job control changes Making the child's process group the foreground process group and placing the child in a specific process group involves co-ordination between the parent and child that must be done post-fork but pre-exec. LGTM=iant R=golang-codereviews, gobot, iant, mikioh.mikioh CC=golang-codereviews https://golang.org/cl/131750044 »»» LGTM=minux, dneil R=dneil, minux CC=golang-codereviews, iant, michael.p.macinnis https://golang.org/cl/174450043 --- src/syscall/exec_bsd.go | 40 ++------------------------------------- src/syscall/exec_linux.go | 36 +---------------------------------- 2 files changed, 3 insertions(+), 73 deletions(-) diff --git a/src/syscall/exec_bsd.go b/src/syscall/exec_bsd.go index 7c2c1f7071..ff78f197f1 100644 --- a/src/syscall/exec_bsd.go +++ b/src/syscall/exec_bsd.go @@ -19,8 +19,6 @@ type SysProcAttr struct { Setpgid bool // Set process group ID to new pid (SYSV setpgrp) Setctty bool // Set controlling terminal to fd 0 Noctty bool // Detach fd 0 from controlling terminal - Foreground bool // Set foreground process group to child's pid. (Implies Setpgid. Stdin should be a TTY) - Joinpgrp int // If != 0, child's process group ID. (Setpgid must not be set) } // Implemented in runtime package. @@ -81,22 +79,7 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr if r1 != 0 { // parent; return PID runtime_AfterFork() - pid = int(r1) - - if sys.Joinpgrp != 0 { - // Place the child in the specified process group. - RawSyscall(SYS_SETPGID, r1, uintptr(sys.Joinpgrp), 0) - } else if sys.Foreground || sys.Setpgid { - // Place the child in a new process group. - RawSyscall(SYS_SETPGID, 0, 0, 0) - - if sys.Foreground { - // Set new foreground process group. - RawSyscall(SYS_IOCTL, uintptr(Stdin), TIOCSPGRP, uintptr(unsafe.Pointer(&pid))) - } - } - - return pid, 0 + return int(r1), 0 } // Fork succeeded, now in child. @@ -118,30 +101,11 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr } // Set process group - if sys.Joinpgrp != 0 { - // Place the child in the specified process group. - _, _, err1 = RawSyscall(SYS_SETPGID, r1, uintptr(sys.Joinpgrp), 0) - if err1 != 0 { - goto childerror - } - } else if sys.Foreground || sys.Setpgid { - // Place the child in a new process group. + if sys.Setpgid { _, _, err1 = RawSyscall(SYS_SETPGID, 0, 0, 0) if err1 != 0 { goto childerror } - - if sys.Foreground { - r1, _, _ = RawSyscall(SYS_GETPID, 0, 0, 0) - - pid := int(r1) - - // Set new foreground process group. - _, _, err1 = RawSyscall(SYS_IOCTL, uintptr(Stdin), TIOCSPGRP, uintptr(unsafe.Pointer(&pid))) - if err1 != 0 { - goto childerror - } - } } // Chroot diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go index 72e2f0b69c..042c20a468 100644 --- a/src/syscall/exec_linux.go +++ b/src/syscall/exec_linux.go @@ -29,8 +29,6 @@ type SysProcAttr struct { Ctty int // Controlling TTY fd (Linux only) Pdeathsig Signal // Signal that the process will get when its parent dies (Linux only) Cloneflags uintptr // Flags for clone calls (Linux only) - Foreground bool // Set foreground process group to child's pid. (Implies Setpgid. Stdin should be a TTY) - Joinpgrp int // If != 0, child's process group ID. (Setpgid must not be set) UidMappings []SysProcIDMap // User ID mappings for user namespaces. GidMappings []SysProcIDMap // Group ID mappings for user namespaces. } @@ -105,19 +103,6 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr Close(p[1]) } - if sys.Joinpgrp != 0 { - // Place the child in the specified process group. - RawSyscall(SYS_SETPGID, r1, uintptr(sys.Joinpgrp), 0) - } else if sys.Foreground || sys.Setpgid { - // Place the child in a new process group. - RawSyscall(SYS_SETPGID, 0, 0, 0) - - if sys.Foreground { - // Set new foreground process group. - RawSyscall(SYS_IOCTL, uintptr(Stdin), TIOCSPGRP, uintptr(unsafe.Pointer(&pid))) - } - } - return pid, 0 } @@ -179,30 +164,11 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr } // Set process group - if sys.Joinpgrp != 0 { - // Place the child in the specified process group. - _, _, err1 = RawSyscall(SYS_SETPGID, r1, uintptr(sys.Joinpgrp), 0) - if err1 != 0 { - goto childerror - } - } else if sys.Foreground || sys.Setpgid { - // Place the child in a new process group. + if sys.Setpgid { _, _, err1 = RawSyscall(SYS_SETPGID, 0, 0, 0) if err1 != 0 { goto childerror } - - if sys.Foreground { - r1, _, _ = RawSyscall(SYS_GETPID, 0, 0, 0) - - pid := int(r1) - - // Set new foreground process group. - _, _, err1 = RawSyscall(SYS_IOCTL, uintptr(Stdin), TIOCSPGRP, uintptr(unsafe.Pointer(&pid))) - if err1 != 0 { - goto childerror - } - } } // Chroot From d11a42595940df79bbd73bfe54469f840952ab79 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Wed, 19 Nov 2014 14:24:41 -0500 Subject: [PATCH 46/68] [dev.cc] runtime: decode power64 branch instructions the way the CPU does Previously, this used the top 8 bits of an instruction as a sort-of opcode and ignored the top two bits of the relative PC. This worked because these jumps are always negative and never big enough for the top two bits of the relative PC (also the bottom 2 bits of the sort-of opcode) to be anything other than 0b11, but the code is confusing because it doesn't match the actual structure of the instruction. Instead, use the real 6 bit opcode and use all 24 bits of relative PC. LGTM=rsc R=rsc, dave CC=golang-codereviews https://golang.org/cl/179960043 --- src/runtime/sys_power64x.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/runtime/sys_power64x.go b/src/runtime/sys_power64x.go index f32d1a44f1..90ebde7b40 100644 --- a/src/runtime/sys_power64x.go +++ b/src/runtime/sys_power64x.go @@ -26,9 +26,9 @@ func rewindmorestack(buf *gobuf) { var inst uint32 if buf.pc&3 == 0 && buf.pc != 0 { inst = *(*uint32)(unsafe.Pointer(buf.pc)) - if inst>>24 == 0x4b && inst&3 == 0 { - //print("runtime: rewind pc=", hex(buf.pc), " to pc=", hex(uintptr(buf.pc + int32(inst<<8)>>8)), "\n"); - buf.pc += uintptr(int32(inst<<8) >> 8) + if inst>>26 == 18 && inst&3 == 0 { + //print("runtime: rewind pc=", hex(buf.pc), " to pc=", hex(uintptr(buf.pc + int32(inst<<6)>>6)), "\n"); + buf.pc += uintptr(int32(inst<<6) >> 6) return } } From f4a525452e1442c08e2a973a5871445258ed0054 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Wed, 19 Nov 2014 14:56:49 -0500 Subject: [PATCH 47/68] [dev.cc] runtime: add explicit siginfo.si_addr field struct siginfo_t's si_addr field is part of a union. Previously, we represented this union in Go using an opaque byte array and accessed the si_addr field using unsafe (and wrong on 386 and arm!) pointer arithmetic. Since si_addr is the only field we use from this union, this replaces the opaque byte array with an explicit declaration of the si_addr field and accesses it directly. LGTM=minux, rsc R=rsc, minux CC=golang-codereviews https://golang.org/cl/179970044 --- src/runtime/defs_linux_386.go | 9 +++++---- src/runtime/defs_linux_amd64.go | 10 +++++----- src/runtime/defs_linux_arm.go | 9 +++++---- src/runtime/defs_linux_power64.go | 10 +++++----- src/runtime/defs_linux_power64le.go | 10 +++++----- src/runtime/signal_linux_386.go | 2 +- src/runtime/signal_linux_amd64.go | 2 +- src/runtime/signal_linux_arm.go | 2 +- src/runtime/signal_linux_power64x.go | 2 +- 9 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/runtime/defs_linux_386.go b/src/runtime/defs_linux_386.go index ddf592c91b..f55924b61c 100644 --- a/src/runtime/defs_linux_386.go +++ b/src/runtime/defs_linux_386.go @@ -155,10 +155,11 @@ type sigactiont struct { } type siginfo struct { - si_signo int32 - si_errno int32 - si_code int32 - _sifields [116]byte + si_signo int32 + si_errno int32 + si_code int32 + // below here is a union; si_addr is the only field we use + si_addr uint32 } type sigaltstackt struct { diff --git a/src/runtime/defs_linux_amd64.go b/src/runtime/defs_linux_amd64.go index 7f8f5816c6..a73f475148 100644 --- a/src/runtime/defs_linux_amd64.go +++ b/src/runtime/defs_linux_amd64.go @@ -117,11 +117,11 @@ type sigactiont struct { } type siginfo struct { - si_signo int32 - si_errno int32 - si_code int32 - pad_cgo_0 [4]byte - _sifields [112]byte + si_signo int32 + si_errno int32 + si_code int32 + // below here is a union; si_addr is the only field we use + si_addr uint64 } type itimerval struct { diff --git a/src/runtime/defs_linux_arm.go b/src/runtime/defs_linux_arm.go index a874b15941..c3a6e2f019 100644 --- a/src/runtime/defs_linux_arm.go +++ b/src/runtime/defs_linux_arm.go @@ -147,10 +147,11 @@ type itimerval struct { } type siginfo struct { - si_signo int32 - si_errno int32 - si_code int32 - _sifields [4]uint8 + si_signo int32 + si_errno int32 + si_code int32 + // below here is a union; si_addr is the only field we use + si_addr uint32 } type sigactiont struct { diff --git a/src/runtime/defs_linux_power64.go b/src/runtime/defs_linux_power64.go index 0dfc09caa4..f90b84874b 100644 --- a/src/runtime/defs_linux_power64.go +++ b/src/runtime/defs_linux_power64.go @@ -121,11 +121,11 @@ type sigactiont struct { } type siginfo struct { - si_signo int32 - si_errno int32 - si_code int32 - pad_cgo_0 [4]byte - _sifields [112]byte + si_signo int32 + si_errno int32 + si_code int32 + // below here is a union; si_addr is the only field we use + si_addr uint64 } type itimerval struct { diff --git a/src/runtime/defs_linux_power64le.go b/src/runtime/defs_linux_power64le.go index 0dfc09caa4..f90b84874b 100644 --- a/src/runtime/defs_linux_power64le.go +++ b/src/runtime/defs_linux_power64le.go @@ -121,11 +121,11 @@ type sigactiont struct { } type siginfo struct { - si_signo int32 - si_errno int32 - si_code int32 - pad_cgo_0 [4]byte - _sifields [112]byte + si_signo int32 + si_errno int32 + si_code int32 + // below here is a union; si_addr is the only field we use + si_addr uint64 } type itimerval struct { diff --git a/src/runtime/signal_linux_386.go b/src/runtime/signal_linux_386.go index 41eae80ea2..085f66e898 100644 --- a/src/runtime/signal_linux_386.go +++ b/src/runtime/signal_linux_386.go @@ -26,7 +26,7 @@ func (c *sigctxt) cs() uint32 { return uint32(c.regs().cs) } func (c *sigctxt) fs() uint32 { return uint32(c.regs().fs) } func (c *sigctxt) gs() uint32 { return uint32(c.regs().gs) } func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) } -func (c *sigctxt) sigaddr() uint32 { return uint32(*(*uintptr)(add(unsafe.Pointer(c.info), 2*ptrSize))) } +func (c *sigctxt) sigaddr() uint32 { return c.info.si_addr } func (c *sigctxt) set_eip(x uint32) { c.regs().eip = x } func (c *sigctxt) set_esp(x uint32) { c.regs().esp = x } diff --git a/src/runtime/signal_linux_amd64.go b/src/runtime/signal_linux_amd64.go index d94b191024..5e339b8a46 100644 --- a/src/runtime/signal_linux_amd64.go +++ b/src/runtime/signal_linux_amd64.go @@ -36,7 +36,7 @@ func (c *sigctxt) cs() uint64 { return uint64(c.regs().cs) } func (c *sigctxt) fs() uint64 { return uint64(c.regs().fs) } func (c *sigctxt) gs() uint64 { return uint64(c.regs().gs) } func (c *sigctxt) sigcode() uint64 { return uint64(c.info.si_code) } -func (c *sigctxt) sigaddr() uint64 { return uint64(*(*uintptr)(add(unsafe.Pointer(c.info), 2*ptrSize))) } +func (c *sigctxt) sigaddr() uint64 { return c.info.si_addr } func (c *sigctxt) set_rip(x uint64) { c.regs().rip = x } func (c *sigctxt) set_rsp(x uint64) { c.regs().rsp = x } diff --git a/src/runtime/signal_linux_arm.go b/src/runtime/signal_linux_arm.go index 4a5670e740..bdb4314fa8 100644 --- a/src/runtime/signal_linux_arm.go +++ b/src/runtime/signal_linux_arm.go @@ -35,7 +35,7 @@ func (c *sigctxt) error() uint32 { return c.regs().error_code } func (c *sigctxt) oldmask() uint32 { return c.regs().oldmask } func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) } -func (c *sigctxt) sigaddr() uint32 { return uint32(*(*uintptr)(add(unsafe.Pointer(c.info), 2*ptrSize))) } +func (c *sigctxt) sigaddr() uint32 { return c.info.si_addr } func (c *sigctxt) set_pc(x uint32) { c.regs().pc = x } func (c *sigctxt) set_sp(x uint32) { c.regs().sp = x } diff --git a/src/runtime/signal_linux_power64x.go b/src/runtime/signal_linux_power64x.go index 8f357033bf..0a406b31fc 100644 --- a/src/runtime/signal_linux_power64x.go +++ b/src/runtime/signal_linux_power64x.go @@ -56,7 +56,7 @@ func (c *sigctxt) xer() uint64 { return c.regs().xer } func (c *sigctxt) ccr() uint64 { return c.regs().ccr } func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) } -func (c *sigctxt) sigaddr() uint64 { return uint64(*(*uintptr)(add(unsafe.Pointer(c.info), 2*ptrSize))) } +func (c *sigctxt) sigaddr() uint64 { return c.info.si_addr } func (c *sigctxt) fault() uint64 { return c.regs().dar } func (c *sigctxt) set_r0(x uint64) { c.regs().gpr[0] = x } From 378c2515aeec0e23662631dc6ba63148594ad92b Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 19 Nov 2014 15:25:33 -0500 Subject: [PATCH 48/68] runtime: remove assumption that noptrdata data bss noptrbss are ordered and contiguous The assumption can be violated by external linkers reordering them or inserting non-Go sections in between them. I looked briefly at trying to write out the _go_.o in external linking mode in a way that forced the ordering, but no matter what there's no way to force Go's data and Go's bss to be next to each other. If there is any data or bss from non-Go objects, it's very likely to get stuck in between them. Instead, rewrite the two places we know about that make the assumption. I grepped for noptrdata to look for more and didn't find any. The added race test (os/exec in external linking mode) fails without the changes in the runtime. It crashes with an invalid pointer dereference. Fixes #9133. LGTM=dneil R=dneil CC=dvyukov, golang-codereviews, iant https://golang.org/cl/179980043 --- src/run.bash | 5 +++-- src/runtime/malloc.go | 11 +++++++++-- src/runtime/race.c | 44 ++++++++++++++++++++++++++++++++++++++----- 3 files changed, 51 insertions(+), 9 deletions(-) diff --git a/src/run.bash b/src/run.bash index 3c9430c87e..9a0e1cb0f2 100755 --- a/src/run.bash +++ b/src/run.bash @@ -70,9 +70,10 @@ case "$GOHOSTOS-$GOOS-$GOARCH-$CGO_ENABLED" in linux-linux-amd64-1 | freebsd-freebsd-amd64-1 | darwin-darwin-amd64-1) echo echo '# Testing race detector.' - go test -race -i runtime/race flag + go test -race -i runtime/race flag os/exec go test -race -run=Output runtime/race - go test -race -short flag + go test -race -short flag os/exec + go test -race -short -ldflags=-linkmode=external flag os/exec esac xcd() { diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 8cf1c3d342..1170449440 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -490,6 +490,8 @@ func GC() { // linker-provided var noptrdata struct{} +var enoptrdata struct{} +var noptrbss struct{} var enoptrbss struct{} // SetFinalizer sets the finalizer associated with x to f. @@ -566,8 +568,13 @@ func SetFinalizer(obj interface{}, finalizer interface{}) { // func main() { // runtime.SetFinalizer(Foo, nil) // } - // The segments are, in order: text, rodata, noptrdata, data, bss, noptrbss. - if uintptr(unsafe.Pointer(&noptrdata)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&enoptrbss)) { + // The relevant segments are: noptrdata, data, bss, noptrbss. + // We cannot assume they are in any order or even contiguous, + // due to external linking. + if uintptr(unsafe.Pointer(&noptrdata)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&enoptrdata)) || + uintptr(unsafe.Pointer(&data)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&edata)) || + uintptr(unsafe.Pointer(&bss)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&ebss)) || + uintptr(unsafe.Pointer(&noptrbss)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&enoptrbss)) { return } gothrow("runtime.SetFinalizer: pointer not in allocated block") diff --git a/src/runtime/race.c b/src/runtime/race.c index 9ac73fbccf..e400c8d102 100644 --- a/src/runtime/race.c +++ b/src/runtime/race.c @@ -63,8 +63,14 @@ void __tsan_go_ignore_sync_end(void); #pragma cgo_import_static __tsan_go_atomic64_compare_exchange extern byte runtime·noptrdata[]; +extern byte runtime·enoptrdata[]; +extern byte runtime·data[]; +extern byte runtime·edata[]; +extern byte runtime·bss[]; +extern byte runtime·ebss[]; +extern byte runtime·noptrbss[]; extern byte runtime·enoptrbss[]; - + // start/end of heap for race_amd64.s uintptr runtime·racearenastart; uintptr runtime·racearenaend; @@ -86,7 +92,13 @@ isvalidaddr(uintptr addr) { if(addr >= runtime·racearenastart && addr < runtime·racearenaend) return true; - if(addr >= (uintptr)runtime·noptrdata && addr < (uintptr)runtime·enoptrbss) + if(addr >= (uintptr)runtime·noptrdata && addr < (uintptr)runtime·enoptrdata) + return true; + if(addr >= (uintptr)runtime·data && addr < (uintptr)runtime·edata) + return true; + if(addr >= (uintptr)runtime·bss && addr < (uintptr)runtime·ebss) + return true; + if(addr >= (uintptr)runtime·noptrbss && addr < (uintptr)runtime·enoptrbss) return true; return false; } @@ -95,15 +107,37 @@ isvalidaddr(uintptr addr) uintptr runtime·raceinit(void) { - uintptr racectx, start, size; + uintptr racectx, start, end, size; // cgo is required to initialize libc, which is used by race runtime if(!runtime·iscgo) runtime·throw("raceinit: race build must use cgo"); runtime·racecall(__tsan_init, &racectx, runtime·racesymbolizethunk); // Round data segment to page boundaries, because it's used in mmap(). - start = (uintptr)runtime·noptrdata & ~(PageSize-1); - size = ROUND((uintptr)runtime·enoptrbss - start, PageSize); + // The relevant sections are noptrdata, data, bss, noptrbss. + // In external linking mode, there may be other non-Go data mixed in, + // and the sections may even occur out of order. + // Work out a conservative range of addresses. + start = ~(uintptr)0; + end = 0; + if(start > (uintptr)runtime·noptrdata) + start = (uintptr)runtime·noptrdata; + if(start > (uintptr)runtime·data) + start = (uintptr)runtime·data; + if(start > (uintptr)runtime·noptrbss) + start = (uintptr)runtime·noptrbss; + if(start > (uintptr)runtime·bss) + start = (uintptr)runtime·bss; + if(end < (uintptr)runtime·enoptrdata) + end = (uintptr)runtime·enoptrdata; + if(end < (uintptr)runtime·edata) + end = (uintptr)runtime·edata; + if(end < (uintptr)runtime·enoptrbss) + end = (uintptr)runtime·enoptrbss; + if(end < (uintptr)runtime·ebss) + end = (uintptr)runtime·ebss; + start = start & ~(PageSize-1); + size = ROUND(end - start, PageSize); runtime·racecall(__tsan_map_shadow, start, size); return racectx; } From ab4578adefd216a6753728b5503ff22fae4ab60b Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Thu, 20 Nov 2014 12:24:03 +1100 Subject: [PATCH 49/68] [dev.cc] runtime: convert remaining windows C code to Go LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/177090043 --- src/runtime/netpoll_windows.go | 2 +- src/runtime/os1_windows.go | 564 +++++++++++++++++++++++++++ src/runtime/os1_windows_386.go | 118 ++++++ src/runtime/os1_windows_amd64.go | 137 +++++++ src/runtime/os2_windows.go | 25 ++ src/runtime/os_windows.c | 636 ------------------------------- src/runtime/os_windows.go | 16 - src/runtime/os_windows.h | 42 -- src/runtime/os_windows_386.c | 128 ------- src/runtime/os_windows_amd64.c | 150 -------- src/runtime/stubs2.go | 1 + src/runtime/syscall_windows.go | 18 +- 12 files changed, 853 insertions(+), 984 deletions(-) create mode 100644 src/runtime/os1_windows.go create mode 100644 src/runtime/os1_windows_386.go create mode 100644 src/runtime/os1_windows_amd64.go create mode 100644 src/runtime/os2_windows.go delete mode 100644 src/runtime/os_windows.c delete mode 100644 src/runtime/os_windows.h delete mode 100644 src/runtime/os_windows_386.c delete mode 100644 src/runtime/os_windows_amd64.c diff --git a/src/runtime/netpoll_windows.go b/src/runtime/netpoll_windows.go index 8a15f182cd..23d5dc00f0 100644 --- a/src/runtime/netpoll_windows.go +++ b/src/runtime/netpoll_windows.go @@ -152,5 +152,5 @@ func handlecompletion(gpp **g, op *net_op, errno int32, qty uint32) { } op.errno = errno op.qty = qty - netpollready(gpp, op.pd, mode) + netpollready((**g)(noescape(unsafe.Pointer(gpp))), op.pd, mode) } diff --git a/src/runtime/os1_windows.go b/src/runtime/os1_windows.go new file mode 100644 index 0000000000..abd2297a30 --- /dev/null +++ b/src/runtime/os1_windows.go @@ -0,0 +1,564 @@ +// Copyright 2009 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. + +package runtime + +import ( + "unsafe" +) + +//go:cgo_import_dynamic runtime._AddVectoredExceptionHandler AddVectoredExceptionHandler "kernel32.dll" +//go:cgo_import_dynamic runtime._CloseHandle CloseHandle "kernel32.dll" +//go:cgo_import_dynamic runtime._CreateEventA CreateEventA "kernel32.dll" +//go:cgo_import_dynamic runtime._CreateThread CreateThread "kernel32.dll" +//go:cgo_import_dynamic runtime._CreateWaitableTimerA CreateWaitableTimerA "kernel32.dll" +//go:cgo_import_dynamic runtime._CryptAcquireContextW CryptAcquireContextW "advapi32.dll" +//go:cgo_import_dynamic runtime._CryptGenRandom CryptGenRandom "advapi32.dll" +//go:cgo_import_dynamic runtime._CryptReleaseContext CryptReleaseContext "advapi32.dll" +//go:cgo_import_dynamic runtime._DuplicateHandle DuplicateHandle "kernel32.dll" +//go:cgo_import_dynamic runtime._ExitProcess ExitProcess "kernel32.dll" +//go:cgo_import_dynamic runtime._FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll" +//go:cgo_import_dynamic runtime._GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll" +//go:cgo_import_dynamic runtime._GetProcAddress GetProcAddress "kernel32.dll" +//go:cgo_import_dynamic runtime._GetStdHandle GetStdHandle "kernel32.dll" +//go:cgo_import_dynamic runtime._GetSystemInfo GetSystemInfo "kernel32.dll" +//go:cgo_import_dynamic runtime._GetThreadContext GetThreadContext "kernel32.dll" +//go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW "kernel32.dll" +//go:cgo_import_dynamic runtime._LoadLibraryA LoadLibraryA "kernel32.dll" +//go:cgo_import_dynamic runtime._NtWaitForSingleObject NtWaitForSingleObject "ntdll.dll" +//go:cgo_import_dynamic runtime._ResumeThread ResumeThread "kernel32.dll" +//go:cgo_import_dynamic runtime._SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll" +//go:cgo_import_dynamic runtime._SetEvent SetEvent "kernel32.dll" +//go:cgo_import_dynamic runtime._SetProcessPriorityBoost SetProcessPriorityBoost "kernel32.dll" +//go:cgo_import_dynamic runtime._SetThreadPriority SetThreadPriority "kernel32.dll" +//go:cgo_import_dynamic runtime._SetUnhandledExceptionFilter SetUnhandledExceptionFilter "kernel32.dll" +//go:cgo_import_dynamic runtime._SetWaitableTimer SetWaitableTimer "kernel32.dll" +//go:cgo_import_dynamic runtime._Sleep Sleep "kernel32.dll" +//go:cgo_import_dynamic runtime._SuspendThread SuspendThread "kernel32.dll" +//go:cgo_import_dynamic runtime._WaitForSingleObject WaitForSingleObject "kernel32.dll" +//go:cgo_import_dynamic runtime._WriteFile WriteFile "kernel32.dll" +//go:cgo_import_dynamic runtime._timeBeginPeriod timeBeginPeriod "winmm.dll" + +var ( + _AddVectoredExceptionHandler, + _CloseHandle, + _CreateEventA, + _CreateThread, + _CreateWaitableTimerA, + _CryptAcquireContextW, + _CryptGenRandom, + _CryptReleaseContext, + _DuplicateHandle, + _ExitProcess, + _FreeEnvironmentStringsW, + _GetEnvironmentStringsW, + _GetProcAddress, + _GetStdHandle, + _GetSystemInfo, + _GetThreadContext, + _LoadLibraryW, + _LoadLibraryA, + _NtWaitForSingleObject, + _ResumeThread, + _SetConsoleCtrlHandler, + _SetEvent, + _SetProcessPriorityBoost, + _SetThreadPriority, + _SetUnhandledExceptionFilter, + _SetWaitableTimer, + _Sleep, + _SuspendThread, + _WaitForSingleObject, + _WriteFile, + _timeBeginPeriod stdFunction +) + +var _GetQueuedCompletionStatusEx stdFunction + +// in sys_windows_386.s and sys_windows_amd64.s +func externalthreadhandler() +func exceptiontramp() +func firstcontinuetramp() +func lastcontinuetramp() + +//go:nosplit +func getLoadLibrary() uintptr { + return uintptr(unsafe.Pointer(_LoadLibraryW)) +} + +//go:nosplit +func getGetProcAddress() uintptr { + return uintptr(unsafe.Pointer(_GetProcAddress)) +} + +func getproccount() int32 { + var info systeminfo + stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info))) + return int32(info.dwnumberofprocessors) +} + +const ( + currentProcess = ^uintptr(0) // -1 = current process + currentThread = ^uintptr(1) // -2 = current thread +) + +var ( + kernel32Name = []byte("kernel32.dll\x00") + addVectoredContinueHandlerName = []byte("AddVectoredContinueHandler\x00") + getQueuedCompletionStatusExName = []byte("GetQueuedCompletionStatusEx\x00") +) + +func osinit() { + setBadSignalMsg() + + kernel32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&kernel32Name[0]))) + + externalthreadhandlerp = funcPC(externalthreadhandler) + + stdcall2(_AddVectoredExceptionHandler, 1, funcPC(exceptiontramp)) + addVectoredContinueHandler := uintptr(0) + if kernel32 != 0 { + addVectoredContinueHandler = stdcall2(_GetProcAddress, kernel32, uintptr(unsafe.Pointer(&addVectoredContinueHandlerName[0]))) + } + if addVectoredContinueHandler == 0 || unsafe.Sizeof(&kernel32) == 4 { + // use SetUnhandledExceptionFilter for windows-386 or + // if VectoredContinueHandler is unavailable. + // note: SetUnhandledExceptionFilter handler won't be called, if debugging. + stdcall1(_SetUnhandledExceptionFilter, funcPC(lastcontinuetramp)) + } else { + stdcall2(stdFunction(unsafe.Pointer(addVectoredContinueHandler)), 1, funcPC(firstcontinuetramp)) + stdcall2(stdFunction(unsafe.Pointer(addVectoredContinueHandler)), 0, funcPC(lastcontinuetramp)) + } + + stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1) + + stdcall1(_timeBeginPeriod, 1) + + ncpu = getproccount() + + // Windows dynamic priority boosting assumes that a process has different types + // of dedicated threads -- GUI, IO, computational, etc. Go processes use + // equivalent threads that all do a mix of GUI, IO, computations, etc. + // In such context dynamic priority boosting does nothing but harm, so we turn it off. + stdcall2(_SetProcessPriorityBoost, currentProcess, 1) + + if kernel32 != 0 { + _GetQueuedCompletionStatusEx = stdFunction(unsafe.Pointer(stdcall2(_GetProcAddress, kernel32, uintptr(unsafe.Pointer(&getQueuedCompletionStatusExName[0]))))) + } +} + +var random_data [_HashRandomBytes]byte + +//go:nosplit +func get_random_data(rnd *unsafe.Pointer, rnd_len *int32) { + const ( + prov_rsa_full = 1 + crypt_verifycontext = 0xF0000000 + ) + var handle uintptr + *rnd = nil + *rnd_len = 0 + if stdcall5(_CryptAcquireContextW, uintptr(unsafe.Pointer(&handle)), 0, 0, prov_rsa_full, crypt_verifycontext) != 0 { + if stdcall3(_CryptGenRandom, handle, _HashRandomBytes, uintptr(unsafe.Pointer(&random_data[0]))) != 0 { + *rnd = unsafe.Pointer(&random_data[0]) + *rnd_len = _HashRandomBytes + } + stdcall2(_CryptReleaseContext, handle, 0) + } +} + +func goenvs() { + var p *uint16 + + env := (*uint16)(unsafe.Pointer(stdcall0(_GetEnvironmentStringsW))) + + n := 0 + for p = env; *p != 0; n++ { + p = (*uint16)(add(unsafe.Pointer(p), uintptr(findnullw(p)+1))) + } + + envs = makeStringSlice(int(n)) + + p = env + for i := 0; i < n; i++ { + envs[i] = gostringw(p) + p = (*uint16)(add(unsafe.Pointer(p), uintptr(findnullw(p)+1))) + } + + stdcall1(_FreeEnvironmentStringsW, uintptr(unsafe.Pointer(env))) +} + +//go:nosplit +func exit(code int32) { + stdcall1(_ExitProcess, uintptr(code)) +} + +//go:nosplit +func write(fd uintptr, buf unsafe.Pointer, n int32) int32 { + const ( + _STD_OUTPUT_HANDLE = ^uintptr(10) // -11 + _STD_ERROR_HANDLE = ^uintptr(11) // -12 + ) + var handle uintptr + switch fd { + case 1: + handle = stdcall1(_GetStdHandle, _STD_OUTPUT_HANDLE) + case 2: + handle = stdcall1(_GetStdHandle, _STD_ERROR_HANDLE) + default: + // assume fd is real windows handle. + handle = fd + } + var written uint32 + stdcall5(_WriteFile, handle, uintptr(buf), uintptr(n), uintptr(unsafe.Pointer(&written)), 0) + return int32(written) +} + +//go:nosplit +func semasleep(ns int64) int32 { + // store ms in ns to save stack space + if ns < 0 { + ns = _INFINITE + } else { + ns = int64(timediv(ns, 1000000, nil)) + if ns == 0 { + ns = 1 + } + } + if stdcall2(_WaitForSingleObject, getg().m.waitsema, uintptr(ns)) != 0 { + return -1 // timeout + } + return 0 +} + +//go:nosplit +func semawakeup(mp *m) { + stdcall1(_SetEvent, mp.waitsema) +} + +//go:nosplit +func semacreate() uintptr { + return stdcall4(_CreateEventA, 0, 0, 0, 0) +} + +func newosproc(mp *m, stk unsafe.Pointer) { + const _STACK_SIZE_PARAM_IS_A_RESERVATION = 0x00010000 + thandle := stdcall6(_CreateThread, 0, 0x20000, + funcPC(tstart_stdcall), uintptr(unsafe.Pointer(mp)), + _STACK_SIZE_PARAM_IS_A_RESERVATION, 0) + if thandle == 0 { + println("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", getlasterror(), ")") + gothrow("runtime.newosproc") + } +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the parent thread (main thread in case of bootstrap), can allocate memory. +func mpreinit(mp *m) { +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the new thread, can not allocate memory. +func minit() { + var thandle uintptr + stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS) + atomicstoreuintptr(&getg().m.thread, thandle) +} + +// Called from dropm to undo the effect of an minit. +func unminit() { + tp := &getg().m.thread + stdcall1(_CloseHandle, *tp) + *tp = 0 +} + +// Described in http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/ +type _KSYSTEM_TIME struct { + LowPart uint32 + High1Time int32 + High2Time int32 +} + +const ( + _INTERRUPT_TIME = 0x7ffe0008 + _SYSTEM_TIME = 0x7ffe0014 +) + +//go:nosplit +func systime(addr uintptr) int64 { + timeaddr := (*_KSYSTEM_TIME)(unsafe.Pointer(addr)) + + var t _KSYSTEM_TIME + for i := 1; i < 10000; i++ { + // these fields must be read in that order (see URL above) + t.High1Time = timeaddr.High1Time + t.LowPart = timeaddr.LowPart + t.High2Time = timeaddr.High2Time + if t.High1Time == t.High2Time { + return int64(t.High1Time)<<32 | int64(t.LowPart) + } + if (i % 100) == 0 { + osyield() + } + } + systemstack(func() { + gothrow("interrupt/system time is changing too fast") + }) + return 0 +} + +//go:nosplit +func unixnano() int64 { + return (systime(_SYSTEM_TIME) - 116444736000000000) * 100 +} + +//go:nosplit +func nanotime() int64 { + return systime(_INTERRUPT_TIME) * 100 +} + +// Calling stdcall on os stack. +//go:nosplit +func stdcall(fn stdFunction) uintptr { + gp := getg() + mp := gp.m + mp.libcall.fn = uintptr(unsafe.Pointer(fn)) + + if mp.profilehz != 0 { + // leave pc/sp for cpu profiler + mp.libcallg = gp + mp.libcallpc = getcallerpc(unsafe.Pointer(&fn)) + // sp must be the last, because once async cpu profiler finds + // all three values to be non-zero, it will use them + mp.libcallsp = getcallersp(unsafe.Pointer(&fn)) + } + asmcgocall(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&mp.libcall)) + mp.libcallsp = 0 + return mp.libcall.r1 +} + +//go:nosplit +func stdcall0(fn stdFunction) uintptr { + mp := getg().m + mp.libcall.n = 0 + mp.libcall.args = uintptr(noescape(unsafe.Pointer(&fn))) // it's unused but must be non-nil, otherwise crashes + return stdcall(fn) +} + +//go:nosplit +func stdcall1(fn stdFunction, a0 uintptr) uintptr { + mp := getg().m + mp.libcall.n = 1 + mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) + return stdcall(fn) +} + +//go:nosplit +func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr { + mp := getg().m + mp.libcall.n = 2 + mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) + return stdcall(fn) +} + +//go:nosplit +func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr { + mp := getg().m + mp.libcall.n = 3 + mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) + return stdcall(fn) +} + +//go:nosplit +func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr { + mp := getg().m + mp.libcall.n = 4 + mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) + return stdcall(fn) +} + +//go:nosplit +func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr { + mp := getg().m + mp.libcall.n = 5 + mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) + return stdcall(fn) +} + +//go:nosplit +func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr { + mp := getg().m + mp.libcall.n = 6 + mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) + return stdcall(fn) +} + +//go:nosplit +func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr { + mp := getg().m + mp.libcall.n = 7 + mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) + return stdcall(fn) +} + +// in sys_windows_386.s and sys_windows_amd64.s +func usleep1(usec uint32) + +//go:nosplit +func osyield() { + usleep1(1) +} + +//go:nosplit +func usleep(us uint32) { + // Have 1us units; want 100ns units. + usleep1(10 * us) +} + +func issigpanic(code uint32) uint32 { + switch code { + default: + return 0 + case _EXCEPTION_ACCESS_VIOLATION: + case _EXCEPTION_INT_DIVIDE_BY_ZERO: + case _EXCEPTION_INT_OVERFLOW: + case _EXCEPTION_FLT_DENORMAL_OPERAND: + case _EXCEPTION_FLT_DIVIDE_BY_ZERO: + case _EXCEPTION_FLT_INEXACT_RESULT: + case _EXCEPTION_FLT_OVERFLOW: + case _EXCEPTION_FLT_UNDERFLOW: + case _EXCEPTION_BREAKPOINT: + } + return 1 +} + +func initsig() { + /* + // TODO(brainman): I don't think we need that bit of code + // following line keeps these functions alive at link stage + // if there's a better way please write it here + void *e = runtime·exceptiontramp; + void *f = runtime·firstcontinuetramp; + void *l = runtime·lastcontinuetramp; + USED(e); + USED(f); + USED(l); + */ +} + +func ctrlhandler1(_type uint32) uint32 { + var s uint32 + + switch _type { + case _CTRL_C_EVENT, _CTRL_BREAK_EVENT: + s = _SIGINT + default: + return 0 + } + + if sigsend(s) { + return 1 + } + exit(2) // SIGINT, SIGTERM, etc + return 0 +} + +// in sys_windows_386.s and sys_windows_amd64.s +func profileloop() + +var profiletimer uintptr + +func profilem(mp *m) { + var r *context + rbuf := make([]byte, unsafe.Sizeof(*r)+15) + + tls := &mp.tls[0] + if mp == &m0 { + tls = &tls0[0] + } + gp := *((**g)(unsafe.Pointer(tls))) + + // align Context to 16 bytes + r = (*context)(unsafe.Pointer((uintptr(unsafe.Pointer(&rbuf[15]))) &^ 15)) + r.contextflags = _CONTEXT_CONTROL + stdcall2(_GetThreadContext, mp.thread, uintptr(unsafe.Pointer(r))) + dosigprof(r, gp, mp) +} + +func profileloop1() { + stdcall2(_SetThreadPriority, currentThread, _THREAD_PRIORITY_HIGHEST) + + for { + stdcall2(_WaitForSingleObject, profiletimer, _INFINITE) + first := (*m)(atomicloadp(unsafe.Pointer(&allm))) + for mp := first; mp != nil; mp = mp.alllink { + thread := atomicloaduintptr(&mp.thread) + // Do not profile threads blocked on Notes, + // this includes idle worker threads, + // idle timer thread, idle heap scavenger, etc. + if thread == 0 || mp.profilehz == 0 || mp.blocked { + continue + } + stdcall1(_SuspendThread, thread) + if mp.profilehz != 0 && !mp.blocked { + profilem(mp) + } + stdcall1(_ResumeThread, thread) + } + } +} + +var cpuprofilerlock mutex + +func resetcpuprofiler(hz int32) { + lock(&cpuprofilerlock) + if profiletimer == 0 { + timer := stdcall3(_CreateWaitableTimerA, 0, 0, 0) + atomicstoreuintptr(&profiletimer, timer) + thread := stdcall6(_CreateThread, 0, 0, funcPC(profileloop), 0, 0, 0) + stdcall2(_SetThreadPriority, thread, _THREAD_PRIORITY_HIGHEST) + stdcall1(_CloseHandle, thread) + } + unlock(&cpuprofilerlock) + + ms := int32(0) + due := ^int64(^uint64(1 << 63)) + if hz > 0 { + ms = 1000 / hz + if ms == 0 { + ms = 1 + } + due = int64(ms) * -10000 + } + stdcall6(_SetWaitableTimer, profiletimer, uintptr(unsafe.Pointer(&due)), uintptr(ms), 0, 0, 0) + atomicstore((*uint32)(unsafe.Pointer(&getg().m.profilehz)), uint32(hz)) +} + +func memlimit() uintptr { + return 0 +} + +var ( + badsignalmsg [100]byte + badsignallen int32 +) + +func setBadSignalMsg() { + const msg = "runtime: signal received on thread not created by Go.\n" + for i, c := range msg { + badsignalmsg[i] = byte(c) + badsignallen++ + } +} + +func crash() { + // TODO: This routine should do whatever is needed + // to make the Windows program abort/crash as it + // would if Go was not intercepting signals. + // On Unix the routine would remove the custom signal + // handler and then raise a signal (like SIGABRT). + // Something like that should happen here. + // It's okay to leave this empty for now: if crash returns + // the ordinary exit-after-panic happens. +} diff --git a/src/runtime/os1_windows_386.go b/src/runtime/os1_windows_386.go new file mode 100644 index 0000000000..0afef91566 --- /dev/null +++ b/src/runtime/os1_windows_386.go @@ -0,0 +1,118 @@ +// Copyright 2009 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. + +package runtime + +import ( + "unsafe" +) + +var text struct{} + +func dumpregs(r *context) { + print("eax ", hex(r.eax), "\n") + print("ebx ", hex(r.ebx), "\n") + print("ecx ", hex(r.ecx), "\n") + print("edx ", hex(r.edx), "\n") + print("edi ", hex(r.edi), "\n") + print("esi ", hex(r.esi), "\n") + print("ebp ", hex(r.ebp), "\n") + print("esp ", hex(r.esp), "\n") + print("eip ", hex(r.eip), "\n") + print("eflags ", hex(r.eflags), "\n") + print("cs ", hex(r.segcs), "\n") + print("fs ", hex(r.segfs), "\n") + print("gs ", hex(r.seggs), "\n") +} + +func isgoexception(info *exceptionrecord, r *context) bool { + // Only handle exception if executing instructions in Go binary + // (not Windows library code). + if r.eip < uint32(uintptr(unsafe.Pointer(&text))) || uint32(uintptr(unsafe.Pointer(&etext))) < r.eip { + return false + } + + if issigpanic(info.exceptioncode) == 0 { + return false + } + + return true +} + +// Called by sigtramp from Windows VEH handler. +// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION) +// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH). +func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 { + if !isgoexception(info, r) { + return _EXCEPTION_CONTINUE_SEARCH + } + + // Make it look like a call to the signal func. + // Have to pass arguments out of band since + // augmenting the stack frame would break + // the unwinding code. + gp.sig = info.exceptioncode + gp.sigcode0 = uintptr(info.exceptioninformation[0]) + gp.sigcode1 = uintptr(info.exceptioninformation[1]) + gp.sigpc = uintptr(r.eip) + + // Only push runtime·sigpanic if r->eip != 0. + // If r->eip == 0, probably panicked because of a + // call to a nil func. Not pushing that onto sp will + // make the trace look like a call to runtime·sigpanic instead. + // (Otherwise the trace will end at runtime·sigpanic and we + // won't get to see who faulted.) + if r.eip != 0 { + sp := unsafe.Pointer(uintptr(r.esp)) + sp = add(sp, ^uintptr(unsafe.Sizeof(uintptr(0))-1)) // sp-- + *((*uintptr)(sp)) = uintptr(r.eip) + r.esp = uint32(uintptr(sp)) + } + r.eip = uint32(funcPC(sigpanic)) + return _EXCEPTION_CONTINUE_EXECUTION +} + +// lastcontinuehandler is reached, because runtime cannot handle +// current exception. lastcontinuehandler will print crash info and exit. +func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) uint32 { + _g_ := getg() + + if panicking != 0 { // traceback already printed + exit(2) + } + panicking = 1 + + print("Exception ", hex(info.exceptioncode), " ", hex(info.exceptioninformation[0]), " ", hex(info.exceptioninformation[1]), " ", hex(r.eip), "\n") + + print("PC=", hex(r.eip), "\n") + if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 { + print("signal arrived during cgo execution\n") + gp = _g_.m.lockedg + } + print("\n") + + var docrash bool + if gotraceback(&docrash) > 0 { + tracebacktrap(uintptr(r.eip), uintptr(r.esp), 0, gp) + tracebackothers(gp) + dumpregs(r) + } + + if docrash { + crash() + } + + exit(2) + return 0 // not reached +} + +func sigenable(sig uint32) { +} + +func sigdisable(sig uint32) { +} + +func dosigprof(r *context, gp *g, mp *m) { + sigprof((*byte)(unsafe.Pointer(uintptr(r.eip))), (*byte)(unsafe.Pointer(uintptr(r.esp))), nil, gp, mp) +} diff --git a/src/runtime/os1_windows_amd64.go b/src/runtime/os1_windows_amd64.go new file mode 100644 index 0000000000..0d21b38812 --- /dev/null +++ b/src/runtime/os1_windows_amd64.go @@ -0,0 +1,137 @@ +// Copyright 2011 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. + +package runtime + +import ( + "unsafe" +) + +var text struct{} + +func dumpregs(r *context) { + print("rax ", hex(r.rax), "\n") + print("rbx ", hex(r.rbx), "\n") + print("rcx ", hex(r.rcx), "\n") + print("rdi ", hex(r.rdi), "\n") + print("rsi ", hex(r.rsi), "\n") + print("rbp ", hex(r.rbp), "\n") + print("rsp ", hex(r.rsp), "\n") + print("r8 ", hex(r.r8), "\n") + print("r9 ", hex(r.r9), "\n") + print("r10 ", hex(r.r10), "\n") + print("r11 ", hex(r.r11), "\n") + print("r12 ", hex(r.r12), "\n") + print("r13 ", hex(r.r13), "\n") + print("r14 ", hex(r.r14), "\n") + print("r15 ", hex(r.r15), "\n") + print("rip ", hex(r.rip), "\n") + print("rflags ", hex(r.eflags), "\n") + print("cs ", hex(r.segcs), "\n") + print("fs ", hex(r.segfs), "\n") + print("gs ", hex(r.seggs), "\n") +} + +func isgoexception(info *exceptionrecord, r *context) bool { + // Only handle exception if executing instructions in Go binary + // (not Windows library code). + if r.rip < uint64(uintptr(unsafe.Pointer(&text))) || uint64(uintptr(unsafe.Pointer(&etext))) < r.rip { + return false + } + + if issigpanic(info.exceptioncode) == 0 { + return false + } + + return true +} + +// Called by sigtramp from Windows VEH handler. +// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION) +// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH). + +func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 { + if !isgoexception(info, r) { + return _EXCEPTION_CONTINUE_SEARCH + } + + // Make it look like a call to the signal func. + // Have to pass arguments out of band since + // augmenting the stack frame would break + // the unwinding code. + gp.sig = info.exceptioncode + gp.sigcode0 = uintptr(info.exceptioninformation[0]) + gp.sigcode1 = uintptr(info.exceptioninformation[1]) + gp.sigpc = uintptr(r.rip) + + // Only push runtime·sigpanic if r->rip != 0. + // If r->rip == 0, probably panicked because of a + // call to a nil func. Not pushing that onto sp will + // make the trace look like a call to runtime·sigpanic instead. + // (Otherwise the trace will end at runtime·sigpanic and we + // won't get to see who faulted.) + if r.rip != 0 { + sp := unsafe.Pointer(uintptr(r.rsp)) + sp = add(sp, ^uintptr(unsafe.Sizeof(uintptr(0))-1)) // sp-- + *((*uintptr)(sp)) = uintptr(r.rip) + r.rsp = uint64(uintptr(sp)) + } + r.rip = uint64(funcPC(sigpanic)) + return _EXCEPTION_CONTINUE_EXECUTION +} + +// It seems Windows searches ContinueHandler's list even +// if ExceptionHandler returns EXCEPTION_CONTINUE_EXECUTION. +// firstcontinuehandler will stop that search, +// if exceptionhandler did the same earlier. +func firstcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 { + if !isgoexception(info, r) { + return _EXCEPTION_CONTINUE_SEARCH + } + return _EXCEPTION_CONTINUE_EXECUTION +} + +// lastcontinuehandler is reached, because runtime cannot handle +// current exception. lastcontinuehandler will print crash info and exit. +func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) uint32 { + _g_ := getg() + + if panicking != 0 { // traceback already printed + exit(2) + } + panicking = 1 + + print("Exception ", hex(info.exceptioncode), " ", hex(info.exceptioninformation[0]), " ", hex(info.exceptioninformation[1]), " ", hex(r.rip), "\n") + + print("PC=", hex(r.rip), "\n") + if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 { + print("signal arrived during cgo execution\n") + gp = _g_.m.lockedg + } + print("\n") + + var docrash bool + if gotraceback(&docrash) > 0 { + tracebacktrap(uintptr(r.rip), uintptr(r.rsp), 0, gp) + tracebackothers(gp) + dumpregs(r) + } + + if docrash { + crash() + } + + exit(2) + return 0 // not reached +} + +func sigenable(sig uint32) { +} + +func sigdisable(sig uint32) { +} + +func dosigprof(r *context, gp *g, mp *m) { + sigprof((*byte)(unsafe.Pointer(uintptr(r.rip))), (*byte)(unsafe.Pointer(uintptr(r.rsp))), nil, gp, mp) +} diff --git a/src/runtime/os2_windows.go b/src/runtime/os2_windows.go new file mode 100644 index 0000000000..d5b1f471fc --- /dev/null +++ b/src/runtime/os2_windows.go @@ -0,0 +1,25 @@ +// Copyright 2009 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. + +package runtime + +import "unsafe" + +// Call a Windows function with stdcall conventions, +// and switch to os stack during the call. +func asmstdcall(fn unsafe.Pointer) + +func getlasterror() uint32 +func setlasterror(err uint32) + +// Function to be called by windows CreateThread +// to start new os thread. +func tstart_stdcall(newm *m) uint32 + +func ctrlhandler(_type uint32) uint32 + +// TODO(brainman): should not need those +const ( + _NSIG = 65 +) diff --git a/src/runtime/os_windows.c b/src/runtime/os_windows.c deleted file mode 100644 index b8b8eda5f3..0000000000 --- a/src/runtime/os_windows.c +++ /dev/null @@ -1,636 +0,0 @@ -// Copyright 2009 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. - -#include "runtime.h" -#include "type.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "textflag.h" -#include "arch_GOARCH.h" -#include "malloc.h" - -#pragma dynimport runtime·AddVectoredExceptionHandler AddVectoredExceptionHandler "kernel32.dll" -#pragma dynimport runtime·CloseHandle CloseHandle "kernel32.dll" -#pragma dynimport runtime·CreateEvent CreateEventA "kernel32.dll" -#pragma dynimport runtime·CreateThread CreateThread "kernel32.dll" -#pragma dynimport runtime·CreateWaitableTimer CreateWaitableTimerA "kernel32.dll" -#pragma dynimport runtime·CryptAcquireContextW CryptAcquireContextW "advapi32.dll" -#pragma dynimport runtime·CryptGenRandom CryptGenRandom "advapi32.dll" -#pragma dynimport runtime·CryptReleaseContext CryptReleaseContext "advapi32.dll" -#pragma dynimport runtime·DuplicateHandle DuplicateHandle "kernel32.dll" -#pragma dynimport runtime·ExitProcess ExitProcess "kernel32.dll" -#pragma dynimport runtime·FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll" -#pragma dynimport runtime·GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll" -#pragma dynimport runtime·GetProcAddress GetProcAddress "kernel32.dll" -#pragma dynimport runtime·GetStdHandle GetStdHandle "kernel32.dll" -#pragma dynimport runtime·GetSystemInfo GetSystemInfo "kernel32.dll" -#pragma dynimport runtime·GetThreadContext GetThreadContext "kernel32.dll" -#pragma dynimport runtime·LoadLibrary LoadLibraryW "kernel32.dll" -#pragma dynimport runtime·LoadLibraryA LoadLibraryA "kernel32.dll" -#pragma dynimport runtime·NtWaitForSingleObject NtWaitForSingleObject "ntdll.dll" -#pragma dynimport runtime·ResumeThread ResumeThread "kernel32.dll" -#pragma dynimport runtime·SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll" -#pragma dynimport runtime·SetEvent SetEvent "kernel32.dll" -#pragma dynimport runtime·SetProcessPriorityBoost SetProcessPriorityBoost "kernel32.dll" -#pragma dynimport runtime·SetThreadPriority SetThreadPriority "kernel32.dll" -#pragma dynimport runtime·SetUnhandledExceptionFilter SetUnhandledExceptionFilter "kernel32.dll" -#pragma dynimport runtime·SetWaitableTimer SetWaitableTimer "kernel32.dll" -#pragma dynimport runtime·Sleep Sleep "kernel32.dll" -#pragma dynimport runtime·SuspendThread SuspendThread "kernel32.dll" -#pragma dynimport runtime·WaitForSingleObject WaitForSingleObject "kernel32.dll" -#pragma dynimport runtime·WriteFile WriteFile "kernel32.dll" -#pragma dynimport runtime·timeBeginPeriod timeBeginPeriod "winmm.dll" - -extern void *runtime·AddVectoredExceptionHandler; -extern void *runtime·CloseHandle; -extern void *runtime·CreateEvent; -extern void *runtime·CreateThread; -extern void *runtime·CreateWaitableTimer; -extern void *runtime·CryptAcquireContextW; -extern void *runtime·CryptGenRandom; -extern void *runtime·CryptReleaseContext; -extern void *runtime·DuplicateHandle; -extern void *runtime·ExitProcess; -extern void *runtime·FreeEnvironmentStringsW; -extern void *runtime·GetEnvironmentStringsW; -extern void *runtime·GetProcAddress; -extern void *runtime·GetStdHandle; -extern void *runtime·GetSystemInfo; -extern void *runtime·GetThreadContext; -extern void *runtime·LoadLibrary; -extern void *runtime·LoadLibraryA; -extern void *runtime·NtWaitForSingleObject; -extern void *runtime·ResumeThread; -extern void *runtime·SetConsoleCtrlHandler; -extern void *runtime·SetEvent; -extern void *runtime·SetProcessPriorityBoost; -extern void *runtime·SetThreadPriority; -extern void *runtime·SetUnhandledExceptionFilter; -extern void *runtime·SetWaitableTimer; -extern void *runtime·Sleep; -extern void *runtime·SuspendThread; -extern void *runtime·WaitForSingleObject; -extern void *runtime·WriteFile; -extern void *runtime·timeBeginPeriod; - -#pragma dataflag NOPTR -void *runtime·GetQueuedCompletionStatusEx; - -extern uintptr runtime·externalthreadhandlerp; -void runtime·externalthreadhandler(void); -void runtime·exceptiontramp(void); -void runtime·firstcontinuetramp(void); -void runtime·lastcontinuetramp(void); - -#pragma textflag NOSPLIT -uintptr -runtime·getLoadLibrary(void) -{ - return (uintptr)runtime·LoadLibrary; -} - -#pragma textflag NOSPLIT -uintptr -runtime·getGetProcAddress(void) -{ - return (uintptr)runtime·GetProcAddress; -} - -static int32 -getproccount(void) -{ - SystemInfo info; - - runtime·stdcall1(runtime·GetSystemInfo, (uintptr)&info); - return info.dwNumberOfProcessors; -} - -void -runtime·osinit(void) -{ - void *kernel32; - void *addVectoredContinueHandler; - - kernel32 = runtime·stdcall1(runtime·LoadLibraryA, (uintptr)"kernel32.dll"); - - runtime·externalthreadhandlerp = (uintptr)runtime·externalthreadhandler; - - runtime·stdcall2(runtime·AddVectoredExceptionHandler, 1, (uintptr)runtime·exceptiontramp); - addVectoredContinueHandler = nil; - if(kernel32 != nil) - addVectoredContinueHandler = runtime·stdcall2(runtime·GetProcAddress, (uintptr)kernel32, (uintptr)"AddVectoredContinueHandler"); - if(addVectoredContinueHandler == nil || sizeof(void*) == 4) { - // use SetUnhandledExceptionFilter for windows-386 or - // if VectoredContinueHandler is unavailable. - // note: SetUnhandledExceptionFilter handler won't be called, if debugging. - runtime·stdcall1(runtime·SetUnhandledExceptionFilter, (uintptr)runtime·lastcontinuetramp); - } else { - runtime·stdcall2(addVectoredContinueHandler, 1, (uintptr)runtime·firstcontinuetramp); - runtime·stdcall2(addVectoredContinueHandler, 0, (uintptr)runtime·lastcontinuetramp); - } - - runtime·stdcall2(runtime·SetConsoleCtrlHandler, (uintptr)runtime·ctrlhandler, 1); - - runtime·stdcall1(runtime·timeBeginPeriod, 1); - - runtime·ncpu = getproccount(); - - // Windows dynamic priority boosting assumes that a process has different types - // of dedicated threads -- GUI, IO, computational, etc. Go processes use - // equivalent threads that all do a mix of GUI, IO, computations, etc. - // In such context dynamic priority boosting does nothing but harm, so we turn it off. - runtime·stdcall2(runtime·SetProcessPriorityBoost, -1, 1); - - if(kernel32 != nil) { - runtime·GetQueuedCompletionStatusEx = runtime·stdcall2(runtime·GetProcAddress, (uintptr)kernel32, (uintptr)"GetQueuedCompletionStatusEx"); - } -} - -#pragma textflag NOSPLIT -void -runtime·get_random_data(byte **rnd, int32 *rnd_len) -{ - uintptr handle; - *rnd = nil; - *rnd_len = 0; - if(runtime·stdcall5(runtime·CryptAcquireContextW, (uintptr)&handle, (uintptr)nil, (uintptr)nil, - 1 /* PROV_RSA_FULL */, - 0xf0000000U /* CRYPT_VERIFYCONTEXT */) != 0) { - static byte random_data[HashRandomBytes]; - if(runtime·stdcall3(runtime·CryptGenRandom, handle, HashRandomBytes, (uintptr)&random_data[0])) { - *rnd = random_data; - *rnd_len = HashRandomBytes; - } - runtime·stdcall2(runtime·CryptReleaseContext, handle, 0); - } -} - -void -runtime·goenvs(void) -{ - extern Slice runtime·envs; - - uint16 *env; - String *s; - int32 i, n; - uint16 *p; - - env = runtime·stdcall0(runtime·GetEnvironmentStringsW); - - n = 0; - for(p=env; *p; n++) - p += runtime·findnullw(p)+1; - - runtime·envs = runtime·makeStringSlice(n); - s = (String*)runtime·envs.array; - - p = env; - for(i=0; im->waitsema, ns) != 0) - return -1; // timeout - return 0; -} - -#pragma textflag NOSPLIT -void -runtime·semawakeup(M *mp) -{ - runtime·stdcall1(runtime·SetEvent, mp->waitsema); -} - -#pragma textflag NOSPLIT -uintptr -runtime·semacreate(void) -{ - return (uintptr)runtime·stdcall4(runtime·CreateEvent, 0, 0, 0, 0); -} - -#define STACK_SIZE_PARAM_IS_A_RESERVATION ((uintptr)0x00010000) - -void -runtime·newosproc(M *mp, void *stk) -{ - void *thandle; - - USED(stk); - - thandle = runtime·stdcall6(runtime·CreateThread, - (uintptr)nil, 0x20000, (uintptr)runtime·tstart_stdcall, (uintptr)mp, - STACK_SIZE_PARAM_IS_A_RESERVATION, (uintptr)nil); - if(thandle == nil) { - runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror()); - runtime·throw("runtime.newosproc"); - } -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the parent thread (main thread in case of bootstrap), can allocate memory. -void -runtime·mpreinit(M *mp) -{ - USED(mp); -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the new thread, can not allocate memory. -void -runtime·minit(void) -{ - uintptr thandle; - - // -1 = current process, -2 = current thread - runtime·stdcall7(runtime·DuplicateHandle, -1, -2, -1, (uintptr)&thandle, 0, 0, DUPLICATE_SAME_ACCESS); - runtime·atomicstoreuintptr(&g->m->thread, thandle); -} - -// Called from dropm to undo the effect of an minit. -void -runtime·unminit(void) -{ - runtime·stdcall1(runtime·CloseHandle, g->m->thread); - g->m->thread = 0; -} - -// Described in http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/ -typedef struct KSYSTEM_TIME { - uint32 LowPart; - int32 High1Time; - int32 High2Time; -} KSYSTEM_TIME; - -#pragma dataflag NOPTR -const KSYSTEM_TIME* INTERRUPT_TIME = (KSYSTEM_TIME*)0x7ffe0008; -#pragma dataflag NOPTR -const KSYSTEM_TIME* SYSTEM_TIME = (KSYSTEM_TIME*)0x7ffe0014; - -static void badsystime(void); - -#pragma textflag NOSPLIT -int64 -runtime·systime(KSYSTEM_TIME *timeaddr) -{ - KSYSTEM_TIME t; - int32 i; - void (*fn)(void); - - for(i = 1; i < 10000; i++) { - // these fields must be read in that order (see URL above) - t.High1Time = timeaddr->High1Time; - t.LowPart = timeaddr->LowPart; - t.High2Time = timeaddr->High2Time; - if(t.High1Time == t.High2Time) - return (int64)t.High1Time<<32 | t.LowPart; - if((i%100) == 0) - runtime·osyield(); - } - fn = badsystime; - runtime·onM(&fn); - return 0; -} - -#pragma textflag NOSPLIT -int64 -runtime·unixnano(void) -{ - return (runtime·systime(SYSTEM_TIME) - 116444736000000000LL) * 100LL; -} - -static void -badsystime(void) -{ - runtime·throw("interrupt/system time is changing too fast"); -} - -#pragma textflag NOSPLIT -int64 -runtime·nanotime(void) -{ - return runtime·systime(INTERRUPT_TIME) * 100LL; -} - -// Calling stdcall on os stack. -#pragma textflag NOSPLIT -static void* -stdcall(void *fn) -{ - g->m->libcall.fn = (uintptr)fn; - if(g->m->profilehz != 0) { - // leave pc/sp for cpu profiler - g->m->libcallg = g; - g->m->libcallpc = (uintptr)runtime·getcallerpc(&fn); - // sp must be the last, because once async cpu profiler finds - // all three values to be non-zero, it will use them - g->m->libcallsp = (uintptr)runtime·getcallersp(&fn); - } - runtime·asmcgocall(runtime·asmstdcall, &g->m->libcall); - g->m->libcallsp = 0; - return (void*)g->m->libcall.r1; -} - -#pragma textflag NOSPLIT -void* -runtime·stdcall0(void *fn) -{ - g->m->libcall.n = 0; - g->m->libcall.args = (uintptr)&fn; // it's unused but must be non-nil, otherwise crashes - return stdcall(fn); -} - -#pragma textflag NOSPLIT -void* -runtime·stdcall1(void *fn, uintptr a0) -{ - USED(a0); - g->m->libcall.n = 1; - g->m->libcall.args = (uintptr)&a0; - return stdcall(fn); -} - -#pragma textflag NOSPLIT -void* -runtime·stdcall2(void *fn, uintptr a0, uintptr a1) -{ - USED(a0, a1); - g->m->libcall.n = 2; - g->m->libcall.args = (uintptr)&a0; - return stdcall(fn); -} - -#pragma textflag NOSPLIT -void* -runtime·stdcall3(void *fn, uintptr a0, uintptr a1, uintptr a2) -{ - USED(a0, a1, a2); - g->m->libcall.n = 3; - g->m->libcall.args = (uintptr)&a0; - return stdcall(fn); -} - -#pragma textflag NOSPLIT -void* -runtime·stdcall4(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3) -{ - USED(a0, a1, a2, a3); - g->m->libcall.n = 4; - g->m->libcall.args = (uintptr)&a0; - return stdcall(fn); -} - -#pragma textflag NOSPLIT -void* -runtime·stdcall5(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4) -{ - USED(a0, a1, a2, a3, a4); - g->m->libcall.n = 5; - g->m->libcall.args = (uintptr)&a0; - return stdcall(fn); -} - -#pragma textflag NOSPLIT -void* -runtime·stdcall6(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5) -{ - USED(a0, a1, a2, a3, a4, a5); - g->m->libcall.n = 6; - g->m->libcall.args = (uintptr)&a0; - return stdcall(fn); -} - -#pragma textflag NOSPLIT -void* -runtime·stdcall7(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5, uintptr a6) -{ - USED(a0, a1, a2, a3, a4, a5, a6); - g->m->libcall.n = 7; - g->m->libcall.args = (uintptr)&a0; - return stdcall(fn); -} - -extern void runtime·usleep1(uint32); - -#pragma textflag NOSPLIT -void -runtime·osyield(void) -{ - runtime·usleep1(1); -} - -#pragma textflag NOSPLIT -void -runtime·usleep(uint32 us) -{ - // Have 1us units; want 100ns units. - runtime·usleep1(10*us); -} - -uint32 -runtime·issigpanic(uint32 code) -{ - switch(code) { - case EXCEPTION_ACCESS_VIOLATION: - case EXCEPTION_INT_DIVIDE_BY_ZERO: - case EXCEPTION_INT_OVERFLOW: - case EXCEPTION_FLT_DENORMAL_OPERAND: - case EXCEPTION_FLT_DIVIDE_BY_ZERO: - case EXCEPTION_FLT_INEXACT_RESULT: - case EXCEPTION_FLT_OVERFLOW: - case EXCEPTION_FLT_UNDERFLOW: - case EXCEPTION_BREAKPOINT: - return 1; - } - return 0; -} - -void -runtime·initsig(void) -{ - // following line keeps these functions alive at link stage - // if there's a better way please write it here - void *e = runtime·exceptiontramp; - void *f = runtime·firstcontinuetramp; - void *l = runtime·lastcontinuetramp; - USED(e); - USED(f); - USED(l); -} - -uint32 -runtime·ctrlhandler1(uint32 type) -{ - int32 s; - - switch(type) { - case CTRL_C_EVENT: - case CTRL_BREAK_EVENT: - s = SIGINT; - break; - default: - return 0; - } - - if(runtime·sigsend(s)) - return 1; - runtime·exit(2); // SIGINT, SIGTERM, etc - return 0; -} - -extern void runtime·dosigprof(Context *r, G *gp, M *mp); -extern void runtime·profileloop(void); -#pragma dataflag NOPTR -static void *profiletimer; - -static void -profilem(M *mp) -{ - extern M runtime·m0; - extern uint32 runtime·tls0[]; - byte rbuf[sizeof(Context)+15]; - Context *r; - void *tls; - G *gp; - - tls = mp->tls; - if(mp == &runtime·m0) - tls = runtime·tls0; - gp = *(G**)tls; - - // align Context to 16 bytes - r = (Context*)((uintptr)(&rbuf[15]) & ~15); - r->ContextFlags = CONTEXT_CONTROL; - runtime·stdcall2(runtime·GetThreadContext, (uintptr)mp->thread, (uintptr)r); - runtime·dosigprof(r, gp, mp); -} - -void -runtime·profileloop1(void) -{ - M *mp, *allm; - uintptr thread; - - runtime·stdcall2(runtime·SetThreadPriority, -2, THREAD_PRIORITY_HIGHEST); - - for(;;) { - runtime·stdcall2(runtime·WaitForSingleObject, (uintptr)profiletimer, -1); - allm = runtime·atomicloadp(&runtime·allm); - for(mp = allm; mp != nil; mp = mp->alllink) { - thread = runtime·atomicloaduintptr(&mp->thread); - // Do not profile threads blocked on Notes, - // this includes idle worker threads, - // idle timer thread, idle heap scavenger, etc. - if(thread == 0 || mp->profilehz == 0 || mp->blocked) - continue; - runtime·stdcall1(runtime·SuspendThread, (uintptr)thread); - if(mp->profilehz != 0 && !mp->blocked) - profilem(mp); - runtime·stdcall1(runtime·ResumeThread, (uintptr)thread); - } - } -} - -void -runtime·resetcpuprofiler(int32 hz) -{ - static Mutex lock; - void *timer, *thread; - int32 ms; - int64 due; - - runtime·lock(&lock); - if(profiletimer == nil) { - timer = runtime·stdcall3(runtime·CreateWaitableTimer, (uintptr)nil, (uintptr)nil, (uintptr)nil); - runtime·atomicstorep(&profiletimer, timer); - thread = runtime·stdcall6(runtime·CreateThread, - (uintptr)nil, (uintptr)nil, (uintptr)runtime·profileloop, (uintptr)nil, (uintptr)nil, (uintptr)nil); - runtime·stdcall2(runtime·SetThreadPriority, (uintptr)thread, THREAD_PRIORITY_HIGHEST); - runtime·stdcall1(runtime·CloseHandle, (uintptr)thread); - } - runtime·unlock(&lock); - - ms = 0; - due = 1LL<<63; - if(hz > 0) { - ms = 1000 / hz; - if(ms == 0) - ms = 1; - due = ms * -10000; - } - runtime·stdcall6(runtime·SetWaitableTimer, - (uintptr)profiletimer, (uintptr)&due, ms, (uintptr)nil, (uintptr)nil, (uintptr)nil); - runtime·atomicstore((uint32*)&g->m->profilehz, hz); -} - -uintptr -runtime·memlimit(void) -{ - return 0; -} - -#pragma dataflag NOPTR -int8 runtime·badsignalmsg[] = "runtime: signal received on thread not created by Go.\n"; -int32 runtime·badsignallen = sizeof runtime·badsignalmsg - 1; - -void -runtime·crash(void) -{ - // TODO: This routine should do whatever is needed - // to make the Windows program abort/crash as it - // would if Go was not intercepting signals. - // On Unix the routine would remove the custom signal - // handler and then raise a signal (like SIGABRT). - // Something like that should happen here. - // It's okay to leave this empty for now: if crash returns - // the ordinary exit-after-panic happens. -} diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go index fcd8f44cc4..097b5d6290 100644 --- a/src/runtime/os_windows.go +++ b/src/runtime/os_windows.go @@ -4,24 +4,8 @@ package runtime -import "unsafe" - type stdFunction *byte -func stdcall0(fn stdFunction) uintptr -func stdcall1(fn stdFunction, a0 uintptr) uintptr -func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr -func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr -func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr -func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr -func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr -func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr - -func asmstdcall(fn unsafe.Pointer) -func getlasterror() uint32 -func setlasterror(err uint32) -func usleep1(usec uint32) - func os_sigpipe() { gothrow("too many writes on closed pipe") } diff --git a/src/runtime/os_windows.h b/src/runtime/os_windows.h deleted file mode 100644 index d5d168d77b..0000000000 --- a/src/runtime/os_windows.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2009 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. - -extern void *runtime·LoadLibrary; -extern void *runtime·GetProcAddress; -extern void *runtime·GetQueuedCompletionStatusEx; - -// Call a Windows function with stdcall conventions, -// and switch to os stack during the call. -void runtime·asmstdcall(void *c); -void *runtime·stdcall0(void *fn); -void *runtime·stdcall1(void *fn, uintptr a0); -void *runtime·stdcall2(void *fn, uintptr a0, uintptr a1); -void *runtime·stdcall3(void *fn, uintptr a0, uintptr a1, uintptr a2); -void *runtime·stdcall4(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3); -void *runtime·stdcall5(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4); -void *runtime·stdcall6(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5); -void *runtime·stdcall7(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5, uintptr a6); - -uint32 runtime·getlasterror(void); -void runtime·setlasterror(uint32 err); - -// Function to be called by windows CreateThread -// to start new os thread. -uint32 runtime·tstart_stdcall(M *newm); - -uint32 runtime·issigpanic(uint32); -void runtime·sigpanic(void); -uint32 runtime·ctrlhandler(uint32 type); - -// Windows dll function to go callback entry. -byte *runtime·compilecallback(Eface fn, bool cleanstack); -void *runtime·callbackasm(void); - -void runtime·install_exception_handler(void); -void runtime·remove_exception_handler(void); - -// TODO(brainman): should not need those -enum { - NSIG = 65, -}; diff --git a/src/runtime/os_windows_386.c b/src/runtime/os_windows_386.c deleted file mode 100644 index 9962f0dc2e..0000000000 --- a/src/runtime/os_windows_386.c +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2009 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. - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" - -void -runtime·dumpregs(Context *r) -{ - runtime·printf("eax %x\n", r->Eax); - runtime·printf("ebx %x\n", r->Ebx); - runtime·printf("ecx %x\n", r->Ecx); - runtime·printf("edx %x\n", r->Edx); - runtime·printf("edi %x\n", r->Edi); - runtime·printf("esi %x\n", r->Esi); - runtime·printf("ebp %x\n", r->Ebp); - runtime·printf("esp %x\n", r->Esp); - runtime·printf("eip %x\n", r->Eip); - runtime·printf("eflags %x\n", r->EFlags); - runtime·printf("cs %x\n", r->SegCs); - runtime·printf("fs %x\n", r->SegFs); - runtime·printf("gs %x\n", r->SegGs); -} - -bool -runtime·isgoexception(ExceptionRecord *info, Context *r) -{ - extern byte runtime·text[], runtime·etext[]; - - // Only handle exception if executing instructions in Go binary - // (not Windows library code). - if(r->Eip < (uint32)runtime·text || (uint32)runtime·etext < r->Eip) - return false; - - if(!runtime·issigpanic(info->ExceptionCode)) - return false; - - return true; -} - -// Called by sigtramp from Windows VEH handler. -// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION) -// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH). -uint32 -runtime·exceptionhandler(ExceptionRecord *info, Context *r, G *gp) -{ - uintptr *sp; - - if(!runtime·isgoexception(info, r)) - return EXCEPTION_CONTINUE_SEARCH; - - // Make it look like a call to the signal func. - // Have to pass arguments out of band since - // augmenting the stack frame would break - // the unwinding code. - gp->sig = info->ExceptionCode; - gp->sigcode0 = info->ExceptionInformation[0]; - gp->sigcode1 = info->ExceptionInformation[1]; - gp->sigpc = r->Eip; - - // Only push runtime·sigpanic if r->eip != 0. - // If r->eip == 0, probably panicked because of a - // call to a nil func. Not pushing that onto sp will - // make the trace look like a call to runtime·sigpanic instead. - // (Otherwise the trace will end at runtime·sigpanic and we - // won't get to see who faulted.) - if(r->Eip != 0) { - sp = (uintptr*)r->Esp; - *--sp = r->Eip; - r->Esp = (uintptr)sp; - } - r->Eip = (uintptr)runtime·sigpanic; - return EXCEPTION_CONTINUE_EXECUTION; -} - -// lastcontinuehandler is reached, because runtime cannot handle -// current exception. lastcontinuehandler will print crash info and exit. -uint32 -runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp) -{ - bool crash; - - if(runtime·panicking) // traceback already printed - runtime·exit(2); - runtime·panicking = 1; - - runtime·printf("Exception %x %p %p %p\n", info->ExceptionCode, - (uintptr)info->ExceptionInformation[0], (uintptr)info->ExceptionInformation[1], (uintptr)r->Eip); - - runtime·printf("PC=%x\n", r->Eip); - if(g->m->lockedg != nil && g->m->ncgo > 0 && gp == g->m->g0) { - runtime·printf("signal arrived during cgo execution\n"); - gp = g->m->lockedg; - } - runtime·printf("\n"); - - if(runtime·gotraceback(&crash)){ - runtime·tracebacktrap(r->Eip, r->Esp, 0, gp); - runtime·tracebackothers(gp); - runtime·dumpregs(r); - } - - if(crash) - runtime·crash(); - - runtime·exit(2); - return 0; // not reached -} - -void -runtime·sigenable(uint32 sig) -{ - USED(sig); -} - -void -runtime·sigdisable(uint32 sig) -{ - USED(sig); -} - -void -runtime·dosigprof(Context *r, G *gp, M *mp) -{ - runtime·sigprof((uint8*)r->Eip, (uint8*)r->Esp, nil, gp, mp); -} diff --git a/src/runtime/os_windows_amd64.c b/src/runtime/os_windows_amd64.c deleted file mode 100644 index e4617e4cef..0000000000 --- a/src/runtime/os_windows_amd64.c +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright 2011 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. - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" - -void -runtime·dumpregs(Context *r) -{ - runtime·printf("rax %X\n", r->Rax); - runtime·printf("rbx %X\n", r->Rbx); - runtime·printf("rcx %X\n", r->Rcx); - runtime·printf("rdx %X\n", r->Rdx); - runtime·printf("rdi %X\n", r->Rdi); - runtime·printf("rsi %X\n", r->Rsi); - runtime·printf("rbp %X\n", r->Rbp); - runtime·printf("rsp %X\n", r->Rsp); - runtime·printf("r8 %X\n", r->R8 ); - runtime·printf("r9 %X\n", r->R9 ); - runtime·printf("r10 %X\n", r->R10); - runtime·printf("r11 %X\n", r->R11); - runtime·printf("r12 %X\n", r->R12); - runtime·printf("r13 %X\n", r->R13); - runtime·printf("r14 %X\n", r->R14); - runtime·printf("r15 %X\n", r->R15); - runtime·printf("rip %X\n", r->Rip); - runtime·printf("rflags %X\n", r->EFlags); - runtime·printf("cs %X\n", (uint64)r->SegCs); - runtime·printf("fs %X\n", (uint64)r->SegFs); - runtime·printf("gs %X\n", (uint64)r->SegGs); -} - -bool -runtime·isgoexception(ExceptionRecord *info, Context *r) -{ - extern byte runtime·text[], runtime·etext[]; - - // Only handle exception if executing instructions in Go binary - // (not Windows library code). - if(r->Rip < (uint64)runtime·text || (uint64)runtime·etext < r->Rip) - return false; - - if(!runtime·issigpanic(info->ExceptionCode)) - return false; - - return true; -} - -// Called by sigtramp from Windows VEH handler. -// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION) -// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH). -uint32 -runtime·exceptionhandler(ExceptionRecord *info, Context *r, G *gp) -{ - uintptr *sp; - - if(!runtime·isgoexception(info, r)) - return EXCEPTION_CONTINUE_SEARCH; - - // Make it look like a call to the signal func. - // Have to pass arguments out of band since - // augmenting the stack frame would break - // the unwinding code. - gp->sig = info->ExceptionCode; - gp->sigcode0 = info->ExceptionInformation[0]; - gp->sigcode1 = info->ExceptionInformation[1]; - gp->sigpc = r->Rip; - - // Only push runtime·sigpanic if r->rip != 0. - // If r->rip == 0, probably panicked because of a - // call to a nil func. Not pushing that onto sp will - // make the trace look like a call to runtime·sigpanic instead. - // (Otherwise the trace will end at runtime·sigpanic and we - // won't get to see who faulted.) - if(r->Rip != 0) { - sp = (uintptr*)r->Rsp; - *--sp = r->Rip; - r->Rsp = (uintptr)sp; - } - r->Rip = (uintptr)runtime·sigpanic; - return EXCEPTION_CONTINUE_EXECUTION; -} - -// It seems Windows searches ContinueHandler's list even -// if ExceptionHandler returns EXCEPTION_CONTINUE_EXECUTION. -// firstcontinuehandler will stop that search, -// if exceptionhandler did the same earlier. -uint32 -runtime·firstcontinuehandler(ExceptionRecord *info, Context *r, G *gp) -{ - USED(gp); - if(!runtime·isgoexception(info, r)) - return EXCEPTION_CONTINUE_SEARCH; - return EXCEPTION_CONTINUE_EXECUTION; -} - -// lastcontinuehandler is reached, because runtime cannot handle -// current exception. lastcontinuehandler will print crash info and exit. -uint32 -runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp) -{ - bool crash; - - if(runtime·panicking) // traceback already printed - runtime·exit(2); - runtime·panicking = 1; - - runtime·printf("Exception %x %p %p %p\n", info->ExceptionCode, - info->ExceptionInformation[0], info->ExceptionInformation[1], r->Rip); - - - runtime·printf("PC=%X\n", r->Rip); - if(g->m->lockedg != nil && g->m->ncgo > 0 && gp == g->m->g0) { - runtime·printf("signal arrived during cgo execution\n"); - gp = g->m->lockedg; - } - runtime·printf("\n"); - - if(runtime·gotraceback(&crash)){ - runtime·tracebacktrap(r->Rip, r->Rsp, 0, gp); - runtime·tracebackothers(gp); - runtime·dumpregs(r); - } - - if(crash) - runtime·crash(); - - runtime·exit(2); - return 0; // not reached -} - -void -runtime·sigenable(uint32 sig) -{ - USED(sig); -} - -void -runtime·sigdisable(uint32 sig) -{ - USED(sig); -} - -void -runtime·dosigprof(Context *r, G *gp, M *mp) -{ - runtime·sigprof((uint8*)r->Rip, (uint8*)r->Rsp, nil, gp, mp); -} diff --git a/src/runtime/stubs2.go b/src/runtime/stubs2.go index 526b3c5691..cb0b0f0ed5 100644 --- a/src/runtime/stubs2.go +++ b/src/runtime/stubs2.go @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. // +build !solaris +// +build !windows package runtime diff --git a/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go index efbcab510d..661ee59d7b 100644 --- a/src/runtime/syscall_windows.go +++ b/src/runtime/syscall_windows.go @@ -41,20 +41,20 @@ func callbackasmAddr(i int) uintptr { func compileCallback(fn eface, cleanstack bool) (code uintptr) { if fn._type == nil || (fn._type.kind&kindMask) != kindFunc { - panic("compilecallback: not a function") + panic("compileCallback: not a function") } ft := (*functype)(unsafe.Pointer(fn._type)) - if len(ft.out) != 1 { - panic("compilecallback: function must have one output parameter") + if ft.out.len != 1 { + panic("compileCallback: function must have one output parameter") } uintptrSize := unsafe.Sizeof(uintptr(0)) - if t := (**_type)(unsafe.Pointer(&ft.out[0])); (*t).size != uintptrSize { - panic("compilecallback: output parameter size is wrong") + if t := (**_type)(unsafe.Pointer(ft.out.array)); (*t).size != uintptrSize { + panic("compileCallback: output parameter size is wrong") } argsize := uintptr(0) - for _, t := range (*[1024](*_type))(unsafe.Pointer(&ft.in[0]))[:len(ft.in)] { + for _, t := range (*[1024](*_type))(unsafe.Pointer(ft.in.array))[:ft.in.len] { if (*t).size > uintptrSize { - panic("compilecallback: input parameter size is wrong") + panic("compileCallback: input parameter size is wrong") } argsize += uintptrSize } @@ -87,8 +87,6 @@ func compileCallback(fn eface, cleanstack bool) (code uintptr) { return callbackasmAddr(n) } -func getLoadLibrary() uintptr - //go:nosplit func syscall_loadlibrary(filename *uint16) (handle, err uintptr) { var c libcall @@ -103,8 +101,6 @@ func syscall_loadlibrary(filename *uint16) (handle, err uintptr) { return } -func getGetProcAddress() uintptr - //go:nosplit func syscall_getprocaddress(handle uintptr, procname *byte) (outhandle, err uintptr) { var c libcall From 361199749d81d06cc1007db9f7da5818b6f830b2 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 19 Nov 2014 20:52:58 -0500 Subject: [PATCH 50/68] build: disable race external linking test on OS X 10.6 and earlier External linking doesn't work there at all. LGTM=bradfitz R=adg, bradfitz CC=golang-codereviews https://golang.org/cl/176070043 --- src/run.bash | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/src/run.bash b/src/run.bash index 9a0e1cb0f2..5f20451a2d 100755 --- a/src/run.bash +++ b/src/run.bash @@ -64,18 +64,6 @@ echo echo '# sync -cpu=10' go test sync -short -timeout=$(expr 120 \* $timeout_scale)s -cpu=10 -# Race detector only supported on Linux, FreeBSD and OS X, -# and only on amd64, and only when cgo is enabled. -case "$GOHOSTOS-$GOOS-$GOARCH-$CGO_ENABLED" in -linux-linux-amd64-1 | freebsd-freebsd-amd64-1 | darwin-darwin-amd64-1) - echo - echo '# Testing race detector.' - go test -race -i runtime/race flag os/exec - go test -race -run=Output runtime/race - go test -race -short flag os/exec - go test -race -short -ldflags=-linkmode=external flag os/exec -esac - xcd() { echo echo '#' $1 @@ -121,6 +109,7 @@ go run $GOROOT/test/run.go - . || exit 1 [ "$CGO_ENABLED" != 1 ] || (xcd ../misc/cgo/test # cgo tests inspect the traceback for runtime functions +extlink=0 export GOTRACEBACK=2 go test -ldflags '-linkmode=auto' || exit 1 # linkmode=internal fails on dragonfly since errno is a TLS relocation. @@ -129,19 +118,24 @@ case "$GOHOSTOS-$GOARCH" in openbsd-386 | openbsd-amd64) # test linkmode=external, but __thread not supported, so skip testtls. go test -ldflags '-linkmode=external' || exit 1 + extlink=1 ;; darwin-386 | darwin-amd64) # linkmode=external fails on OS X 10.6 and earlier == Darwin # 10.8 and earlier. case $(uname -r) in [0-9].* | 10.*) ;; - *) go test -ldflags '-linkmode=external' || exit 1;; + *) + go test -ldflags '-linkmode=external' || exit 1 + extlink=1 + ;; esac ;; android-arm | dragonfly-386 | dragonfly-amd64 | freebsd-386 | freebsd-amd64 | freebsd-arm | linux-386 | linux-amd64 | linux-arm | netbsd-386 | netbsd-amd64) go test -ldflags '-linkmode=external' || exit 1 go test -ldflags '-linkmode=auto' ../testtls || exit 1 go test -ldflags '-linkmode=external' ../testtls || exit 1 + extlink=1 case "$GOHOSTOS-$GOARCH" in netbsd-386 | netbsd-amd64) ;; # no static linking @@ -165,6 +159,23 @@ android-arm | dragonfly-386 | dragonfly-amd64 | freebsd-386 | freebsd-amd64 | fr esac ) || exit $? +# Race detector only supported on Linux, FreeBSD and OS X, +# and only on amd64, and only when cgo is enabled. +# Delayed until here so we know whether to try external linking. +case "$GOHOSTOS-$GOOS-$GOARCH-$CGO_ENABLED" in +linux-linux-amd64-1 | freebsd-freebsd-amd64-1 | darwin-darwin-amd64-1) + echo + echo '# Testing race detector.' + go test -race -i runtime/race flag os/exec + go test -race -run=Output runtime/race + go test -race -short flag os/exec + + # Test with external linking; see issue 9133. + if [ "$extlink" = 1 ]; then + go test -race -short -ldflags=-linkmode=external flag os/exec + fi +esac + # This tests cgo -cdefs. That mode is not supported, # so it's okay if it doesn't work on some systems. # In particular, it works badly with clang on OS X. From 2b3f37908060837f8715c61af110b01b8a590c7c Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Thu, 20 Nov 2014 09:51:02 -0500 Subject: [PATCH 51/68] runtime: fix atomic operations on non-heap addresses Race detector runtime does not tolerate operations on addresses that was not previously declared with __tsan_map_shadow (namely, data, bss and heap). The corresponding address checks for atomic operations were removed in https://golang.org/cl/111310044 Restore these checks. It's tricker than just not calling into race runtime, because it is the race runtime that makes the atomic operations themselves (if we do not call into race runtime we skip the atomic operation itself as well). So instead we call __tsan_go_ignore_sync_start/end around the atomic operation. This forces race runtime to skip all other processing except than doing the atomic operation itself. Fixes #9136. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/179030043 --- src/runtime/race.c | 13 +++++---- src/runtime/race/race_unix_test.go | 30 +++++++++++++++++++++ src/runtime/race_amd64.s | 43 +++++++++++++++++++++++++----- 3 files changed, 73 insertions(+), 13 deletions(-) create mode 100644 src/runtime/race/race_unix_test.go diff --git a/src/runtime/race.c b/src/runtime/race.c index e400c8d102..5b0d116640 100644 --- a/src/runtime/race.c +++ b/src/runtime/race.c @@ -71,6 +71,9 @@ extern byte runtime·ebss[]; extern byte runtime·noptrbss[]; extern byte runtime·enoptrbss[]; +// start/end of global data (data+bss). +uintptr runtime·racedatastart; +uintptr runtime·racedataend; // start/end of heap for race_amd64.s uintptr runtime·racearenastart; uintptr runtime·racearenaend; @@ -92,13 +95,7 @@ isvalidaddr(uintptr addr) { if(addr >= runtime·racearenastart && addr < runtime·racearenaend) return true; - if(addr >= (uintptr)runtime·noptrdata && addr < (uintptr)runtime·enoptrdata) - return true; - if(addr >= (uintptr)runtime·data && addr < (uintptr)runtime·edata) - return true; - if(addr >= (uintptr)runtime·bss && addr < (uintptr)runtime·ebss) - return true; - if(addr >= (uintptr)runtime·noptrbss && addr < (uintptr)runtime·enoptrbss) + if(addr >= runtime·racedatastart && addr < runtime·racedataend) return true; return false; } @@ -139,6 +136,8 @@ runtime·raceinit(void) start = start & ~(PageSize-1); size = ROUND(end - start, PageSize); runtime·racecall(__tsan_map_shadow, start, size); + runtime·racedatastart = start; + runtime·racedataend = start + size; return racectx; } diff --git a/src/runtime/race/race_unix_test.go b/src/runtime/race/race_unix_test.go new file mode 100644 index 0000000000..84f0acece6 --- /dev/null +++ b/src/runtime/race/race_unix_test.go @@ -0,0 +1,30 @@ +// Copyright 2014 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. + +// +build race +// +build darwin freebsd linux + +package race_test + +import ( + "sync/atomic" + "syscall" + "testing" + "unsafe" +) + +// Test that race detector does not crash when accessing non-Go allocated memory (issue 9136). +func TestNonGoMemory(t *testing.T) { + data, err := syscall.Mmap(-1, 0, 4096, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_ANON|syscall.MAP_PRIVATE) + if err != nil { + t.Fatalf("failed to mmap memory: %v", err) + } + p := (*uint32)(unsafe.Pointer(&data[0])) + atomic.AddUint32(p, 1) + (*p)++ + if *p != 2 { + t.Fatalf("data[0] = %v, expect 2", *p) + } + syscall.Munmap(data) +} diff --git a/src/runtime/race_amd64.s b/src/runtime/race_amd64.s index bdea28c7c0..a96d9de123 100644 --- a/src/runtime/race_amd64.s +++ b/src/runtime/race_amd64.s @@ -138,17 +138,15 @@ TEXT racecalladdr<>(SB), NOSPLIT, $0-0 get_tls(R12) MOVQ g(R12), R14 MOVQ g_racectx(R14), RARG0 // goroutine context - // Check that addr is within [arenastart, arenaend) or within [noptrdata, enoptrbss). + // Check that addr is within [arenastart, arenaend) or within [racedatastart, racedataend). CMPQ RARG1, runtime·racearenastart(SB) JB racecalladdr_data CMPQ RARG1, runtime·racearenaend(SB) JB racecalladdr_call racecalladdr_data: - MOVQ $runtime·noptrdata(SB), R13 - CMPQ RARG1, R13 + CMPQ RARG1, runtime·racedatastart(SB) JB racecalladdr_ret - MOVQ $runtime·enoptrbss(SB), R13 - CMPQ RARG1, R13 + CMPQ RARG1, runtime·racedataend(SB) JAE racecalladdr_ret racecalladdr_call: MOVQ AX, AX // w/o this 6a miscompiles this function @@ -166,6 +164,7 @@ TEXT runtime·racefuncenter(SB), NOSPLIT, $0-8 MOVQ callpc+0(FP), RARG1 // void __tsan_func_enter(ThreadState *thr, void *pc); MOVQ $__tsan_func_enter(SB), AX + // racecall<> preserves R15 CALL racecall<>(SB) MOVQ R15, DX // restore function entry context RET @@ -306,13 +305,45 @@ TEXT sync∕atomic·CompareAndSwapPointer(SB), NOSPLIT, $0-0 TEXT racecallatomic<>(SB), NOSPLIT, $0-0 // Trigger SIGSEGV early. MOVQ 16(SP), R12 - MOVL (R12), R12 + MOVL (R12), R13 + // Check that addr is within [arenastart, arenaend) or within [racedatastart, racedataend). + CMPQ R12, runtime·racearenastart(SB) + JB racecallatomic_data + CMPQ R12, runtime·racearenaend(SB) + JB racecallatomic_ok +racecallatomic_data: + CMPQ R12, runtime·racedatastart(SB) + JB racecallatomic_ignore + CMPQ R12, runtime·racedataend(SB) + JAE racecallatomic_ignore +racecallatomic_ok: + // Addr is within the good range, call the atomic function. get_tls(R12) MOVQ g(R12), R14 MOVQ g_racectx(R14), RARG0 // goroutine context MOVQ 8(SP), RARG1 // caller pc MOVQ (SP), RARG2 // pc LEAQ 16(SP), RARG3 // arguments + JMP racecall<>(SB) // does not return +racecallatomic_ignore: + // Addr is outside the good range. + // Call __tsan_go_ignore_sync_begin to ignore synchronization during the atomic op. + // An attempt to synchronize on the address would cause crash. + MOVQ AX, R15 // remember the original function + MOVQ $__tsan_go_ignore_sync_begin(SB), AX + MOVQ g(R12), R14 + MOVQ g_racectx(R14), RARG0 // goroutine context + CALL racecall<>(SB) + MOVQ R15, AX // restore the original function + // Call the atomic function. + MOVQ g_racectx(R14), RARG0 // goroutine context + MOVQ 8(SP), RARG1 // caller pc + MOVQ (SP), RARG2 // pc + LEAQ 16(SP), RARG3 // arguments + CALL racecall<>(SB) + // Call __tsan_go_ignore_sync_end. + MOVQ $__tsan_go_ignore_sync_end(SB), AX + MOVQ g_racectx(R14), RARG0 // goroutine context JMP racecall<>(SB) // void runtime·racecall(void(*f)(...), ...) From e538770d4b58eef23bcac62324c42a0972a4e035 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 20 Nov 2014 09:35:22 -0800 Subject: [PATCH 52/68] go/parser: Use test-specific filesets to avoid races. Only affects test code. Fixes #9025. Fixes #9130. LGTM=r, adonovan R=adonovan, r CC=golang-codereviews https://golang.org/cl/180920043 --- src/go/parser/error_test.go | 27 +++++++++++++-------------- src/go/parser/parser_test.go | 20 +++++++++----------- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/src/go/parser/error_test.go b/src/go/parser/error_test.go index 48fb53e5b0..1a08d5a6b1 100644 --- a/src/go/parser/error_test.go +++ b/src/go/parser/error_test.go @@ -34,11 +34,9 @@ import ( const testdata = "testdata" -var fsetErrs = token.NewFileSet() - // getFile assumes that each filename occurs at most once -func getFile(filename string) (file *token.File) { - fsetErrs.Iterate(func(f *token.File) bool { +func getFile(fset *token.FileSet, filename string) (file *token.File) { + fset.Iterate(func(f *token.File) bool { if f.Name() == filename { if file != nil { panic(filename + " used multiple times") @@ -50,8 +48,8 @@ func getFile(filename string) (file *token.File) { return file } -func getPos(filename string, offset int) token.Pos { - if f := getFile(filename); f != nil { +func getPos(fset *token.FileSet, filename string, offset int) token.Pos { + if f := getFile(fset, filename); f != nil { return f.Pos(offset) } return token.NoPos @@ -68,14 +66,14 @@ var errRx = regexp.MustCompile(`^/\* *ERROR *(HERE)? *"([^"]*)" *\*/$`) // expectedErrors collects the regular expressions of ERROR comments found // in files and returns them as a map of error positions to error messages. // -func expectedErrors(t *testing.T, filename string, src []byte) map[token.Pos]string { +func expectedErrors(t *testing.T, fset *token.FileSet, filename string, src []byte) map[token.Pos]string { errors := make(map[token.Pos]string) var s scanner.Scanner // file was parsed already - do not add it again to the file // set otherwise the position information returned here will // not match the position information collected by the parser - s.Init(getFile(filename), src, nil, scanner.ScanComments) + s.Init(getFile(fset, filename), src, nil, scanner.ScanComments) var prev token.Pos // position of last non-comment, non-semicolon token var here token.Pos // position immediately after the token at position prev @@ -109,11 +107,11 @@ func expectedErrors(t *testing.T, filename string, src []byte) map[token.Pos]str // compareErrors compares the map of expected error messages with the list // of found errors and reports discrepancies. // -func compareErrors(t *testing.T, expected map[token.Pos]string, found scanner.ErrorList) { +func compareErrors(t *testing.T, fset *token.FileSet, expected map[token.Pos]string, found scanner.ErrorList) { for _, error := range found { // error.Pos is a token.Position, but we want // a token.Pos so we can do a map lookup - pos := getPos(error.Pos.Filename, error.Pos.Offset) + pos := getPos(fset, error.Pos.Filename, error.Pos.Offset) if msg, found := expected[pos]; found { // we expect a message at pos; check if it matches rx, err := regexp.Compile(msg) @@ -140,7 +138,7 @@ func compareErrors(t *testing.T, expected map[token.Pos]string, found scanner.Er if len(expected) > 0 { t.Errorf("%d errors not reported:", len(expected)) for pos, msg := range expected { - t.Errorf("%s: %s\n", fsetErrs.Position(pos), msg) + t.Errorf("%s: %s\n", fset.Position(pos), msg) } } } @@ -152,7 +150,8 @@ func checkErrors(t *testing.T, filename string, input interface{}) { return } - _, err = ParseFile(fsetErrs, filename, src, DeclarationErrors|AllErrors) + fset := token.NewFileSet() + _, err = ParseFile(fset, filename, src, DeclarationErrors|AllErrors) found, ok := err.(scanner.ErrorList) if err != nil && !ok { t.Error(err) @@ -162,10 +161,10 @@ func checkErrors(t *testing.T, filename string, input interface{}) { // we are expecting the following errors // (collect these after parsing a file so that it is found in the file set) - expected := expectedErrors(t, filename, src) + expected := expectedErrors(t, fset, filename, src) // verify errors returned by the parser - compareErrors(t, expected, found) + compareErrors(t, fset, expected, found) } func TestErrors(t *testing.T) { diff --git a/src/go/parser/parser_test.go b/src/go/parser/parser_test.go index 85065fd182..51ce1a9337 100644 --- a/src/go/parser/parser_test.go +++ b/src/go/parser/parser_test.go @@ -14,8 +14,6 @@ import ( "testing" ) -var fset = token.NewFileSet() - var validFiles = []string{ "parser.go", "parser_test.go", @@ -25,7 +23,7 @@ var validFiles = []string{ func TestParse(t *testing.T) { for _, filename := range validFiles { - _, err := ParseFile(fset, filename, nil, DeclarationErrors) + _, err := ParseFile(token.NewFileSet(), filename, nil, DeclarationErrors) if err != nil { t.Fatalf("ParseFile(%s): %v", filename, err) } @@ -46,7 +44,7 @@ func dirFilter(f os.FileInfo) bool { return nameFilter(f.Name()) } func TestParseDir(t *testing.T) { path := "." - pkgs, err := ParseDir(fset, path, dirFilter, 0) + pkgs, err := ParseDir(token.NewFileSet(), path, dirFilter, 0) if err != nil { t.Fatalf("ParseDir(%s): %v", path, err) } @@ -131,7 +129,7 @@ func TestParseExpr(t *testing.T) { } func TestColonEqualsScope(t *testing.T) { - f, err := ParseFile(fset, "", `package p; func f() { x, y, z := x, y, z }`, 0) + f, err := ParseFile(token.NewFileSet(), "", `package p; func f() { x, y, z := x, y, z }`, 0) if err != nil { t.Fatal(err) } @@ -153,7 +151,7 @@ func TestColonEqualsScope(t *testing.T) { } func TestVarScope(t *testing.T) { - f, err := ParseFile(fset, "", `package p; func f() { var x, y, z = x, y, z }`, 0) + f, err := ParseFile(token.NewFileSet(), "", `package p; func f() { var x, y, z = x, y, z }`, 0) if err != nil { t.Fatal(err) } @@ -183,7 +181,7 @@ var x int func f() { L: } ` - f, err := ParseFile(fset, "", src, 0) + f, err := ParseFile(token.NewFileSet(), "", src, 0) if err != nil { t.Fatal(err) } @@ -221,7 +219,7 @@ func f() { L: } } func TestUnresolved(t *testing.T) { - f, err := ParseFile(fset, "", ` + f, err := ParseFile(token.NewFileSet(), "", ` package p // func f1a(int) @@ -316,7 +314,7 @@ var imports = map[string]bool{ func TestImports(t *testing.T) { for path, isValid := range imports { src := fmt.Sprintf("package p; import %s", path) - _, err := ParseFile(fset, "", src, 0) + _, err := ParseFile(token.NewFileSet(), "", src, 0) switch { case err != nil && isValid: t.Errorf("ParseFile(%s): got %v; expected no error", src, err) @@ -327,7 +325,7 @@ func TestImports(t *testing.T) { } func TestCommentGroups(t *testing.T) { - f, err := ParseFile(fset, "", ` + f, err := ParseFile(token.NewFileSet(), "", ` package p /* 1a */ /* 1b */ /* 1c */ // 1d /* 2a */ @@ -421,7 +419,7 @@ func checkFieldComments(t *testing.T, file *ast.File, fieldname, lead, line stri } func TestLeadAndLineComments(t *testing.T) { - f, err := ParseFile(fset, "", ` + f, err := ParseFile(token.NewFileSet(), "", ` package p type T struct { /* F1 lead comment */ From 7b596457d18d2010d40d75d74cf4a678a54a5e4a Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Thu, 20 Nov 2014 14:28:54 -0500 Subject: [PATCH 53/68] [dev.cc] liblink: fix Solaris build some more a->name and a->class are char, so Solaris doesn't like using them as array indexes. (This same problem was fixed for amd64 in CL 169630043.) LGTM=aram, minux R=rsc, minux, aram CC=golang-codereviews https://golang.org/cl/175430043 --- src/liblink/list9.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/liblink/list9.c b/src/liblink/list9.c index 5436e36ac7..0a158cd61e 100644 --- a/src/liblink/list9.c +++ b/src/liblink/list9.c @@ -178,13 +178,13 @@ Dconv(Fmt *fp) s += sprint(s, "type=%s ", dnames9[a->type]); else s += sprint(s, "type=%d ", a->type); - if(a->name >= 0 && a->name < D_LAST && dnames9[a->name] != nil) - s += sprint(s, "name=%s ", dnames9[a->name]); + if(a->name >= 0 && a->name < D_LAST && dnames9[(int)a->name] != nil) + s += sprint(s, "name=%s ", dnames9[(int)a->name]); else s += sprint(s, "name=%d ", a->name); s += sprint(s, "offset=%ld etype=%E width=%d", a->offset, a->etype, a->width); if(a->class != 0) - s += sprint(s, " class=%s", cnames9[a->class]); + s += sprint(s, " class=%s", cnames9[(int)a->class]); if(a->reg != NREG) s += sprint(s, " reg=%d", a->reg); if(a->sym != nil) From 0a38b2cdaf6bac030b1a3c5a895ce681be40862b Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Fri, 21 Nov 2014 12:15:18 +1100 Subject: [PATCH 54/68] [dev.cc] runtime: fix windows goenvs conversion mistake uint16 occupies 2 bytes, not 1 LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/178100043 --- src/runtime/os1_windows.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/os1_windows.go b/src/runtime/os1_windows.go index abd2297a30..57ea050f26 100644 --- a/src/runtime/os1_windows.go +++ b/src/runtime/os1_windows.go @@ -175,7 +175,7 @@ func goenvs() { n := 0 for p = env; *p != 0; n++ { - p = (*uint16)(add(unsafe.Pointer(p), uintptr(findnullw(p)+1))) + p = (*uint16)(add(unsafe.Pointer(p), uintptr(findnullw(p)+1)*unsafe.Sizeof(*p))) } envs = makeStringSlice(int(n)) @@ -183,7 +183,7 @@ func goenvs() { p = env for i := 0; i < n; i++ { envs[i] = gostringw(p) - p = (*uint16)(add(unsafe.Pointer(p), uintptr(findnullw(p)+1))) + p = (*uint16)(add(unsafe.Pointer(p), uintptr(findnullw(p)+1)*unsafe.Sizeof(*p))) } stdcall1(_FreeEnvironmentStringsW, uintptr(unsafe.Pointer(env))) From 841de809bb9d36ea7949b67857978d35f4fcc2f2 Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Fri, 21 Nov 2014 15:59:22 +1100 Subject: [PATCH 55/68] [dev.cc] runtime: windows does not use _cgo_setenv and _cgo_unsetenv LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/175480043 --- src/runtime/proc.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 50920afe8b..295190cb4e 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -63,11 +63,13 @@ func main() { if _cgo_free == nil { gothrow("_cgo_free missing") } - if _cgo_setenv == nil { - gothrow("_cgo_setenv missing") - } - if _cgo_unsetenv == nil { - gothrow("_cgo_unsetenv missing") + if GOOS != "windows" { + if _cgo_setenv == nil { + gothrow("_cgo_setenv missing") + } + if _cgo_unsetenv == nil { + gothrow("_cgo_unsetenv missing") + } } } From ce3e8e4edcb2288ae06cd3892c88a4afe2a0a746 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 21 Nov 2014 00:21:49 -0500 Subject: [PATCH 56/68] [dev.cc] build: skip API checks on Windows too (not just Unix) TBR=brainman CC=golang-codereviews https://golang.org/cl/175490043 --- src/run.bat | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/run.bat b/src/run.bat index 14c1b45fda..efa97662f8 100644 --- a/src/run.bat +++ b/src/run.bat @@ -134,9 +134,11 @@ if %FAIL%==1 goto fail set GOMAXPROCS=%OLDGOMAXPROCS% set OLDGOMAXPROCS= -echo # Checking API compatibility. -go run "%GOROOT%\src\cmd\api\run.go" -if errorlevel 1 goto fail +:: echo # Checking API compatibility. +:: go run "%GOROOT%\src\cmd\api\run.go" +:: if errorlevel 1 goto fail +:: echo. +echo # SKIPPING API COMPATIBILITY UNTIL ALL SYSTEMS BUILD. echo. echo ALL TESTS PASSED From ad8179281d314663f94358589a8c39ecf644007b Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 21 Nov 2014 10:22:18 -0500 Subject: [PATCH 57/68] [dev.cc] runtime: convert nacl support to Go LGTM=dave R=minux, dave CC=golang-codereviews https://golang.org/cl/181030043 --- src/runtime/arch1_amd64p32.go | 15 + src/runtime/arch_amd64p32.h | 17 - src/runtime/lfstack_32bit.go | 2 +- src/runtime/mem_bsd.go | 4 +- src/runtime/mem_nacl.c | 120 ------- src/runtime/os1_nacl.go | 197 +++++++++++ src/runtime/os2_nacl.go | 154 +++++++++ src/runtime/os_nacl.c | 312 ------------------ src/runtime/os_nacl.go | 21 +- src/runtime/os_nacl.h | 162 --------- src/runtime/{os_nacl_arm.c => os_nacl_arm.go} | 19 +- src/runtime/signal_nacl.go | 45 +++ src/runtime/signal_nacl_386.go | 34 ++ src/runtime/signal_nacl_386.h | 23 -- src/runtime/signal_nacl_amd64p32.go | 44 +++ src/runtime/signal_nacl_amd64p32.h | 31 -- src/runtime/signal_nacl_arm.go | 47 +++ src/runtime/signal_nacl_arm.h | 28 -- src/runtime/signals_nacl.h | 53 --- src/runtime/stubs2.go | 1 + 20 files changed, 562 insertions(+), 767 deletions(-) create mode 100644 src/runtime/arch1_amd64p32.go delete mode 100644 src/runtime/arch_amd64p32.h delete mode 100644 src/runtime/mem_nacl.c create mode 100644 src/runtime/os1_nacl.go create mode 100644 src/runtime/os2_nacl.go delete mode 100644 src/runtime/os_nacl.c delete mode 100644 src/runtime/os_nacl.h rename src/runtime/{os_nacl_arm.c => os_nacl_arm.go} (61%) create mode 100644 src/runtime/signal_nacl.go create mode 100644 src/runtime/signal_nacl_386.go delete mode 100644 src/runtime/signal_nacl_386.h create mode 100644 src/runtime/signal_nacl_amd64p32.go delete mode 100644 src/runtime/signal_nacl_amd64p32.h create mode 100644 src/runtime/signal_nacl_arm.go delete mode 100644 src/runtime/signal_nacl_arm.h delete mode 100644 src/runtime/signals_nacl.h diff --git a/src/runtime/arch1_amd64p32.go b/src/runtime/arch1_amd64p32.go new file mode 100644 index 0000000000..2cee21f0ca --- /dev/null +++ b/src/runtime/arch1_amd64p32.go @@ -0,0 +1,15 @@ +// Copyright 2011 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. + +package runtime + +const ( + thechar = '6' + _BigEndian = 0 + _CacheLineSize = 64 + _RuntimeGogoBytes = 64 + _PhysPageSize = 65536*goos_nacl + 4096*(1-goos_nacl) + _PCQuantum = 1 + _Int64Align = 8 +) diff --git a/src/runtime/arch_amd64p32.h b/src/runtime/arch_amd64p32.h deleted file mode 100644 index d3e8649875..0000000000 --- a/src/runtime/arch_amd64p32.h +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2011 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. - -enum { - thechar = '6', - BigEndian = 0, - CacheLineSize = 64, - RuntimeGogoBytes = 64, -#ifdef GOOS_nacl - PhysPageSize = 65536, -#else - PhysPageSize = 4096, -#endif - PCQuantum = 1, - Int64Align = 8 -}; diff --git a/src/runtime/lfstack_32bit.go b/src/runtime/lfstack_32bit.go index 61d8678d9c..4b8bcbac6a 100644 --- a/src/runtime/lfstack_32bit.go +++ b/src/runtime/lfstack_32bit.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build 386 arm +// +build 386 arm nacl package runtime diff --git a/src/runtime/mem_bsd.go b/src/runtime/mem_bsd.go index 4bd40a39fc..e9be5ec8c9 100644 --- a/src/runtime/mem_bsd.go +++ b/src/runtime/mem_bsd.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build dragonfly freebsd netbsd openbsd solaris +// +build dragonfly freebsd nacl netbsd openbsd solaris package runtime @@ -38,7 +38,7 @@ func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer { // On 64-bit, people with ulimit -v set complain if we reserve too // much address space. Instead, assume that the reservation is okay // and check the assumption in SysMap. - if ptrSize == 8 && uint64(n) > 1<<32 { + if ptrSize == 8 && uint64(n) > 1<<32 || goos_nacl != 0 { *reserved = false return v } diff --git a/src/runtime/mem_nacl.c b/src/runtime/mem_nacl.c deleted file mode 100644 index 6c836f18a7..0000000000 --- a/src/runtime/mem_nacl.c +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2010 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. - -#include "runtime.h" -#include "arch_GOARCH.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "malloc.h" -#include "textflag.h" - -enum -{ - Debug = 0, -}; - -#pragma textflag NOSPLIT -void* -runtime·sysAlloc(uintptr n, uint64 *stat) -{ - void *v; - - v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); - if(v < (void*)4096) { - if(Debug) - runtime·printf("sysAlloc(%p): %p\n", n, v); - return nil; - } - runtime·xadd64(stat, n); - if(Debug) - runtime·printf("sysAlloc(%p) = %p\n", n, v); - return v; -} - -void -runtime·SysUnused(void *v, uintptr n) -{ - if(Debug) - runtime·printf("SysUnused(%p, %p)\n", v, n); -} - -void -runtime·SysUsed(void *v, uintptr n) -{ - USED(v); - USED(n); -} - -void -runtime·SysFree(void *v, uintptr n, uint64 *stat) -{ - if(Debug) - runtime·printf("SysFree(%p, %p)\n", v, n); - runtime·xadd64(stat, -(uint64)n); - runtime·munmap(v, n); -} - -void -runtime·SysFault(void *v, uintptr n) -{ - runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0); -} - -void* -runtime·SysReserve(void *v, uintptr n, bool *reserved) -{ - void *p; - - // On 64-bit, people with ulimit -v set complain if we reserve too - // much address space. Instead, assume that the reservation is okay - // and check the assumption in SysMap. - if(NaCl || sizeof(void*) == 8) { - *reserved = false; - return v; - } - - p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0); - if(p < (void*)4096) - return nil; - *reserved = true; - return p; -} - -void -runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat) -{ - void *p; - - runtime·xadd64(stat, n); - - // On 64-bit, we don't actually have v reserved, so tread carefully. - if(!reserved) { - p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); - if(p == (void*)ENOMEM) { - runtime·printf("SysMap(%p, %p): %p\n", v, n, p); - runtime·throw("runtime: out of memory"); - } - if(p != v) { - runtime·printf("SysMap(%p, %p): %p\n", v, n, p); - runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p); - runtime·throw("runtime: address space conflict"); - } - if(Debug) - runtime·printf("SysMap(%p, %p) = %p\n", v, n, p); - return; - } - - p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0); - if(p == (void*)ENOMEM) { - runtime·printf("SysMap(%p, %p): %p\n", v, n, p); - runtime·throw("runtime: out of memory"); - } - if(p != v) { - runtime·printf("SysMap(%p, %p): %p\n", v, n, p); - runtime·printf("mmap MAP_FIXED %p returned %p\n", v, p); - runtime·throw("runtime: cannot map pages in arena address space"); - } - if(Debug) - runtime·printf("SysMap(%p, %p) = %p\n", v, n, p); -} diff --git a/src/runtime/os1_nacl.go b/src/runtime/os1_nacl.go new file mode 100644 index 0000000000..7b4c99a3dd --- /dev/null +++ b/src/runtime/os1_nacl.go @@ -0,0 +1,197 @@ +// Copyright 2010 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. + +package runtime + +import "unsafe" + +// Called to initialize a new m (including the bootstrap m). +// Called on the parent thread (main thread in case of bootstrap), can allocate memory. +func mpreinit(mp *m) { + mp.gsignal = malg(32 * 1024) + mp.gsignal.m = mp +} + +func sigtramp() + +// Called to initialize a new m (including the bootstrap m). +// Called on the new thread, can not allocate memory. +func minit() { + _g_ := getg() + + // Initialize signal handling + ret := nacl_exception_stack(_g_.m.gsignal.stack.lo, 32*1024) + if ret < 0 { + print("runtime: nacl_exception_stack: error ", -ret, "\n") + } + + ret = nacl_exception_handler(funcPC(sigtramp), nil) + if ret < 0 { + print("runtime: nacl_exception_handler: error ", -ret, "\n") + } +} + +// Called from dropm to undo the effect of an minit. +func unminit() { +} + +func osinit() { + ncpu = 1 + getg().m.procid = 2 + //nacl_exception_handler(funcPC(sigtramp), nil); +} + +func crash() { + *(*int32)(nil) = 0 +} + +//go:nosplit +func get_random_data(rnd *unsafe.Pointer, rnd_len *int32) { + *rnd = nil + *rnd_len = 0 +} + +func goenvs() { + goenvs_unix() +} + +func initsig() { +} + +//go:nosplit +func usleep(us uint32) { + var ts timespec + + ts.tv_sec = int64(us / 1e6) + ts.tv_nsec = int32(us%1e6) * 1e3 + nacl_nanosleep(&ts, nil) +} + +func mstart_nacl() + +func newosproc(mp *m, stk unsafe.Pointer) { + tls := (*[3]unsafe.Pointer)(unsafe.Pointer(&mp.tls)) + tls[0] = unsafe.Pointer(mp.g0) + tls[1] = unsafe.Pointer(mp) + ret := nacl_thread_create(funcPC(mstart_nacl), stk, unsafe.Pointer(&tls[2]), nil) + if ret < 0 { + print("nacl_thread_create: error ", -ret, "\n") + gothrow("newosproc") + } +} + +//go:nosplit +func semacreate() uintptr { + var cond uintptr + systemstack(func() { + mu := nacl_mutex_create(0) + if mu < 0 { + print("nacl_mutex_create: error ", -mu, "\n") + gothrow("semacreate") + } + c := nacl_cond_create(0) + if c < 0 { + print("nacl_cond_create: error ", -cond, "\n") + gothrow("semacreate") + } + cond = uintptr(c) + _g_ := getg() + _g_.m.waitsemalock = uint32(mu) + }) + return cond +} + +//go:nosplit +func semasleep(ns int64) int32 { + var ret int32 + + systemstack(func() { + _g_ := getg() + if nacl_mutex_lock(int32(_g_.m.waitsemalock)) < 0 { + gothrow("semasleep") + } + + for _g_.m.waitsemacount == 0 { + if ns < 0 { + if nacl_cond_wait(int32(_g_.m.waitsema), int32(_g_.m.waitsemalock)) < 0 { + gothrow("semasleep") + } + } else { + var ts timespec + end := ns + nanotime() + ts.tv_sec = end / 1e9 + ts.tv_nsec = int32(end % 1e9) + r := nacl_cond_timed_wait_abs(int32(_g_.m.waitsema), int32(_g_.m.waitsemalock), &ts) + if r == -_ETIMEDOUT { + nacl_mutex_unlock(int32(_g_.m.waitsemalock)) + ret = -1 + return + } + if r < 0 { + gothrow("semasleep") + } + } + } + + _g_.m.waitsemacount = 0 + nacl_mutex_unlock(int32(_g_.m.waitsemalock)) + ret = 0 + }) + return ret +} + +//go:nosplit +func semawakeup(mp *m) { + systemstack(func() { + if nacl_mutex_lock(int32(mp.waitsemalock)) < 0 { + gothrow("semawakeup") + } + if mp.waitsemacount != 0 { + gothrow("semawakeup") + } + mp.waitsemacount = 1 + nacl_cond_signal(int32(mp.waitsema)) + nacl_mutex_unlock(int32(mp.waitsemalock)) + }) +} + +func memlimit() uintptr { + return 0 +} + +// This runs on a foreign stack, without an m or a g. No stack split. +//go:nosplit +func badsignal2() { + write(2, unsafe.Pointer(&badsignal1[0]), int32(len(badsignal1))) + exit(2) +} + +var badsignal1 = []byte("runtime: signal received on thread not created by Go.\n") + +func madvise(addr unsafe.Pointer, n uintptr, flags int32) {} +func munmap(addr unsafe.Pointer, n uintptr) {} +func resetcpuprofiler(hz int32) {} +func sigdisable(uint32) {} +func sigenable(uint32) {} +func closeonexec(int32) {} + +var writelock uint32 // test-and-set spin lock for write + +/* +An attempt at IRT. Doesn't work. See end of sys_nacl_amd64.s. + +void (*nacl_irt_query)(void); + +int8 nacl_irt_basic_v0_1_str[] = "nacl-irt-basic-0.1"; +void *nacl_irt_basic_v0_1[6]; // exit, gettod, clock, nanosleep, sched_yield, sysconf +int32 nacl_irt_basic_v0_1_size = sizeof(nacl_irt_basic_v0_1); + +int8 nacl_irt_memory_v0_3_str[] = "nacl-irt-memory-0.3"; +void *nacl_irt_memory_v0_3[3]; // mmap, munmap, mprotect +int32 nacl_irt_memory_v0_3_size = sizeof(nacl_irt_memory_v0_3); + +int8 nacl_irt_thread_v0_1_str[] = "nacl-irt-thread-0.1"; +void *nacl_irt_thread_v0_1[3]; // thread_create, thread_exit, thread_nice +int32 nacl_irt_thread_v0_1_size = sizeof(nacl_irt_thread_v0_1); +*/ diff --git a/src/runtime/os2_nacl.go b/src/runtime/os2_nacl.go new file mode 100644 index 0000000000..0c91e0f737 --- /dev/null +++ b/src/runtime/os2_nacl.go @@ -0,0 +1,154 @@ +// Copyright 2014 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. + +package runtime + +const ( + _NSIG = 32 + _SI_USER = 1 + + // native_client/src/trusted/service_runtime/include/sys/errno.h + // The errors are mainly copied from Linux. + _EPERM = 1 /* Operation not permitted */ + _ENOENT = 2 /* No such file or directory */ + _ESRCH = 3 /* No such process */ + _EINTR = 4 /* Interrupted system call */ + _EIO = 5 /* I/O error */ + _ENXIO = 6 /* No such device or address */ + _E2BIG = 7 /* Argument list too long */ + _ENOEXEC = 8 /* Exec format error */ + _EBADF = 9 /* Bad file number */ + _ECHILD = 10 /* No child processes */ + _EAGAIN = 11 /* Try again */ + _ENOMEM = 12 /* Out of memory */ + _EACCES = 13 /* Permission denied */ + _EFAULT = 14 /* Bad address */ + _EBUSY = 16 /* Device or resource busy */ + _EEXIST = 17 /* File exists */ + _EXDEV = 18 /* Cross-device link */ + _ENODEV = 19 /* No such device */ + _ENOTDIR = 20 /* Not a directory */ + _EISDIR = 21 /* Is a directory */ + _EINVAL = 22 /* Invalid argument */ + _ENFILE = 23 /* File table overflow */ + _EMFILE = 24 /* Too many open files */ + _ENOTTY = 25 /* Not a typewriter */ + _EFBIG = 27 /* File too large */ + _ENOSPC = 28 /* No space left on device */ + _ESPIPE = 29 /* Illegal seek */ + _EROFS = 30 /* Read-only file system */ + _EMLINK = 31 /* Too many links */ + _EPIPE = 32 /* Broken pipe */ + _ENAMETOOLONG = 36 /* File name too long */ + _ENOSYS = 38 /* Function not implemented */ + _EDQUOT = 122 /* Quota exceeded */ + _EDOM = 33 /* Math arg out of domain of func */ + _ERANGE = 34 /* Math result not representable */ + _EDEADLK = 35 /* Deadlock condition */ + _ENOLCK = 37 /* No record locks available */ + _ENOTEMPTY = 39 /* Directory not empty */ + _ELOOP = 40 /* Too many symbolic links */ + _ENOMSG = 42 /* No message of desired type */ + _EIDRM = 43 /* Identifier removed */ + _ECHRNG = 44 /* Channel number out of range */ + _EL2NSYNC = 45 /* Level 2 not synchronized */ + _EL3HLT = 46 /* Level 3 halted */ + _EL3RST = 47 /* Level 3 reset */ + _ELNRNG = 48 /* Link number out of range */ + _EUNATCH = 49 /* Protocol driver not attached */ + _ENOCSI = 50 /* No CSI structure available */ + _EL2HLT = 51 /* Level 2 halted */ + _EBADE = 52 /* Invalid exchange */ + _EBADR = 53 /* Invalid request descriptor */ + _EXFULL = 54 /* Exchange full */ + _ENOANO = 55 /* No anode */ + _EBADRQC = 56 /* Invalid request code */ + _EBADSLT = 57 /* Invalid slot */ + _EDEADLOCK = _EDEADLK /* File locking deadlock error */ + _EBFONT = 59 /* Bad font file fmt */ + _ENOSTR = 60 /* Device not a stream */ + _ENODATA = 61 /* No data (for no delay io) */ + _ETIME = 62 /* Timer expired */ + _ENOSR = 63 /* Out of streams resources */ + _ENONET = 64 /* Machine is not on the network */ + _ENOPKG = 65 /* Package not installed */ + _EREMOTE = 66 /* The object is remote */ + _ENOLINK = 67 /* The link has been severed */ + _EADV = 68 /* Advertise error */ + _ESRMNT = 69 /* Srmount error */ + _ECOMM = 70 /* Communication error on send */ + _EPROTO = 71 /* Protocol error */ + _EMULTIHOP = 72 /* Multihop attempted */ + _EDOTDOT = 73 /* Cross mount point (not really error) */ + _EBADMSG = 74 /* Trying to read unreadable message */ + _EOVERFLOW = 75 /* Value too large for defined data type */ + _ENOTUNIQ = 76 /* Given log. name not unique */ + _EBADFD = 77 /* f.d. invalid for this operation */ + _EREMCHG = 78 /* Remote address changed */ + _ELIBACC = 79 /* Can't access a needed shared lib */ + _ELIBBAD = 80 /* Accessing a corrupted shared lib */ + _ELIBSCN = 81 /* .lib section in a.out corrupted */ + _ELIBMAX = 82 /* Attempting to link in too many libs */ + _ELIBEXEC = 83 /* Attempting to exec a shared library */ + _EILSEQ = 84 + _EUSERS = 87 + _ENOTSOCK = 88 /* Socket operation on non-socket */ + _EDESTADDRREQ = 89 /* Destination address required */ + _EMSGSIZE = 90 /* Message too long */ + _EPROTOTYPE = 91 /* Protocol wrong type for socket */ + _ENOPROTOOPT = 92 /* Protocol not available */ + _EPROTONOSUPPORT = 93 /* Unknown protocol */ + _ESOCKTNOSUPPORT = 94 /* Socket type not supported */ + _EOPNOTSUPP = 95 /* Operation not supported on transport endpoint */ + _EPFNOSUPPORT = 96 /* Protocol family not supported */ + _EAFNOSUPPORT = 97 /* Address family not supported by protocol family */ + _EADDRINUSE = 98 /* Address already in use */ + _EADDRNOTAVAIL = 99 /* Address not available */ + _ENETDOWN = 100 /* Network interface is not configured */ + _ENETUNREACH = 101 /* Network is unreachable */ + _ENETRESET = 102 + _ECONNABORTED = 103 /* Connection aborted */ + _ECONNRESET = 104 /* Connection reset by peer */ + _ENOBUFS = 105 /* No buffer space available */ + _EISCONN = 106 /* Socket is already connected */ + _ENOTCONN = 107 /* Socket is not connected */ + _ESHUTDOWN = 108 /* Can't send after socket shutdown */ + _ETOOMANYREFS = 109 + _ETIMEDOUT = 110 /* Connection timed out */ + _ECONNREFUSED = 111 /* Connection refused */ + _EHOSTDOWN = 112 /* Host is down */ + _EHOSTUNREACH = 113 /* Host is unreachable */ + _EALREADY = 114 /* Socket already connected */ + _EINPROGRESS = 115 /* Connection already in progress */ + _ESTALE = 116 + _ENOTSUP = _EOPNOTSUPP /* Not supported */ + _ENOMEDIUM = 123 /* No medium (in tape drive) */ + _ECANCELED = 125 /* Operation canceled. */ + _ELBIN = 2048 /* Inode is remote (not really error) */ + _EFTYPE = 2049 /* Inappropriate file type or format */ + _ENMFILE = 2050 /* No more files */ + _EPROCLIM = 2051 + _ENOSHARE = 2052 /* No such host or network path */ + _ECASECLASH = 2053 /* Filename exists with different case */ + _EWOULDBLOCK = _EAGAIN /* Operation would block */ + + // native_client/src/trusted/service_runtime/include/bits/mman.h. + // NOTE: DO NOT USE native_client/src/shared/imc/nacl_imc_c.h. + // Those MAP_*values are different from these. + _PROT_NONE = 0x0 + _PROT_READ = 0x1 + _PROT_WRITE = 0x2 + _PROT_EXEC = 0x4 + + _MAP_SHARED = 0x1 + _MAP_PRIVATE = 0x2 + _MAP_FIXED = 0x10 + _MAP_ANON = 0x20 + + _MADV_FREE = 0 + _SIGFPE = 8 + _FPE_INTDIV = 0 +) + +type siginfo struct{} diff --git a/src/runtime/os_nacl.c b/src/runtime/os_nacl.c deleted file mode 100644 index 14b5583033..0000000000 --- a/src/runtime/os_nacl.c +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright 2010 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. - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "arch_GOARCH.h" -#include "textflag.h" -#include "stack.h" - -int8 *goos = "nacl"; -extern SigTab runtime·sigtab[]; - -void runtime·sigtramp(void); - -// Called to initialize a new m (including the bootstrap m). -// Called on the parent thread (main thread in case of bootstrap), can allocate memory. -void -runtime·mpreinit(M *mp) -{ - mp->gsignal = runtime·malg(32*1024); // OS X wants >=8K, Linux >=2K - mp->gsignal->m = mp; -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the new thread, can not allocate memory. -void -runtime·minit(void) -{ - int32 ret; - - // Initialize signal handling - ret = runtime·nacl_exception_stack((byte*)g->m->gsignal->stack.lo, 32*1024); - if(ret < 0) - runtime·printf("runtime: nacl_exception_stack: error %d\n", -ret); - - ret = runtime·nacl_exception_handler(runtime·sigtramp, nil); - if(ret < 0) - runtime·printf("runtime: nacl_exception_handler: error %d\n", -ret); -} - -// Called from dropm to undo the effect of an minit. -void -runtime·unminit(void) -{ -} - -int8 runtime·sigtrampf[] = "runtime: signal at PC=%X AX=%X CX=%X DX=%X BX=%X DI=%X R15=%X *SP=%X\n"; -int8 runtime·sigtrampp[] = "runtime: sigtramp"; - -extern byte runtime·tls0[]; - -void -runtime·osinit(void) -{ - runtime·ncpu = 1; - g->m->procid = 2; -//runtime·nacl_exception_handler(runtime·sigtramp, nil); -} - -void -runtime·crash(void) -{ - *(int32*)0 = 0; -} - -#pragma textflag NOSPLIT -void -runtime·get_random_data(byte **rnd, int32 *rnd_len) -{ - *rnd = nil; - *rnd_len = 0; -} - -void -runtime·goenvs(void) -{ - runtime·goenvs_unix(); -} - -void -runtime·initsig(void) -{ -} - -#pragma textflag NOSPLIT -void -runtime·usleep(uint32 us) -{ - Timespec ts; - - ts.tv_sec = us/1000000; - ts.tv_nsec = (us%1000000)*1000; - runtime·nacl_nanosleep(&ts, nil); -} - -void runtime·mstart_nacl(void); - -void -runtime·newosproc(M *mp, void *stk) -{ - int32 ret; - void **tls; - - tls = (void**)mp->tls; - tls[0] = mp->g0; - tls[1] = mp; - ret = runtime·nacl_thread_create(runtime·mstart_nacl, stk, tls+2, 0); - if(ret < 0) { - runtime·printf("nacl_thread_create: error %d\n", -ret); - runtime·throw("newosproc"); - } -} - -static void -semacreate(void) -{ - int32 mu, cond; - - mu = runtime·nacl_mutex_create(0); - if(mu < 0) { - runtime·printf("nacl_mutex_create: error %d\n", -mu); - runtime·throw("semacreate"); - } - cond = runtime·nacl_cond_create(0); - if(cond < 0) { - runtime·printf("nacl_cond_create: error %d\n", -cond); - runtime·throw("semacreate"); - } - g->m->waitsemalock = mu; - g->m->scalararg[0] = cond; // assigned to m->waitsema -} - -#pragma textflag NOSPLIT -uint32 -runtime·semacreate(void) -{ - void (*fn)(void); - uint32 x; - - fn = semacreate; - runtime·onM(&fn); - x = g->m->scalararg[0]; - g->m->scalararg[0] = 0; - return x; -} - -static void -semasleep(void) -{ - int32 ret; - int64 ns; - - ns = (int64)(uint32)g->m->scalararg[0] | (int64)(uint32)g->m->scalararg[1]<<32; - g->m->scalararg[0] = 0; - g->m->scalararg[1] = 0; - - ret = runtime·nacl_mutex_lock(g->m->waitsemalock); - if(ret < 0) { - //runtime·printf("nacl_mutex_lock: error %d\n", -ret); - runtime·throw("semasleep"); - } - if(g->m->waitsemacount > 0) { - g->m->waitsemacount = 0; - runtime·nacl_mutex_unlock(g->m->waitsemalock); - g->m->scalararg[0] = 0; - return; - } - - while(g->m->waitsemacount == 0) { - if(ns < 0) { - ret = runtime·nacl_cond_wait(g->m->waitsema, g->m->waitsemalock); - if(ret < 0) { - //runtime·printf("nacl_cond_wait: error %d\n", -ret); - runtime·throw("semasleep"); - } - } else { - Timespec ts; - - ns += runtime·nanotime(); - ts.tv_sec = runtime·timediv(ns, 1000000000, (int32*)&ts.tv_nsec); - ret = runtime·nacl_cond_timed_wait_abs(g->m->waitsema, g->m->waitsemalock, &ts); - if(ret == -ETIMEDOUT) { - runtime·nacl_mutex_unlock(g->m->waitsemalock); - g->m->scalararg[0] = -1; - return; - } - if(ret < 0) { - //runtime·printf("nacl_cond_timed_wait_abs: error %d\n", -ret); - runtime·throw("semasleep"); - } - } - } - - g->m->waitsemacount = 0; - runtime·nacl_mutex_unlock(g->m->waitsemalock); - g->m->scalararg[0] = 0; -} - -#pragma textflag NOSPLIT -int32 -runtime·semasleep(int64 ns) -{ - int32 r; - void (*fn)(void); - - g->m->scalararg[0] = (uint32)ns; - g->m->scalararg[1] = (uint32)(ns>>32); - fn = semasleep; - runtime·onM(&fn); - r = g->m->scalararg[0]; - g->m->scalararg[0] = 0; - return r; -} - -static void -semawakeup(void) -{ - int32 ret; - M *mp; - - mp = g->m->ptrarg[0]; - g->m->ptrarg[0] = nil; - - ret = runtime·nacl_mutex_lock(mp->waitsemalock); - if(ret < 0) { - //runtime·printf("nacl_mutex_lock: error %d\n", -ret); - runtime·throw("semawakeup"); - } - if(mp->waitsemacount != 0) { - //runtime·printf("semawakeup: double wakeup\n"); - runtime·throw("semawakeup"); - } - mp->waitsemacount = 1; - runtime·nacl_cond_signal(mp->waitsema); - runtime·nacl_mutex_unlock(mp->waitsemalock); -} - -#pragma textflag NOSPLIT -void -runtime·semawakeup(M *mp) -{ - void (*fn)(void); - - g->m->ptrarg[0] = mp; - fn = semawakeup; - runtime·onM(&fn); -} - -uintptr -runtime·memlimit(void) -{ - runtime·printf("memlimit\n"); - return 0; -} - -#pragma dataflag NOPTR -static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n"; - -// This runs on a foreign stack, without an m or a g. No stack split. -#pragma textflag NOSPLIT -void -runtime·badsignal2(void) -{ - runtime·write(2, badsignal, sizeof badsignal - 1); - runtime·exit(2); -} - -void runtime·madvise(byte*, uintptr, int32) { } -void runtime·munmap(byte*, uintptr) {} - -void -runtime·resetcpuprofiler(int32 hz) -{ - USED(hz); -} - -void -runtime·sigdisable(uint32) -{ -} - -void -runtime·sigenable(uint32) -{ -} - -void -runtime·closeonexec(int32) -{ -} - -uint32 runtime·writelock; // test-and-set spin lock for runtime.write - -/* -An attempt at IRT. Doesn't work. See end of sys_nacl_amd64.s. - -void (*runtime·nacl_irt_query)(void); - -int8 runtime·nacl_irt_basic_v0_1_str[] = "nacl-irt-basic-0.1"; -void *runtime·nacl_irt_basic_v0_1[6]; // exit, gettod, clock, nanosleep, sched_yield, sysconf -int32 runtime·nacl_irt_basic_v0_1_size = sizeof(runtime·nacl_irt_basic_v0_1); - -int8 runtime·nacl_irt_memory_v0_3_str[] = "nacl-irt-memory-0.3"; -void *runtime·nacl_irt_memory_v0_3[3]; // mmap, munmap, mprotect -int32 runtime·nacl_irt_memory_v0_3_size = sizeof(runtime·nacl_irt_memory_v0_3); - -int8 runtime·nacl_irt_thread_v0_1_str[] = "nacl-irt-thread-0.1"; -void *runtime·nacl_irt_thread_v0_1[3]; // thread_create, thread_exit, thread_nice -int32 runtime·nacl_irt_thread_v0_1_size = sizeof(runtime·nacl_irt_thread_v0_1); -*/ diff --git a/src/runtime/os_nacl.go b/src/runtime/os_nacl.go index 8dd43ff06f..eff9ec30e4 100644 --- a/src/runtime/os_nacl.go +++ b/src/runtime/os_nacl.go @@ -6,8 +6,8 @@ package runtime import "unsafe" -func nacl_exception_stack(p unsafe.Pointer, size int32) int32 -func nacl_exception_handler(fn, arg unsafe.Pointer) int32 +func nacl_exception_stack(p uintptr, size int32) int32 +func nacl_exception_handler(fn uintptr, arg unsafe.Pointer) int32 func nacl_sem_create(flag int32) int32 func nacl_sem_wait(sem int32) int32 func nacl_sem_post(sem int32) int32 @@ -19,9 +19,20 @@ func nacl_cond_create(flag int32) int32 func nacl_cond_wait(cond, n int32) int32 func nacl_cond_signal(cond int32) int32 func nacl_cond_broadcast(cond int32) int32 -func nacl_cond_timed_wait_abs(cond, lock int32, ts unsafe.Pointer) int32 -func nacl_thread_create(fn, stk, tls, xx unsafe.Pointer) int32 -func nacl_nanosleep(ts, extra unsafe.Pointer) int32 + +//go:noescape +func nacl_cond_timed_wait_abs(cond, lock int32, ts *timespec) int32 +func nacl_thread_create(fn uintptr, stk, tls, xx unsafe.Pointer) int32 + +//go:noescape +func nacl_nanosleep(ts, extra *timespec) int32 +func nanotime() int64 +func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer +func exit(code int32) +func osyield() + +//go:noescape +func write(fd uintptr, p unsafe.Pointer, n int32) int32 func os_sigpipe() { gothrow("too many writes on closed pipe") diff --git a/src/runtime/os_nacl.h b/src/runtime/os_nacl.h deleted file mode 100644 index 7c9d9c242f..0000000000 --- a/src/runtime/os_nacl.h +++ /dev/null @@ -1,162 +0,0 @@ -enum { - NSIG = 32, - SI_USER = 1, - - // native_client/src/trusted/service_runtime/include/sys/errno.h - // The errors are mainly copied from Linux. - EPERM = 1, /* Operation not permitted */ - ENOENT = 2, /* No such file or directory */ - ESRCH = 3, /* No such process */ - EINTR = 4, /* Interrupted system call */ - EIO = 5, /* I/O error */ - ENXIO = 6, /* No such device or address */ - E2BIG = 7, /* Argument list too long */ - ENOEXEC = 8, /* Exec format error */ - EBADF = 9, /* Bad file number */ - ECHILD = 10, /* No child processes */ - EAGAIN = 11, /* Try again */ - ENOMEM = 12, /* Out of memory */ - EACCES = 13, /* Permission denied */ - EFAULT = 14, /* Bad address */ - EBUSY = 16, /* Device or resource busy */ - EEXIST = 17, /* File exists */ - EXDEV = 18, /* Cross-device link */ - ENODEV = 19, /* No such device */ - ENOTDIR = 20, /* Not a directory */ - EISDIR = 21, /* Is a directory */ - EINVAL = 22, /* Invalid argument */ - ENFILE = 23, /* File table overflow */ - EMFILE = 24, /* Too many open files */ - ENOTTY = 25, /* Not a typewriter */ - EFBIG = 27, /* File too large */ - ENOSPC = 28, /* No space left on device */ - ESPIPE = 29, /* Illegal seek */ - EROFS = 30, /* Read-only file system */ - EMLINK = 31, /* Too many links */ - EPIPE = 32, /* Broken pipe */ - ENAMETOOLONG = 36, /* File name too long */ - ENOSYS = 38, /* Function not implemented */ - EDQUOT = 122, /* Quota exceeded */ - EDOM = 33, /* Math arg out of domain of func */ - ERANGE = 34, /* Math result not representable */ - EDEADLK = 35, /* Deadlock condition */ - ENOLCK = 37, /* No record locks available */ - ENOTEMPTY = 39, /* Directory not empty */ - ELOOP = 40, /* Too many symbolic links */ - ENOMSG = 42, /* No message of desired type */ - EIDRM = 43, /* Identifier removed */ - ECHRNG = 44, /* Channel number out of range */ - EL2NSYNC = 45, /* Level 2 not synchronized */ - EL3HLT = 46, /* Level 3 halted */ - EL3RST = 47, /* Level 3 reset */ - ELNRNG = 48, /* Link number out of range */ - EUNATCH = 49, /* Protocol driver not attached */ - ENOCSI = 50, /* No CSI structure available */ - EL2HLT = 51, /* Level 2 halted */ - EBADE = 52, /* Invalid exchange */ - EBADR = 53, /* Invalid request descriptor */ - EXFULL = 54, /* Exchange full */ - ENOANO = 55, /* No anode */ - EBADRQC = 56, /* Invalid request code */ - EBADSLT = 57, /* Invalid slot */ - EDEADLOCK = EDEADLK, /* File locking deadlock error */ - EBFONT = 59, /* Bad font file fmt */ - ENOSTR = 60, /* Device not a stream */ - ENODATA = 61, /* No data (for no delay io) */ - ETIME = 62, /* Timer expired */ - ENOSR = 63, /* Out of streams resources */ - ENONET = 64, /* Machine is not on the network */ - ENOPKG = 65, /* Package not installed */ - EREMOTE = 66, /* The object is remote */ - ENOLINK = 67, /* The link has been severed */ - EADV = 68, /* Advertise error */ - ESRMNT = 69, /* Srmount error */ - ECOMM = 70, /* Communication error on send */ - EPROTO = 71, /* Protocol error */ - EMULTIHOP = 72, /* Multihop attempted */ - EDOTDOT = 73, /* Cross mount point (not really error) */ - EBADMSG = 74, /* Trying to read unreadable message */ - EOVERFLOW = 75, /* Value too large for defined data type */ - ENOTUNIQ = 76, /* Given log. name not unique */ - EBADFD = 77, /* f.d. invalid for this operation */ - EREMCHG = 78, /* Remote address changed */ - ELIBACC = 79, /* Can't access a needed shared lib */ - ELIBBAD = 80, /* Accessing a corrupted shared lib */ - ELIBSCN = 81, /* .lib section in a.out corrupted */ - ELIBMAX = 82, /* Attempting to link in too many libs */ - ELIBEXEC = 83, /* Attempting to exec a shared library */ - EILSEQ = 84, - EUSERS = 87, - ENOTSOCK = 88, /* Socket operation on non-socket */ - EDESTADDRREQ = 89, /* Destination address required */ - EMSGSIZE = 90, /* Message too long */ - EPROTOTYPE = 91, /* Protocol wrong type for socket */ - ENOPROTOOPT = 92, /* Protocol not available */ - EPROTONOSUPPORT = 93, /* Unknown protocol */ - ESOCKTNOSUPPORT = 94, /* Socket type not supported */ - EOPNOTSUPP = 95, /* Operation not supported on transport endpoint */ - EPFNOSUPPORT = 96, /* Protocol family not supported */ - EAFNOSUPPORT = 97, /* Address family not supported by protocol family */ - EADDRINUSE = 98, /* Address already in use */ - EADDRNOTAVAIL = 99, /* Address not available */ - ENETDOWN = 100, /* Network interface is not configured */ - ENETUNREACH = 101, /* Network is unreachable */ - ENETRESET = 102, - ECONNABORTED = 103, /* Connection aborted */ - ECONNRESET = 104, /* Connection reset by peer */ - ENOBUFS = 105, /* No buffer space available */ - EISCONN = 106, /* Socket is already connected */ - ENOTCONN = 107, /* Socket is not connected */ - ESHUTDOWN = 108, /* Can't send after socket shutdown */ - ETOOMANYREFS = 109, - ETIMEDOUT = 110, /* Connection timed out */ - ECONNREFUSED = 111, /* Connection refused */ - EHOSTDOWN = 112, /* Host is down */ - EHOSTUNREACH = 113, /* Host is unreachable */ - EALREADY = 114, /* Socket already connected */ - EINPROGRESS = 115, /* Connection already in progress */ - ESTALE = 116, - ENOTSUP = EOPNOTSUPP, /* Not supported */ - ENOMEDIUM = 123, /* No medium (in tape drive) */ - ECANCELED = 125, /* Operation canceled. */ - ELBIN = 2048, /* Inode is remote (not really error) */ - EFTYPE = 2049, /* Inappropriate file type or format */ - ENMFILE = 2050, /* No more files */ - EPROCLIM = 2051, - ENOSHARE = 2052, /* No such host or network path */ - ECASECLASH = 2053, /* Filename exists with different case */ - EWOULDBLOCK = EAGAIN, /* Operation would block */ - - // native_client/src/trusted/service_runtime/include/bits/mman.h. - // NOTE: DO NOT USE native_client/src/shared/imc/nacl_imc_c.h. - // Those MAP_*values are different from these. - PROT_NONE = 0x0, - PROT_READ = 0x1, - PROT_WRITE = 0x2, - PROT_EXEC = 0x4, - - MAP_SHARED = 0x1, - MAP_PRIVATE = 0x2, - MAP_FIXED = 0x10, - MAP_ANON = 0x20, -}; -typedef byte* kevent_udata; - -int32 runtime·nacl_exception_stack(byte*, int32); -int32 runtime·nacl_exception_handler(void*, void*); -int32 runtime·nacl_sem_create(int32); -int32 runtime·nacl_sem_wait(int32); -int32 runtime·nacl_sem_post(int32); -int32 runtime·nacl_mutex_create(int32); -int32 runtime·nacl_mutex_lock(int32); -int32 runtime·nacl_mutex_trylock(int32); -int32 runtime·nacl_mutex_unlock(int32); -int32 runtime·nacl_cond_create(int32); -int32 runtime·nacl_cond_wait(int32, int32); -int32 runtime·nacl_cond_signal(int32); -int32 runtime·nacl_cond_broadcast(int32); -int32 runtime·nacl_cond_timed_wait_abs(int32, int32, Timespec*); -int32 runtime·nacl_thread_create(void*, void*, void*, void*); -int32 runtime·nacl_nanosleep(Timespec*, Timespec*); - -void runtime·sigpanic(void); diff --git a/src/runtime/os_nacl_arm.c b/src/runtime/os_nacl_arm.go similarity index 61% rename from src/runtime/os_nacl_arm.c rename to src/runtime/os_nacl_arm.go index 1248ea6449..a43e7c47b7 100644 --- a/src/runtime/os_nacl_arm.c +++ b/src/runtime/os_nacl_arm.go @@ -2,23 +2,16 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "textflag.h" +package runtime -void -runtime·checkgoarm(void) -{ - return; // NaCl/ARM only supports ARMv7 +func checkgoarm() { + return // NaCl/ARM only supports ARMv7 } -#pragma textflag NOSPLIT -int64 -runtime·cputicks(void) -{ +//go:nosplit +func cputicks() int64 { // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1(). // runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler. // TODO: need more entropy to better seed fastrand1. - return runtime·nanotime(); + return nanotime() } diff --git a/src/runtime/signal_nacl.go b/src/runtime/signal_nacl.go new file mode 100644 index 0000000000..122648bc33 --- /dev/null +++ b/src/runtime/signal_nacl.go @@ -0,0 +1,45 @@ +// Copyright 2009 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. + +package runtime + +type sigTabT struct { + flags int32 + name string +} + +var sigtable = [...]sigTabT{ + /* 0 */ {0, "SIGNONE: no trap"}, + /* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"}, + /* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"}, + /* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"}, + /* 4 */ {_SigThrow, "SIGILL: illegal instruction"}, + /* 5 */ {_SigThrow, "SIGTRAP: trace trap"}, + /* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"}, + /* 7 */ {_SigThrow, "SIGEMT: emulate instruction executed"}, + /* 8 */ {_SigPanic, "SIGFPE: floating-point exception"}, + /* 9 */ {0, "SIGKILL: kill"}, + /* 10 */ {_SigPanic, "SIGBUS: bus error"}, + /* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"}, + /* 12 */ {_SigThrow, "SIGSYS: bad system call"}, + /* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"}, + /* 14 */ {_SigNotify, "SIGALRM: alarm clock"}, + /* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"}, + /* 16 */ {_SigNotify, "SIGURG: urgent condition on socket"}, + /* 17 */ {0, "SIGSTOP: stop"}, + /* 18 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"}, + /* 19 */ {0, "SIGCONT: continue after stop"}, + /* 20 */ {_SigNotify, "SIGCHLD: child status has changed"}, + /* 21 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"}, + /* 22 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"}, + /* 23 */ {_SigNotify, "SIGIO: i/o now possible"}, + /* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"}, + /* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"}, + /* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"}, + /* 27 */ {_SigNotify, "SIGPROF: profiling alarm clock"}, + /* 28 */ {_SigNotify, "SIGWINCH: window size change"}, + /* 29 */ {_SigNotify, "SIGINFO: status request from keyboard"}, + /* 30 */ {_SigNotify, "SIGUSR1: user-defined signal 1"}, + /* 31 */ {_SigNotify, "SIGUSR2: user-defined signal 2"}, +} diff --git a/src/runtime/signal_nacl_386.go b/src/runtime/signal_nacl_386.go new file mode 100644 index 0000000000..0a1e7c6ea5 --- /dev/null +++ b/src/runtime/signal_nacl_386.go @@ -0,0 +1,34 @@ +// 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. + +package runtime + +import "unsafe" + +type sigctxt struct { + info *siginfo + ctxt unsafe.Pointer +} + +func (c *sigctxt) regs() *excregs386 { return &(*exccontext)(c.ctxt).regs } +func (c *sigctxt) eax() uint32 { return c.regs().eax } +func (c *sigctxt) ebx() uint32 { return c.regs().ebx } +func (c *sigctxt) ecx() uint32 { return c.regs().ecx } +func (c *sigctxt) edx() uint32 { return c.regs().edx } +func (c *sigctxt) edi() uint32 { return c.regs().edi } +func (c *sigctxt) esi() uint32 { return c.regs().esi } +func (c *sigctxt) ebp() uint32 { return c.regs().ebp } +func (c *sigctxt) esp() uint32 { return c.regs().esp } +func (c *sigctxt) eip() uint32 { return c.regs().eip } +func (c *sigctxt) eflags() uint32 { return c.regs().eflags } +func (c *sigctxt) cs() uint32 { return ^uint32(0) } +func (c *sigctxt) fs() uint32 { return ^uint32(0) } +func (c *sigctxt) gs() uint32 { return ^uint32(0) } +func (c *sigctxt) sigcode() uint32 { return ^uint32(0) } +func (c *sigctxt) sigaddr() uint32 { return 0 } + +func (c *sigctxt) set_eip(x uint32) { c.regs().eip = x } +func (c *sigctxt) set_esp(x uint32) { c.regs().esp = x } +func (c *sigctxt) set_sigcode(x uint32) {} +func (c *sigctxt) set_sigaddr(x uint32) {} diff --git a/src/runtime/signal_nacl_386.h b/src/runtime/signal_nacl_386.h deleted file mode 100644 index c9481b5f4f..0000000000 --- a/src/runtime/signal_nacl_386.h +++ /dev/null @@ -1,23 +0,0 @@ -// 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. - -#define SIG_REGS(ctxt) (((ExcContext*)(ctxt))->regs) - -#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).eax) -#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).ebx) -#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).ecx) -#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).edx) -#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).edi) -#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).esi) -#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).ebp) -#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).esp) -#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).eip) -#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).eflags) - -#define SIG_CS(info, ctxt) (~0) -#define SIG_FS(info, ctxt) (~0) -#define SIG_GS(info, ctxt) (~0) - -#define SIG_CODE0(info, ctxt) (~0) -#define SIG_CODE1(info, ctxt) (0) diff --git a/src/runtime/signal_nacl_amd64p32.go b/src/runtime/signal_nacl_amd64p32.go new file mode 100644 index 0000000000..024cebaddd --- /dev/null +++ b/src/runtime/signal_nacl_amd64p32.go @@ -0,0 +1,44 @@ +// Copyright 2014 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. + +package runtime + +import "unsafe" + +type sigctxt struct { + info *siginfo + ctxt unsafe.Pointer +} + +func (c *sigctxt) regs() *excregsamd64 { + return &(*exccontext)(c.ctxt).regs +} +func (c *sigctxt) rax() uint64 { return c.regs().rax } +func (c *sigctxt) rbx() uint64 { return c.regs().rbx } +func (c *sigctxt) rcx() uint64 { return c.regs().rcx } +func (c *sigctxt) rdx() uint64 { return c.regs().rdx } +func (c *sigctxt) rdi() uint64 { return c.regs().rdi } +func (c *sigctxt) rsi() uint64 { return c.regs().rsi } +func (c *sigctxt) rbp() uint64 { return c.regs().rbp } +func (c *sigctxt) rsp() uint64 { return c.regs().rsp } +func (c *sigctxt) r8() uint64 { return c.regs().r8 } +func (c *sigctxt) r9() uint64 { return c.regs().r9 } +func (c *sigctxt) r10() uint64 { return c.regs().r10 } +func (c *sigctxt) r11() uint64 { return c.regs().r11 } +func (c *sigctxt) r12() uint64 { return c.regs().r12 } +func (c *sigctxt) r13() uint64 { return c.regs().r13 } +func (c *sigctxt) r14() uint64 { return c.regs().r14 } +func (c *sigctxt) r15() uint64 { return c.regs().r15 } +func (c *sigctxt) rip() uint64 { return c.regs().rip } +func (c *sigctxt) rflags() uint64 { return uint64(c.regs().rflags) } +func (c *sigctxt) cs() uint64 { return ^uint64(0) } +func (c *sigctxt) fs() uint64 { return ^uint64(0) } +func (c *sigctxt) gs() uint64 { return ^uint64(0) } +func (c *sigctxt) sigcode() uint64 { return ^uint64(0) } +func (c *sigctxt) sigaddr() uint64 { return 0 } + +func (c *sigctxt) set_rip(x uint64) { c.regs().rip = x } +func (c *sigctxt) set_rsp(x uint64) { c.regs().rsp = x } +func (c *sigctxt) set_sigcode(x uint64) {} +func (c *sigctxt) set_sigaddr(x uint64) {} diff --git a/src/runtime/signal_nacl_amd64p32.h b/src/runtime/signal_nacl_amd64p32.h deleted file mode 100644 index f62305cb52..0000000000 --- a/src/runtime/signal_nacl_amd64p32.h +++ /dev/null @@ -1,31 +0,0 @@ -// 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. - -#define SIG_REGS(ctxt) (((ExcContext*)(ctxt))->regs.regs64) - -#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).rax) -#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).rbx) -#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).rcx) -#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).rdx) -#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).rdi) -#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).rsi) -#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).rbp) -#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).rsp) -#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).r8) -#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).r9) -#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).r10) -#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).r11) -#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).r12) -#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).r13) -#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).r14) -#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).r15) -#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).rip) -#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).rflags) - -#define SIG_CS(info, ctxt) (~0) -#define SIG_FS(info, ctxt) (~0) -#define SIG_GS(info, ctxt) (~0) - -#define SIG_CODE0(info, ctxt) (~0) -#define SIG_CODE1(info, ctxt) (0) diff --git a/src/runtime/signal_nacl_arm.go b/src/runtime/signal_nacl_arm.go new file mode 100644 index 0000000000..1aeaa4e428 --- /dev/null +++ b/src/runtime/signal_nacl_arm.go @@ -0,0 +1,47 @@ +// Copyright 2014 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. + +package runtime + +import "unsafe" + +type sigctxt struct { + info *siginfo + ctxt unsafe.Pointer +} + +func (c *sigctxt) regs() *excregsarm { return &(*exccontext)(c.ctxt).regs } + +func (c *sigctxt) r0() uint32 { return c.regs().r0 } +func (c *sigctxt) r1() uint32 { return c.regs().r1 } +func (c *sigctxt) r2() uint32 { return c.regs().r2 } +func (c *sigctxt) r3() uint32 { return c.regs().r3 } +func (c *sigctxt) r4() uint32 { return c.regs().r4 } +func (c *sigctxt) r5() uint32 { return c.regs().r5 } +func (c *sigctxt) r6() uint32 { return c.regs().r6 } +func (c *sigctxt) r7() uint32 { return c.regs().r7 } +func (c *sigctxt) r8() uint32 { return c.regs().r8 } +func (c *sigctxt) r9() uint32 { return c.regs().r9 } +func (c *sigctxt) r10() uint32 { return c.regs().r10 } +func (c *sigctxt) fp() uint32 { return c.regs().r11 } +func (c *sigctxt) ip() uint32 { return c.regs().r12 } +func (c *sigctxt) sp() uint32 { return c.regs().sp } +func (c *sigctxt) lr() uint32 { return c.regs().lr } +func (c *sigctxt) pc() uint32 { return c.regs().pc } +func (c *sigctxt) cpsr() uint32 { return c.regs().cpsr } +func (c *sigctxt) fault() uint32 { return ^uint32(0) } +func (c *sigctxt) trap() uint32 { return ^uint32(0) } +func (c *sigctxt) error() uint32 { return ^uint32(0) } +func (c *sigctxt) oldmask() uint32 { return ^uint32(0) } + +func (c *sigctxt) sigcode() uint32 { return 0 } +func (c *sigctxt) sigaddr() uint32 { return 0 } + +func (c *sigctxt) set_pc(x uint32) { c.regs().pc = x } +func (c *sigctxt) set_sp(x uint32) { c.regs().sp = x } +func (c *sigctxt) set_lr(x uint32) { c.regs().lr = x } +func (c *sigctxt) set_r10(x uint32) { c.regs().r10 = x } + +func (c *sigctxt) set_sigcode(x uint32) {} +func (c *sigctxt) set_sigaddr(x uint32) {} diff --git a/src/runtime/signal_nacl_arm.h b/src/runtime/signal_nacl_arm.h deleted file mode 100644 index e5bbb211dd..0000000000 --- a/src/runtime/signal_nacl_arm.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2014 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. - -#define SIG_REGS(ctxt) (((ExcContext*)(ctxt))->regs) - -#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).r0) -#define SIG_R1(info, ctxt) (SIG_REGS(ctxt).r1) -#define SIG_R2(info, ctxt) (SIG_REGS(ctxt).r2) -#define SIG_R3(info, ctxt) (SIG_REGS(ctxt).r3) -#define SIG_R4(info, ctxt) (SIG_REGS(ctxt).r4) -#define SIG_R5(info, ctxt) (SIG_REGS(ctxt).r5) -#define SIG_R6(info, ctxt) (SIG_REGS(ctxt).r6) -#define SIG_R7(info, ctxt) (SIG_REGS(ctxt).r7) -#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).r8) -#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).r9) -#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).r10) -#define SIG_FP(info, ctxt) (SIG_REGS(ctxt).r11) -#define SIG_IP(info, ctxt) (SIG_REGS(ctxt).r12) -#define SIG_SP(info, ctxt) (SIG_REGS(ctxt).sp) -#define SIG_LR(info, ctxt) (SIG_REGS(ctxt).lr) -#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).pc) -#define SIG_CPSR(info, ctxt) (SIG_REGS(ctxt).cpsr) -#define SIG_FAULT(info, ctxt) (~0) -#define SIG_TRAP(info, ctxt) (~0) -#define SIG_ERROR(info, ctxt) (~0) -#define SIG_OLDMASK(info, ctxt) (~0) -#define SIG_CODE0(info, ctxt) (~0) diff --git a/src/runtime/signals_nacl.h b/src/runtime/signals_nacl.h deleted file mode 100644 index 8761e1bd94..0000000000 --- a/src/runtime/signals_nacl.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2009 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. - -#include "textflag.h" - -#define N SigNotify -#define K SigKill -#define T SigThrow -#define P SigPanic -#define D SigDefault - -#pragma dataflag NOPTR -SigTab runtime·sigtab[] = { - /* 0 */ 0, "SIGNONE: no trap", - /* 1 */ N+K, "SIGHUP: terminal line hangup", - /* 2 */ N+K, "SIGINT: interrupt", - /* 3 */ N+T, "SIGQUIT: quit", - /* 4 */ T, "SIGILL: illegal instruction", - /* 5 */ T, "SIGTRAP: trace trap", - /* 6 */ N+T, "SIGABRT: abort", - /* 7 */ T, "SIGEMT: emulate instruction executed", - /* 8 */ P, "SIGFPE: floating-point exception", - /* 9 */ 0, "SIGKILL: kill", - /* 10 */ P, "SIGBUS: bus error", - /* 11 */ P, "SIGSEGV: segmentation violation", - /* 12 */ T, "SIGSYS: bad system call", - /* 13 */ N, "SIGPIPE: write to broken pipe", - /* 14 */ N, "SIGALRM: alarm clock", - /* 15 */ N+K, "SIGTERM: termination", - /* 16 */ N, "SIGURG: urgent condition on socket", - /* 17 */ 0, "SIGSTOP: stop", - /* 18 */ N+D, "SIGTSTP: keyboard stop", - /* 19 */ 0, "SIGCONT: continue after stop", - /* 20 */ N, "SIGCHLD: child status has changed", - /* 21 */ N+D, "SIGTTIN: background read from tty", - /* 22 */ N+D, "SIGTTOU: background write to tty", - /* 23 */ N, "SIGIO: i/o now possible", - /* 24 */ N, "SIGXCPU: cpu limit exceeded", - /* 25 */ N, "SIGXFSZ: file size limit exceeded", - /* 26 */ N, "SIGVTALRM: virtual alarm clock", - /* 27 */ N, "SIGPROF: profiling alarm clock", - /* 28 */ N, "SIGWINCH: window size change", - /* 29 */ N, "SIGINFO: status request from keyboard", - /* 30 */ N, "SIGUSR1: user-defined signal 1", - /* 31 */ N, "SIGUSR2: user-defined signal 2", -}; - -#undef N -#undef K -#undef T -#undef P -#undef D diff --git a/src/runtime/stubs2.go b/src/runtime/stubs2.go index cb0b0f0ed5..74cc5c6a7c 100644 --- a/src/runtime/stubs2.go +++ b/src/runtime/stubs2.go @@ -4,6 +4,7 @@ // +build !solaris // +build !windows +// +build !nacl package runtime From e9c57d8a2d7833a66a511888c4744e058bc68967 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Fri, 21 Nov 2014 19:39:01 +0100 Subject: [PATCH 58/68] [dev.cc] runtime: convert Plan 9 port to Go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thanks to Aram Hăvărneanu, Nick Owens and Russ Cox for the early reviews. LGTM=aram, rsc R=rsc, lucio.dere, aram, ality CC=golang-codereviews, mischief https://golang.org/cl/175370043 --- src/runtime/defs_plan9_386.go | 2 + src/runtime/defs_plan9_amd64.go | 2 + src/runtime/env_plan9.go | 3 + src/runtime/mem_plan9.c | 121 ------ src/runtime/mem_plan9.go | 70 ++++ .../{netpoll_stub.c => netpoll_stub.go} | 9 +- src/runtime/os1_plan9.go | 270 +++++++++++++ src/runtime/os2_plan9.go | 72 ++++ src/runtime/os_plan9.c | 362 ------------------ src/runtime/os_plan9.go | 27 ++ src/runtime/os_plan9.h | 93 ----- src/runtime/os_plan9_386.c | 150 -------- src/runtime/os_plan9_386.go | 131 +++++++ src/runtime/os_plan9_amd64.c | 158 -------- src/runtime/os_plan9_amd64.go | 139 +++++++ .../{signals_plan9.h => signal_plan9.go} | 57 ++- src/runtime/stubs2.go | 1 + src/runtime/stubs3.go | 12 + 18 files changed, 756 insertions(+), 923 deletions(-) delete mode 100644 src/runtime/mem_plan9.c create mode 100644 src/runtime/mem_plan9.go rename src/runtime/{netpoll_stub.c => netpoll_stub.go} (81%) create mode 100644 src/runtime/os1_plan9.go create mode 100644 src/runtime/os2_plan9.go delete mode 100644 src/runtime/os_plan9.c delete mode 100644 src/runtime/os_plan9.h delete mode 100644 src/runtime/os_plan9_386.c create mode 100644 src/runtime/os_plan9_386.go delete mode 100644 src/runtime/os_plan9_amd64.c create mode 100644 src/runtime/os_plan9_amd64.go rename src/runtime/{signals_plan9.h => signal_plan9.go} (54%) create mode 100644 src/runtime/stubs3.go diff --git a/src/runtime/defs_plan9_386.go b/src/runtime/defs_plan9_386.go index 170506b230..212ecdf14a 100644 --- a/src/runtime/defs_plan9_386.go +++ b/src/runtime/defs_plan9_386.go @@ -1,5 +1,7 @@ package runtime +const _PAGESIZE = 0x1000 + type ureg struct { di uint32 /* general registers */ si uint32 /* ... */ diff --git a/src/runtime/defs_plan9_amd64.go b/src/runtime/defs_plan9_amd64.go index 17becfb66f..510da0e994 100644 --- a/src/runtime/defs_plan9_amd64.go +++ b/src/runtime/defs_plan9_amd64.go @@ -1,5 +1,7 @@ package runtime +const _PAGESIZE = 0x1000 + type ureg struct { ax uint64 bx uint64 diff --git a/src/runtime/env_plan9.go b/src/runtime/env_plan9.go index e442c34835..ec50cac484 100644 --- a/src/runtime/env_plan9.go +++ b/src/runtime/env_plan9.go @@ -54,3 +54,6 @@ func gogetenv(key string) string { sp.len = int(r) return s } + +var _cgo_setenv unsafe.Pointer // pointer to C function +var _cgo_unsetenv unsafe.Pointer // pointer to C function diff --git a/src/runtime/mem_plan9.c b/src/runtime/mem_plan9.c deleted file mode 100644 index d673d6f830..0000000000 --- a/src/runtime/mem_plan9.c +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2010 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. - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "arch_GOARCH.h" -#include "malloc.h" -#include "os_GOOS.h" -#include "textflag.h" - -extern byte runtime·end[]; -#pragma dataflag NOPTR -static byte *bloc = { runtime·end }; -static Mutex memlock; - -enum -{ - Round = PAGESIZE-1 -}; - -static void* -brk(uintptr nbytes) -{ - uintptr bl; - - runtime·lock(&memlock); - // Plan 9 sbrk from /sys/src/libc/9sys/sbrk.c - bl = ((uintptr)bloc + Round) & ~Round; - if(runtime·brk_((void*)(bl + nbytes)) < 0) { - runtime·unlock(&memlock); - return nil; - } - bloc = (byte*)bl + nbytes; - runtime·unlock(&memlock); - return (void*)bl; -} - -static void -sysalloc(void) -{ - uintptr nbytes; - uint64 *stat; - void *p; - - nbytes = g->m->scalararg[0]; - stat = g->m->ptrarg[0]; - g->m->scalararg[0] = 0; - g->m->ptrarg[0] = nil; - - p = brk(nbytes); - if(p != nil) - runtime·xadd64(stat, nbytes); - - g->m->ptrarg[0] = p; -} - -#pragma textflag NOSPLIT -void* -runtime·sysAlloc(uintptr nbytes, uint64 *stat) -{ - void (*fn)(void); - void *p; - - g->m->scalararg[0] = nbytes; - g->m->ptrarg[0] = stat; - fn = sysalloc; - runtime·onM(&fn); - p = g->m->ptrarg[0]; - g->m->ptrarg[0] = nil; - return p; -} - -void -runtime·SysFree(void *v, uintptr nbytes, uint64 *stat) -{ - runtime·xadd64(stat, -(uint64)nbytes); - runtime·lock(&memlock); - // from tiny/mem.c - // Push pointer back if this is a free - // of the most recent sysAlloc. - nbytes += (nbytes + Round) & ~Round; - if(bloc == (byte*)v+nbytes) - bloc -= nbytes; - runtime·unlock(&memlock); -} - -void -runtime·SysUnused(void *v, uintptr nbytes) -{ - USED(v, nbytes); -} - -void -runtime·SysUsed(void *v, uintptr nbytes) -{ - USED(v, nbytes); -} - -void -runtime·SysMap(void *v, uintptr nbytes, bool reserved, uint64 *stat) -{ - // SysReserve has already allocated all heap memory, - // but has not adjusted stats. - USED(v, reserved); - runtime·xadd64(stat, nbytes); -} - -void -runtime·SysFault(void *v, uintptr nbytes) -{ - USED(v, nbytes); -} - -void* -runtime·SysReserve(void *v, uintptr nbytes, bool *reserved) -{ - USED(v); - *reserved = true; - return brk(nbytes); -} diff --git a/src/runtime/mem_plan9.go b/src/runtime/mem_plan9.go new file mode 100644 index 0000000000..a5d7c1a4cf --- /dev/null +++ b/src/runtime/mem_plan9.go @@ -0,0 +1,70 @@ +// Copyright 2010 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. + +package runtime + +import "unsafe" + +var bloc uintptr +var memlock mutex + +const memRound = _PAGESIZE - 1 + +func initBloc() { + bloc = uintptr(unsafe.Pointer(&end)) +} + +func sbrk(n uintptr) unsafe.Pointer { + lock(&memlock) + // Plan 9 sbrk from /sys/src/libc/9sys/sbrk.c + bl := (bloc + memRound) &^ memRound + if brk_(unsafe.Pointer(bl+n)) < 0 { + unlock(&memlock) + return nil + } + bloc = bl + n + unlock(&memlock) + return unsafe.Pointer(bl) +} + +func sysAlloc(n uintptr, stat *uint64) unsafe.Pointer { + p := sbrk(n) + if p != nil { + xadd64(stat, int64(n)) + } + return p +} + +func sysFree(v unsafe.Pointer, n uintptr, stat *uint64) { + xadd64(stat, -int64(n)) + lock(&memlock) + // from tiny/mem.c + // Push pointer back if this is a free + // of the most recent sysAlloc. + n += (n + memRound) &^ memRound + if bloc == uintptr(v)+n { + bloc -= n + } + unlock(&memlock) +} + +func sysUnused(v unsafe.Pointer, n uintptr) { +} + +func sysUsed(v unsafe.Pointer, n uintptr) { +} + +func sysMap(v unsafe.Pointer, n uintptr, reserved bool, stat *uint64) { + // sysReserve has already allocated all heap memory, + // but has not adjusted stats. + xadd64(stat, int64(n)) +} + +func sysFault(v unsafe.Pointer, n uintptr) { +} + +func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer { + *reserved = true + return sbrk(n) +} diff --git a/src/runtime/netpoll_stub.c b/src/runtime/netpoll_stub.go similarity index 81% rename from src/runtime/netpoll_stub.c rename to src/runtime/netpoll_stub.go index b7a8f2944c..6c7e79ea37 100644 --- a/src/runtime/netpoll_stub.c +++ b/src/runtime/netpoll_stub.go @@ -4,15 +4,12 @@ // +build plan9 -#include "runtime.h" +package runtime // Polls for ready network connections. // Returns list of goroutines that become runnable. -G* -runtime·netpoll(bool block) -{ +func netpoll(block bool) (gp *g) { // Implementation for platforms that do not support // integrated network poller. - USED(block); - return nil; + return } diff --git a/src/runtime/os1_plan9.go b/src/runtime/os1_plan9.go new file mode 100644 index 0000000000..0f8da03f2b --- /dev/null +++ b/src/runtime/os1_plan9.go @@ -0,0 +1,270 @@ +// Copyright 2010 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. + +package runtime + +import "unsafe" + +// Called to initialize a new m (including the bootstrap m). +// Called on the parent thread (main thread in case of bootstrap), can allocate memory. +func mpreinit(mp *m) { + // Initialize stack and goroutine for note handling. + mp.gsignal = malg(32 * 1024) + mp.gsignal.m = mp + mp.notesig = (*int8)(mallocgc(_ERRMAX, nil, _FlagNoScan)) + // Initialize stack for handling strings from the + // errstr system call, as used in package syscall. + mp.errstr = (*byte)(mallocgc(_ERRMAX, nil, _FlagNoScan)) +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the new thread, can not allocate memory. +func minit() { + // Mask all SSE floating-point exceptions + // when running on the 64-bit kernel. + setfpmasks() +} + +// Called from dropm to undo the effect of an minit. +func unminit() { +} + +var sysstat = []byte("/dev/sysstat\x00") + +func getproccount() int32 { + var buf [2048]byte + fd := open(&sysstat[0], _OREAD, 0) + if fd < 0 { + return 1 + } + ncpu := int32(0) + for { + n := read(fd, unsafe.Pointer(&buf), int32(len(buf))) + if n <= 0 { + break + } + for i := int32(0); i < n; i++ { + if buf[i] == '\n' { + ncpu++ + } + } + } + close(fd) + if ncpu == 0 { + ncpu = 1 + } + return ncpu +} + +var pid = []byte("#c/pid\x00") + +func getpid() uint64 { + var b [20]byte + fd := open(&pid[0], 0, 0) + if fd >= 0 { + read(fd, unsafe.Pointer(&b), int32(len(b))) + close(fd) + } + c := b[:] + for c[0] == ' ' || c[0] == '\t' { + c = c[1:] + } + return uint64(atoi(c)) +} + +func osinit() { + initBloc() + ncpu = getproccount() + getg().m.procid = getpid() + notify(unsafe.Pointer(funcPC(sigtramp))) +} + +func crash() { + notify(nil) + *(*int)(nil) = 0 +} + +var random_data [_HashRandomBytes]byte +var random_dev = []byte("/dev/random\x00") + +//go:nosplit +func get_random_data(rnd *unsafe.Pointer, rnd_len *int32) { + fd := open(&random_dev[0], 0 /* O_RDONLY */, 0) + if read(fd, unsafe.Pointer(&random_data), _HashRandomBytes) == _HashRandomBytes { + *rnd = unsafe.Pointer(&random_data[0]) + *rnd_len = _HashRandomBytes + } else { + *rnd = nil + *rnd_len = 0 + } + close(fd) +} + +func goenvs() { +} + +func initsig() { +} + +//go:nosplit +func osyield() { + sleep(0) +} + +//go:nosplit +func usleep(µs uint32) { + ms := int32(µs / 1000) + if ms == 0 { + ms = 1 + } + sleep(ms) +} + +//go:nosplit +func nanotime() int64 { + var scratch int64 + ns := nsec(&scratch) + // TODO(aram): remove hack after I fix _nsec in the pc64 kernel. + if ns == 0 { + return scratch + } + return ns +} + +//go:nosplit +func itoa(buf []byte, val uint64) []byte { + i := len(buf) - 1 + for val >= 10 { + buf[i] = byte(val%10 + '0') + i-- + val /= 10 + } + buf[i] = byte(val + '0') + return buf[i:] +} + +var goexits = []byte("go: exit ") + +func goexitsall(status *byte) { + var buf [_ERRMAX]byte + n := copy(buf[:], goexits) + n = copy(buf[n:], gostringnocopy(status)) + pid := getpid() + for mp := (*m)(atomicloadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink { + if mp.procid != pid { + postnote(mp.procid, buf[:]) + } + } +} + +var procdir = []byte("/proc/") +var notefile = []byte("/note\x00") + +func postnote(pid uint64, msg []byte) int { + var buf [128]byte + var tmp [32]byte + n := copy(buf[:], procdir) + n += copy(buf[n:], itoa(tmp[:], pid)) + copy(buf[n:], notefile) + fd := open(&buf[0], _OWRITE, 0) + if fd < 0 { + return -1 + } + len := findnull(&msg[0]) + if write(uintptr(fd), (unsafe.Pointer)(&msg[0]), int32(len)) != int64(len) { + close(fd) + return -1 + } + close(fd) + return 0 +} + +//go:nosplit +func exit(e int) { + var status []byte + if e == 0 { + status = []byte("\x00") + } else { + // build error string + var tmp [32]byte + status = []byte(gostringnocopy(&itoa(tmp[:], uint64(e))[0]) + "\x00") + } + goexitsall(&status[0]) + exits(&status[0]) +} + +func newosproc(mp *m, stk unsafe.Pointer) { + if false { + print("newosproc mp=", mp, " ostk=", &mp, "\n") + } + pid := rfork(_RFPROC | _RFMEM | _RFNOWAIT) + if pid < 0 { + gothrow("newosproc: rfork failed") + } + if pid == 0 { + tstart_plan9(mp) + } +} + +//go:nosplit +func semacreate() uintptr { + return 1 +} + +//go:nosplit +func semasleep(ns int64) int { + _g_ := getg() + if ns >= 0 { + ms := timediv(ns, 1000000, nil) + if ms == 0 { + ms = 1 + } + ret := plan9_tsemacquire(&_g_.m.waitsemacount, ms) + if ret == 1 { + return 0 // success + } + return -1 // timeout or interrupted + } + for plan9_semacquire(&_g_.m.waitsemacount, 1) < 0 { + // interrupted; try again (c.f. lock_sema.go) + } + return 0 // success +} + +//go:nosplit +func semawakeup(mp *m) { + plan9_semrelease(&mp.waitsemacount, 1) +} + +//go:nosplit +func read(fd int32, buf unsafe.Pointer, n int32) int32 { + return pread(fd, buf, n, -1) +} + +//go:nosplit +func write(fd uintptr, buf unsafe.Pointer, n int32) int64 { + return int64(pwrite(int32(fd), buf, n, -1)) +} + +func memlimit() uint64 { + return 0 +} + +var _badsignal = []byte("runtime: signal received on thread not created by Go.\n") + +// This runs on a foreign stack, without an m or a g. No stack split. +//go:nosplit +func badsignal2() { + pwrite(2, unsafe.Pointer(&_badsignal[0]), int32(len(_badsignal)), -1) + exits(&_badsignal[0]) +} + +func atoi(b []byte) int { + n := 0 + for len(b) > 0 && '0' <= b[0] && b[0] <= '9' { + n = n*10 + int(b[0]) - '0' + b = b[1:] + } + return n +} diff --git a/src/runtime/os2_plan9.go b/src/runtime/os2_plan9.go new file mode 100644 index 0000000000..f64f4c8dab --- /dev/null +++ b/src/runtime/os2_plan9.go @@ -0,0 +1,72 @@ +// Copyright 2010 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. + +// Plan 9-specific system calls + +package runtime + +// open +const ( + _OREAD = 0 + _OWRITE = 1 + _ORDWR = 2 + _OEXEC = 3 + _OTRUNC = 16 + _OCEXEC = 32 + _ORCLOSE = 64 + _OEXCL = 0x1000 +) + +// rfork +const ( + _RFNAMEG = 1 << 0 + _RFENVG = 1 << 1 + _RFFDG = 1 << 2 + _RFNOTEG = 1 << 3 + _RFPROC = 1 << 4 + _RFMEM = 1 << 5 + _RFNOWAIT = 1 << 6 + _RFCNAMEG = 1 << 10 + _RFCENVG = 1 << 11 + _RFCFDG = 1 << 12 + _RFREND = 1 << 13 + _RFNOMNT = 1 << 14 +) + +// notify +const ( + _NCONT = 0 + _NDFLT = 1 +) + +type uinptr _Plink + +type tos struct { + prof struct { // Per process profiling + pp *_Plink // known to be 0(ptr) + next *_Plink // known to be 4(ptr) + last *_Plink + first *_Plink + pid uint32 + what uint32 + } + cyclefreq uint64 // cycle clock frequency if there is one, 0 otherwise + kcycles int64 // cycles spent in kernel + pcycles int64 // cycles spent in process (kernel + user) + pid uint32 // might as well put the pid here + clock uint32 + // top of stack is here +} + +const ( + _NSIG = 14 // number of signals in sigtable array + _ERRMAX = 128 // max length of note string + + // Notes in runtime·sigtab that are handled by runtime·sigpanic. + _SIGRFAULT = 2 + _SIGWFAULT = 3 + _SIGINTDIV = 4 + _SIGFLOAT = 5 + _SIGTRAP = 6 +) diff --git a/src/runtime/os_plan9.c b/src/runtime/os_plan9.c deleted file mode 100644 index f8c543f6f6..0000000000 --- a/src/runtime/os_plan9.c +++ /dev/null @@ -1,362 +0,0 @@ -// Copyright 2010 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. - -#include "runtime.h" -#include "os_GOOS.h" -#include "arch_GOARCH.h" -#include "textflag.h" -#include "malloc.h" - -int8 *goos = "plan9"; -extern SigTab runtime·sigtab[]; - -int32 runtime·postnote(int32, int8*); - -// Called to initialize a new m (including the bootstrap m). -// Called on the parent thread (main thread in case of bootstrap), can allocate memory. -void -runtime·mpreinit(M *mp) -{ - // Initialize stack and goroutine for note handling. - mp->gsignal = runtime·malg(32*1024); - mp->gsignal->m = mp; - mp->notesig = (int8*)runtime·mallocgc(ERRMAX*sizeof(int8), nil, FlagNoScan); - - // Initialize stack for handling strings from the - // errstr system call, as used in package syscall. - mp->errstr = (byte*)runtime·mallocgc(ERRMAX*sizeof(byte), nil, FlagNoScan); -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the new thread, can not allocate memory. -void -runtime·minit(void) -{ - // Mask all SSE floating-point exceptions - // when running on the 64-bit kernel. - runtime·setfpmasks(); -} - -// Called from dropm to undo the effect of an minit. -void -runtime·unminit(void) -{ -} - - -static int32 -getproccount(void) -{ - int32 fd, i, n, ncpu; - byte buf[2048]; - - fd = runtime·open("/dev/sysstat", OREAD, 0); - if(fd < 0) - return 1; - ncpu = 0; - for(;;) { - n = runtime·read(fd, buf, sizeof buf); - if(n <= 0) - break; - for(i = 0; i < n; i++) { - if(buf[i] == '\n') - ncpu++; - } - } - runtime·close(fd); - return ncpu > 0 ? ncpu : 1; -} - -static int32 -getpid(void) -{ - byte b[20], *c; - int32 fd; - - runtime·memclr(b, sizeof(b)); - fd = runtime·open("#c/pid", 0, 0); - if(fd >= 0) { - runtime·read(fd, b, sizeof(b)); - runtime·close(fd); - } - c = b; - while(*c == ' ' || *c == '\t') - c++; - return runtime·atoi(c); -} - -void -runtime·osinit(void) -{ - runtime·ncpu = getproccount(); - g->m->procid = getpid(); - runtime·notify(runtime·sigtramp); -} - -void -runtime·crash(void) -{ - runtime·notify(nil); - *(int32*)0 = 0; -} - -#pragma textflag NOSPLIT -void -runtime·get_random_data(byte **rnd, int32 *rnd_len) -{ - static byte random_data[HashRandomBytes]; - int32 fd; - - fd = runtime·open("/dev/random", 0 /* O_RDONLY */, 0); - if(runtime·read(fd, random_data, HashRandomBytes) == HashRandomBytes) { - *rnd = random_data; - *rnd_len = HashRandomBytes; - } else { - *rnd = nil; - *rnd_len = 0; - } - runtime·close(fd); -} - -void -runtime·goenvs(void) -{ -} - -void -runtime·initsig(void) -{ -} - -#pragma textflag NOSPLIT -void -runtime·osyield(void) -{ - runtime·sleep(0); -} - -#pragma textflag NOSPLIT -void -runtime·usleep(uint32 µs) -{ - uint32 ms; - - ms = µs/1000; - if(ms == 0) - ms = 1; - runtime·sleep(ms); -} - -#pragma textflag NOSPLIT -int64 -runtime·nanotime(void) -{ - int64 ns, scratch; - - ns = runtime·nsec(&scratch); - // TODO(aram): remove hack after I fix _nsec in the pc64 kernel. - if(ns == 0) - return scratch; - return ns; -} - -#pragma textflag NOSPLIT -void -runtime·itoa(int32 n, byte *p, uint32 len) -{ - byte *q, c; - uint32 i; - - if(len <= 1) - return; - - runtime·memclr(p, len); - q = p; - - if(n==0) { - *q++ = '0'; - USED(q); - return; - } - if(n < 0) { - *q++ = '-'; - p++; - n = -n; - } - for(i=0; n > 0 && i < len; i++) { - *q++ = '0' + (n%10); - n = n/10; - } - for(q--; q >= p; ) { - c = *p; - *p++ = *q; - *q-- = c; - } -} - -void -runtime·goexitsall(int8 *status) -{ - int8 buf[ERRMAX]; - M *mp; - int32 pid; - - runtime·snprintf((byte*)buf, sizeof buf, "go: exit %s", status); - pid = getpid(); - for(mp=runtime·atomicloadp(&runtime·allm); mp; mp=mp->alllink) - if(mp->procid != pid) - runtime·postnote(mp->procid, buf); -} - -int32 -runtime·postnote(int32 pid, int8* msg) -{ - int32 fd; - intgo len; - uint8 buf[128]; - uint8 tmp[16]; - uint8 *p, *q; - - runtime·memclr(buf, sizeof buf); - - /* build path string /proc/pid/note */ - q = tmp; - p = buf; - runtime·itoa(pid, tmp, sizeof tmp); - runtime·memmove((void*)p, (void*)"/proc/", 6); - for(p += 6; *p++ = *q++; ); - p--; - runtime·memmove((void*)p, (void*)"/note", 5); - - fd = runtime·open((int8*)buf, OWRITE, 0); - if(fd < 0) - return -1; - - len = runtime·findnull((byte*)msg); - if(runtime·write(fd, msg, len) != len) { - runtime·close(fd); - return -1; - } - runtime·close(fd); - return 0; -} - -static void exit(void); - -#pragma textflag NOSPLIT -void -runtime·exit(int32 e) -{ - void (*fn)(void); - - g->m->scalararg[0] = e; - fn = exit; - runtime·onM(&fn); -} - -static void -exit(void) -{ - int32 e; - byte tmp[16]; - int8 *status; - - e = g->m->scalararg[0]; - g->m->scalararg[0] = 0; - - if(e == 0) - status = ""; - else { - /* build error string */ - runtime·itoa(e, tmp, sizeof tmp); - status = (int8*)tmp; - } - - runtime·goexitsall(status); - runtime·exits(status); -} - -void -runtime·newosproc(M *mp, void *stk) -{ - int32 pid; - - if(0) - runtime·printf("newosproc mp=%p ostk=%p\n", mp, &mp); - - USED(stk); - if((pid = runtime·rfork(RFPROC|RFMEM|RFNOWAIT)) < 0) - runtime·throw("newosproc: rfork failed\n"); - if(pid == 0) - runtime·tstart_plan9(mp); -} - -#pragma textflag NOSPLIT -uintptr -runtime·semacreate(void) -{ - return 1; -} - -#pragma textflag NOSPLIT -int32 -runtime·semasleep(int64 ns) -{ - int32 ret; - int32 ms; - - if(ns >= 0) { - ms = runtime·timediv(ns, 1000000, nil); - if(ms == 0) - ms = 1; - ret = runtime·plan9_tsemacquire(&g->m->waitsemacount, ms); - if(ret == 1) - return 0; // success - return -1; // timeout or interrupted - } - - while(runtime·plan9_semacquire(&g->m->waitsemacount, 1) < 0) { - /* interrupted; try again (c.f. lock_sema.c) */ - } - return 0; // success -} - -#pragma textflag NOSPLIT -void -runtime·semawakeup(M *mp) -{ - runtime·plan9_semrelease(&mp->waitsemacount, 1); -} - -#pragma textflag NOSPLIT -int32 -runtime·read(int32 fd, void *buf, int32 nbytes) -{ - return runtime·pread(fd, buf, nbytes, -1LL); -} - -#pragma textflag NOSPLIT -int32 -runtime·write(uintptr fd, void *buf, int32 nbytes) -{ - return runtime·pwrite((int32)fd, buf, nbytes, -1LL); -} - -uintptr -runtime·memlimit(void) -{ - return 0; -} - -#pragma dataflag NOPTR -static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n"; - -// This runs on a foreign stack, without an m or a g. No stack split. -#pragma textflag NOSPLIT -void -runtime·badsignal2(void) -{ - runtime·pwrite(2, badsignal, sizeof badsignal - 1, -1LL); - runtime·exits(badsignal); -} diff --git a/src/runtime/os_plan9.go b/src/runtime/os_plan9.go index 20e47bf42e..2dcdfc009a 100644 --- a/src/runtime/os_plan9.go +++ b/src/runtime/os_plan9.go @@ -6,22 +6,49 @@ package runtime import "unsafe" +//go:noescape func pread(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32 + +//go:noescape func pwrite(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32 + func seek(fd int32, offset int64, whence int32) int64 + +//go:noescape func exits(msg *byte) + +//go:noescape func brk_(addr unsafe.Pointer) uintptr + func sleep(ms int32) int32 + func rfork(flags int32) int32 + +//go:noescape func plan9_semacquire(addr *uint32, block int32) int32 + +//go:noescape func plan9_tsemacquire(addr *uint32, ms int32) int32 + +//go:noescape func plan9_semrelease(addr *uint32, count int32) int32 + +//go:noescape func notify(fn unsafe.Pointer) int32 + func noted(mode int32) int32 + +//go:noescape func nsec(*int64) int64 + +//go:noescape func sigtramp(ureg, msg unsafe.Pointer) + func setfpmasks() + +//go:noescape func tstart_plan9(newm *m) + func errstr() string type _Plink uintptr diff --git a/src/runtime/os_plan9.h b/src/runtime/os_plan9.h deleted file mode 100644 index 6d18024834..0000000000 --- a/src/runtime/os_plan9.h +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2010 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. - -// Plan 9-specific system calls -int32 runtime·pread(int32 fd, void *buf, int32 nbytes, int64 offset); -int32 runtime·pwrite(int32 fd, void *buf, int32 nbytes, int64 offset); -int64 runtime·seek(int32 fd, int64 offset, int32 whence); -void runtime·exits(int8* msg); -intptr runtime·brk_(void*); -int32 runtime·sleep(int32 ms); -int32 runtime·rfork(int32 flags); -int32 runtime·plan9_semacquire(uint32 *addr, int32 block); -int32 runtime·plan9_tsemacquire(uint32 *addr, int32 ms); -int32 runtime·plan9_semrelease(uint32 *addr, int32 count); -int32 runtime·notify(void (*fn)(void*, int8*)); -int32 runtime·noted(int32); -int64 runtime·nsec(int64*); -void runtime·sigtramp(void*, int8*); -void runtime·sigpanic(void); -void runtime·goexitsall(int8*); -void runtime·setfpmasks(void); -void runtime·tstart_plan9(M *newm); - -/* open */ -enum -{ - OREAD = 0, - OWRITE = 1, - ORDWR = 2, - OEXEC = 3, - OTRUNC = 16, - OCEXEC = 32, - ORCLOSE = 64, - OEXCL = 0x1000 -}; - -/* rfork */ -enum -{ - RFNAMEG = (1<<0), - RFENVG = (1<<1), - RFFDG = (1<<2), - RFNOTEG = (1<<3), - RFPROC = (1<<4), - RFMEM = (1<<5), - RFNOWAIT = (1<<6), - RFCNAMEG = (1<<10), - RFCENVG = (1<<11), - RFCFDG = (1<<12), - RFREND = (1<<13), - RFNOMNT = (1<<14) -}; - -/* notify */ -enum -{ - NCONT = 0, - NDFLT = 1 -}; - -typedef struct Tos Tos; -typedef intptr _Plink; - -struct Tos { - struct TosProf /* Per process profiling */ - { - _Plink *pp; /* known to be 0(ptr) */ - _Plink *next; /* known to be 4(ptr) */ - _Plink *last; - _Plink *first; - uint32 pid; - uint32 what; - } prof; - uint64 cyclefreq; /* cycle clock frequency if there is one, 0 otherwise */ - int64 kcycles; /* cycles spent in kernel */ - int64 pcycles; /* cycles spent in process (kernel + user) */ - uint32 pid; /* might as well put the pid here */ - uint32 clock; - /* top of stack is here */ -}; - -enum { - NSIG = 14, /* number of signals in runtime·SigTab array */ - ERRMAX = 128, /* max length of note string */ - - /* Notes in runtime·sigtab that are handled by runtime·sigpanic. */ - SIGRFAULT = 2, - SIGWFAULT = 3, - SIGINTDIV = 4, - SIGFLOAT = 5, - SIGTRAP = 6, -}; diff --git a/src/runtime/os_plan9_386.c b/src/runtime/os_plan9_386.c deleted file mode 100644 index 42c6d161c7..0000000000 --- a/src/runtime/os_plan9_386.c +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright 2010 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. - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "signals_GOOS.h" - -void -runtime·dumpregs(Ureg *u) -{ - runtime·printf("ax %x\n", u->ax); - runtime·printf("bx %x\n", u->bx); - runtime·printf("cx %x\n", u->cx); - runtime·printf("dx %x\n", u->dx); - runtime·printf("di %x\n", u->di); - runtime·printf("si %x\n", u->si); - runtime·printf("bp %x\n", u->bp); - runtime·printf("sp %x\n", u->sp); - runtime·printf("pc %x\n", u->pc); - runtime·printf("flags %x\n", u->flags); - runtime·printf("cs %x\n", u->cs); - runtime·printf("fs %x\n", u->fs); - runtime·printf("gs %x\n", u->gs); -} - -int32 -runtime·sighandler(void *v, int8 *note, G *gp) -{ - uintptr *sp; - SigTab *t; - bool crash; - Ureg *ureg; - intgo len, n; - int32 sig, flags; - - ureg = (Ureg*)v; - - // The kernel will never pass us a nil note or ureg so we probably - // made a mistake somewhere in runtime·sigtramp. - if(ureg == nil || note == nil) { - runtime·printf("sighandler: ureg %p note %p\n", ureg, note); - goto Throw; - } - - // Check that the note is no more than ERRMAX bytes (including - // the trailing NUL). We should never receive a longer note. - len = runtime·findnull((byte*)note); - if(len > ERRMAX-1) { - runtime·printf("sighandler: note is longer than ERRMAX\n"); - goto Throw; - } - - // See if the note matches one of the patterns in runtime·sigtab. - // Notes that do not match any pattern can be handled at a higher - // level by the program but will otherwise be ignored. - flags = SigNotify; - for(sig = 0; sig < nelem(runtime·sigtab); sig++) { - t = &runtime·sigtab[sig]; - n = runtime·findnull((byte*)t->name); - if(len < n) - continue; - if(runtime·strncmp((byte*)note, (byte*)t->name, n) == 0) { - flags = t->flags; - break; - } - } - - if(flags & SigGoExit) - runtime·exits(note+9); // Strip "go: exit " prefix. - - if(flags & SigPanic) { - // Copy the error string from sigtramp's stack into m->notesig so - // we can reliably access it from the panic routines. - runtime·memmove(g->m->notesig, note, len+1); - - gp->sig = sig; - gp->sigpc = ureg->pc; - - // Only push runtime·sigpanic if PC != 0. - // - // If PC == 0, probably panicked because of a call to a nil func. - // Not pushing that onto SP will make the trace look like a call - // to runtime·sigpanic instead. (Otherwise the trace will end at - // runtime·sigpanic and we won't get to see who faulted). - if(ureg->pc != 0) { - sp = (uintptr*)ureg->sp; - *--sp = ureg->pc; - ureg->sp = (uint32)sp; - } - ureg->pc = (uintptr)runtime·sigpanic; - return NCONT; - } - - if(flags & SigNotify) { - // TODO(ality): See if os/signal wants it. - //if(runtime·sigsend(...)) - // return NCONT; - } - if(flags & SigKill) - goto Exit; - if(!(flags & SigThrow)) - return NCONT; - -Throw: - g->m->throwing = 1; - g->m->caughtsig = gp; - runtime·startpanic(); - - runtime·printf("%s\n", note); - runtime·printf("PC=%x\n", ureg->pc); - runtime·printf("\n"); - - if(runtime·gotraceback(&crash)) { - runtime·goroutineheader(gp); - runtime·tracebacktrap(ureg->pc, ureg->sp, 0, gp); - runtime·tracebackothers(gp); - runtime·printf("\n"); - runtime·dumpregs(ureg); - } - - if(crash) - runtime·crash(); - -Exit: - runtime·goexitsall(note); - runtime·exits(note); - return NDFLT; // not reached -} - -void -runtime·sigenable(uint32 sig) -{ - USED(sig); -} - -void -runtime·sigdisable(uint32 sig) -{ - USED(sig); -} - -void -runtime·resetcpuprofiler(int32 hz) -{ - // TODO: Enable profiling interrupts. - - g->m->profilehz = hz; -} diff --git a/src/runtime/os_plan9_386.go b/src/runtime/os_plan9_386.go new file mode 100644 index 0000000000..7dda13931e --- /dev/null +++ b/src/runtime/os_plan9_386.go @@ -0,0 +1,131 @@ +// Copyright 2010 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. + +package runtime + +import "unsafe" + +func dumpregs(u *ureg) { + print("ax ", hex(u.ax), "\n") + print("bx ", hex(u.bx), "\n") + print("cx ", hex(u.cx), "\n") + print("dx ", hex(u.dx), "\n") + print("di ", hex(u.di), "\n") + print("si ", hex(u.si), "\n") + print("bp ", hex(u.bp), "\n") + print("sp ", hex(u.sp), "\n") + print("pc ", hex(u.pc), "\n") + print("flags ", hex(u.flags), "\n") + print("cs ", hex(u.cs), "\n") + print("fs ", hex(u.fs), "\n") + print("gs ", hex(u.gs), "\n") +} + +func sighandler(_ureg *ureg, note *byte, gp *g) int { + _g_ := getg() + var t sigTabT + var docrash bool + var length int + var sig int + var flags int + + // The kernel will never pass us a nil note or ureg so we probably + // made a mistake somewhere in sigtramp. + if _ureg == nil || note == nil { + print("sighandler: ureg ", _ureg, " note ", note, "\n") + goto Throw + } + // Check that the note is no more than ERRMAX bytes (including + // the trailing NUL). We should never receive a longer note. + length = findnull(note) + if length > _ERRMAX-1 { + print("sighandler: note is longer than ERRMAX\n") + goto Throw + } + // See if the note matches one of the patterns in sigtab. + // Notes that do not match any pattern can be handled at a higher + // level by the program but will otherwise be ignored. + flags = _SigNotify + for sig, t = range sigtable { + n := len(t.name) + if length < n { + continue + } + if strncmp(note, &t.name[0], uintptr(n)) == 0 { + flags = t.flags + break + } + } + if flags&_SigGoExit != 0 { + exits((*byte)(add(unsafe.Pointer(note), 9))) // Strip "go: exit " prefix. + } + if flags&_SigPanic != 0 { + // Copy the error string from sigtramp's stack into m->notesig so + // we can reliably access it from the panic routines. + memmove(unsafe.Pointer(_g_.m.notesig), unsafe.Pointer(note), uintptr(length+1)) + gp.sig = uint32(sig) + gp.sigpc = uintptr(_ureg.pc) + // Only push sigpanic if PC != 0. + // + // If PC == 0, probably panicked because of a call to a nil func. + // Not pushing that onto SP will make the trace look like a call + // to sigpanic instead. (Otherwise the trace will end at + // sigpanic and we won't get to see who faulted). + if _ureg.pc != 0 { + sp := _ureg.sp + if regSize > ptrSize { + sp -= ptrSize + *(*uintptr)(unsafe.Pointer(uintptr(sp))) = 0 + } + sp -= ptrSize + *(*uintptr)(unsafe.Pointer(uintptr(sp))) = uintptr(_ureg.pc) + _ureg.sp = sp + } + _ureg.pc = uint32(funcPC(sigpanic)) + return _NCONT + } + if flags&_SigNotify != 0 { + // TODO(ality): See if os/signal wants it. + //if(sigsend(...)) + // return _NCONT; + } + if flags&_SigKill != 0 { + goto Exit + } + if flags&_SigThrow == 0 { + return _NCONT + } +Throw: + _g_.m.throwing = 1 + _g_.m.caughtsig = gp + startpanic() + print(gostringnocopy(note), "\n") + print("PC=", hex(_ureg.pc), "\n") + print("\n") + if gotraceback(&docrash) > 0 { + goroutineheader(gp) + tracebacktrap(uintptr(_ureg.pc), uintptr(_ureg.sp), 0, gp) + tracebackothers(gp) + print("\n") + dumpregs(_ureg) + } + if docrash { + crash() + } +Exit: + goexitsall(note) + exits(note) + return _NDFLT // not reached +} + +func sigenable(sig uint32) { +} + +func sigdisable(sig uint32) { +} + +func resetcpuprofiler(hz int32) { + // TODO: Enable profiling interrupts. + getg().m.profilehz = hz +} diff --git a/src/runtime/os_plan9_amd64.c b/src/runtime/os_plan9_amd64.c deleted file mode 100644 index a9dc0eb966..0000000000 --- a/src/runtime/os_plan9_amd64.c +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright 2010 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. - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "signals_GOOS.h" - -void -runtime·dumpregs(Ureg *u) -{ - runtime·printf("ax %X\n", u->ax); - runtime·printf("bx %X\n", u->bx); - runtime·printf("cx %X\n", u->cx); - runtime·printf("dx %X\n", u->dx); - runtime·printf("di %X\n", u->di); - runtime·printf("si %X\n", u->si); - runtime·printf("bp %X\n", u->bp); - runtime·printf("sp %X\n", u->sp); - runtime·printf("r8 %X\n", u->r8); - runtime·printf("r9 %X\n", u->r9); - runtime·printf("r10 %X\n", u->r10); - runtime·printf("r11 %X\n", u->r11); - runtime·printf("r12 %X\n", u->r12); - runtime·printf("r13 %X\n", u->r13); - runtime·printf("r14 %X\n", u->r14); - runtime·printf("r15 %X\n", u->r15); - runtime·printf("ip %X\n", u->ip); - runtime·printf("flags %X\n", u->flags); - runtime·printf("cs %X\n", (uint64)u->cs); - runtime·printf("fs %X\n", (uint64)u->fs); - runtime·printf("gs %X\n", (uint64)u->gs); -} - -int32 -runtime·sighandler(void *v, int8 *note, G *gp) -{ - uintptr *sp; - SigTab *t; - bool crash; - Ureg *ureg; - intgo len, n; - int32 sig, flags; - - ureg = (Ureg*)v; - - // The kernel will never pass us a nil note or ureg so we probably - // made a mistake somewhere in runtime·sigtramp. - if(ureg == nil || note == nil) { - runtime·printf("sighandler: ureg %p note %p\n", ureg, note); - goto Throw; - } - - // Check that the note is no more than ERRMAX bytes (including - // the trailing NUL). We should never receive a longer note. - len = runtime·findnull((byte*)note); - if(len > ERRMAX-1) { - runtime·printf("sighandler: note is longer than ERRMAX\n"); - goto Throw; - } - - // See if the note matches one of the patterns in runtime·sigtab. - // Notes that do not match any pattern can be handled at a higher - // level by the program but will otherwise be ignored. - flags = SigNotify; - for(sig = 0; sig < nelem(runtime·sigtab); sig++) { - t = &runtime·sigtab[sig]; - n = runtime·findnull((byte*)t->name); - if(len < n) - continue; - if(runtime·strncmp((byte*)note, (byte*)t->name, n) == 0) { - flags = t->flags; - break; - } - } - - if(flags & SigGoExit) - runtime·exits(note+9); // Strip "go: exit " prefix. - - if(flags & SigPanic) { - // Copy the error string from sigtramp's stack into m->notesig so - // we can reliably access it from the panic routines. - runtime·memmove(g->m->notesig, note, len+1); - - gp->sig = sig; - gp->sigpc = ureg->ip; - - // Only push runtime·sigpanic if PC != 0. - // - // If PC == 0, probably panicked because of a call to a nil func. - // Not pushing that onto SP will make the trace look like a call - // to runtime·sigpanic instead. (Otherwise the trace will end at - // runtime·sigpanic and we won't get to see who faulted). - if(ureg->ip != 0) { - sp = (uintptr*)ureg->sp; - *--sp = ureg->ip; - ureg->sp = (uint64)sp; - } - ureg->ip = (uintptr)runtime·sigpanic; - return NCONT; - } - - if(flags & SigNotify) { - // TODO(ality): See if os/signal wants it. - //if(runtime·sigsend(...)) - // return NCONT; - } - if(flags & SigKill) - goto Exit; - if(!(flags & SigThrow)) - return NCONT; - -Throw: - g->m->throwing = 1; - g->m->caughtsig = gp; - runtime·startpanic(); - - runtime·printf("%s\n", note); - runtime·printf("PC=%X\n", ureg->ip); - runtime·printf("\n"); - - if(runtime·gotraceback(&crash)) { - runtime·goroutineheader(gp); - runtime·tracebacktrap(ureg->ip, ureg->sp, 0, gp); - runtime·tracebackothers(gp); - runtime·printf("\n"); - runtime·dumpregs(ureg); - } - - if(crash) - runtime·crash(); - -Exit: - runtime·goexitsall(note); - runtime·exits(note); - return NDFLT; // not reached -} - -void -runtime·sigenable(uint32 sig) -{ - USED(sig); -} - -void -runtime·sigdisable(uint32 sig) -{ - USED(sig); -} - -void -runtime·resetcpuprofiler(int32 hz) -{ - // TODO: Enable profiling interrupts. - - g->m->profilehz = hz; -} diff --git a/src/runtime/os_plan9_amd64.go b/src/runtime/os_plan9_amd64.go new file mode 100644 index 0000000000..8727dcc20f --- /dev/null +++ b/src/runtime/os_plan9_amd64.go @@ -0,0 +1,139 @@ +// Copyright 2010 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. + +package runtime + +import "unsafe" + +func dumpregs(u *ureg) { + print("ax ", hex(u.ax), "\n") + print("bx ", hex(u.bx), "\n") + print("cx ", hex(u.cx), "\n") + print("dx ", hex(u.dx), "\n") + print("di ", hex(u.di), "\n") + print("si ", hex(u.si), "\n") + print("bp ", hex(u.bp), "\n") + print("sp ", hex(u.sp), "\n") + print("r8 ", hex(u.r8), "\n") + print("r9 ", hex(u.r9), "\n") + print("r10 ", hex(u.r10), "\n") + print("r11 ", hex(u.r11), "\n") + print("r12 ", hex(u.r12), "\n") + print("r13 ", hex(u.r13), "\n") + print("r14 ", hex(u.r14), "\n") + print("r15 ", hex(u.r15), "\n") + print("ip ", hex(u.ip), "\n") + print("flags ", hex(u.flags), "\n") + print("cs ", hex(uint64(u.cs)), "\n") + print("fs ", hex(uint64(u.fs)), "\n") + print("gs ", hex(uint64(u.gs)), "\n") +} + +func sighandler(_ureg *ureg, note *byte, gp *g) int { + _g_ := getg() + var t sigTabT + var docrash bool + var length int + var sig int + var flags int + + // The kernel will never pass us a nil note or ureg so we probably + // made a mistake somewhere in sigtramp. + if _ureg == nil || note == nil { + print("sighandler: ureg ", _ureg, " note ", note, "\n") + goto Throw + } + // Check that the note is no more than ERRMAX bytes (including + // the trailing NUL). We should never receive a longer note. + length = findnull(note) + if length > _ERRMAX-1 { + print("sighandler: note is longer than ERRMAX\n") + goto Throw + } + // See if the note matches one of the patterns in sigtab. + // Notes that do not match any pattern can be handled at a higher + // level by the program but will otherwise be ignored. + flags = _SigNotify + for sig, t = range sigtable { + n := len(t.name) + if length < n { + continue + } + if strncmp(note, &t.name[0], uintptr(n)) == 0 { + flags = t.flags + break + } + } + if flags&_SigGoExit != 0 { + exits((*byte)(add(unsafe.Pointer(note), 9))) // Strip "go: exit " prefix. + } + if flags&_SigPanic != 0 { + // Copy the error string from sigtramp's stack into m->notesig so + // we can reliably access it from the panic routines. + memmove(unsafe.Pointer(_g_.m.notesig), unsafe.Pointer(note), uintptr(length+1)) + gp.sig = uint32(sig) + gp.sigpc = uintptr(_ureg.ip) + // Only push sigpanic if PC != 0. + // + // If PC == 0, probably panicked because of a call to a nil func. + // Not pushing that onto SP will make the trace look like a call + // to sigpanic instead. (Otherwise the trace will end at + // sigpanic and we won't get to see who faulted). + if _ureg.ip != 0 { + sp := _ureg.sp + if regSize > ptrSize { + sp -= ptrSize + *(*uintptr)(unsafe.Pointer(uintptr(sp))) = 0 + } + sp -= ptrSize + *(*uintptr)(unsafe.Pointer(uintptr(sp))) = uintptr(_ureg.ip) + _ureg.sp = sp + } + _ureg.ip = uint64(funcPC(sigpanic)) + return _NCONT + } + if flags&_SigNotify != 0 { + // TODO(ality): See if os/signal wants it. + //if(sigsend(...)) + // return _NCONT; + } + if flags&_SigKill != 0 { + goto Exit + } + if flags&_SigThrow == 0 { + return _NCONT + } +Throw: + _g_.m.throwing = 1 + _g_.m.caughtsig = gp + startpanic() + print(gostringnocopy(note), "\n") + print("PC=", hex(_ureg.ip), "\n") + print("\n") + if gotraceback(&docrash) > 0 { + goroutineheader(gp) + tracebacktrap(uintptr(_ureg.ip), uintptr(_ureg.sp), 0, gp) + tracebackothers(gp) + print("\n") + dumpregs(_ureg) + } + if docrash { + crash() + } +Exit: + goexitsall(note) + exits(note) + return _NDFLT // not reached +} + +func sigenable(sig uint32) { +} + +func sigdisable(sig uint32) { +} + +func resetcpuprofiler(hz int32) { + // TODO: Enable profiling interrupts. + getg().m.profilehz = hz +} diff --git a/src/runtime/signals_plan9.h b/src/runtime/signal_plan9.go similarity index 54% rename from src/runtime/signals_plan9.h rename to src/runtime/signal_plan9.go index 4ee8e542c9..37d24359bf 100644 --- a/src/runtime/signals_plan9.h +++ b/src/runtime/signal_plan9.go @@ -2,62 +2,53 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include "textflag.h" +package runtime -#define N SigNotify -#define K SigKill -#define T SigThrow -#define P SigPanic -#define E SigGoExit +type sigTabT struct { + flags int + name []byte +} // Incoming notes are compared against this table using strncmp, so the // order matters: longer patterns must appear before their prefixes. -// There are #defined SIG constants in os_plan9.h for the table index of -// some of these. +// There are _SIG constants in os2_plan9.go for the table index of some +// of these. // // If you add entries to this table, you must respect the prefix ordering -// and also update the constant values is os_plan9.h. - -#pragma dataflag NOPTR -SigTab runtime·sigtab[] = { +// and also update the constant values is os2_plan9.go. +var sigtable = [...]sigTabT{ // Traps that we cannot be recovered. - T, "sys: trap: debug exception", - T, "sys: trap: invalid opcode", + {_SigThrow, []byte("sys: trap: debug exception")}, + {_SigThrow, []byte("sys: trap: invalid opcode")}, // We can recover from some memory errors in runtime·sigpanic. - P, "sys: trap: fault read addr", // SIGRFAULT - P, "sys: trap: fault write addr", // SIGWFAULT + {_SigPanic, []byte("sys: trap: fault read addr")}, // SIGRFAULT + {_SigPanic, []byte("sys: trap: fault write addr")}, // SIGWFAULT // We can also recover from math errors. - P, "sys: trap: divide error", // SIGINTDIV - P, "sys: fp:", // SIGFLOAT + {_SigPanic, []byte("sys: trap: divide error")}, // SIGINTDIV + {_SigPanic, []byte("sys: fp:")}, // SIGFLOAT // All other traps are normally handled as if they were marked SigThrow. // We mark them SigPanic here so that debug.SetPanicOnFault will work. - P, "sys: trap:", // SIGTRAP + {_SigPanic, []byte("sys: trap:")}, // SIGTRAP // Writes to a closed pipe can be handled if desired, otherwise they're ignored. - N, "sys: write on closed pipe", + {_SigNotify, []byte("sys: write on closed pipe")}, // Other system notes are more serious and cannot be recovered. - T, "sys:", + {_SigThrow, []byte("sys:")}, // Issued to all other procs when calling runtime·exit. - E, "go: exit ", + {_SigGoExit, []byte("go: exit ")}, // Kill is sent by external programs to cause an exit. - K, "kill", + {_SigKill, []byte("kill")}, // Interrupts can be handled if desired, otherwise they cause an exit. - N+K, "interrupt", - N+K, "hangup", + {_SigNotify + _SigKill, []byte("interrupt")}, + {_SigNotify + _SigKill, []byte("hangup")}, // Alarms can be handled if desired, otherwise they're ignored. - N, "alarm", -}; - -#undef N -#undef K -#undef T -#undef P -#undef E + {_SigNotify, []byte("alarm")}, +} diff --git a/src/runtime/stubs2.go b/src/runtime/stubs2.go index 74cc5c6a7c..60751dd343 100644 --- a/src/runtime/stubs2.go +++ b/src/runtime/stubs2.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build !plan9 // +build !solaris // +build !windows // +build !nacl diff --git a/src/runtime/stubs3.go b/src/runtime/stubs3.go new file mode 100644 index 0000000000..ffaa28775d --- /dev/null +++ b/src/runtime/stubs3.go @@ -0,0 +1,12 @@ +// Copyright 2014 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. + +// +build plan9 + +package runtime + +func close(fd int32) int32 + +//go:noescape +func open(name *byte, mode, perm int32) int32 From 213a6645cee2e7050eabb28042aa733f9c8452c8 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Fri, 21 Nov 2014 20:44:04 +0100 Subject: [PATCH 59/68] [dev.cc] cmd/8g: fix warning on Plan 9 warning: /usr/go/src/cmd/8g/reg.c:365 format mismatch d VLONG, arg 5 LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/177160043 --- src/cmd/8g/reg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c index 13beaf9414..d7394a16d2 100644 --- a/src/cmd/8g/reg.c +++ b/src/cmd/8g/reg.c @@ -362,7 +362,7 @@ brk: print("\nregisterizing\n"); for(i=0; icost, rgp->varno, rgp->enter->f.prog->pc); + print("region %d: cost %d varno %d enter %lld\n", i, rgp->cost, rgp->varno, rgp->enter->f.prog->pc); bit = blsh(rgp->varno); vreg = paint2(rgp->enter, rgp->varno, 0); vreg = allreg(vreg, rgp); From 2f28916f02b3e75ffdf253c8f672fffed0f63753 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Fri, 21 Nov 2014 20:56:33 +0100 Subject: [PATCH 60/68] [dev.cc] liblink: fix warnings on Plan 9 warning: src/liblink/list6.c:94 set and not used: s warning: src/liblink/list6.c:157 format mismatch ld VLONG, arg 3 warning: src/liblink/list6.c:157 format mismatch E UINT, arg 4 warning: src/liblink/list6.c:157 format mismatch d VLONG, arg 5 warning: src/liblink/list6.c:163 set and not used: s warning: src/liblink/list9.c:105 set and not used: s warning: src/liblink/list9.c:185 format mismatch ld VLONG, arg 3 warning: src/liblink/list9.c:185 format mismatch E UINT, arg 4 warning: src/liblink/list9.c:185 format mismatch d VLONG, arg 5 warning: src/liblink/list9.c:193 set and not used: s LGTM=rsc R=rsc CC=austin, golang-codereviews, minux https://golang.org/cl/176130043 --- include/link.h | 1 + src/liblink/list6.c | 6 +++--- src/liblink/list9.c | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/include/link.h b/include/link.h index 225c6f95df..33a66e93cb 100644 --- a/include/link.h +++ b/include/link.h @@ -639,6 +639,7 @@ extern LinkArch linkpower64; extern LinkArch linkpower64le; #pragma varargck type "A" int +#pragma varargck type "E" uint #pragma varargck type "D" Addr* #pragma varargck type "lD" Addr* #pragma varargck type "P" Prog* diff --git a/src/liblink/list6.c b/src/liblink/list6.c index 54cce4aa4b..ff22273c4a 100644 --- a/src/liblink/list6.c +++ b/src/liblink/list6.c @@ -91,7 +91,7 @@ Pconv(Fmt *fp) if(p->reg) s += sprint(s, " reg=%d", p->reg); if(p->to.type != D_NONE) - s += sprint(s, " to={%#D}", &p->to); + sprint(s, " to={%#D}", &p->to); return fmtstrcpy(fp, str); } @@ -154,13 +154,13 @@ Dconv(Fmt *fp) s += sprint(s, "%s ", dnames6[i]); else s += sprint(s, "%d ", i); - s += sprint(s, "offset=%ld etype=%E width=%d", a->offset, a->etype, a->width); + s += sprint(s, "offset=%lld etype=%E width=%lld", a->offset, a->etype, a->width); if(a->class != 0) s += sprint(s, " class=%s", cnames9[(int)a->class]); if(a->sym != nil) s += sprint(s, " sym=%s", a->sym->name); if(a->type == D_BRANCH && a->u.branch != nil) - s += sprint(s, " branch=%.5lld", a->u.branch->pc); + sprint(s, " branch=%.5lld", a->u.branch->pc); goto brk; } diff --git a/src/liblink/list9.c b/src/liblink/list9.c index 0a158cd61e..32fcf8f87b 100644 --- a/src/liblink/list9.c +++ b/src/liblink/list9.c @@ -102,7 +102,7 @@ Pconv(Fmt *fp) if(p->from3.type != D_NONE) s += sprint(s, " from3={%#D}", &p->from3); if(p->to.type != D_NONE) - s += sprint(s, " to={%#D}", &p->to); + sprint(s, " to={%#D}", &p->to); return fmtstrcpy(fp, str); } @@ -182,7 +182,7 @@ Dconv(Fmt *fp) s += sprint(s, "name=%s ", dnames9[(int)a->name]); else s += sprint(s, "name=%d ", a->name); - s += sprint(s, "offset=%ld etype=%E width=%d", a->offset, a->etype, a->width); + s += sprint(s, "offset=%lld etype=%E width=%lld", a->offset, a->etype, a->width); if(a->class != 0) s += sprint(s, " class=%s", cnames9[(int)a->class]); if(a->reg != NREG) @@ -190,7 +190,7 @@ Dconv(Fmt *fp) if(a->sym != nil) s += sprint(s, " sym=%s", a->sym->name); if(a->type == D_BRANCH && a->u.branch != nil) - s += sprint(s, " branch=%.5lld", a->u.branch->pc); + sprint(s, " branch=%.5lld", a->u.branch->pc); goto ret; } From ee853dacf5143ac4cb3550ee35016e3889081d80 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 21 Nov 2014 15:58:01 -0500 Subject: [PATCH 61/68] [dev.cc] 9g: correct bad proginfo for ADUFFZERO and ADUFFCOPY LGTM=rsc R=rsc, dave CC=golang-codereviews https://golang.org/cl/176130044 --- src/cmd/9g/prog.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/cmd/9g/prog.c b/src/cmd/9g/prog.c index e3e50f28a9..51c132d183 100644 --- a/src/cmd/9g/prog.c +++ b/src/cmd/9g/prog.c @@ -134,11 +134,12 @@ proginfo(ProgInfo *info, Prog *p) } if(p->as == ADUFFZERO) { - info->reguse |= RtoB(0) | RtoB(2); - info->regset |= RtoB(2); + info->reguse |= (1<regset |= RtoB(3); } if(p->as == ADUFFCOPY) { - info->reguse |= RtoB(0) | RtoB(2) | RtoB(3); - info->regset |= RtoB(2) | RtoB(3); + // TODO(austin) Revisit when duffcopy is implemented + info->reguse |= RtoB(3) | RtoB(4) | RtoB(5); + info->regset |= RtoB(3) | RtoB(4); } } From cabc55532624706eb6ee0b92347e7461e146e244 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 21 Nov 2014 15:58:29 -0500 Subject: [PATCH 62/68] [dev.cc] liblink: more docs on Prog and Addr fields LGTM=rsc R=rsc, dave CC=golang-codereviews https://golang.org/cl/174530043 --- include/link.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/link.h b/include/link.h index 33a66e93cb..2b1d02102b 100644 --- a/include/link.h +++ b/include/link.h @@ -62,7 +62,7 @@ struct Addr short type; uint8 index; int8 scale; - int8 reg; // for 5l, 9l + int8 reg; // for 5l, 9l; GPRs and FPRs both start at 0 int8 name; // for 5l, 9l int8 class; // for 5l, 9l uint8 etype; // for 5g, 6g, 8g @@ -94,6 +94,7 @@ struct Prog // operands Addr from; uchar reg; // arm, power64 only (e.g., ADD from, reg, to); + // starts at 0 for both GPRs and FPRs; // also used for ADATA width on arm, power64 Addr from3; // power64 only (e.g., RLWM/FMADD from, reg, from3, to) Addr to; From adbca13cb36489651ac5b989b6361d81c358d91e Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Fri, 21 Nov 2014 18:13:59 -0500 Subject: [PATCH 63/68] [dev.cc] runtime: explicitly exclude android in zgoos_linux.go Otherwise both zgoos_linux.go and zgoos_android.go will be compiled for GOOS=android. LGTM=crawshaw, rsc R=rsc, crawshaw CC=golang-codereviews https://golang.org/cl/178110043 --- src/runtime/gengoos.go | 4 +++- src/runtime/zgoos_android.go | 2 -- src/runtime/zgoos_darwin.go | 2 -- src/runtime/zgoos_dragonfly.go | 2 -- src/runtime/zgoos_freebsd.go | 2 -- src/runtime/zgoos_linux.go | 2 +- src/runtime/zgoos_nacl.go | 2 -- src/runtime/zgoos_netbsd.go | 2 -- src/runtime/zgoos_openbsd.go | 2 -- src/runtime/zgoos_plan9.go | 2 -- src/runtime/zgoos_solaris.go | 2 -- src/runtime/zgoos_windows.go | 2 -- 12 files changed, 4 insertions(+), 22 deletions(-) diff --git a/src/runtime/gengoos.go b/src/runtime/gengoos.go index 029575bee2..06621c8dba 100644 --- a/src/runtime/gengoos.go +++ b/src/runtime/gengoos.go @@ -46,7 +46,9 @@ func main() { for _, target := range gooses { var buf bytes.Buffer fmt.Fprintf(&buf, "// generated by gengoos.go using 'go generate'\n\n") - fmt.Fprintf(&buf, "// +build %s\n\n", target) // usually redundant, but not always; see linux vs android + if target == "linux" { + fmt.Fprintf(&buf, "// +build !android\n\n") // must explicitly exclude android for linux + } fmt.Fprintf(&buf, "package runtime\n\n") fmt.Fprintf(&buf, "const theGoos = `%s`\n\n", target) for _, goos := range gooses { diff --git a/src/runtime/zgoos_android.go b/src/runtime/zgoos_android.go index abfba808ba..0590bd9ab7 100644 --- a/src/runtime/zgoos_android.go +++ b/src/runtime/zgoos_android.go @@ -1,7 +1,5 @@ // generated by gengoos.go using 'go generate' -// +build android - package runtime const theGoos = `android` diff --git a/src/runtime/zgoos_darwin.go b/src/runtime/zgoos_darwin.go index eb39b53dd4..c0a7cd6e74 100644 --- a/src/runtime/zgoos_darwin.go +++ b/src/runtime/zgoos_darwin.go @@ -1,7 +1,5 @@ // generated by gengoos.go using 'go generate' -// +build darwin - package runtime const theGoos = `darwin` diff --git a/src/runtime/zgoos_dragonfly.go b/src/runtime/zgoos_dragonfly.go index f6e839d3d8..008d6de811 100644 --- a/src/runtime/zgoos_dragonfly.go +++ b/src/runtime/zgoos_dragonfly.go @@ -1,7 +1,5 @@ // generated by gengoos.go using 'go generate' -// +build dragonfly - package runtime const theGoos = `dragonfly` diff --git a/src/runtime/zgoos_freebsd.go b/src/runtime/zgoos_freebsd.go index 3c47aef2ab..2478940353 100644 --- a/src/runtime/zgoos_freebsd.go +++ b/src/runtime/zgoos_freebsd.go @@ -1,7 +1,5 @@ // generated by gengoos.go using 'go generate' -// +build freebsd - package runtime const theGoos = `freebsd` diff --git a/src/runtime/zgoos_linux.go b/src/runtime/zgoos_linux.go index 5d899e3db6..c775ab538d 100644 --- a/src/runtime/zgoos_linux.go +++ b/src/runtime/zgoos_linux.go @@ -1,6 +1,6 @@ // generated by gengoos.go using 'go generate' -// +build linux +// +build !android package runtime diff --git a/src/runtime/zgoos_nacl.go b/src/runtime/zgoos_nacl.go index b5c4281fb5..d9d88f4508 100644 --- a/src/runtime/zgoos_nacl.go +++ b/src/runtime/zgoos_nacl.go @@ -1,7 +1,5 @@ // generated by gengoos.go using 'go generate' -// +build nacl - package runtime const theGoos = `nacl` diff --git a/src/runtime/zgoos_netbsd.go b/src/runtime/zgoos_netbsd.go index b2e45222ae..ff2c5cb8f4 100644 --- a/src/runtime/zgoos_netbsd.go +++ b/src/runtime/zgoos_netbsd.go @@ -1,7 +1,5 @@ // generated by gengoos.go using 'go generate' -// +build netbsd - package runtime const theGoos = `netbsd` diff --git a/src/runtime/zgoos_openbsd.go b/src/runtime/zgoos_openbsd.go index 331c96dd66..b071dc63ab 100644 --- a/src/runtime/zgoos_openbsd.go +++ b/src/runtime/zgoos_openbsd.go @@ -1,7 +1,5 @@ // generated by gengoos.go using 'go generate' -// +build openbsd - package runtime const theGoos = `openbsd` diff --git a/src/runtime/zgoos_plan9.go b/src/runtime/zgoos_plan9.go index f29eb45230..4306b0f1ef 100644 --- a/src/runtime/zgoos_plan9.go +++ b/src/runtime/zgoos_plan9.go @@ -1,7 +1,5 @@ // generated by gengoos.go using 'go generate' -// +build plan9 - package runtime const theGoos = `plan9` diff --git a/src/runtime/zgoos_solaris.go b/src/runtime/zgoos_solaris.go index ac613db33c..10f9537d05 100644 --- a/src/runtime/zgoos_solaris.go +++ b/src/runtime/zgoos_solaris.go @@ -1,7 +1,5 @@ // generated by gengoos.go using 'go generate' -// +build solaris - package runtime const theGoos = `solaris` diff --git a/src/runtime/zgoos_windows.go b/src/runtime/zgoos_windows.go index 43710d862f..56f5c58ce6 100644 --- a/src/runtime/zgoos_windows.go +++ b/src/runtime/zgoos_windows.go @@ -1,7 +1,5 @@ // generated by gengoos.go using 'go generate' -// +build windows - package runtime const theGoos = `windows` From d3526ea0f6ff6775794ebce22192f48eec20aca0 Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Fri, 21 Nov 2014 18:15:30 -0500 Subject: [PATCH 64/68] [dev.cc] runtime: migrate Android/ARM port to Go. I tested building Go itself, but not any of go.mobile tests. LGTM=crawshaw R=crawshaw, rsc CC=golang-codereviews https://golang.org/cl/179110043 --- src/runtime/os_android.h | 1 - src/runtime/{os_android.c => os_android_arm.go} | 11 +++++------ src/runtime/signal_android_386.h | 1 - src/runtime/signal_android_arm.h | 1 - src/runtime/signals_android.h | 1 - 5 files changed, 5 insertions(+), 10 deletions(-) delete mode 100644 src/runtime/os_android.h rename src/runtime/{os_android.c => os_android_arm.go} (64%) delete mode 100644 src/runtime/signal_android_386.h delete mode 100644 src/runtime/signal_android_arm.h delete mode 100644 src/runtime/signals_android.h diff --git a/src/runtime/os_android.h b/src/runtime/os_android.h deleted file mode 100644 index c7c1098e8d..0000000000 --- a/src/runtime/os_android.h +++ /dev/null @@ -1 +0,0 @@ -#include "os_linux.h" diff --git a/src/runtime/os_android.c b/src/runtime/os_android_arm.go similarity index 64% rename from src/runtime/os_android.c rename to src/runtime/os_android_arm.go index 5805f68713..132832236a 100644 --- a/src/runtime/os_android.c +++ b/src/runtime/os_android_arm.go @@ -2,15 +2,14 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" +package runtime + +import _ "unsafe" // Export the runtime entry point symbol. // // Used by the app package to start the Go runtime after loading // a shared library via JNI. See golang.org/x/mobile/app. -void _rt0_arm_linux1(); -#pragma cgo_export_static _rt0_arm_linux1 -#pragma cgo_export_dynamic _rt0_arm_linux1 +//go:cgo_export_static _rt0_arm_linux1 +//go:cgo_export_dynamic _rt0_arm_linux1 diff --git a/src/runtime/signal_android_386.h b/src/runtime/signal_android_386.h deleted file mode 100644 index 2a1bb4b3e4..0000000000 --- a/src/runtime/signal_android_386.h +++ /dev/null @@ -1 +0,0 @@ -#include "signal_linux_386.h" diff --git a/src/runtime/signal_android_arm.h b/src/runtime/signal_android_arm.h deleted file mode 100644 index 8a05e21e59..0000000000 --- a/src/runtime/signal_android_arm.h +++ /dev/null @@ -1 +0,0 @@ -#include "signal_linux_arm.h" diff --git a/src/runtime/signals_android.h b/src/runtime/signals_android.h deleted file mode 100644 index 5140d8a184..0000000000 --- a/src/runtime/signals_android.h +++ /dev/null @@ -1 +0,0 @@ -#include "signals_linux.h" From cfc8099a9a71bbcdd8b3259be2f50578872c9626 Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Sat, 22 Nov 2014 16:05:31 +1100 Subject: [PATCH 65/68] [dev.cc] runtime: convert netbsd/amd64 port to Go LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/169620043 --- src/runtime/defs1_netbsd_amd64.go | 20 +- src/runtime/os1_netbsd.go | 265 +++++++++++++++++++++ src/runtime/os1_netbsd_amd64.go | 16 ++ src/runtime/os2_netbsd.go | 18 ++ src/runtime/os_netbsd.c | 368 ----------------------------- src/runtime/os_netbsd.go | 32 ++- src/runtime/os_netbsd.h | 31 --- src/runtime/os_netbsd_amd64.c | 18 -- src/runtime/signal_netbsd.go | 46 ++++ src/runtime/signal_netbsd_amd64.go | 48 ++++ src/runtime/signal_netbsd_amd64.h | 31 --- src/runtime/signals_netbsd.h | 54 ----- 12 files changed, 436 insertions(+), 511 deletions(-) create mode 100644 src/runtime/os1_netbsd.go create mode 100644 src/runtime/os1_netbsd_amd64.go create mode 100644 src/runtime/os2_netbsd.go delete mode 100644 src/runtime/os_netbsd.c delete mode 100644 src/runtime/os_netbsd.h delete mode 100644 src/runtime/os_netbsd_amd64.c create mode 100644 src/runtime/signal_netbsd.go create mode 100644 src/runtime/signal_netbsd_amd64.go delete mode 100644 src/runtime/signal_netbsd_amd64.h delete mode 100644 src/runtime/signals_netbsd.h diff --git a/src/runtime/defs1_netbsd_amd64.go b/src/runtime/defs1_netbsd_amd64.go index cca701e5bc..c2bde4dabe 100644 --- a/src/runtime/defs1_netbsd_amd64.go +++ b/src/runtime/defs1_netbsd_amd64.go @@ -84,8 +84,8 @@ const ( ) type sigaltstackt struct { - ss_sp *byte - ss_size uint64 + ss_sp uintptr + ss_size uintptr ss_flags int32 pad_cgo_0 [4]byte } @@ -103,8 +103,8 @@ type siginfo struct { } type stackt struct { - ss_sp *byte - ss_size uint64 + ss_sp uintptr + ss_size uintptr ss_flags int32 pad_cgo_0 [4]byte } @@ -114,12 +114,24 @@ type timespec struct { tv_nsec int64 } +func (ts *timespec) set_sec(x int32) { + ts.tv_sec = int64(x) +} + +func (ts *timespec) set_nsec(x int32) { + ts.tv_nsec = int64(x) +} + type timeval struct { tv_sec int64 tv_usec int32 pad_cgo_0 [4]byte } +func (tv *timeval) set_usec(x int32) { + tv.tv_usec = x +} + type itimerval struct { it_interval timeval it_value timeval diff --git a/src/runtime/os1_netbsd.go b/src/runtime/os1_netbsd.go new file mode 100644 index 0000000000..493be30fa5 --- /dev/null +++ b/src/runtime/os1_netbsd.go @@ -0,0 +1,265 @@ +// Copyright 2011 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. + +package runtime + +import "unsafe" + +const ( + _ESRCH = 3 + _ENOTSUP = 91 + + // From NetBSD's + _CLOCK_REALTIME = 0 + _CLOCK_VIRTUAL = 1 + _CLOCK_PROF = 2 + _CLOCK_MONOTONIC = 3 +) + +var sigset_none = sigset{} +var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}} + +// From NetBSD's +const ( + _CTL_HW = 6 + _HW_NCPU = 3 +) + +func getncpu() int32 { + mib := [2]uint32{_CTL_HW, _HW_NCPU} + out := uint32(0) + nout := unsafe.Sizeof(out) + ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) + if ret >= 0 { + return int32(out) + } + return 1 +} + +//go:nosplit +func semacreate() uintptr { + return 1 +} + +//go:nosplit +func semasleep(ns int64) int32 { + _g_ := getg() + + // spin-mutex lock + for { + if xchg(&_g_.m.waitsemalock, 1) == 0 { + break + } + osyield() + } + + for { + // lock held + if _g_.m.waitsemacount == 0 { + // sleep until semaphore != 0 or timeout. + // thrsleep unlocks m.waitsemalock. + if ns < 0 { + // TODO(jsing) - potential deadlock! + // + // There is a potential deadlock here since we + // have to release the waitsemalock mutex + // before we call lwp_park() to suspend the + // thread. This allows another thread to + // release the lock and call lwp_unpark() + // before the thread is actually suspended. + // If this occurs the current thread will end + // up sleeping indefinitely. Unfortunately + // the NetBSD kernel does not appear to provide + // a mechanism for unlocking the userspace + // mutex once the thread is actually parked. + atomicstore(&_g_.m.waitsemalock, 0) + lwp_park(nil, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil) + } else { + var ts timespec + var nsec int32 + ns += nanotime() + ts.set_sec(timediv(ns, 1000000000, &nsec)) + ts.set_nsec(nsec) + // TODO(jsing) - potential deadlock! + // See above for details. + atomicstore(&_g_.m.waitsemalock, 0) + lwp_park(&ts, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil) + } + // reacquire lock + for { + if xchg(&_g_.m.waitsemalock, 1) == 0 { + break + } + osyield() + } + } + + // lock held (again) + if _g_.m.waitsemacount != 0 { + // semaphore is available. + _g_.m.waitsemacount-- + // spin-mutex unlock + atomicstore(&_g_.m.waitsemalock, 0) + return 0 + } + + // semaphore not available. + // if there is a timeout, stop now. + // otherwise keep trying. + if ns >= 0 { + break + } + } + + // lock held but giving up + // spin-mutex unlock + atomicstore(&_g_.m.waitsemalock, 0) + return -1 +} + +//go:nosplit +func semawakeup(mp *m) { + // spin-mutex lock + for { + if xchg(&mp.waitsemalock, 1) == 0 { + break + } + osyield() + } + + mp.waitsemacount++ + // TODO(jsing) - potential deadlock, see semasleep() for details. + // Confirm that LWP is parked before unparking... + ret := lwp_unpark(int32(mp.procid), unsafe.Pointer(&mp.waitsemacount)) + if ret != 0 && ret != _ESRCH { + // semawakeup can be called on signal stack. + systemstack(func() { + print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n") + }) + } + + // spin-mutex unlock + atomicstore(&mp.waitsemalock, 0) +} + +func newosproc(mp *m, stk unsafe.Pointer) { + if false { + print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, "/", int32(mp.tls[0]), " ostk=", &mp, "\n") + } + + mp.tls[0] = uintptr(mp.id) // so 386 asm can find it + + var uc ucontextt + getcontext(unsafe.Pointer(&uc)) + + uc.uc_flags = _UC_SIGMASK | _UC_CPU + uc.uc_link = nil + uc.uc_sigmask = sigset_all + + lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp.g0, funcPC(mstart)) + + ret := lwp_create(unsafe.Pointer(&uc), 0, unsafe.Pointer(&mp.procid)) + if ret < 0 { + print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n") + gothrow("runtime.newosproc") + } +} + +func osinit() { + ncpu = getncpu() +} + +var urandom_data [_HashRandomBytes]byte +var urandom_dev = []byte("/dev/urandom\x00") + +//go:nosplit +func get_random_data(rnd *unsafe.Pointer, rnd_len *int32) { + fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0) + if read(fd, unsafe.Pointer(&urandom_data), _HashRandomBytes) == _HashRandomBytes { + *rnd = unsafe.Pointer(&urandom_data[0]) + *rnd_len = _HashRandomBytes + } else { + *rnd = nil + *rnd_len = 0 + } + close(fd) +} + +func goenvs() { + goenvs_unix() +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the parent thread (main thread in case of bootstrap), can allocate memory. +func mpreinit(mp *m) { + mp.gsignal = malg(32 * 1024) + mp.gsignal.m = mp +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the new thread, can not allocate memory. +func minit() { + _g_ := getg() + _g_.m.procid = uint64(lwp_self()) + + // Initialize signal handling + signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024) + sigprocmask(_SIG_SETMASK, &sigset_none, nil) +} + +// Called from dropm to undo the effect of an minit. +func unminit() { + signalstack(nil, 0) +} + +func memlimit() uintptr { + return 0 +} + +func sigtramp() + +type sigactiont struct { + sa_sigaction uintptr + sa_mask sigset + sa_flags int32 +} + +func setsig(i int32, fn uintptr, restart bool) { + var sa sigactiont + sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK + if restart { + sa.sa_flags |= _SA_RESTART + } + sa.sa_mask = sigset_all + if fn == funcPC(sighandler) { + fn = funcPC(sigtramp) + } + sa.sa_sigaction = fn + sigaction(i, &sa, nil) +} + +func getsig(i int32) uintptr { + var sa sigactiont + sigaction(i, nil, &sa) + if sa.sa_sigaction == funcPC(sigtramp) { + return funcPC(sighandler) + } + return sa.sa_sigaction +} + +func signalstack(p *byte, n int32) { + var st sigaltstackt + + st.ss_sp = uintptr(unsafe.Pointer(p)) + st.ss_size = uintptr(n) + st.ss_flags = 0 + if p == nil { + st.ss_flags = _SS_DISABLE + } + sigaltstack(&st, nil) +} + +func unblocksignals() { + sigprocmask(_SIG_SETMASK, &sigset_none, nil) +} diff --git a/src/runtime/os1_netbsd_amd64.go b/src/runtime/os1_netbsd_amd64.go new file mode 100644 index 0000000000..5118b0c4ff --- /dev/null +++ b/src/runtime/os1_netbsd_amd64.go @@ -0,0 +1,16 @@ +// Copyright 2009 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. + +package runtime + +import "unsafe" + +func lwp_mcontext_init(mc *mcontextt, stk unsafe.Pointer, mp *m, gp *g, fn uintptr) { + // Machine dependent mcontext initialisation for LWP. + mc.__gregs[_REG_RIP] = uint64(funcPC(lwp_tramp)) + mc.__gregs[_REG_RSP] = uint64(uintptr(stk)) + mc.__gregs[_REG_R8] = uint64(uintptr(unsafe.Pointer(mp))) + mc.__gregs[_REG_R9] = uint64(uintptr(unsafe.Pointer(gp))) + mc.__gregs[_REG_R12] = uint64(fn) +} diff --git a/src/runtime/os2_netbsd.go b/src/runtime/os2_netbsd.go new file mode 100644 index 0000000000..46576b9bc3 --- /dev/null +++ b/src/runtime/os2_netbsd.go @@ -0,0 +1,18 @@ +// Copyright 2010 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. + +package runtime + +const ( + _SS_DISABLE = 4 + _SIG_BLOCK = 1 + _SIG_UNBLOCK = 2 + _SIG_SETMASK = 3 + _NSIG = 33 + _SI_USER = 0 + + // From NetBSD's + _UC_SIGMASK = 0x01 + _UC_CPU = 0x04 +) diff --git a/src/runtime/os_netbsd.c b/src/runtime/os_netbsd.c deleted file mode 100644 index 58e5bedf2f..0000000000 --- a/src/runtime/os_netbsd.c +++ /dev/null @@ -1,368 +0,0 @@ -// Copyright 2011 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. - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "signal_unix.h" -#include "stack.h" -#include "textflag.h" - -enum -{ - ESRCH = 3, - ENOTSUP = 91, - - // From NetBSD's - CLOCK_REALTIME = 0, - CLOCK_VIRTUAL = 1, - CLOCK_PROF = 2, - CLOCK_MONOTONIC = 3 -}; - -extern SigTab runtime·sigtab[]; - -static Sigset sigset_none; -static Sigset sigset_all = { ~(uint32)0, ~(uint32)0, ~(uint32)0, ~(uint32)0, }; - -extern void runtime·getcontext(UcontextT *context); -extern int32 runtime·lwp_create(UcontextT *context, uintptr flags, void *lwpid); -extern void runtime·lwp_mcontext_init(void *mc, void *stack, M *mp, G *gp, void (*fn)(void)); -extern int32 runtime·lwp_park(Timespec *abstime, int32 unpark, void *hint, void *unparkhint); -extern int32 runtime·lwp_unpark(int32 lwp, void *hint); -extern int32 runtime·lwp_self(void); - -// From NetBSD's -#define CTL_HW 6 -#define HW_NCPU 3 - -static int32 -getncpu(void) -{ - uint32 mib[2]; - uint32 out; - int32 ret; - uintptr nout; - - // Fetch hw.ncpu via sysctl. - mib[0] = CTL_HW; - mib[1] = HW_NCPU; - nout = sizeof out; - out = 0; - ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0); - if(ret >= 0) - return out; - else - return 1; -} - -#pragma textflag NOSPLIT -uintptr -runtime·semacreate(void) -{ - return 1; -} - -static void -semasleep(void) -{ - int64 ns; - Timespec ts; - - ns = (int64)(uint32)g->m->scalararg[0] | (int64)(uint32)g->m->scalararg[1]<<32; - g->m->scalararg[0] = 0; - g->m->scalararg[1] = 0; - - // spin-mutex lock - while(runtime·xchg(&g->m->waitsemalock, 1)) - runtime·osyield(); - - for(;;) { - // lock held - if(g->m->waitsemacount == 0) { - // sleep until semaphore != 0 or timeout. - // thrsleep unlocks m->waitsemalock. - if(ns < 0) { - // TODO(jsing) - potential deadlock! - // - // There is a potential deadlock here since we - // have to release the waitsemalock mutex - // before we call lwp_park() to suspend the - // thread. This allows another thread to - // release the lock and call lwp_unpark() - // before the thread is actually suspended. - // If this occurs the current thread will end - // up sleeping indefinitely. Unfortunately - // the NetBSD kernel does not appear to provide - // a mechanism for unlocking the userspace - // mutex once the thread is actually parked. - runtime·atomicstore(&g->m->waitsemalock, 0); - runtime·lwp_park(nil, 0, &g->m->waitsemacount, nil); - } else { - ns = ns + runtime·nanotime(); - // NOTE: tv_nsec is int64 on amd64, so this assumes a little-endian system. - ts.tv_nsec = 0; - ts.tv_sec = runtime·timediv(ns, 1000000000, (int32*)&ts.tv_nsec); - // TODO(jsing) - potential deadlock! - // See above for details. - runtime·atomicstore(&g->m->waitsemalock, 0); - runtime·lwp_park(&ts, 0, &g->m->waitsemacount, nil); - } - // reacquire lock - while(runtime·xchg(&g->m->waitsemalock, 1)) - runtime·osyield(); - } - - // lock held (again) - if(g->m->waitsemacount != 0) { - // semaphore is available. - g->m->waitsemacount--; - // spin-mutex unlock - runtime·atomicstore(&g->m->waitsemalock, 0); - g->m->scalararg[0] = 0; // semaphore acquired - return; - } - - // semaphore not available. - // if there is a timeout, stop now. - // otherwise keep trying. - if(ns >= 0) - break; - } - - // lock held but giving up - // spin-mutex unlock - runtime·atomicstore(&g->m->waitsemalock, 0); - g->m->scalararg[0] = -1; - return; -} - -#pragma textflag NOSPLIT -int32 -runtime·semasleep(int64 ns) -{ - int32 r; - void (*fn)(void); - - g->m->scalararg[0] = (uint32)ns; - g->m->scalararg[1] = (uint32)(ns>>32); - fn = semasleep; - runtime·onM(&fn); - r = g->m->scalararg[0]; - g->m->scalararg[0] = 0; - return r; -} - -static void badsemawakeup(void); - -#pragma textflag NOSPLIT -void -runtime·semawakeup(M *mp) -{ - uint32 ret; - void (*fn)(void); - void *oldptr; - uintptr oldscalar; - - // spin-mutex lock - while(runtime·xchg(&mp->waitsemalock, 1)) - runtime·osyield(); - mp->waitsemacount++; - // TODO(jsing) - potential deadlock, see semasleep() for details. - // Confirm that LWP is parked before unparking... - ret = runtime·lwp_unpark(mp->procid, &mp->waitsemacount); - if(ret != 0 && ret != ESRCH) { - // semawakeup can be called on signal stack. - // Save old ptrarg/scalararg so we can restore them. - oldptr = g->m->ptrarg[0]; - oldscalar = g->m->scalararg[0]; - g->m->ptrarg[0] = mp; - g->m->scalararg[0] = ret; - fn = badsemawakeup; - if(g == g->m->gsignal) - fn(); - else - runtime·onM(&fn); - g->m->ptrarg[0] = oldptr; - g->m->scalararg[0] = oldscalar; - } - // spin-mutex unlock - runtime·atomicstore(&mp->waitsemalock, 0); -} - -static void -badsemawakeup(void) -{ - M *mp; - int32 ret; - - mp = g->m->ptrarg[0]; - g->m->ptrarg[0] = nil; - ret = g->m->scalararg[0]; - g->m->scalararg[0] = 0; - - runtime·printf("thrwakeup addr=%p sem=%d ret=%d\n", &mp->waitsemacount, mp->waitsemacount, ret); -} - -void -runtime·newosproc(M *mp, void *stk) -{ - UcontextT uc; - int32 ret; - - if(0) { - runtime·printf( - "newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n", - stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp); - } - - mp->tls[0] = mp->id; // so 386 asm can find it - - runtime·getcontext(&uc); - - uc.uc_flags = _UC_SIGMASK | _UC_CPU; - uc.uc_link = nil; - uc.uc_sigmask = sigset_all; - - runtime·lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp->g0, runtime·mstart); - - ret = runtime·lwp_create(&uc, 0, &mp->procid); - - if(ret < 0) { - runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount() - 1, -ret); - runtime·throw("runtime.newosproc"); - } -} - -void -runtime·osinit(void) -{ - runtime·ncpu = getncpu(); -} - -#pragma textflag NOSPLIT -void -runtime·get_random_data(byte **rnd, int32 *rnd_len) -{ - #pragma dataflag NOPTR - static byte urandom_data[HashRandomBytes]; - int32 fd; - fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0); - if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) { - *rnd = urandom_data; - *rnd_len = HashRandomBytes; - } else { - *rnd = nil; - *rnd_len = 0; - } - runtime·close(fd); -} - -void -runtime·goenvs(void) -{ - runtime·goenvs_unix(); -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the parent thread (main thread in case of bootstrap), can allocate memory. -void -runtime·mpreinit(M *mp) -{ - mp->gsignal = runtime·malg(32*1024); - mp->gsignal->m = mp; -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the new thread, can not allocate memory. -void -runtime·minit(void) -{ - g->m->procid = runtime·lwp_self(); - - // Initialize signal handling - runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024); - runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil); -} - -// Called from dropm to undo the effect of an minit. -void -runtime·unminit(void) -{ - runtime·signalstack(nil, 0); -} - -uintptr -runtime·memlimit(void) -{ - return 0; -} - -extern void runtime·sigtramp(void); - -typedef struct sigaction { - union { - void (*_sa_handler)(int32); - void (*_sa_sigaction)(int32, Siginfo*, void *); - } _sa_u; /* signal handler */ - uint32 sa_mask[4]; /* signal mask to apply */ - int32 sa_flags; /* see signal options below */ -} SigactionT; - -void -runtime·setsig(int32 i, GoSighandler *fn, bool restart) -{ - SigactionT sa; - - runtime·memclr((byte*)&sa, sizeof sa); - sa.sa_flags = SA_SIGINFO|SA_ONSTACK; - if(restart) - sa.sa_flags |= SA_RESTART; - sa.sa_mask[0] = ~0U; - sa.sa_mask[1] = ~0U; - sa.sa_mask[2] = ~0U; - sa.sa_mask[3] = ~0U; - if (fn == runtime·sighandler) - fn = (void*)runtime·sigtramp; - sa._sa_u._sa_sigaction = (void*)fn; - runtime·sigaction(i, &sa, nil); -} - -GoSighandler* -runtime·getsig(int32 i) -{ - SigactionT sa; - - runtime·memclr((byte*)&sa, sizeof sa); - runtime·sigaction(i, nil, &sa); - if((void*)sa._sa_u._sa_sigaction == runtime·sigtramp) - return runtime·sighandler; - return (void*)sa._sa_u._sa_sigaction; -} - -void -runtime·signalstack(byte *p, int32 n) -{ - StackT st; - - st.ss_sp = (void*)p; - st.ss_size = n; - st.ss_flags = 0; - if(p == nil) - st.ss_flags = SS_DISABLE; - runtime·sigaltstack(&st, nil); -} - -void -runtime·unblocksignals(void) -{ - runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil); -} - -#pragma textflag NOSPLIT -int8* -runtime·signame(int32 sig) -{ - return runtime·sigtab[sig].name; -} diff --git a/src/runtime/os_netbsd.go b/src/runtime/os_netbsd.go index f000c5e9f6..a153bf2ebc 100644 --- a/src/runtime/os_netbsd.go +++ b/src/runtime/os_netbsd.go @@ -6,15 +6,37 @@ package runtime import "unsafe" -func setitimer(mode int32, new, old unsafe.Pointer) -func sigaction(sig int32, new, old unsafe.Pointer) -func sigaltstack(new, old unsafe.Pointer) -func sigprocmask(mode int32, new, old unsafe.Pointer) +//go:noescape +func setitimer(mode int32, new, old *itimerval) + +//go:noescape +func sigaction(sig int32, new, old *sigactiont) + +//go:noescape +func sigaltstack(new, old *sigaltstackt) + +//go:noescape +func sigprocmask(mode int32, new, old *sigset) + +//go:noescape func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32 + func lwp_tramp() + func raise(sig int32) + +//go:noescape func getcontext(ctxt unsafe.Pointer) + +//go:noescape func lwp_create(ctxt unsafe.Pointer, flags uintptr, lwpid unsafe.Pointer) int32 -func lwp_park(abstime unsafe.Pointer, unpark int32, hint, unparkhint unsafe.Pointer) int32 + +//go:noescape +func lwp_park(abstime *timespec, unpark int32, hint, unparkhint unsafe.Pointer) int32 + +//go:noescape func lwp_unpark(lwp int32, hint unsafe.Pointer) int32 + func lwp_self() int32 + +func osyield() diff --git a/src/runtime/os_netbsd.h b/src/runtime/os_netbsd.h deleted file mode 100644 index f95db325f0..0000000000 --- a/src/runtime/os_netbsd.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2010 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. - - -typedef uintptr kevent_udata; - -struct sigaction; - -void runtime·sigpanic(void); - -void runtime·setitimer(int32, Itimerval*, Itimerval*); -void runtime·sigaction(int32, struct sigaction*, struct sigaction*); -void runtime·sigaltstack(SigaltstackT*, SigaltstackT*); -void runtime·sigprocmask(int32, Sigset*, Sigset*); -void runtime·unblocksignals(void); -int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr); -extern void runtime·lwp_tramp(void); - -enum { - SS_DISABLE = 4, - SIG_BLOCK = 1, - SIG_UNBLOCK = 2, - SIG_SETMASK = 3, - NSIG = 33, - SI_USER = 0, - - // From NetBSD's - _UC_SIGMASK = 0x01, - _UC_CPU = 0x04, -}; diff --git a/src/runtime/os_netbsd_amd64.c b/src/runtime/os_netbsd_amd64.c deleted file mode 100644 index 226846cbb0..0000000000 --- a/src/runtime/os_netbsd_amd64.c +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2009 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. - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" - -void -runtime·lwp_mcontext_init(McontextT *mc, void *stack, M *mp, G *gp, void (*fn)(void)) -{ - // Machine dependent mcontext initialisation for LWP. - mc->__gregs[REG_RIP] = (uint64)runtime·lwp_tramp; - mc->__gregs[REG_RSP] = (uint64)stack; - mc->__gregs[REG_R8] = (uint64)mp; - mc->__gregs[REG_R9] = (uint64)gp; - mc->__gregs[REG_R12] = (uint64)fn; -} diff --git a/src/runtime/signal_netbsd.go b/src/runtime/signal_netbsd.go new file mode 100644 index 0000000000..78afc59efa --- /dev/null +++ b/src/runtime/signal_netbsd.go @@ -0,0 +1,46 @@ +// Copyright 2009 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. + +package runtime + +type sigTabT struct { + flags int32 + name string +} + +var sigtable = [...]sigTabT{ + /* 0 */ {0, "SIGNONE: no trap"}, + /* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"}, + /* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"}, + /* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"}, + /* 4 */ {_SigThrow, "SIGILL: illegal instruction"}, + /* 5 */ {_SigThrow, "SIGTRAP: trace trap"}, + /* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"}, + /* 7 */ {_SigThrow, "SIGEMT: emulate instruction executed"}, + /* 8 */ {_SigPanic, "SIGFPE: floating-point exception"}, + /* 9 */ {0, "SIGKILL: kill"}, + /* 10 */ {_SigPanic, "SIGBUS: bus error"}, + /* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"}, + /* 12 */ {_SigThrow, "SIGSYS: bad system call"}, + /* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"}, + /* 14 */ {_SigNotify, "SIGALRM: alarm clock"}, + /* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"}, + /* 16 */ {_SigNotify, "SIGURG: urgent condition on socket"}, + /* 17 */ {0, "SIGSTOP: stop"}, + /* 18 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"}, + /* 19 */ {0, "SIGCONT: continue after stop"}, + /* 20 */ {_SigNotify, "SIGCHLD: child status has changed"}, + /* 21 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"}, + /* 22 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"}, + /* 23 */ {_SigNotify, "SIGIO: i/o now possible"}, + /* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"}, + /* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"}, + /* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"}, + /* 27 */ {_SigNotify, "SIGPROF: profiling alarm clock"}, + /* 28 */ {_SigNotify, "SIGWINCH: window size change"}, + /* 29 */ {_SigNotify, "SIGINFO: status request from keyboard"}, + /* 30 */ {_SigNotify, "SIGUSR1: user-defined signal 1"}, + /* 31 */ {_SigNotify, "SIGUSR2: user-defined signal 2"}, + /* 32 */ {_SigNotify, "SIGTHR: reserved"}, +} diff --git a/src/runtime/signal_netbsd_amd64.go b/src/runtime/signal_netbsd_amd64.go new file mode 100644 index 0000000000..e22f4a724a --- /dev/null +++ b/src/runtime/signal_netbsd_amd64.go @@ -0,0 +1,48 @@ +// 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. + +package runtime + +import "unsafe" + +type sigctxt struct { + info *siginfo + ctxt unsafe.Pointer +} + +func (c *sigctxt) regs() *mcontextt { + return (*mcontextt)(unsafe.Pointer(&(*ucontextt)(c.ctxt).uc_mcontext)) +} +func (c *sigctxt) rax() uint64 { return c.regs().__gregs[_REG_RAX] } +func (c *sigctxt) rbx() uint64 { return c.regs().__gregs[_REG_RBX] } +func (c *sigctxt) rcx() uint64 { return c.regs().__gregs[_REG_RCX] } +func (c *sigctxt) rdx() uint64 { return c.regs().__gregs[_REG_RDX] } +func (c *sigctxt) rdi() uint64 { return c.regs().__gregs[_REG_RDI] } +func (c *sigctxt) rsi() uint64 { return c.regs().__gregs[_REG_RSI] } +func (c *sigctxt) rbp() uint64 { return c.regs().__gregs[_REG_RBP] } +func (c *sigctxt) rsp() uint64 { return c.regs().__gregs[_REG_RSP] } +func (c *sigctxt) r8() uint64 { return c.regs().__gregs[_REG_R8] } +func (c *sigctxt) r9() uint64 { return c.regs().__gregs[_REG_R8] } +func (c *sigctxt) r10() uint64 { return c.regs().__gregs[_REG_R10] } +func (c *sigctxt) r11() uint64 { return c.regs().__gregs[_REG_R11] } +func (c *sigctxt) r12() uint64 { return c.regs().__gregs[_REG_R12] } +func (c *sigctxt) r13() uint64 { return c.regs().__gregs[_REG_R13] } +func (c *sigctxt) r14() uint64 { return c.regs().__gregs[_REG_R14] } +func (c *sigctxt) r15() uint64 { return c.regs().__gregs[_REG_R15] } +func (c *sigctxt) rip() uint64 { return c.regs().__gregs[_REG_RIP] } +func (c *sigctxt) rflags() uint64 { return c.regs().__gregs[_REG_RFLAGS] } +func (c *sigctxt) cs() uint64 { return c.regs().__gregs[_REG_CS] } +func (c *sigctxt) fs() uint64 { return c.regs().__gregs[_REG_FS] } +func (c *sigctxt) gs() uint64 { return c.regs().__gregs[_REG_GS] } +func (c *sigctxt) sigcode() uint64 { return uint64(c.info._code) } +func (c *sigctxt) sigaddr() uint64 { + return uint64(*(*uint64)(unsafe.Pointer(&c.info._reason[0]))) +} + +func (c *sigctxt) set_rip(x uint64) { c.regs().__gregs[_REG_RIP] = x } +func (c *sigctxt) set_rsp(x uint64) { c.regs().__gregs[_REG_RSP] = x } +func (c *sigctxt) set_sigcode(x uint64) { c.info._code = int32(x) } +func (c *sigctxt) set_sigaddr(x uint64) { + *(*uint64)(unsafe.Pointer(&c.info._reason[0])) = x +} diff --git a/src/runtime/signal_netbsd_amd64.h b/src/runtime/signal_netbsd_amd64.h deleted file mode 100644 index 7ec4cd98cd..0000000000 --- a/src/runtime/signal_netbsd_amd64.h +++ /dev/null @@ -1,31 +0,0 @@ -// 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. - -#define SIG_REGS(ctxt) (((UcontextT*)(ctxt))->uc_mcontext) - -#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RAX]) -#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RBX]) -#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RCX]) -#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RDX]) -#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RDI]) -#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RSI]) -#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RBP]) -#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RSP]) -#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R8]) -#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R9]) -#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R10]) -#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R11]) -#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R12]) -#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R13]) -#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R14]) -#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R15]) -#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RIP]) -#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RFLAGS]) - -#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_CS]) -#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_FS]) -#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_GS]) - -#define SIG_CODE0(info, ctxt) ((info)->_code) -#define SIG_CODE1(info, ctxt) (*(uintptr*)&(info)->_reason[0]) diff --git a/src/runtime/signals_netbsd.h b/src/runtime/signals_netbsd.h deleted file mode 100644 index 950a2fe62c..0000000000 --- a/src/runtime/signals_netbsd.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2009 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. - -#include "textflag.h" - -#define N SigNotify -#define K SigKill -#define T SigThrow -#define P SigPanic -#define D SigDefault - -#pragma dataflag NOPTR -SigTab runtime·sigtab[] = { - /* 0 */ 0, "SIGNONE: no trap", - /* 1 */ N+K, "SIGHUP: terminal line hangup", - /* 2 */ N+K, "SIGINT: interrupt", - /* 3 */ N+T, "SIGQUIT: quit", - /* 4 */ T, "SIGILL: illegal instruction", - /* 5 */ T, "SIGTRAP: trace trap", - /* 6 */ N+T, "SIGABRT: abort", - /* 7 */ T, "SIGEMT: emulate instruction executed", - /* 8 */ P, "SIGFPE: floating-point exception", - /* 9 */ 0, "SIGKILL: kill", - /* 10 */ P, "SIGBUS: bus error", - /* 11 */ P, "SIGSEGV: segmentation violation", - /* 12 */ T, "SIGSYS: bad system call", - /* 13 */ N, "SIGPIPE: write to broken pipe", - /* 14 */ N, "SIGALRM: alarm clock", - /* 15 */ N+K, "SIGTERM: termination", - /* 16 */ N, "SIGURG: urgent condition on socket", - /* 17 */ 0, "SIGSTOP: stop", - /* 18 */ N+D, "SIGTSTP: keyboard stop", - /* 19 */ 0, "SIGCONT: continue after stop", - /* 20 */ N, "SIGCHLD: child status has changed", - /* 21 */ N+D, "SIGTTIN: background read from tty", - /* 22 */ N+D, "SIGTTOU: background write to tty", - /* 23 */ N, "SIGIO: i/o now possible", - /* 24 */ N, "SIGXCPU: cpu limit exceeded", - /* 25 */ N, "SIGXFSZ: file size limit exceeded", - /* 26 */ N, "SIGVTALRM: virtual alarm clock", - /* 27 */ N, "SIGPROF: profiling alarm clock", - /* 28 */ N, "SIGWINCH: window size change", - /* 29 */ N, "SIGINFO: status request from keyboard", - /* 30 */ N, "SIGUSR1: user-defined signal 1", - /* 31 */ N, "SIGUSR2: user-defined signal 2", - /* 32 */ N, "SIGTHR: reserved", -}; - -#undef N -#undef K -#undef T -#undef P -#undef D From 0d76887433b3034c4dfd8b909f3a4b76b0eabefb Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Sat, 22 Nov 2014 22:09:11 +1100 Subject: [PATCH 66/68] [dev.cc] runtime: convert netbsd/386 port to Go LGTM=minux R=rsc, minux CC=golang-codereviews https://golang.org/cl/177170043 --- src/runtime/defs1_netbsd_386.go | 22 +++++++++++++----- src/runtime/os1_netbsd_386.go | 16 ++++++++++++++ src/runtime/os_netbsd_386.c | 17 -------------- src/runtime/signal_netbsd_386.go | 38 ++++++++++++++++++++++++++++++++ src/runtime/signal_netbsd_386.h | 23 ------------------- 5 files changed, 71 insertions(+), 45 deletions(-) create mode 100644 src/runtime/os1_netbsd_386.go delete mode 100644 src/runtime/os_netbsd_386.c create mode 100644 src/runtime/signal_netbsd_386.go delete mode 100644 src/runtime/signal_netbsd_386.h diff --git a/src/runtime/defs1_netbsd_386.go b/src/runtime/defs1_netbsd_386.go index e39fd04c7a..f222bed996 100644 --- a/src/runtime/defs1_netbsd_386.go +++ b/src/runtime/defs1_netbsd_386.go @@ -84,8 +84,8 @@ const ( ) type sigaltstackt struct { - ss_sp *byte - ss_size uint32 + ss_sp uintptr + ss_size uintptr ss_flags int32 } @@ -101,8 +101,8 @@ type siginfo struct { } type stackt struct { - ss_sp *byte - ss_size uint32 + ss_sp uintptr + ss_size uintptr ss_flags int32 } @@ -111,18 +111,30 @@ type timespec struct { tv_nsec int32 } +func (ts *timespec) set_sec(x int32) { + ts.tv_sec = int64(x) +} + +func (ts *timespec) set_nsec(x int32) { + ts.tv_nsec = x +} + type timeval struct { tv_sec int64 tv_usec int32 } +func (tv *timeval) set_usec(x int32) { + tv.tv_usec = x +} + type itimerval struct { it_interval timeval it_value timeval } type mcontextt struct { - __gregs [19]int32 + __gregs [19]uint32 __fpregs [644]byte _mc_tlsbase int32 } diff --git a/src/runtime/os1_netbsd_386.go b/src/runtime/os1_netbsd_386.go new file mode 100644 index 0000000000..037f7e36dc --- /dev/null +++ b/src/runtime/os1_netbsd_386.go @@ -0,0 +1,16 @@ +// Copyright 2009 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. + +package runtime + +import "unsafe" + +func lwp_mcontext_init(mc *mcontextt, stk unsafe.Pointer, mp *m, gp *g, fn uintptr) { + // Machine dependent mcontext initialisation for LWP. + mc.__gregs[_REG_EIP] = uint32(funcPC(lwp_tramp)) + mc.__gregs[_REG_UESP] = uint32(uintptr(stk)) + mc.__gregs[_REG_EBX] = uint32(uintptr(unsafe.Pointer(mp))) + mc.__gregs[_REG_EDX] = uint32(uintptr(unsafe.Pointer(gp))) + mc.__gregs[_REG_ESI] = uint32(fn) +} diff --git a/src/runtime/os_netbsd_386.c b/src/runtime/os_netbsd_386.c deleted file mode 100644 index 23e9db3c1c..0000000000 --- a/src/runtime/os_netbsd_386.c +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2009 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. - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" - -void -runtime·lwp_mcontext_init(McontextT *mc, void *stack, M *mp, G *gp, void (*fn)(void)) -{ - mc->__gregs[REG_EIP] = (uint32)runtime·lwp_tramp; - mc->__gregs[REG_UESP] = (uint32)stack; - mc->__gregs[REG_EBX] = (uint32)mp; - mc->__gregs[REG_EDX] = (uint32)gp; - mc->__gregs[REG_ESI] = (uint32)fn; -} diff --git a/src/runtime/signal_netbsd_386.go b/src/runtime/signal_netbsd_386.go new file mode 100644 index 0000000000..6702336abe --- /dev/null +++ b/src/runtime/signal_netbsd_386.go @@ -0,0 +1,38 @@ +// 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. + +package runtime + +import "unsafe" + +type sigctxt struct { + info *siginfo + ctxt unsafe.Pointer +} + +func (c *sigctxt) regs() *mcontextt { return &(*ucontextt)(c.ctxt).uc_mcontext } +func (c *sigctxt) eax() uint32 { return c.regs().__gregs[_REG_EAX] } +func (c *sigctxt) ebx() uint32 { return c.regs().__gregs[_REG_EBX] } +func (c *sigctxt) ecx() uint32 { return c.regs().__gregs[_REG_ECX] } +func (c *sigctxt) edx() uint32 { return c.regs().__gregs[_REG_EDX] } +func (c *sigctxt) edi() uint32 { return c.regs().__gregs[_REG_EDI] } +func (c *sigctxt) esi() uint32 { return c.regs().__gregs[_REG_ESI] } +func (c *sigctxt) ebp() uint32 { return c.regs().__gregs[_REG_EBP] } +func (c *sigctxt) esp() uint32 { return c.regs().__gregs[_REG_UESP] } +func (c *sigctxt) eip() uint32 { return c.regs().__gregs[_REG_EIP] } +func (c *sigctxt) eflags() uint32 { return c.regs().__gregs[_REG_EFL] } +func (c *sigctxt) cs() uint32 { return uint32(c.regs().__gregs[_REG_CS]) } +func (c *sigctxt) fs() uint32 { return uint32(c.regs().__gregs[_REG_FS]) } +func (c *sigctxt) gs() uint32 { return uint32(c.regs().__gregs[_REG_GS]) } +func (c *sigctxt) sigcode() uint32 { return uint32(c.info._code) } +func (c *sigctxt) sigaddr() uint32 { + return uint32(*(*uint32)(unsafe.Pointer(&c.info._reason[0]))) +} + +func (c *sigctxt) set_eip(x uint32) { c.regs().__gregs[_REG_EIP] = x } +func (c *sigctxt) set_esp(x uint32) { c.regs().__gregs[_REG_UESP] = x } +func (c *sigctxt) set_sigcode(x uint32) { c.info._code = int32(x) } +func (c *sigctxt) set_sigaddr(x uint32) { + *(*uint32)(unsafe.Pointer(&c.info._reason[0])) = x +} diff --git a/src/runtime/signal_netbsd_386.h b/src/runtime/signal_netbsd_386.h deleted file mode 100644 index d5a8a0c4bc..0000000000 --- a/src/runtime/signal_netbsd_386.h +++ /dev/null @@ -1,23 +0,0 @@ -// 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. - -#define SIG_REGS(ctxt) (((UcontextT*)(ctxt))->uc_mcontext) - -#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EAX]) -#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EBX]) -#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_ECX]) -#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EDX]) -#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EDI]) -#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_ESI]) -#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EBP]) -#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_UESP]) -#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EIP]) -#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EFL]) - -#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_CS]) -#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_FS]) -#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_GS]) - -#define SIG_CODE0(info, ctxt) ((info)->_code) -#define SIG_CODE1(info, ctxt) (*(uintptr*)&(info)->_reason[0]) From 8cda58c25ebdd46dc29c6aee776e286ed8c31081 Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Sat, 22 Nov 2014 13:37:46 -0500 Subject: [PATCH 67/68] cmd/go: fix running pprof on windows. Fixes #9149. LGTM=alex.brainman, rsc R=rsc, dave, alex.brainman CC=golang-codereviews https://golang.org/cl/176170043 --- src/cmd/go/tool.go | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/cmd/go/tool.go b/src/cmd/go/tool.go index c96161e0f9..3f11c3e3d4 100644 --- a/src/cmd/go/tool.go +++ b/src/cmd/go/tool.go @@ -47,7 +47,7 @@ const toolWindowsExtension = ".exe" func tool(toolName string) string { toolPath := filepath.Join(toolDir, toolName) - if toolIsWindows && toolName != "pprof" { + if toolIsWindows { toolPath += toolWindowsExtension } // Give a nice message if there is no tool with that name. @@ -91,16 +91,6 @@ func runTool(cmd *Command, args []string) { if toolPath == "" { return } - if toolIsWindows && toolName == "pprof" { - args = append([]string{"perl", toolPath}, args[1:]...) - var err error - toolPath, err = exec.LookPath("perl") - if err != nil { - fmt.Fprintf(os.Stderr, "go tool: perl not found\n") - setExitStatus(3) - return - } - } if toolN { fmt.Printf("%s %s\n", toolPath, strings.Join(args[1:], " ")) return From 04923042bd402def7f48663a165d759d1fdbf15d Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Sat, 22 Nov 2014 13:55:33 -0500 Subject: [PATCH 68/68] image/jpeg: handle Read returning n > 0, err != nil in d.fill Fixes #9127. LGTM=r R=bradfitz, r CC=golang-codereviews, nigeltao https://golang.org/cl/178120043 --- src/image/jpeg/reader.go | 3 +++ src/image/jpeg/reader_test.go | 46 +++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/src/image/jpeg/reader.go b/src/image/jpeg/reader.go index c8fae3cea9..6d8b1d1d03 100644 --- a/src/image/jpeg/reader.go +++ b/src/image/jpeg/reader.go @@ -143,6 +143,9 @@ func (d *decoder) fill() error { // Fill in the rest of the buffer. n, err := d.r.Read(d.bytes.buf[d.bytes.j:]) d.bytes.j += n + if n > 0 { + err = nil + } return err } diff --git a/src/image/jpeg/reader_test.go b/src/image/jpeg/reader_test.go index 93f4adab9d..4de2e8ee73 100644 --- a/src/image/jpeg/reader_test.go +++ b/src/image/jpeg/reader_test.go @@ -9,6 +9,7 @@ import ( "fmt" "image" "image/color" + "io" "io/ioutil" "math/rand" "os" @@ -88,6 +89,51 @@ func decodeFile(filename string) (image.Image, error) { return Decode(f) } +type eofReader struct { + data []byte // deliver from Read without EOF + dataEOF []byte // then deliver from Read with EOF on last chunk + lenAtEOF int +} + +func (r *eofReader) Read(b []byte) (n int, err error) { + if len(r.data) > 0 { + n = copy(b, r.data) + r.data = r.data[n:] + } else { + n = copy(b, r.dataEOF) + r.dataEOF = r.dataEOF[n:] + if len(r.dataEOF) == 0 { + err = io.EOF + if r.lenAtEOF == -1 { + r.lenAtEOF = n + } + } + } + return +} + +func TestDecodeEOF(t *testing.T) { + // Check that if reader returns final data and EOF at same time, jpeg handles it. + data, err := ioutil.ReadFile("../testdata/video-001.jpeg") + if err != nil { + t.Fatal(err) + } + + n := len(data) + for i := 0; i < n; { + r := &eofReader{data[:n-i], data[n-i:], -1} + _, err := Decode(r) + if err != nil { + t.Errorf("Decode with Read() = %d, EOF: %v", r.lenAtEOF, err) + } + if i == 0 { + i = 1 + } else { + i *= 2 + } + } +} + // check checks that the two pix data are equal, within the given bounds. func check(bounds image.Rectangle, pix0, pix1 []byte, stride0, stride1 int) error { if stride0 <= 0 || stride0%8 != 0 {