Skip to content

Commit 7f492b3

Browse files
zherczegclover2123
authored andcommitted
Fix a crash in try-catch
Signed-off-by: Zoltan Herczeg [email protected]
1 parent f82a879 commit 7f492b3

File tree

3 files changed

+146
-8
lines changed

3 files changed

+146
-8
lines changed

src/jit/Analysis.cpp

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,13 @@ void DependencyGenContext::update(size_t dependencyStart, size_t id, size_t excl
9696
&& maxDistance[dependencyStart / size] <= id);
9797

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

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

104107
offset += STACK_OFFSET(valueStackAllocatedSize(it));
105108
}
@@ -287,6 +290,7 @@ void JITCompiler::buildVariables(uint32_t requiredStackSize)
287290
size_t nextId = 0;
288291
size_t nextTryBlock = m_tryBlockStart;
289292

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

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

323327
DependencyGenContext dependencyCtx(dependencySize, requiredStackSize);
324328
bool updateDeps = true;
329+
std::vector<size_t> activeTryBlocks;
325330

326331
m_variableList = new VariableList(variableCount, requiredStackSize);
327332
nextTryBlock = m_tryBlockStart;
@@ -365,11 +370,16 @@ void JITCompiler::buildVariables(uint32_t requiredStackSize)
365370
}
366371
}
367372

373+
activeTryBlocks.push_back(nextTryBlock);
368374
nextTryBlock++;
369375
} while (nextTryBlock < tryBlocks().size()
370376
&& tryBlocks()[nextTryBlock].start == label);
371377
}
372378

379+
if (label->info() & Label::kHasCatchInfo) {
380+
activeTryBlocks.pop_back();
381+
}
382+
373383
for (size_t i = 0; i < requiredStackSize; ++i) {
374384
dependencyCtx.currentDependencies[i] = VARIABLE_SET_PTR(label);
375385
dependencyCtx.currentOptions[i] = 0;
@@ -424,7 +434,28 @@ void JITCompiler::buildVariables(uint32_t requiredStackSize)
424434
continue;
425435
}
426436

427-
if (instr->opcode() == ByteCode::ThrowOpcode || instr->opcode() == ByteCode::UnreachableOpcode) {
437+
if (activeTryBlocks.size() > 0 && (instr->group() == Instruction::Call || instr->opcode() == ByteCode::ThrowOpcode)) {
438+
// Every call or throw may jump to any active catch block. Future
439+
// optimizations could reduce these (e.g. a throw can be converted
440+
// to a jump if its target catch block is in the same function).
441+
for (auto blockIt : activeTryBlocks) {
442+
for (auto it : tryBlocks()[blockIt].catchBlocks) {
443+
if (it.tagIndex == std::numeric_limits<uint32_t>::max()) {
444+
dependencyCtx.update(it.u.handler->m_dependencyStart, instr->id());
445+
} else {
446+
TagType* tagType = module()->tagType(it.tagIndex);
447+
const ValueTypeVector& param = module()->functionType(tagType->sigIndex())->param();
448+
Label* catchLabel = it.u.handler;
449+
450+
dependencyCtx.update(catchLabel->m_dependencyStart, catchLabel->id(),
451+
STACK_OFFSET(it.stackSizeToBe), param, nullptr);
452+
}
453+
}
454+
}
455+
}
456+
457+
if (instr->opcode() == ByteCode::ThrowOpcode || instr->opcode() == ByteCode::UnreachableOpcode
458+
|| instr->opcode() == ByteCode::EndOpcode) {
428459
updateDeps = false;
429460
continue;
430461
}
@@ -495,6 +526,7 @@ void JITCompiler::buildVariables(uint32_t requiredStackSize)
495526
}
496527

497528
ASSERT(variableCount == m_variableList->variables.size());
529+
ASSERT(activeTryBlocks.size() == 0);
498530

499531
// Phase 2: the indirect instruction
500532
// references are computed for labels.

src/jit/RegisterAlloc.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -298,14 +298,16 @@ uint8_t RegisterSet::allocateRegisterPair(VariableList::Variable* variable, uint
298298
size_t freeReg = VariableList::kUnusedReg;
299299
uint16_t constraints = variable != nullptr ? variable->info : 0;
300300
size_t size = m_registers.size();
301-
size_t i = 0;
301+
size_t minIndex = 0;
302302

303303
if (constraints & VariableList::kIsCallback) {
304-
i = m_savedStartIndex;
304+
minIndex = m_savedStartIndex;
305305
} else if ((constraints & VariableList::kDestroysR0R1) && (m_regStatus & kIsInteger)) {
306-
i = 2;
306+
minIndex = 2;
307307
}
308308

309+
size_t i = minIndex;
310+
309311
while (i < size) {
310312
if (m_registers[i].rangeEnd == kUnassignedReg) {
311313
if (freeReg != VariableList::kUnusedReg) {
@@ -317,7 +319,8 @@ uint8_t RegisterSet::allocateRegisterPair(VariableList::Variable* variable, uint
317319
VariableList::Variable* targetVariable = m_registers[i].variable;
318320

319321
if (targetVariable->reg1 != targetVariable->reg2) {
320-
if (targetVariable->rangeEnd > maxRangeEndPair) {
322+
if (targetVariable->reg1 >= minIndex && targetVariable->reg2 >= minIndex
323+
&& targetVariable->rangeEnd > maxRangeEndPair) {
321324
maxRangeEndPair = targetVariable->rangeEnd;
322325
maxRangeIndexPair = i;
323326
}

test/jit/trycatch-dep.wast

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
(module
2+
(memory 1)
3+
4+
(tag $except0 (param i32 i64))
5+
(tag $except1 (param f32 f64))
6+
(tag $except3)
7+
8+
(func $throw1 (param i64)
9+
i32.const 1234
10+
local.get 0
11+
throw $except0
12+
)
13+
14+
(func $throw2 (param i64)
15+
f32.const 2345.0
16+
local.get 0
17+
f64.convert_i64_s
18+
throw $except1
19+
)
20+
21+
(func $throw3 (param i64)
22+
throw $except3
23+
)
24+
25+
(func (export "try1") (param i64) (result i64 i32) (local $l1 i64) (local $l2 i32)
26+
i32.const 123456
27+
local.set $l2
28+
(try
29+
(do
30+
(try
31+
(do
32+
local.get 0
33+
local.set $l1
34+
35+
local.get $l1
36+
i32.wrap_i64
37+
i32.const 100
38+
i32.add
39+
local.set $l2
40+
41+
i64.const 1000
42+
local.get $l1
43+
i64.lt_s
44+
if
45+
local.get $l1
46+
call $throw1
47+
end
48+
49+
local.get $l1
50+
i64.const 500
51+
i64.gt_s
52+
if
53+
local.get $l1
54+
call $throw2
55+
end
56+
57+
local.get $l1
58+
i64.const 250
59+
i64.gt_s
60+
if
61+
local.get $l1
62+
call $throw3
63+
end
64+
65+
local.get $l1
66+
i64.const 17
67+
i64.sub
68+
i32.const -678
69+
return
70+
)
71+
(catch $except0
72+
local.set $l1
73+
i64.extend_i32_s
74+
local.get $l1
75+
i64.add
76+
local.set $l1
77+
)
78+
)
79+
)
80+
(catch $except1
81+
i64.trunc_sat_f64_s
82+
local.set $l1
83+
84+
i64.trunc_sat_f32_s
85+
local.get $l1
86+
i64.add
87+
local.set $l1
88+
)
89+
(catch_all
90+
i64.const 888
91+
local.set $l1
92+
)
93+
)
94+
95+
local.get $l1
96+
local.get $l2
97+
)
98+
)
99+
100+
(assert_return (invoke "try1" (i64.const 99)) (i64.const 82) (i32.const -678))
101+
(assert_return (invoke "try1" (i64.const 2000)) (i64.const 3234) (i32.const 2100))
102+
(assert_return (invoke "try1" (i64.const 600)) (i64.const 2945) (i32.const 700))
103+
(assert_return (invoke "try1" (i64.const 300)) (i64.const 888) (i32.const 400))

0 commit comments

Comments
 (0)