(6) SlotStackMisaligned.patch
CodeGeneratorLexicalContext#pop() must only decrease "nextFreeSlotSize"
for a given node when #nextFreeSlot() has been called for that node.
- pop() without nextFreeSlot() happens for anonymous function
expressions which are copied in finally blocks, see early return in
CodeGenerator#enterBlock(). Named function expressions don't show this
bug because they are assigned new names for each copy. Yes, that means
named function expressions (and function declarations) which are copied
due to finally-inlining are generated multiple times in the class file...
test case:
function f(a) { try {} catch(x1 if (function(){})()) {} finally { try {}
catch(y if (function(){})()) {} catch(x3 if (x3)) {} } }
- André
On 10/15/2013 1:16 PM, André Bargull wrote:
(5) EnforceObjectTypeForNull.patch
This one looks like a bug in asm's frame computation, adding a
`checkcast` instruction makes sure things work as expected...
test cases:
function f(){ try { var x = 1, x = null; } catch(x2) {} }
function f(){ try { var x = 1; x = null; } catch(x2) {} return x }
- André
On 10/15/2013 10:45 AM, André Bargull wrote:
I've needed to apply the following patches to continue fuzzing. If
those changes look reasonable, can someone make sure they get into
the upstream repo?
- André
(1) IncompatibleAssignmentCoercion.patch:
`Type.widest(Type, Type)` can promote boolean -> number, or number ->
string. This is not wanted for (?:) - ConditionalExpressions or
ReturnStatements. Added a new uncoercedWidest(Type, Type) method to
Attr which makes sure only valid promotions are applied.
test cases:
/* no verify error */ function f1(c,x){ c (x ? [1] : 1); }
function f2(c,x){ c = (x ? "123" : 1); return c }
typeof f2(null,true) === "string"
typeof f2(null,false) === "number"
function f3(v){if (v) return 123; else return true}
f3(true) === 123
f3(false) === true
(2) JDK-8026249-WidenDISCARD.patch:
The left-hand side of a BinaryNode does not have a Type if it is a
Discard node, that means `lhs.getType()` may throw an assertion
error. Moving the Type.widest() calls makes sure `lhs.getType()` is
only called when it is safe to do.
test case:
/* no assertion */ function f() { if(x3, y) x; }
(3) JDK-8026249-EnsureTypeDiscard.patch:
The type for a CommaRight BinaryNode is based on the right-hand
side's type, make sure the RHS always has a proper type attached.
[I've also fixed this for CommaLeft, but that one isn't actually
used, is it?]
test case:
/* no assertion */ function f(x) { return y, x }
(4) JDK-8026249-ControlFlowEscape.patch:
Control flow may escape from SwitchNode or LabelNode through `break`
or `continue` statements. Simply moving the "controlFlowEscapes"
logic from LoopNode to BreakableStatement solves the SwitchNode
issue. And for LabelNode just clear the "terminal" on its body node.
test cases:
/* no verify error / NPE */ function f() { L: { try { return 1; }
finally { break L; }} }
/* no verify error / NPE */ function f() { L: { if (v) break L;
return} }
/* no verify error / NPE */ function f() { L: {{ break L; } return; } }
/* no verify error / NPE */ function f() { L: { if (x2) { break L; }
throw x; } }
/* no verify error / NPE */ function f() { switch(v) { default: if(v)
break; return; } }
/* no verify error / NPE */ function f() { switch(x) { default:
if(true) break; return; } }
/* no verify error / NPE */ function f() { switch(x) { default: L:
break; return; } }
diff --git a/src/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java
b/src/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java
--- a/src/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java
+++ b/src/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java
@@ -70,6 +70,9 @@
/** size of next free slot vector */
private int nextFreeSlotsSize;
+ /** Stack tracking the currently active blocks */
+ private Deque<Block> blocks = new ArrayDeque<>();
+
@Override
public <T extends LexicalContextNode> T push(final T node) {
if (isDynamicScopeBoundary(node)) {
@@ -84,7 +87,9 @@
if (isDynamicScopeBoundary(popped)) {
--dynamicScopeCount;
}
- if (node instanceof Block) {
+ if (node instanceof Block && blocks.peek() == node) {
+ assert nextFreeSlotsSize > 0;
+ blocks.pop();
--nextFreeSlotsSize;
}
return popped;
@@ -200,6 +205,7 @@
nextFreeSlots = newNextFreeSlots;
}
nextFreeSlots[nextFreeSlotsSize++] = assignSlots(block, nextFreeSlot);
+ blocks.push(block);
}
private static int assignSlots(final Block block, final int firstSlot) {