Skip to content

Commit

Permalink
[SPARK-16845][SQL][BRANCH-1.6] GeneratedClass$SpecificOrdering` grows…
Browse files Browse the repository at this point in the history
… beyond 64 KB

## What changes were proposed in this pull request?

This is a backport pr of apache#15480 into `branch-1.6`.

## How was this patch tested?

Existing tests.

Author: Liwei Lin <[email protected]>

Closes apache#17158 from ueshin/issues/SPARK-16845_1.6.
  • Loading branch information
lw-lin authored and cloud-fan committed Mar 6, 2017
1 parent a50ef3d commit 23f9faa
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,27 @@ class CodeGenContext {
* @param expressions the codes to evaluate expressions.
*/
def splitExpressions(row: String, expressions: Seq[String]): String = {
splitExpressions(expressions, "apply", ("InternalRow", row) :: Nil)
}

/**
* Splits the generated code of expressions into multiple functions, because function has
* 64kb code size limit in JVM
*
* @param expressions the codes to evaluate expressions.
* @param funcName the split function name base.
* @param arguments the list of (type, name) of the arguments of the split function.
* @param returnType the return type of the split function.
* @param makeSplitFunction makes split function body, e.g. add preparation or cleanup.
* @param foldFunctions folds the split function calls.
*/
def splitExpressions(
expressions: Seq[String],
funcName: String,
arguments: Seq[(String, String)],
returnType: String = "void",
makeSplitFunction: String => String = identity,
foldFunctions: Seq[String] => String = _.mkString("", ";\n", ";")): String = {
val blocks = new ArrayBuffer[String]()
val blockBuilder = new StringBuilder()
for (code <- expressions) {
Expand All @@ -380,19 +401,20 @@ class CodeGenContext {
// inline execution if only one block
blocks.head
} else {
val apply = freshName("apply")
val func = freshName(funcName)
val argString = arguments.map { case (t, name) => s"$t $name" }.mkString(", ")
val functions = blocks.zipWithIndex.map { case (body, i) =>
val name = s"${apply}_$i"
val name = s"${func}_$i"
val code = s"""
|private void $name(InternalRow $row) {
| $body
|private $returnType $name($argString) {
| ${makeSplitFunction(body)}
|}
""".stripMargin
addNewFunction(name, code)
name
}

functions.map(name => s"$name($row);").mkString("\n")
foldFunctions(functions.map(name => s"$name(${arguments.map(_._2).mkString(", ")})"))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,31 @@ object GenerateOrdering extends CodeGenerator[Seq[SortOrder], Ordering[InternalR
}
}
"""
}.mkString("\n")
comparisons
}

ctx.splitExpressions(
expressions = comparisons,
funcName = "compare",
arguments = Seq(("InternalRow", "a"), ("InternalRow", "b")),
returnType = "int",
makeSplitFunction = { body =>
s"""
InternalRow ${ctx.INPUT_ROW} = null; // Holds current row being evaluated.
$body
return 0;
"""
},
foldFunctions = { funCalls =>
funCalls.zipWithIndex.map { case (funCall, i) =>
val comp = ctx.freshName("comp")
s"""
int $comp = $funCall;
if ($comp != 0) {
return $comp;
}
"""
}.mkString
})
}

protected def create(ordering: Seq[SortOrder]): BaseOrdering = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,14 @@ class OrderingSuite extends SparkFunSuite with ExpressionEvalHelper {
}
}
}

test("SPARK-16845: GeneratedClass$SpecificOrdering grows beyond 64 KB") {
val sortOrder = Literal("abc").asc

// this is passing prior to SPARK-16845, and it should also be passing after SPARK-16845
GenerateOrdering.generate(Array.fill(40)(sortOrder))

// verify that we can support up to 5000 ordering comparisons, which should be sufficient
GenerateOrdering.generate(Array.fill(5000)(sortOrder))
}
}

0 comments on commit 23f9faa

Please sign in to comment.