From 766f2d101fd4d91ab470b79fdf93cbc2fc72c515 Mon Sep 17 00:00:00 2001 From: Ondřej Surý Date: Thu, 6 Oct 2011 08:56:49 +0200 Subject: Imported Upstream version 60.2 --- doc/debugging_with_gdb.html | 479 +++++++++++++++++++++++++++++++++++++++++ doc/devel/release.html | 6 + doc/docs.html | 17 ++ doc/go_tutorial.html | 5 +- doc/go_tutorial.tmpl | 4 +- doc/install.html | 3 +- doc/root.html | 7 +- src/cmd/ld/dwarf.c | 2 +- src/pkg/image/draw/draw.go | 8 +- src/pkg/image/image.go | 3 + src/pkg/runtime/hashmap.c | 58 ++--- src/pkg/runtime/hashmap.h | 2 +- src/pkg/runtime/runtime-gdb.py | 4 +- 13 files changed, 553 insertions(+), 45 deletions(-) create mode 100644 doc/debugging_with_gdb.html diff --git a/doc/debugging_with_gdb.html b/doc/debugging_with_gdb.html new file mode 100644 index 000000000..04850c026 --- /dev/null +++ b/doc/debugging_with_gdb.html @@ -0,0 +1,479 @@ + + +

+This applies to the 6g toolchain. Gccgo has native gdb support. Besides this +overview you might want to consult the +GDB manual. +

+ +

Introduction

+ +

+When you compile and link your Go programs with the 6g/6l or 8g/8l toolchains +on Linux, Mac OSX or FreeBSD, the resulting binaries contain DWARFv3 +debugging information that recent versions (>7.1) of the GDB debugger can +use to inspect a live process or a core dump. +

+ +

+Pass the '-s' flag to the linker to omit the debug information. +

+ + +

Common Operations

+ + + + +

Go Extensions

+ +

+A recent extension mechanism to GDB allows it to load extension scripts for a +given binary. The tool chain uses this to extend GDB with a handful of +commands to inspect internals of the runtime code (such as goroutines) and to +pretty print the built-in map, slice and channel types. +

+ + + +

+If you'd like to see how this works, or want to extend it, take a look at src/pkg/runtime/runtime-gdb.py in +the Go source distribution. It depends on some special magic types +(hash<T,U>) and variables (runtime.m and +runtime.g) that the linker +(src/cmd/ld/dwarf.c) ensures are described in +the DWARF code. + +If you're interested in what the debugging information looks like, run +'objdump -W 6.out' and browse through the .debug_* +sections. +

+ + +

Known Issues

+ +
    +
  1. String pretty printing only triggers for type string, not for types derived +from it.
  2. +
  3. Type information is missing for the C parts of the runtime library.
  4. +
  5. GDB does not understand Go’s name qualifications and treats +"fmt.Print" as an unstructured literal with a "." +that needs to be quoted. It objects even more strongly to method names of +the form pkg.(*MyType).Meth. +
  6. All global variables are lumped into package "main".
  7. +
+ +

Tutorial

+ +

+In this tutorial we will inspect the binary of the +regexp package's unit tests. To build the binary, +change to $GOROOT/src/pkg/regexp and run gotest. +This should produce an executable file named 6.out. +

+ + +

Getting Started

+ +

+Launch GDB, debugging 6.out: +

+ +
+$ gdb 6.out
+GNU gdb (GDB) 7.2-gg8
+Copyright (C) 2010 Free Software Foundation, Inc.
+License GPLv  3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
+Type "show copying" and "show warranty" for licensing/warranty details.
+This GDB was configured as "x86_64-linux".
+
+Reading symbols from  /home/user/go/src/pkg/regexp/6.out...
+done.
+Loading Go Runtime support.
+(gdb) 
+
+ +

+The message "Loading Go Runtime support" means that GDB loaded the +extension from $GOROOT/src/pkg/runtime/runtime-gdb.py. +

+ +

+To help GDB find the Go runtime sources and the accompanying support script, +pass your $GOROOT with the '-d' flag: +

+ +
+$ gdb 6.out -d $GOROOT
+
+ +

+If for some reason GDB still can't find that directory or that script, you can load +it by hand by telling gdb (assuming you have the go sources in +~/go/): +

+ +

+(gdb) source ~/go/src/pkg/runtime/runtime-gdb.py
+Loading Go Runtime support.
+
+ +

Inspecting the source

+ +

+Use the "l" or "list" command to inspect source code. +

+ +
+(gdb) l
+
+ +

+List a specific part of the source parametrizing "list" with a +function name (it must be qualified with its package name). +

+ +
+(gdb) l main.main
+
+ +

+List a specific file and line number: +

+ +
+(gdb) l regexp.go:1
+(gdb) # Hit enter to repeat last command. Here, this lists next 10 lines.
+
+ + +

Naming

+ +

+Variable and function names must be qualified with the name of the packages +they belong to. The Compile function from the regexp +package is known to GDB as 'regexp.Compile'. +

+ +

+Methods must be qualified with the name of their receiver types. For example, +the *Regexp type’s doParse method is known as +'regexp.*Regexp.doParse'. (Note that the second dot is a "middot," +an artifact of Go’s internal representation of methods.) +

+ +

+Variables that shadow other variables are magically suffixed with a number in the debug info. +Variables referenced by closures will appear as pointers magically prefixed with '&'. +

+ +

Setting breakpoints

+ +

+Set a breakpoint at the TestFind function: +

+ +
+(gdb) b 'regexp.TestFind'
+Breakpoint 1 at 0x424908: file /home/user/go/src/pkg/regexp/find_test.go, line 148.
+
+ +

+Run the program: +

+ +
+(gdb) run
+Starting program: /home/lvd/g/src/pkg/regexp/6.out 
+
+Breakpoint 1, regexp.TestFind (t=0xf8404a89c0) at /home/user/go/src/pkg/regexp/find_test.go:148
+148	func TestFind(t *testing.T) {
+
+ +

+Execution has paused at the breakpoint. +See which goroutines are running, and what they're doing: +

+ +
+(gdb) info goroutines
+  1  waiting runtime.gosched
+* 13  running runtime.goexit
+
+ +

+the one marked with the * is the current goroutine. +

+ +

Inspecting the stack

+ +

+Look at the stack trace for where we’ve paused the program: +

+ +
+(gdb) bt  # backtrace
+#0  regexp.TestFind (t=0xf8404a89c0) at /home/user/go/src/pkg/regexp/find_test.go:148
+#1  0x000000000042f60b in testing.tRunner (t=0xf8404a89c0, test=0x573720) at /home/user/go/src/pkg/testing/testing.go:156
+#2  0x000000000040df64 in runtime.initdone () at /home/user/go/src/pkg/runtime/proc.c:242
+#3  0x000000f8404a89c0 in ?? ()
+#4  0x0000000000573720 in ?? ()
+#5  0x0000000000000000 in ?? ()
+
+ +

+The other goroutine, number 1, is stuck in runtime.gosched, blocked on a channel receive: +

+ +
+(gdb) goroutine 1 bt
+#0  0x000000000040facb in runtime.gosched () at /home/lvd/g/src/pkg/runtime/proc.c:873
+#1  0x00000000004031c9 in runtime.chanrecv (c=void, ep=void, selected=void, received=void)
+ at  /home/lvd/g/src/pkg/runtime/chan.c:342
+#2  0x0000000000403299 in runtime.chanrecv1 (t=void, c=void) at/home/lvd/g/src/pkg/runtime/chan.c:423
+#3  0x000000000043075b in testing.RunTests (matchString={void (struct string, struct string, bool *, os.Error *)} 0x7ffff7f9ef60, tests=  []testing.InternalTest = {...}) at /home/lvd/g/src/pkg/testing/testing.go:201
+#4  0x00000000004302b1 in testing.Main (matchString={void (struct string, struct string, bool *, os.Error *)} 0x7ffff7f9ef80, tests= []testing.InternalTest = {...}, benchmarks= []testing.InternalBenchmark = {...})
+    at /home/lvd/g/src/pkg/testing/testing.go:168
+#5  0x0000000000400dc1 in main.main () at /home/lvd/g/src/pkg/regexp/_testmain.go:98
+#6  0x00000000004022e7 in runtime.mainstart () at /home/lvd/g/src/pkg/runtime/amd64/asm.s:78
+#7  0x000000000040ea6f in runtime.initdone () at /home/lvd/g/src/pkg/runtime/proc.c:243
+#8  0x0000000000000000 in ?? ()
+
+ +

+The stack frame shows we’re currently executing the regexp.TestFind function, as expected. +

+ +
+(gdb) info frame
+Stack level 0, frame at 0x7ffff7f9ff88:
+ rip = 0x425530 in regexp.TestFind (/home/lvd/g/src/pkg/regexp/find_test.go:148); 
+    saved rip 0x430233
+ called by frame at 0x7ffff7f9ffa8
+ source language minimal.
+ Arglist at 0x7ffff7f9ff78, args: t=0xf840688b60
+ Locals at 0x7ffff7f9ff78, Previous frame's sp is 0x7ffff7f9ff88
+ Saved registers:
+  rip at 0x7ffff7f9ff80
+
+ +

+The command info locals lists all variables local to the function and their values, but is a bit +dangerous to use, since it will also try to print uninitialized variables. Uninitialized slices may cause gdb to try +to print arbitrary large arrays. +

+ +

+The function’s arguments: +

+ +
+(gdb) info args
+t = 0xf840688b60
+
+ +

+When printing the argument, notice that it’s a pointer to a +Regexp value. Note that GDB has incorrectly put the * +on the right-hand side of the type name and made up a 'struct' keyword, in traditional C style. +

+ +
+(gdb) p re
+(gdb) p t
+$1 = (struct testing.T *) 0xf840688b60
+(gdb) p t
+$1 = (struct testing.T *) 0xf840688b60
+(gdb) p *t
+$2 = {errors = "", failed = false, ch = 0xf8406f5690}
+(gdb) p *t->ch
+$3 = struct hchan<*testing.T>
+
+ +

+That struct hchan<*testing.T> is the runtime-internal represntation of a channel. It is currently empty, or gdb would have pretty-printed it's contents. +

+ +

+Stepping forward: +

+ +
+(gdb) n  # execute next line
+149             for _, test := range findTests {
+(gdb)    # enter is repeat
+150                     re := MustCompile(test.pat)
+(gdb) p test.pat
+$4 = ""
+(gdb) p re
+$5 = (struct regexp.Regexp *) 0xf84068d070
+(gdb) p *re
+$6 = {expr = "", prog = 0xf840688b80, prefix = "", prefixBytes =  []uint8, prefixComplete = true, 
+  prefixRune = 0, cond = 0 '\000', numSubexp = 0, longest = false, mu = {state = 0, sema = 0}, 
+  machine =  []*regexp.machine}
+(gdb) p *re->prog
+$7 = {Inst =  []regexp/syntax.Inst = {{Op = 5 '\005', Out = 0, Arg = 0, Rune =  []int}, {Op = 
+    6 '\006', Out = 2, Arg = 0, Rune =  []int}, {Op = 4 '\004', Out = 0, Arg = 0, Rune =  []int}}, 
+  Start = 1, NumCap = 2}
+
+ + +

+We can step into the Stringfunction call with "s": +

+ +
+(gdb) s
+regexp.(*Regexp).String (re=0xf84068d070, noname=void) at /home/lvd/g/src/pkg/regexp/regexp.go:97
+97      func (re *Regexp) String() string {
+
+ +

+Get a stack trace to see where we are: +

+ +
+(gdb) bt
+(gdb) bt
+#0  regexp.(*Regexp).String (re=0xf84068d070, noname=void)
+    at /home/lvd/g/src/pkg/regexp/regexp.go:97
+#1  0x0000000000425615 in regexp.TestFind (t=0xf840688b60)
+    at /home/lvd/g/src/pkg/regexp/find_test.go:151
+#2  0x0000000000430233 in testing.tRunner (t=0xf840688b60, test=0x5747b8)
+    at /home/lvd/g/src/pkg/testing/testing.go:156
+#3  0x000000000040ea6f in runtime.initdone () at /home/lvd/g/src/pkg/runtime/proc.c:243
+....
+
+ +

+Look at the source code: +

+ +
+(gdb) l
+92              mu      sync.Mutex
+93              machine []*machine
+94      }
+95
+96      // String returns the source text used to compile the regular expression.
+97      func (re *Regexp) String() string {
+98              return re.expr
+99      }
+100
+101     // Compile parses a regular expression and returns, if successful,
+
+ +

Pretty Printing

+ +

+GDB's pretty printing mechanism is triggered by regexp matches on type names. An example for slices: +

+ +
+(gdb) p utf
+$22 =  []uint8 = {0 '\000', 0 '\000', 0 '\000', 0 '\000'}
+
+ +

+Since slices, arrays and strings are not C pointers, GDB can't interpret the subscripting operation for you, but +you can look inside the runtime representation to do that (tab completion helps here): +

+
+
+(gdb) p slc
+$11 =  []int = {0, 0}
+(gdb) p slc-><TAB>
+array  slc    len    
+(gdb) p slc->array
+$12 = (int *) 0xf84057af00
+(gdb) p slc->array[1]
+$13 = 0
+ + + +

+The extension functions $len and $cap work on strings, arrays and slices: +

+ +
+(gdb) p $len(utf)
+$23 = 4
+(gdb) p $cap(utf)
+$24 = 4
+
+ +

+Channels and maps are 'reference' types, which gdb shows as pointers to C++-like types hash<int,string>*. Dereferencing will trigger prettyprinting +

+ +

+Interfaces are represented in the runtime as a pointer to a type descriptor and a pointer to a value. The Go GDB runtime extension decodes this and automatically triggers pretty printing for the runtime type. The extension function $dtype decodes the dynamic type for you (examples are taken from a breakpoint at regexp.go line 293.) +

+ +
+(gdb) p i
+$4 = {str = "cbb"}
+(gdb) whatis i
+type = regexp.input
+(gdb) p $dtype(i)
+$26 = (struct regexp.inputBytes *) 0xf8400b4930
+(gdb) iface i
+regexp.input: struct regexp.inputBytes *
+
diff --git a/doc/devel/release.html b/doc/devel/release.html index 4ce3d37c1..d6de1d71c 100644 --- a/doc/devel/release.html +++ b/doc/devel/release.html @@ -104,6 +104,12 @@ a new option.

+

+r60.2 +fixes +a memory leak involving maps. +

+

r59 (released 2011/08/01)

diff --git a/doc/docs.html b/doc/docs.html index ce833fdd1..a86d1714e 100644 --- a/doc/docs.html +++ b/doc/docs.html @@ -16,6 +16,16 @@ Once you've learned a little about the language, idioms of programming in Go.

+

A Tour of Go

+

+An interactive introduction to Go in three sections. +The first section covers basic syntax and data structures; the second discusses +methods and interfaces; and the third introduces Go's concurrency primitives. +Each section concludes with a few exercises so you can practice what you've +learned. You can take the tour online or +install it locally. +

+

A Tutorial for the Go Programming Language

The first tutorial. An introductory text that touches upon several core @@ -97,6 +107,8 @@ Notable articles from the Go Blog.

  • JSON and Go - using the json package.
  • Gobs of data - the design and use of the gob package.
  • The Laws of Reflection - the fundamentals of the reflect package.
  • +
  • The Go image package - the fundamentals of the image package.
  • +
  • The Go image/draw package - the fundamentals of the image/draw package.
  • Tools

    @@ -179,6 +191,11 @@ one goroutine can be guaranteed to observe values produced by writes to the same variable in a different goroutine.

    +

    Debugging Go Code with GDB

    +

    +Using GDB to debug Go programs. +

    +

    Videos and Talks

    Writing Web Apps in Go

    diff --git a/doc/go_tutorial.html b/doc/go_tutorial.html index 0b366bb2b..8f6e07b06 100644 --- a/doc/go_tutorial.html +++ b/doc/go_tutorial.html @@ -95,7 +95,7 @@ Here's how to compile and run our program. With 6g, say,
     $ 6g helloworld.go  # compile; object goes into helloworld.6
     $ 6l helloworld.6   # link; output goes into 6.out
    -$ 6.out
    +$ ./6.out
     Hello, world; or Καλημέρα κόσμε; or こんにちは 世界
     $
     
    @@ -544,13 +544,12 @@ composite literal, as is done here in the return statement from We can use the factory to construct some familiar, exported variables of type *File:

    -

    var (
         Stdin  = newFile(syscall.Stdin, "/dev/stdin")
         Stdout = newFile(syscall.Stdout, "/dev/stdout")
         Stderr = newFile(syscall.Stderr, "/dev/stderr")
     )
    -
     

    The newFile function was not exported because it's internal. The proper, diff --git a/doc/go_tutorial.tmpl b/doc/go_tutorial.tmpl index c170c25aa..15f87ca4b 100644 --- a/doc/go_tutorial.tmpl +++ b/doc/go_tutorial.tmpl @@ -87,7 +87,7 @@ Here's how to compile and run our program. With 6g, say,

     $ 6g helloworld.go  # compile; object goes into helloworld.6
     $ 6l helloworld.6   # link; output goes into 6.out
    -$ 6.out
    +$ ./6.out
     Hello, world; or Καλημέρα κόσμε; or こんにちは 世界
     $
     
    @@ -470,7 +470,7 @@ composite literal, as is done here in the return statement from We can use the factory to construct some familiar, exported variables of type *File:

    -{{code "progs/file.go" `/var/` `/^.$/`}} +{{code "progs/file.go" `/var/` `/^\)/`}}

    The newFile function was not exported because it's internal. The proper, exported factory to use is OpenFile (we'll explain that name in a moment): diff --git a/doc/install.html b/doc/install.html index a1bc89982..c47f9218b 100644 --- a/doc/install.html +++ b/doc/install.html @@ -257,7 +257,8 @@ the process of building and testing Go programs.

    What's next

    -Start by reading the Go Tutorial. +Start by taking A Tour of Go +or reading the Go Tutorial.

    diff --git a/doc/root.html b/doc/root.html index 8d76928c8..2d9a8979b 100644 --- a/doc/root.html +++ b/doc/root.html @@ -49,10 +49,13 @@ google.setOnLoadCallback(loadFeed); It's a fast, statically typed, compiled language that feels like a dynamically typed, interpreted language.

    -

    Check it out!

    +

    + Get started now with + A Tour of Go. +

    - Install Go now, or try it right here in your browser:

    + Or try it right here in your browser:

    diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c index 77536018a..373cf5523 100644 --- a/src/cmd/ld/dwarf.c +++ b/src/cmd/ld/dwarf.c @@ -1356,7 +1356,7 @@ synthesizemaptypes(DWDie *die) getattr(keytype, DW_AT_name)->data, getattr(valtype, DW_AT_name)->data)); copychildren(dwhs, hash_subtable); - substitutetype(dwhs, "end", defptrto(dwhe)); + substitutetype(dwhs, "last", defptrto(dwhe)); substitutetype(dwhs, "entry", dwhe); // todo: []hash_entry with dynamic size newattr(dwhs, DW_AT_byte_size, DW_CLS_CONSTANT, getattr(hash_subtable, DW_AT_byte_size)->value, nil); diff --git a/src/pkg/image/draw/draw.go b/src/pkg/image/draw/draw.go index a748ff8c7..5171e03b1 100644 --- a/src/pkg/image/draw/draw.go +++ b/src/pkg/image/draw/draw.go @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package draw provides image composition functions -// in the style of the Plan 9 graphics library -// (see http://plan9.bell-labs.com/magic/man2html/2/draw) -// and the X Render extension. +// Package draw provides image composition functions. +// +// See "The Go image/draw package" for an introduction to this package: +// http://blog.golang.org/2011/09/go-imagedraw-package.html package draw import ( diff --git a/src/pkg/image/image.go b/src/pkg/image/image.go index 11def9435..7c7a4b7a7 100644 --- a/src/pkg/image/image.go +++ b/src/pkg/image/image.go @@ -3,6 +3,9 @@ // license that can be found in the LICENSE file. // Package image implements a basic 2-D image library. +// +// See "The Go image package" for an introduction to this package: +// http://blog.golang.org/2011/09/go-image-package.html package image // Config holds an image's color model and dimensions. diff --git a/src/pkg/runtime/hashmap.c b/src/pkg/runtime/hashmap.c index 0c0e3e4a2..22664b548 100644 --- a/src/pkg/runtime/hashmap.c +++ b/src/pkg/runtime/hashmap.c @@ -54,7 +54,7 @@ struct hash_subtable { uint8 datasize; /* bytes of client data in an entry */ uint8 max_probes; /* max number of probes when searching */ int16 limit_bytes; /* max_probes * (datasize+sizeof (hash_hash_t)) */ - struct hash_entry *end; /* points just past end of entry[] */ + struct hash_entry *last; /* points to last element of entry[] */ struct hash_entry entry[1]; /* 2**power+max_probes-1 elements of elemsize bytes */ }; @@ -101,7 +101,7 @@ hash_subtable_new (Hmap *h, int32 power, int32 used) st->datasize = h->datasize; st->max_probes = max_probes; st->limit_bytes = limit_bytes; - st->end = HASH_OFFSET (st->entry, bytes); + st->last = HASH_OFFSET (st->entry, bytes) - 1; memset (st->entry, HASH_NIL_MEMSET, bytes); return (st); } @@ -160,7 +160,7 @@ hash_remove_n (struct hash_subtable *st, struct hash_entry *dst_e, int32 n) { int32 elemsize = st->datasize + offsetof (struct hash_entry, data[0]); struct hash_entry *src_e = HASH_OFFSET (dst_e, n * elemsize); - struct hash_entry *end_e = st->end; + struct hash_entry *last_e = st->last; int32 shift = HASH_BITS - (st->power + st->used); int32 index_mask = (((hash_hash_t)1) << st->power) - 1; int32 dst_i = (((byte *) dst_e) - ((byte *) st->entry)) / elemsize; @@ -170,10 +170,10 @@ hash_remove_n (struct hash_subtable *st, struct hash_entry *dst_e, int32 n) int32 bytes; while (dst_e != src_e) { - if (src_e != end_e) { + if (src_e <= last_e) { struct hash_entry *cp_e = src_e; int32 save_dst_i = dst_i; - while (cp_e != end_e && (hash = cp_e->hash) != HASH_NIL && + while (cp_e <= last_e && (hash = cp_e->hash) != HASH_NIL && ((hash >> shift) & index_mask) <= dst_i) { cp_e = HASH_OFFSET (cp_e, elemsize); dst_i++; @@ -183,7 +183,7 @@ hash_remove_n (struct hash_subtable *st, struct hash_entry *dst_e, int32 n) dst_e = HASH_OFFSET (dst_e, bytes); src_e = cp_e; src_i += dst_i - save_dst_i; - if (src_e != end_e && (hash = src_e->hash) != HASH_NIL) { + if (src_e <= last_e && (hash = src_e->hash) != HASH_NIL) { skip = ((hash >> shift) & index_mask) - dst_i; } else { skip = src_i - dst_i; @@ -224,7 +224,7 @@ hash_conv (Hmap *h, } de = e; - while (e != st->end && + while (e <= st->last && (e_hash = e->hash) != HASH_NIL && (e_hash & HASH_MASK) != HASH_SUBHASH) { struct hash_entry *target_e = HASH_OFFSET (st->entry, ((e_hash >> shift) & index_mask) * elemsize); @@ -235,14 +235,14 @@ hash_conv (Hmap *h, de = target_e; } if ((hash & prefix_mask) == current || - (ne != st->end && (e_hash = ne->hash) != HASH_NIL && + (ne <= st->last && (e_hash = ne->hash) != HASH_NIL && (e_hash & prefix_mask) == current)) { struct hash_subtable *new_st = hash_subtable_new (h, 1, HASH_USED (new_flags)); int32 rc = hash_insert_internal (&new_st, new_flags, e->hash, h, e->data, &dummy_result); assert (rc == 0); memcpy(dummy_result, e->data, h->datasize); e = ne; - while (e != st->end && (e_hash = e->hash) != HASH_NIL && (e_hash & prefix_mask) == current) { + while (e <= st->last && (e_hash = e->hash) != HASH_NIL && (e_hash & prefix_mask) == current) { assert ((e_hash & HASH_MASK) != HASH_SUBHASH); rc = hash_insert_internal (&new_st, new_flags, e_hash, h, e->data, &dummy_result); assert (rc == 0); @@ -271,13 +271,13 @@ hash_grow (Hmap *h, struct hash_subtable **pst, int32 flags) struct hash_subtable *old_st = *pst; int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]); *pst = hash_subtable_new (h, old_st->power + 1, HASH_USED (flags)); - struct hash_entry *end_e = old_st->end; + struct hash_entry *last_e = old_st->last; struct hash_entry *e; void *dummy_result; int32 used = 0; flags |= HASH_REHASH; - for (e = old_st->entry; e != end_e; e = HASH_OFFSET (e, elemsize)) { + for (e = old_st->entry; e <= last_e; e = HASH_OFFSET (e, elemsize)) { hash_hash_t hash = e->hash; if (hash != HASH_NIL) { int32 rc = hash_insert_internal (pst, flags, e->hash, h, e->data, &dummy_result); @@ -428,13 +428,13 @@ hash_insert_internal (struct hash_subtable **pst, int32 flags, hash_hash_t hash, ins_e_hash = 0; /* move ins_e to point at the end of the contiguous block, but stop if any element can't be moved by one up */ - while (ins_e != st->end && (ins_e_hash = ins_e->hash) != HASH_NIL && + while (ins_e <= st->last && (ins_e_hash = ins_e->hash) != HASH_NIL && ins_i + 1 - ((ins_e_hash >> shift) & index_mask) < st->max_probes && (ins_e_hash & HASH_MASK) != HASH_SUBHASH) { ins_e = HASH_OFFSET (ins_e, elemsize); ins_i++; } - if (e == end_e || ins_e == st->end || ins_e_hash != HASH_NIL) { + if (e == end_e || ins_e > st->last || ins_e_hash != HASH_NIL) { e = end_e; /* can't insert; must grow or convert to subtable */ } else { /* make space for element */ memmove (HASH_OFFSET (e, elemsize), e, ((byte *) ins_e) - (byte *) e); @@ -477,17 +477,17 @@ iter_restart (struct hash_iter *it, struct hash_subtable *st, int32 used) struct hash_entry *e; hash_hash_t e_hash; struct hash_iter_sub *sub = &it->subtable_state[it->i]; - struct hash_entry *end; + struct hash_entry *last; for (;;) { int32 shift = HASH_BITS - (st->power + used); int32 index_mask = (1 << st->power) - 1; int32 i = (last_hash >> shift) & index_mask; - end = st->end; + last = st->last; e = HASH_OFFSET (st->entry, i * elemsize); sub->start = st->entry; - sub->end = end; + sub->last = last; if ((e->hash & HASH_MASK) != HASH_SUBHASH) { break; @@ -497,7 +497,7 @@ iter_restart (struct hash_iter *it, struct hash_subtable *st, int32 used) used += st->power; st = *(struct hash_subtable **)e->data; } - while (e != end && ((e_hash = e->hash) == HASH_NIL || e_hash <= last_hash)) { + while (e <= last && ((e_hash = e->hash) == HASH_NIL || e_hash <= last_hash)) { e = HASH_OFFSET (e, elemsize); } sub->e = e; @@ -509,7 +509,7 @@ hash_next (struct hash_iter *it) int32 elemsize = it->elemsize; struct hash_iter_sub *sub = &it->subtable_state[it->i]; struct hash_entry *e = sub->e; - struct hash_entry *end = sub->end; + struct hash_entry *last = sub->last; hash_hash_t e_hash = 0; if (it->changes != it->h->changes) { /* hash table's structure changed; recompute */ @@ -518,7 +518,7 @@ hash_next (struct hash_iter *it) iter_restart (it, it->h->st, 0); sub = &it->subtable_state[it->i]; e = sub->e; - end = sub->end; + last = sub->last; } if (e != sub->start && it->last_hash != HASH_OFFSET (e, -elemsize)->hash) { struct hash_entry *start = HASH_OFFSET (e, -(elemsize * it->h->max_probes)); @@ -531,16 +531,16 @@ hash_next (struct hash_iter *it) e = pe; pe = HASH_OFFSET (pe, -elemsize); } - while (e != end && ((e_hash = e->hash) == HASH_NIL || e_hash <= last_hash)) { + while (e <= last && ((e_hash = e->hash) == HASH_NIL || e_hash <= last_hash)) { e = HASH_OFFSET (e, elemsize); } } for (;;) { - while (e != end && (e_hash = e->hash) == HASH_NIL) { + while (e <= last && (e_hash = e->hash) == HASH_NIL) { e = HASH_OFFSET (e, elemsize); } - if (e == end) { + if (e > last) { if (it->i == 0) { it->last_hash = HASH_OFFSET (e, -elemsize)->hash; sub->e = e; @@ -549,7 +549,7 @@ hash_next (struct hash_iter *it) it->i--; sub = &it->subtable_state[it->i]; e = sub->e; - end = sub->end; + last = sub->last; } } else if ((e_hash & HASH_MASK) != HASH_SUBHASH) { it->last_hash = e->hash; @@ -565,7 +565,7 @@ hash_next (struct hash_iter *it) sub = &it->subtable_state[it->i]; sub->e = e = st->entry; sub->start = st->entry; - sub->end = end = st->end; + sub->last = last = st->last; } } } @@ -580,7 +580,7 @@ hash_iter_init (Hmap *h, struct hash_iter *it) it->last_hash = 0; it->subtable_state[0].e = h->st->entry; it->subtable_state[0].start = h->st->entry; - it->subtable_state[0].end = h->st->end; + it->subtable_state[0].last = h->st->last; } static void @@ -588,11 +588,11 @@ clean_st (struct hash_subtable *st, int32 *slots, int32 *used) { int32 elemsize = st->datasize + offsetof (struct hash_entry, data[0]); struct hash_entry *e = st->entry; - struct hash_entry *end = st->end; - int32 lslots = (((byte *) end) - (byte *) e) / elemsize; + struct hash_entry *last = st->last; + int32 lslots = (((byte *) (last+1)) - (byte *) e) / elemsize; int32 lused = 0; - while (e != end) { + while (e <= last) { hash_hash_t hash = e->hash; if ((hash & HASH_MASK) == HASH_SUBHASH) { clean_st (*(struct hash_subtable **)e->data, slots, used); @@ -627,7 +627,7 @@ hash_visit_internal (struct hash_subtable *st, int32 shift = HASH_BITS - (used + st->power); int32 i = 0; - while (e != st->end) { + while (e <= st->last) { int32 index = ((e->hash >> (shift - 1)) >> 1) & ((1 << st->power) - 1); if ((e->hash & HASH_MASK) == HASH_SUBHASH) { (*data_visit) (arg, level, e->data); diff --git a/src/pkg/runtime/hashmap.h b/src/pkg/runtime/hashmap.h index 19ff41697..81b0cff88 100644 --- a/src/pkg/runtime/hashmap.h +++ b/src/pkg/runtime/hashmap.h @@ -87,7 +87,7 @@ struct hash_iter { struct hash_iter_sub { struct hash_entry *e; /* pointer into subtable */ struct hash_entry *start; /* start of subtable */ - struct hash_entry *end; /* end of subtable */ + struct hash_entry *last; /* last entry in subtable */ } subtable_state[4]; /* Should be large enough unless the hashing is so bad that many distinct data values hash to the same hash value. */ diff --git a/src/pkg/runtime/runtime-gdb.py b/src/pkg/runtime/runtime-gdb.py index a96f3f382..b74705e5f 100644 --- a/src/pkg/runtime/runtime-gdb.py +++ b/src/pkg/runtime/runtime-gdb.py @@ -91,8 +91,8 @@ class MapTypePrinter: def traverse_hash(self, stab): ptr = stab['entry'].address - end = stab['end'] - while ptr < end: + last = stab['last'] + while ptr <= last: v = ptr.dereference() ptr = ptr + 1 if v['hash'] == 0: continue -- cgit v1.2.3