|
32 | 32 | import java.io.ObjectOutputStream; |
33 | 33 | import java.lang.invoke.MethodHandle; |
34 | 34 | import java.util.ArrayList; |
| 35 | +import java.util.Arrays; |
35 | 36 | import java.util.Collections; |
36 | 37 | import java.util.LinkedHashMap; |
37 | 38 | import java.util.Map; |
@@ -105,6 +106,27 @@ public VariableTableManager(RubyClass realClass) { |
105 | 106 | this.realClass = realClass; |
106 | 107 | } |
107 | 108 |
|
| 109 | + /** |
| 110 | + * Copy constructor with deep cloning. |
| 111 | + * |
| 112 | + * @param original VariableTableManager to copy |
| 113 | + */ |
| 114 | + VariableTableManager(VariableTableManager original) { |
| 115 | + synchronized (original) { |
| 116 | + this.realClass = original.realClass; |
| 117 | + this.variableAccessors = copyVariableAccessors(original.variableAccessors); |
| 118 | + this.variableNames = original.variableNames.clone(); |
| 119 | + this.hasObjectID = original.hasObjectID; |
| 120 | + this.hasFFI = original.hasFFI; |
| 121 | + this.hasObjectspaceGroup = original.hasObjectspaceGroup; |
| 122 | + this.fieldVariables = original.fieldVariables; |
| 123 | + } |
| 124 | + } |
| 125 | + |
| 126 | + public RubyClass getRealClass() { |
| 127 | + return realClass; |
| 128 | + } |
| 129 | + |
108 | 130 | /** |
109 | 131 | * Get the map of all current variable accessors with intent to read from it. |
110 | 132 | * |
@@ -253,18 +275,24 @@ VariableAccessor getVariableAccessorWithBuilder(String name, Function<Integer, V |
253 | 275 | if (ivarAccessor == null) { |
254 | 276 | // allocate a new accessor and populate a new table |
255 | 277 | ivarAccessor = allocateVariableAccessors(name, defaultAccessorBuilder); |
256 | | - Map<String, VariableAccessor> newVariableAccessors = new LinkedHashMap<>(myVariableAccessors.size() + 1); |
257 | | - |
258 | | - newVariableAccessors.putAll(myVariableAccessors); |
259 | | - newVariableAccessors.put(name, ivarAccessor); |
260 | | - |
261 | | - variableAccessors = newVariableAccessors; |
| 278 | + variableAccessors = copyVariableAccessors(myVariableAccessors, name, ivarAccessor); |
262 | 279 | } |
263 | 280 | } |
264 | 281 | } |
265 | 282 | return ivarAccessor; |
266 | 283 | } |
267 | 284 |
|
| 285 | + private static Map<String, VariableAccessor> copyVariableAccessors(Map<String, VariableAccessor> myVariableAccessors) { |
| 286 | + return new LinkedHashMap<>(myVariableAccessors); |
| 287 | + } |
| 288 | + |
| 289 | + private static Map<String, VariableAccessor> copyVariableAccessors(Map<String, VariableAccessor> myVariableAccessors, String name, VariableAccessor ivarAccessor) { |
| 290 | + LinkedHashMap<String, VariableAccessor> newVariableAccessors = new LinkedHashMap<>(myVariableAccessors.size() + 1); |
| 291 | + newVariableAccessors.putAll(myVariableAccessors); |
| 292 | + newVariableAccessors.put(name, ivarAccessor); |
| 293 | + return newVariableAccessors; |
| 294 | + } |
| 295 | + |
268 | 296 | /** |
269 | 297 | * Get the variable accessor for the given name with intent to use it for |
270 | 298 | * reading. |
@@ -514,6 +542,10 @@ public Object clearVariable(RubyBasicObject object, String name) { |
514 | 542 | } |
515 | 543 | } |
516 | 544 |
|
| 545 | + public VariableTableManager duplicate() { |
| 546 | + return new VariableTableManager(this); |
| 547 | + } |
| 548 | + |
517 | 549 | /** |
518 | 550 | * We lazily stand up the object ID since it forces us to stand up |
519 | 551 | * per-object state for a given object. We also check for ObjectSpace here, |
|
0 commit comments