com.facebook.presto.bytecode.MethodGenerationContext Maven / Gradle / Ivy
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.facebook.presto.bytecode;
import com.facebook.presto.bytecode.debug.LocalVariableNode;
import com.facebook.presto.bytecode.instruction.LabelNode;
import com.google.common.collect.ImmutableList;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
public class MethodGenerationContext
{
private final MethodVisitor methodVisitor;
private final Set allEnteredScopes = new LinkedHashSet<>();
private final Deque scopes = new ArrayDeque<>();
private final Map variableSlots = new HashMap<>();
private int nextSlot;
private int currentLineNumber = -1;
public MethodGenerationContext(MethodVisitor methodVisitor)
{
this.methodVisitor = requireNonNull(methodVisitor, "methodVisitor is null");
}
public void enterScope(Scope scope)
{
requireNonNull(scope, "scope is null");
checkArgument(!allEnteredScopes.contains(scope), "scope has already been entered");
allEnteredScopes.add(scope);
ScopeContext scopeContext = new ScopeContext(scope);
scopes.addLast(scopeContext);
for (Variable variable : scopeContext.getVariables()) {
checkArgument(!"this".equals(variable.getName()) || nextSlot == 0, "The 'this' variable must be in slot 0");
variableSlots.put(variable, nextSlot);
nextSlot += Type.getType(variable.getType().getType()).getSize();
}
scopeContext.getStartLabel().accept(methodVisitor, this);
}
public void exitScope(Scope scope)
{
checkArgument(allEnteredScopes.contains(scope), "scope has not been entered");
checkArgument(!scopes.isEmpty() && scope == scopes.peekLast().getScope(), "Scope is not top of the stack");
ScopeContext scopeContext = scopes.removeLast();
scopeContext.getEndLabel().accept(methodVisitor, this);
for (Variable variable : scopeContext.getVariables()) {
new LocalVariableNode(variable, scopeContext.getStartLabel(), scopeContext.getEndLabel()).accept(methodVisitor, this);
}
variableSlots.keySet().removeAll(scopeContext.getVariables());
}
public int getVariableSlot(Variable variable)
{
Integer slot = variableSlots.get(variable);
checkArgument(slot != null, "Variable '%s' has not been assigned a slot", variable);
return slot;
}
public boolean updateLineNumber(int lineNumber)
{
if (lineNumber == currentLineNumber) {
return false;
}
currentLineNumber = lineNumber;
return true;
}
private final class ScopeContext
{
private final Scope scope;
private final ImmutableList variables;
private final LabelNode startLabel = new LabelNode("VariableStart");
private final LabelNode endLabel = new LabelNode("VariableEnd");
public ScopeContext(Scope scope)
{
this.scope = scope;
this.variables = ImmutableList.copyOf(scope.getVariables());
}
public Scope getScope()
{
return scope;
}
public ImmutableList getVariables()
{
return variables;
}
public LabelNode getStartLabel()
{
return startLabel;
}
public LabelNode getEndLabel()
{
return endLabel;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy