/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- addMethodInfo
- addMethodBodyInfo
- createPoolId
- getPoolId
- semanticAssertion
- syntaxError
- dump
- getName
- getName
- getNamespace
- getNsset
- getUsualSuspectNamespaces
- getLabel
- generateLabel
- addScript
- semanticAnalysis
- finishTraits
- translateImmediate
- getNameId
- getMethod
- pushTraits
- popTraits
/* -*- Mode: Java; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is [Open Source Virtual Machine.].
*
* The Initial Developer of the Original Code is
* Adobe System Incorporated.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Adobe AS3 Team
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package abcasm;
import java.util.*;
import java.lang.reflect.Field;
import static abcasm.AbcConstants.*;
class AssemblerCore
{
AssemblerOptions options;
/**
* Scripts defined by this translation unit.
*/
Vector<ScriptInfo> scripts = new Vector<ScriptInfo>();
/**
* Functions defined by this translation unit in method ID order.
*/
Vector<MethodInfo> methodSignatures = new Vector<MethodInfo>();
int methodMasterId = 0;
Map<String,Integer> methodsByName = new HashMap<String,Integer>();
/**
* Method bodies, in entry order.
*/
List<MethodBodyInfo> methodBodies = new ArrayList<MethodBodyInfo>();
List<String> syntaxErrors = new LinkedList<String>();
List<String> semanticErrors = new LinkedList<String>();
/*
* ABC pools.
*/
Pool<Name> namePool = new Pool<Name>(1);
Pool<String> stringPool = new Pool<String>(1);
Pool<Integer> intPool = new Pool<Integer>(1);
Pool<Long> uintPool = new Pool<Long>(1);
Pool<Double> doublePool = new Pool<Double>(1);
Pool<Namespace> nsPool = new Pool<Namespace>(1);
Pool<Nsset> nssetPool = new Pool<Nsset>(1);
AssemblerCore(AssemblerOptions options)
{
this.options = options;
}
void addMethodInfo(MethodInfo new_function)
{
if ( methodsByName.containsKey(new_function.methodName) )
{
throw new IllegalArgumentException (
"Duplicate method name: " + new_function.methodName
);
}
methodSignatures.add(new_function);
new_function.methodId = methodMasterId++;
if ( new_function.methodName != null )
{
createPoolId(new_function.methodName);
methodsByName.put(new_function.methodName, new_function.methodId);
}
}
void addMethodBodyInfo(MethodBodyInfo new_body)
{
methodBodies.add(new_body);
}
Integer createPoolId(Object value)
{
if ( value instanceof Integer )
{
Integer iKey = (Integer)value;
return intPool.add(iKey);
}
else if ( value instanceof Long )
{
Long lKey = (Long)value;
return uintPool.add(lKey);
}
else if ( value instanceof Double )
{
Double dKey = (Double)value;
return doublePool.add(dKey);
}
else if ( value instanceof String )
{
String sKey = (String)value;
return stringPool.add(sKey);
}
else if ( value instanceof Namespace )
{
Namespace nsKey = (Namespace)value;
if ( nsKey.name.equals("*") )
return 0;
else
return nsPool.add(nsKey);
}
else
throw new IllegalArgumentException("Don't have a pool for " + value.getClass().getSimpleName());
}
int getPoolId(Object value )
{
if ( null == value )
{
throw new IllegalArgumentException("null object has no pool value");
}
else if ( value instanceof Integer )
{
Integer iKey = (Integer)value;
return intPool.id(iKey);
}
else if ( value instanceof Long )
{
Long lKey = (Long)value;
return uintPool.id(lKey);
}
else if ( value instanceof Double )
{
Double dKey = (Double)value;
return doublePool.id(dKey);
}
else if ( value instanceof String )
{
String sKey = (String)value;
return stringPool.id(sKey);
}
else
throw new IllegalArgumentException("Don't have a pool for " + value.getClass().getSimpleName());
}
void semanticAssertion(boolean cond, String diagnostic )
{
if (!cond)
semanticErrors.add(diagnostic);
}
void syntaxError(String diagnostic)
{
syntaxErrors.add(diagnostic);
}
void dump(java.io.PrintStream out)
{
for ( String fname: methodsByName.keySet() )
/* FIXME: not working right now... functionsByName.get(fname).dump(out) */;
}
Name getName(String unqualifiedName)
{
// Ensure the package namespace is present.
getNamespace("package");
Name result = new Name(unqualifiedName);
if ( !"*".equals(unqualifiedName))
{
namePool.add(result);
stringPool.add(unqualifiedName);
}
return result;
}
Name getName(Nsset qualifiers, String baseName)
{
Name result = new Name(qualifiers, baseName);
namePool.add(result);
stringPool.add(baseName);
return result;
}
Namespace getNamespace(String nsName)
{
Namespace result;
String nsPoolName;
if ( "Package".equalsIgnoreCase(nsName))
{
nsPoolName = "";
result = new Namespace(CONSTANT_PackageNs, "");
}
else if ( "Private".equalsIgnoreCase(nsName))
{
nsPoolName = "";
result = new Namespace(CONSTANT_PrivateNs, "");
}
else if ( "Namespace".equalsIgnoreCase(nsName))
{
nsPoolName = "";
result = new Namespace(CONSTANT_Namespace, "");
}
else
{
nsPoolName = nsName;
result = new Namespace(CONSTANT_Namespace, nsName);
}
stringPool.add(nsPoolName);
nsPool.add(result);
return result;
}
Nsset getNsset(Vector<Namespace> namespaces)
{
Nsset result = new Nsset(namespaces);
this.nssetPool.add(result);
return result;
}
/**
* Supports a convenience in the syntax:
* if a multiname doesn't have qualfiers,
* then hack together a Nsset with the
* commonly-searched namespaces.
* @return
*/
Nsset getUsualSuspectNamespaces()
{
Vector<Namespace> namespaces = new Vector<Namespace>();
namespaces.add(getNamespace("package"));
namespaces.add(getNamespace("private"));
return getNsset(namespaces);
}
Label getLabel(String labelName)
{
return new Label(labelName);
}
int generated_label_serial = 0;
Label generateLabel(String labelPrefix)
{
return getLabel(labelPrefix + " #" + generated_label_serial++);
}
void addScript(ScriptInfo s)
{
scripts.add(s);
}
void semanticAnalysis()
{
// Add a default script if none was specified.
if ( scripts.isEmpty() )
{
scripts.add(new ScriptInfo());
}
else
{
for ( ScriptInfo s: scripts )
{
s.init_id = translateImmediate(s.init_id);
finishTraits(s.traits);
}
}
// TODO: Classes change these semantics.
if ( scripts.size() == 1 )
pushTraits(scripts.elementAt(0).traits);
for ( MethodBodyInfo info: methodBodies)
{
info.methodId = translateImmediate(info.methodId);
finishTraits(info.traits);
pushTraits(info.traits);
for ( Block b: info.blocks )
{
for ( Instruction insn: b.insns)
{
if ( insn.operands != null )
{
insn.imm = new int[insn.operands.length];
for ( int i = 0; i < insn.operands.length; i++)
{
try
{
insn.imm[i] = translateImmediate(insn.operands[i]);
}
catch ( IllegalArgumentException ex )
{
System.err.println("Method " + this.methodSignatures.elementAt(info.getMethodId()).methodName
+ " insn " + insn.toString() + " untranslatable: " + ex.getMessage() );
throw ex;
}
}
}
}
}
popTraits();
}
if ( scripts.size() == 1 )
popTraits();
}
/**
* Ensure that all required traits entries are present.
* @param traits - the traits to finish.
*/
private void finishTraits(Traits traits)
{
int slot_id = 1;
for ( Trait t: traits )
{
if ( TRAIT_Var == t.getKind())
{
if ( t.hasAttr("slot_id") )
{
slot_id = Math.max(t.getIntAttr("slot_id") + 1, slot_id);
}
else
{
t.setAttr("slot_id", new Integer(slot_id++));
}
if ( !t.hasAttr("type_name"))
{
// Unspecified type is type ANY.
t.setAttr("type_name", new Name("*"));
}
}
}
}
Integer translateImmediate(Object immediate_operand)
{
if ( null == immediate_operand )
{
throw new IllegalArgumentException("Unable to translate null operand");
}
Integer result = null;
if ( immediate_operand instanceof Integer )
{
// ID was specified.
result = (Integer) immediate_operand;
}
else if ( immediate_operand instanceof SymbolicReference )
{
SymbolicReference symconst = (SymbolicReference) immediate_operand;
if ( SymbolicReference.function_id == symconst.kind )
{
// ID should be in the table.
if ( methodsByName.containsKey(symconst.symbolicReference))
result = methodsByName.get(symconst.symbolicReference);
}
else if ( SymbolicReference.slot_id == symconst.kind )
{
for ( int i = staticScopes.size() -1; i >= 0 && null == result; i-- )
{
result = staticScopes.elementAt(i).getSlotId(symconst.symbolicReference);
}
}
}
if ( null == result )
{
throw new IllegalArgumentException("Unknown operand " + immediate_operand + ", type " + immediate_operand.getClass().getCanonicalName());
}
return result;
}
int getNameId(Name n)
{
if ( null == n || n.baseName.equals("*"))
return 0;
else
return namePool.id(n);
}
MethodInfo getMethod(Object method_key)
{
int method_index = translateImmediate(method_key);
return methodSignatures.elementAt(method_index);
}
java.util.Vector<Traits> staticScopes = new java.util.Vector<Traits>();
void pushTraits(Traits traits)
{
staticScopes.add(traits);
}
void popTraits()
{
staticScopes.remove(staticScopes.size()-1);
}
}