/**
     * Emit an implicit conversion for an argument which must be of the given pclass.
     * This is usually a no-op, except when pclass is a subword type or a reference other than Object or an interface.
     *
     * @param ptype type of value present on stack
     * @param pclass type of value required on stack
     * @param arg compile-time representation of value on stack (Node, constant) or null if none
     */
    private void emitImplicitConversion(BasicType ptype, Class pclass, object arg)
    {
        //assert(basicType(pclass) == ptype);  // boxing/unboxing handled by caller
        if (pclass == ptype.basicTypeClass() && ptype != BasicType.L_TYPE)
        {
            return;   // nothing to do
        }
        switch (ptype.name())
        {
        case "L_TYPE":
            if (VerifyType.isNullConversion(CoreClasses.java.lang.Object.Wrapper.ClassObject, pclass, false))
            {
                //if (PROFILE_LEVEL > 0)
                //    emitReferenceCast(Object.class, arg);
                return;
            }
            emitReferenceCast(pclass, arg);
            return;

        case "I_TYPE":
            if (!VerifyType.isNullConversion(java.lang.Integer.TYPE, pclass, false))
            {
                emitPrimCast(ptype.basicTypeWrapper(), Wrapper.forPrimitiveType(pclass));
            }
            return;
        }
        throw new BailoutException(Bailout.PreconditionViolated, "bad implicit conversion: tc=" + ptype + ": " + pclass);
    }
    void emitNewArray(Name name)
    {
        Class rtype = name.function.methodType().returnType();

        if (name.arguments.Length == 0)
        {
            // The array will be a constant.
            object emptyArray;
            try {
                emptyArray = name.function._resolvedHandle().invoke();
            } catch (Exception ex) {
                throw new java.lang.InternalError(ex);
            }
            //assert(java.lang.reflect.Array.getLength(emptyArray) == 0);
            //assert(emptyArray.getClass() == rtype);  // exact typing
            //mv.visitLdcInsn(constantPlaceholder(emptyArray));
            EmitConstant(emptyArray);
            emitReferenceCast(rtype, emptyArray);
            return;
        }
        Class arrayElementType = rtype.getComponentType();

        //assert(arrayElementType != null);
        emitIconstInsn(name.arguments.Length);
        OpCode xas = OpCodes.Stelem_Ref;

        if (!arrayElementType.isPrimitive())
        {
            TypeWrapper tw = TypeWrapper.FromClass(arrayElementType);
            if (tw.IsUnloadable || tw.IsGhost || tw.IsGhostArray || tw.IsNonPrimitiveValueType)
            {
                throw new BailoutException(Bailout.UnsupportedArrayType, tw);
            }
            ilgen.Emit(OpCodes.Newarr, tw.TypeAsArrayType);
        }
        else
        {
            byte tc = arrayTypeCode(Wrapper.forPrimitiveType(arrayElementType));
            xas = arrayInsnOpcode(tc);
            //mv.visitIntInsn(Opcodes.NEWARRAY, tc);
            ilgen.Emit(OpCodes.Newarr, TypeWrapper.FromClass(arrayElementType).TypeAsArrayType);
        }
        // store arguments
        for (int i = 0; i < name.arguments.Length; i++)
        {
            //mv.visitInsn(Opcodes.DUP);
            ilgen.Emit(OpCodes.Dup);
            emitIconstInsn(i);
            emitPushArgument(name, i);
            //mv.visitInsn(xas);
            ilgen.Emit(xas);
        }
        // the array is left on the stack
        assertStaticType(rtype, name);
    }
    void emitArrayLoad(Name name)
    {
        OpCode arrayOpcode = OpCodes.Ldelem_Ref;
        Class  elementType = name.function.methodType().parameterType(0).getComponentType();

        emitPushArguments(name);
        if (elementType.isPrimitive())
        {
            Wrapper w = Wrapper.forPrimitiveType(elementType);
            arrayOpcode = arrayLoadOpcode(arrayTypeCode(w));
        }
        ilgen.Emit(arrayOpcode);
    }