Example #1
0
        private object OpLdtoken(MethodContext context, ITypeMember member)
        {
            var key = new InstructionKey(InstructionCode.Ldtoken, member);
            var var = context.Vars[key];

            if (var != null)
            {
                return(var);
            }

            var field = member as IField;

            if (field != null)
            {
                if (field.IsArrayInitializer())
                {
                    var blob = field.GetBlob();
                    var arr  = new JsArray(blob.ToArray().Select(x => (object)x));
                    return(context.Vars.Add(key, arr));
                }

                throw new NotImplementedException();
            }

            var type = member as IType;

            if (type != null)
            {
                CompileType(type);
                return(type.FullName);
            }

            throw new NotImplementedException();
        }
Example #2
0
        private static bool IsSuperCall(MethodContext context, IMethod method, CallFlags flags)
        {
            bool thiscall = (flags & CallFlags.Thiscall) != 0;
            bool virtcall = (flags & CallFlags.Virtcall) != 0;

            return(thiscall && !virtcall && IsSuperCall(context, method));
        }
Example #3
0
        internal JsFunction CompileMethodBody(JsClass klass, IMethod method, IClrMethodBody body)
        {
            var blocks  = body.GetAllProtectedBlocks().ToArray();
            var context = new MethodContext(this, klass, method, blocks);

            var func = new JsFunction(null, method.JsParams());

            //TODO: cache info and code as separate class property

            var info = new JsObject(true)
            {
                { "isVoid", method.IsVoid() },
                { "blocks", CompileBlocks(blocks) },
                { "blockMap", CompileBlockMap(body, blocks) },
            };

            var args = CompilerArgs(method);
            var vars = new JsArray(method.Body.LocalVariables.Select(x => x.Type.InitialValue()));
            var code = new JsArray(body.Code.Select <Instruction, object>(i => new JsInstruction(i, CompileInstruction(context, i))), "\n");

            func.Body.Add(args.Var("args"));
            func.Body.Add(vars.Var("vars"));
            func.Body.Add(info.Var("info"));

            foreach (var var in context.Vars)
            {
                func.Body.Add(var);
            }

            func.Body.Add(code.Var("code"));
            func.Body.Add(new JsText("var ctx = new $context(info, args, vars);"));
            func.Body.Add(new JsText("return ctx.exec(code);"));

            return(func);
        }
Example #4
0
        private object OpCall(MethodContext context, Instruction i)
        {
            var method   = i.Method;
            var callInfo = context.Vars[method];

            if (callInfo != null)
            {
                return(callInfo.Id());
            }

            CompileCallMethod(method);

            var func = CreateCallFunc(context, method, i.CallInfo);

            callInfo = context.Vars[method];
            if (callInfo != null)
            {
                return(callInfo.Id());
            }

            var info = new JsObject
            {
                { "n", method.Parameters.Count },
                { "s", method.IsStatic },
                { "r", !method.IsVoid() },
                { "f", func },
            };

            callInfo = context.Vars.Add(method, info);

            return(callInfo.Id());
        }
Example #5
0
        private JsNode OpNewarr(MethodContext context, IType elemType)
        {
            var key = new InstructionKey(InstructionCode.Newarr, elemType);
            var var = context.Vars[key];

            if (var != null)
            {
                return(var.Id());
            }

            var type = RegisterArrayType(elemType);

            var elemInit = new JsFunction(null);

            elemInit.Body.Add(elemType.InitialValue().Return());

            var info = new JsObject
            {
                { "init", elemInit },
                { "type", type.FullName },
                { "box", new BoxingImpl(this).Box(context, elemType) },
                { "unbox", new BoxingImpl(this).Unbox(context, elemType) },
                { "etc", elemType.JsTypeCode() },
            };

            var = context.Vars.Add(key, info);

            CompileClass(SystemTypes.Array);
            CompileType(elemType);

            return(var.Id());
        }
Example #6
0
 private static bool IsSuperCall(MethodContext context, IMethod method)
 {
     if (method.IsStatic || method.IsConstructor || method.IsAbstract)
     {
         return(false);
     }
     return(context.Method.IsBaseMethod(method));
 }
Example #7
0
        public object Compile(MethodContext context, IField field)
        {
            var fieldInfo = context.Vars[field];

            if (fieldInfo != null)
            {
                return(fieldInfo.Id());
            }

            var obj = "o".Id();
            var val = "v".Id();
            var get = new JsFunction(null, obj.Value);
            var set = new JsFunction(null, obj.Value, val.Value);

            var info = new JsObject
            {
                { "get", get },
                { "set", set }
            };

            fieldInfo = context.Vars.Add(field, info);

            if (field.IsStatic)
            {
                _host.InitClass(context, get, field);
                _host.InitClass(context, set, field);

                var name = field.JsFullName();

#if JSC_FIELD_DEBUG
                var value = name.Id().Var("v");
                get.Body.Add(value);
                get.Body.Add(new JsText(string.Format("if (v === undefined) throw new ReferenceError('{0} is undefined');", field.FullName)));
                get.Body.Add(value.Name.Id().Return());
#else
                get.Body.Add(name.Id().Return());
#endif

                set.Body.Add(name.Id().Set(val));
            }
            else
            {
                var name = field.JsName();

#if JSC_FIELD_DEBUG
                var value = obj.Get(name).Var("v");
                get.Body.Add(value);
                get.Body.Add(new JsText(string.Format("if (v === undefined) throw new ReferenceError('{0} is undefined');", field.FullName)));
                get.Body.Add(value.Name.Id().Return());
#else
                get.Body.Add(obj.Get(name).Return());
#endif

                set.Body.Add(obj.Set(name, val));
            }

            return(fieldInfo.Id());
        }
Example #8
0
        public JsNode Box(MethodContext context, IType type)
        {
            var klass = CompileClass(type);

            if (type.IsBoxableType() || type.IsNullableInstance())
            {
                var name = CompileBox(type, klass);

                return(name.Id());
            }

            return("$copy".Id());
        }
Example #9
0
        private static object OpLeave(MethodContext context, Instruction i)
        {
            var index = -1;

            if (i.IsEndOfSehBlock)
            {
                var b = GetSurroundingTryFinally(i);
                if (b != null)
                {
                    index = context.ProtectedBlocks.IndexOf(x => x == b);
                }
            }
            return(new JsTuple(i.Value, index));
        }
Example #10
0
        private JsFunction CreateCallFunc(MethodContext context, IMethod method, CallInfo info)
        {
            var obj  = "o".Id();
            var args = "a".Id();
            var func = new JsFunction(null, obj.Value, args.Value);

            InitClass(context, func, method);

            JsNode call = null;

            //TODO: inplace inline calls
            if (method.DeclaringType.Is(SystemTypeCode.Boolean) && method.IsToString())
            {
                call = obj.Ternary("True", "False");
            }

            //to detect stackoverflows
            //func.Body.Add("console.log".Id().Call(method.JsFullName()).AsStatement());

            if (call == null && info != null)
            {
                if (info.ReceiverType != null && (info.Flags & CallFlags.Basecall) != 0)
                {
                    call = method.JsFullName(info.ReceiverType).Id().Apply(obj, args);
                }
                else if (IsSuperCall(context, method, info.Flags))
                {
                    var baseType = context.Method.DeclaringType.BaseType;
                    call = method.JsFullName(baseType).Id().Apply(obj, args);
                    //TODO: remove $base if it is not needed
                    //call = obj.Get("$base").Get(method.JsName()).Apply(obj, args);
                }
            }

            if (call == null)
            {
                if (!method.IsStatic && !method.IsConstructor && method.DeclaringType.IsBoxableType())
                {
                    new BoxingImpl(this).BoxUnboxed(context, method.DeclaringType, func, obj);
                }

                call = method.Apply(obj, args);
            }

            func.Body.Add(method.IsVoid() ? call.AsStatement() : call.Return());

            return(func);
        }
Example #11
0
        public JsNode Unbox(MethodContext context, IType type)
        {
            var klass = CompileClass(type);

            //TODO: InvalidCastException

            if (type.IsNullableInstance())
            {
                return(CompileUnbox(context, type, klass).Id());
            }

            if (type.IsBoxableType())
            {
                return("$unbox".Id());
            }

            return("$copy".Id());
        }
Example #12
0
        private object OpLdftn(MethodContext context, Instruction i)
        {
            var method = i.Method;
            var key    = new InstructionKey(i.Code, method);

            var info = context.Vars[key];

            if (info != null)
            {
                return(info);
            }

            CompileCallMethod(method);

            var func = CreateCallFunc(context, method, i.CallInfo);

            return(context.Vars.Add(key, func));
        }
Example #13
0
        internal void InitClass(MethodContext context, JsFunction func, ITypeMember member)
        {
            var type = member is IType ? (IType)member : member.DeclaringType;

            if (ExcludeInitClass(type))
            {
                return;
            }

            if (member is IType)
            {
                CompileFields(type, true);
                CompileFields(type, false);
            }
            else
            {
                CompileFields(type, member.IsStatic);
            }

            new ClassInitImpl(this).InitClass(context, func, member);
        }
Example #14
0
        private JsNode OpNewobj(MethodContext context, IMethod method)
        {
            var key  = new InstructionKey(InstructionCode.Newobj, method);
            var data = context.Vars[key];

            if (data != null)
            {
                return(data.Id());
            }

            var args = "a".Id();

            var func = new JsFunction(null, args.Value);

            var info = new JsObject
            {
                { "n", method.Parameters.Count },
                { "f", func },
            };

            data = context.Vars.Add(key, info);

            CompileCallMethod(method);

            InitClass(context, func, method);

            if (method.IsConstructor && method.DeclaringType.IsString())
            {
                func.Body.Add(method.Apply(null, args).Return());
            }
            else
            {
                var obj = "o".Id();
                func.Body.Add(method.DeclaringType.New().Var(obj.Value));
                func.Body.Add(method.Apply(obj, args).AsStatement());
                func.Body.Add(obj.Return());
            }

            return(data.Id());
        }
Example #15
0
        private JsNode OpInitobj(MethodContext context, IType type)
        {
            var key  = new InstructionKey(InstructionCode.Initobj, type);
            var info = context.Vars[key];

            if (info != null)
            {
                return(info.Id());
            }

            var func = new JsFunction(null);

            info = context.Vars.Add(key, func);

            CompileClass(type);

            InitClass(context, func, type);

            func.Body.Add(type.New().Return());

            return(info.Id());
        }
Example #16
0
        public JsProgram Compile()
        {
            if (_program != null)
            {
                return(_program);
            }

            _program = new JsProgram();

            _program.Require("core.js");

            var entryPoint = _assembly.EntryPoint;
            var method     = CompileMethod(entryPoint);

            // system exceptions
            CompileClass(CorlibTypes[CorlibTypeId.NullReferenceException]);
            CompileClass(CorlibTypes[CorlibTypeId.InvalidCastException]);
            CompileClass(CorlibTypes[CorlibTypeId.NotImplementedException]);
            CompileClass(CorlibTypes[CorlibTypeId.IndexOutOfRangeException]);

            // build types
            CompileClass(SystemTypes.Type);


            new TypeInfoBuilder(this, _program).Build();

            //TODO: pass args to main from node.js args

            var ctx  = new MethodContext(this, CompileClass(entryPoint.DeclaringType), entryPoint, new TryCatchBlock[0]);
            var main = new JsFunction(null);

            InitClass(ctx, main, entryPoint);
            main.Body.Add(method.FullName.Id().Call().AsStatement());

            _program.Add(main.Call().AsStatement());

            return(_program);
        }
Example #17
0
        private string CompileUnbox(MethodContext context, IType type, JsClass klass)
        {
            var name = string.Format("{0}.$unbox", type.JsFullName());

            if (klass.UnboxCompiled)
            {
                return(name);
            }

            klass.UnboxCompiled = true;

            var valueType = type.GetTypeArgument(0);
            var unbox     = Unbox(context, valueType);

            var val  = (JsNode)"v".Id();
            var func = new JsFunction(null, "v");

            func.Body.Add(val.Set(unbox.Call(val)));
            func.Body.Add(type.New(val).Return());

            klass.Add(new JsGeneratedMethod(name, func));

            return(name);
        }
Example #18
0
        public void BoxUnboxed(MethodContext context, IType type, JsFunction func, JsNode obj)
        {
            var f = Box(context, type);

            func.Body.Add(obj.Set("$cbox".Id().Call(obj, f)));
        }
Example #19
0
 public static IType ResolveSystemType(this MethodContext context, SystemTypeCode typeCode)
 {
     return(context.Method.DeclaringType.SystemType(typeCode));
 }
Example #20
0
        private object CompileInstruction(MethodContext context, Instruction i)
        {
            //TODO: for every instruction set index of protected block to quickly find exception handlers

            var value = i.Value;

            if (value is long)
            {
                return(CompileInt64((long)value));
            }
            if (value is ulong)
            {
                return(CompileUInt64((ulong)value));
            }

            switch (i.Code)
            {
            // conv ops
            case InstructionCode.Conv_I1:
            case InstructionCode.Conv_I2:
            case InstructionCode.Conv_I4:
            case InstructionCode.Conv_I8:
            case InstructionCode.Conv_U1:
            case InstructionCode.Conv_U2:
            case InstructionCode.Conv_U4:
            case InstructionCode.Conv_U8:
            case InstructionCode.Conv_R4:
            case InstructionCode.Conv_R8:
            case InstructionCode.Conv_R_Un:
            case InstructionCode.Conv_Ovf_I1:
            case InstructionCode.Conv_Ovf_I2:
            case InstructionCode.Conv_Ovf_I4:
            case InstructionCode.Conv_Ovf_I8:
            case InstructionCode.Conv_Ovf_U1:
            case InstructionCode.Conv_Ovf_U2:
            case InstructionCode.Conv_Ovf_U4:
            case InstructionCode.Conv_Ovf_U8:

            // ldelem ops
            case InstructionCode.Ldelem_I1:
            case InstructionCode.Ldelem_I2:
            case InstructionCode.Ldelem_I4:
            case InstructionCode.Ldelem_I8:
            case InstructionCode.Ldelem_R4:
            case InstructionCode.Ldelem_R8:
            case InstructionCode.Ldelem_U1:
            case InstructionCode.Ldelem_U2:
            case InstructionCode.Ldelem_U4:

            // stelem ops
            case InstructionCode.Stelem_I1:
            case InstructionCode.Stelem_I2:
            case InstructionCode.Stelem_I4:
            case InstructionCode.Stelem_I8:
            case InstructionCode.Stelem_R4:
            case InstructionCode.Stelem_R8:

            // ldind ops
            case InstructionCode.Ldind_I1:
            case InstructionCode.Ldind_I2:
            case InstructionCode.Ldind_I4:
            case InstructionCode.Ldind_I8:
            case InstructionCode.Ldind_R4:
            case InstructionCode.Ldind_R8:
            case InstructionCode.Ldind_U1:
            case InstructionCode.Ldind_U2:
            case InstructionCode.Ldind_U4:
                return(OpWithTypeCode(i));

            // stind ops
            case InstructionCode.Stind_I1:
            case InstructionCode.Stind_I2:
            case InstructionCode.Stind_I4:
            case InstructionCode.Stind_I8:
            case InstructionCode.Stind_R4:
            case InstructionCode.Stind_R8:
                return(OpStind(i));

            case InstructionCode.Ldstr:
                // string should be compiled to be ready for Object method calls.
                CompileClass(SystemTypes.String);
                return(value);

            case InstructionCode.Call:
            case InstructionCode.Callvirt:
                return(OpCall(context, i));

            case InstructionCode.Ldftn:
            case InstructionCode.Ldvirtftn:
                return(OpLdftn(context, i));

            case InstructionCode.Calli:
                throw new NotImplementedException();

            case InstructionCode.Newobj:
                return(OpNewobj(context, i.Method));

            case InstructionCode.Initobj:
                return(OpInitobj(context, i.Type));

            case InstructionCode.Newarr:
                return(OpNewarr(context, i.Type));

            case InstructionCode.Ldfld:
            case InstructionCode.Ldsfld:
            case InstructionCode.Ldflda:
            case InstructionCode.Ldsflda:
            case InstructionCode.Stfld:
            case InstructionCode.Stsfld:
                CompileFields(i.Field.DeclaringType, i.Field.IsStatic);
                return(new FieldCompiler(this).Compile(context, i.Field));

            case InstructionCode.Box:
                return(new BoxingImpl(this).Box(context, i.Type));

            case InstructionCode.Unbox:
            case InstructionCode.Unbox_Any:
                return(new BoxingImpl(this).Unbox(context, i.Type));

            case InstructionCode.Ldtoken:
                return(OpLdtoken(context, i.Member));

            case InstructionCode.Isinst:
            case InstructionCode.Castclass:
            case InstructionCode.Ldobj:
            case InstructionCode.Stobj:
                CompileType(i.Type);
                return(i.Type.FullName);

            case InstructionCode.Ldelem:
            case InstructionCode.Ldelema:
                CompileType(i.Type);
                //TODO: add type name
                return(null);

                #region binary, unary arithmetic operations
            //arithmetic operations
            // a + b
            case InstructionCode.Add:
                return(Op(i, BinaryOperator.Addition, false, false));

            case InstructionCode.Add_Ovf:
                return(Op(i, BinaryOperator.Addition, false, true));

            case InstructionCode.Add_Ovf_Un:
                return(Op(i, BinaryOperator.Addition, true, true));

            // a - b
            case InstructionCode.Sub:
                return(Op(i, BinaryOperator.Subtraction, false, false));

            case InstructionCode.Sub_Ovf:
                return(Op(i, BinaryOperator.Subtraction, false, true));

            case InstructionCode.Sub_Ovf_Un:
                return(Op(i, BinaryOperator.Subtraction, true, true));

            // a * b
            case InstructionCode.Mul:
                return(Op(i, BinaryOperator.Multiply, false, false));

            case InstructionCode.Mul_Ovf:
                return(Op(i, BinaryOperator.Multiply, false, true));

            case InstructionCode.Mul_Ovf_Un:
                return(Op(i, BinaryOperator.Multiply, true, true));

            // a / b
            case InstructionCode.Div:
                return(Op(i, BinaryOperator.Division, false, false));

            case InstructionCode.Div_Un:
                return(Op(i, BinaryOperator.Division, true, false));

            // a % b
            case InstructionCode.Rem:
                return(Op(i, BinaryOperator.Modulus, false, false));

            case InstructionCode.Rem_Un:
                return(Op(i, BinaryOperator.Modulus, true, false));

            //bitwise operations
            // a & b
            case InstructionCode.And:
                return(Op(i, BinaryOperator.BitwiseAnd, false, false));

            // a | b
            case InstructionCode.Or:
                return(Op(i, BinaryOperator.BitwiseOr, false, false));

            // a ^ b
            case InstructionCode.Xor:
                return(Op(i, BinaryOperator.ExclusiveOr, false, false));

            // a << b
            case InstructionCode.Shl:
                return(Op(i, BinaryOperator.LeftShift, false, false));

            // a >> b
            case InstructionCode.Shr:
                return(Op(i, BinaryOperator.RightShift, false, false));

            case InstructionCode.Shr_Un:
                return(Op(i, BinaryOperator.RightShift, true, false));

            //unary operations
            case InstructionCode.Neg:
                return(Op(i, UnaryOperator.Negate, false));

            case InstructionCode.Not:
                return(Op(i, UnaryOperator.BitwiseNot, false));

            //relation operations
            // a == b
            case InstructionCode.Ceq:
                return(Op(i, BinaryOperator.Equality, false, false));

            // a > b
            case InstructionCode.Cgt:
                return(Op(i, BinaryOperator.GreaterThan, false, false));

            case InstructionCode.Cgt_Un:
                return(Op(i, BinaryOperator.GreaterThan, true, false));

            // a < b
            case InstructionCode.Clt:
                return(Op(i, BinaryOperator.LessThan, false, false));

            case InstructionCode.Clt_Un:
                return(Op(i, BinaryOperator.LessThan, true, false));

                #endregion

                #region conditional branches

            case InstructionCode.Beq:
            case InstructionCode.Beq_S:
            case InstructionCode.Bne_Un:
            case InstructionCode.Bne_Un_S:
                return(Br(i, BinaryOperator.Equality));

            case InstructionCode.Blt:
            case InstructionCode.Blt_S:
            case InstructionCode.Blt_Un:
            case InstructionCode.Blt_Un_S:
                return(Br(i, BinaryOperator.LessThan));

            case InstructionCode.Ble:
            case InstructionCode.Ble_S:
            case InstructionCode.Ble_Un:
            case InstructionCode.Ble_Un_S:
                return(Br(i, BinaryOperator.LessThanOrEqual));

            case InstructionCode.Bgt:
            case InstructionCode.Bgt_S:
            case InstructionCode.Bgt_Un:
            case InstructionCode.Bgt_Un_S:
                return(Br(i, BinaryOperator.GreaterThan));

            case InstructionCode.Bge:
            case InstructionCode.Bge_S:
            case InstructionCode.Bge_Un:
            case InstructionCode.Bge_Un_S:
                return(Br(i, BinaryOperator.GreaterThanOrEqual));

                #endregion

            case InstructionCode.Leave:
            case InstructionCode.Leave_S:
                return(OpLeave(context, i));
            }

            return(value);
        }