[compiler] Pass inlining_id via relocation info.

This passes the inlining_id of deoptimization points via the relocation
info instead of via a side-channel to the CPU profiler. This is one step
towards deprecating the side-channel in question and avoid the need for
performing a lookup of the return address of the deopt point.

R=jarin@chromium.org

Review-Url: https://codereview.chromium.org/1956693002
Cr-Commit-Position: refs/heads/master@{#36177}
This commit is contained in:
mstarzinger 2016-05-11 07:05:41 -07:00 committed by Commit bot
parent af02c0336d
commit 32049620d2
32 changed files with 54 additions and 81 deletions

View File

@ -1379,7 +1379,7 @@ class Assembler : public AssemblerBase {
// Record a deoptimization reason that can be used by a log or cpu profiler.
// Use --trace-deopt to enable.
void RecordDeoptReason(const int reason, int raw_position);
void RecordDeoptReason(const int reason, int raw_position, int inlining_id);
// Record the emission of a constant pool.
//

View File

@ -329,13 +329,11 @@ bool Operand::NeedsRelocation(const Assembler* assembler) const {
// Constant Pool.
void ConstPool::RecordEntry(intptr_t data,
RelocInfo::Mode mode) {
DCHECK(mode != RelocInfo::COMMENT &&
mode != RelocInfo::POSITION &&
DCHECK(mode != RelocInfo::COMMENT && mode != RelocInfo::POSITION &&
mode != RelocInfo::STATEMENT_POSITION &&
mode != RelocInfo::CONST_POOL &&
mode != RelocInfo::VENEER_POOL &&
mode != RelocInfo::CONST_POOL && mode != RelocInfo::VENEER_POOL &&
mode != RelocInfo::CODE_AGE_SEQUENCE &&
mode != RelocInfo::DEOPT_REASON);
mode != RelocInfo::DEOPT_REASON && mode != RelocInfo::DEOPT_ID);
uint64_t raw_data = static_cast<uint64_t>(data);
int offset = assm_->pc_offset();
if (IsEmpty()) {
@ -2913,11 +2911,12 @@ void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
(rmode <= RelocInfo::DEBUG_BREAK_SLOT_AT_TAIL_CALL)) ||
(rmode == RelocInfo::INTERNAL_REFERENCE) ||
(rmode == RelocInfo::CONST_POOL) || (rmode == RelocInfo::VENEER_POOL) ||
(rmode == RelocInfo::DEOPT_REASON) ||
(rmode == RelocInfo::DEOPT_REASON) || (rmode == RelocInfo::DEOPT_ID) ||
(rmode == RelocInfo::GENERATOR_CONTINUATION)) {
// Adjust code for new modes.
DCHECK(RelocInfo::IsDebugBreakSlot(rmode) || RelocInfo::IsComment(rmode) ||
RelocInfo::IsDeoptReason(rmode) || RelocInfo::IsPosition(rmode) ||
RelocInfo::IsDeoptReason(rmode) || RelocInfo::IsDeoptId(rmode) ||
RelocInfo::IsPosition(rmode) ||
RelocInfo::IsInternalReference(rmode) ||
RelocInfo::IsConstPool(rmode) || RelocInfo::IsVeneerPool(rmode) ||
RelocInfo::IsGeneratorContinuation(rmode));

View File

@ -935,7 +935,7 @@ class Assembler : public AssemblerBase {
// Record a deoptimization reason that can be used by a log or cpu profiler.
// Use --trace-deopt to enable.
void RecordDeoptReason(const int reason, int raw_position);
void RecordDeoptReason(const int reason, int raw_position, int inlining_id);
int buffer_space() const;

View File

@ -514,7 +514,8 @@ void RelocInfoWriter::Write(const RelocInfo* rinfo) {
if (RelocInfo::IsComment(rmode)) {
WriteData(rinfo->data());
} else if (RelocInfo::IsConstPool(rmode) ||
RelocInfo::IsVeneerPool(rmode)) {
RelocInfo::IsVeneerPool(rmode) ||
RelocInfo::IsDeoptId(rmode)) {
WriteIntData(static_cast<int>(rinfo->data()));
}
}
@ -705,7 +706,8 @@ void RelocIterator::next() {
Advance(kIntSize);
}
} else if (RelocInfo::IsConstPool(rmode) ||
RelocInfo::IsVeneerPool(rmode)) {
RelocInfo::IsVeneerPool(rmode) ||
RelocInfo::IsDeoptId(rmode)) {
if (SetMode(rmode)) {
AdvanceReadInt();
return;
@ -828,6 +830,8 @@ const char* RelocInfo::RelocModeName(RelocInfo::Mode rmode) {
return "encoded internal reference";
case DEOPT_REASON:
return "deopt reason";
case DEOPT_ID:
return "deopt inlining id";
case CONST_POOL:
return "constant pool";
case VENEER_POOL:
@ -935,6 +939,7 @@ void RelocInfo::Verify(Isolate* isolate) {
case STATEMENT_POSITION:
case EXTERNAL_REFERENCE:
case DEOPT_REASON:
case DEOPT_ID:
case CONST_POOL:
case VENEER_POOL:
case DEBUG_BREAK_SLOT_AT_POSITION:
@ -2052,12 +2057,13 @@ int ConstantPoolBuilder::Emit(Assembler* assm) {
// Platform specific but identical code for all the platforms.
void Assembler::RecordDeoptReason(const int reason, int raw_position) {
void Assembler::RecordDeoptReason(const int reason, int raw_position,
int inlining_id) {
if (FLAG_trace_deopt || isolate()->cpu_profiler()->is_profiling()) {
EnsureSpace ensure_space(this);
RecordRelocInfo(RelocInfo::POSITION, raw_position);
RecordRelocInfo(RelocInfo::DEOPT_REASON, reason);
RecordRelocInfo(RelocInfo::DEOPT_ID, inlining_id);
}
}

View File

@ -416,6 +416,7 @@ class RelocInfo {
VENEER_POOL,
DEOPT_REASON, // Deoptimization reason index.
DEOPT_ID, // Deoptimization inlining id.
// This is not an actual reloc mode, but used to encode a long pc jump that
// cannot be encoded as part of another record.
@ -476,6 +477,9 @@ class RelocInfo {
static inline bool IsDeoptReason(Mode mode) {
return mode == DEOPT_REASON;
}
static inline bool IsDeoptId(Mode mode) {
return mode == DEOPT_ID;
}
static inline bool IsPosition(Mode mode) {
return mode == POSITION || mode == STATEMENT_POSITION;
}

View File

@ -131,7 +131,6 @@ struct InlinedFunctionInfo {
SourcePosition inline_position;
int script_id;
int start_position;
std::vector<size_t> deopt_pc_offsets;
static const int kNoParentId = -1;
};

View File

@ -329,8 +329,6 @@ bool LCodeGen::GenerateJumpTable() {
} else {
__ bl(&call_deopt_entry);
}
LogDeoptCallPosition(masm()->pc_offset(),
table_entry->deopt_info.inlining_id);
masm()->CheckConstPool(false, false);
}
@ -832,7 +830,6 @@ void LCodeGen::DeoptimizeIf(Condition condition, LInstruction* instr,
!info()->saves_caller_doubles()) {
DeoptComment(deopt_info);
__ Call(entry, RelocInfo::RUNTIME_ENTRY);
LogDeoptCallPosition(masm()->pc_offset(), deopt_info.inlining_id);
} else {
Deoptimizer::JumpTableEntry table_entry(entry, deopt_info, bailout_type,
!frame_is_built_);

View File

@ -775,8 +775,6 @@ bool LCodeGen::GenerateJumpTable() {
// table.
__ Bl(&call_deopt_entry);
}
LogDeoptCallPosition(masm()->pc_offset(),
table_entry->deopt_info.inlining_id);
masm()->CheckConstPool(false, false);
}
@ -900,7 +898,6 @@ void LCodeGen::DeoptimizeBranch(
frame_is_built_ && !info()->saves_caller_doubles()) {
DeoptComment(deopt_info);
__ Call(entry, RelocInfo::RUNTIME_ENTRY);
LogDeoptCallPosition(masm()->pc_offset(), deopt_info.inlining_id);
} else {
Deoptimizer::JumpTableEntry* table_entry =
new (zone()) Deoptimizer::JumpTableEntry(

View File

@ -274,8 +274,6 @@ bool LCodeGen::GenerateJumpTable() {
if (info()->saves_caller_doubles()) RestoreCallerDoubles();
__ call(entry, RelocInfo::RUNTIME_ENTRY);
}
LogDeoptCallPosition(masm()->pc_offset(),
table_entry->deopt_info.inlining_id);
}
if (needs_frame.is_linked()) {
__ bind(&needs_frame);
@ -731,7 +729,6 @@ void LCodeGen::DeoptimizeIf(Condition cc, LInstruction* instr,
if (cc == no_condition && frame_is_built_) {
DeoptComment(deopt_info);
__ call(entry, RelocInfo::RUNTIME_ENTRY);
LogDeoptCallPosition(masm()->pc_offset(), deopt_info.inlining_id);
} else {
Deoptimizer::JumpTableEntry table_entry(entry, deopt_info, bailout_type,
!frame_is_built_);

View File

@ -158,8 +158,9 @@ void LCodeGenBase::Comment(const char* format, ...) {
void LCodeGenBase::DeoptComment(const Deoptimizer::DeoptInfo& deopt_info) {
SourcePosition position = deopt_info.position;
int inlining_id = deopt_info.inlining_id;
int raw_position = position.IsUnknown() ? 0 : position.raw();
masm()->RecordDeoptReason(deopt_info.deopt_reason, raw_position);
masm()->RecordDeoptReason(deopt_info.deopt_reason, raw_position, inlining_id);
}
@ -364,19 +365,12 @@ void LCodeGenBase::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
}
}
void LCodeGenBase::LogDeoptCallPosition(int pc_offset, int inlining_id) {
if (!info()->is_tracking_positions() || info()->IsStub()) return;
auto& inlined_function_infos = info()->inlined_function_infos();
DCHECK_LT(static_cast<size_t>(inlining_id), inlined_function_infos.size());
inlined_function_infos.at(inlining_id).deopt_pc_offsets.push_back(pc_offset);
}
Deoptimizer::DeoptInfo LCodeGenBase::MakeDeoptInfo(
LInstruction* instr, Deoptimizer::DeoptReason deopt_reason) {
Deoptimizer::DeoptInfo deopt_info(instr->hydrogen_value()->position(),
deopt_reason);
HEnterInlined* enter_inlined = instr->environment()->entry();
deopt_info.inlining_id = enter_inlined ? enter_inlined->inlining_id() : 0;
int inlining_id = enter_inlined ? enter_inlined->inlining_id() : 0;
Deoptimizer::DeoptInfo deopt_info(instr->hydrogen_value()->position(),
deopt_reason, inlining_id);
return deopt_info;
}
} // namespace internal

View File

@ -58,8 +58,6 @@ class LCodeGenBase BASE_EMBEDDED {
void PopulateDeoptimizationData(Handle<Code> code);
void PopulateDeoptimizationLiteralsWithInlinedFunctions();
void LogDeoptCallPosition(int pc_offset, int inlining_id);
// Check that an environment assigned via AssignEnvironment is actually being
// used. Redundant assignments keep things alive longer than necessary, and
// consequently lead to worse code, so it's important to minimize this.

View File

@ -330,8 +330,6 @@ bool LCodeGen::GenerateJumpTable() {
} else {
__ Call(&call_deopt_entry);
}
LogDeoptCallPosition(masm()->pc_offset(),
table_entry->deopt_info.inlining_id);
}
if (needs_frame.is_linked()) {
@ -798,7 +796,6 @@ void LCodeGen::DeoptimizeIf(Condition condition, LInstruction* instr,
!info()->saves_caller_doubles()) {
DeoptComment(deopt_info);
__ Call(entry, RelocInfo::RUNTIME_ENTRY, condition, src1, src2);
LogDeoptCallPosition(masm()->pc_offset(), deopt_info.inlining_id);
} else {
Deoptimizer::JumpTableEntry table_entry(entry, deopt_info, bailout_type,
!frame_is_built_);

View File

@ -315,8 +315,6 @@ bool LCodeGen::GenerateJumpTable() {
__ BranchAndLink(&call_deopt_entry);
}
}
LogDeoptCallPosition(masm()->pc_offset(),
table_entry->deopt_info.inlining_id);
}
if (needs_frame.is_linked()) {
__ bind(&needs_frame);
@ -785,7 +783,6 @@ void LCodeGen::DeoptimizeIf(Condition condition, LInstruction* instr,
!info()->saves_caller_doubles()) {
DeoptComment(deopt_info);
__ Call(entry, RelocInfo::RUNTIME_ENTRY, condition, src1, src2);
LogDeoptCallPosition(masm()->pc_offset(), deopt_info.inlining_id);
} else {
Deoptimizer::JumpTableEntry* table_entry =
new (zone()) Deoptimizer::JumpTableEntry(

View File

@ -326,8 +326,6 @@ bool LCodeGen::GenerateJumpTable() {
} else {
__ b(&call_deopt_entry, SetLK);
}
LogDeoptCallPosition(masm()->pc_offset(),
table_entry->deopt_info.inlining_id);
}
if (needs_frame.is_linked()) {
@ -763,7 +761,6 @@ void LCodeGen::DeoptimizeIf(Condition cond, LInstruction* instr,
if (cond == al && frame_is_built_ && !info()->saves_caller_doubles()) {
DeoptComment(deopt_info);
__ Call(entry, RelocInfo::RUNTIME_ENTRY);
LogDeoptCallPosition(masm()->pc_offset(), deopt_info.inlining_id);
} else {
Deoptimizer::JumpTableEntry table_entry(entry, deopt_info, bailout_type,
!frame_is_built_);

View File

@ -312,8 +312,6 @@ bool LCodeGen::GenerateJumpTable() {
} else {
__ b(r14, &call_deopt_entry);
}
LogDeoptCallPosition(masm()->pc_offset(),
table_entry->deopt_info.inlining_id);
}
if (needs_frame.is_linked()) {
@ -753,7 +751,6 @@ void LCodeGen::DeoptimizeIf(Condition cond, LInstruction* instr,
// restore caller doubles.
if (cond == al && frame_is_built_ && !info()->saves_caller_doubles()) {
__ Call(entry, RelocInfo::RUNTIME_ENTRY);
LogDeoptCallPosition(masm()->pc_offset(), deopt_info.inlining_id);
} else {
Deoptimizer::JumpTableEntry table_entry(entry, deopt_info, bailout_type,
!frame_is_built_);

View File

@ -299,8 +299,6 @@ bool LCodeGen::GenerateJumpTable() {
}
__ call(entry, RelocInfo::RUNTIME_ENTRY);
}
LogDeoptCallPosition(masm()->pc_offset(),
table_entry->deopt_info.inlining_id);
}
if (needs_frame.is_linked()) {
@ -757,7 +755,6 @@ void LCodeGen::DeoptimizeIf(Condition cc, LInstruction* instr,
!info()->saves_caller_doubles()) {
DeoptComment(deopt_info);
__ call(entry, RelocInfo::RUNTIME_ENTRY);
LogDeoptCallPosition(masm()->pc_offset(), deopt_info.inlining_id);
} else {
Deoptimizer::JumpTableEntry table_entry(entry, deopt_info, bailout_type,
!frame_is_built_);

View File

@ -275,8 +275,6 @@ bool LCodeGen::GenerateJumpTable() {
} else {
__ call(entry, RelocInfo::RUNTIME_ENTRY);
}
LogDeoptCallPosition(masm()->pc_offset(),
table_entry->deopt_info.inlining_id);
}
if (needs_frame.is_linked()) {
__ bind(&needs_frame);
@ -1022,7 +1020,6 @@ void LCodeGen::DeoptimizeIf(Condition cc, LInstruction* instr,
if (cc == no_condition && frame_is_built_) {
DeoptComment(deopt_info);
__ call(entry, RelocInfo::RUNTIME_ENTRY);
LogDeoptCallPosition(masm()->pc_offset(), deopt_info.inlining_id);
} else {
Deoptimizer::JumpTableEntry table_entry(entry, deopt_info, bailout_type,
!frame_is_built_);

View File

@ -2752,20 +2752,26 @@ const char* Deoptimizer::GetDeoptReason(DeoptReason deopt_reason) {
Deoptimizer::DeoptInfo Deoptimizer::GetDeoptInfo(Code* code, Address pc) {
SourcePosition last_position = SourcePosition::Unknown();
Deoptimizer::DeoptReason last_reason = Deoptimizer::kNoReason;
int last_inlining_id = InlinedFunctionInfo::kNoParentId;
int mask = RelocInfo::ModeMask(RelocInfo::DEOPT_REASON) |
RelocInfo::ModeMask(RelocInfo::DEOPT_ID) |
RelocInfo::ModeMask(RelocInfo::POSITION);
for (RelocIterator it(code, mask); !it.done(); it.next()) {
RelocInfo* info = it.rinfo();
if (info->pc() >= pc) return DeoptInfo(last_position, last_reason);
if (info->pc() >= pc) {
return DeoptInfo(last_position, last_reason, last_inlining_id);
}
if (info->rmode() == RelocInfo::POSITION) {
int raw_position = static_cast<int>(info->data());
last_position = raw_position ? SourcePosition::FromRaw(raw_position)
: SourcePosition::Unknown();
} else if (info->rmode() == RelocInfo::DEOPT_ID) {
last_inlining_id = static_cast<int>(info->data());
} else if (info->rmode() == RelocInfo::DEOPT_REASON) {
last_reason = static_cast<Deoptimizer::DeoptReason>(info->data());
}
}
return DeoptInfo(SourcePosition::Unknown(), Deoptimizer::kNoReason);
return DeoptInfo(SourcePosition::Unknown(), Deoptimizer::kNoReason, -1);
}

View File

@ -410,8 +410,8 @@ class Deoptimizer : public Malloced {
static const char* GetDeoptReason(DeoptReason deopt_reason);
struct DeoptInfo {
DeoptInfo(SourcePosition position, DeoptReason d)
: position(position), deopt_reason(d), inlining_id(0) {}
DeoptInfo(SourcePosition position, DeoptReason d, int inlining_id)
: position(position), deopt_reason(d), inlining_id(inlining_id) {}
SourcePosition position;
DeoptReason deopt_reason;

View File

@ -181,6 +181,9 @@ static int DecodeIt(Isolate* isolate, std::ostream* os,
static_cast<Deoptimizer::DeoptReason>(relocinfo.data());
out.AddFormatted(" ;; debug: deopt reason '%s'",
Deoptimizer::GetDeoptReason(reason));
} else if (rmode == RelocInfo::DEOPT_ID) {
out.AddFormatted(" ;; debug: deopt inlining id %d",
static_cast<int>(relocinfo.data()));
} else if (rmode == RelocInfo::EMBEDDED_OBJECT) {
HeapStringAllocator allocator;
StringStream accumulator(&allocator);

View File

@ -1438,7 +1438,7 @@ class Assembler : public AssemblerBase {
// Record a deoptimization reason that can be used by a log or cpu profiler.
// Use --trace-deopt to enable.
void RecordDeoptReason(const int reason, int raw_position);
void RecordDeoptReason(const int reason, int raw_position, int inlining_id);
// Writes a single byte or word of data in the code stream. Used for
// inline tables, e.g., jump-tables.

View File

@ -1045,8 +1045,7 @@ class Assembler : public AssemblerBase {
// Record a deoptimization reason that can be used by a log or cpu profiler.
// Use --trace-deopt to enable.
void RecordDeoptReason(const int reason, int raw_position);
void RecordDeoptReason(const int reason, int raw_position, int inlining_id);
static int RelocateInternalReference(RelocInfo::Mode rmode, byte* pc,
intptr_t pc_delta);

View File

@ -1105,7 +1105,7 @@ class Assembler : public AssemblerBase {
// Record a deoptimization reason that can be used by a log or cpu profiler.
// Use --trace-deopt to enable.
void RecordDeoptReason(const int reason, int raw_position);
void RecordDeoptReason(const int reason, int raw_position, int inlining_id);
static int RelocateInternalReference(RelocInfo::Mode rmode, byte* pc,
intptr_t pc_delta);

View File

@ -1214,7 +1214,7 @@ class Assembler : public AssemblerBase {
// Record a deoptimization reason that can be used by a log or cpu profiler.
// Use --trace-deopt to enable.
void RecordDeoptReason(const int reason, int raw_position);
void RecordDeoptReason(const int reason, int raw_position, int inlining_id);
// Writes a single byte or word of data in the code stream. Used
// for inline tables, e.g., jump-tables.

View File

@ -35,7 +35,7 @@ void CodeDisableOptEventRecord::UpdateCodeMap(CodeMap* code_map) {
void CodeDeoptEventRecord::UpdateCodeMap(CodeMap* code_map) {
CodeEntry* entry = code_map->FindEntry(start);
if (entry != NULL) entry->set_deopt_info(deopt_reason, position, pc_offset);
if (entry != NULL) entry->set_deopt_info(deopt_reason, position, inlining_id);
}

View File

@ -353,7 +353,7 @@ void CpuProfiler::CodeDeoptEvent(Code* code, Address pc, int fp_to_sp_delta) {
rec->start = code->address();
rec->deopt_reason = Deoptimizer::GetDeoptReason(info.deopt_reason);
rec->position = info.position;
rec->pc_offset = pc - code->instruction_start();
rec->inlining_id = info.inlining_id;
processor_->Enqueue(evt_rec);
processor_->AddDeoptStack(isolate_, pc, fp_to_sp_delta);
}

View File

@ -81,7 +81,7 @@ class CodeDeoptEventRecord : public CodeEventRecord {
Address start;
const char* deopt_reason;
SourcePosition position;
size_t pc_offset;
int inlining_id;
INLINE(void UpdateCodeMap(CodeMap* code_map));
};

View File

@ -138,15 +138,7 @@ CpuProfileDeoptInfo CodeEntry::GetDeoptInfo() {
}
// Copy the only branch from the inlining tree where the deopt happened.
SourcePosition position = deopt_position_;
int inlining_id = InlinedFunctionInfo::kNoParentId;
for (size_t i = 0; i < inlined_function_infos_.size(); ++i) {
InlinedFunctionInfo& current_info = inlined_function_infos_.at(i);
if (std::binary_search(current_info.deopt_pc_offsets.begin(),
current_info.deopt_pc_offsets.end(), pc_offset_)) {
inlining_id = static_cast<int>(i);
break;
}
}
int inlining_id = deopt_inlining_id_;
while (inlining_id != InlinedFunctionInfo::kNoParentId) {
InlinedFunctionInfo& inlined_info = inlined_function_infos_.at(inlining_id);
info.stack.push_back(

View File

@ -64,11 +64,11 @@ class CodeEntry {
const char* bailout_reason() const { return bailout_reason_; }
void set_deopt_info(const char* deopt_reason, SourcePosition position,
size_t pc_offset) {
int inlining_id) {
DCHECK(deopt_position_.IsUnknown());
deopt_reason_ = deopt_reason;
deopt_position_ = position;
pc_offset_ = pc_offset;
deopt_inlining_id_ = inlining_id;
}
CpuProfileDeoptInfo GetDeoptInfo();
const char* deopt_reason() const { return deopt_reason_; }
@ -125,7 +125,7 @@ class CodeEntry {
const char* bailout_reason_;
const char* deopt_reason_;
SourcePosition deopt_position_;
size_t pc_offset_;
int deopt_inlining_id_;
JITLineInfoTable* line_info_;
Address instruction_start_;
// Should be an unordered_map, but it doesn't currently work on Win & MacOS.

View File

@ -1243,7 +1243,7 @@ class Assembler : public AssemblerBase {
// Record a deoptimization reason that can be used by a log or cpu profiler.
// Use --trace-deopt to enable.
void RecordDeoptReason(const int reason, int raw_position);
void RecordDeoptReason(const int reason, int raw_position, int inlining_id);
// Writes a single byte or word of data in the code stream. Used
// for inline tables, e.g., jump-tables.

View File

@ -1696,7 +1696,7 @@ class Assembler : public AssemblerBase {
// Record a deoptimization reason that can be used by a log or cpu profiler.
// Use --trace-deopt to enable.
void RecordDeoptReason(const int reason, int raw_position);
void RecordDeoptReason(const int reason, int raw_position, int inlining_id);
void PatchConstantPoolAccessInstruction(int pc_offset, int offset,
ConstantPoolEntry::Access access,

View File

@ -963,7 +963,7 @@ class Assembler : public AssemblerBase {
// Record a deoptimization reason that can be used by a log or cpu profiler.
// Use --trace-deopt to enable.
void RecordDeoptReason(const int reason, int raw_position);
void RecordDeoptReason(const int reason, int raw_position, int inlining_id);
// Writes a single byte or word of data in the code stream. Used for
// inline tables, e.g., jump-tables.