Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Single entry slot map #1784

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public void create() {
public Object embeddedInsert1Key(EmbeddedState state) {
Slot newSlot = null;
for (int i = 0; i < 100; i++) {
newSlot = state.emptyMap.modify(state.randomKeys[i], 0, 0);
newSlot = state.emptyMap.modify(null, state.randomKeys[i], 0, 0);
}
if (newSlot == null) {
throw new AssertionError();
Expand Down Expand Up @@ -109,7 +109,7 @@ public void create() {
public Object hashInsert1Key(HashState state) {
Slot newSlot = null;
for (int i = 0; i < 100; i++) {
newSlot = state.emptyMap.modify(state.randomKeys[i], 0, 0);
newSlot = state.emptyMap.modify(null, state.randomKeys[i], 0, 0);
}
if (newSlot == null) {
throw new AssertionError();
Expand Down Expand Up @@ -156,7 +156,7 @@ private static String makeRandomString() {
/** Insert a random key and value into the map */
private static String insertRandomEntry(SlotMap map) {
String key = makeRandomString();
Slot slot = map.modify(key, 0, 0);
Slot slot = map.modify(null, key, 0, 0);
slot.setValue(key, null, null);
return key;
}
Expand Down
93 changes: 53 additions & 40 deletions rhino/src/main/java/org/mozilla/javascript/EmbeddedSlotMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public Slot query(Object key, int index) {
* @param index index or 0 if slot holds property name.
*/
@Override
public Slot modify(Object key, int index, int attributes) {
public Slot modify(SlotMapOwner owner, Object key, int index, int attributes) {
final int indexOrHash = (key != null ? key.hashCode() : index);
Slot slot;

Expand All @@ -110,13 +110,12 @@ public Slot modify(Object key, int index, int attributes) {
}
}

// A new slot has to be inserted.
Slot newSlot = new Slot(key, index, attributes);
createNewSlot(newSlot);
createNewSlot(owner, newSlot);
return newSlot;
}

private void createNewSlot(Slot newSlot) {
private void createNewSlot(SlotMapOwner owner, Slot newSlot) {
if (count == 0) {
// Always throw away old slots if any on empty insert.
slots = new Slot[INITIAL_SLOT_SIZE];
Expand All @@ -125,6 +124,11 @@ private void createNewSlot(Slot newSlot) {
// Check if the table is not too full before inserting.
if (4 * (count + 1) > 3 * slots.length) {
// table size must be a power of 2 -- always grow by x2!
if (count > SlotMapContainer.LARGE_HASH_SIZE) {
var newMap = new HashSlotMap(this, newSlot);
owner.setMap(newMap);
return;
}
Slot[] newSlots = new Slot[slots.length * 2];
copyTable(slots, newSlots);
slots = newSlots;
Expand All @@ -134,7 +138,8 @@ private void createNewSlot(Slot newSlot) {
}

@Override
public <S extends Slot> S compute(Object key, int index, SlotComputer<S> c) {
public <S extends Slot> S compute(
SlotMapOwner owner, Object key, int index, SlotComputer<S> c) {
final int indexOrHash = (key != null ? key.hashCode() : index);

if (slots != null) {
Expand All @@ -148,54 +153,62 @@ public <S extends Slot> S compute(Object key, int index, SlotComputer<S> c) {
prev = slot;
}
if (slot != null) {
// Modify or remove existing slot
S newSlot = c.compute(key, index, slot);
if (newSlot == null) {
// Need to delete this slot actually
removeSlot(slot, prev, slotIndex, key);
} else if (!Objects.equals(slot, newSlot)) {
// Replace slot in hash table
if (prev == slot) {
slots[slotIndex] = newSlot;
} else {
prev.next = newSlot;
}
newSlot.next = slot.next;
// Replace new slot in linked list, keeping same order
if (slot == firstAdded) {
firstAdded = newSlot;
} else {
Slot ps = firstAdded;
while ((ps != null) && (ps.orderedNext != slot)) {
ps = ps.orderedNext;
}
if (ps != null) {
ps.orderedNext = newSlot;
}
}
newSlot.orderedNext = slot.orderedNext;
if (slot == lastAdded) {
lastAdded = newSlot;
}
}
return newSlot;
return computeExisting(key, index, c, slot, prev, slotIndex);
}
}
return computeNew(owner, key, index, c);
}

// If we get here, we know we are potentially adding a new slot
private <S extends Slot> S computeNew(
SlotMapOwner owner, Object key, int index, SlotComputer<S> c) {
S newSlot = c.compute(key, index, null);
if (newSlot != null) {
createNewSlot(newSlot);
createNewSlot(owner, newSlot);
}
return newSlot;
}

private <S extends Slot> S computeExisting(
Object key, int index, SlotComputer<S> c, Slot slot, Slot prev, int slotIndex) {
// Modify or remove existing slot
S newSlot = c.compute(key, index, slot);
if (newSlot == null) {
// Need to delete this slot actually
removeSlot(slot, prev, slotIndex, key);
} else if (!Objects.equals(slot, newSlot)) {
// Replace slot in hash table
if (prev == slot) {
slots[slotIndex] = newSlot;
} else {
prev.next = newSlot;
}
newSlot.next = slot.next;
// Replace new slot in linked list, keeping same order
if (slot == firstAdded) {
firstAdded = newSlot;
} else {
Slot ps = firstAdded;
while ((ps != null) && (ps.orderedNext != slot)) {
ps = ps.orderedNext;
}
if (ps != null) {
ps.orderedNext = newSlot;
}
}
newSlot.orderedNext = slot.orderedNext;
if (slot == lastAdded) {
lastAdded = newSlot;
}
}
return newSlot;
}

@Override
public void add(Slot newSlot) {
public void add(SlotMapOwner owner, Slot newSlot) {
if (slots == null) {
slots = new Slot[INITIAL_SLOT_SIZE];
}
insertNewSlot(newSlot);
createNewSlot(owner, newSlot);
}

private void insertNewSlot(Slot newSlot) {
Expand Down
17 changes: 13 additions & 4 deletions rhino/src/main/java/org/mozilla/javascript/HashSlotMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,18 @@ public HashSlotMap() {
public HashSlotMap(SlotMap oldMap) {
map = new LinkedHashMap<>(oldMap.size());
for (Slot n : oldMap) {
add(n.copySlot());
add(null, n.copySlot());
}
}

public HashSlotMap(SlotMap oldMap, Slot newSlot) {
map = new LinkedHashMap<>(oldMap.dirtySize() + 1);
for (Slot n : oldMap) {
add(null, n.copySlot());
}
add(null, newSlot);
}

@Override
public int size() {
return map.size();
Expand All @@ -47,21 +55,22 @@ public Slot query(Object key, int index) {
}

@Override
public Slot modify(Object key, int index, int attributes) {
public Slot modify(SlotMapOwner owner, Object key, int index, int attributes) {
Object name = makeKey(key, index);
return map.computeIfAbsent(name, n -> new Slot(key, index, attributes));
}

@SuppressWarnings("unchecked")
@Override
public <S extends Slot> S compute(Object key, int index, SlotComputer<S> c) {
public <S extends Slot> S compute(
SlotMapOwner owner, Object key, int index, SlotComputer<S> c) {
Object name = makeKey(key, index);
Slot ret = map.compute(name, (n, existing) -> c.compute(key, index, existing));
return (S) ret;
}

@Override
public void add(Slot newSlot) {
public void add(SlotMapOwner owner, Slot newSlot) {
Object name = makeKey(newSlot);
map.put(name, newSlot);
}
Expand Down
Loading
Loading