github.com/google/grumpy@v0.0.0-20171122020858-3ec87959189c/runtime/dict.go (about)

     1  // Copyright 2016 Google Inc. All Rights Reserved.
     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  //     http://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  
    15  package grumpy
    16  
    17  import (
    18  	"bytes"
    19  	"fmt"
    20  	"reflect"
    21  	"sync/atomic"
    22  	"unsafe"
    23  )
    24  
    25  var (
    26  	// DictType is the object representing the Python 'dict' type.
    27  	DictType              = newBasisType("dict", reflect.TypeOf(Dict{}), toDictUnsafe, ObjectType)
    28  	dictItemIteratorType  = newBasisType("dictionary-itemiterator", reflect.TypeOf(dictItemIterator{}), toDictItemIteratorUnsafe, ObjectType)
    29  	dictKeyIteratorType   = newBasisType("dictionary-keyiterator", reflect.TypeOf(dictKeyIterator{}), toDictKeyIteratorUnsafe, ObjectType)
    30  	dictValueIteratorType = newBasisType("dictionary-valueiterator", reflect.TypeOf(dictValueIterator{}), toDictValueIteratorUnsafe, ObjectType)
    31  	deletedEntry          = &dictEntry{}
    32  )
    33  
    34  const (
    35  	// maxDictSize is the largest number of entries a dictionary can hold.
    36  	// Dict sizes must be a power of two and this is the largest such
    37  	// number representable as int32.
    38  	maxDictSize = 1 << 30
    39  	minDictSize = 8
    40  )
    41  
    42  // dictEntry represents a slot in the hash table of a Dict. Entries are
    43  // intended to be immutable so that they can be read atomically.
    44  type dictEntry struct {
    45  	hash  int
    46  	key   *Object
    47  	value *Object
    48  }
    49  
    50  // dictTable is the hash table underlying Dict.
    51  type dictTable struct {
    52  	// used is the number of slots in the entries table that contain values.
    53  	used int32
    54  	// fill is the number of slots that are used or once were used but have
    55  	// since been cleared. Thus used <= fill <= len(entries).
    56  	fill int
    57  	// entries is a slice of immutable dict entries. Although elements in
    58  	// the slice will be modified to point to different dictEntry objects
    59  	// as the dictionary is updated, the slice itself (i.e. location in
    60  	// memory and size) will not change for the lifetime of a dictTable.
    61  	// When the table is no longer large enough to hold a dict's contents,
    62  	// a new dictTable will be created.
    63  	entries []*dictEntry
    64  }
    65  
    66  // newDictTable allocates a table where at least minCapacity entries can be
    67  // accommodated. minCapacity must be <= maxDictSize.
    68  func newDictTable(minCapacity int) *dictTable {
    69  	// This takes the given capacity and sets all bits less than the highest bit.
    70  	// Adding 1 to that value causes the number to become a multiple of 2 again.
    71  	// The minDictSize is mixed in to make sure the resulting value is at least
    72  	// that big. This implementation makes the function able to be inlined, as
    73  	// well as allows for complete evaluation of constants at compile time.
    74  	numEntries := (minDictSize - 1) | minCapacity
    75  	numEntries |= numEntries >> 1
    76  	numEntries |= numEntries >> 2
    77  	numEntries |= numEntries >> 4
    78  	numEntries |= numEntries >> 8
    79  	numEntries |= numEntries >> 16
    80  	return &dictTable{entries: make([]*dictEntry, numEntries+1)}
    81  }
    82  
    83  // loadEntry atomically loads the i'th entry in t and returns it.
    84  func (t *dictTable) loadEntry(i int) *dictEntry {
    85  	p := (*unsafe.Pointer)(unsafe.Pointer(&t.entries[i]))
    86  	return (*dictEntry)(atomic.LoadPointer(p))
    87  }
    88  
    89  // storeEntry atomically sets the i'th entry in t to entry.
    90  func (t *dictTable) storeEntry(i int, entry *dictEntry) {
    91  	p := (*unsafe.Pointer)(unsafe.Pointer(&t.entries[i]))
    92  	atomic.StorePointer(p, unsafe.Pointer(entry))
    93  }
    94  
    95  func (t *dictTable) loadUsed() int {
    96  	return int(atomic.LoadInt32(&t.used))
    97  }
    98  
    99  func (t *dictTable) incUsed(n int) {
   100  	atomic.AddInt32(&t.used, int32(n))
   101  }
   102  
   103  // insertAbsentEntry adds the populated entry to t assuming that the key
   104  // specified in entry is absent from t. Since the key is absent, no key
   105  // comparisons are necessary to perform the insert.
   106  func (t *dictTable) insertAbsentEntry(entry *dictEntry) {
   107  	mask := uint(len(t.entries) - 1)
   108  	i := uint(entry.hash) & mask
   109  	perturb := uint(entry.hash)
   110  	index := i
   111  	// The key we're trying to insert is known to be absent from the dict
   112  	// so probe for the first nil entry.
   113  	for ; t.entries[index] != nil; index = i & mask {
   114  		i, perturb = dictNextIndex(i, perturb)
   115  	}
   116  	t.entries[index] = entry
   117  	t.incUsed(1)
   118  	t.fill++
   119  }
   120  
   121  // lookupEntry returns the index and entry in t with the given hash and key.
   122  // Elements in the table are updated with immutable entries atomically and
   123  // lookupEntry loads them atomically. So it is not necessary to lock the dict
   124  // to do entry lookups in a consistent way.
   125  func (t *dictTable) lookupEntry(f *Frame, hash int, key *Object) (int, *dictEntry, *BaseException) {
   126  	mask := uint(len(t.entries) - 1)
   127  	i, perturb := uint(hash)&mask, uint(hash)
   128  	// free is the first slot that's available. We don't immediately use it
   129  	// because it has been previously used and therefore an exact match may
   130  	// be found further on.
   131  	free := -1
   132  	var freeEntry *dictEntry
   133  	index := int(i & mask)
   134  	entry := t.loadEntry(index)
   135  	for {
   136  		if entry == nil {
   137  			if free != -1 {
   138  				index = free
   139  				// Store the entry instead of fetching by index
   140  				// later since it may have changed by then.
   141  				entry = freeEntry
   142  			}
   143  			break
   144  		}
   145  		if entry == deletedEntry {
   146  			if free == -1 {
   147  				free = index
   148  			}
   149  		} else if entry.hash == hash {
   150  			o, raised := Eq(f, entry.key, key)
   151  			if raised != nil {
   152  				return -1, nil, raised
   153  			}
   154  			eq, raised := IsTrue(f, o)
   155  			if raised != nil {
   156  				return -1, nil, raised
   157  			}
   158  			if eq {
   159  				break
   160  			}
   161  		}
   162  		i, perturb = dictNextIndex(i, perturb)
   163  		index = int(i & mask)
   164  		entry = t.loadEntry(index)
   165  	}
   166  	return index, entry, nil
   167  }
   168  
   169  // writeEntry replaces t's entry at the given index with entry. If writing
   170  // entry would cause t's fill ratio to grow too large then a new table is
   171  // created, the entry is instead inserted there and that table is returned. t
   172  // remains unchanged. When a sufficiently sized table cannot be created, false
   173  // will be returned for the second value, otherwise true will be returned.
   174  func (t *dictTable) writeEntry(f *Frame, index int, entry *dictEntry) (*dictTable, bool) {
   175  	if t.entries[index] == deletedEntry {
   176  		t.storeEntry(index, entry)
   177  		t.incUsed(1)
   178  		return nil, true
   179  	}
   180  	if t.entries[index] != nil {
   181  		t.storeEntry(index, entry)
   182  		return nil, true
   183  	}
   184  	if (t.fill+1)*3 <= len(t.entries)*2 {
   185  		// New entry does not necessitate growing the table.
   186  		t.storeEntry(index, entry)
   187  		t.incUsed(1)
   188  		t.fill++
   189  		return nil, true
   190  	}
   191  	// Grow the table.
   192  	var n int
   193  	if t.used <= 50000 {
   194  		n = int(t.used * 4)
   195  	} else if t.used <= maxDictSize/2 {
   196  		n = int(t.used * 2)
   197  	} else {
   198  		return nil, false
   199  	}
   200  	newTable := newDictTable(n)
   201  	for _, oldEntry := range t.entries {
   202  		if oldEntry != nil && oldEntry != deletedEntry {
   203  			newTable.insertAbsentEntry(oldEntry)
   204  		}
   205  	}
   206  	newTable.insertAbsentEntry(entry)
   207  	return newTable, true
   208  }
   209  
   210  // dictEntryIterator is used to iterate over the entries in a dictTable in an
   211  // arbitrary order.
   212  type dictEntryIterator struct {
   213  	index int64
   214  	table *dictTable
   215  }
   216  
   217  // newDictEntryIterator creates a dictEntryIterator object for d. It assumes
   218  // that d.mutex is held by the caller.
   219  func newDictEntryIterator(d *Dict) dictEntryIterator {
   220  	return dictEntryIterator{table: d.loadTable()}
   221  }
   222  
   223  // next advances this iterator to the next occupied entry and returns it. The
   224  // second return value is true if the dict changed since iteration began, false
   225  // otherwise.
   226  func (iter *dictEntryIterator) next() *dictEntry {
   227  	numEntries := len(iter.table.entries)
   228  	var entry *dictEntry
   229  	for entry == nil {
   230  		// 64bit atomic ops need to be 8 byte aligned. This compile time check
   231  		// verifies alignment by creating a negative constant for an unsigned type.
   232  		// See sync/atomic docs for details.
   233  		const blank = -(unsafe.Offsetof(iter.index) % 8)
   234  		index := int(atomic.AddInt64(&iter.index, 1)) - 1
   235  		if index >= numEntries {
   236  			break
   237  		}
   238  		entry = iter.table.loadEntry(index)
   239  		if entry == deletedEntry {
   240  			entry = nil
   241  		}
   242  	}
   243  	return entry
   244  }
   245  
   246  // dictVersionGuard is used to detect when a dict has been modified.
   247  type dictVersionGuard struct {
   248  	dict    *Dict
   249  	version int64
   250  }
   251  
   252  func newDictVersionGuard(d *Dict) dictVersionGuard {
   253  	return dictVersionGuard{d, d.loadVersion()}
   254  }
   255  
   256  // check returns false if the dict held by g has changed since g was created,
   257  // true otherwise.
   258  func (g *dictVersionGuard) check() bool {
   259  	return g.dict.loadVersion() == g.version
   260  }
   261  
   262  // Dict represents Python 'dict' objects. The public methods of *Dict are
   263  // thread safe.
   264  type Dict struct {
   265  	Object
   266  	table *dictTable
   267  	// We use a recursive mutex for synchronization because the hash and
   268  	// key comparison operations may re-enter DelItem/SetItem.
   269  	mutex recursiveMutex
   270  	// version is incremented whenever the Dict is modified. See:
   271  	// https://www.python.org/dev/peps/pep-0509/
   272  	version int64
   273  }
   274  
   275  // NewDict returns an empty Dict.
   276  func NewDict() *Dict {
   277  	return &Dict{Object: Object{typ: DictType}, table: newDictTable(0)}
   278  }
   279  
   280  func newStringDict(items map[string]*Object) *Dict {
   281  	if len(items) > maxDictSize/2 {
   282  		panic(fmt.Sprintf("dictionary too big: %d", len(items)))
   283  	}
   284  	n := len(items) * 2
   285  	table := newDictTable(n)
   286  	for key, value := range items {
   287  		table.insertAbsentEntry(&dictEntry{hashString(key), NewStr(key).ToObject(), value})
   288  	}
   289  	return &Dict{Object: Object{typ: DictType}, table: table}
   290  }
   291  
   292  func toDictUnsafe(o *Object) *Dict {
   293  	return (*Dict)(o.toPointer())
   294  }
   295  
   296  // loadTable atomically loads and returns d's underlying dictTable.
   297  func (d *Dict) loadTable() *dictTable {
   298  	p := (*unsafe.Pointer)(unsafe.Pointer(&d.table))
   299  	return (*dictTable)(atomic.LoadPointer(p))
   300  }
   301  
   302  // storeTable atomically updates d's underlying dictTable to the one given.
   303  func (d *Dict) storeTable(table *dictTable) {
   304  	p := (*unsafe.Pointer)(unsafe.Pointer(&d.table))
   305  	atomic.StorePointer(p, unsafe.Pointer(table))
   306  }
   307  
   308  // loadVersion atomically loads and returns d's version.
   309  func (d *Dict) loadVersion() int64 {
   310  	// 64bit atomic ops need to be 8 byte aligned. This compile time check
   311  	// verifies alignment by creating a negative constant for an unsigned type.
   312  	// See sync/atomic docs for details.
   313  	const blank = -(unsafe.Offsetof(d.version) % 8)
   314  	return atomic.LoadInt64(&d.version)
   315  }
   316  
   317  // incVersion atomically increments d's version.
   318  func (d *Dict) incVersion() {
   319  	// 64bit atomic ops need to be 8 byte aligned. This compile time check
   320  	// verifies alignment by creating a negative constant for an unsigned type.
   321  	// See sync/atomic docs for details.
   322  	const blank = -(unsafe.Offsetof(d.version) % 8)
   323  	atomic.AddInt64(&d.version, 1)
   324  }
   325  
   326  // DelItem removes the entry associated with key from d. It returns true if an
   327  // item was removed, or false if it did not exist in d.
   328  func (d *Dict) DelItem(f *Frame, key *Object) (bool, *BaseException) {
   329  	originValue, raised := d.putItem(f, key, nil, true)
   330  	if raised != nil {
   331  		return false, raised
   332  	}
   333  	return originValue != nil, nil
   334  }
   335  
   336  // DelItemString removes the entry associated with key from d. It returns true
   337  // if an item was removed, or false if it did not exist in d.
   338  func (d *Dict) DelItemString(f *Frame, key string) (bool, *BaseException) {
   339  	return d.DelItem(f, NewStr(key).ToObject())
   340  }
   341  
   342  // GetItem looks up key in d, returning the associated value or nil if key is
   343  // not present in d.
   344  func (d *Dict) GetItem(f *Frame, key *Object) (*Object, *BaseException) {
   345  	hash, raised := Hash(f, key)
   346  	if raised != nil {
   347  		return nil, raised
   348  	}
   349  	_, entry, raised := d.loadTable().lookupEntry(f, hash.Value(), key)
   350  	if raised != nil {
   351  		return nil, raised
   352  	}
   353  	if entry != nil && entry != deletedEntry {
   354  		return entry.value, nil
   355  	}
   356  	return nil, nil
   357  }
   358  
   359  // GetItemString looks up key in d, returning the associated value or nil if
   360  // key is not present in d.
   361  func (d *Dict) GetItemString(f *Frame, key string) (*Object, *BaseException) {
   362  	return d.GetItem(f, NewStr(key).ToObject())
   363  }
   364  
   365  // Pop looks up key in d, returning and removing the associalted value if exist,
   366  // or nil if key is not present in d.
   367  func (d *Dict) Pop(f *Frame, key *Object) (*Object, *BaseException) {
   368  	return d.putItem(f, key, nil, true)
   369  }
   370  
   371  // Keys returns a list containing all the keys in d.
   372  func (d *Dict) Keys(f *Frame) *List {
   373  	d.mutex.Lock(f)
   374  	keys := make([]*Object, d.Len())
   375  	i := 0
   376  	for _, entry := range d.table.entries {
   377  		if entry != nil && entry != deletedEntry {
   378  			keys[i] = entry.key
   379  			i++
   380  		}
   381  	}
   382  	d.mutex.Unlock(f)
   383  	return NewList(keys...)
   384  }
   385  
   386  // Len returns the number of entries in d.
   387  func (d *Dict) Len() int {
   388  	return d.loadTable().loadUsed()
   389  }
   390  
   391  // putItem associates value with key in d, returning the old associated value if
   392  // the key was added, or nil if it was not already present in d.
   393  func (d *Dict) putItem(f *Frame, key, value *Object, overwrite bool) (*Object, *BaseException) {
   394  	hash, raised := Hash(f, key)
   395  	if raised != nil {
   396  		return nil, raised
   397  	}
   398  	d.mutex.Lock(f)
   399  	t := d.table
   400  	v := d.version
   401  	index, entry, raised := t.lookupEntry(f, hash.Value(), key)
   402  	var originValue *Object
   403  	if raised == nil {
   404  		if v != d.version {
   405  			// Dictionary was recursively modified. Blow up instead
   406  			// of trying to recover.
   407  			raised = f.RaiseType(RuntimeErrorType, "dictionary changed during write")
   408  		} else {
   409  			if value == nil {
   410  				// Going to delete the entry.
   411  				if entry != nil && entry != deletedEntry {
   412  					d.table.storeEntry(index, deletedEntry)
   413  					d.table.incUsed(-1)
   414  					d.incVersion()
   415  				}
   416  			} else if overwrite || entry == nil {
   417  				newEntry := &dictEntry{hash.Value(), key, value}
   418  				if newTable, ok := t.writeEntry(f, index, newEntry); ok {
   419  					if newTable != nil {
   420  						d.storeTable(newTable)
   421  					}
   422  					d.incVersion()
   423  				} else {
   424  					raised = f.RaiseType(OverflowErrorType, errResultTooLarge)
   425  				}
   426  			}
   427  			if entry != nil && entry != deletedEntry {
   428  				originValue = entry.value
   429  			}
   430  		}
   431  	}
   432  	d.mutex.Unlock(f)
   433  	return originValue, raised
   434  }
   435  
   436  // SetItem associates value with key in d.
   437  func (d *Dict) SetItem(f *Frame, key, value *Object) *BaseException {
   438  	_, raised := d.putItem(f, key, value, true)
   439  	return raised
   440  }
   441  
   442  // SetItemString associates value with key in d.
   443  func (d *Dict) SetItemString(f *Frame, key string, value *Object) *BaseException {
   444  	return d.SetItem(f, NewStr(key).ToObject(), value)
   445  }
   446  
   447  // ToObject upcasts d to an Object.
   448  func (d *Dict) ToObject() *Object {
   449  	return &d.Object
   450  }
   451  
   452  // Update copies the items from the mapping or sequence of 2-tuples o into d.
   453  func (d *Dict) Update(f *Frame, o *Object) (raised *BaseException) {
   454  	var iter *Object
   455  	if o.isInstance(DictType) {
   456  		d2 := toDictUnsafe(o)
   457  		d2.mutex.Lock(f)
   458  		// Concurrent modifications to d2 will cause Update to raise
   459  		// "dictionary changed during iteration".
   460  		iter = newDictItemIterator(d2).ToObject()
   461  		d2.mutex.Unlock(f)
   462  	} else {
   463  		iter, raised = Iter(f, o)
   464  	}
   465  	if raised != nil {
   466  		return raised
   467  	}
   468  	return seqForEach(f, iter, func(item *Object) *BaseException {
   469  		return seqApply(f, item, func(elems []*Object, _ bool) *BaseException {
   470  			if numElems := len(elems); numElems != 2 {
   471  				format := "dictionary update sequence element has length %d; 2 is required"
   472  				return f.RaiseType(ValueErrorType, fmt.Sprintf(format, numElems))
   473  			}
   474  			return d.SetItem(f, elems[0], elems[1])
   475  		})
   476  	})
   477  }
   478  
   479  // dictsAreEqual returns true if d1 and d2 have the same keys and values, false
   480  // otherwise. If either d1 or d2 are concurrently modified then RuntimeError is
   481  // raised.
   482  func dictsAreEqual(f *Frame, d1, d2 *Dict) (bool, *BaseException) {
   483  	if d1 == d2 {
   484  		return true, nil
   485  	}
   486  	// Do not hold both locks at the same time to avoid deadlock.
   487  	d1.mutex.Lock(f)
   488  	iter := newDictEntryIterator(d1)
   489  	g1 := newDictVersionGuard(d1)
   490  	len1 := d1.Len()
   491  	d1.mutex.Unlock(f)
   492  	d2.mutex.Lock(f)
   493  	g2 := newDictVersionGuard(d1)
   494  	len2 := d2.Len()
   495  	d2.mutex.Unlock(f)
   496  	if len1 != len2 {
   497  		return false, nil
   498  	}
   499  	result := true
   500  	for entry := iter.next(); entry != nil && result; entry = iter.next() {
   501  		if v, raised := d2.GetItem(f, entry.key); raised != nil {
   502  			return false, raised
   503  		} else if v == nil {
   504  			result = false
   505  		} else {
   506  			eq, raised := Eq(f, entry.value, v)
   507  			if raised != nil {
   508  				return false, raised
   509  			}
   510  			result, raised = IsTrue(f, eq)
   511  			if raised != nil {
   512  				return false, raised
   513  			}
   514  		}
   515  	}
   516  	if !g1.check() || !g2.check() {
   517  		return false, f.RaiseType(RuntimeErrorType, "dictionary changed during iteration")
   518  	}
   519  	return result, nil
   520  }
   521  
   522  func dictClear(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
   523  	if raised := checkMethodArgs(f, "clear", args, DictType); raised != nil {
   524  		return nil, raised
   525  	}
   526  	d := toDictUnsafe(args[0])
   527  	d.mutex.Lock(f)
   528  	d.table = newDictTable(0)
   529  	d.incVersion()
   530  	d.mutex.Unlock(f)
   531  	return None, nil
   532  }
   533  
   534  func dictContains(f *Frame, seq, value *Object) (*Object, *BaseException) {
   535  	item, raised := toDictUnsafe(seq).GetItem(f, value)
   536  	if raised != nil {
   537  		return nil, raised
   538  	}
   539  	return GetBool(item != nil).ToObject(), nil
   540  }
   541  
   542  func dictCopy(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
   543  	if raised := checkMethodArgs(f, "copy", args, DictType); raised != nil {
   544  		return nil, raised
   545  	}
   546  	return DictType.Call(f, args, nil)
   547  }
   548  
   549  func dictDelItem(f *Frame, o, key *Object) *BaseException {
   550  	deleted, raised := toDictUnsafe(o).DelItem(f, key)
   551  	if raised != nil {
   552  		return raised
   553  	}
   554  	if !deleted {
   555  		return raiseKeyError(f, key)
   556  	}
   557  	return nil
   558  }
   559  
   560  func dictEq(f *Frame, v, w *Object) (*Object, *BaseException) {
   561  	if !w.isInstance(DictType) {
   562  		return NotImplemented, nil
   563  	}
   564  	eq, raised := dictsAreEqual(f, toDictUnsafe(v), toDictUnsafe(w))
   565  	if raised != nil {
   566  		return nil, raised
   567  	}
   568  	return GetBool(eq).ToObject(), nil
   569  }
   570  
   571  func dictGet(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
   572  	expectedTypes := []*Type{DictType, ObjectType, ObjectType}
   573  	argc := len(args)
   574  	if argc == 2 {
   575  		expectedTypes = expectedTypes[:2]
   576  	}
   577  	if raised := checkMethodArgs(f, "get", args, expectedTypes...); raised != nil {
   578  		return nil, raised
   579  	}
   580  	item, raised := toDictUnsafe(args[0]).GetItem(f, args[1])
   581  	if raised == nil && item == nil {
   582  		item = None
   583  		if argc > 2 {
   584  			item = args[2]
   585  		}
   586  	}
   587  	return item, raised
   588  }
   589  
   590  func dictHasKey(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
   591  	if raised := checkMethodArgs(f, "has_key", args, DictType, ObjectType); raised != nil {
   592  		return nil, raised
   593  	}
   594  	return dictContains(f, args[0], args[1])
   595  }
   596  
   597  func dictItems(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
   598  	if raised := checkMethodArgs(f, "items", args, DictType); raised != nil {
   599  		return nil, raised
   600  	}
   601  	d := toDictUnsafe(args[0])
   602  	d.mutex.Lock(f)
   603  	iter := newDictItemIterator(d).ToObject()
   604  	d.mutex.Unlock(f)
   605  	return ListType.Call(f, Args{iter}, nil)
   606  }
   607  
   608  func dictIterItems(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
   609  	if raised := checkMethodArgs(f, "iteritems", args, DictType); raised != nil {
   610  		return nil, raised
   611  	}
   612  	d := toDictUnsafe(args[0])
   613  	d.mutex.Lock(f)
   614  	iter := newDictItemIterator(d).ToObject()
   615  	d.mutex.Unlock(f)
   616  	return iter, nil
   617  }
   618  
   619  func dictIterKeys(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
   620  	if raised := checkMethodArgs(f, "iterkeys", args, DictType); raised != nil {
   621  		return nil, raised
   622  	}
   623  	return dictIter(f, args[0])
   624  }
   625  
   626  func dictIterValues(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
   627  	if raised := checkMethodArgs(f, "itervalues", args, DictType); raised != nil {
   628  		return nil, raised
   629  	}
   630  	d := toDictUnsafe(args[0])
   631  	d.mutex.Lock(f)
   632  	iter := newDictValueIterator(d).ToObject()
   633  	d.mutex.Unlock(f)
   634  	return iter, nil
   635  }
   636  
   637  func dictKeys(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
   638  	if raised := checkMethodArgs(f, "keys", args, DictType); raised != nil {
   639  		return nil, raised
   640  	}
   641  	return toDictUnsafe(args[0]).Keys(f).ToObject(), nil
   642  }
   643  
   644  func dictGetItem(f *Frame, o, key *Object) (*Object, *BaseException) {
   645  	item, raised := toDictUnsafe(o).GetItem(f, key)
   646  	if raised != nil {
   647  		return nil, raised
   648  	}
   649  	if item == nil {
   650  		return nil, raiseKeyError(f, key)
   651  	}
   652  	return item, nil
   653  }
   654  
   655  func dictInit(f *Frame, o *Object, args Args, kwargs KWArgs) (*Object, *BaseException) {
   656  	var expectedTypes []*Type
   657  	argc := len(args)
   658  	if argc > 0 {
   659  		expectedTypes = []*Type{ObjectType}
   660  	}
   661  	if raised := checkFunctionArgs(f, "__init__", args, expectedTypes...); raised != nil {
   662  		return nil, raised
   663  	}
   664  	d := toDictUnsafe(o)
   665  	if argc > 0 {
   666  		if raised := d.Update(f, args[0]); raised != nil {
   667  			return nil, raised
   668  		}
   669  	}
   670  	for _, kwarg := range kwargs {
   671  		if raised := d.SetItemString(f, kwarg.Name, kwarg.Value); raised != nil {
   672  			return nil, raised
   673  		}
   674  	}
   675  	return None, nil
   676  }
   677  
   678  func dictIter(f *Frame, o *Object) (*Object, *BaseException) {
   679  	d := toDictUnsafe(o)
   680  	d.mutex.Lock(f)
   681  	iter := newDictKeyIterator(d).ToObject()
   682  	d.mutex.Unlock(f)
   683  	return iter, nil
   684  }
   685  
   686  func dictLen(f *Frame, o *Object) (*Object, *BaseException) {
   687  	d := toDictUnsafe(o)
   688  	ret := NewInt(d.Len()).ToObject()
   689  	return ret, nil
   690  }
   691  
   692  func dictNE(f *Frame, v, w *Object) (*Object, *BaseException) {
   693  	if !w.isInstance(DictType) {
   694  		return NotImplemented, nil
   695  	}
   696  	eq, raised := dictsAreEqual(f, toDictUnsafe(v), toDictUnsafe(w))
   697  	if raised != nil {
   698  		return nil, raised
   699  	}
   700  	return GetBool(!eq).ToObject(), nil
   701  }
   702  
   703  func dictNew(f *Frame, t *Type, _ Args, _ KWArgs) (*Object, *BaseException) {
   704  	d := toDictUnsafe(newObject(t))
   705  	d.table = &dictTable{entries: make([]*dictEntry, minDictSize, minDictSize)}
   706  	return d.ToObject(), nil
   707  }
   708  
   709  func dictPop(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
   710  	expectedTypes := []*Type{DictType, ObjectType, ObjectType}
   711  	argc := len(args)
   712  	if argc == 2 {
   713  		expectedTypes = expectedTypes[:2]
   714  	}
   715  	if raised := checkMethodArgs(f, "pop", args, expectedTypes...); raised != nil {
   716  		return nil, raised
   717  	}
   718  	key := args[1]
   719  	d := toDictUnsafe(args[0])
   720  	item, raised := d.Pop(f, key)
   721  	if raised == nil && item == nil {
   722  		if argc > 2 {
   723  			item = args[2]
   724  		} else {
   725  			raised = raiseKeyError(f, key)
   726  		}
   727  	}
   728  	return item, raised
   729  }
   730  
   731  func dictPopItem(f *Frame, args Args, _ KWArgs) (item *Object, raised *BaseException) {
   732  	if raised := checkMethodArgs(f, "popitem", args, DictType); raised != nil {
   733  		return nil, raised
   734  	}
   735  	d := toDictUnsafe(args[0])
   736  	d.mutex.Lock(f)
   737  	iter := newDictEntryIterator(d)
   738  	entry := iter.next()
   739  	if entry == nil {
   740  		raised = f.RaiseType(KeyErrorType, "popitem(): dictionary is empty")
   741  	} else {
   742  		item = NewTuple(entry.key, entry.value).ToObject()
   743  		d.table.storeEntry(int(iter.index-1), deletedEntry)
   744  		d.table.incUsed(-1)
   745  		d.incVersion()
   746  	}
   747  	d.mutex.Unlock(f)
   748  	return item, raised
   749  }
   750  
   751  func dictRepr(f *Frame, o *Object) (*Object, *BaseException) {
   752  	d := toDictUnsafe(o)
   753  	if f.reprEnter(d.ToObject()) {
   754  		return NewStr("{...}").ToObject(), nil
   755  	}
   756  	defer f.reprLeave(d.ToObject())
   757  	// Lock d so that we get a consistent view of it. Otherwise we may
   758  	// return a state that d was never actually in.
   759  	d.mutex.Lock(f)
   760  	defer d.mutex.Unlock(f)
   761  	var buf bytes.Buffer
   762  	buf.WriteString("{")
   763  	iter := newDictEntryIterator(d)
   764  	i := 0
   765  	for entry := iter.next(); entry != nil; entry = iter.next() {
   766  		if i > 0 {
   767  			buf.WriteString(", ")
   768  		}
   769  		s, raised := Repr(f, entry.key)
   770  		if raised != nil {
   771  			return nil, raised
   772  		}
   773  		buf.WriteString(s.Value())
   774  		buf.WriteString(": ")
   775  		if s, raised = Repr(f, entry.value); raised != nil {
   776  			return nil, raised
   777  		}
   778  		buf.WriteString(s.Value())
   779  		i++
   780  	}
   781  	buf.WriteString("}")
   782  	return NewStr(buf.String()).ToObject(), nil
   783  }
   784  
   785  func dictSetDefault(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
   786  	argc := len(args)
   787  	if argc == 1 {
   788  		return nil, f.RaiseType(TypeErrorType, "setdefault expected at least 1 arguments, got 0")
   789  	}
   790  	if argc > 3 {
   791  		return nil, f.RaiseType(TypeErrorType, fmt.Sprintf("setdefault expected at most 2 arguments, got %v", argc-1))
   792  	}
   793  	expectedTypes := []*Type{DictType, ObjectType, ObjectType}
   794  	if argc == 2 {
   795  		expectedTypes = expectedTypes[:2]
   796  	}
   797  	if raised := checkMethodArgs(f, "setdefault", args, expectedTypes...); raised != nil {
   798  		return nil, raised
   799  	}
   800  	d := toDictUnsafe(args[0])
   801  	key := args[1]
   802  	var value *Object
   803  	if argc > 2 {
   804  		value = args[2]
   805  	} else {
   806  		value = None
   807  	}
   808  	originValue, raised := d.putItem(f, key, value, false)
   809  	if originValue != nil {
   810  		return originValue, raised
   811  	}
   812  	return value, raised
   813  }
   814  
   815  func dictSetItem(f *Frame, o, key, value *Object) *BaseException {
   816  	return toDictUnsafe(o).SetItem(f, key, value)
   817  }
   818  
   819  func dictUpdate(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
   820  	expectedTypes := []*Type{DictType, ObjectType}
   821  	argc := len(args)
   822  	if argc == 1 {
   823  		expectedTypes = expectedTypes[:1]
   824  	}
   825  	if raised := checkMethodArgs(f, "update", args, expectedTypes...); raised != nil {
   826  		return nil, raised
   827  	}
   828  	d := toDictUnsafe(args[0])
   829  	if argc > 1 {
   830  		if raised := d.Update(f, args[1]); raised != nil {
   831  			return nil, raised
   832  		}
   833  	}
   834  	for _, kwarg := range kwargs {
   835  		if raised := d.SetItemString(f, kwarg.Name, kwarg.Value); raised != nil {
   836  			return nil, raised
   837  		}
   838  	}
   839  	return None, nil
   840  }
   841  
   842  func dictValues(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
   843  	if raised := checkMethodArgs(f, "values", args, DictType); raised != nil {
   844  		return nil, raised
   845  	}
   846  	iter, raised := dictIterValues(f, args, nil)
   847  	if raised != nil {
   848  		return nil, raised
   849  	}
   850  	return ListType.Call(f, Args{iter}, nil)
   851  }
   852  
   853  func initDictType(dict map[string]*Object) {
   854  	dict["clear"] = newBuiltinFunction("clear", dictClear).ToObject()
   855  	dict["copy"] = newBuiltinFunction("copy", dictCopy).ToObject()
   856  	dict["get"] = newBuiltinFunction("get", dictGet).ToObject()
   857  	dict["has_key"] = newBuiltinFunction("has_key", dictHasKey).ToObject()
   858  	dict["items"] = newBuiltinFunction("items", dictItems).ToObject()
   859  	dict["iteritems"] = newBuiltinFunction("iteritems", dictIterItems).ToObject()
   860  	dict["iterkeys"] = newBuiltinFunction("iterkeys", dictIterKeys).ToObject()
   861  	dict["itervalues"] = newBuiltinFunction("itervalues", dictIterValues).ToObject()
   862  	dict["keys"] = newBuiltinFunction("keys", dictKeys).ToObject()
   863  	dict["pop"] = newBuiltinFunction("pop", dictPop).ToObject()
   864  	dict["popitem"] = newBuiltinFunction("popitem", dictPopItem).ToObject()
   865  	dict["setdefault"] = newBuiltinFunction("setdefault", dictSetDefault).ToObject()
   866  	dict["update"] = newBuiltinFunction("update", dictUpdate).ToObject()
   867  	dict["values"] = newBuiltinFunction("values", dictValues).ToObject()
   868  	DictType.slots.Contains = &binaryOpSlot{dictContains}
   869  	DictType.slots.DelItem = &delItemSlot{dictDelItem}
   870  	DictType.slots.Eq = &binaryOpSlot{dictEq}
   871  	DictType.slots.GetItem = &binaryOpSlot{dictGetItem}
   872  	DictType.slots.Hash = &unaryOpSlot{hashNotImplemented}
   873  	DictType.slots.Init = &initSlot{dictInit}
   874  	DictType.slots.Iter = &unaryOpSlot{dictIter}
   875  	DictType.slots.Len = &unaryOpSlot{dictLen}
   876  	DictType.slots.NE = &binaryOpSlot{dictNE}
   877  	DictType.slots.New = &newSlot{dictNew}
   878  	DictType.slots.Repr = &unaryOpSlot{dictRepr}
   879  	DictType.slots.SetItem = &setItemSlot{dictSetItem}
   880  }
   881  
   882  type dictItemIterator struct {
   883  	Object
   884  	iter  dictEntryIterator
   885  	guard dictVersionGuard
   886  }
   887  
   888  // newDictItemIterator creates a dictItemIterator object for d. It assumes that
   889  // d.mutex is held by the caller.
   890  func newDictItemIterator(d *Dict) *dictItemIterator {
   891  	return &dictItemIterator{
   892  		Object: Object{typ: dictItemIteratorType},
   893  		iter:   newDictEntryIterator(d),
   894  		guard:  newDictVersionGuard(d),
   895  	}
   896  }
   897  
   898  func toDictItemIteratorUnsafe(o *Object) *dictItemIterator {
   899  	return (*dictItemIterator)(o.toPointer())
   900  }
   901  
   902  func (iter *dictItemIterator) ToObject() *Object {
   903  	return &iter.Object
   904  }
   905  
   906  func dictItemIteratorIter(f *Frame, o *Object) (*Object, *BaseException) {
   907  	return o, nil
   908  }
   909  
   910  func dictItemIteratorNext(f *Frame, o *Object) (ret *Object, raised *BaseException) {
   911  	iter := toDictItemIteratorUnsafe(o)
   912  	entry, raised := dictIteratorNext(f, &iter.iter, &iter.guard)
   913  	if raised != nil {
   914  		return nil, raised
   915  	}
   916  	return NewTuple2(entry.key, entry.value).ToObject(), nil
   917  }
   918  
   919  func initDictItemIteratorType(map[string]*Object) {
   920  	dictItemIteratorType.flags &^= typeFlagBasetype | typeFlagInstantiable
   921  	dictItemIteratorType.slots.Iter = &unaryOpSlot{dictItemIteratorIter}
   922  	dictItemIteratorType.slots.Next = &unaryOpSlot{dictItemIteratorNext}
   923  }
   924  
   925  type dictKeyIterator struct {
   926  	Object
   927  	iter  dictEntryIterator
   928  	guard dictVersionGuard
   929  }
   930  
   931  // newDictKeyIterator creates a dictKeyIterator object for d. It assumes that
   932  // d.mutex is held by the caller.
   933  func newDictKeyIterator(d *Dict) *dictKeyIterator {
   934  	return &dictKeyIterator{
   935  		Object: Object{typ: dictKeyIteratorType},
   936  		iter:   newDictEntryIterator(d),
   937  		guard:  newDictVersionGuard(d),
   938  	}
   939  }
   940  
   941  func toDictKeyIteratorUnsafe(o *Object) *dictKeyIterator {
   942  	return (*dictKeyIterator)(o.toPointer())
   943  }
   944  
   945  func (iter *dictKeyIterator) ToObject() *Object {
   946  	return &iter.Object
   947  }
   948  
   949  func dictKeyIteratorIter(f *Frame, o *Object) (*Object, *BaseException) {
   950  	return o, nil
   951  }
   952  
   953  func dictKeyIteratorNext(f *Frame, o *Object) (*Object, *BaseException) {
   954  	iter := toDictKeyIteratorUnsafe(o)
   955  	entry, raised := dictIteratorNext(f, &iter.iter, &iter.guard)
   956  	if raised != nil {
   957  		return nil, raised
   958  	}
   959  	return entry.key, nil
   960  }
   961  
   962  func initDictKeyIteratorType(map[string]*Object) {
   963  	dictKeyIteratorType.flags &^= typeFlagBasetype | typeFlagInstantiable
   964  	dictKeyIteratorType.slots.Iter = &unaryOpSlot{dictKeyIteratorIter}
   965  	dictKeyIteratorType.slots.Next = &unaryOpSlot{dictKeyIteratorNext}
   966  }
   967  
   968  type dictValueIterator struct {
   969  	Object
   970  	iter  dictEntryIterator
   971  	guard dictVersionGuard
   972  }
   973  
   974  // newDictValueIterator creates a dictValueIterator object for d. It assumes
   975  // that d.mutex is held by the caller.
   976  func newDictValueIterator(d *Dict) *dictValueIterator {
   977  	return &dictValueIterator{
   978  		Object: Object{typ: dictValueIteratorType},
   979  		iter:   newDictEntryIterator(d),
   980  		guard:  newDictVersionGuard(d),
   981  	}
   982  }
   983  
   984  func toDictValueIteratorUnsafe(o *Object) *dictValueIterator {
   985  	return (*dictValueIterator)(o.toPointer())
   986  }
   987  
   988  func (iter *dictValueIterator) ToObject() *Object {
   989  	return &iter.Object
   990  }
   991  
   992  func dictValueIteratorIter(f *Frame, o *Object) (*Object, *BaseException) {
   993  	return o, nil
   994  }
   995  
   996  func dictValueIteratorNext(f *Frame, o *Object) (*Object, *BaseException) {
   997  	iter := toDictValueIteratorUnsafe(o)
   998  	entry, raised := dictIteratorNext(f, &iter.iter, &iter.guard)
   999  	if raised != nil {
  1000  		return nil, raised
  1001  	}
  1002  	return entry.value, nil
  1003  }
  1004  
  1005  func initDictValueIteratorType(map[string]*Object) {
  1006  	dictValueIteratorType.flags &^= typeFlagBasetype | typeFlagInstantiable
  1007  	dictValueIteratorType.slots.Iter = &unaryOpSlot{dictValueIteratorIter}
  1008  	dictValueIteratorType.slots.Next = &unaryOpSlot{dictValueIteratorNext}
  1009  }
  1010  
  1011  func raiseKeyError(f *Frame, key *Object) *BaseException {
  1012  	s, raised := ToStr(f, key)
  1013  	if raised == nil {
  1014  		raised = f.RaiseType(KeyErrorType, s.Value())
  1015  	}
  1016  	return raised
  1017  }
  1018  
  1019  func dictNextIndex(i, perturb uint) (uint, uint) {
  1020  	return (i << 2) + i + perturb + 1, perturb >> 5
  1021  }
  1022  
  1023  func dictIteratorNext(f *Frame, iter *dictEntryIterator, guard *dictVersionGuard) (*dictEntry, *BaseException) {
  1024  	// NOTE: The behavior here diverges from CPython where an iterator that
  1025  	// is exhausted will always return StopIteration regardless whether the
  1026  	// underlying dict is subsequently modified. In Grumpy, an iterator for
  1027  	// a dict that has been modified will always raise RuntimeError even if
  1028  	// the iterator was exhausted before the modification.
  1029  	entry := iter.next()
  1030  	if !guard.check() {
  1031  		return nil, f.RaiseType(RuntimeErrorType, "dictionary changed during iteration")
  1032  	}
  1033  	if entry == nil {
  1034  		return nil, f.Raise(StopIterationType.ToObject(), nil, nil)
  1035  	}
  1036  	return entry, nil
  1037  }