blob: a8a4be46c841b4dab3204a0a6485d2e141253936 [file] [log] [blame]
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// part of "core_patch.dart";
// This function takes care of rehashing of the expandos in [objects]. We
// do this eagerly after snapshot deserialization.
@pragma("vm:entry-point", "call")
void _rehashObjects(List objects) {
final int length = objects.length;
for (int i = 0; i < length; ++i) {
objects[i]._rehash();
}
}
@patch
@pragma("vm:entry-point")
class Expando<T> {
@patch
Expando([String? name])
: name = name,
_data = new List<_WeakProperty?>.filled(_minSize, null),
_used = 0;
static const _minSize = 8;
static final _deletedEntry = new _WeakProperty();
@patch
T? operator [](Object object) {
_checkType(object);
var mask = _size - 1;
var idx = object._identityHashCode & mask;
var wp = _data[idx];
while (wp != null) {
if (identical(wp.key, object)) {
return unsafeCast<T?>(wp.value);
} else if (wp.key == null) {
// This entry has been cleared by the GC.
_data[idx] = _deletedEntry;
}
idx = (idx + 1) & mask;
wp = _data[idx];
}
return null;
}
@patch
void operator []=(Object object, T? value) {
_checkType(object);
var mask = _size - 1;
var idx = object._identityHashCode & mask;
var empty_idx = -1;
var wp = _data[idx];
while (wp != null) {
if (identical(wp.key, object)) {
if (value != null) {
// Update the associated value.
wp.value = value;
} else {
// Mark the entry as deleted.
_data[idx] = _deletedEntry;
}
return;
} else if ((empty_idx < 0) && identical(wp, _deletedEntry)) {
empty_idx = idx; // Insert at this location if not found.
} else if (wp.key == null) {
// This entry has been cleared by the GC.
_data[idx] = _deletedEntry;
if (empty_idx < 0) {
empty_idx = idx; // Insert at this location if not found.
}
}
idx = (idx + 1) & mask;
wp = _data[idx];
}
if (value == null) {
// Not entering a null value. We just needed to make sure to clear an
// existing value if it existed.
return;
}
if (empty_idx >= 0) {
// We will be reusing the empty slot below.
_used--;
idx = empty_idx;
}
if (_used < _limit) {
var ephemeron = new _WeakProperty();
ephemeron.key = object;
ephemeron.value = value;
_data[idx] = ephemeron;
_used++;
return;
}
// Grow/reallocate if too many slots have been used.
_rehash();
this[object] = value; // Recursively add the value.
}
_rehash() {
// Determine the population count of the map to allocate an appropriately
// sized map below.
var count = 0;
var old_data = _data;
var len = old_data.length;
for (var i = 0; i < len; i++) {
var entry = old_data[i];
if ((entry != null) && (entry.key != null)) {
// Only count non-cleared entries.
count++;
}
}
var new_size = _size;
if (count <= (new_size >> 2)) {
new_size = new_size >> 1;
} else if (count > (new_size >> 1)) {
new_size = new_size << 1;
}
new_size = (new_size < _minSize) ? _minSize : new_size;
// Reset the mappings to empty so that we can just add the existing
// valid entries.
_data = new List<_WeakProperty?>.filled(new_size, null);
_used = 0;
for (var i = 0; i < old_data.length; i++) {
var entry = old_data[i];
if (entry != null) {
// Ensure that the entry.key is not cleared between checking for it and
// inserting it into the new table.
var val = entry.value;
var key = entry.key;
if (key != null) {
this[key] = val;
}
}
}
}
static _checkType(object) {
if ((object == null) ||
(object is bool) ||
(object is num) ||
(object is String) ||
(object is Pointer) ||
(object is Struct) ||
(object is Union)) {
throw new ArgumentError.value(object,
"Expandos are not allowed on strings, numbers, booleans, null, Pointers, Structs or Unions.");
}
}
int get _size => _data.length;
int get _limit => (3 * (_size ~/ 4));
List<_WeakProperty?> _data;
int _used; // Number of used (active and deleted) slots.
}
@patch
class WeakReference<T extends Object> {
@patch
factory WeakReference(T object) {
final weakProperty = _WeakProperty()..key = object;
return _WeakReferenceImpl<T>(weakProperty);
}
}
class _WeakReferenceImpl<T extends Object> implements WeakReference<T> {
// TODO(http://dartbug.com/48162): Implement _WeakReference in the VM
// instead of reusing WeakProperty.
final _WeakProperty _weakProperty;
_WeakReferenceImpl(this._weakProperty);
T? get target => _weakProperty.key as T?;
}
@patch
class Finalizer<T> {
@patch
factory Finalizer(void Function(T) object) {
throw UnimplementedError("Finalizer");
}
}