thunk.js 4.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. "use strict"
  2. // The function below is called when constructing a cwise function object, and does the following:
  3. // A function object is constructed which accepts as argument a compilation function and returns another function.
  4. // It is this other function that is eventually returned by createThunk, and this function is the one that actually
  5. // checks whether a certain pattern of arguments has already been used before and compiles new loops as needed.
  6. // The compilation passed to the first function object is used for compiling new functions.
  7. // Once this function object is created, it is called with compile as argument, where the first argument of compile
  8. // is bound to "proc" (essentially containing a preprocessed version of the user arguments to cwise).
  9. // So createThunk roughly works like this:
  10. // function createThunk(proc) {
  11. // var thunk = function(compileBound) {
  12. // var CACHED = {}
  13. // return function(arrays and scalars) {
  14. // if (dtype and order of arrays in CACHED) {
  15. // var func = CACHED[dtype and order of arrays]
  16. // } else {
  17. // var func = CACHED[dtype and order of arrays] = compileBound(dtype and order of arrays)
  18. // }
  19. // return func(arrays and scalars)
  20. // }
  21. // }
  22. // return thunk(compile.bind1(proc))
  23. // }
  24. var compile = require("./compile.js")
  25. function createThunk(proc) {
  26. var code = ["'use strict'", "var CACHED={}"]
  27. var vars = []
  28. var thunkName = proc.funcName + "_cwise_thunk"
  29. //Build thunk
  30. code.push(["return function ", thunkName, "(", proc.shimArgs.join(","), "){"].join(""))
  31. var typesig = []
  32. var string_typesig = []
  33. var proc_args = [["array",proc.arrayArgs[0],".shape.slice(", // Slice shape so that we only retain the shape over which we iterate (which gets passed to the cwise operator as SS).
  34. Math.max(0,proc.arrayBlockIndices[0]),proc.arrayBlockIndices[0]<0?(","+proc.arrayBlockIndices[0]+")"):")"].join("")]
  35. var shapeLengthConditions = [], shapeConditions = []
  36. // Process array arguments
  37. for(var i=0; i<proc.arrayArgs.length; ++i) {
  38. var j = proc.arrayArgs[i]
  39. vars.push(["t", j, "=array", j, ".dtype,",
  40. "r", j, "=array", j, ".order"].join(""))
  41. typesig.push("t" + j)
  42. typesig.push("r" + j)
  43. string_typesig.push("t"+j)
  44. string_typesig.push("r"+j+".join()")
  45. proc_args.push("array" + j + ".data")
  46. proc_args.push("array" + j + ".stride")
  47. proc_args.push("array" + j + ".offset|0")
  48. if (i>0) { // Gather conditions to check for shape equality (ignoring block indices)
  49. shapeLengthConditions.push("array" + proc.arrayArgs[0] + ".shape.length===array" + j + ".shape.length+" + (Math.abs(proc.arrayBlockIndices[0])-Math.abs(proc.arrayBlockIndices[i])))
  50. shapeConditions.push("array" + proc.arrayArgs[0] + ".shape[shapeIndex+" + Math.max(0,proc.arrayBlockIndices[0]) + "]===array" + j + ".shape[shapeIndex+" + Math.max(0,proc.arrayBlockIndices[i]) + "]")
  51. }
  52. }
  53. // Check for shape equality
  54. if (proc.arrayArgs.length > 1) {
  55. code.push("if (!(" + shapeLengthConditions.join(" && ") + ")) throw new Error('cwise: Arrays do not all have the same dimensionality!')")
  56. code.push("for(var shapeIndex=array" + proc.arrayArgs[0] + ".shape.length-" + Math.abs(proc.arrayBlockIndices[0]) + "; shapeIndex-->0;) {")
  57. code.push("if (!(" + shapeConditions.join(" && ") + ")) throw new Error('cwise: Arrays do not all have the same shape!')")
  58. code.push("}")
  59. }
  60. // Process scalar arguments
  61. for(var i=0; i<proc.scalarArgs.length; ++i) {
  62. proc_args.push("scalar" + proc.scalarArgs[i])
  63. }
  64. // Check for cached function (and if not present, generate it)
  65. vars.push(["type=[", string_typesig.join(","), "].join()"].join(""))
  66. vars.push("proc=CACHED[type]")
  67. code.push("var " + vars.join(","))
  68. code.push(["if(!proc){",
  69. "CACHED[type]=proc=compile([", typesig.join(","), "])}",
  70. "return proc(", proc_args.join(","), ")}"].join(""))
  71. if(proc.debug) {
  72. console.log("-----Generated thunk:\n" + code.join("\n") + "\n----------")
  73. }
  74. //Compile thunk
  75. var thunk = new Function("compile", code.join("\n"))
  76. return thunk(compile.bind(undefined, proc))
  77. }
  78. module.exports = createThunk