package org.jruby.ir.persistence;
import org.jruby.EvalType;
import org.jruby.RubyInstanceConfig;
import org.jruby.ir.*;
import org.jruby.parser.StaticScope;
import org.jruby.parser.StaticScopeFactory;
import org.jruby.runtime.Signature;
import java.io.IOException;
import java.util.EnumSet;
import org.jruby.util.ByteList;
public class IRReader implements IRPersistenceValues {
public static IRScope load(IRManager manager, final IRReaderDecoder file) throws IOException {
int version = file.decodeIntRaw();
if (version != VERSION) {
throw new IOException("Trying to read incompatible persistence format (version found: " +
version + ", version expected: " + VERSION);
}
int headersOffset = file.decodeIntRaw();
if (RubyInstanceConfig.IR_READING_DEBUG) System.out.println("header_offset = " + headersOffset);
file.seek(headersOffset);
int scopesToRead = file.decodeInt();
if (RubyInstanceConfig.IR_READING_DEBUG) System.out.println("scopes to read = " + scopesToRead);
IRScope firstScope = null;
for (int i = 0; i < scopesToRead; i++) {
IRScopeType type = file.decodeIRScopeType();
int line = file.decodeInt();
int tempVarsCount = file.decodeInt();
int nextLabelInt = file.decodeInt();
IRScope scope = decodeScopeHeader(manager, file, type, line);
scope.setNextLabelIndex(nextLabelInt);
EnumSet<IRFlags> flags = file.decodeIRFlags();
if (file.decodeBoolean()) scope.setHasBreakInstructions();
if (file.decodeBoolean()) scope.setHasLoops();
if (file.decodeBoolean()) scope.setHasNonLocalReturns();
if (file.decodeBoolean()) scope.setReceivesClosureArg();
if (file.decodeBoolean()) scope.setReceivesKeywordArgs();
if (file.decodeBoolean()) scope.setAccessesParentsLocalVariables();
if (file.decodeBoolean()) scope.setIsMaybeUsingRefinements();
if (file.decodeBoolean()) scope.setCanCaptureCallersBinding();
if (file.decodeBoolean()) scope.setCanReceiveBreaks();
if (file.decodeBoolean()) scope.setCanReceiveNonlocalReturns();
if (file.decodeBoolean()) scope.setUsesZSuper();
if (file.decodeBoolean()) scope.setNeedsCodeCoverage();
if (file.decodeBoolean()) scope.setUsesEval();
if (firstScope == null) firstScope = scope;
int instructionsOffset = file.decodeInt();
int poolOffset = file.decodeInt();
scope.allocateInterpreterContext(() -> file.dup().decodeInstructionsAt(scope, poolOffset, instructionsOffset), tempVarsCount, flags);
}
return firstScope;
}
private static IRScope (IRManager manager, IRReaderDecoder decoder, IRScopeType type, int line) {
if (RubyInstanceConfig.IR_READING_DEBUG) System.out.println("DECODING SCOPE HEADER");
boolean isEND = false;
Signature signature;
if (type == IRScopeType.CLOSURE || type == IRScopeType.FOR) {
isEND = decoder.decodeBoolean();
signature = Signature.decode(decoder.decodeLong());
} else {
signature = Signature.OPTIONAL;
}
String file = null;
ByteList name = null;
IRScope parent = null;
if (type == IRScopeType.SCRIPT_BODY) {
file = decoder.decodeString();
} else {
name = decoder.decodeByteList();
parent = decoder.decodeScope();
}
StaticScope parentScope = parent == null ? null : parent.getStaticScope();
StaticScope staticScope = decodeStaticScope(decoder, parentScope);
IRScope scope = createScope(manager, type, name, file, line, parent, signature, staticScope);
if (scope instanceof IRClosure && isEND) {
((IRClosure) scope).setIsEND();
}
decoder.addScope(scope);
return scope;
}
private static StaticScope decodeStaticScope(IRReaderDecoder decoder, StaticScope parentScope) {
StaticScope scope = StaticScopeFactory.newStaticScope(parentScope, decoder.decodeStaticScopeType(), decoder.decodeStringArray(), decoder.decodeInt());
scope.setSignature(decoder.decodeSignature());
return scope;
}
public static IRScope createScope(IRManager manager, IRScopeType type, ByteList byteName, String file, int line,
IRScope lexicalParent, Signature signature, StaticScope staticScope) {
switch (type) {
case CLASS_BODY:
return new IRClassBody(manager, lexicalParent, byteName, line, staticScope, false);
case METACLASS_BODY:
return new IRMetaClassBody(manager, lexicalParent, manager.getMetaClassName().getBytes(), line, staticScope);
case INSTANCE_METHOD:
return new IRMethod(manager, lexicalParent, null, byteName, true, line, staticScope, false);
case CLASS_METHOD:
return new IRMethod(manager, lexicalParent, null, byteName, false, line, staticScope, false);
case MODULE_BODY:
return new IRModuleBody(manager, lexicalParent, byteName, line, staticScope, false);
case SCRIPT_BODY:
return new IRScriptBody(manager, file, staticScope);
case FOR:
return new IRFor(manager, lexicalParent, line, staticScope, signature);
case CLOSURE:
return new IRClosure(manager, lexicalParent, line, staticScope, signature);
case EVAL_SCRIPT:
return new IREvalScript(manager, lexicalParent, lexicalParent.getFileName(), line, staticScope, EvalType.NONE);
}
throw new RuntimeException("No such scope type: " + type);
}
}