Ejemplo n.º 1
0
        /// <summary>
        /// Generate the code to push one parameter onto the caller stack. There are
        /// three different approaches here:
        /// 
        /// 1. Passing a defined variable. We either pass the address of the
        ///    variable (which may be local, parameter or static) if the corresponding
        ///    argument is BYREF, or we pass the value.
        /// 2. Passing a computed value. A computed value has no storage so if the
        ///    corresponding argument is BYREF, we need to allocate storage for it
        ///    and pass the address of the storage.
        /// 3. Finally, a computed value where the argument is BYVAL is passed on
        ///    the stack.
        /// 
        /// </summary>
        /// <param name="cg">A CodeGenerator object</param>
        /// <param name="symParam">Symbol entry for the called function</param>
        /// <param name="locals">A Temporaries collection for any local temporaries</param>
        /// <returns>The system type corresponding to this parameter.</returns>
        public Type Generate(CodeGenerator cg, Symbol symParam, Temporaries locals)
        {
            if (cg == null) {
                throw new ArgumentNullException("cg");
            }
            if (locals == null) {
                throw new ArgumentNullException("locals");
            }

            // Set some flags up-front
            bool isByRef = (symParam != null) ? symParam.IsByRef : IsByRef;
            bool isArray = (symParam != null) && symParam.IsArray;

            // The argument is an array, so the source must either be an array or
            // an array reference.
            if (isArray && _paramNode.ID == ParseID.IDENT) {
                IdentifierParseNode identNode = (IdentifierParseNode)_paramNode;
                Symbol symIdent = identNode.Symbol;
                if (symIdent.IsArray) {
                    GenerateLoadSubArray(cg, identNode, symParam, locals);
                    return symIdent.SystemType;
                }
            }

            // Parameter is an identifier. If passing by reference, pass the address
            // of the identifier in the local context. Otherwise extract and pass the
            // value.
            if (_paramNode.ID == ParseID.IDENT) {
                IdentifierParseNode identNode = (IdentifierParseNode)_paramNode;
                SymType identType = identNode.Type;
                Symbol symIdent = identNode.Symbol;

                if (!symIdent.IsInline && !identNode.HasSubstring) {
                    // If we're passing an existing parameter, it is already
                    // a reference so don't double it up.
                    if (symIdent.IsParameter) {
                        cg.Emitter.LoadParameter(symIdent.ParameterIndex);
                        if (!isByRef && symIdent.IsValueType) {
                            cg.Emitter.LoadIndirect(identType);
                        }
                    } else {
                        if (symIdent.IsArray && !identNode.HasIndexes) {
                            cg.GenerateLoadArray(identNode, false);
                            return symIdent.SystemType;
                        }
                        if (isByRef) {
                            cg.LoadAddress(identNode);
                        } else {
                            identNode.Generate(cg);
                            if (symParam != null) {
                                if (!symParam.IsMethod) {
                                    cg.Emitter.ConvertType(identNode.Type, symParam.Type);
                                }
                                identType = symParam.Type;
                            }
                        }
                    }
                    Type paramType = Symbol.SymTypeToSystemType(identType);
                    if (isByRef) {
                        paramType = paramType.MakeByRefType();
                    }
                    return paramType;
                }
            }

            // For reference function parameters, if this argument is not an
            // addressable object, such as a literal value or an expression,
            // then we need to generate local storage for the result and pass
            // the address of that.
            if (isByRef) {
                LocalDescriptor index = locals.New(_paramNode.Type);

                SymType exprType = cg.GenerateExpression(_paramNode.Type, _paramNode);
                cg.Emitter.StoreLocal(index);
                cg.Emitter.LoadLocalAddress(index);
                return Symbol.SymTypeToSystemType(exprType).MakeByRefType();
            }

            // Byval argument passing
            SymType neededType = (symParam != null) ? symParam.Type : Type;
            SymType thisType = cg.GenerateExpression(neededType, _paramNode);
            if (symParam != null) {
                thisType = symParam.Type;
            }
            return Symbol.SymTypeToSystemType(thisType);
        }