EmitConvert() public method

public EmitConvert ( BoundExpression expr, TypeSymbol to ) : void
expr Pchp.CodeAnalysis.Semantics.BoundExpression
to TypeSymbol
return void
コード例 #1
0
ファイル: BoundEdge.cs プロジェクト: iolevel/peachpie
        internal override void Generate(CodeGenerator cg)
        {
            Contract.ThrowIfNull(Condition);

            if (IsLoop) // perf
            {
                cg.Builder.EmitBranch(ILOpCode.Br, this.Condition);

                // {
                cg.GenerateScope(TrueTarget, NextBlock.Ordinal);
                // }

                // if (Condition)
                cg.EmitSequencePoint(this.Condition.PhpSyntax);
                cg.Builder.MarkLabel(this.Condition);
                cg.EmitConvert(this.Condition, cg.CoreTypes.Boolean);
                cg.Builder.EmitBranch(ILOpCode.Brtrue, TrueTarget);
            }
            else
            {
                // if (Condition)
                cg.EmitSequencePoint(this.Condition.PhpSyntax);
                cg.EmitConvert(this.Condition, cg.CoreTypes.Boolean);
                cg.Builder.EmitBranch(ILOpCode.Brfalse, FalseTarget);

                // {
                cg.GenerateScope(TrueTarget, NextBlock.Ordinal);
                // }
            }

            cg.Scope.ContinueWith(FalseTarget);
        }
コード例 #2
0
                /// <summary>
                /// Emit runtime chain.
                /// </summary>
                /// <returns>Runtime chain value type pushed on top of the stack.</returns>
                public TypeSymbol EmitRuntimeChain(CodeGenerator cg)
                {
                    // create and initialize the chain struct
                    var chaintmp = cg.GetTemporaryLocal(this.Type, true);

                    cg.Builder.EmitLocalAddress(chaintmp);
                    cg.Builder.EmitOpCode(ILOpCode.Initobj);
                    cg.Builder.EmitSymbolToken(cg.Module, cg.Diagnostics, this.Type, null);

                    // fill in the fields
                    for (var element = this; element != null; element = element.Next)
                    {
                        Debug.Assert(element.Type.IsValueType);

                        if (element.Fields != null)
                        {
                            foreach (var pair in element.Fields)
                            {
                                // Template: ADDR chain.Next[.Next]
                                cg.Builder.EmitLocalAddress(chaintmp);
                                for (var x = this; x != element; x = x.Next)
                                {
                                    var nextfield = new FieldPlace_Raw((FieldSymbol)x.Type.GetMembers("Next").Single(), cg.Module);
                                    nextfield.EmitLoadAddress(cg.Builder);
                                }

                                // Template: .<Field> = <Value>
                                var valuefield = new FieldPlace_Raw((FieldSymbol)element.Type.GetMembers(pair.Key).Single(), cg.Module);
                                valuefield.EmitStorePrepare(cg.Builder);
                                if (pair.Value is BoundExpression valueexpr)
                                {
                                    cg.EmitConvert(valueexpr, valuefield.Type);
                                }
                                else if (pair.Value is BoundVariableName nameexpr)
                                {
                                    cg.EmitConvert(nameexpr.EmitVariableName(cg), 0, valuefield.Type);
                                }
                                else
                                {
                                    throw Peachpie.CodeAnalysis.Utilities.ExceptionUtilities.UnexpectedValue(pair.Value);
                                }
                                valuefield.EmitStore(cg.Builder);
                            }
                        }
                    }

                    //
                    cg.Builder.EmitLocalLoad(chaintmp);

                    //
                    return(this.Type);
                }
コード例 #3
0
        /// <summary>
        /// Generates ghost method body that calls <c>this</c> method.
        /// </summary>
        static void GenerateGhostBody(PEModuleBuilder module, DiagnosticBag diagnostic, MethodSymbol method, SynthesizedMethodSymbol ghost)
        {
            var containingtype = ghost.ContainingType;

            var body = MethodGenerator.GenerateMethodBody(module, ghost,
                                                          (il) =>
            {
                // $this
                var thisPlace = ghost.HasThis ? new ArgPlace(containingtype, 0) : null;

                // Context
                var ctxPlace = thisPlace != null && ghost.ContainingType is SourceTypeSymbol sourcetype
                        ? (sourcetype.ContextStore != null ? new FieldPlace(thisPlace, sourcetype.ContextStore, module) : null)
                        : (IPlace) new ArgPlace(module.Compilation.CoreTypes.Context, 0);

                // .callvirt
                bool callvirt = ghost.ExplicitOverride != null && ghost.ExplicitOverride.ContainingType.IsInterface;      // implementing interface, otherwise we should be able to call specific method impl. non-virtually via ghost

                var cg = new CodeGenerator(il, module, diagnostic, module.Compilation.Options.OptimizationLevel, false, containingtype, ctxPlace, thisPlace)
                {
                    DebugRoutine = ghost,
                };

                // return (T){routine}(p0, ..., pN);
                cg.EmitConvert(cg.EmitForwardCall(method, ghost, callvirt: callvirt), 0, ghost.ReturnType);
                cg.EmitRet(ghost.ReturnType);
            },
                                                          null, diagnostic, false);

            module.SetMethodBody(ghost, body);
        }
コード例 #4
0
ファイル: GhostMethodBuilder.cs プロジェクト: xee5ch/peachpie
        /// <summary>
        /// Generates ghost method body that calls <c>this</c> method.
        /// </summary>
        static void GenerateGhostBody(PEModuleBuilder module, DiagnosticBag diagnostic, MethodSymbol method, SynthesizedMethodSymbol ghost)
        {
            var containingtype = ghost.ContainingType;

            var body = MethodGenerator.GenerateMethodBody(module, ghost,
                                                          (il) =>
            {
                // $this
                var thisPlace = ghost.HasThis ? new ArgPlace(containingtype, 0) : null;

                // Context
                var ctxPlace = thisPlace != null && ghost.ContainingType is SourceTypeSymbol sourcetype
                        ? new FieldPlace(thisPlace, sourcetype.ContextStore)
                        : (IPlace) new ArgPlace(module.Compilation.CoreTypes.Context, 0);

                var cg = new CodeGenerator(il, module, diagnostic, module.Compilation.Options.OptimizationLevel, false, containingtype, ctxPlace, thisPlace);

                // return (T){routine}(p0, ..., pN);
                cg.EmitConvert(cg.EmitForwardCall(method, ghost), 0, ghost.ReturnType);
                cg.EmitRet(ghost.ReturnType);
            },
                                                          null, diagnostic, false);

            module.SetMethodBody(ghost, body);
        }
コード例 #5
0
            public TypeSymbol EmitLoad(ILBuilder il)
            {
                if (_loc != null)
                {
                    il.EmitLocalLoad(_loc);
                }
                else
                {
                    // <temporary>[name]
                    Debug.Assert(_cg.TemporalLocalsPlace != null);
                    Debug.Assert(_tempName != null);
                    _cg.TemporalLocalsPlace.EmitLoad(il);
                    _cg.EmitIntStringKey(_tempName);
                    _cg.EmitConvert(_cg.EmitCall(System.Reflection.Metadata.ILOpCode.Callvirt, _cg.CoreMethods.PhpArray.GetItemValue_IntStringKey), 0, Type);
                }

                return(Type);
            }
コード例 #6
0
ファイル: SourceFieldSymbol.cs プロジェクト: iolevel/peachpie
 internal void EmitInit(CodeGenerator cg)
 {
     var fldplace = new FieldPlace(IsStatic ? null : new ArgPlace(ContainingType, 0), this);
     
     if (this.Initializer != null)
     {
         // fld = <initializer>
         fldplace.EmitStorePrepare(cg.Builder);
         cg.EmitConvert(this.Initializer, this.Type);
         fldplace.EmitStore(cg.Builder);
     }
     else
     {
         // fld = default(type)
         cg.EmitInitializePlace(fldplace);
     }
 }
コード例 #7
0
ファイル: BoundTypeRef.cs プロジェクト: iolevel/peachpie
 /// <summary>
 /// Emits name of bound type.
 /// </summary>
 /// <param name="cg"></param>
 internal void EmitClassName(CodeGenerator cg)
 {
     if (TypeExpression != null)
     {
         cg.EmitConvert(TypeExpression, cg.CoreTypes.String);
     }
     else
     {
         if (_typeRef is PrimitiveTypeRef)
         {
             throw new InvalidOperationException();
         }
         else if (_typeRef is TranslatedTypeRef || _typeRef is ClassTypeRef)
         {
             var classname = ((INamedTypeRef)_typeRef).ClassName;
             cg.Builder.EmitStringConstant(classname.ToString());
         }
         else
         {
             throw Roslyn.Utilities.ExceptionUtilities.UnexpectedValue(_typeRef);
         }
     }
 }
コード例 #8
0
ファイル: BoundStatement.cs プロジェクト: iolevel/peachpie
        internal override void Emit(CodeGenerator cg)
        {
            cg.EmitSequencePoint(this.PhpSyntax);

            var rtype = cg.Routine.ReturnType;
            var rvoid = rtype.SpecialType == SpecialType.System_Void;

            //
            if (this.Returned == null)
            {
                if (rvoid)
                {
                    // <void>
                }
                else
                {
                    // <default>
                    cg.EmitLoadDefault(rtype, cg.Routine.ResultTypeMask);
                }
            }
            else
            {
                if (rvoid)
                {
                    // <expr>;
                    cg.EmitPop(this.Returned.Emit(cg));
                }
                else
                {
                    // return (T)<expr>;
                    cg.EmitConvert(this.Returned, rtype);
                }
            }

            // .ret
            cg.EmitRet(rtype);
        }
コード例 #9
0
ファイル: BoundExpression.cs プロジェクト: iolevel/peachpie
        internal override TypeSymbol Emit(CodeGenerator cg)
        {
            // new PhpString()
            cg.EmitCall(ILOpCode.Newobj, cg.CoreMethods.Ctors.PhpString);

            // TODO: overload for 2, 3, 4 parameters directly

            // <PhpString>.Append(<expr>)
            foreach (var x in this.ArgumentsInSourceOrder)
            {
                var expr = x.Value;
                if (IsEmpty(expr))
                    continue;

                //
                cg.Builder.EmitOpCode(ILOpCode.Dup);    // PhpString

                var t = cg.Emit(expr);
                if (t == cg.CoreTypes.PhpString)
                {
                    cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.PhpString.Append_PhpString);
                }
                else
                {
                    // TODO: PhpValue -> PhpString (instead of String)

                    cg.EmitConvert(t, 0, cg.CoreTypes.String);
                    cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.PhpString.Append_String);
                }

                //
                cg.Builder.EmitOpCode(ILOpCode.Nop);
            }

            //
            return cg.CoreTypes.PhpString;
        }
コード例 #10
0
ファイル: Places.cs プロジェクト: iolevel/peachpie
        public void EmitStore(CodeGenerator cg, TypeSymbol valueType)
        {
            var type = _place.TypeOpt;

            // Write Ref
            if (_access.IsWriteRef)
            {
                if (valueType != cg.CoreTypes.PhpAlias)
                {
                    Debug.Assert(false, "caller should get aliased value");
                    cg.EmitConvertToPhpValue(valueType, 0);
                    valueType = cg.Emit_PhpValue_MakeAlias();
                }

                //
                if (type == cg.CoreTypes.PhpAlias)
                {
                    // <place> = <alias>
                    _place.EmitStore(cg.Builder);
                }
                else if (type == cg.CoreTypes.PhpValue)
                {
                    // <place> = PhpValue.Create(<alias>)
                    cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.Create_PhpAlias);
                    _place.EmitStore(cg.Builder);
                }
                else
                {
                    Debug.Assert(false, "Assigning alias to non-aliasable variable.");
                    cg.EmitConvert(valueType, 0, type);
                    _place.EmitStore(cg.Builder);
                }
            }
            else if (_access.IsUnset)
            {
                Debug.Assert(valueType == null);

                // <place> =

                if (type == cg.CoreTypes.PhpAlias)
                {
                    // new PhpAlias(void)
                    cg.Emit_PhpValue_Void();
                    cg.Emit_PhpValue_MakeAlias();
                }
                else if (type.IsReferenceType)
                {
                    // null
                    cg.Builder.EmitNullConstant();
                }
                else
                {
                    // default(T)
                    cg.EmitLoadDefaultOfValueType(type);
                }

                _place.EmitStore(cg.Builder);
            }
            else
            {
                //
                if (type == cg.CoreTypes.PhpAlias)
                {
                    // <place>.Value = <value>
                    cg.EmitConvertToPhpValue(valueType, 0);
                    cg.Emit_PhpAlias_SetValue();
                }
                else if (type == cg.CoreTypes.PhpValue)
                {
                    if (_thint.IsRef)
                    {
                        // Operators.SetValue(ref <place>, (PhpValue)<value>);
                        cg.EmitConvertToPhpValue(valueType, 0);
                        cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.SetValue_PhpValueRef_PhpValue);
                    }
                    else
                    {
                        // <place> = <value>
                        cg.EmitConvertToPhpValue(valueType, 0);
                        _place.EmitStore(cg.Builder);
                    }
                }
                else
                {
                    cg.EmitConvert(valueType, 0, type);
                    _place.EmitStore(cg.Builder);
                }
            }
        }
コード例 #11
0
ファイル: BoundExpression.cs プロジェクト: iolevel/peachpie
        /// <summary>
        /// Emits check for values equality.
        /// Lefts <c>bool</c> on top of evaluation stack.
        /// </summary>
        internal static TypeSymbol EmitEquality(CodeGenerator cg, TypeSymbol xtype, BoundExpression right)
        {
            TypeSymbol ytype;

            switch (xtype.SpecialType)
            {
                case SpecialType.System_Boolean:

                    // bool == y.ToBoolean()
                    cg.EmitConvert(right, cg.CoreTypes.Boolean);
                    cg.Builder.EmitOpCode(ILOpCode.Ceq);

                    return cg.CoreTypes.Boolean;

                case SpecialType.System_Int32:
                    // i4 -> i8
                    cg.Builder.EmitOpCode(ILOpCode.Conv_i8);
                    goto case SpecialType.System_Int64;

                case SpecialType.System_Int64:

                    ytype = cg.Emit(right);

                    //
                    if (ytype.SpecialType == SpecialType.System_Int32)
                    {
                        cg.Builder.EmitOpCode(ILOpCode.Conv_i8);    // i4 -> i8
                        ytype = cg.CoreTypes.Long;
                    }

                    //
                    if (ytype.SpecialType == SpecialType.System_Int64)
                    {
                        // i8 == i8
                        cg.Builder.EmitOpCode(ILOpCode.Ceq);
                        return cg.CoreTypes.Boolean;
                    }
                    else if (ytype.SpecialType == SpecialType.System_Double)
                    {
                        // i8 == r8
                        return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Ceq_long_double)
                            .Expect(SpecialType.System_Boolean);
                    }
                    else if (ytype.SpecialType == SpecialType.System_Boolean)
                    {
                        // i8 == bool
                        return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Ceq_long_bool)
                            .Expect(SpecialType.System_Boolean);
                    }
                    else if (ytype.SpecialType == SpecialType.System_String)
                    {
                        // i8 == string
                        return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Ceq_long_string)
                            .Expect(SpecialType.System_Boolean);
                    }

                    // value
                    ytype = cg.EmitConvertToPhpValue(ytype, 0);

                    // compare(i8, value) == 0
                    cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_long_value);
                    cg.EmitLogicNegation();

                    return cg.CoreTypes.Boolean;

                case SpecialType.System_Double:

                    ytype = cg.EmitConvertNumberToDouble(right);  // bool|long|int -> double

                    if (ytype.SpecialType == SpecialType.System_Double)
                    {
                        // r8 == r8
                        cg.Builder.EmitOpCode(ILOpCode.Ceq);
                        return cg.CoreTypes.Boolean;
                    }
                    else if (ytype.SpecialType == SpecialType.System_String)
                    {
                        // r8 == string
                        return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Ceq_double_string)
                            .Expect(SpecialType.System_Boolean);
                    }

                    // value
                    ytype = cg.EmitConvertToPhpValue(ytype, 0);

                    // compare(double, value) == 0
                    cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_double_value);
                    cg.EmitLogicNegation();

                    return cg.CoreTypes.Boolean;

                case SpecialType.System_String:

                    ytype = cg.Emit(right);

                    if (ytype.SpecialType == SpecialType.System_Int32)
                    {
                        // i4 -> i8
                        cg.Builder.EmitOpCode(ILOpCode.Conv_i8);
                        ytype = cg.CoreTypes.Long;
                    }

                    if (ytype.SpecialType == SpecialType.System_Int64)
                    {
                        // string == i8
                        return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Ceq_string_long)
                            .Expect(SpecialType.System_Boolean);
                    }
                    else if (ytype.SpecialType == SpecialType.System_Boolean)
                    {
                        // string == bool
                        return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Ceq_string_bool)
                            .Expect(SpecialType.System_Boolean);
                    }
                    else if (ytype.SpecialType == SpecialType.System_Double)
                    {
                        // string == r8
                        return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Ceq_string_double)
                            .Expect(SpecialType.System_Boolean);
                    }
                    else if (ytype.SpecialType == SpecialType.System_String)
                    {
                        // compare(string, string) == 0
                        cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_string_string).Expect(SpecialType.System_Int32);
                        cg.EmitLogicNegation();
                        return cg.CoreTypes.Boolean;
                    }

                    // value
                    ytype = cg.EmitConvertToPhpValue(ytype, 0);

                    // compare(string, value) == 0
                    cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_string_value);
                    cg.EmitLogicNegation();
                    return cg.CoreTypes.Boolean;

                //case SpecialType.System_Object:
                //    goto default;

                default:

                    if (xtype == cg.CoreTypes.PhpNumber)
                    {
                        ytype = cg.EmitConvertIntToLong(cg.Emit(right));
                        if (ytype.SpecialType == SpecialType.System_Int64)
                        {
                            // number == i8
                            return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Eq_number_long)
                                .Expect(SpecialType.System_Boolean);
                        }
                        else if (ytype.SpecialType == SpecialType.System_Double)
                        {
                            // number == r8
                            return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Eq_number_double)
                                .Expect(SpecialType.System_Boolean);
                        }
                        else if (ytype == cg.CoreTypes.PhpNumber)
                        {
                            // number == number
                            return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Eq_number_number)
                                .Expect(SpecialType.System_Boolean);
                        }
                        else
                        {
                            ytype = cg.EmitConvertToPhpValue(ytype, 0);
                            // number == value
                            return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Eq_number_PhpValue)
                                .Expect(SpecialType.System_Boolean);
                        }
                    }
                    else
                    {
                        // TODO: xtype: PhpArray, ...

                        xtype = cg.EmitConvertToPhpValue(xtype, 0);

                        // TODO: overloads for type of <right>

                        ytype = cg.EmitConvertToPhpValue(cg.Emit(right), right.TypeRefMask);

                        // value == value
                        return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.Eq_PhpValue_PhpValue)
                            .Expect(SpecialType.System_Boolean);
                    }
            }
        }
コード例 #12
0
ファイル: BoundExpression.cs プロジェクト: iolevel/peachpie
        /// <summary>
        /// Emits binary boolean operation (AND or OR).
        /// </summary>
        /// <param name="cg">A code generator.</param>
        /// <param name="isAnd">Whether to emit AND, otherwise OR.</param>
        /// <returns>A type code of the result.</returns>
        TypeSymbol EmitBinaryBooleanOperation(CodeGenerator cg, bool isAnd)
        {
            var boolean = cg.CoreTypes.Boolean;  // typeof(bool)

            var il = cg.Builder;
            var partial_eval_label = new object();
            var end_label = new object();

            // IF [!]<(bool) Left> THEN GOTO partial_eval;
            cg.EmitConvert(Left, cg.CoreTypes.Boolean);
            il.EmitBranch(isAnd ? ILOpCode.Brfalse : ILOpCode.Brtrue, partial_eval_label);

            // <RESULT> = <(bool) Right>;
            cg.EmitConvert(Right, cg.CoreTypes.Boolean);

            // GOTO end;
            il.EmitBranch(ILOpCode.Br, end_label);
            il.AdjustStack(-1); // workarounds assert in ILBuilder.MarkLabel, we're doing something wrong with ILBuilder

            // partial_eval:
            il.MarkLabel(partial_eval_label);
            il.EmitOpCode(isAnd ? ILOpCode.Ldc_i4_0 : ILOpCode.Ldc_i4_1, 1);

            // end:
            il.MarkLabel(end_label);

            //
            return boolean;
        }
コード例 #13
0
ファイル: BoundExpression.cs プロジェクト: iolevel/peachpie
 internal static TypeSymbol EmitBitOr(CodeGenerator cg, BoundExpression left, BoundExpression right)
 {
     // most common cases:
     if (cg.IsLongOnly(left.TypeRefMask) || cg.IsLongOnly(right.TypeRefMask))
     {
         // i64 | i64 : i64
         cg.EmitConvert(left, cg.CoreTypes.Long);
         cg.EmitConvert(right, cg.CoreTypes.Long);
         cg.Builder.EmitOpCode(ILOpCode.Or);
         return cg.CoreTypes.Long;
     }
     
     //
     return EmitBitOr(cg, cg.Emit(left), right);
 }
コード例 #14
0
ファイル: BoundExpression.cs プロジェクト: iolevel/peachpie
        internal override TypeSymbol Emit(CodeGenerator cg)
        {
            // new PhpArray(count)
            cg.Builder.EmitIntConstant(_items.Length);
            var result = cg.EmitCall(ILOpCode.Newobj, cg.CoreMethods.Ctors.PhpArray_int)
                .Expect(cg.CoreTypes.PhpArray);

            foreach (var x in _items)
            {
                // <PhpArray>
                cg.Builder.EmitOpCode(ILOpCode.Dup);

                // key
                if (x.Key != null)
                {
                    cg.EmitIntStringKey(x.Key);
                }

                // value | alias
                Debug.Assert(x.Value != null);

                var byref = x.Value.Access.IsReadRef;
                var valuetype = byref ? cg.CoreTypes.PhpAlias : cg.CoreTypes.PhpValue;
                cg.EmitConvert(x.Value, valuetype);

                if (x.Key != null)
                {
                    if (byref)  // .SetItemAlias( key, PhpAlias )
                        cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpArray.SetItemAlias_IntStringKey_PhpAlias);
                    else   // .SetItemValue( key, PhpValue )
                        cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpArray.SetItemValue_IntStringKey_PhpValue);
                }
                else
                {
                    if (byref)  // PhpValue.Create( PhpAlias )
                        cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.Create_PhpAlias);

                    // .AddValue( PhpValue )
                    cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpArray.AddValue_PhpValue);
                }
            }

            //
            return result;
        }
コード例 #15
0
ファイル: BoundExpression.cs プロジェクト: iolevel/peachpie
        static TypeSymbol EmitAppend(CodeGenerator cg, TypeSymbol xtype, BoundExpression y)
        {
            if (xtype == cg.CoreTypes.PhpString)
            {
                // x.Append(y); return x;
                cg.Builder.EmitOpCode(ILOpCode.Dup);

                cg.EmitConvert(y, cg.CoreTypes.String);
                cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.PhpString.Append_String);

                //
                return xtype;
            }
            else
            {
                // concat(x, y)
                cg.EmitConvert(xtype, 0, cg.CoreTypes.String);
                cg.EmitConvert(y, cg.CoreTypes.String);

                return cg.EmitCall(ILOpCode.Newobj, cg.CoreMethods.Ctors.PhpString_string_string);
            }
        }
コード例 #16
0
ファイル: BoundExpression.cs プロジェクト: iolevel/peachpie
        internal static TypeSymbol EmitDiv(CodeGenerator cg, TypeSymbol xtype, BoundExpression right, TypeSymbol resultTypeOpt = null)
        {
            var il = cg.Builder;

            xtype = cg.EmitConvertIntToLong(xtype);    // int|bool -> int64
            TypeSymbol ytype;

            switch (xtype.SpecialType)
            {
                case SpecialType.System_Double:
                    ytype = cg.EmitConvertNumberToDouble(right); // bool|int|long|number -> double
                    if (ytype.SpecialType == SpecialType.System_Double)
                    {
                        il.EmitOpCode(ILOpCode.Div);
                        return xtype;   // r8
                    }

                    // double / value : double
                    cg.EmitConvertToPhpValue(ytype, 0);
                    return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Div_double_PhpValue);

                case SpecialType.System_Int64:
                    ytype = cg.EmitConvertIntToLong(cg.Emit(right));  // bool|int -> long
                    if (ytype == cg.CoreTypes.PhpNumber)
                    {
                        // long / number : number
                        return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Division_long_number)
                            .Expect(cg.CoreTypes.PhpNumber);
                    }

                    // long / value : number
                    cg.EmitConvertToPhpValue(ytype, 0);
                    return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Div_long_PhpValue);

                default:
                    if (xtype == cg.CoreTypes.PhpNumber)
                    {
                        ytype = cg.EmitConvertIntToLong(cg.Emit(right));  // bool|int -> long
                        if (ytype == cg.CoreTypes.PhpNumber)
                        {
                            // nmumber / number : number
                            return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Division_number_number)
                                .Expect(cg.CoreTypes.PhpNumber);
                        }
                    }

                    // x -> PhpValue
                    xtype = cg.EmitConvertToPhpValue(xtype, 0);
                    cg.EmitConvert(right, cg.CoreTypes.PhpValue);
                    ytype = cg.CoreTypes.PhpValue;

                    // value / value : number
                    return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Div_PhpValue_PhpValue);
            }
        }
コード例 #17
0
ファイル: BoundExpression.cs プロジェクト: iolevel/peachpie
        /// <summary>
        /// Emits comparison operator pushing <c>bool</c> (<c>i4</c> of value <c>0</c> or <c>1</c>) onto the evaluation stack.
        /// </summary>
        /// <returns>Resulting type code pushed onto the top of evaliuation stack.</returns>
        internal static TypeSymbol EmitLtGt(CodeGenerator cg, TypeSymbol xtype, BoundExpression right, bool lt)
        {
            TypeSymbol ytype;
            var il = cg.Builder;

            switch (xtype.SpecialType)
            {
                case SpecialType.System_Void:
                    // Operators.CompareNull(value)
                    throw new NotImplementedException();

                case SpecialType.System_Int32:
                    // i4 -> i8
                    il.EmitOpCode(ILOpCode.Conv_i8);
                    goto case SpecialType.System_Int64;

                case SpecialType.System_Int64:
                    ytype = cg.EmitConvertIntToLong(cg.Emit(right));    // bool|int -> long
                    if (ytype.SpecialType == SpecialType.System_Int64)
                    {
                        il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt);
                    }
                    else if (ytype.SpecialType == SpecialType.System_Double)
                    {
                        // i8 <> r8
                        return cg.EmitCall(ILOpCode.Call, lt
                            ? cg.CoreMethods.Operators.Clt_long_double
                            : cg.CoreMethods.Operators.Cgt_long_double);
                    }
                    else
                    {
                        ytype = cg.EmitConvertToPhpValue(ytype, 0);

                        // compare(i8, value) <> 0
                        cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_long_value);

                        il.EmitOpCode(ILOpCode.Ldc_i4_0, 1);
                        il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt);
                    }
                    return cg.CoreTypes.Boolean;

                case SpecialType.System_Double:
                    ytype = cg.EmitConvertNumberToDouble(right);    // bool|int|long|number -> double
                    if (ytype.SpecialType == SpecialType.System_Double)
                    {
                        // r8 <> r8
                        il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt);
                    }
                    else
                    {
                        // compare(r8, value)
                        ytype = cg.EmitConvertToPhpValue(ytype, 0);
                        cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_double_value);

                        // <> 0
                        il.EmitOpCode(ILOpCode.Ldc_i4_0, 1);
                        il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt);
                    }
                    return cg.CoreTypes.Boolean;

                case SpecialType.System_String:
                    ytype = cg.Emit(right);
                    if (ytype.SpecialType == SpecialType.System_String)
                    {
                        // compare(string, string)
                        cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_string_string);
                    }
                    else if (ytype.SpecialType == SpecialType.System_Int64)
                    {
                        // compare(string, long)
                        cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_string_long);
                    }
                    else if (ytype.SpecialType == SpecialType.System_Double)
                    {
                        // compare(string, double)
                        cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_string_double);
                    }
                    else
                    {
                        // compare(string, value)
                        ytype = cg.EmitConvertToPhpValue(ytype, 0);
                        cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_string_value);
                    }

                    // <> 0
                    il.EmitOpCode(ILOpCode.Ldc_i4_0, 1);
                    il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt);
                    return cg.CoreTypes.Boolean;

                case SpecialType.System_Boolean:

                    cg.EmitConvert(right, cg.CoreTypes.Boolean);
                    ytype = cg.CoreTypes.Boolean;

                    // compare(bool, bool)
                    cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_bool_bool);

                    // <> 0
                    il.EmitOpCode(ILOpCode.Ldc_i4_0, 1);
                    il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt);
                    return cg.CoreTypes.Boolean;

                default:
                    if (xtype == cg.CoreTypes.PhpNumber)
                    {
                        ytype = cg.EmitConvertIntToLong(cg.Emit(right));    // bool|int -> long
                        if (ytype.SpecialType == SpecialType.System_Int64)
                        {
                            // number <> i8
                            return cg.EmitCall(ILOpCode.Call, lt
                                ? cg.CoreMethods.PhpNumber.lt_number_long
                                : cg.CoreMethods.PhpNumber.gt_number_long)
                                .Expect(SpecialType.System_Boolean);
                        }
                        else if (ytype.SpecialType == SpecialType.System_Double)
                        {
                            // number <> r8
                            return cg.EmitCall(ILOpCode.Call, lt
                                ? cg.CoreMethods.PhpNumber.lt_number_double
                                : cg.CoreMethods.PhpNumber.gt_number_double)
                                .Expect(SpecialType.System_Boolean);
                        }
                        else if (ytype == cg.CoreTypes.PhpNumber)
                        {
                            // number <> number
                            return cg.EmitCall(ILOpCode.Call, lt
                                ? cg.CoreMethods.PhpNumber.lt_number_number
                                : cg.CoreMethods.PhpNumber.gt_number_number)
                                .Expect(SpecialType.System_Boolean);
                        }
                        else
                        {
                            ytype = cg.EmitConvertToPhpValue(ytype, 0);

                            // compare(number, value)
                            cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_number_value);

                            // <> 0
                            il.EmitOpCode(ILOpCode.Ldc_i4_0, 1);    // +1 on stack
                            il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt);
                            return cg.CoreTypes.Boolean;
                        }
                    }
                    else
                    {
                        xtype = cg.EmitConvertToPhpValue(xtype, 0);
                        ytype = cg.Emit(right);

                        // TODO: if (ytype.SpecialType == SpecialType.System_Boolean) ...
                        // TODO: if (ytype.SpecialType == SpecialType.System_Int64) ...
                        // TODO: if (ytype.SpecialType == SpecialType.System_String) ...
                        // TODO: if (ytype.SpecialType == SpecialType.System_Double) ...

                        // compare(value, value)
                        ytype = cg.EmitConvertToPhpValue(ytype, right.TypeRefMask);
                        cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_value_value);

                        // <> 0
                        il.EmitOpCode(ILOpCode.Ldc_i4_0, 1);
                        il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt);
                        return cg.CoreTypes.Boolean;
                    }
            }
        }
コード例 #18
0
ファイル: Places.cs プロジェクト: iolevel/peachpie
        public void EmitStorePrepare(CodeGenerator cg, InstanceCacheHolder instanceOpt = null)
        {
            if (_lazyStoreCallSite == null)
                _lazyStoreCallSite = cg.Factory.StartCallSite("set_" + this.NameValueOpt);

            // callsite.Target callsite
            _lazyStoreCallSite.EmitLoadTarget(cg.Builder);
            _lazyStoreCallSite.Place.EmitLoad(cg.Builder);

            // instance
            InstanceCacheHolder.EmitInstance(instanceOpt, cg, Instance);

            // NameExpression in case of indirect call
            if (!_name.IsDirect)
            {
                cg.EmitConvert(_name.NameExpression, cg.CoreTypes.String);
            }
        }
コード例 #19
0
ファイル: Places.cs プロジェクト: iolevel/peachpie
        public TypeSymbol EmitLoad(CodeGenerator cg)
        {
            // resolve actual return type
            TypeSymbol return_type;
            if (Access.EnsureObject) return_type = cg.CoreTypes.Object;
            else if (Access.EnsureArray) return_type = cg.CoreTypes.IPhpArray;
            else if (Access.IsReadRef) return_type = cg.CoreTypes.PhpAlias;
            else return_type = Access.TargetType ?? cg.CoreTypes.PhpValue;

            var args = new List<TypeSymbol>();

            // NameExpression in case of indirect call
            if (!_name.IsDirect)
            {
                cg.EmitConvert(_name.NameExpression, cg.CoreTypes.String);
                args.Add(cg.CoreTypes.String);
            }

            // Target()
            var functype = cg.Factory.GetCallSiteDelegateType(
                cg.CoreTypes.PhpTypeInfo, RefKind.None,
                args.AsImmutable(),
                default(ImmutableArray<RefKind>),
                null,
                return_type);


            cg.EmitCall(ILOpCode.Callvirt, functype.DelegateInvokeMethod);

            if (_boundref.IsClassConstant)
            {
                throw new NotImplementedException();
            }

            //
            _lazyLoadCallSite.Construct(functype, cctor =>
            {
                // new GetFieldBinder(field_name, context, return, flags)   // TODO: class constants
                cctor.Builder.EmitStringConstant(this.NameValueOpt);
                cctor.EmitLoadToken(cg.Routine.ContainingType, null);
                cctor.EmitLoadToken(return_type, null);
                cctor.Builder.EmitIntConstant((int)Access.AccessFlags);
                cctor.EmitCall(ILOpCode.Newobj, cg.CoreMethods.Dynamic.GetFieldBinder_ctor);
            });

            //
            return return_type;
        }
コード例 #20
0
ファイル: Places.cs プロジェクト: iolevel/peachpie
        /// <summary>
        /// Emits name as string. Caches the result if holder is provided, or loads evaluated name if holder was initialized already.
        /// </summary>
        public static void EmitName(InstanceCacheHolder holderOrNull, CodeGenerator cg, BoundExpression name)
        {
            Contract.ThrowIfNull(cg);
            Contract.ThrowIfNull(name);

            if (holderOrNull != null)
            {
                holderOrNull.EmitName(cg, name);
            }
            else
            {
                cg.EmitConvert(name, cg.CoreTypes.String);
            }
        }
コード例 #21
0
ファイル: BoundEdge.cs プロジェクト: iolevel/peachpie
        internal override void Generate(CodeGenerator cg)
        {
            // four cases:
            // 1. just single or none case label that can be replaced with single IF
            // 2. switch over integers, using native CIL switch
            // 3. switch over strings, using C# static Dictionary and CIL switch
            // 4. PHP style switch which is just a bunch of IFs

            if (this.CaseBlocks.Length == 0 || this.CaseBlocks[0].IsDefault)
            {
                Debug.Assert(this.CaseBlocks.Length <= 1);

                // no SWITCH or IF needed

                cg.EmitPop(this.SwitchValue.WithAccess(BoundAccess.None).Emit(cg)); // None Access, also using BoundExpression.Emit directly to avoid CodeGenerator type specialization which is not needed
                if (this.CaseBlocks.Length == 1)
                {
                    cg.GenerateScope(this.CaseBlocks[0], NextBlock.Ordinal);
                }
            }
            else
            {
                // CIL Switch:
                bool allconsts = this.CaseBlocks.All(c => c.IsDefault || c.CaseValue.ConstantValue.HasValue);
                bool allconstints = allconsts && this.CaseBlocks.All(c => c.IsDefault || IsInt32(c.CaseValue.ConstantValue.Value));
                //bool allconststrings = allconsts && this.CaseBlocks.All(c => c.IsDefault || IsString(c.CaseValue.ConstantValue.Value));

                var default_block = this.DefaultBlock;

                // <switch_loc> = <SwitchValue>;
                TypeSymbol switch_type;
                LocalDefinition switch_loc;

                // Switch Header
                if (allconstints)
                {
                    switch_type = cg.CoreTypes.Int32;
                    cg.EmitSequencePoint(this.SwitchValue.PhpSyntax);
                    cg.EmitConvert(this.SwitchValue, switch_type);
                    switch_loc = cg.GetTemporaryLocal(switch_type);
                    cg.Builder.EmitLocalStore(switch_loc);

                    // switch (labels)
                    cg.Builder.EmitIntegerSwitchJumpTable(GetSwitchCaseLabels(CaseBlocks), default_block ?? NextBlock, switch_loc, switch_type.PrimitiveTypeCode);
                }
                //else if (allconststrings)
                //{

                //}
                else
                {
                    // legacy jump table
                    // IF (case_i) GOTO label_i;

                    cg.EmitSequencePoint(this.SwitchValue.PhpSyntax);
                    switch_type = cg.Emit(this.SwitchValue);
                    switch_loc = cg.GetTemporaryLocal(switch_type);
                    cg.Builder.EmitLocalStore(switch_loc);

                    //
                    for (int i = 0; i < this.CaseBlocks.Length; i++)
                    {
                        var this_block = this.CaseBlocks[i];
                        if (this_block.CaseValue != null)
                        {
                            // <CaseValue>:
                            cg.EmitSequencePoint(this_block.CaseValue.PhpSyntax);
                            
                            // if (<switch_loc> == c.CaseValue) goto this_block;
                            cg.Builder.EmitLocalLoad(switch_loc);
                            BoundBinaryEx.EmitEquality(cg, switch_type, this_block.CaseValue);
                            cg.Builder.EmitBranch(ILOpCode.Brtrue, this_block);
                        }
                    }

                    // default:
                    cg.Builder.EmitBranch(ILOpCode.Br, default_block ?? NextBlock);
                }

                // FREE <switch_loc>
                cg.ReturnTemporaryLocal(switch_loc);

                // Switch Body
                this.CaseBlocks.ForEach((i, this_block) =>
                {
                    var next_case = (i + 1 < this.CaseBlocks.Length) ? this.CaseBlocks[i + 1] : null;

                    // {
                    cg.GenerateScope(this_block, (next_case ?? NextBlock).Ordinal);
                    // }
                });
            }

            //
            cg.Scope.ContinueWith(NextBlock);
        }
コード例 #22
0
ファイル: BoundExpression.cs プロジェクト: iolevel/peachpie
        internal override TypeSymbol Emit(CodeGenerator cg)
        {
            TypeSymbol result;
            var isvoid = this.Access.IsNone;

            Debug.Assert(_arguments.Length == 1);
            Debug.Assert(_arguments[0].Value.Access.IsRead);
            Debug.Assert(Access.IsRead || Access.IsNone);

            var method = this.Target;
            if (method != null) // => IsResolved
            {
                // emit condition for include_once/require_once
                if (IsOnceSemantic)
                {
                    var tscript = method.ContainingType;

                    result = isvoid
                        ? cg.CoreTypes.Void.Symbol
                        : cg.DeclaringCompilation.GetTypeFromTypeRef(cg.Routine.TypeRefContext, this.TypeRefMask);

                    // Template: (<ctx>.CheckIncludeOnce<TScript>()) ? <Main>() : TRUE
                    // Template<isvoid>: if (<ctx>.CheckIncludeOnce<TScript>()) <Main>()
                    var falseLabel = new object();
                    var endLabel = new object();

                    cg.EmitLoadContext();
                    cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.Context.CheckIncludeOnce_TScript.Symbol.Construct(tscript));

                    cg.Builder.EmitBranch(ILOpCode.Brfalse, falseLabel);

                    // ? (PhpValue)<Main>(...)
                    cg.EmitCallMain(method);
                    if (isvoid)
                    {
                        cg.EmitPop(method.ReturnType);
                    }
                    else
                    {
                        cg.EmitConvert(method.ReturnType, 0, result);
                    }
                    cg.Builder.EmitBranch(ILOpCode.Br, endLabel);

                    if (!isvoid)
                    {
                        cg.Builder.AdjustStack(-1); // workarounds assert in ILBuilder.MarkLabel, we're doing something wrong with ILBuilder
                    }

                    // : PhpValue.Create(true)
                    cg.Builder.MarkLabel(falseLabel);
                    if (!isvoid)
                    {
                        cg.Builder.EmitBoolConstant(true);
                        cg.EmitConvert(cg.CoreTypes.Boolean, 0, result);
                    }

                    //
                    cg.Builder.MarkLabel(endLabel);
                }
                else
                {
                    // <Main>
                    result = cg.EmitCallMain(method);
                }
            }
            else
            {
                Debug.Assert(cg.LocalsPlaceOpt != null);

                // Template: <ctx>.Include(dir, path, locals, @this, bool once = false, bool throwOnError = false)
                cg.EmitLoadContext();
                cg.Builder.EmitStringConstant(cg.Routine.ContainingFile.DirectoryRelativePath);
                cg.EmitConvert(_arguments[0].Value, cg.CoreTypes.String);
                cg.LocalsPlaceOpt.EmitLoad(cg.Builder); // scope of local variables, corresponds to $GLOBALS in global scope.
                cg.EmitThisOrNull();    // $this
                cg.Builder.EmitBoolConstant(IsOnceSemantic);
                cg.Builder.EmitBoolConstant(IsRequireSemantic);
                return cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.Context.Include_string_string_PhpArray_object_bool_bool);
            }

            //
            return result;
        }
コード例 #23
0
ファイル: BoundExpression.cs プロジェクト: iolevel/peachpie
        internal override TypeSymbol Emit(CodeGenerator cg)
        {
            var target_place = this.Target.BindPlace(cg);
            Debug.Assert(target_place != null);
            Debug.Assert(target_place.TypeOpt == null || target_place.TypeOpt.SpecialType != SpecialType.System_Void);

            // T tmp; // in case access is Read
            var t_value = target_place.TypeOpt;
            if (t_value == cg.CoreTypes.PhpAlias || t_value == cg.CoreTypes.PhpValue)
                t_value = null; // no inplace conversion

            LocalDefinition tmp = null;

            // <target> = <value>
            target_place.EmitStorePrepare(cg);

            // TODO: load value & dereference eventually
            if (t_value != null) cg.EmitConvert(this.Value, t_value);   // TODO: do not convert here yet
            else t_value = cg.Emit(this.Value);

            switch (this.Access.Flags)
            {
                case AccessMask.Read:
                    tmp = cg.GetTemporaryLocal(t_value, false);
                    cg.Builder.EmitOpCode(ILOpCode.Dup);
                    cg.Builder.EmitLocalStore(tmp);
                    break;
                case AccessMask.None:
                    break;
                default:
                    throw ExceptionUtilities.UnexpectedValue(this.Access);
            }

            target_place.EmitStore(cg, t_value);

            //
            switch (this.Access.Flags)
            {
                case AccessMask.None:
                    t_value = cg.CoreTypes.Void;
                    break;
                case AccessMask.Read:
                    cg.Builder.EmitLocalLoad(tmp);
                    break;
                default:
                    throw ExceptionUtilities.UnexpectedValue(this.Access);
            }

            if (tmp != null)
            {
                cg.ReturnTemporaryLocal(tmp);
            }

            //
            return t_value;
        }
コード例 #24
0
ファイル: BoundExpression.cs プロジェクト: iolevel/peachpie
        internal static TypeSymbol EmitPow(CodeGenerator cg, TypeSymbol xtype, FlowAnalysis.TypeRefMask xtype_hint, BoundExpression right)
        {
            var il = cg.Builder;

            TypeSymbol ytype;
            xtype = cg.EmitConvertIntToLong(xtype);    // int|bool -> long

            switch (xtype.SpecialType)
            {
                case SpecialType.System_Int64:
                    ytype = cg.EmitConvertIntToLong(cg.Emit(right));    // int|bool -> long

                    if (ytype.SpecialType == SpecialType.System_Int64)
                    {
                        // i8 ** i8 : number
                        return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_long_long);
                    }
                    else if (ytype.SpecialType == SpecialType.System_Double)
                    {
                        // i8 ** r8 : r8
                        return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_long_double);
                    }
                    else if (ytype == cg.CoreTypes.PhpNumber)
                    {
                        // i8 ** number : number
                        return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_long_number);
                    }
                    // y -> PhpValue
                    cg.EmitConvert(ytype, right.TypeRefMask, cg.CoreTypes.PhpValue);
                    ytype = cg.CoreTypes.PhpValue;

                    // i8 ** value : number
                    return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_long_value);

                case SpecialType.System_Double:
                    ytype = cg.EmitConvertNumberToDouble(right);    // int|bool|long|number -> double

                    if (ytype.SpecialType == SpecialType.System_Double)
                    {
                        // r8 ** r8 : r8
                        return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_double_double);
                    }
                    // y -> PhpValue
                    cg.EmitConvert(ytype, right.TypeRefMask, cg.CoreTypes.PhpValue);
                    ytype = cg.CoreTypes.PhpValue;

                    // r8 ** value : r8
                    return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_double_value);

                default:
                    if (xtype == cg.CoreTypes.PhpNumber)
                    {
                        ytype = cg.EmitConvertIntToLong(cg.Emit(right));    // int|bool -> long
                        if (ytype == cg.CoreTypes.Double)
                        {
                            // number ** r8 : r8
                            return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_number_double);
                        }

                        if (ytype.SpecialType == SpecialType.System_Int64)
                        {
                            // y -> number
                            ytype = cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Create_Long);
                        }

                        if (ytype == cg.CoreTypes.PhpNumber)
                        {
                            // number ** number : number
                            return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_number_number);
                        }

                        // y -> PhpValue
                        ytype = cg.EmitConvertToPhpValue(ytype, right.TypeRefMask);

                        // number ** value : number
                        return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_number_value);
                    }

                    // x -> PhpValue
                    xtype = cg.EmitConvertToPhpValue(xtype, xtype_hint);
                    cg.EmitConvert(right, cg.CoreTypes.PhpValue);
                    ytype = cg.CoreTypes.PhpValue;

                    // value ** value : number
                    return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_value_value);
            }
        }
コード例 #25
0
ファイル: BoundExpression.cs プロジェクト: iolevel/peachpie
        internal override TypeSymbol Emit(CodeGenerator cg)
        {
            var result_type = cg.DeclaringCompilation.GetTypeFromTypeRef(cg.Routine, this.TypeRefMask);

            if (this.IfTrue != null)
            {
                object trueLbl = new object();
                object endLbl = new object();

                // Cond ? True : False
                cg.EmitConvert(this.Condition, cg.CoreTypes.Boolean);   // i4
                cg.Builder.EmitBranch(ILOpCode.Brtrue, trueLbl);

                // false:
                cg.EmitConvert(this.IfFalse, result_type);
                cg.Builder.EmitBranch(ILOpCode.Br, endLbl);
                cg.Builder.AdjustStack(-1); // workarounds assert in ILBuilder.MarkLabel, we're doing something wrong with ILBuilder
                // trueLbl:
                cg.Builder.MarkLabel(trueLbl);
                cg.EmitConvert(this.IfTrue, result_type);

                // endLbl:
                cg.Builder.MarkLabel(endLbl);
            }
            else
            {
                object trueLbl = new object();
                object endLbl = new object();

                // Cond ?: False

                // <stack> = <cond_var> = Cond
                var cond_type = cg.Emit(this.Condition);
                var cond_var = cg.GetTemporaryLocal(cond_type);
                cg.Builder.EmitOpCode(ILOpCode.Dup);
                cg.Builder.EmitLocalStore(cond_var);

                cg.EmitConvertToBool(cond_type, this.Condition.TypeRefMask);
                cg.Builder.EmitBranch(ILOpCode.Brtrue, trueLbl);

                // false:
                cg.EmitConvert(this.IfFalse, result_type);
                cg.Builder.EmitBranch(ILOpCode.Br, endLbl);
                cg.Builder.AdjustStack(-1); // workarounds assert in ILBuilder.MarkLabel, we're doing something wrong with ILBuilder

                // trueLbl:
                cg.Builder.MarkLabel(trueLbl);
                cg.Builder.EmitLocalLoad(cond_var);
                cg.EmitConvert(cond_type, this.Condition.TypeRefMask, result_type);

                // endLbl:
                cg.Builder.MarkLabel(endLbl);

                //
                cg.ReturnTemporaryLocal(cond_var);
            }

            //
            if (Access.IsNone)
            {
                cg.EmitPop(result_type);
                result_type = cg.CoreTypes.Void;
            }

            //
            return result_type;
        }
コード例 #26
0
ファイル: BoundExpression.cs プロジェクト: iolevel/peachpie
        internal override TypeSymbol Emit(CodeGenerator cg)
        {
            Debug.Assert(Access.IsRead || Access.IsNone);

            TypeSymbol returned_type;

            switch (this.Operation)
            {
                case Operations.AtSign:
                    // special arrangement
                    // Template:
                    //		context.DisableErrorReporting();
                    //		s;
                    //		context.EnableErrorReporting();
                    returned_type = cg.EmitWithDisabledErrorReporting(Operand);
                    break;

                case Operations.BitNegation:
                    //Template: "~x" Operators.BitNot(x)                                     
                    returned_type = EmitBitNot(cg);
                    break;

                case Operations.Clone:
                    // Template: clone x
                    Debug.WriteLine("TODO: clone(object)");
                    returned_type = cg.Emit(Operand);   // TODO: clone
                    break;

                case Operations.LogicNegation:
                    //Template: !(bool)(x);                              
                    cg.EmitConvertToBool(this.Operand, true);
                    returned_type = cg.CoreTypes.Boolean;
                    break;

                case Operations.Minus:
                    //Template: "-x"
                    returned_type = EmitMinus(cg);
                    break;

                case Operations.Plus:
                    //Template: "+x"
                    returned_type = EmitPlus(cg);
                    break;

                case Operations.ObjectCast:
                    //Template: "(object)x"
                    cg.EmitConvert(this.Operand, cg.CoreTypes.Object);
                    returned_type = cg.CoreTypes.Object;
                    break;

                case Operations.Print:
                    cg.EmitEcho(this.Operand);

                    if (Access.IsRead)
                    {
                        // Always returns 1
                        cg.Builder.EmitLongConstant(1);
                        returned_type = cg.CoreTypes.Long;
                    }
                    else
                    {
                        // nobody reads the result anyway
                        returned_type = cg.CoreTypes.Void;
                    }
                    break;

                case Operations.BoolCast:
                    //Template: "(bool)x"
                    cg.EmitConvert(this.Operand, cg.CoreTypes.Boolean);
                    returned_type = cg.CoreTypes.Boolean;
                    break;

                case Operations.Int8Cast:
                case Operations.Int16Cast:
                case Operations.Int32Cast:
                case Operations.UInt8Cast:
                case Operations.UInt16Cast:

                case Operations.UInt64Cast:
                case Operations.UInt32Cast:
                case Operations.Int64Cast:

                    cg.EmitConvert(this.Operand, cg.CoreTypes.Long);
                    returned_type = cg.CoreTypes.Long;
                    break;

                case Operations.DecimalCast:
                case Operations.DoubleCast:
                case Operations.FloatCast:

                    cg.EmitConvert(this.Operand, cg.CoreTypes.Double);
                    returned_type = cg.CoreTypes.Double;
                    break;

                case Operations.UnicodeCast: // TODO
                case Operations.StringCast:
                    // (string)x
                    cg.EmitConvert(this.Operand, cg.CoreTypes.String);  // TODO: to String or PhpString ? to not corrupt single-byte string
                    return cg.CoreTypes.String;

                case Operations.BinaryCast:
                    //if ((returned_typecode = node.Expr.Emit(codeGenerator)) != PhpTypeCode.PhpBytes)
                    //{
                    //    codeGenerator.EmitBoxing(returned_typecode);
                    //    //codeGenerator.EmitLoadClassContext();
                    //    il.Emit(OpCodes.Call, Methods.Convert.ObjectToPhpBytes);
                    //    returned_typecode = PhpTypeCode.PhpBytes;
                    //}
                    //break;
                    throw new NotImplementedException();

                case Operations.ArrayCast:
                    //Template: "(array)x"
                    cg.EmitConvert(this.Operand, cg.CoreTypes.PhpArray);    // TODO: EmitArrayCast()
                    returned_type = cg.CoreTypes.PhpArray;
                    break;
                    
                case Operations.UnsetCast:
                    // Template: "(unset)x"  null

                    cg.EmitPop(cg.Emit(this.Operand));

                    if (this.Access.IsRead)
                    {
                        cg.Builder.EmitNullConstant();
                        returned_type = cg.CoreTypes.Object;
                    }
                    else
                    {
                        returned_type = cg.CoreTypes.Void;
                    }
                    break;

                default:
                    throw ExceptionUtilities.Unreachable;
            }

            switch (Access.Flags)
            {
                case AccessMask.Read:
                    Debug.Assert(returned_type.SpecialType != SpecialType.System_Void);
                    // do nothing
                    break;
                case AccessMask.None:
                    // pop operation's result value from stack
                    cg.EmitPop(returned_type);
                    returned_type = cg.CoreTypes.Void;
                    break;
                default:
                    throw ExceptionUtilities.UnexpectedValue(Access);
            }

            return returned_type;
        }
コード例 #27
0
ファイル: BoundExpression.cs プロジェクト: iolevel/peachpie
 internal override TypeSymbol Emit(CodeGenerator cg)
 {
     cg.EmitConvert(this.Variable, cg.CoreTypes.PhpValue);
     return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.IsEmpty_PhpValue)
         .Expect(SpecialType.System_Boolean);
 }
コード例 #28
0
ファイル: BoundExpression.cs プロジェクト: iolevel/peachpie
        void IBoundReference.EmitStore(CodeGenerator cg, TypeSymbol valueType)
        {
            var rtype = cg.CoreTypes.IPhpArray;
            cg.EmitConvert(valueType, 0, rtype);

            var tmp = cg.GetTemporaryLocal(rtype);
            cg.Builder.EmitLocalStore(tmp);

            // NOTE: since PHP7, variables are assigned from left to right
            var vars = this.Variables;
            for (int i = 0; i < vars.Length; i++)
            {
                var target = vars[i];
                if (target == null)
                    continue;

                var boundtarget = target.BindPlace(cg);
                boundtarget.EmitStorePrepare(cg);

                // LOAD IPhpArray.GetItemValue(IntStringKey{i})
                cg.Builder.EmitLocalLoad(tmp);
                cg.EmitIntStringKey(i);
                var itemtype = cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.IPhpArray.GetItemValue_IntStringKey);

                // STORE vars[i]
                boundtarget.EmitStore(cg, itemtype);
            }

            //
            cg.ReturnTemporaryLocal(tmp);
        }
コード例 #29
0
ファイル: BoundExpression.cs プロジェクト: iolevel/peachpie
        internal static TypeSymbol EmitBitOr(CodeGenerator cg, TypeSymbol xtype, BoundExpression right)
        {
            switch (xtype.SpecialType)
            {
                case SpecialType.System_Void:
                case SpecialType.System_Int32:
                case SpecialType.System_Boolean:
                case SpecialType.System_Double:
                    cg.EmitConvert(xtype, 0, cg.CoreTypes.Long);
                    goto case SpecialType.System_Int64;

                case SpecialType.System_Int64:
                    cg.EmitConvert(right, cg.CoreTypes.Long);
                    cg.Builder.EmitOpCode(ILOpCode.Or);
                    return cg.CoreTypes.Long;

                case SpecialType.System_String:
                    throw new NotImplementedException();    // string | string or string | long

                default:
                    if (right.ResultType != null && right.ResultType.SpecialType != SpecialType.System_String)
                    {
                        // value | !string -> long | long -> long
                        cg.EmitConvert(xtype, 0, cg.CoreTypes.Long);
                        goto case SpecialType.System_Int64;
                    }

                    cg.EmitConvert(xtype, 0, cg.CoreTypes.PhpValue);
                    cg.EmitConvert(right, cg.CoreTypes.PhpValue);
                    return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.BitwiseOr_PhpValue_PhpValue)
                        .Expect(cg.CoreTypes.PhpValue);
            }
        }
コード例 #30
0
ファイル: BoundExpression.cs プロジェクト: iolevel/peachpie
        internal virtual TypeSymbol EmitCallsiteCall(CodeGenerator cg)
        {
            // callsite

            var nameOpt = this.CallsiteName;
            var callsite = cg.Factory.StartCallSite("call_" + nameOpt);

            var callsiteargs = new List<TypeSymbol>(_arguments.Length);
            var return_type = this.Access.IsRead
                    ? this.Access.IsReadRef
                        ? cg.CoreTypes.PhpAlias.Symbol
                        : (this.Access.TargetType ?? cg.CoreTypes.PhpValue.Symbol)
                    : cg.CoreTypes.Void.Symbol;

            // callsite
            var fldPlace = callsite.Place;

            // LOAD callsite.Target
            callsite.EmitLoadTarget(cg.Builder);

            // LOAD callsite arguments

            // (callsite, [target], ctx, [name], ...)
            fldPlace.EmitLoad(cg.Builder);

            if (Instance != null)
            {
                callsiteargs.Add(cg.Emit(Instance));   // instance
            }
            else if (TypeNameExpr != null)
            {
                cg.EmitConvert(TypeNameExpr, cg.CoreTypes.String);
                callsiteargs.Add(cg.CoreTypes.String);   // type
            }

            callsiteargs.Add(cg.EmitLoadContext());     // ctx

            if (RoutineNameExpr != null)
            {
                callsiteargs.Add(cg.Emit(RoutineNameExpr));   // name
            }

            foreach (var a in _arguments)
            {
                callsiteargs.Add(cg.Emit(a.Value));
            }

            // Target()
            var functype = cg.Factory.GetCallSiteDelegateType(
                null, RefKind.None,
                callsiteargs.AsImmutable(),
                default(ImmutableArray<RefKind>),
                null,
                return_type);

            cg.EmitCall(ILOpCode.Callvirt, functype.DelegateInvokeMethod);

            // Create CallSite ...
            callsite.Construct(functype, cctor_cg => BuildCallsiteCreate(cctor_cg, return_type));

            //
            return return_type;
        }
コード例 #31
0
ファイル: BoundExpression.cs プロジェクト: iolevel/peachpie
        /// <summary>
        /// Emits binary operation XOR.
        /// </summary>
        TypeSymbol EmitBinaryXor(CodeGenerator cg)
        {
            // LOAD <(bool) leftSon> == <(bool) rightSon>;
            cg.EmitConvert(Left, cg.CoreTypes.Boolean);
            cg.EmitConvert(Right, cg.CoreTypes.Boolean);
            cg.EmitOpCode(ILOpCode.Ceq);

            cg.EmitOpCode(ILOpCode.Ldc_i4_0);
            cg.EmitOpCode(ILOpCode.Ceq);

            return cg.CoreTypes.Boolean;
        }
コード例 #32
0
ファイル: BoundExpression.cs プロジェクト: iolevel/peachpie
        internal override TypeSymbol EmitCallsiteCall(CodeGenerator cg)
        {
            if (_name.IsDirect)
            {
                return base.EmitCallsiteCall(cg);
            }
            else
            {
                Debug.Assert(_name.NameExpression != null);

                // faster to emit PhpCallback.Invoke

                // NameExpression.AsCallback().Invoke(Context, PhpValue[])

                cg.EmitConvert(_name.NameExpression, cg.CoreTypes.IPhpCallable);    // (IPhpCallable)Name
                cg.EmitLoadContext();       // Context
                cg.Emit_NewArray(cg.CoreTypes.PhpValue, _arguments.Select(a => a.Value).ToArray()); // PhpValue[]

                return cg.EmitCall(ILOpCode.Callvirt, cg.CoreTypes.IPhpCallable.Symbol.LookupMember<MethodSymbol>("Invoke"));
            }
        }
コード例 #33
0
ファイル: BoundExpression.cs プロジェクト: iolevel/peachpie
        TypeSymbol EmitBitNot(CodeGenerator cg)
        {
            var il = cg.Builder;
            var t = cg.Emit(this.Operand);

            switch (t.SpecialType)
            {
                case SpecialType.System_Double:
                case SpecialType.System_Int32:
                    // r8|i4 -> i8
                    il.EmitOpCode(ILOpCode.Conv_i8);
                    goto case SpecialType.System_Int64;

                case SpecialType.System_Int64:
                    il.EmitOpCode(ILOpCode.Not);    // ~i64 : i64
                    return cg.CoreTypes.Long;

                case SpecialType.System_Boolean:
                    throw new NotImplementedException();    // Err
                default:
                    if (t == cg.CoreTypes.PhpArray)
                    {
                        // ERR
                    }

                    // ~ PhpValue
                    cg.EmitConvert(t, Operand.TypeRefMask, cg.CoreTypes.PhpValue);
                    return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.BitwiseNot_PhpValue);
            }
        }
コード例 #34
0
ファイル: Places.cs プロジェクト: iolevel/peachpie
        /// <summary>
        /// Emits name as string, uses cached variable.
        /// </summary>
        void EmitName(CodeGenerator cg, BoundExpression name)
        {
            Contract.ThrowIfNull(cg);
            Contract.ThrowIfNull(name);

            if (_name_loc != null)
            {
                cg.Builder.EmitLocalLoad(_name_loc);
            }
            else
            {
                _cg = cg;

                // return (<loc> = <name>)
                _name_loc = cg.GetTemporaryLocal(cg.CoreTypes.String);
                cg.EmitConvert(name, cg.CoreTypes.String);
                cg.Builder.EmitOpCode(ILOpCode.Dup);
                cg.Builder.EmitLocalStore(_name_loc);
            }
        }