@@ -16,7 +16,7 @@ import java.util.Locale;
1616public class Loader {
1717
1818 public static ParseResult load(byte[] serialized, byte[] sourceBytes) {
19- return new Loader(serialized, sourceBytes ).load();
19+ return new Loader(serialized).load(sourceBytes );
2020 }
2121
2222 // Overridable methods
@@ -71,19 +71,21 @@ public class Loader {
7171 }
7272
7373 private final ByteBuffer buffer;
74- private final Nodes.Source source;
7574 protected String encodingName;
7675 <%- if string_type == "String" -%>
7776 private Charset encodingCharset;
7877 <%- end -%>
7978 private ConstantPool constantPool;
8079
81- protected Loader(byte[] serialized, byte[] sourceBytes ) {
80+ protected Loader(byte[] serialized) {
8281 this.buffer = ByteBuffer.wrap(serialized).order(ByteOrder.nativeOrder());
83- this.source = new Nodes.Source(sourceBytes);
8482 }
8583
86- protected ParseResult load() {
84+ // We pass sourceBytes here and not in the constructor to avoid keeping
85+ // the sourceBytes in memory unnecessarily with lazy DefNode's which hold on the Loader.
86+ protected ParseResult load(byte[] sourceBytes) {
87+ Nodes.Source source = new Nodes.Source(sourceBytes);
88+
8789 expect((byte) 'P', "incorrect prism header");
8890 expect((byte) 'R', "incorrect prism header");
8991 expect((byte) 'I', "incorrect prism header");
@@ -331,6 +333,10 @@ public class Loader {
331333 return negative ? result.negate() : result;
332334 }
333335
336+ <%-
337+ base_params = [ *( "nodeId" if Prism ::Template ::INCLUDE_NODE_ID ) , "startOffset" , "length" ]
338+ base_params_sig = base_params . map { "int #{ _1 } " } . join ( ", " )
339+ -%>
334340 private Nodes.Node loadNode() {
335341 int type = buffer.get() & 0xFF;
336342 <%- if Prism ::Template ::INCLUDE_NODE_ID -%>
@@ -347,7 +353,7 @@ public class Loader {
347353 params = [ ]
348354 params << "nodeId" if Prism ::Template ::INCLUDE_NODE_ID
349355 params << "startOffset" << "length"
350- params << "buffer.getInt()" if node . needs_serialized_length?
356+ params << "buffer.getInt()" << "null" if node . needs_serialized_length?
351357 params << "loadFlags()" if node . flags
352358 params . concat node . semantic_fields . map { |field |
353359 case field
@@ -370,13 +376,44 @@ public class Loader {
370376 else raise
371377 end
372378 }
379+ $DefNode_params = params if node . name == "DefNode"
373380 -%>
381+ <%- if node . name == "DefNode" -%>
382+ return loadDefNode(<%= base_params . join ( ", " ) -%> );
383+ <%- else -%>
374384 return new Nodes.<%= node . name %> (<%= params . join ( ", " ) -%> );
385+ <%- end -%>
375386 <%- end -%>
376387 default:
377388 throw new Error( "Unknown node type: " + type);
378389 }
379390 }
391+
392+ // Can be overridden to use createLazyDefNode instead
393+ protected Nodes.DefNode loadDefNode(<%= base_params_sig -%> ) {
394+ return createDefNode(<%= base_params . join ( ", " ) -%> );
395+ }
396+
397+ protected Nodes.DefNode createLazyDefNode(<%= base_params_sig -%> ) {
398+ int bufferPosition = buffer.position();
399+ int serializedLength = buffer.getInt();
400+ // Load everything except the body and locals, because the name, receiver, parameters are still needed for lazily defining the method
401+ Nodes.DefNode lazyDefNode = new Nodes.DefNode(<%= base_params . join ( ", " ) -%> , -bufferPosition, this, loadConstant(), loadOptionalNode(), (Nodes.ParametersNode) loadOptionalNode(), null, Nodes.EMPTY_STRING_ARRAY);
402+ buffer.position(bufferPosition + serializedLength); // skip past the serialized DefNode
403+ return lazyDefNode;
404+ }
405+
406+ protected Nodes.DefNode createDefNode(<%= base_params_sig -%> ) {
407+ return new Nodes.DefNode(<%= $DefNode_params. join ( ", " ) -%> );
408+ }
409+
410+ Nodes.DefNode createDefNodeFromSavedPosition(<%= base_params_sig -%> , int bufferPosition) {
411+ // This method mutates the buffer position and may be called from different threads so we must synchronize
412+ synchronized (this) {
413+ buffer.position(bufferPosition);
414+ return createDefNode(<%= base_params . join ( ", " ) -%> );
415+ }
416+ }
380417 <%- array_types . uniq . each do |type | -%>
381418
382419 private static final Nodes.<%= type %> [] EMPTY_<%= type %> _ARRAY = {};
0 commit comments