diff --git a/compiler/expressions.go b/compiler/expressions.go index 2768e3d2a..622101997 100644 --- a/compiler/expressions.go +++ b/compiler/expressions.go @@ -1058,6 +1058,9 @@ func (fc *funcContext) translateBuiltin(name string, sig *types.Signature, args case "Offsetof": sel, _ := fc.selectionOf(astutil.RemoveParens(args[0]).(*ast.SelectorExpr)) return fc.formatExpr("%d", typesutil.OffsetOf(sizes32, sel)) + case "SliceData": + t := fc.typeOf(args[0]).Underlying().(*types.Slice) + return fc.formatExpr(`$sliceData(%e, %s)`, args[0], fc.typeName(t)) default: panic(fmt.Sprintf("Unhandled builtin: %s\n", name)) } diff --git a/compiler/prelude/prelude.js b/compiler/prelude/prelude.js index d35de6b01..0f6b9cb80 100644 --- a/compiler/prelude/prelude.js +++ b/compiler/prelude/prelude.js @@ -569,3 +569,10 @@ var $instanceOf = (x, y) => { var $typeOf = x => { return typeof (x); }; + +var $sliceData = (slice, typ) => { + if (slice === typ.nil) { + return $ptrType(typ.elem).nil; + } + return $indexPtr(slice.$array, slice.$offset, typ.elem); +}; diff --git a/tests/js_test.go b/tests/js_test.go index 2ce43865f..ebebeca2a 100644 --- a/tests/js_test.go +++ b/tests/js_test.go @@ -9,6 +9,7 @@ import ( "strings" "testing" "time" + "unsafe" "github.com/google/go-cmp/cmp" "github.com/gopherjs/gopherjs/js" @@ -936,3 +937,41 @@ func TestStructWithNonIdentifierJSTag(t *testing.T) { t.Errorf("value via js.Object.Get gave %q, want %q", got, want) } } + +func TestSliceData(t *testing.T) { + var ( + s0 = []int(nil) + s1 = []int{} + s2 = []int{1, 2, 3} + s3 = s2[1:] + s4 = []int{4, 5, 6} + + sd0 = unsafe.SliceData(s0) + sd1 = unsafe.SliceData(s1) + sd2 = unsafe.SliceData(s2) + sd3 = unsafe.SliceData(s3) + sd4 = unsafe.SliceData(s4) + ) + + if sd0 != nil { + t.Errorf("slice data for nil slice was not nil") + } + if sd1 == nil { + t.Errorf("slice data for empty slice was nil") + } + if sd2 == nil { + t.Errorf("slice data for non-empty slice was nil") + } + if sd3 == nil { + t.Errorf("slice data for sub-slice was nil") + } + if sd1 == sd2 { + t.Errorf("slice data for empty and non-empty slices were the same") + } + if sd2 == sd3 { + t.Errorf("slice data for slice and sub-slice were the same") + } + if sd2 == sd4 { + t.Errorf("slice data for different slices were the same") + } +}