private void setupLexicalContainment() { if (manager.isDryRun() || RubyInstanceConfig.IR_WRITING || RubyInstanceConfig.RECORD_LEXICAL_HIERARCHY) { lexicalChildren = new ArrayList<>(1); if (lexicalParent != null) lexicalParent.addChildScope(this); } }
public LocalVariable getNewFlipStateVariable() { ByteList flip = FLIP.dup(); flip.append(allocateNextPrefixedName("%flip")); return getLocalVariable(getManager().getRuntime().newSymbol(flip) , 0); }
public boolean needsFrame() { boolean bindingHasEscaped = bindingHasEscaped(); boolean requireFrame = bindingHasEscaped || usesEval(); for (IRFlags flag : getFlags()) { switch (flag) { case BINDING_HAS_ESCAPED: case CAN_CAPTURE_CALLERS_BINDING: case REQUIRES_LASTLINE: case REQUIRES_BACKREF: case REQUIRES_VISIBILITY: case REQUIRES_BLOCK: case REQUIRES_SELF: case REQUIRES_METHODNAME: case REQUIRES_CLASS: case USES_EVAL: case USES_ZSUPER: requireFrame = true; } } return requireFrame; }
public LocalVariable getNewFlipStateVariable() { return getLocalVariable("%flip_" + allocateNextPrefixedName("%flip"), 0); }
private Operand findContainerModule() { int nearestModuleBodyDepth = scope.getNearestModuleReferencingScopeDepth(); return (nearestModuleBodyDepth == -1) ? scope.getCurrentModuleVariable() : ScopeModule.ModuleFor(nearestModuleBodyDepth); }
private Operand buildSuperInstr(IRScope s, Operand block, Operand[] args) { CallInstr superInstr; Variable ret = s.getNewTemporaryVariable(); if ((s instanceof IRMethod) && (s.getLexicalParent() instanceof IRClassBody)) { IRMethod m = (IRMethod)s; if (m.isInstanceMethod) { superInstr = new InstanceSuperInstr(ret, s.getCurrentModuleVariable(), new MethAddr(s.getName()), args, block); } else { superInstr = new ClassSuperInstr(ret, s.getCurrentModuleVariable(), new MethAddr(s.getName()), args, block); } } else { // We dont always know the method name we are going to be invoking if the super occurs in a closure. // This is because the super can be part of a block that will be used by 'define_method' to define // a new method. In that case, the method called by super will be determined by the 'name' argument // to 'define_method'. superInstr = new UnresolvedSuperInstr(ret, getSelf(s), args, block); } receiveBreakException(s, block, superInstr); return ret; }
boolean scopeBindingHasEscaped = scope.bindingHasEscaped(); it.next(); for (LocalVariable v: reqdLoads) { if (!scope.definesLocalVariable(v)) { it.add(new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v)); it.previous(); if ((scope instanceof IRClosure) && (basicBlock == problem.getScope().cfg().getEntryBB())) { if (scope.usesLocalVariable(v) || scope.definesLocalVariable(v)) { if (isEvalScript || !(v instanceof ClosureLocalVariable) || (scope != ((ClosureLocalVariable)v).definingScope)) { it.add(new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
public boolean usesLocalVariable(Variable v) { if (usedLocalVars == null) setUpUseDefLocalVarMaps(); if (usedLocalVars.contains(v)) return true; for (IRClosure cl : getClosures()) { if (cl.usesLocalVariable(v)) return true; } return false; }
public IRClosure cloneForInlining(CloneInfo ii) { IRClosure clonedClosure; IRScope lexicalParent = ii.getScope(); if (ii instanceof SimpleCloneInfo && !((SimpleCloneInfo)ii).isEnsureBlockCloneMode()) { clonedClosure = new IRClosure(this, lexicalParent, closureId, getName()); } else { int id = lexicalParent.getNextClosureId(); ByteList fullName = lexicalParent.getName().getBytes().dup(); fullName.append(CLOSURE_CLONE); fullName.append(new Integer(id).toString().getBytes()); clonedClosure = new IRClosure(this, lexicalParent, id, getManager().runtime.newSymbol(fullName)); } // WrappedIRClosure should always have a single unique IRClosure in them so we should // not end up adding n copies of the same closure as distinct clones... lexicalParent.addClosure(clonedClosure); return cloneForInlining(ii, clonedClosure); }
public void addLoads(Map<Operand, Operand> varRenameMap) { IRScope scope = problem.getScope(); boolean isEvalScript = scope instanceof IREvalScript; boolean scopeBindingHasEscaped = scope.bindingHasEscaped(); for (Iterator<LocalVariable> iter = reqdLoads.iterator(); iter.hasNext();) { LocalVariable v = iter.next(); if (!scope.definesLocalVariable(v)) { it.add(new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v)); it.previous(); if (scope.usesLocalVariable(v) || scope.definesLocalVariable(v)) { if (isEvalScript || !(v instanceof ClosureLocalVariable) || ((ClosureLocalVariable)v).isOuterScopeVar()) { it.add(new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
@Override public Object execute(IRScope s, Object... data) { for (BasicBlock b: s.getCFG().getBasicBlocks()) { runLocalOptsOnBasicBlock(s, b); } // SSS FIXME: What is this about? // Why 'Only after running local opts'? Figure out and document. // // Only after running local opts, compute various execution scope flags. s.computeScopeFlags(); // LVA information is no longer valid after this pass // Currently, we don't run this after LVA, but just in case ... // // FIXME: Grrr ... this seems broken to have to create a new object to invalidate (new LiveVariableAnalysis()).invalidate(s); return null; }
private InterpreterContext buildPrePostExeInner(Node body) { // Set up %current_scope and %current_module addInstr(new CopyInstr(scope.getCurrentScopeVariable(), CurrentScope.INSTANCE)); addInstr(new CopyInstr(scope.getCurrentModuleVariable(), SCOPE_MODULE[0])); build(body); // END does not have either explicit or implicit return, so we add one addInstr(new ReturnInstr(new Nil())); return scope.allocateInterpreterContext(instructions); }
private Operand buildSuperInstr(Operand block, Operand[] args) { CallInstr superInstr; Variable ret = createTemporaryVariable(); if (scope instanceof IRMethod && scope.getLexicalParent() instanceof IRClassBody) { if (((IRMethod) scope).isInstanceMethod) { superInstr = new InstanceSuperInstr(scope, ret, scope.getCurrentModuleVariable(), getName(), args, block, scope.maybeUsingRefinements()); } else { superInstr = new ClassSuperInstr(scope, ret, scope.getCurrentModuleVariable(), getName(), args, block, scope.maybeUsingRefinements()); } } else { // We dont always know the method name we are going to be invoking if the super occurs in a closure. // This is because the super can be part of a block that will be used by 'define_method' to define // a new method. In that case, the method called by super will be determined by the 'name' argument // to 'define_method'. superInstr = new UnresolvedSuperInstr(scope, ret, buildSelf(), args, block, scope.maybeUsingRefinements()); } receiveBreakException(block, superInstr); return ret; }
public Operand buildLambda(LambdaNode node, IRScope s) { IRClosure closure = new IRClosure(manager, s, false, node.getPosition().getStartLine(), node.getScope(), Arity.procArityOf(node.getArgs()), node.getArgumentType(), true); s.addClosure(closure); // Create a new nested builder to ensure this gets its own IR builder state // like the ensure block stack IRBuilder closureBuilder = newIRBuilder(manager); // Receive self closure.addInstr(new ReceiveSelfInstr(getSelf(closure))); // args closureBuilder.receiveBlockArgs(node, closure); closureBuilder.receiveBlockClosureArg(node.getBlockVarNode(), closure); Operand closureRetVal = node.getBody() == null ? manager.getNil() : closureBuilder.build(node.getBody(), closure); // can be U_NIL if the node is an if node with returns in both branches. if (closureRetVal != U_NIL) closure.addInstr(new ReturnInstr(closureRetVal)); // Added as part of 'prepareForInterpretation' code. // catchUncaughtBreakInLambdas(closure); Variable lambda = s.getNewTemporaryVariable(); s.addInstr(new BuildLambdaInstr(lambda, closure, node.getPosition())); return lambda; }
public boolean canBeDeleted(IRScope s) { if (hasSideEffects() || getOperation().isDebugOp() || getOperation().canRaiseException() || transfersControl()) { return false; } else if (this instanceof ResultInstr) { Variable r = ((ResultInstr)this).getResult(); if (s.bindingHasEscaped() && !r.getName().equals(Variable.BLOCK)) { // If the binding of this scope has escaped, then we have to preserve writes to // all local variables because anyone who uses the binding might query any of the // local variables from the binding. This is safe, but extremely conservative. return !(r instanceof LocalVariable); } else if (s.usesEval() && r.getName().equals(Variable.BLOCK)) { // If this scope (or any nested scope) has any evals, then the eval might have a yield which // would use %block. In that scenario, we cannot delete the '%block = recv_closure' instruction. // This is safe, but conservative. return false; } else if (s.usesZSuper() && getOperation().isArgReceive()) { // If this scope (or any nested scope) has a ZSuperInstr, then the arguments of this // scope could be used by any of those ZSuper instructions. If so, we cannot delete // the argument receive. return false; } else { return true; } } else { return true; } }
public boolean applyTransferFunction() { IRScope scope = problem.getScope(); boolean scopeBindingHasEscaped = scope.bindingHasEscaped(); if (!scope.definesLocalVariable(v)) newReqdLoads.remove(v); if ((basicBlock == problem.getScope().cfg().getEntryBB()) || basicBlock.isRescueEntry()) { reqdLoads.clear();
/** * Get the control flow graph */ public CFG getCFG() { return problem.scope.getCFG(); }
@Override public LocalVariable findExistingLocalVariable(String name, int scopeDepth) { // Look in the nearest non-eval scope's shared eval scope vars first. // If you dont find anything there, look in the nearest non-eval scope's regular vars. LocalVariable lvar = nearestNonEvalScope.evalScopeVars.getVariable(name); if ((lvar != null) || scopeDepth == 0) return lvar; else return nearestNonEvalScope.findExistingLocalVariable(name, scopeDepth-nearestNonEvalScopeDepth-1); }
private void addCurrentScopeAndModule() { addInstr(new CopyInstr(scope.getCurrentScopeVariable(), CurrentScope.INSTANCE)); // %current_scope addInstr(new CopyInstr(scope.getCurrentModuleVariable(), SCOPE_MODULE[0])); // %current_module }
/** * Find or create a local variable. By default, scopes are assumed to * only check current depth. Blocks/Closures override this because they * have special nesting rules. */ public LocalVariable getLocalVariable(RubySymbol name, int scopeDepth) { LocalVariable lvar = findExistingLocalVariable(name, scopeDepth); if (lvar == null) { lvar = getNewLocalVariable(name, scopeDepth); } else if (lvar.getScopeDepth() != scopeDepth) { lvar = lvar.cloneForDepth(scopeDepth); } return lvar; }