Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2009-2010 Ken Wenzel and Mathias Doenitz
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.parboiled.transform;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.FieldNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.IntInsnNode;
import org.objectweb.asm.tree.JumpInsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.TypeInsnNode;
import org.objectweb.asm.tree.VarInsnNode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static org.parboiled.common.Preconditions.checkArgNotNull;
import static org.parboiled.common.Preconditions.checkState;
import static org.parboiled.common.Utils.toObjectArray;
import static org.objectweb.asm.Opcodes.AASTORE;
import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
import static org.objectweb.asm.Opcodes.ALOAD;
import static org.objectweb.asm.Opcodes.ANEWARRAY;
import static org.objectweb.asm.Opcodes.ARETURN;
import static org.objectweb.asm.Opcodes.ASTORE;
import static org.objectweb.asm.Opcodes.BIPUSH;
import static org.objectweb.asm.Opcodes.CHECKCAST;
import static org.objectweb.asm.Opcodes.DLOAD;
import static org.objectweb.asm.Opcodes.DUP;
import static org.objectweb.asm.Opcodes.DUP_X1;
import static org.objectweb.asm.Opcodes.DUP_X2;
import static org.objectweb.asm.Opcodes.FLOAD;
import static org.objectweb.asm.Opcodes.GETFIELD;
import static org.objectweb.asm.Opcodes.IFNONNULL;
import static org.objectweb.asm.Opcodes.IFNULL;
import static org.objectweb.asm.Opcodes.ILOAD;
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
import static org.objectweb.asm.Opcodes.INVOKESTATIC;
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
import static org.objectweb.asm.Opcodes.LLOAD;
import static org.objectweb.asm.Opcodes.NEW;
import static org.objectweb.asm.Opcodes.POP;
import static org.objectweb.asm.Opcodes.PUTFIELD;
import static org.objectweb.asm.Opcodes.SWAP;
/**
* Wraps the method code with caching and proxying constructs.
*/
class CachingGenerator implements RuleMethodProcessor {
private ParserClassNode classNode;
private RuleMethod method;
private InsnList instructions;
private AbstractInsnNode current;
private String cacheFieldName;
public boolean appliesTo(ParserClassNode classNode, RuleMethod method) {
checkArgNotNull(classNode, "classNode");
checkArgNotNull(method, "method");
return method.hasCachedAnnotation();
}
public void process(ParserClassNode classNode, RuleMethod method) throws Exception {
checkArgNotNull(classNode, "classNode");
checkArgNotNull(method, "method");
checkState(!method.isSuperMethod()); // super methods have flag moved to the overriding method
this.classNode = classNode;
this.method = method;
this.instructions = method.instructions;
this.current = instructions.getFirst();
generateCacheHitReturn();
generateStoreNewProxyMatcher();
seekToReturnInstruction();
generateArmProxyMatcher();
generateStoreInCache();
}
// if ( != null) return ;
private void generateCacheHitReturn() {
// stack:
generateGetFromCache();
// stack:
insert(new InsnNode(DUP));
// stack: ::
LabelNode cacheMissLabel = new LabelNode();
insert(new JumpInsnNode(IFNULL, cacheMissLabel));
// stack:
insert(new InsnNode(ARETURN));
// stack:
insert(cacheMissLabel);
// stack:
insert(new InsnNode(POP));
// stack:
}
@SuppressWarnings( {"unchecked"})
private void generateGetFromCache() {
Type[] paramTypes = Type.getArgumentTypes(method.desc);
cacheFieldName = findUnusedCacheFieldName();
// if we have no parameters we use a simple Rule field as cache, otherwise a HashMap
String cacheFieldDesc = paramTypes.length == 0 ? Types.RULE_DESC : "Ljava/util/HashMap;";
classNode.fields.add(new FieldNode(ACC_PRIVATE, cacheFieldName, cacheFieldDesc, null, null));
// stack:
insert(new VarInsnNode(ALOAD, 0));
// stack:
insert(new FieldInsnNode(GETFIELD, classNode.name, cacheFieldName, cacheFieldDesc));
// stack:
if (paramTypes.length == 0) return; // if we have no parameters we are done
// generate: if ( == null) = new HashMap