From 0128da4317e33074cde76e75614505d414ca8d7b Mon Sep 17 00:00:00 2001 From: "daniel.zeitlin" Date: Mon, 2 Jun 2014 11:05:05 +0300 Subject: [PATCH 1/7] - TypeUtil.IsStructImmutable() added, [JSImmutable] works with readonly/immutable structs with member methods (no MemberwiseClone() anymore) - Exception.GetType() implemented - JSIL.Array.FindIndex()/Find()/ForEach()/ConvertAll() implemented via proxy (support typed arrays) - Builtins.IsFalsy/IsTruthy() explicit case to object in parameter - Configuration.EmitAttributes list introduced (minimizes .js output substantially) - JSIL.Meta.dll made strong named - Float and Double +/-Infinity added via proxy --- JSIL/AssemblyTranslator.cs | 29 ++++++++++++- JSIL/Configuration.cs | 2 + .../StaticAnalysis/EmulateStructAssignment.cs | 2 +- JSIL/TypeUtil.cs | 11 +++++ Libraries/JSIL.Bootstrap.js | 7 ++++ Libraries/JSIL.Core.js | 39 ++++++++++++++++++ Meta/Builtins.cs | 4 +- Meta/Meta.csproj | 9 ++++ Meta/jsil.snk | Bin 0 -> 596 bytes Proxies/Array.cs | 31 +++++++++++++- Proxies/Numbers.cs | 23 ++++++++++- 11 files changed, 150 insertions(+), 7 deletions(-) create mode 100644 Meta/jsil.snk diff --git a/JSIL/AssemblyTranslator.cs b/JSIL/AssemblyTranslator.cs index 190ffd7da..f52f31f04 100644 --- a/JSIL/AssemblyTranslator.cs +++ b/JSIL/AssemblyTranslator.cs @@ -269,6 +269,20 @@ protected bool IsRedirected (string assemblyName) { return false; } + protected bool IsAttributeIgnored(string attributeName) + { + List emitAttributes = Configuration.CodeGenerator.EmitAttributes; + if (emitAttributes.Count == 0) + return false; + foreach (var ia in emitAttributes) + { + if (Regex.IsMatch(attributeName, ia, RegexOptions.IgnoreCase)) + return false; + } + + return true; + } + public string ClassifyAssembly (AssemblyDefinition asm) { if (IsIgnored(asm.FullName)) return "ignored"; @@ -2175,6 +2189,11 @@ where NeedsStaticConstructor(f.FieldType) output.NewLine(); astEmitter.Visit(expr); + //if (typedef.ToString() == "System.TimeSpan") + //{ + //Console.WriteLine(fd.FullName); // detect TimeSpan.MaxValue issue + //} + TranslateCustomAttributes(context, typedef, fd, astEmitter, output); output.Semicolon(false); @@ -2313,6 +2332,10 @@ private void TranslateCustomAttributes ( bool isFirst = true; foreach (var attribute in member.CustomAttributes) { + if (IsAttributeIgnored(attribute.AttributeType.FullName)) + { + continue; + } if (!isFirst || standalone) output.NewLine(); @@ -2356,10 +2379,14 @@ private void TranslateParameterAttributes ( JavascriptAstEmitter astEmitter, JavascriptFormatter output ) { + if (!Configuration.CodeGenerator.EmitAllParameterNames.GetValueOrDefault(false)) + { + return; + } output.Indent(); foreach (var parameter in method.Parameters) { - if (!parameter.HasCustomAttributes && !Configuration.CodeGenerator.EmitAllParameterNames.GetValueOrDefault(false)) + if (!parameter.HasCustomAttributes) continue; output.NewLine(); diff --git a/JSIL/Configuration.cs b/JSIL/Configuration.cs index 4b9a94d57..278630a6e 100644 --- a/JSIL/Configuration.cs +++ b/JSIL/Configuration.cs @@ -46,6 +46,7 @@ public sealed class CodeGeneratorConfiguration { public bool? AutoGenerateEventAccessorsInSkeletons; public bool? AggressivelyUseElementProxies; public bool? EmitAllParameterNames; + public readonly List EmitAttributes = new List(); public void MergeInto (CodeGeneratorConfiguration result) { if (EliminateStructCopies.HasValue) @@ -86,6 +87,7 @@ public void MergeInto (CodeGeneratorConfiguration result) { result.AggressivelyUseElementProxies = AggressivelyUseElementProxies; if (EmitAllParameterNames.HasValue) result.EmitAllParameterNames = EmitAllParameterNames; + result.EmitAttributes.AddRange(EmitAttributes); } } diff --git a/JSIL/Transforms/StaticAnalysis/EmulateStructAssignment.cs b/JSIL/Transforms/StaticAnalysis/EmulateStructAssignment.cs index 8b036a61e..9e005978f 100644 --- a/JSIL/Transforms/StaticAnalysis/EmulateStructAssignment.cs +++ b/JSIL/Transforms/StaticAnalysis/EmulateStructAssignment.cs @@ -329,7 +329,7 @@ public void VisitNode (JSInvocationExpression invocation) { // before we call it. var thisReferenceType = thisReference.GetActualType(TypeSystem); - if (TypeUtil.IsStruct(thisReferenceType)) { + if (TypeUtil.IsStruct(thisReferenceType) && !TypeUtil.IsStructImmutable(thisReferenceType)) { if ((thisReference is JSVariable) || (thisReference is JSFieldAccess)) { var rre = ParentNode as JSResultReferenceExpression; var cloneExpr = new JSBinaryOperatorExpression( diff --git a/JSIL/TypeUtil.cs b/JSIL/TypeUtil.cs index 413e72bd8..4e8e4a897 100644 --- a/JSIL/TypeUtil.cs +++ b/JSIL/TypeUtil.cs @@ -96,6 +96,17 @@ public static bool IsStruct (TypeReference type) { return (etype == MetadataType.ValueType); } + public static bool IsStructImmutable(TypeReference type) + { + bool isImmutable = false; + TypeDefinition typeDef = type.Resolve(); + if (typeDef.CustomAttributes.Count > 0) + { + isImmutable = typeDef.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.FullName == "JSIL.Meta.JSImmutable") != null; + } + return isImmutable; + } + public static bool IsNumeric (TypeReference type) { type = DereferenceType(type); diff --git a/Libraries/JSIL.Bootstrap.js b/Libraries/JSIL.Bootstrap.js index 56fb3be7f..2b0e641e0 100644 --- a/Libraries/JSIL.Bootstrap.js +++ b/Libraries/JSIL.Bootstrap.js @@ -539,6 +539,13 @@ JSIL.ImplementExternals( } ); + $.Method({ Static: false, Public: true }, "GetType", + new JSIL.MethodSignature(mscorlib.TypeRef("System.Type"), []), + function () { + return this.__ThisType__; + } + ); + $.Method({Static: false, Public: true }, "toString", new JSIL.MethodSignature($.String, []), function () { diff --git a/Libraries/JSIL.Core.js b/Libraries/JSIL.Core.js index 969f4ff44..207991e24 100644 --- a/Libraries/JSIL.Core.js +++ b/Libraries/JSIL.Core.js @@ -8313,6 +8313,45 @@ JSIL.Array.ShallowCopy = function (destination, source) { JSIL.Array.CopyTo(source, destination, 0); }; +JSIL.Array.FindIndex = function (array, predicate) { // implements: int System.Array.FindIndex(T[] array, Predicate match) + for (var i = 0, l = array.length; i < l; i++) { + if (predicate(array[i])) + return i; + } + return -1; +}; + +JSIL.Array.Find = function (array, predicate) { // implements: T System.Array.Find(T[] array, Predicate match) + for (var i = 0, l = array.length; i < l; i++) { + if (predicate(array[i])) + return array[i]; + } + return null; // use 'null' and not 'undefined' +}; + +JSIL.Array.ForEach = function (array, action) { // implements: void ForEach(T[] array, Action action) + if (JSIL.IsTypedArray(array)) { + for (var i = 0, l = array.length; i < l; i++) { + array[i] = action(array[i]); + } + } + else Array.prototype.forEach.call(array, action); +}; + +JSIL.Array.ConvertAll = function (array, converter) { // implements: TOutput[] ConvertAll(TInput[] array, Converter converter) + var cloned; + if (JSIL.IsTypedArray(array)) { + var ctor = Object.getPrototypeOf(array).constructor; // clone the typed array + cloned = new ctor(array); + for (var i = 0, l = cloned.length; i < l; i++) { + cloned[i] = converter(cloned[i]); + } + } + else cloned = Array.prototype.map.call(array, converter); + + return cloned; +}; + $jsilcore.CheckDelegateType = function (value) { if (value === null) return false; diff --git a/Meta/Builtins.cs b/Meta/Builtins.cs index dd8e94770..d93a835cd 100644 --- a/Meta/Builtins.cs +++ b/Meta/Builtins.cs @@ -54,11 +54,11 @@ public static T CreateNamedFunction ( throw new NotImplementedException("Not available outside JS"); } - public static bool IsTruthy (dynamic value) { + public static bool IsTruthy (object valueExplicitCastToObject) { throw new NotImplementedException("Not available outside JS"); } - public static bool IsFalsy (dynamic value) { + public static bool IsFalsy (object valueExplicitCastToObject) { throw new NotImplementedException("Not available outside JS"); } diff --git a/Meta/Meta.csproj b/Meta/Meta.csproj index 3c892c00e..b666f7960 100644 --- a/Meta/Meta.csproj +++ b/Meta/Meta.csproj @@ -37,6 +37,12 @@ jsil.ico + + true + + + jsil.snk + @@ -57,6 +63,9 @@ + + +