diff --git a/compiler/il-structs.rkt b/compiler/il-structs.rkt index 3301803..e9b0537 100644 --- a/compiler/il-structs.rkt +++ b/compiler/il-structs.rkt @@ -201,11 +201,15 @@ #:transparent) +;; FIXME: it would be nice if I can reduce AssignImmediate and +;; AssignPrimOp into a single Assign statement, but I run into major +;; issues with Typed Racket taking minutes to compile. So we're +;; running into some kind of degenerate behavior. (define-struct: AssignImmediate ([target : Target] - [value : OpArg]) + [value : OpArg]) #:transparent) (define-struct: AssignPrimOp ([target : Target] - [op : PrimitiveOperator]) + [op : PrimitiveOperator]) #:transparent) @@ -328,8 +332,6 @@ (define-struct: ApplyPrimitiveProcedure () #:transparent) - - (define-struct: MakeBoxedEnvironmentValue ([depth : Natural]) #:transparent) diff --git a/js-assembler/assemble-open-coded.rkt b/js-assembler/assemble-open-coded.rkt index b6f2ffe..0213c40 100644 --- a/js-assembler/assemble-open-coded.rkt +++ b/js-assembler/assemble-open-coded.rkt @@ -11,6 +11,9 @@ (provide open-code-kernel-primitive-procedure) +;; Conservative estimate: JavaScript evaluators don't like to eat +;; more than some number of arguments at once. +(define MAX-JAVASCRIPT-ARGS-AT-ONCE 100) (: open-code-kernel-primitive-procedure (CallKernelPrimitiveProcedure Blockht -> String)) @@ -33,14 +36,18 @@ [(+) (cond [(empty? checked-operands) (assemble-numeric-constant 0)] + [(< (length operands) MAX-JAVASCRIPT-ARGS-AT-ONCE) + (format "RT.checkedAdd(M, ~a)" (string-join operands ","))] [else - (assemble-binop-chain "plt.baselib.numbers.add" checked-operands)])] + (format "RT.checkedAddSlowPath(M, [~a])" (string-join operands ","))])] [(-) (cond [(empty? (rest checked-operands)) (format "RT.checkedNegate(M, ~a)" (first operands))] + [(< (length operands) MAX-JAVASCRIPT-ARGS-AT-ONCE) + (format "RT.checkedSub(M, ~a)" (string-join operands ","))] [else - (assemble-binop-chain "plt.baselib.numbers.subtract" checked-operands)])] + (format "RT.checkedSubSlowPath(M, [~a])" (string-join operands ","))])] [(*) (cond [(empty? checked-operands) @@ -133,8 +140,6 @@ - - (: assemble-boolean-chain (String (Listof String) -> String)) (define (assemble-boolean-chain rator rands) (string-append "(" diff --git a/js-assembler/runtime-src/runtime.js b/js-assembler/runtime-src/runtime.js index 4f93f08..d849f21 100644 --- a/js-assembler/runtime-src/runtime.js +++ b/js-assembler/runtime-src/runtime.js @@ -833,6 +833,70 @@ testArgument(M, 'number', isNumber, n, 0, '-')); }; + var checkedAdd = function(M) { + var i; + var sum = 0; + for (i = 1; i < arguments.length; i++) { + if (typeof(arguments[i] === 'number')) { + sum += arguments[i]; + if (sum < -9e15 || sum > 9e15) { + return checkedAddSlowPath(M, Array.prototype.slice.call(arguments, 1)); + } + } else { + return checkedAddSlowPath(M, Array.prototype.slice.call(arguments, 1)); + } + } + return sum; + }; + + var checkedAddSlowPath = function(M, args) { + var i; + var sum = 0; + for (i = 0; i < args.length; i++) { + if (! isNumber(args[i])) { + raiseArgumentTypeError(M, '+', 'number', i, args[i]); + } + sum = plt.baselib.numbers.add(sum, args[i]); + } + return sum; + }; + + var checkedSub = function(M) { + // Assumption: at least two arguments to subtract. + var i; + if (typeof(arguments[1]) !== 'number') { + return checkedSubSlowPath(M, Array.prototype.slice.call(arguments, 1)); + } + var sum = arguments[1]; + for (i = 2; i < arguments.length; i++) { + if (typeof(arguments[i] === 'number')) { + sum -= arguments[i]; + if (sum < -9e15 || sum > 9e15) { + return checkedSubSlowPath(M, Array.prototype.slice.call(arguments, 1)); + } + } else { + return checkedSubSlowPath(M, Array.prototype.slice.call(arguments, 1)); + } + } + return sum; + }; + + var checkedSubSlowPath = function(M, args) { + var i; + if (! isNumber(args[0])) { + raiseArgumentTypeError(M, '-', 'number', 0, args[0]); + } + var sum = args[0]; + for (i = 1; i < args.length; i++) { + if (! isNumber(args[i])) { + raiseArgumentTypeError(M, '-', 'number', i, args[i]); + } + sum = plt.baselib.numbers.sub(sum, args[i]); + } + return sum; + }; + + var checkedCar = function(M, v) { if (isPair(v)) { return v.first; } raiseArgumentTypeError(M, 'car', 'pair', 0, v); @@ -983,6 +1047,10 @@ exports['checkedAdd1'] = checkedAdd1; exports['checkedSub1'] = checkedSub1; exports['checkedNegate'] = checkedNegate; + exports['checkedAdd'] = checkedAdd; + exports['checkedAddSlowPath'] = checkedAddSlowPath; + exports['checkedSub'] = checkedSub; + exports['checkedSubSlowPath'] = checkedSubSlowPath; exports['checkedCar'] = checkedCar; exports['checkedCdr'] = checkedCdr; }(this.plt, this.plt.baselib)); \ No newline at end of file diff --git a/version.rkt b/version.rkt index b83c1d9..fd81eb7 100644 --- a/version.rkt +++ b/version.rkt @@ -7,4 +7,4 @@ (provide version) (: version String) -(define version "1.150") +(define version "1.154")