Ejemplo n.º 1
0
        /// <summary>
        /// Returns a handle to a helper function for creating a new Object instance from the
        /// keys and values on the stack. This is used for the newobject ABC instruction. The keys
        /// must be of the String type and the values must be of the "any" type.
        /// </summary>
        /// <param name="size">The size argument to the newarray instruction, i.e. the number of
        /// key-value pairs on the stack.</param>
        /// <param name="handle">If a helper function is available or can be emitted, a handle to
        /// the function is set to this argument.</param>
        /// <returns>True if a helper function is available or can be created, otherwise false.</returns>
        public bool tryGetNewObjectHelper(int size, out EntityHandle handle)
        {
            handle = default;

            if (size > newObjectHelperMaxSize)
            {
                return(false);
            }

            if (m_newObjectHelperMethods[size] != null)
            {
                handle = m_newObjectHelperMethods[size].handle;
                return(true);
            }

            _createContainerTypeIfNotCreated();

            TypeSignature[] parameterTypes = new TypeSignature[size * 2];

            var typeSigForString = TypeSignature.forPrimitiveType(PrimitiveTypeCode.String);
            var typeSigForAny    = m_assemblyBuilder.metadataContext.getTypeSignature(typeof(ASAny));

            for (int i = 0; i < parameterTypes.Length; i++)
            {
                parameterTypes[i] = ((i & 1) == 0) ? typeSigForString : typeSigForAny;
            }

            string methodName = "newobject" + size.ToString(CultureInfo.InvariantCulture);

            var methodBuilder = m_containerType !.defineMethod(
                methodName,
                MethodAttributes.Public | MethodAttributes.Static,
                m_assemblyBuilder.metadataContext.getTypeSignature(typeof(ASObject)),
                parameterTypes
                );

            m_ilBuilder.reset();

            var objLocal = m_ilBuilder.declareLocal(typeof(ASObject));
            var dpLocal  = m_ilBuilder.declareLocal(typeof(DynamicPropertyCollection));

            m_ilBuilder.emit(ILOp.newobj, KnownMembers.objectCtor);
            m_ilBuilder.emit(ILOp.dup);
            m_ilBuilder.emit(ILOp.call, KnownMembers.getObjectDynamicPropCollection, 0);
            m_ilBuilder.emit(ILOp.stloc, dpLocal);
            m_ilBuilder.emit(ILOp.stloc, objLocal);

            // Object properties are set in top-to-bottom stack order.
            // So for example if the arguments are "a", 1, "b", 2, "a", 3 then the value of the property
            // "a" in the created object is 1, not 3.

            for (int i = size - 1; i >= 0; i--)
            {
                m_ilBuilder.emit(ILOp.ldloc, dpLocal);
                m_ilBuilder.emit(ILOp.ldarg, 2 * i);
                m_ilBuilder.emit(ILOp.ldarg, 2 * i + 1);
                m_ilBuilder.emit(ILOp.ldc_i4_1);    // isEnum = true
                m_ilBuilder.emit(ILOp.call, KnownMembers.dynamicPropCollectionSet, -4);
            }

            m_ilBuilder.emit(ILOp.ldloc, objLocal);
            m_ilBuilder.emit(ILOp.ret);

            methodBuilder.setMethodBody(m_ilBuilder.createMethodBody());

            m_newObjectHelperMethods[size] = methodBuilder;
            handle = methodBuilder.handle;

            return(true);
        }