@@ -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");
@@ -332,6 +334,10 @@ public class Loader {
332334 return negative ? result.negate() : result;
333335 }
334336
337+ <%-
338+ base_params = [ *( "nodeId" if Prism ::Template ::INCLUDE_NODE_ID ) , "startOffset" , "length" ]
339+ base_params_sig = base_params . map { "int #{ _1 } " } . join ( ", " )
340+ -%>
335341 private Nodes.Node loadNode() {
336342 int type = buffer.get() & 0xFF;
337343 <%- if Prism ::Template ::INCLUDE_NODE_ID -%>
@@ -348,7 +354,7 @@ public class Loader {
348354 params = [ ]
349355 params << "nodeId" if Prism ::Template ::INCLUDE_NODE_ID
350356 params << "startOffset" << "length"
351- params << "buffer.getInt()" if node . needs_serialized_length?
357+ params << "buffer.getInt()" << "null" if node . needs_serialized_length?
352358 params << "loadFlags()" if node . flags
353359 params . concat node . semantic_fields . map { |field |
354360 case field
@@ -371,13 +377,44 @@ public class Loader {
371377 else raise
372378 end
373379 }
380+ $DefNode_params = params if node . name == "DefNode"
374381 -%>
382+ <%- if node . name == "DefNode" -%>
383+ return loadDefNode(<%= base_params . join ( ", " ) -%> );
384+ <%- else -%>
375385 return new Nodes.<%= node . name %> (<%= params . join ( ", " ) -%> );
386+ <%- end -%>
376387 <%- end -%>
377388 default:
378389 throw new Error( "Unknown node type: " + type);
379390 }
380391 }
392+
393+ // Can be overridden to use createLazyDefNode instead
394+ protected Nodes.DefNode loadDefNode(<%= base_params_sig -%> ) {
395+ return createDefNode(<%= base_params . join ( ", " ) -%> );
396+ }
397+
398+ protected Nodes.DefNode createLazyDefNode(<%= base_params_sig -%> ) {
399+ int bufferPosition = buffer.position();
400+ int serializedLength = buffer.getInt();
401+ // Load everything except the body and locals, because the name, receiver, parameters are still needed for lazily defining the method
402+ Nodes.DefNode lazyDefNode = new Nodes.DefNode(<%= base_params . join ( ", " ) -%> , -bufferPosition, this, loadConstant(), loadOptionalNode(), (Nodes.ParametersNode) loadOptionalNode(), null, Nodes.EMPTY_STRING_ARRAY);
403+ buffer.position(bufferPosition + serializedLength); // skip past the serialized DefNode
404+ return lazyDefNode;
405+ }
406+
407+ protected Nodes.DefNode createDefNode(<%= base_params_sig -%> ) {
408+ return new Nodes.DefNode(<%= $DefNode_params. join ( ", " ) -%> );
409+ }
410+
411+ Nodes.DefNode createDefNodeFromSavedPosition(<%= base_params_sig -%> , int bufferPosition) {
412+ // This method mutates the buffer position and may be called from different threads so we must synchronize
413+ synchronized (this) {
414+ buffer.position(bufferPosition);
415+ return createDefNode(<%= base_params . join ( ", " ) -%> );
416+ }
417+ }
381418 <%- array_types . uniq . each do |type | -%>
382419
383420 private static final Nodes.<%= type %> [] EMPTY_<%= type %> _ARRAY = {};
0 commit comments