public void lower(ArrayCopySlowPathNode arraycopy, LoweringTool tool) { StructuredGraph graph = arraycopy.graph(); if (!graph.getGuardsStage().areFrameStatesAtDeopts()) { // Can't be lowered yet return; } SnippetInfo snippetInfo = arraycopy.getSnippet(); Arguments args = new Arguments(snippetInfo, graph.getGuardsStage(), tool.getLoweringStage()); args.add("nonNullSrc", arraycopy.getSource()); args.add("srcPos", arraycopy.getSourcePosition()); args.add("nonNullDest", arraycopy.getDestination()); args.add("destPos", arraycopy.getDestinationPosition()); if (snippetInfo == arraycopyUnrolledWorkSnippet) { args.addConst("length", ((Integer) arraycopy.getArgument()).intValue()); args.addConst("elementKind", arraycopy.getElementKind()); } else { args.add("length", arraycopy.getLength()); } if (snippetInfo == arraycopyPredictedObjectWorkSnippet) { HotSpotResolvedObjectType arrayKlass = (HotSpotResolvedObjectType) tool.getMetaAccess().lookupJavaType(Object[].class); ValueNode objectArrayKlass = ConstantNode.forConstant( KlassPointerStamp.klassNonNull(), arrayKlass.klass(), tool.getMetaAccess(), arraycopy.graph()); args.add("objectArrayKlass", objectArrayKlass); args.addConst("counter", arraycopyCallCounters.get(JavaKind.Object)); args.addConst("copiedCounter", arraycopyCallCopiedCounters.get(JavaKind.Object)); } instantiate(args, arraycopy); }
/** * Instantiate the snippet template and fix up the FrameState of any Invokes of System.arraycopy * and propagate the captured bci in the ArrayCopySlowPathNode. * * @param args * @param arraycopy */ private void instantiate(Arguments args, BasicArrayCopyNode arraycopy) { StructuredGraph graph = arraycopy.graph(); SnippetTemplate template = template(args); Map<Node, Node> replacements = template.instantiate( providers.getMetaAccess(), arraycopy, SnippetTemplate.DEFAULT_REPLACER, args); for (Node originalNode : replacements.keySet()) { if (originalNode instanceof Invoke) { Invoke invoke = (Invoke) replacements.get(originalNode); assert invoke.asNode().graph() == graph; CallTargetNode call = invoke.callTarget(); if (!call.targetMethod().equals(originalArraycopy)) { throw new GraalError("unexpected invoke %s in snippet", call.targetMethod()); } // Here we need to fix the bci of the invoke InvokeNode newInvoke = graph.add(new InvokeNode(invoke.callTarget(), arraycopy.getBci())); if (arraycopy.stateDuring() != null) { newInvoke.setStateDuring(arraycopy.stateDuring()); } else { assert arraycopy.stateAfter() != null; newInvoke.setStateAfter(arraycopy.stateAfter()); } graph.replaceFixedWithFixed((InvokeNode) invoke.asNode(), newInvoke); } else if (originalNode instanceof ArrayCopySlowPathNode) { ArrayCopySlowPathNode slowPath = (ArrayCopySlowPathNode) replacements.get(originalNode); assert arraycopy.stateAfter() != null; slowPath.setStateAfter(arraycopy.stateAfter()); slowPath.setBci(arraycopy.getBci()); } } }
/** * This is the basic template for the full arraycopy checks, including a check that the underlying * type is really an array type. */ @Snippet public static void arraycopySlowPathIntrinsic( Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter JavaKind elementKind, @ConstantParameter SnippetInfo slowPath, @ConstantParameter Object slowPathArgument) { Object nonNullSrc = GraalDirectives.guardingNonNull(src); Object nonNullDest = GraalDirectives.guardingNonNull(dest); KlassPointer srcHub = loadHub(nonNullSrc); KlassPointer destHub = loadHub(nonNullDest); checkArrayType(srcHub); checkArrayType(destHub); checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length); if (length == 0) { zeroLengthDynamicCounter.inc(); } else { nonZeroLengthDynamicCounter.inc(); nonZeroLengthDynamicCopiedCounter.add(length); } ArrayCopySlowPathNode.arraycopy( nonNullSrc, srcPos, nonNullDest, destPos, length, elementKind, slowPath, slowPathArgument); }