private boolean generateBody()

in boot/src/main/java/org/netbeans/html/boot/impl/FnUtils.java [200:479]


            private boolean generateBody(boolean hasCode) {
                if (bodyGenerated) {
                    return false;
                }
                bodyGenerated = true;
                if (mv != null) {
                    AnnotationVisitor va = super.visitAnnotation("Lnet/java/html/js/JavaScriptBody;", false);
                    AnnotationVisitor varr = va.visitArray("args");
                    for (String argName : fia.args) {
                        varr.visit(null, argName);
                    }
                    varr.visitEnd();
                    va.visit("body", fia.body);
                    if (fia.javacall != null) {
                        va.visit("javacall", fia.javacall);
                    }
                    if (fia.wait4js != null) {
                        va.visit("wait4js", fia.wait4js);
                    }
                    if (fia.wait4java != null) {
                        va.visit("wait4java", fia.wait4java);
                    }
                    if (fia.keepAlive != null) {
                        va.visit("keepAlive", fia.keepAlive);
                    }
                    va.visitEnd();
                }
                
                String body;
                List<String> args;
                if ((fia.javacall())) {
                    body = callback(fia.body, fia.usePromise());
                    args = new ArrayList<>(fia.args);
                    args.add("vm");
                } else {
                    body = fia.body;
                    args = fia.args;
                }

                super.visitFieldInsn(
                        Opcodes.GETSTATIC, FindInClass.this.name,
                        "$$fn$$" + name + "_" + found,
                        "Lorg/netbeans/html/boot/spi/Fn;"
                );
                super.visitInsn(Opcodes.DUP);
                super.visitMethodInsn(
                        Opcodes.INVOKESTATIC,
                        "org/netbeans/html/boot/spi/Fn", "isValid",
                        "(Lorg/netbeans/html/boot/spi/Fn;)Z"
                );
                Label ifNotNull = new Label();
                super.visitJumpInsn(Opcodes.IFNE, ifNotNull);

                // init Fn
                super.visitInsn(Opcodes.POP);
                super.visitLdcInsn(Type.getObjectType(FindInClass.this.name));
                super.visitInsn(fia.keepAlive() ? Opcodes.ICONST_1 : Opcodes.ICONST_0);
                super.visitLdcInsn(body);
                super.visitIntInsn(Opcodes.SIPUSH, args.size());
                super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/String");
                boolean needsVM = false;
                for (int i = 0; i < args.size(); i++) {
                    assert !needsVM;
                    String argName = args.get(i);
                    needsVM = "vm".equals(argName);
                    super.visitInsn(Opcodes.DUP);
                    super.visitIntInsn(Opcodes.BIPUSH, i);
                    super.visitLdcInsn(argName);
                    super.visitInsn(Opcodes.AASTORE);
                }
                super.visitMethodInsn(Opcodes.INVOKESTATIC,
                        "org/netbeans/html/boot/spi/Fn", "define",
                        "(Ljava/lang/Class;ZLjava/lang/String;[Ljava/lang/String;)Lorg/netbeans/html/boot/spi/Fn;"
                );
                Label noPresenter = new Label();
                super.visitInsn(Opcodes.DUP);
                super.visitJumpInsn(Opcodes.IFNULL, noPresenter);
                int cnt = resourcesCnt;
                while (cnt > 0) {
                    String resource = resources[--cnt];
                    if (resource == null) {
                        continue;
                    }
                    super.visitLdcInsn(Type.getObjectType(FindInClass.this.name));
                    super.visitLdcInsn(resource);
                    super.visitMethodInsn(Opcodes.INVOKESTATIC,
                            "org/netbeans/html/boot/spi/Fn", "preload",
                            "(Lorg/netbeans/html/boot/spi/Fn;Ljava/lang/Class;Ljava/lang/String;)Lorg/netbeans/html/boot/spi/Fn;"
                    );
                }
                super.visitInsn(Opcodes.DUP);
                super.visitFieldInsn(
                        Opcodes.PUTSTATIC, FindInClass.this.name,
                        "$$fn$$" + name + "_" + found,
                        "Lorg/netbeans/html/boot/spi/Fn;"
                );
                // end of Fn init

                super.visitLabel(ifNotNull);

                final int offset;
                if ((access & Opcodes.ACC_STATIC) == 0) {
                    offset = 1;
                    super.visitIntInsn(Opcodes.ALOAD, 0);
                } else {
                    offset = 0;
                    super.visitInsn(Opcodes.ACONST_NULL);
                }

                super.visitIntInsn(Opcodes.SIPUSH, args.size());
                super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");

                class SV extends SignatureVisitor {

                    private boolean nowReturn;
                    private Type returnType;
                    private int index;
                    private int loadIndex = offset;

                    public SV() {
                        super(Opcodes.ASM5);
                    }

                    @Override
                    public void visitBaseType(char descriptor) {
                        final Type t = Type.getType("" + descriptor);
                        if (nowReturn) {
                            returnType = t;
                            return;
                        }
                        FindInMethod.super.visitInsn(Opcodes.DUP);
                        FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, index++);
                        FindInMethod.super.visitVarInsn(t.getOpcode(Opcodes.ILOAD), loadIndex++);
                        String factory;
                        switch (descriptor) {
                            case 'I':
                                factory = "java/lang/Integer";
                                break;
                            case 'J':
                                factory = "java/lang/Long";
                                loadIndex++;
                                break;
                            case 'S':
                                factory = "java/lang/Short";
                                break;
                            case 'F':
                                factory = "java/lang/Float";
                                break;
                            case 'D':
                                factory = "java/lang/Double";
                                loadIndex++;
                                break;
                            case 'Z':
                                factory = "java/lang/Boolean";
                                break;
                            case 'C':
                                factory = "java/lang/Character";
                                break;
                            case 'B':
                                factory = "java/lang/Byte";
                                break;
                            default:
                                throw new IllegalStateException(t.toString());
                        }
                        FindInMethod.super.visitMethodInsn(Opcodes.INVOKESTATIC,
                                factory, "valueOf", "(" + descriptor + ")L" + factory + ";"
                        );
                        FindInMethod.super.visitInsn(Opcodes.AASTORE);
                    }

                    @Override
                    public SignatureVisitor visitArrayType() {
                        if (nowReturn) {
                            return new SignatureVisitor(Opcodes.ASM5) {
                                @Override
                                public void visitClassType(String name) {
                                    returnType = Type.getType("[" + Type.getObjectType(name).getDescriptor());
                                }

                                @Override
                                public void visitBaseType(char descriptor) {
                                    returnType = Type.getType("[" + descriptor);
                                }
                            };
                        }
                        loadObject();
                        return new SignatureWriter();
                    }

                    @Override
                    public void visitClassType(String name) {
                        if (nowReturn) {
                            returnType = Type.getObjectType(name);
                            return;
                        }
                        loadObject();
                    }

                    @Override
                    public SignatureVisitor visitReturnType() {
                        nowReturn = true;
                        return this;
                    }

                    private void loadObject() {
                        FindInMethod.super.visitInsn(Opcodes.DUP);
                        FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, index++);
                        FindInMethod.super.visitVarInsn(Opcodes.ALOAD, loadIndex++);
                        FindInMethod.super.visitInsn(Opcodes.AASTORE);
                    }

                }
                SV sv = new SV();
                SignatureReader sr = new SignatureReader(desc);
                sr.accept(sv);

                if (needsVM) {
                    FindInMethod.super.visitInsn(Opcodes.DUP);
                    FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, sv.index);
                    int lastSlash = FindInClass.this.name.lastIndexOf('/');
                    String jsCallbacks = FindInClass.this.name.substring(0, lastSlash + 1) + "$JsCallbacks$";
                    FindInMethod.super.visitFieldInsn(Opcodes.GETSTATIC, jsCallbacks, "VM", "L" + jsCallbacks + ";");
                    FindInMethod.super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, jsCallbacks, "current", "()L" + jsCallbacks + ";");
                    FindInMethod.super.visitInsn(Opcodes.AASTORE);
                }

                if (!fia.asyncJavaScript()) {
                    super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
                            "org/netbeans/html/boot/spi/Fn", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"
                    );
                    switch (sv.returnType.getSort()) {
                        case Type.VOID:
                            super.visitInsn(Opcodes.RETURN);
                            break;
                        case Type.ARRAY:
                        case Type.OBJECT:
                            super.visitTypeInsn(Opcodes.CHECKCAST, sv.returnType.getInternalName());
                            super.visitInsn(Opcodes.ARETURN);
                            break;
                        case Type.BOOLEAN: {
                            Label handleNullValue = new Label();
                            super.visitInsn(Opcodes.DUP);
                            super.visitJumpInsn(Opcodes.IFNULL, handleNullValue);
                            super.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Boolean");
                            super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
                                    "java/lang/Boolean", "booleanValue", "()Z"
                            );
                            super.visitInsn(Opcodes.IRETURN);
                            super.visitLabel(handleNullValue);
                            super.visitInsn(Opcodes.ICONST_0);
                            super.visitInsn(Opcodes.IRETURN);
                            break;
                        }
                        default:
                            super.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Number");
                            super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
                                    "java/lang/Number", sv.returnType.getClassName() + "Value", "()" + sv.returnType.getDescriptor()
                            );
                            super.visitInsn(sv.returnType.getOpcode(Opcodes.IRETURN));
                    }
                } else {
                    super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
                            "org/netbeans/html/boot/spi/Fn", "invokeLater", "(Ljava/lang/Object;[Ljava/lang/Object;)V"
                    );
                    super.visitInsn(Opcodes.RETURN);
                }
                super.visitLabel(noPresenter);
                if (hasCode) {
                    super.visitCode();
                } else {
                    super.visitTypeInsn(Opcodes.NEW, "java/lang/IllegalStateException");
                    super.visitInsn(Opcodes.DUP);
                    super.visitLdcInsn("No presenter active. Use BrwsrCtx.execute!");
                    super.visitMethodInsn(Opcodes.INVOKESPECIAL, 
                        "java/lang/IllegalStateException", "<init>", "(Ljava/lang/String;)V"
                    );
                    this.visitInsn(Opcodes.ATHROW);
                }
                return true;
            }