| 52 | } |
| 53 | |
| 54 | string ToNative(NativeRegistry &natreg, NativeGenerator &ng, |
| 55 | string_view bytecode_buffer) { |
| 56 | auto bcf = bytecode::GetBytecodeFile(bytecode_buffer.data()); |
| 57 | assert(FLATBUFFERS_LITTLEENDIAN); |
| 58 | auto code = (const int *)bcf->bytecode()->Data(); // Assumes we're on a little-endian machine. |
| 59 | //auto typetable = (const type_elem_t *)bcf->typetable()->Data(); // Same. |
| 60 | map<int, const bytecode::Function *> function_lookup; |
| 61 | for (flatbuffers::uoffset_t i = 0; i < bcf->functions()->size(); i++) { |
| 62 | auto f = bcf->functions()->Get(i); |
| 63 | function_lookup[f->bytecodestart()] = f; |
| 64 | } |
| 65 | ng.FileStart(); |
| 66 | auto len = bcf->bytecode()->Length(); |
| 67 | vector<int> block_ids(bcf->bytecode_attr()->size(), -1); |
| 68 | const int *ip = code; |
| 69 | // Skip past 1st jump. |
| 70 | assert(*ip == IL_JUMP); |
| 71 | ip++; |
| 72 | auto starting_point = *ip++; |
| 73 | int block_id = 1; |
| 74 | while (ip < code + len) { |
| 75 | if (bcf->bytecode_attr()->Get((flatbuffers::uoffset_t)(ip - code)) & bytecode::Attr_SPLIT) { |
| 76 | auto id = block_ids[ip - code] = block_id++; |
| 77 | ng.DeclareBlock(id); |
| 78 | } |
| 79 | if ((false)) { // Debug corrupt bytecode. |
| 80 | ostringstream dss; |
| 81 | DisAsmIns(natreg, dss, ip, code, (const type_elem_t *)bcf->typetable()->Data(), bcf); |
| 82 | LOG_DEBUG(dss.str()); |
| 83 | } |
| 84 | int opc = *ip++; |
| 85 | if (opc < 0 || opc >= IL_MAX_OPS) { |
| 86 | return cat("Corrupt bytecode: ", opc, " at: ", ip - 1 - code); |
| 87 | } |
| 88 | ParseOpAndGetArity(opc, ip); |
| 89 | } |
| 90 | ng.BeforeBlocks(block_ids[starting_point], bytecode_buffer); |
| 91 | ip = code + 2; |
| 92 | bool already_returned = false; |
| 93 | while (ip < code + len) { |
| 94 | int opc = *ip++; |
| 95 | if (opc == IL_FUNSTART) { |
| 96 | auto it = function_lookup.find((int)(ip - 1 - code)); |
| 97 | ng.FunStart(it != function_lookup.end() ? it->second : nullptr); |
| 98 | } |
| 99 | auto args = ip; |
| 100 | if (bcf->bytecode_attr()->Get((flatbuffers::uoffset_t)(ip - 1 - code)) & bytecode::Attr_SPLIT) { |
| 101 | auto cid = block_ids[args - 1 - code]; |
| 102 | ng.current_block_id = cid; |
| 103 | ng.BlockStart(cid); |
| 104 | already_returned = false; |
| 105 | } |
| 106 | auto arity = ParseOpAndGetArity(opc, ip); |
| 107 | auto is_vararg = ILArity()[opc] == ILUNKNOWNARITY; |
| 108 | ng.InstStart(); |
| 109 | if (opc == IL_JUMP) { |
| 110 | already_returned = true; |
| 111 | ng.EmitJump(block_ids[args[0]]); |
no test coverage detected