1// Copyright 2017 The Wuffs Authors. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// https://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package cgen 16 17import ( 18 "errors" 19 "fmt" 20 21 a "github.com/google/wuffs/lang/ast" 22 t "github.com/google/wuffs/lang/token" 23) 24 25var errNeedDerivedVar = errors.New("cgen: internal error: need derived var") 26 27func (g *gen) needDerivedVar(name t.ID) bool { 28 for _, o := range g.currFunk.astFunc.Body() { 29 err := o.Walk(func(p *a.Node) error { 30 // Look for p matching "args.name.etc(etc)". 31 if p.Kind() != a.KExpr { 32 return nil 33 } 34 q := p.AsExpr() 35 if q.Operator() != t.IDOpenParen { 36 return nil 37 } 38 q = q.LHS().AsExpr() 39 if q.Operator() != t.IDDot { 40 return nil 41 } 42 q = q.LHS().AsExpr() 43 if q.Operator() != t.IDDot || q.Ident() != name { 44 return nil 45 } 46 q = q.LHS().AsExpr() 47 if q.Operator() != 0 || q.Ident() != t.IDArgs { 48 return nil 49 } 50 return errNeedDerivedVar 51 }) 52 if err == errNeedDerivedVar { 53 return true 54 } 55 } 56 return false 57} 58 59func (g *gen) findDerivedVars() { 60 for _, o := range g.currFunk.astFunc.In().Fields() { 61 o := o.AsField() 62 if !o.XType().IsIOType() || !g.needDerivedVar(o.Name()) { 63 continue 64 } 65 if g.currFunk.derivedVars == nil { 66 g.currFunk.derivedVars = map[t.ID]struct{}{} 67 } 68 g.currFunk.derivedVars[o.Name()] = struct{}{} 69 } 70} 71 72func (g *gen) writeLoadDerivedVar(b *buffer, hack string, prefix string, name t.ID, typ *a.TypeExpr, header bool) error { 73 // TODO: remove this hack. We're picking up the wrong name for "src:r, 74 // dummy:args.src". 75 if name.Str(g.tm) == "dummy" { 76 name = g.tm.ByName("src") 77 } 78 // TODO: also remove this hack. 79 if hack == "w" { 80 b.printf("%s%sw = %sw.data.ptr + %sw.meta.wi;\n", iopPrefix, vPrefix, uPrefix, uPrefix) 81 return nil 82 } else if hack == "r" { 83 b.printf("%s%sr = %sr.data.ptr + %sr.meta.ri;\n", iopPrefix, vPrefix, uPrefix, uPrefix) 84 return nil 85 } 86 87 if !typ.IsIOType() { 88 return nil 89 } 90 if g.currFunk.derivedVars == nil { 91 return nil 92 } 93 if _, ok := g.currFunk.derivedVars[name]; !ok { 94 return nil 95 } 96 97 preName := prefix + name.Str(g.tm) 98 i1, i2 := "meta.ri", "meta.wi" 99 if typ.QID()[1] == t.IDIOWriter { 100 i1, i2 = "meta.wi", "data.len" 101 } 102 103 if header { 104 b.printf("uint8_t* %s%s = NULL;", iopPrefix, preName) 105 b.printf("uint8_t* %s%s WUFFS_BASE__POTENTIALLY_UNUSED = NULL;", io0Prefix, preName) 106 b.printf("uint8_t* %s%s WUFFS_BASE__POTENTIALLY_UNUSED = NULL;", io1Prefix, preName) 107 b.printf("uint8_t* %s%s WUFFS_BASE__POTENTIALLY_UNUSED = NULL;", io2Prefix, preName) 108 } 109 110 b.printf("if (%s) {", preName) 111 112 if header { 113 b.printf("%s%s = %s->data.ptr;", io0Prefix, preName, preName) 114 b.printf("%s%s = %s%s + %s->%s;", io1Prefix, preName, io0Prefix, preName, preName, i1) 115 b.printf("%s%s = %s%s;", iopPrefix, preName, io1Prefix, preName) 116 b.printf("%s%s = %s%s + %s->%s;", io2Prefix, preName, io0Prefix, preName, preName, i2) 117 118 if typ.QID()[1] == t.IDIOWriter { 119 b.printf("if (%s->meta.closed) {", preName) 120 b.printf("%s%s = %s%s;", io2Prefix, preName, iopPrefix, preName) 121 b.printf("}\n") 122 } 123 } else { 124 b.printf("%s%s = %s->data.ptr + %s->%s;", iopPrefix, preName, preName, preName, i1) 125 } 126 127 b.printf("}\n") 128 return nil 129} 130 131func (g *gen) writeSaveDerivedVar(b *buffer, hack string, prefix string, name t.ID, typ *a.TypeExpr) error { 132 // TODO: remove this hack. We're picking up the wrong name for "src:r, 133 // dummy:args.src". 134 if name.Str(g.tm) == "dummy" { 135 name = g.tm.ByName("src") 136 } 137 // TODO: also remove this hack. 138 if hack == "w" { 139 b.printf("%sw.meta.wi = ((size_t)(%s%sw - %sw.data.ptr));\n", uPrefix, iopPrefix, vPrefix, uPrefix) 140 return nil 141 } else if hack == "r" { 142 b.printf("%sr.meta.ri = ((size_t)(%s%sr - %sr.data.ptr));\n", uPrefix, iopPrefix, vPrefix, uPrefix) 143 return nil 144 } 145 146 if !typ.IsIOType() { 147 return nil 148 } 149 if g.currFunk.derivedVars == nil { 150 return nil 151 } 152 if _, ok := g.currFunk.derivedVars[name]; !ok { 153 return nil 154 } 155 156 preName := prefix + name.Str(g.tm) 157 index := "ri" 158 if typ.QID()[1] == t.IDIOWriter { 159 index = "wi" 160 } 161 162 b.printf("if (%s) { %s->meta.%s = ((size_t)(%s%s - %s->data.ptr)); }\n", 163 preName, preName, index, iopPrefix, preName, preName) 164 return nil 165} 166 167func (g *gen) writeLoadExprDerivedVars(b *buffer, n *a.Expr) error { 168 if g.currFunk.derivedVars == nil { 169 return nil 170 } 171 if n.Operator() != t.IDOpenParen { 172 return nil 173 } 174 for _, o := range n.Args() { 175 o := o.AsArg() 176 prefix := aPrefix 177 // TODO: don't hard-code these. 178 hack := "" 179 if s := o.Value().Str(g.tm); s != "args.dst" && s != "args.src" && s != "w" && s != "r" { 180 continue 181 } else if s == "w" || s == "r" { 182 prefix = vPrefix 183 hack = s 184 } 185 if err := g.writeLoadDerivedVar(b, hack, prefix, o.Name(), o.Value().MType(), false); err != nil { 186 return err 187 } 188 } 189 return nil 190} 191 192func (g *gen) writeSaveExprDerivedVars(b *buffer, n *a.Expr) error { 193 if g.currFunk.derivedVars == nil { 194 return nil 195 } 196 if n.Operator() != t.IDOpenParen { 197 return nil 198 } 199 for _, o := range n.Args() { 200 o := o.AsArg() 201 prefix := aPrefix 202 // TODO: don't hard-code these. 203 hack := "" 204 if s := o.Value().Str(g.tm); s != "args.dst" && s != "args.src" && s != "w" && s != "r" { 205 continue 206 } else if s == "w" || s == "r" { 207 prefix = vPrefix 208 hack = s 209 } 210 if err := g.writeSaveDerivedVar(b, hack, prefix, o.Name(), o.Value().MType()); err != nil { 211 return err 212 } 213 } 214 return nil 215} 216 217func (g *gen) writeResumeSuspend1(b *buffer, f *funk, n *a.Var, suspend bool) error { 218 if typ := n.XType(); typ.HasPointers() { 219 return nil 220 } else if f.varResumables == nil || !f.varResumables[n.Name()] { 221 return nil 222 } else { 223 local := fmt.Sprintf("%s%s", vPrefix, n.Name().Str(g.tm)) 224 lhs := local 225 // TODO: don't hard-code [0], and allow recursive coroutines. 226 rhs := fmt.Sprintf("self->private_data.%s%s[0].%s", sPrefix, g.currFunk.astFunc.FuncName().Str(g.tm), lhs) 227 if suspend { 228 lhs, rhs = rhs, lhs 229 } 230 231 switch typ.Decorator() { 232 case 0: 233 b.printf("%s = %s;\n", lhs, rhs) 234 return nil 235 case t.IDArray: 236 inner := typ.Inner() 237 if inner.Decorator() != 0 { 238 break 239 } 240 qid := inner.QID() 241 if qid[0] != t.IDBase { 242 break 243 } 244 switch qid[1] { 245 case t.IDU8, t.IDU16, t.IDU32, t.IDU64: 246 b.printf("memcpy(%s, %s, sizeof(%s));\n", lhs, rhs, local) 247 return nil 248 } 249 } 250 } 251 252 return fmt.Errorf("cannot resume or suspend a local variable %q of type %q", 253 n.Name().Str(g.tm), n.XType().Str(g.tm)) 254} 255 256func (g *gen) writeResumeSuspend(b *buffer, f *funk, suspend bool) error { 257 for _, n := range f.varList { 258 if err := g.writeResumeSuspend1(b, f, n, suspend); err != nil { 259 return err 260 } 261 } 262 return nil 263} 264 265func (g *gen) writeVars(b *buffer, f *funk, inStructDecl bool) error { 266 for _, n := range f.varList { 267 typ := n.XType() 268 if inStructDecl { 269 if typ.HasPointers() || f.varResumables == nil || !f.varResumables[n.Name()] { 270 continue 271 } 272 } 273 274 name := n.Name().Str(g.tm) 275 276 if typ.IsIOType() { 277 b.printf("wuffs_base__io_buffer %s%s = wuffs_base__empty_io_buffer();\n", uPrefix, name) 278 } 279 280 if err := g.writeCTypeName(b, typ, vPrefix, name); err != nil { 281 return err 282 } 283 if inStructDecl { 284 b.writes(";\n") 285 } else if typ.IsNumType() { 286 b.writes(" = 0;\n") 287 } else if typ.IsBool() { 288 b.writes(" = false;\n") 289 } else if typ.IsStatus() { 290 b.writes(" = NULL;\n") 291 } else if typ.IsIOType() { 292 b.printf(" = &%s%s;\n", uPrefix, name) 293 } else { 294 b.writes(" = {0};\n") 295 } 296 297 if typ.IsIOType() { 298 b.printf("uint8_t* %s%s%s WUFFS_BASE__POTENTIALLY_UNUSED = NULL;\n", iopPrefix, vPrefix, name) 299 b.printf("uint8_t* %s%s%s WUFFS_BASE__POTENTIALLY_UNUSED = NULL;\n", io0Prefix, vPrefix, name) 300 b.printf("uint8_t* %s%s%s WUFFS_BASE__POTENTIALLY_UNUSED = NULL;\n", io1Prefix, vPrefix, name) 301 b.printf("uint8_t* %s%s%s WUFFS_BASE__POTENTIALLY_UNUSED = NULL;\n", io2Prefix, vPrefix, name) 302 } 303 } 304 return nil 305} 306