diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_code.py b/graalpython/com.oracle.graal.python.test/src/tests/test_code.py index 3e85b1eb51..6e78575bfc 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_code.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_code.py @@ -226,16 +226,17 @@ def g(): x = g() assert g.__code__ is x.gi_code -def dedup(lst, prev=object()): - for item in lst: - if item != prev: - yield item - prev = item - def check_lines(func): co = func.__code__ - lines = [line for _, _, line in co.co_lines()] - assert lines == list(dedup(lines)) + prev_line = object() # None is a valid line value. + prev_end = 0 + for start, end, line in co.co_lines(): + assert start <= end + assert line != prev_line + assert line is None or line > 0 + assert prev_end == start + prev_line = line + prev_end = end def test_check_lines_dedup(): def misshappen(): @@ -277,8 +278,11 @@ def bug93662(): ).strip() raise ValueError() + def singleline(): return 42 + check_lines(misshappen) check_lines(bug93662) + check_lines(singleline) def test_code_identity(): diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/CodeBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/CodeBuiltins.java index c409ab4877..dbf62ab8f0 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/CodeBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/CodeBuiltins.java @@ -462,7 +462,7 @@ private static void traverseSourceInformationTree(SourceInformationTree tree, Li /** * The bci ranges in the triples are not stable and can change when the bytecode is * instrumented. We create new triples with stable instruction indices by walking the - * instructions. + * instructions. We also coalesce triples with the same line numbers. */ private static List convertTripleBcisToInstructionIndices(BytecodeNode bytecodeNode, PythonLanguage language, List triples) { List result = new ArrayList<>(triples.size()); @@ -472,32 +472,33 @@ private static List convertTripleBcisToInstructionIndices(BytecodeNode b int startInstructionIndex = 0; int instructionIndex = 0; - boolean rangeHasInstruction = false; - int lastTripleLine = -1; + int pendingLine = triple[2]; + for (Instruction instruction : bytecodeNode.getInstructions()) { + // Iterate the instructions, counting the stable instruction index as we go. if (instruction.getBytecodeIndex() == triple[1] /* end bci */) { - if (lastTripleLine != triple[2]) { - if (rangeHasInstruction) { - result.add(PFactory.createTuple(language, new int[]{startInstructionIndex, instructionIndex, triple[2]})); - lastTripleLine = triple[2]; - } - startInstructionIndex = instructionIndex; - } + // We hit the end of the current triple. Continue with the next one. triple = triples.get(++tripleIndex); assert triple[0] == instruction.getBytecodeIndex() : "bytecode ranges should be consecutive"; - rangeHasInstruction = false; + // If this new triple has a different line, emit a tuple for the previous line. + // Otherwise, continue (this new triple's range is combined with the previous). + if (pendingLine != triple[2] /* line */) { + result.add(PFactory.createTuple(language, new int[]{startInstructionIndex, instructionIndex, pendingLine})); + startInstructionIndex = instructionIndex; + pendingLine = triple[2]; + } } if (!instruction.isInstrumentation()) { // Emulate CPython's fixed 2-word instructions. instructionIndex += 2; - rangeHasInstruction = true; } } - result.add(PFactory.createTuple(language, new int[]{startInstructionIndex, instructionIndex, triple[2]})); + // Emit a tuple for the remaining range. + result.add(PFactory.createTuple(language, new int[]{startInstructionIndex, instructionIndex, pendingLine})); assert tripleIndex == triples.size() - 1 : String.format("every bytecode range should have been converted to " + - "an instruction range, %d != %d, function: %s", tripleIndex, triples.size(), bytecodeNode.getRootNode()); + "an instruction range, %d != %d, function: %s", tripleIndex, triples.size() - 1, bytecodeNode.getRootNode()); return result; }