// ---------------------------------------------------------------------- // SPECIAL CASE: Imported methods // ---------------------------------------------------------------------- public JST.FunctionExpression ImportedMethod(CST.CSTWriter trace) { if (!env.InteropManager.IsImported(methEnv.Assembly, methEnv.Type, methEnv.Method)) return null; var isFactory = env.InteropManager.IsFactory(methEnv.Assembly, methEnv.Type, methEnv.Method); var delta = isFactory ? 1 : 0; var methCompEnv = MethodCompilerEnvironment.EnterUntranslatedMethod (env, outerNameSupply, nameSupply, rootId, assemblyId, typeDefinitionId, methEnv, parent.TypeTrace); var parameters = new Seq<JST.Identifier>(); var body = new Seq<JST.Statement>(); foreach (var id in methCompEnv.TypeBoundTypeParameterIds) parameters.Add(id); foreach (var id in methCompEnv.MethodBoundTypeParameterIds) parameters.Add(id); var valueParameters = new Seq<JST.Identifier>(); for (var i = delta; i < methCompEnv.Method.Arity; i++) { var id = methCompEnv.ValueParameterIds[i]; if (i == 0 && !methCompEnv.Method.IsStatic && methCompEnv.Type.Arity == 0) body.Add(JST.Statement.Var(id, new JST.ThisExpression())); else parameters.Add(id); valueParameters.Add(id); } // Take account of imports and exports on args/result to improve type sharing var usage = new CST.Usage(); for (var i = delta; i < methCompEnv.Method.Arity; i++) { if (!env.InteropManager.IsNoInteropParameter(methEnv.Assembly, methEnv.Type, methEnv.Method, i)) methCompEnv.SubstituteType(methCompEnv.Method.ValueParameters[i].Type).AccumUsage(usage, true); } if (isFactory) { if (!env.InteropManager.IsNoInteropParameter(methEnv.Assembly, methEnv.Type, methEnv.Method, 0)) methCompEnv.TypeRef.AccumUsage(usage, true); } else if (methCompEnv.Method.Result != null) { if (!env.InteropManager.IsNoInteropResult(methEnv.Assembly, methEnv.Type, methEnv.Method)) methCompEnv.SubstituteType(methCompEnv.Method.Result.Type).AccumUsage(usage, true); } methCompEnv.BindUsage(body, usage); if (methCompEnv.Method.IsConstructor && !methCompEnv.Method.IsStatic) { // Constructor or factory var isValType = methCompEnv.Type.Style is CST.ValueTypeStyle; var callArgs = new Seq<JST.Expression>(); var managedObjId = default(JST.Identifier); for (var i = delta; i < methCompEnv.Method.Arity; i++) { if (i == 0) // First argument is always the managed object or a managed pointer to value managedObjId = valueParameters[i]; else if (env.InteropManager.IsNoInteropParameter(methEnv.Assembly, methEnv.Type, methEnv.Method, i)) // Supress exports callArgs.Add(valueParameters[i].ToE()); else callArgs.Add (env.JSTHelpers.ExportExpressionForType (methCompEnv, methCompEnv.Method.ValueParameters[i].Type, valueParameters[i - delta].ToE())); } var call = env.InteropManager.AppendImport (nameSupply, rootId, methEnv.Assembly, methEnv.Type, methEnv.Method, body, callArgs); if (isValType) { if (isFactory) body.Add(new JST.ReturnStatement(call)); else body.Add(JST.Statement.DotCall(managedObjId.ToE(), Constants.PointerWrite, call)); } else { var state = env.InteropManager.GetTypeRepresentation(methEnv.Assembly, methEnv.Type).State; switch (state) { case InstanceState.ManagedOnly: if (isFactory) body.Add(new JST.ReturnStatement(call)); else throw new InvalidOperationException ("imported constructors of 'ManagedOnly' types must be factories"); break; case InstanceState.Merged: if (isFactory) { if (env.InteropManager.IsNoInteropParameter (methEnv.Assembly, methEnv.Type, methEnv.Method, 0)) body.Add(new JST.ReturnStatement(call)); else body.Add (new JST.ReturnStatement (env.JSTHelpers.ImportExpressionForType(methCompEnv, methCompEnv.TypeRef, call))); } else throw new InvalidOperationException ("imported constructors of 'ManagedOnly' types must be factories"); break; case InstanceState.ManagedAndJavaScript: case InstanceState.JavaScriptOnly: { var unmanagedObjId = nameSupply.GenSym(); body.Add(JST.Statement.Var(unmanagedObjId, call)); body.Add (JST.Statement.DotAssignment (managedObjId.ToE(), Constants.ObjectUnmanaged, unmanagedObjId.ToE())); body.Add (JST.Statement.DotCall (rootId.ToE(), state == InstanceState.ManagedAndJavaScript ? Constants.RootSetupManagedAndJavaScript : Constants.RootSetupJavaScriptOnly, managedObjId.ToE())); env.JSTHelpers.AppendInvokeImportingConstructor (methCompEnv, nameSupply, valueParameters, body, unmanagedObjId); break; } default: throw new ArgumentOutOfRangeException(); } } } else { if (isFactory) throw new InvalidOperationException("only constructors can be factories"); var outer = methCompEnv.Type.OuterPropertyOrEvent(methCompEnv.Method.MethodSignature); if (outer != null && outer.Flavor == CST.MemberDefFlavor.Event) { // Event adder/remover var eventDef = (CST.EventDef)outer; var simulateMulticast = env.InteropManager.IsSimulateMulticastEvents (methEnv.Assembly, methEnv.Type, eventDef); // Since event is in same type as this method, ok to use handler type directly var handlerType = eventDef.HandlerType; var slotName = new JST.StringLiteral (Constants.ObjectEventSlot(env.GlobalMapping.ResolveEventDefToSlot(methCompEnv.Assembly, methCompEnv.Type, eventDef))); var obj = default(JST.Expression); var delegateArg = default(JST.Expression); if (methCompEnv.Method.IsStatic) { obj = methCompEnv.ResolveType(methCompEnv.TypeRef); delegateArg = valueParameters[0].ToE(); } else { obj = valueParameters[0].ToE(); delegateArg = valueParameters[1].ToE(); } var slotExp = new JST.IndexExpression(obj, slotName); var callArgs = new Seq<JST.Expression>(); if (!methCompEnv.Method.IsStatic) { if (env.InteropManager.IsNoInteropParameter (methEnv.Assembly, methEnv.Type, methEnv.Method, callArgs.Count)) callArgs.Add(obj); else callArgs.Add (env.JSTHelpers.ExportExpressionForType (methCompEnv, methCompEnv.Method.ValueParameters[0].Type, obj)); } if (methCompEnv.Method.Signature.Equals(eventDef.Add)) { if (simulateMulticast) { body.Add (JST.Statement.DotCall (rootId.ToE(), Constants.RootAddEventHandler, obj, slotName, delegateArg)); if (env.InteropManager.IsNoInteropParameter (methEnv.Assembly, methEnv.Type, methEnv.Method, callArgs.Count)) callArgs.Add(slotExp); else callArgs.Add (env.JSTHelpers.ExportExpressionForType(methCompEnv, handlerType, slotExp)); } else callArgs.Add(delegateArg); body.Add (new JST.ExpressionStatement (env.InteropManager.AppendImport (nameSupply, rootId, methEnv.Assembly, methEnv.Type, methEnv.Method, body, callArgs))); } else if (methCompEnv.Method.Signature.Equals(eventDef.Remove)) { if (simulateMulticast) { body.Add (JST.Statement.DotCall (rootId.ToE(), Constants.RootRemoveEventHandler, obj, slotName, delegateArg)); if (env.InteropManager.IsNoInteropParameter (methEnv.Assembly, methEnv.Type, methEnv.Method, callArgs.Count)) callArgs.Add(slotExp); else callArgs.Add (env.JSTHelpers.ExportExpressionForType(methCompEnv, handlerType, slotExp)); } else callArgs.Add(new JST.NullExpression()); body.Add (new JST.ExpressionStatement (env.InteropManager.AppendImport (nameSupply, rootId, methEnv.Assembly, methEnv.Type, methEnv.Method, body, callArgs))); } else throw new InvalidOperationException("method not adder or remover"); } else { // Property getter/setter and normal methods var callArgs = new Seq<JST.Expression>(); for (var i = 0; i < methCompEnv.Method.Arity; i++) { if (env.InteropManager.IsNoInteropParameter(methEnv.Assembly, methEnv.Type, methEnv.Method, i)) callArgs.Add(valueParameters[i].ToE()); else callArgs.Add (env.JSTHelpers.ExportExpressionForType (methCompEnv, methEnv.Method.ValueParameters[i].Type, valueParameters[i].ToE())); } var call = env.InteropManager.AppendImport (nameSupply, rootId, methEnv.Assembly, methEnv.Type, methEnv.Method, body, callArgs); if (methCompEnv.Method.Result == null) body.Add(new JST.ExpressionStatement(call)); else if (env.InteropManager.IsNoInteropResult(methEnv.Assembly, methEnv.Type, methEnv.Method)) body.Add(new JST.ReturnStatement(call)); else body.Add (new JST.ReturnStatement (env.JSTHelpers.ImportExpressionForType (methCompEnv, methCompEnv.Method.Result.Type, call))); } } var func = default(JST.FunctionExpression); if (env.CLRInteropExceptions) { var exId = nameSupply.GenSym(); var funcBody = new Seq<JST.Statement>(); #if !JSCRIPT_IS_CORRECT funcBody.Add(JST.Statement.Var(exId)); #endif funcBody.Add (new JST.TryStatement (new JST.Statements(body), new JST.CatchClause (exId, new JST.Statements (new JST.ThrowStatement (JST.Expression.DotCall (rootId.ToE(), Constants.RootImportException, exId.ToE())))))); func = new JST.FunctionExpression(methCompEnv.MethodId, parameters, new JST.Statements(funcBody)); } else func = new JST.FunctionExpression(methCompEnv.MethodId, parameters, new JST.Statements(body)); if (trace != null) trace.Trace ("Imported JavaScript function", w => { func.Append(w); w.EndLine(); }); return func; }
public override void AccumUsage(CompilationEnvironment compEnv, bool isAlwaysUsed, Usage usage, bool asPointer) { usage.SeenVariable(StateId, isAlwaysUsed); }
public abstract void AccumUsage(CompilationEnvironment compEnv, bool isAlwaysUsed, Usage usage, bool asPointer);
public override void AccumUsage(CompilationEnvironment compEnv, bool isAlwaysUsed, Usage usage, bool asPointer) { Box.AccumUsage(compEnv, isAlwaysUsed, usage, false); }
public override void AccumUsage(CompilationEnvironment compEnv, bool isAlwaysUsed, Usage usage, bool asPointer) { if (Object != null) { Object.AccumUsage(compEnv, isAlwaysUsed, usage, false); } usage.SeenField(Field, isAlwaysUsed); }