RefOptimizer.java

/*
 * Copyright (c) 2001-2017, Zoltan Farkas All Rights Reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * Additionally licensed with:
 *
 * 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 org.spf4j.zel.vm;

import java.util.Map;
import java.util.function.Function;
import javax.annotation.Nullable;
import org.spf4j.zel.instr.Instruction;
import org.spf4j.zel.instr.LODAX;
import org.spf4j.zel.instr.LODAXF;
import org.spf4j.zel.instr.LODX;
import org.spf4j.zel.instr.LODXF;

/**
 * Changes reference by name instructions to reference by index.
 * @author zoly
 */
public final class RefOptimizer implements Function<Program, Program> {

    private RefOptimizer() { }

    public static final Function<Program, Program> INSTANCE = new RefOptimizer();

    @Override
    public Program apply(final Program input) {
        if (input == null) {
            throw new IllegalArgumentException("Input cannot be null for " + this);
        }
        Instruction[] instructions = input.getInstructions().clone();
        Map<String, Integer> lsym = input.getLocalSymbolTable();
        Map<String, Integer> gsym = input.getGlobalSymbolTable();

        for (int i = 0; i < instructions.length; i++) {
            Instruction instr = instructions[i];
            if (LODX.class.equals(instr.getClass())) {
                String symbol = ((LODX) instr).getSymbol();
                Address addr = getAddress(lsym, symbol, gsym);
                if (addr == null) {
                  continue;
                }
                instructions[i] = new LODXF(addr);
            } else if (LODAX.class.equals(instr.getClass())) {
                String symbol = ((LODAX) instr).getSymbol();
                Address addr = getAddress(lsym, symbol, gsym);
                if (addr == null) {
                  continue;
                }
                instructions[i] = new LODAXF(addr);
            }
        }

        return new Program(input.getName(), input.getGlobalSymbolTable(),
                    input.getGlobalMem(), input.getLocalSymbolTable(),
                    instructions, input.getDebug(), input.getSource(),
                    input.getType(), input.getExecType(),
                    input.hasDeterministicFunctions(), input.getParameterNamesInternal());
    }

    @Nullable
    private static Address getAddress(final Map<String, Integer> lsym,
            final String symbol, final Map<String, Integer> gsym) {
        Address addr;
        Integer idx = lsym.get(symbol);
        if (idx == null) {
            idx = gsym.get(symbol);
            if (idx == null) {
              return null;
            }
            addr = new Address(idx, Address.Scope.GLOBAL);
        } else {
            addr = new Address(idx, Address.Scope.LOCAL);
        }
        return addr;
    }

}