static void after_assert_return_nan(WasmType type, WasmParserCookie cookie, void* user_data) { Context* ctx = user_data; int num_local_f32 = 0; int num_local_f64 = 0; switch (type) { case WASM_TYPE_F32: num_local_f32++; out_opcode(&ctx->buf, WASM_OPCODE_F32_NE); break; case WASM_TYPE_F64: num_local_f64++; out_opcode(&ctx->buf, WASM_OPCODE_F64_NE); break; default: assert(0); } /* x != x is true iff x is NaN */ out_opcode(&ctx->buf, WASM_OPCODE_GET_LOCAL); out_u8(&ctx->buf, 0, "remapped local index"); out_opcode(&ctx->buf, WASM_OPCODE_GET_LOCAL); out_u8(&ctx->buf, 0, "remapped local index"); char name[256]; snprintf(name, 256, "$assert_return_nan_%d", ctx->assert_return_nan_count++); append_nullary_function(ctx, name, WASM_TYPE_I32, 0, 0, num_local_f32, num_local_f64); ctx->in_assert = 0; }
static void out_set_addr (symbolS *sym) { expressionS exp; out_opcode (DW_LNS_extended_op); out_uleb128 (sizeof_address + 1); out_opcode (DW_LNE_set_address); exp.X_op = O_symbol; exp.X_add_symbol = sym; exp.X_add_number = 0; emit_expr (&exp, sizeof_address); }
static void before_call(int function_index, void* user_data) { Context* ctx = user_data; out_opcode(&ctx->buf, WASM_OPCODE_CALL); /* defined functions are always after all imports */ out_leb128(&ctx->buf, ctx->module->imports.size + function_index, "func index"); }
static void before_store(enum WasmOpcode opcode, uint8_t access, void* user_data) { Context* ctx = user_data; out_opcode(&ctx->buf, opcode); out_u8(&ctx->buf, access, "store access byte"); }
static void out_set_addr (segT seg, fragS *frag, addressT ofs) { expressionS expr; symbolS *sym; sym = symbol_temp_new (seg, ofs, frag); out_opcode (DW_LNS_extended_op); out_uleb128 (sizeof_address + 1); out_opcode (DW_LNE_set_address); expr.X_op = O_symbol; expr.X_add_symbol = sym; expr.X_add_number = 0; emit_expr (&expr, sizeof_address); }
static WasmParserCookie before_loop(void* user_data) { Context* ctx = user_data; out_opcode(&ctx->buf, WASM_OPCODE_LOOP); WasmParserCookie cookie = (WasmParserCookie)ctx->buf.size; out_u8(&ctx->buf, 0, "num expressions"); ctx->block_depth++; return cookie; }
static WasmParserCookie before_assert_return_nan(WasmSourceLocation loc, void* user_data) { Context* ctx = user_data; ctx->in_assert = 1; if (g_verbose) printf("; before assert_return_nan_%d\n", ctx->assert_return_nan_count); init_output_buffer(&ctx->buf, INITIAL_OUTPUT_BUFFER_CAPACITY); out_opcode(&ctx->buf, WASM_OPCODE_SET_LOCAL); out_u8(&ctx->buf, 0, "remapped local index"); return 0; }
static WasmParserCookie before_assert_return(WasmSourceLocation loc, void* user_data) { Context* ctx = user_data; ctx->in_assert = 1; if (g_verbose) printf("; before assert_return_%d\n", ctx->assert_return_count); init_output_buffer(&ctx->buf, INITIAL_OUTPUT_BUFFER_CAPACITY); WasmParserCookie cookie = (WasmParserCookie)ctx->buf.size; out_opcode(&ctx->buf, WASM_OPCODE_I32_EQ); return cookie; }
static WasmParserCookie before_label(void* user_data) { Context* ctx = user_data; LabelInfo* label_info = malloc(sizeof(LabelInfo)); label_info->offset = ctx->buf.size; label_info->block_depth = ctx->block_depth++; label_info->next_label = ctx->top_label; ctx->top_label = label_info; out_opcode(&ctx->buf, WASM_OPCODE_BLOCK); out_u8(&ctx->buf, 0, "num expressions"); return (WasmParserCookie)label_info; }
static WasmParserCookie before_break(int with_expr, int label_depth, void* user_data) { Context* ctx = user_data; out_opcode(&ctx->buf, with_expr ? WASM_OPCODE_EXPR_BREAK : WASM_OPCODE_BREAK); LabelInfo* label_info = ctx->top_label; for (; label_depth > 0; label_depth--) label_info = label_info->next_label; int block_depth = (ctx->block_depth - 1) - label_info->block_depth; out_u8(&ctx->buf, block_depth, "break depth"); return 0; }
static void out_fixed_inc_line_addr (int line_delta, symbolS *to_sym, symbolS *from_sym) { expressionS expr; /* INT_MAX is a signal that this is actually a DW_LNE_end_sequence. */ if (line_delta == INT_MAX) { out_opcode (DW_LNS_fixed_advance_pc); expr.X_op = O_subtract; expr.X_add_symbol = to_sym; expr.X_op_symbol = from_sym; expr.X_add_number = 0; emit_expr (&expr, 2); out_opcode (DW_LNS_extended_op); out_byte (1); out_opcode (DW_LNE_end_sequence); return; } out_opcode (DW_LNS_advance_line); out_sleb128 (line_delta); out_opcode (DW_LNS_fixed_advance_pc); expr.X_op = O_subtract; expr.X_add_symbol = to_sym; expr.X_op_symbol = from_sym; expr.X_add_number = 0; emit_expr (&expr, 2); out_opcode (DW_LNS_copy); }
static void after_const(enum WasmOpcode opcode, WasmType type, WasmNumber value, void* user_data) { Context* ctx = user_data; switch (type) { case WASM_TYPE_I32: { int32_t i32 = value.i32; if (i32 >= -128 && i32 < 127) { out_opcode(&ctx->buf, WASM_OPCODE_I8_CONST); out_u8(&ctx->buf, value.i32, "u8 literal"); } else { out_opcode(&ctx->buf, opcode); out_u32(&ctx->buf, value.i32, "u32 literal"); } break; } case WASM_TYPE_I64: out_opcode(&ctx->buf, opcode); out_u64(&ctx->buf, value.i64, "u64 literal"); break; case WASM_TYPE_F32: out_opcode(&ctx->buf, opcode); out_f32(&ctx->buf, value.f32, "f32 literal"); break; case WASM_TYPE_F64: out_opcode(&ctx->buf, opcode); out_f64(&ctx->buf, value.f64, "f64 literal"); break; default: assert(0); break; } }
static WasmParserCookie before_invoke(WasmSourceLocation loc, const char* invoke_name, int invoke_function_index, void* user_data) { Context* ctx = user_data; if (!ctx->in_assert) { if (g_verbose) printf("; before invoke_%d\n", ctx->invoke_count); init_output_buffer(&ctx->buf, INITIAL_OUTPUT_BUFFER_CAPACITY); } out_opcode(&ctx->buf, WASM_OPCODE_CALL); /* defined functions are always after all imports */ out_leb128(&ctx->buf, ctx->module->imports.size + invoke_function_index, "invoke func index"); return (WasmParserCookie)invoke_function_index; }
static void after_load_global(int index, void* user_data) { Context* ctx = user_data; out_opcode(&ctx->buf, WASM_OPCODE_GET_GLOBAL); out_leb128(&ctx->buf, index, "global index"); }
static void process_entries (segT seg, struct line_entry *e) { unsigned filenum = 1; unsigned line = 1; unsigned column = 0; unsigned isa = 0; unsigned flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0; fragS *last_frag = NULL, *frag; addressT last_frag_ofs = 0, frag_ofs; symbolS *last_lab = NULL, *lab; struct line_entry *next; do { int line_delta; if (filenum != e->loc.filenum) { filenum = e->loc.filenum; out_opcode (DW_LNS_set_file); out_uleb128 (filenum); } if (column != e->loc.column) { column = e->loc.column; out_opcode (DW_LNS_set_column); out_uleb128 (column); } if (e->loc.discriminator != 0) { out_opcode (DW_LNS_extended_op); out_leb128 (1 + sizeof_leb128 (e->loc.discriminator, 0)); out_opcode (DW_LNE_set_discriminator); out_uleb128 (e->loc.discriminator); } if (isa != e->loc.isa) { isa = e->loc.isa; out_opcode (DW_LNS_set_isa); out_uleb128 (isa); } if ((e->loc.flags ^ flags) & DWARF2_FLAG_IS_STMT) { flags = e->loc.flags; out_opcode (DW_LNS_negate_stmt); } if (e->loc.flags & DWARF2_FLAG_BASIC_BLOCK) out_opcode (DW_LNS_set_basic_block); if (e->loc.flags & DWARF2_FLAG_PROLOGUE_END) out_opcode (DW_LNS_set_prologue_end); if (e->loc.flags & DWARF2_FLAG_EPILOGUE_BEGIN) out_opcode (DW_LNS_set_epilogue_begin); /* Don't try to optimize away redundant entries; gdb wants two entries for a function where the code starts on the same line as the {, and there's no way to identify that case here. Trust gcc to optimize appropriately. */ line_delta = e->loc.line - line; lab = e->label; frag = symbol_get_frag (lab); frag_ofs = S_GET_VALUE (lab); if (last_frag == NULL) { out_set_addr (lab); out_inc_line_addr (line_delta, 0); } else if (frag == last_frag && ! DWARF2_USE_FIXED_ADVANCE_PC) out_inc_line_addr (line_delta, frag_ofs - last_frag_ofs); else relax_inc_line_addr (line_delta, lab, last_lab); line = e->loc.line; last_lab = lab; last_frag = frag; last_frag_ofs = frag_ofs; next = e->next; free (e); e = next; } while (e); /* Emit a DW_LNE_end_sequence for the end of the section. */ frag = last_frag_for_seg (seg); frag_ofs = get_frag_fix (frag, seg); if (frag == last_frag && ! DWARF2_USE_FIXED_ADVANCE_PC) out_inc_line_addr (INT_MAX, frag_ofs - last_frag_ofs); else { lab = symbol_temp_new (seg, frag_ofs, frag); relax_inc_line_addr (INT_MAX, lab, last_lab); } }
static void before_unary(enum WasmOpcode opcode, void* user_data) { Context* ctx = user_data; out_opcode(&ctx->buf, opcode); }
static void before_store_global(int index, void* user_data) { Context* ctx = user_data; out_opcode(&ctx->buf, WASM_OPCODE_SET_GLOBAL); out_leb128(&ctx->buf, index, "global index"); }
static void process_entries (segT seg, struct line_entry *e) { unsigned filenum = 1; unsigned line = 1; unsigned column = 0; unsigned flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_BEGIN_STMT : 0; fragS *frag = NULL; fragS *last_frag; addressT frag_ofs = 0; addressT last_frag_ofs; struct line_entry *next; while (e) { int changed = 0; if (filenum != e->loc.filenum) { filenum = e->loc.filenum; out_opcode (DW_LNS_set_file); out_uleb128 (filenum); changed = 1; } if (column != e->loc.column) { column = e->loc.column; out_opcode (DW_LNS_set_column); out_uleb128 (column); changed = 1; } if ((e->loc.flags ^ flags) & DWARF2_FLAG_BEGIN_STMT) { flags = e->loc.flags; out_opcode (DW_LNS_negate_stmt); changed = 1; } if (e->loc.flags & DWARF2_FLAG_BEGIN_BLOCK) { out_opcode (DW_LNS_set_basic_block); changed = 1; } /* Don't try to optimize away redundant entries; gdb wants two entries for a function where the code starts on the same line as the {, and there's no way to identify that case here. Trust gcc to optimize appropriately. */ if (1 /* line != e->loc.line || changed */) { int line_delta = e->loc.line - line; if (frag == NULL) { out_set_addr (seg, e->frag, e->frag_ofs); out_inc_line_addr (line_delta, 0); } else if (frag == e->frag) out_inc_line_addr (line_delta, e->frag_ofs - frag_ofs); else relax_inc_line_addr (line_delta, seg, e->frag, e->frag_ofs, frag, frag_ofs); frag = e->frag; frag_ofs = e->frag_ofs; line = e->loc.line; } else if (frag == NULL) { out_set_addr (seg, e->frag, e->frag_ofs); frag = e->frag; frag_ofs = e->frag_ofs; } next = e->next; free (e); e = next; } /* Emit a DW_LNE_end_sequence for the end of the section. */ last_frag = last_frag_for_seg (seg); last_frag_ofs = get_frag_fix (last_frag); if (frag == last_frag) out_inc_line_addr (INT_MAX, last_frag_ofs - frag_ofs); else relax_inc_line_addr (INT_MAX, seg, last_frag, last_frag_ofs, frag, frag_ofs); }
static void before_set_local(int index, void* user_data) { Context* ctx = user_data; out_opcode(&ctx->buf, WASM_OPCODE_SET_LOCAL); out_leb128(&ctx->buf, ctx->remapped_locals[index], "remapped local index"); }
static void before_return(void* user_data) { Context* ctx = user_data; out_opcode(&ctx->buf, WASM_OPCODE_RETURN); }
static void before_resize_memory(void* user_data) { Context* ctx = user_data; out_opcode(&ctx->buf, WASM_OPCODE_RESIZE_MEMORY_I32); }
static void after_page_size(void* user_data) { Context* ctx = user_data; out_opcode(&ctx->buf, WASM_OPCODE_PAGE_SIZE); }
static void after_nop(void* user_data) { Context* ctx = user_data; out_opcode(&ctx->buf, WASM_OPCODE_NOP); }
static void after_memory_size(void* user_data) { Context* ctx = user_data; /* TODO(binji): not currently defined. Return 0 for now. */ out_opcode(&ctx->buf, WASM_OPCODE_I8_CONST); out_u8(&ctx->buf, 0, "zero"); }
static void before_call_import(int import_index, void* user_data) { Context* ctx = user_data; out_opcode(&ctx->buf, WASM_OPCODE_CALL); out_leb128(&ctx->buf, import_index, "import index"); }
static WasmParserCookie before_if(void* user_data) { Context* ctx = user_data; uint32_t offset = ctx->buf.size; out_opcode(&ctx->buf, WASM_OPCODE_IF); return (WasmParserCookie)offset; }