@@ -4,21 +4,17 @@ package interp
4
4
// functions.
5
5
6
6
import (
7
- "errors"
8
7
"strings"
9
8
10
9
"tinygo.org/x/go-llvm"
11
10
)
12
11
13
12
type frame struct {
14
- * Eval
15
- fn llvm.Value
16
- pkgName string
17
- locals map [llvm.Value ]Value
13
+ * evalPackage
14
+ fn llvm.Value
15
+ locals map [llvm.Value ]Value
18
16
}
19
17
20
- var ErrUnreachable = errors .New ("interp: unreachable executed" )
21
-
22
18
// evalBasicBlock evaluates a single basic block, returning the return value (if
23
19
// ending with a ret instruction), a list of outgoing basic blocks (if not
24
20
// ending with a ret instruction), or an error on failure.
@@ -79,13 +75,13 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
79
75
fr .locals [inst ] = & LocalValue {fr .Eval , fr .builder .CreateXor (lhs , rhs , "" )}
80
76
81
77
default :
82
- return nil , nil , & Unsupported { inst }
78
+ return nil , nil , fr . unsupportedInstructionError ( inst )
83
79
}
84
80
85
81
// Memory operators
86
82
case ! inst .IsAAllocaInst ().IsNil ():
87
83
allocType := inst .Type ().ElementType ()
88
- alloca := llvm .AddGlobal (fr .Mod , allocType , fr .pkgName + "$alloca" )
84
+ alloca := llvm .AddGlobal (fr .Mod , allocType , fr .packagePath + "$alloca" )
89
85
alloca .SetInitializer (llvm .ConstNull (allocType ))
90
86
alloca .SetLinkage (llvm .InternalLinkage )
91
87
fr .locals [inst ] = & LocalValue {
@@ -247,12 +243,12 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
247
243
if size != typeSize {
248
244
// allocate an array
249
245
if size % typeSize != 0 {
250
- return nil , nil , & Unsupported { inst }
246
+ return nil , nil , fr . unsupportedInstructionError ( inst )
251
247
}
252
248
elementCount = int (size / typeSize )
253
249
allocType = llvm .ArrayType (allocType , elementCount )
254
250
}
255
- alloc := llvm .AddGlobal (fr .Mod , allocType , fr .pkgName + "$alloc" )
251
+ alloc := llvm .AddGlobal (fr .Mod , allocType , fr .packagePath + "$alloc" )
256
252
alloc .SetInitializer (llvm .ConstNull (allocType ))
257
253
alloc .SetLinkage (llvm .InternalLinkage )
258
254
result := & LocalValue {
@@ -270,13 +266,16 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
270
266
valueSize := inst .Operand (1 ).ZExtValue ()
271
267
fr .locals [inst ] = & MapValue {
272
268
Eval : fr .Eval ,
273
- PkgName : fr .pkgName ,
269
+ PkgName : fr .packagePath ,
274
270
KeySize : int (keySize ),
275
271
ValueSize : int (valueSize ),
276
272
}
277
273
case callee .Name () == "runtime.hashmapStringSet" :
278
274
// set a string key in the map
279
- m := fr .getLocal (inst .Operand (0 )).(* MapValue )
275
+ m , ok := fr .getLocal (inst .Operand (0 )).(* MapValue )
276
+ if ! ok {
277
+ return nil , nil , fr .errorAt (inst , "could not update map with string key" )
278
+ }
280
279
// "key" is a Go string value, which in the TinyGo calling convention is split up
281
280
// into separate pointer and length parameters.
282
281
keyBuf := fr .getLocal (inst .Operand (1 )).(* LocalValue )
@@ -285,7 +284,10 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
285
284
m .PutString (keyBuf , keyLen , valPtr )
286
285
case callee .Name () == "runtime.hashmapBinarySet" :
287
286
// set a binary (int etc.) key in the map
288
- m := fr .getLocal (inst .Operand (0 )).(* MapValue )
287
+ m , ok := fr .getLocal (inst .Operand (0 )).(* MapValue )
288
+ if ! ok {
289
+ return nil , nil , fr .errorAt (inst , "could not update map" )
290
+ }
289
291
keyBuf := fr .getLocal (inst .Operand (1 )).(* LocalValue )
290
292
valPtr := fr .getLocal (inst .Operand (2 )).(* LocalValue )
291
293
m .PutBinary (keyBuf , valPtr )
@@ -304,7 +306,7 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
304
306
}
305
307
globalType := llvm .ArrayType (fr .Mod .Context ().Int8Type (), len (result ))
306
308
globalValue := llvm .ConstArray (fr .Mod .Context ().Int8Type (), vals )
307
- global := llvm .AddGlobal (fr .Mod , globalType , fr .pkgName + "$stringconcat" )
309
+ global := llvm .AddGlobal (fr .Mod , globalType , fr .packagePath + "$stringconcat" )
308
310
global .SetInitializer (globalValue )
309
311
global .SetLinkage (llvm .InternalLinkage )
310
312
global .SetGlobalConstant (true )
@@ -336,20 +338,20 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
336
338
srcArray = srcArray .GetElementPtr ([]uint32 {0 , 0 }).(* LocalValue )
337
339
}
338
340
if fr .Eval .TargetData .TypeAllocSize (dstArray .Type ().ElementType ()) != elementSize {
339
- return nil , nil , errors . New ( "interp: slice dst element size does not match pointer type" )
341
+ return nil , nil , fr . errorAt ( inst , "interp: slice dst element size does not match pointer type" )
340
342
}
341
343
if fr .Eval .TargetData .TypeAllocSize (srcArray .Type ().ElementType ()) != elementSize {
342
- return nil , nil , errors . New ( "interp: slice src element size does not match pointer type" )
344
+ return nil , nil , fr . errorAt ( inst , "interp: slice src element size does not match pointer type" )
343
345
}
344
346
if dstArray .Type () != srcArray .Type () {
345
- return nil , nil , errors . New ( "interp: slice element types don't match" )
347
+ return nil , nil , fr . errorAt ( inst , "interp: slice element types don't match" )
346
348
}
347
349
length := dstLen .Value ().SExtValue ()
348
350
if srcLength := srcLen .Value ().SExtValue (); srcLength < length {
349
351
length = srcLength
350
352
}
351
353
if length < 0 {
352
- return nil , nil , errors . New ( "interp: trying to copy a slice with negative length?" )
354
+ return nil , nil , fr . errorAt ( inst , "interp: trying to copy a slice with negative length?" )
353
355
}
354
356
for i := int64 (0 ); i < length ; i ++ {
355
357
// *dst = *src
@@ -370,7 +372,7 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
370
372
}
371
373
globalType := llvm .ArrayType (fr .Mod .Context ().Int8Type (), len (result ))
372
374
globalValue := llvm .ConstArray (fr .Mod .Context ().Int8Type (), vals )
373
- global := llvm .AddGlobal (fr .Mod , globalType , fr .pkgName + "$bytes" )
375
+ global := llvm .AddGlobal (fr .Mod , globalType , fr .packagePath + "$bytes" )
374
376
global .SetInitializer (globalValue )
375
377
global .SetLinkage (llvm .InternalLinkage )
376
378
global .SetGlobalConstant (true )
@@ -489,7 +491,7 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
489
491
// compile time.
490
492
// * Unbounded: cannot call at runtime so we'll try to
491
493
// interpret anyway and hope for the best.
492
- ret , err = fr .function (callee , params , fr . pkgName , indent + " " )
494
+ ret , err = fr .function (callee , params , indent + " " )
493
495
if err != nil {
494
496
return nil , nil , err
495
497
}
@@ -499,7 +501,7 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
499
501
}
500
502
default :
501
503
// function pointers, etc.
502
- return nil , nil , & Unsupported { inst }
504
+ return nil , nil , fr . unsupportedInstructionError ( inst )
503
505
}
504
506
case ! inst .IsAExtractValueInst ().IsNil ():
505
507
agg := fr .getLocal (inst .Operand (0 )).(* LocalValue ) // must be constant
@@ -509,7 +511,7 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
509
511
fr .locals [inst ] = fr .getValue (newValue )
510
512
} else {
511
513
if len (indices ) != 1 {
512
- return nil , nil , errors . New ( " cannot handle extractvalue with not exactly 1 index" )
514
+ return nil , nil , fr . errorAt ( inst , "interp: cannot handle extractvalue with not exactly 1 index" )
513
515
}
514
516
fr .locals [inst ] = & LocalValue {fr .Eval , fr .builder .CreateExtractValue (agg .Underlying , int (indices [0 ]), inst .Name ())}
515
517
}
@@ -522,7 +524,7 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
522
524
fr .locals [inst ] = & LocalValue {fr .Eval , newValue }
523
525
} else {
524
526
if len (indices ) != 1 {
525
- return nil , nil , errors . New ( " cannot handle insertvalue with not exactly 1 index" )
527
+ return nil , nil , fr . errorAt ( inst , "interp: cannot handle insertvalue with not exactly 1 index" )
526
528
}
527
529
fr .locals [inst ] = & LocalValue {fr .Eval , fr .builder .CreateInsertValue (agg .Underlying , val .Value (), int (indices [0 ]), inst .Name ())}
528
530
}
@@ -540,12 +542,12 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
540
542
thenBB := inst .Operand (1 )
541
543
elseBB := inst .Operand (2 )
542
544
if ! cond .IsAInstruction ().IsNil () {
543
- return nil , nil , errors . New ( "interp: branch on a non-constant" )
545
+ return nil , nil , fr . errorAt ( inst , "interp: branch on a non-constant" )
544
546
}
545
547
if ! cond .IsAConstantExpr ().IsNil () {
546
548
// This may happen when the instruction builder could not
547
549
// const-fold some instructions.
548
- return nil , nil , errors . New ( "interp: branch on a non-const-propagated constant expression" )
550
+ return nil , nil , fr . errorAt ( inst , "interp: branch on a non-const-propagated constant expression" )
549
551
}
550
552
switch cond {
551
553
case llvm .ConstInt (fr .Mod .Context ().Int1Type (), 0 , false ): // false
@@ -561,10 +563,11 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
561
563
case ! inst .IsAUnreachableInst ().IsNil ():
562
564
// Unreachable was reached (e.g. after a call to panic()).
563
565
// Report this as an error, as it is not supposed to happen.
564
- return nil , nil , ErrUnreachable
566
+ // This is a sentinel error value.
567
+ return nil , nil , errUnreachable
565
568
566
569
default :
567
- return nil , nil , & Unsupported { inst }
570
+ return nil , nil , fr . unsupportedInstructionError ( inst )
568
571
}
569
572
}
570
573
0 commit comments