void DefinePrototype(AvmTypeCode type, AbcMethod sig) { var srcmethod = sig.Method; if (srcmethod == null) { return; } string key = GetKey(type, srcmethod.Name); var val = _prototypes[key] as object[]; if (val == null) { return; } var m = val[1] as AbcMethod; if (m != null) { return; } var coder = val[0] as AbcCoder; m = Abc.DefineMethod(Sig.@from(sig), coder); _generator.NewApi.SetProtoFunction(type, sig.TraitName, m); val[0] = m; }
private void CompleteMethod(AbcInstance instance, IMethod method, AbcMethod abcMethod) { BuildBody(abcMethod); BuildImplementedMethods(method, instance, abcMethod); BuildOverrideMethods(method, abcMethod); ImplementProtoMethods(method, abcMethod); }
/// <summary> /// Creates cast_to_type method via given AS method /// </summary> /// <param name="type"></param> /// <param name="AS"></param> /// <returns></returns> private AbcMethod Impl(IType type, AbcMethod AS, AbcMultiname name) { var instance = AS.Instance; var typeName = _generator.TypeBuilder.BuildMemberType(type); return(instance.DefineMethod( Sig.@static(name, typeName, AvmTypeCode.Object, "value"), code => { const int value = 1; code.GetLocal(value); code.IfNullReturnNull(1); code.Getlex(instance); code.GetLocal(value); code.Call(AS); code.SetLocal(value); code.GetLocal(value); var notNull = code.IfNotNull(false); code.ThrowInvalidCastException(type); notNull.BranchTarget = code.Label(); code.GetLocal(value); code.ReturnValue(); })); }
private static bool HasFlashIfaceName(AbcMethod method) { var mn = method.TraitName; if (mn == null) { return(false); } if (!mn.IsQName) { return(false); } if (mn.Namespace.Kind != AbcConstKind.PublicNamespace) { return(false); } var instance = method.Instance; if (instance == null) { return(false); } if (!instance.Name.IsQName) { return(false); } var ns = instance.Name.Namespace.NameString; var name = instance.Name.NameString; ns = string.IsNullOrEmpty(ns) ? name : ns + ":" + name; return(mn.Namespace.NameString == ns); }
internal void CopyParameters(AbcMethod to, AbcMethod from) { int n = from.Parameters.Count; for (int i = 0; i < n; ++i) { var bp = from.Parameters[i]; var ap = new AbcParameter { Type = Abc.ImportConst(bp.Type), Name = Abc.ImportConst(bp.Name) }; if (bp.IsOptional) { ap.IsOptional = true; ap.Value = Abc.ImportValue(bp.Value); to.HasOptionalParams = true; } to.Parameters.Add(ap); } if (from.NeedRest) { to.NeedRest = true; } }
private void BuildOverrideMethods(IMethod method, AbcMethod abcMethod) { if (!method.IsAbstract && !method.IsVirtual) { return; } var type = method.DeclaringType; var instance = type.AbcInstance(); if (instance == null) { throw new InvalidOperationException(); } if (instance.IsInterface) { //TODO: fix this problem //warning: do not use for each since instance.Implementations is modifiable. for (int i = 0; i < instance.Implementations.Count; ++i) { var impl = instance.Implementations[i]; BuildImplementation(impl, impl.Type, method, abcMethod); } } else { BuildSubclassOverrideMethods(instance, method); } }
/// <summary> /// Defines parameters for given <see cref="AbcMethod"/>. /// </summary> /// <param name="target"></param> /// <param name="source">source method of given <see cref="AbcMethod"/></param> public void BuildParameters(AbcMethod target, IMethod source) { if (source == _generator.EntryPoint) { if (AbcGenConfig.ParameterlessEntryPoint) { return; } } if (source.HasPseudoThis()) { target.Parameters.Add(Abc.CreateParameter(source.DeclaringType, "this")); } var abm = GetBaseMethod(target, source); if (abm != null) { CopyParameters(target, abm); } else { target.Parameters.AddRange(source.Parameters.Select(p => Abc.CreateParameter(p.Type, p.Name))); } }
private static AbcMethod BuildEnumCinit(AbcFile abc, IType type) { if (type == null) { return(null); } if (!type.IsEnum) { return(null); } var method = new AbcMethod { ReturnType = abc.BuiltinTypes.Void }; var body = new AbcMethodBody(method); abc.AddMethod(method); var code = new AbcCode(abc); var generator = abc.Generator; foreach (var field in type.Fields.Where(field => field.IsConstant)) { code.LoadThis(); code.LoadConstant(field.Value); code.InitProperty(generator.FieldBuilder.GetFieldName(field)); } code.ReturnVoid(); body.Finish(code); return(method); }
private static void WriteParams(TextWriter writer, AbcMethod method) { writer.Write("("); int n = method.Parameters.Count; for (int i = 0; i < n; ++i) { if (i > 0) { writer.Write(", "); } var p = method.Parameters[i]; WriteQName(writer, p.Type); writer.Write(" "); if (p.HasName) { writer.Write(p.Name.Value); } else { writer.Write("arg{0}", i); } } if ((method.Flags & AbcMethodFlags.NeedRest) != 0) { if (n > 0) { writer.Write(", "); } writer.Write("params object[] rest"); } writer.Write(")"); }
/// <summary> /// Compiles <see cref="IMethod.Implements"/> methods. /// </summary> /// <param name="method"></param> /// <param name="instance"></param> /// <param name="abcMethod"></param> private void BuildImplementedMethods(IMethod method, AbcInstance instance, AbcMethod abcMethod) { var impls = method.Implements; if (impls == null) { return; } int n = impls.Count; if (n <= 0) { return; } //NOTE: To avoid conflict with name of explicit implementation method has the same name as iface method if (method.IsExplicitImplementation) { Build(impls[0]); return; } if (n == 1 && !abcMethod.IsOverride) { Build(impls[0]); return; } foreach (var ifaceMethod in impls) { var ifaceAbcMethod = BuildAbcMethod(ifaceMethod); BuildExplicitImplementation(instance, abcMethod, ifaceMethod, ifaceAbcMethod); } }
private void BuildBodyCore(AbcMethod target, IMethod source) { var targetBody = target.Body; if (targetBody == null) { targetBody = new AbcMethodBody(target); Abc.MethodBodies.Add(targetBody); } var sourceBody = source.Body; var codeProvider = new CodeProviderImpl(_generator, target); var translator = sourceBody.CreateTranslator(); if (translator == null) { throw new InvalidOperationException("No IL translator"); } var il = translator.Translate(source, sourceBody, codeProvider); targetBody.IL.Add(il); targetBody.Finish(Abc); }
private static void BuildExplicitImplementation(AbcInstance instance, AbcMethod abcMethod, IMethod ifaceMethod, AbcMethod ifaceAbcMethod) { instance.DefineMethod( Sig.@from(ifaceAbcMethod), code => { code.LoadThis(); code.LoadArguments(ifaceMethod); code.Call(abcMethod); if (ifaceAbcMethod.IsVoid) { code.ReturnVoid(); } else { code.ReturnValue(); } }, m => { var isOverride = instance.BaseInstances() .FirstOrDefault(x => x.Traits.Contains(ifaceAbcMethod.TraitName, ifaceAbcMethod.Trait.Kind)) != null; m.Trait.IsOverride = isOverride; OverrideExplicitImplsInSubclasses(instance, ifaceAbcMethod); }); }
private static void AddEventListener(AbcCode code, AbcMethod method, string eventName) { code.LoadThis(); code.PushString(eventName); code.LoadThis(); code.GetProperty(method.TraitName); code.CallVoid("addEventListener", 2); }
public static XElement ToXml(this AbcMethod method) { var res = new XElement("method"); if (!string.IsNullOrWhiteSpace(method.Name)) { res.Add(new XAttribute("name", method.Name)); } var retType = method.ReturnType.ToXml(); if (!string.IsNullOrWhiteSpace(retType)) { res.Add(new XAttribute("returns", retType)); } if (method.NeedArguments) { res.Add(new XAttribute("needArguments", CommonFormatter.Format(method.NeedArguments))); } if (method.NeedActivation) { res.Add(new XAttribute("needActivation", CommonFormatter.Format(method.NeedActivation))); } if (method.NeedRest) { res.Add(new XAttribute("needRest", CommonFormatter.Format(method.NeedRest))); } if (method.SetDxns) { res.Add(new XAttribute("setDxns", CommonFormatter.Format(method.SetDxns))); } if (method.IgnoreRest) { res.Add(new XAttribute("ignoreRest", CommonFormatter.Format(method.IgnoreRest))); } if (method.Native) { res.Add(new XAttribute("native", CommonFormatter.Format(method.Native))); } if (method.Params.Count > 0) { var xParams = new XElement("params"); foreach (var param in method.Params) { xParams.Add(ToXml(param)); } res.Add(xParams); } if (method.Body != null) { res.Add(ToXml(method.Body)); } return(res); }
//Generates method for script initializer private AbcMethod DefineMainScriptInit(AbcScript script, AbcInstance instance) { #if DEBUG DebugService.LogInfo("DefineScriptInit started"); #endif var method = new AbcMethod(); bool notSwf = !IsSwf; //Note: entry point also can contains arguments //Note: but in swf entry point can not have arguments if (EntryPoint != null && notSwf) { method.ReturnType = _generator.TypeBuilder.BuildReturnType(EntryPoint.Type); _generator.MethodBuilder.BuildParameters(method, EntryPoint); } var body = new AbcMethodBody(method); _generator.Abc.AddMethod(method); _mainScriptBody = body; var code = new AbcCode(Abc); _mainScriptCode = code; code.PushThisScope(); code.InitClassProperties(script); //code.Trace("Initialization of " + instance.FullName); _insertIndexOfNewApi = code.Count; //code.AddRange(_newAPI); _generator.StaticCtors.Call(code, instance); if (notSwf) //abc? { _generator.NUnit.Main(code); CallEntryPoint(code); } else { code.ReturnVoid(); } //body.Finish(code); #if DEBUG DebugService.LogInfo("DefineScriptInit succeeded"); #endif return(method); }
private static void OverrideExplicitImplsInSubclasses(AbcInstance instance, AbcMethod ifaceMethod) { var name = ifaceMethod.TraitName; foreach (var c in instance.Subclasses) { var t = c.Traits.Find(name, ifaceMethod.Trait.Kind); if (t != null) { t.IsOverride = true; } } }
public AbcMultiname BuildReturnType(AbcMethod abcMethod, IMethod method) { if (method.IsConstructor && method.AsStaticCall()) { return(_generator.TypeBuilder.BuildMemberType(method.DeclaringType)); } var bm = GetBaseMethod(abcMethod, method); if (bm != null) { return(bm.ReturnType); } return(_generator.TypeBuilder.BuildReturnType(method.Type)); }
private object Import(AbcMethod method) { if (method.IsNative) { return(method); } var abc = method.Abc; if (abc.IsCore) { return(method); } if (method.ImportedMethod != null) { return(method.ImportedMethod); } var instance = method.Instance; if (instance != null) { var i2 = Abc.ImportInstance(instance, ref method); if (i2 == null) { throw new InvalidOperationException(); } } else { if (!(method.Owner is AbcScript)) { throw new InvalidOperationException(); } Abc.Import(abc); //NOTE: ABC can be linked externally if (method.ImportedMethod != null) { return(method.ImportedMethod); } } return(method); }
private AbcMethod GetBaseMethod(AbcMethod abcMethod, IMethod method) { var impls = method.Implements; if (impls != null && impls.Count == 1) { return(BuildAbcMethod(impls[0])); } var baseMethod = method.BaseMethod; if (abcMethod.IsOverride && baseMethod != null) { return(baseMethod.AbcMethod()); } return(null); }
private static void LinkMethod(IMethod method, AbcMethod abcMethod) { if (abcMethod == null) { throw new InvalidOperationException("Unable to find method " + method); } method.Data = abcMethod; //Prevent to link overload methods if (method.Parameters.Count == abcMethod.ActualParamCount) { abcMethod.Method = method; } //var instance = abcMethod.Instance; //if (instance != null && !instance.IsNative && abcMethod.IsNative) // instance.IsNative = true; }
private void BuildBody(AbcMethod abcMethod) { if (abcMethod == null) { throw new ArgumentNullException(); } var method = abcMethod.Method; if (method == null) { return; } if (method.Body == null) { return; } BuildBodyCore(abcMethod, method); }
public CodeProviderImpl(AbcGenerator gen, AbcMethod abcMethod) { _generator = gen; _abc = gen.Abc; _method = abcMethod.Method; _body = abcMethod.Body; _declType = _method.DeclaringType; _asStatic = _method.AsStaticCall(); //This code enshures initial capacity for local registers _body.LocalCount = _method.Parameters.Count + 1; var body = _method.Body; if (body == null) { throw new InvalidOperationException("method has no body"); } if (HasPseudoThis) { _body.LocalCount++; } int n = VarCount; if (n == 0) { //NOTE: AVM constraint for LocalCount //if (local_count < info->param_count+1) //{ // must have enough locals to hold all parameters including this //toplevel->throwVerifyError(kCorruptABCError); //} _body.LocalCount++; } else { _body.LocalCount += n; } }
public void Implement(IMethod method, AbcMethod abcMethod) { if (method == null) { return; } if (method.IsStatic) { return; } if (method.IsConstructor) { return; } var declType = method.DeclaringType; if (!declType.Is(SystemTypeCode.Object)) { return; } DefinePrototype(AvmTypeCode.Object, abcMethod); DefinePrototype(AvmTypeCode.String, abcMethod); }
public static XElement AddMethod(this XElement node, AbcMethod method) { node.Add(new XAttribute("method", method.Name)); return(node); }
private AbcMethod DefineTestRunner(IMethod test) { var method = _generator.MethodBuilder.BuildAbcMethod(test); var instance = method.Instance; string name = "run_test_" + test.GetMonoTestCaseName(); name = name.Replace('.', '_'); return(instance.DefineMethod( Sig.@static(name, AvmTypeCode.Void, GetInstance(NUnitTypeId.Test)), code => { var testFixture = test.DeclaringType; const int varTF = 2; const int varErr = 3; //TODO: Redirect Console, Debug output var ee = test.GetExpectedExceptionType(); var setup = testFixture.GetUnitTestSetup(); AbcMethod setupAM = null; if (setup != null) { setupAM = _generator.MethodBuilder.BuildAbcMethod(setup); } Test_Success(code, true); Test_Executed(code, true); code.ConsoleOpenSW(); code.Try(); #region setup & call if (test.IsStatic) { if (setup != null && setup.IsStatic) { code.Getlex(setupAM); code.Call(setupAM); } code.Getlex(method); code.Call(method); } else { code.CreateInstance(testFixture, true); code.CoerceAnyType(); code.SetLocal(varTF); if (setup != null) { code.GetLocal(varTF); code.Call(setupAM); } code.GetLocal(varTF); code.Call(method); } #endregion if (ee != null) { code.ConsoleCloseSW(true); Test_Success(code, false); Test_Output(code, "No expected exception: {0}", ee.FullName); } else { Test_Output(code, () => code.ConsoleCloseSW(false)); } code.ReturnVoid(); if (ee != null) { code.BeginCatch(_generator.TypeBuilder.BuildInstance(ee), false); code.Pop(); Test_Success(code, true); Test_Output(code, () => code.ConsoleCloseSW(false)); code.ReturnVoid(); code.EndCatch(false); } code.BeginCatch(); code.CoerceAnyType(); code.SetLocal(varErr); code.ConsoleCloseSW(true); Test_Success(code, false); Test_Output( code, () => { code.PushString("Unexpected exception: "); code.GetLocal(varErr); code.GetErrorMessage(); code.Add(InstructionCode.Add); }); Test_StackTrace( code, () => { code.GetLocal(varErr); code.GetErrorStackTrace(); }); code.EndCatch(true); code.ReturnVoid(); })); }
private void ImplementProtoMethods(IMethod method, AbcMethod abcMethod) { _generator.StringPrototypes.Implement(method); _generator.ObjectPrototypes.Implement(method, abcMethod); }
internal void AddLateMethod(AbcMethod method, AbcCoder coder) { _lateMethods.Add(method, coder); }
internal void BuildImplementation(AbcInstance implInstance, IType implType, IMethod ifaceMethod, AbcMethod ifaceAbcMethod) { if (implInstance == null) { throw new ArgumentNullException("implInstance"); } if (implInstance.IsInterface) { return; } if (implType == null) { throw new ArgumentNullException("implType"); } if (implType.IsInterface) { return; } var impl = implType.FindImplementation(ifaceMethod, true, false); if (impl == null) { throw new InvalidOperationException( string.Format("Unable to find implementation for method {0} in type {1}", ifaceMethod.FullName, implType.FullName)); } impl = impl.ResolveGenericInstance(implType, ifaceMethod); var abcImpl = Build(impl) as AbcMethod; // determine whether we should create explicit impl if (abcImpl == null || implInstance.IsForeign || ReferenceEquals(impl.DeclaringType, implType) || impl.IsExplicitImplementation || impl.Implements.Any(x => x == ifaceMethod)) { return; } // do not create explicit impl if interface is implemented in base type var iface = ifaceMethod.DeclaringType; var baseIfaces = implType.BaseTypes().SelectMany(x => x.Interfaces.SelectMany(i => i.Interfaces.Append(i))); if (baseIfaces.Any(x => ReferenceEquals(x, iface))) { return; } if (Equals(abcImpl.TraitName, ifaceAbcMethod.TraitName) || (abcImpl.TraitName != null && ifaceAbcMethod.TraitName != null && abcImpl.TraitName.IsGlobalName(ifaceAbcMethod.TraitName.NameString) && HasFlashIfaceName(ifaceAbcMethod))) { return; } BuildExplicitImplementation(implInstance, abcImpl, ifaceMethod, ifaceAbcMethod); }
public void CacheCastOperator(IType source, IType target, AbcMethod op) { string key = GetCastOperatorKey(source, target); _cacheCastOps[key] = op; }
private AbcMethod BuildCtorImpl(IMethod method, AbcInstance instance) { if (!method.IsConstructor) { return(null); } if (method.IsStatic) { return(null); } var type = method.DeclaringType; if (!type.IsArray) { return(null); } var ctor = new AbcMethod { ReturnType = Abc.BuiltinTypes.Void }; _generator.MethodBuilder.BuildParameters(ctor, method); string name1 = "arrctor_" + type.GetSigName(); var name = Abc.DefineName(QName.Global(name1)); var trait = AbcTrait.CreateMethod(ctor, name); instance.Traits.Add(trait); var body = new AbcMethodBody(ctor); Abc.AddMethod(ctor); var code = new AbcCode(Abc); code.PushThisScope(); code.ConstructSuper(); //check arguments int n = method.Parameters.Count; for (int i = 0; i < n; ++i) { code.GetLocal(i + 1); code.PushInt(0); var br = code.If(BranchOperator.GreaterThanOrEqual); var exceptionType = _generator.Corlib.GetType(CorlibTypeId.ArgumentOutOfRangeException); code.ThrowException(exceptionType); br.BranchTarget = code.Label(); } //m_rank = n code.LoadThis(); code.PushInt(n); code.SetProperty(Const.Array.Rank); int varSize = n + 1; for (int i = 0; i < n; ++i) { code.GetLocal(i + 1); } for (int i = 1; i < n; ++i) { code.Add(InstructionCode.Multiply_i); } code.SetLocal(varSize); //init m_value code.LoadThis(); code.CreateArrayVarSize(varSize); code.SetProperty(Const.Array.Value); //init m_lengths code.LoadThis(); for (int i = 0; i < n; ++i) { code.GetLocal(i + 1); } code.Add(InstructionCode.Newarray, n); code.SetProperty(Const.Array.Lengths); int varDimArr = varSize + 1; //init m_dims code.CreateArray(n - 1); code.SetLocal(varDimArr); //1, n, n * (n-1), ..., n * (n-1) * ... * n0 for (int i = n - 2; i >= 0; --i) { int leni = i + 2; code.GetLocal(varDimArr); code.PushInt(i); if (i != n - 2) { code.GetLocal(varDimArr); code.PushInt(i + 1); code.GetNativeArrayItem(); code.CoerceInt32(); //prev code.GetLocal(leni); code.Add(InstructionCode.Multiply_i); //prev * leni } else { code.GetLocal(leni); } code.SetNativeArrayItem(); } code.LoadThis(); code.GetLocal(varDimArr); code.SetProperty(Const.Array.Dims); var elemType = type.GetElementType(); InitFields(code, type, elemType, 0); if (InternalTypeExtensions.IsInitArray(elemType)) { code.InitArray(elemType, () => { code.LoadThis(); code.GetProperty(Const.Array.Value); }, varSize); } code.ReturnVoid(); body.Finish(code); return(ctor); }