Skip to content

Commit

Permalink
Fix a crash in try-catch
Browse files Browse the repository at this point in the history
Signed-off-by: Zoltan Herczeg [email protected]
  • Loading branch information
zherczeg authored and clover2123 committed Oct 31, 2024
1 parent f82a879 commit 7f492b3
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 8 deletions.
40 changes: 36 additions & 4 deletions src/jit/Analysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,13 @@ void DependencyGenContext::update(size_t dependencyStart, size_t id, size_t excl
&& maxDistance[dependencyStart / size] <= id);

for (auto it : param) {
VariableRef ref = variableList->variables.size();
if (variableList != nullptr) {
// Construct new variables.
VariableRef ref = variableList->variables.size();

dependencies[dependencyStart + offset].insert(VARIABLE_SET(ref, Variable));
variableList->variables.push_back(VariableList::Variable(VARIABLE_SET(offset, Instruction::Offset), 0, id));
dependencies[dependencyStart + offset].insert(VARIABLE_SET(ref, Variable));
variableList->variables.push_back(VariableList::Variable(VARIABLE_SET(offset, Instruction::Offset), 0, id));
}

offset += STACK_OFFSET(valueStackAllocatedSize(it));
}
Expand Down Expand Up @@ -287,6 +290,7 @@ void JITCompiler::buildVariables(uint32_t requiredStackSize)
size_t nextId = 0;
size_t nextTryBlock = m_tryBlockStart;

// Create variables for each result or external values.
for (InstructionListItem* item = m_first; item != nullptr; item = item->next()) {
item->m_id = ++nextId;

Expand Down Expand Up @@ -322,6 +326,7 @@ void JITCompiler::buildVariables(uint32_t requiredStackSize)

DependencyGenContext dependencyCtx(dependencySize, requiredStackSize);
bool updateDeps = true;
std::vector<size_t> activeTryBlocks;

m_variableList = new VariableList(variableCount, requiredStackSize);
nextTryBlock = m_tryBlockStart;
Expand Down Expand Up @@ -365,11 +370,16 @@ void JITCompiler::buildVariables(uint32_t requiredStackSize)
}
}

activeTryBlocks.push_back(nextTryBlock);
nextTryBlock++;
} while (nextTryBlock < tryBlocks().size()
&& tryBlocks()[nextTryBlock].start == label);
}

if (label->info() & Label::kHasCatchInfo) {
activeTryBlocks.pop_back();
}

for (size_t i = 0; i < requiredStackSize; ++i) {
dependencyCtx.currentDependencies[i] = VARIABLE_SET_PTR(label);
dependencyCtx.currentOptions[i] = 0;
Expand Down Expand Up @@ -424,7 +434,28 @@ void JITCompiler::buildVariables(uint32_t requiredStackSize)
continue;
}

if (instr->opcode() == ByteCode::ThrowOpcode || instr->opcode() == ByteCode::UnreachableOpcode) {
if (activeTryBlocks.size() > 0 && (instr->group() == Instruction::Call || instr->opcode() == ByteCode::ThrowOpcode)) {
// Every call or throw may jump to any active catch block. Future
// optimizations could reduce these (e.g. a throw can be converted
// to a jump if its target catch block is in the same function).
for (auto blockIt : activeTryBlocks) {
for (auto it : tryBlocks()[blockIt].catchBlocks) {
if (it.tagIndex == std::numeric_limits<uint32_t>::max()) {
dependencyCtx.update(it.u.handler->m_dependencyStart, instr->id());
} else {
TagType* tagType = module()->tagType(it.tagIndex);
const ValueTypeVector& param = module()->functionType(tagType->sigIndex())->param();
Label* catchLabel = it.u.handler;

dependencyCtx.update(catchLabel->m_dependencyStart, catchLabel->id(),
STACK_OFFSET(it.stackSizeToBe), param, nullptr);
}
}
}
}

if (instr->opcode() == ByteCode::ThrowOpcode || instr->opcode() == ByteCode::UnreachableOpcode
|| instr->opcode() == ByteCode::EndOpcode) {
updateDeps = false;
continue;
}
Expand Down Expand Up @@ -495,6 +526,7 @@ void JITCompiler::buildVariables(uint32_t requiredStackSize)
}

ASSERT(variableCount == m_variableList->variables.size());
ASSERT(activeTryBlocks.size() == 0);

// Phase 2: the indirect instruction
// references are computed for labels.
Expand Down
11 changes: 7 additions & 4 deletions src/jit/RegisterAlloc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,14 +298,16 @@ uint8_t RegisterSet::allocateRegisterPair(VariableList::Variable* variable, uint
size_t freeReg = VariableList::kUnusedReg;
uint16_t constraints = variable != nullptr ? variable->info : 0;
size_t size = m_registers.size();
size_t i = 0;
size_t minIndex = 0;

if (constraints & VariableList::kIsCallback) {
i = m_savedStartIndex;
minIndex = m_savedStartIndex;
} else if ((constraints & VariableList::kDestroysR0R1) && (m_regStatus & kIsInteger)) {
i = 2;
minIndex = 2;
}

size_t i = minIndex;

while (i < size) {
if (m_registers[i].rangeEnd == kUnassignedReg) {
if (freeReg != VariableList::kUnusedReg) {
Expand All @@ -317,7 +319,8 @@ uint8_t RegisterSet::allocateRegisterPair(VariableList::Variable* variable, uint
VariableList::Variable* targetVariable = m_registers[i].variable;

if (targetVariable->reg1 != targetVariable->reg2) {
if (targetVariable->rangeEnd > maxRangeEndPair) {
if (targetVariable->reg1 >= minIndex && targetVariable->reg2 >= minIndex
&& targetVariable->rangeEnd > maxRangeEndPair) {
maxRangeEndPair = targetVariable->rangeEnd;
maxRangeIndexPair = i;
}
Expand Down
103 changes: 103 additions & 0 deletions test/jit/trycatch-dep.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
(module
(memory 1)

(tag $except0 (param i32 i64))
(tag $except1 (param f32 f64))
(tag $except3)

(func $throw1 (param i64)
i32.const 1234
local.get 0
throw $except0
)

(func $throw2 (param i64)
f32.const 2345.0
local.get 0
f64.convert_i64_s
throw $except1
)

(func $throw3 (param i64)
throw $except3
)

(func (export "try1") (param i64) (result i64 i32) (local $l1 i64) (local $l2 i32)
i32.const 123456
local.set $l2
(try
(do
(try
(do
local.get 0
local.set $l1

local.get $l1
i32.wrap_i64
i32.const 100
i32.add
local.set $l2

i64.const 1000
local.get $l1
i64.lt_s
if
local.get $l1
call $throw1
end

local.get $l1
i64.const 500
i64.gt_s
if
local.get $l1
call $throw2
end

local.get $l1
i64.const 250
i64.gt_s
if
local.get $l1
call $throw3
end

local.get $l1
i64.const 17
i64.sub
i32.const -678
return
)
(catch $except0
local.set $l1
i64.extend_i32_s
local.get $l1
i64.add
local.set $l1
)
)
)
(catch $except1
i64.trunc_sat_f64_s
local.set $l1

i64.trunc_sat_f32_s
local.get $l1
i64.add
local.set $l1
)
(catch_all
i64.const 888
local.set $l1
)
)

local.get $l1
local.get $l2
)
)

(assert_return (invoke "try1" (i64.const 99)) (i64.const 82) (i32.const -678))
(assert_return (invoke "try1" (i64.const 2000)) (i64.const 3234) (i32.const 2100))
(assert_return (invoke "try1" (i64.const 600)) (i64.const 2945) (i32.const 700))
(assert_return (invoke "try1" (i64.const 300)) (i64.const 888) (i32.const 400))

0 comments on commit 7f492b3

Please sign in to comment.