private void emitPushArgument(Class ptype, object arg) { BasicType bptype = BasicType.basicType(ptype); if (arg is Name) { Name n = (Name)arg; emitLoadInsn(n._type(), n.index()); emitImplicitConversion(n._type(), ptype, n); } else if ((arg == null || arg is string) && bptype == BasicType.L_TYPE) { emitConst(arg); } else { if (Wrapper.isWrapperType(ikvm.extensions.ExtensionMethods.getClass(arg)) && bptype != BasicType.L_TYPE) { emitConst(arg); } else { EmitConstant(arg); emitImplicitConversion(BasicType.L_TYPE, ptype, arg); } } }
/** * Store the name to its local, if necessary. */ private void emitStoreResult(Name name) { if (name != null && name._type() != BasicType.V_TYPE) { // non-void: actually assign emitStoreInsn(name._type(), name.index()); } }
/** * Emit bytecode for the selectAlternative idiom. * * The pattern looks like (Cf. MethodHandleImpl.makeGuardWithTest): * <blockquote><pre>{@code * Lambda(a0:L,a1:I)=>{ * t2:I=foo.test(a1:I); * t3:L=MethodHandleImpl.selectAlternative(t2:I,(MethodHandle(int)int),(MethodHandle(int)int)); * t4:I=MethodHandle.invokeBasic(t3:L,a1:I);t4:I} * }</pre></blockquote> */ private Name emitSelectAlternative(Name selectAlternativeName, Name invokeBasicName) { //assert isStaticallyInvocable(invokeBasicName); Name receiver = (Name)invokeBasicName.arguments[0]; CodeEmitterLabel L_fallback = ilgen.DefineLabel(); CodeEmitterLabel L_done = ilgen.DefineLabel(); // load test result emitPushArgument(selectAlternativeName, 0); // if_icmpne L_fallback ilgen.EmitBrfalse(L_fallback); // invoke selectAlternativeName.arguments[1] //Class<?>[] preForkClasses = localClasses.clone(); emitPushArgument(selectAlternativeName, 1); // get 2nd argument of selectAlternative emitAstoreInsn(receiver.index()); // store the MH in the receiver slot emitStaticInvoke(invokeBasicName); // goto L_done ilgen.EmitBr(L_done); // L_fallback: ilgen.MarkLabel(L_fallback); // invoke selectAlternativeName.arguments[2] //System.arraycopy(preForkClasses, 0, localClasses, 0, preForkClasses.length); emitPushArgument(selectAlternativeName, 2); // get 3rd argument of selectAlternative emitAstoreInsn(receiver.index()); // store the MH in the receiver slot emitStaticInvoke(invokeBasicName); // L_done: ilgen.MarkLabel(L_done); // for now do not bother to merge typestate; just reset to the dominator state //System.arraycopy(preForkClasses, 0, localClasses, 0, preForkClasses.length); return(invokeBasicName); // return what's on stack }
private NativeInvokerBytecodeGenerator(LambdaForm lambdaForm, MethodType invokerType) { if (invokerType != invokerType.basicType()) { throw new BailoutException(Bailout.NotBasicType, invokerType); } this.lambdaForm = lambdaForm; this.invokerType = invokerType; this.delegateType = MethodHandleUtil.GetMemberWrapperDelegateType(invokerType); MethodInfo mi = MethodHandleUtil.GetDelegateInvokeMethod(delegateType); Type[] paramTypes = MethodHandleUtil.GetParameterTypes(typeof(object[]), mi); // HACK the code we generate is not verifiable (known issue: locals aren't typed correctly), so we stick the DynamicMethod into mscorlib (a security critical assembly) this.dm = new DynamicMethod(lambdaForm.debugName, mi.ReturnType, paramTypes, typeof(object).Module, true); this.ilgen = CodeEmitter.Create(this.dm); if (invokerType.parameterCount() > MethodHandleUtil.MaxArity) { this.packedArgType = paramTypes[paramTypes.Length - 1]; this.packedArgPos = paramTypes.Length - 1; } else { this.packedArgPos = Int32.MaxValue; } locals = new CodeEmitterLocal[lambdaForm.names.Length]; for (int i = lambdaForm._arity(); i < lambdaForm.names.Length; i++) { Name name = lambdaForm.names[i]; if (name.index() != i) { throw new BailoutException(Bailout.PreconditionViolated, "name.index() != i"); } switch (name.typeChar()) { case 'L': locals[i] = ilgen.DeclareLocal(Types.Object); break; case 'I': locals[i] = ilgen.DeclareLocal(Types.Int32); break; case 'J': locals[i] = ilgen.DeclareLocal(Types.Int64); break; case 'F': locals[i] = ilgen.DeclareLocal(Types.Single); break; case 'D': locals[i] = ilgen.DeclareLocal(Types.Double); break; case 'V': break; default: throw new BailoutException(Bailout.PreconditionViolated, "Unsupported typeChar(): " + name.typeChar()); } } }