public InlineCloneInfo cloneForInliningClosure(IRScope scopeBeingInlined) { InlineCloneInfo clone = new InlineCloneInfo(hostCFG, hostCFG.getScope(), scopeBeingInlined); clone.call = this.call; clone.callArgs = this.callArgs; clone.callReceiver = this.callReceiver; return clone; }
@Override public Instr clone(CloneInfo info) { if (info instanceof SimpleCloneInfo) return new ReceiveRestArgInstr(info.getRenamedVariable(result), required, argIndex); InlineCloneInfo ii = (InlineCloneInfo) info; // FIXME: Check this if (ii.canMapArgsStatically()) return new CopyInstr(ii.getRenamedVariable(result), ii.getArg(argIndex, true)); return new RestArgMultipleAsgnInstr(ii.getRenamedVariable(result), ii.getArgs(), argIndex, (required - argIndex), argIndex); }
@Override public Instr clone(CloneInfo info) { if (info instanceof SimpleCloneInfo) return new CheckArityInstr(required, opt, rest, receivesKeywords, restKey); InlineCloneInfo ii = (InlineCloneInfo) info; if (ii.canMapArgsStatically()) { // we can error on bad arity or remove check_arity int numArgs = ii.getArgsCount(); if (numArgs < required || (!rest && numArgs > (required + opt))) { return new RaiseArgumentErrorInstr(required, opt, rest, numArgs); } return null; } return new CheckArgsArrayArityInstr(ii.getArgs(), required, opt, rest); }
@Override public Operand cloneForInlining(CloneInfo ii) { if (ii instanceof InlineCloneInfo) { InlineCloneInfo iici = (InlineCloneInfo) ii; // inlined method lives somewhere else so we need to save that scope location. if (iici.getHostScope() != iici.getScopeBeingInlined()) { return new Scope(((InlineCloneInfo) ii).getScopeBeingInlined()); } } return this; }
@Override public Instr clone(CloneInfo info) { if (info instanceof SimpleCloneInfo) return new LoadFrameClosureInstr(info.getRenamedVariable(result)); // SSS FIXME: This code below is for inlining and is untested. InlineCloneInfo ii = (InlineCloneInfo) info; // SSS FIXME: This is not strictly correct -- we have to wrap the block into an // operand type that converts the static code block to a proc which is a closure. if (ii.getCallClosure() instanceof WrappedIRClosure) return NopInstr.NOP; return new CopyInstr(ii.getRenamedVariable(result), ii.getCallClosure()); }
@Override public Instr clone(CloneInfo info) { if (info instanceof SimpleCloneInfo) return new NonlocalReturnInstr(getReturnValue().cloneForInlining(info), methodName); InlineCloneInfo ii = (InlineCloneInfo) info; if (ii.isClosure()) { if (ii.getHostScope() instanceof IRMethod) { // Lexically contained non-local returns can return directly if the live in the method they are inlining to. if (((InlineCloneInfo) info).getScopeBeingInlined().isScopeContainedBy(ii.getHostScope())) { return new ReturnInstr(getReturnValue().cloneForInlining(ii)); } // Treat like inlining of a regular method-return (note: a jump is added to exit so this copy // actually ends up being the methods return value). Variable v = ii.getCallResultVariable(); return v == null ? null : new CopyInstr(v, getReturnValue().cloneForInlining(ii)); } return new NonlocalReturnInstr(getReturnValue().cloneForInlining(ii), methodName); } else { throw new UnsupportedOperationException("Nonlocal returns shouldn't show up outside closures."); } }
InlineCloneInfo ii = new InlineCloneInfo(call, cfg, callReceiverVar, scopeToInline); if (x.isEntryBB() || x.isExitBB()) continue; BasicBlock rx = ii.getRenamedBB(x); for (Edge<BasicBlock> e : methodToInline.getOutgoingEdges(x)) { BasicBlock b = e.getDestination().getData(); if (!b.isExitBB()) cfg.addEdge(rx, ii.getRenamedBB(b), e.getType()); if (destination.isExitBB()) continue; BasicBlock dstBB = ii.getRenamedBB(destination); if (!ii.canMapArgsStatically()) { return "cannot assign non-statically assigned method arguments"; BasicBlock clonedSource = ii.getRenamedBB(source); if (e.getType() == EdgeType.EXCEPTION) { BasicBlock xRenamed = ii.getRenamedBB(x); BasicBlock xProtector = methodToInline.getRescuerBBFor(x); if (xProtector != null) { cfg.setRescuerBB(xRenamed, ii.getRenamedBB(xProtector)); } else if (callBBrescuer != null) { cfg.setRescuerBB(xRenamed, callBBrescuer); List yieldSites = ii.getYieldSites(); if (closureArg != null && !yieldSites.isEmpty()) {
@Override public Instr clone(CloneInfo info) { if (info instanceof SimpleCloneInfo) return new ReturnInstr(getReturnValue().cloneForInlining(info)); InlineCloneInfo ii = (InlineCloneInfo) info; if (ii.isClosure()) return new CopyInstr(ii.getYieldResult(), getReturnValue().cloneForInlining(ii)); Variable v = ii.getCallResultVariable(); return v == null ? null : new CopyInstr(v, getReturnValue().cloneForInlining(ii)); }
public BasicBlock cloneForInlining(InlineCloneInfo ii) { BasicBlock clonedBB = ii.getOrCreateRenamedBB(this); for (Instr i: getInstrs()) { Instr clonedInstr = i.clone(ii); if (clonedInstr != null) { clonedBB.addInstr(clonedInstr); if (clonedInstr instanceof YieldInstr) { ii.recordYieldSite(clonedBB, (YieldInstr)clonedInstr); } else if (i instanceof NonlocalReturnInstr && clonedInstr instanceof CopyInstr) { // non-local returns assign to method return variable but must jump to proper exit point clonedBB.addInstr(new JumpInstr(ii.getHostScope().getCFG().getExitBB().getLabel())); // FIXME: enebo...I see no guarantee that this copy will be part of a return? This behavior is // masked in any case I can see with optimization to not use a copy but convert non-local to local return. } } } return clonedBB; }
ii = ii.cloneForInliningClosure(cl); ii.setupYieldArgsAndYieldResult(yield, beforeInlineBB, cl.getBlockBody().getSignature().arityValue()); if (b.isEntryBB() || b.isExitBB()) continue; BasicBlock bClone = ii.getRenamedBB(b); for (Edge<BasicBlock> e : closureCFG.getOutgoingEdges(b)) { BasicBlock edst = e.getDestination().getData(); if (!edst.isExitBB() && edst != closureGEB) cfg.addEdge(bClone, ii.getRenamedBB(edst), e.getType()); BasicBlock destination = e.getDestination().getData(); if (!destination.isExitBB() && destination != closureGEB) { cfg.addEdge(beforeInlineBB, ii.getRenamedBB(destination), CFG.EdgeType.FALL_THROUGH); if (source.isEntryBB()) continue; BasicBlock clonedSource = ii.getRenamedBB(source); if (cb.isEntryBB() || cb.isExitBB() || cb == closureGEB) continue; BasicBlock cbProtector = ii.getRenamedBB(closureCFG.getRescuerBBFor(cb)); if (cbProtector != null) { cfg.setRescuerBB(ii.getRenamedBB(cb), cbProtector); } else if (yieldBBrescuer != null) { cfg.setRescuerBB(ii.getRenamedBB(cb), yieldBBrescuer);
public InlineCloneInfo(CallBase call, CFG c, Variable callReceiver, IRScope scopeBeingInlined) { super( c.getScope()); this.isClosure = false; this.hostCFG = c; this.call = call; this.callArgs = call.getCallArgs(); this.callReceiver = callReceiver; this.canMapArgsStatically = !containsSplat(callArgs); this.argsArray = this.canMapArgsStatically ? null : getHostScope().createTemporaryVariable(); this.scopeBeingInlined = scopeBeingInlined; synchronized(globalInlineCount) { this.inlineVarPrefix = new ByteList(("%in" + globalInlineCount + "_").getBytes()); globalInlineCount++; } }
protected Label getRenamedLabelSimple(Label l) { return getHostScope().getNewLabel(); }
public Operand getArg(int argIndex, boolean restOfArgArray) { if (!restOfArgArray) return getArg(argIndex); if (isClosure) throw new RuntimeException("Cannot get rest yield arg at inline time!"); if (argIndex >= callArgs.length) return new Array(); Operand[] tmp = new Operand[callArgs.length - argIndex]; System.arraycopy(callArgs, argIndex, tmp, 0, callArgs.length - argIndex); return new Array(tmp); }
public Operand getArg(int index) { // yield 1 -> { |a| } case if (canMapArgsStatically && isClosure && !(yieldArg instanceof Array)) return yieldArg; return index < getArgsCount() ? (isClosure ? ((Array)yieldArg).get(index) : callArgs[index]) : null; }
@Override public Instr clone(CloneInfo info) { if (info instanceof SimpleCloneInfo) return new NonlocalReturnInstr(getReturnValue().cloneForInlining(info), methodName); InlineCloneInfo ii = (InlineCloneInfo) info; if (ii.isClosure()) { if (ii.getHostScope() instanceof IRMethod) { // Lexically contained non-local returns can return directly if the live in the method they are inlining to. if (((InlineCloneInfo) info).getScopeBeingInlined().isScopeContainedBy(ii.getHostScope())) { return new ReturnInstr(getReturnValue().cloneForInlining(ii)); } // Treat like inlining of a regular method-return (note: a jump is added to exit so this copy // actually ends up being the methods return value). Variable v = ii.getCallResultVariable(); return v == null ? null : new CopyInstr(v, getReturnValue().cloneForInlining(ii)); } return new NonlocalReturnInstr(getReturnValue().cloneForInlining(ii), methodName); } else { throw new UnsupportedOperationException("Nonlocal returns shouldn't show up outside closures."); } }
InlineCloneInfo ii = new InlineCloneInfo(call, cfg, callReceiverVar, scopeToInline); if (x.isEntryBB() || x.isExitBB()) continue; BasicBlock rx = ii.getRenamedBB(x); for (Edge<BasicBlock> e : methodToInline.getOutgoingEdges(x)) { BasicBlock b = e.getDestination().getData(); if (!b.isExitBB()) cfg.addEdge(rx, ii.getRenamedBB(b), e.getType()); if (destination.isExitBB()) continue; BasicBlock dstBB = ii.getRenamedBB(destination); if (!ii.canMapArgsStatically()) { return "cannot assign non-statically assigned method arguments"; BasicBlock clonedSource = ii.getRenamedBB(source); if (e.getType() == EdgeType.EXCEPTION) { BasicBlock xRenamed = ii.getRenamedBB(x); BasicBlock xProtector = methodToInline.getRescuerBBFor(x); if (xProtector != null) { cfg.setRescuerBB(xRenamed, ii.getRenamedBB(xProtector)); } else if (callBBrescuer != null) { cfg.setRescuerBB(xRenamed, callBBrescuer); List yieldSites = ii.getYieldSites(); if (closureArg != null && !yieldSites.isEmpty()) {
@Override public Operand cloneForInlining(CloneInfo ii) { if (ii instanceof InlineCloneInfo) { InlineCloneInfo iici = (InlineCloneInfo) ii; // inlined method lives somewhere else so we need to save that scope location. if (iici.getHostScope() != iici.getScopeBeingInlined()) { return new Scope(((InlineCloneInfo) ii).getScopeBeingInlined()); } } return this; }
@Override public Instr clone(CloneInfo info) { if (info instanceof SimpleCloneInfo) return new ReturnInstr(getReturnValue().cloneForInlining(info)); InlineCloneInfo ii = (InlineCloneInfo) info; if (ii.isClosure()) return new CopyInstr(ii.getYieldResult(), getReturnValue().cloneForInlining(ii)); Variable v = ii.getCallResultVariable(); return v == null ? null : new CopyInstr(v, getReturnValue().cloneForInlining(ii)); }
public BasicBlock cloneForInlining(InlineCloneInfo ii) { BasicBlock clonedBB = ii.getOrCreateRenamedBB(this); for (Instr i: getInstrs()) { Instr clonedInstr = i.clone(ii); if (clonedInstr != null) { clonedBB.addInstr(clonedInstr); if (clonedInstr instanceof YieldInstr) { ii.recordYieldSite(clonedBB, (YieldInstr)clonedInstr); } else if (i instanceof NonlocalReturnInstr && clonedInstr instanceof CopyInstr) { // non-local returns assign to method return variable but must jump to proper exit point clonedBB.addInstr(new JumpInstr(ii.getHostScope().getCFG().getExitBB().getLabel())); // FIXME: enebo...I see no guarantee that this copy will be part of a return? This behavior is // masked in any case I can see with optimization to not use a copy but convert non-local to local return. } } } return clonedBB; }
ii = ii.cloneForInliningClosure(cl); ii.setupYieldArgsAndYieldResult(yield, beforeInlineBB, cl.getBlockBody().getSignature().arityValue()); if (b.isEntryBB() || b.isExitBB()) continue; BasicBlock bClone = ii.getRenamedBB(b); for (Edge<BasicBlock> e : closureCFG.getOutgoingEdges(b)) { BasicBlock edst = e.getDestination().getData(); if (!edst.isExitBB() && edst != closureGEB) cfg.addEdge(bClone, ii.getRenamedBB(edst), e.getType()); BasicBlock destination = e.getDestination().getData(); if (!destination.isExitBB() && destination != closureGEB) { cfg.addEdge(beforeInlineBB, ii.getRenamedBB(destination), CFG.EdgeType.FALL_THROUGH); if (source.isEntryBB()) continue; BasicBlock clonedSource = ii.getRenamedBB(source); if (cb.isEntryBB() || cb.isExitBB() || cb == closureGEB) continue; BasicBlock cbProtector = ii.getRenamedBB(closureCFG.getRescuerBBFor(cb)); if (cbProtector != null) { cfg.setRescuerBB(ii.getRenamedBB(cb), cbProtector); } else if (yieldBBrescuer != null) { cfg.setRescuerBB(ii.getRenamedBB(cb), yieldBBrescuer);