Helper object emitting value of a member instance. Used to avoid repetitious evaluation of the instance in case of BoundCompoundAssignEx or Increment/Decrement.
Inheritance: IDisposable
Beispiel #1
0
        private void EmitPrepare(CodeGenerator cg, InstanceCacheHolder instanceOpt = null)
        {
            // Template: <variables> Key

            LoadVariablesArray(cg);

            // key
            cg.EmitIntStringKey(_nameExpr);
        }
Beispiel #2
0
        public TypeSymbol TypeOpt => null;  // PhpArray

        public void EmitLoadPrepare(CodeGenerator cg, InstanceCacheHolder instanceOpt = null)
        {
            // nothing
        }
Beispiel #3
0
 public void EmitStorePrepare(CodeGenerator cg, InstanceCacheHolder instanceOpt = null)
 {
     // Context
     cg.EmitLoadContext();
 }
Beispiel #4
0
        void IBoundReference.EmitLoadPrepare(CodeGenerator cg, InstanceCacheHolder instanceOpt)
        {
            // Template: array[index]

            EmitArrayPrepare(cg, instanceOpt);

            if (this.Index == null)
                throw new ArgumentException();

            cg.EmitIntStringKey(this.Index);    // TODO: save Index into InstanceCacheHolder
        }
Beispiel #5
0
        /// <summary>
        /// Emits instance of the field containing class.
        /// </summary>
        protected virtual void EmitLoadFieldInstance(CodeGenerator cg, InstanceCacheHolder instanceOpt)
        {
            // instance
            var instancetype = InstanceCacheHolder.EmitInstance(instanceOpt, cg, Instance);

            //
            if (Field.IsStatic && Instance != null)
                cg.EmitPop(instancetype);
            else if (!Field.IsStatic && Instance == null)
                throw new NotImplementedException();
        }
Beispiel #6
0
 void IBoundReference.EmitStorePrepare(CodeGenerator cg, InstanceCacheHolder instanceOpt)
 {
     // nop
 }
Beispiel #7
0
        internal override TypeSymbol Emit(CodeGenerator cg)
        {
            Debug.Assert(this.Access.IsNone || Access.IsRead);
            Debug.Assert(!this.Access.IsReadRef);
            Debug.Assert(!this.Access.IsWrite);
            Debug.Assert(this.Target.Access.IsRead && this.Target.Access.IsWrite);
            Debug.Assert(this.Value.Access.IsRead);

            Debug.Assert(this.Value is BoundLiteral);

            if (this.UsesOperatorMethod)
            {
                throw new NotImplementedException();
            }

            TypeSymbol result_type = cg.CoreTypes.Void;
            LocalDefinition postfix_temp = null;

            var read = this.Access.IsRead;

            var target_place = this.Target.BindPlace(cg);
            Debug.Assert(target_place != null);

            using (var instance_holder = new InstanceCacheHolder())
            {

                // prepare target for store operation
                target_place.EmitStorePrepare(cg, instance_holder);

                // load target value
                target_place.EmitLoadPrepare(cg, instance_holder);
            }

            var target_load_type = target_place.EmitLoad(cg);

            TypeSymbol op_type;

            if (read && IsPostfix)
            {
                // store original value of target
                // <temp> = TARGET
                postfix_temp = cg.GetTemporaryLocal(target_load_type);
                cg.EmitOpCode(ILOpCode.Dup);
                cg.Builder.EmitLocalStore(postfix_temp);
            }

            if (IsIncrement)
            {
                op_type = BoundBinaryEx.EmitAdd(cg, target_load_type, this.Value, target_place.TypeOpt);
            }
            else
            {
                Debug.Assert(IsDecrement);
                op_type = BoundBinaryEx.EmitSub(cg, target_load_type, this.Value, target_place.TypeOpt);
            }

            if (read)
            {
                if (IsPostfix)
                {
                    // READ <temp>
                    cg.Builder.EmitLocalLoad(postfix_temp);
                    result_type = target_load_type;

                    //
                    cg.ReturnTemporaryLocal(postfix_temp);
                    postfix_temp = null;
                }
                else
                {
                    // dup resulting value
                    // READ (++TARGET OR --TARGET)
                    cg.Builder.EmitOpCode(ILOpCode.Dup);
                    result_type = op_type;
                }
            }

            //
            target_place.EmitStore(cg, op_type);

            Debug.Assert(postfix_temp == null);
            Debug.Assert(!read || result_type.SpecialType != SpecialType.System_Void);

            //
            return result_type;
        }
Beispiel #8
0
        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);

            _type.EmitLoadTypeInfo(cg);
        }
Beispiel #9
0
 /// <summary>
 /// Emits instance. Caches the result if holder is provided, or loads evaluated instance if holder was initialized already.
 /// </summary>
 public static TypeSymbol EmitInstance(InstanceCacheHolder holderOrNull, CodeGenerator cg, BoundExpression instance)
 {
     return (instance != null) ? EmitInstance(holderOrNull, cg, () => cg.Emit(instance)) : null;
 }
Beispiel #10
0
        public void EmitLoadPrepare(CodeGenerator cg, InstanceCacheHolder instanceOpt = null)
        {
            if (_lazyLoadCallSite == null)
                _lazyLoadCallSite = cg.Factory.StartCallSite("get_" + this.NameValueOpt);

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

            // instance
            InstanceCacheHolder.EmitInstance(instanceOpt, cg, Instance);
        }
Beispiel #11
0
        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);
            }
        }
Beispiel #12
0
        protected override void EmitLoadFieldInstance(CodeGenerator cg, InstanceCacheHolder instanceOpt)
        {
            // Template: <ctx>.GetStatics<_statics>().Field
            var statics = InstanceCacheHolder.EmitInstance(instanceOpt, cg,
                () => this.Field.ContainingType.EmitLoadStatics(cg));

            if (statics == null)
                throw new InvalidOperationException();
        }
Beispiel #13
0
        public void EmitStorePrepare(CodeGenerator cg, InstanceCacheHolder instanceOpt)
        {
            Debug.Assert(Access.IsWrite);

            EmitLoadFieldInstance(cg, instanceOpt);

            //
            var type = Field.Type;

            if (Access.IsWriteRef)
            {
                // no need for preparation
            }
            else
            {
                //
                if (type == cg.CoreTypes.PhpAlias)
                {
                    // (PhpAlias)<place>
                    EmitOpCode_Load(cg);    // PhpAlias
                }
                else if (type == cg.CoreTypes.PhpValue)
                {
                    EmitOpCode_LoadAddress(cg); // &PhpValue
                }
                else
                {
                    // no need for preparation
                }
            }
        }
Beispiel #14
0
 public void EmitLoadPrepare(CodeGenerator cg, InstanceCacheHolder instanceOpt)
 {
     EmitLoadFieldInstance(cg, instanceOpt);
 }
Beispiel #15
0
 public void EmitStorePrepare(CodeGenerator cg, InstanceCacheHolder instanceOpt = null)
 {
     EmitPrepare(cg, instanceOpt);
 }
Beispiel #16
0
 public static TypeSymbol EmitInstance(InstanceCacheHolder holderOrNull, CodeGenerator cg, Func<TypeSymbol> emitter)
 {
     if (holderOrNull != null)
     {
         return holderOrNull.EmitInstance(cg, emitter);
     }
     else
     {
         return emitter();
     }
 }
Beispiel #17
0
 void IBoundReference.EmitLoadPrepare(CodeGenerator cg, InstanceCacheHolder instanceOpt)
 {
     throw new InvalidOperationException();
 }
Beispiel #18
0
        /// <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);
            }
        }
Beispiel #19
0
        internal override TypeSymbol Emit(CodeGenerator cg)
        {
            Debug.Assert(Access.IsRead || Access.IsNone);

            // target X= value;

            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);

            // helper class maintaining reference to already evaluated instance of the eventual chain
            using (var instance_holder = new InstanceCacheHolder())
            {
                // <target> = <target> X <value>
                target_place.EmitStorePrepare(cg, instance_holder);

                //
                target_place.EmitLoadPrepare(cg, instance_holder);
            }

            var xtype = target_place.EmitLoad(cg);  // type of left value operand

            TypeSymbol result_type;

            switch (this.Operation)
            {
                case Operations.AssignAdd:
                    result_type = BoundBinaryEx.EmitAdd(cg, xtype, Value, target_place.TypeOpt);
                    break;
                //case Operations.AssignAnd:
                //    binaryop = Operations.And;
                //    break;
                case Operations.AssignAppend:
                    result_type = EmitAppend(cg, xtype, Value);
                    break;
                ////case Operations.AssignPrepend:
                ////    break;
                case Operations.AssignDiv:
                    result_type = BoundBinaryEx.EmitDiv(cg, xtype, Value, target_place.TypeOpt);
                    break;
                //case Operations.AssignMod:
                //    binaryop = Operations.Mod;
                //    break;
                case Operations.AssignMul:
                    result_type = BoundBinaryEx.EmitMul(cg, xtype, Value, target_place.TypeOpt);
                    break;
                //case Operations.AssignOr:
                //    binaryop = Operations.Or;
                //    break;
                case Operations.AssignPow:
                    result_type = BoundBinaryEx.EmitPow(cg, xtype, /*this.Target.TypeRefMask*/0, Value);
                    break;
                //case Operations.AssignShiftLeft:
                //    binaryop = Operations.ShiftLeft;
                //    break;
                //case Operations.AssignShiftRight:
                //    binaryop = Operations.ShiftRight;
                //    break;
                case Operations.AssignSub:
                    result_type = BoundBinaryEx.EmitSub(cg, xtype, Value, target_place.TypeOpt);
                    break;
                //case Operations.AssignXor:
                //    binaryop = Operations.Xor;
                //    break;
                default:
                    throw ExceptionUtilities.UnexpectedValue(this.Operation);
            }

            LocalDefinition tmp = null;

            switch (this.Access.Flags)
            {
                case AccessMask.Read:
                    tmp = cg.GetTemporaryLocal(result_type, 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, result_type);

            //
            switch (this.Access.Flags)
            {
                case AccessMask.None:
                    return cg.CoreTypes.Void;
                case AccessMask.Read:
                    Debug.Assert(tmp != null);
                    cg.Builder.EmitLoad(tmp);
                    cg.ReturnTemporaryLocal(tmp);
                    return result_type;
                default:
                    throw ExceptionUtilities.UnexpectedValue(this.Access);
            }
        }
Beispiel #20
0
 public void EmitLoadPrepare(CodeGenerator cg, InstanceCacheHolder instanceOpt) { }
Beispiel #21
0
        void EmitArrayPrepare(CodeGenerator cg, InstanceCacheHolder instanceOpt)
        {
            InstanceCacheHolder.EmitInstance(instanceOpt, cg, Array);

            if (Array.ResultType.IsOfType(cg.CoreTypes.IPhpArray))
            {
                // ok
            }
            else if (Array.ResultType == cg.CoreTypes.PhpValue)
            {
                // Convert.ToArray()
                cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.ToArray_PhpValue);
            }
            else if (Array.ResultType == cg.CoreTypes.String)
            {
                // new PhpString(string)
                cg.EmitCall(ILOpCode.Newobj, cg.CoreMethods.Ctors.PhpString_string);
            }
            else if (Array.ResultType == cg.CoreTypes.Void)
            {
                // TODO: uninitialized value, report error
                Debug.WriteLine("Use of uninitialized value.");
                cg.EmitCall(ILOpCode.Newobj, cg.CoreMethods.Ctors.PhpString);
            }
            else
            {
                throw new NotImplementedException();    // TODO: emit convert as PhpArray
            }
        }
Beispiel #22
0
        public void EmitStorePrepare(CodeGenerator cg, InstanceCacheHolder instanceOpt)
        {
            var type = _place.TypeOpt;

            if (_access.IsWriteRef)
            {
                // no need for preparation
                _place.EmitStorePrepare(cg.Builder);
            }
            else
            {
                //
                if (type == cg.CoreTypes.PhpAlias)
                {
                    // (PhpAlias)<place>
                    _place.EmitLoad(cg.Builder);
                }
                else if (type == cg.CoreTypes.PhpValue)
                {
                    if (_thint.IsRef)
                    {
                        // Operators.SetValue(ref <place>, (PhpValue)<value>);
                        _place.EmitLoadAddress(cg.Builder);
                    }
                    else
                    {
                        _place.EmitStorePrepare(cg.Builder);
                    }
                }
                else
                {
                    // no need for preparation
                    _place.EmitStorePrepare(cg.Builder);
                }
            }
        }
Beispiel #23
0
        void IBoundReference.EmitStorePrepare(CodeGenerator cg, InstanceCacheHolder instanceOpt)
        {
            // Template: array[index]

            EmitArrayPrepare(cg, instanceOpt);

            if (this.Index != null)
            {
                cg.EmitIntStringKey(this.Index);    // TODO: save Index into InstanceCacheHolder
            }
        }
Beispiel #24
0
        public void EmitStorePrepare(CodeGenerator cg, InstanceCacheHolder instanceOpt)
        {
            if (_property == null)
            {
                // TODO: callsite.Target callsite
                throw new NotImplementedException();
            }

            InstanceCacheHolder.EmitInstance(instanceOpt, cg, _instance);
        }