Skip to content

Commit 02bbf9f

Browse files
committed
WIP: add top-down use-site coercions to asm.js.
1 parent 1613892 commit 02bbf9f

1 file changed

Lines changed: 87 additions & 32 deletions

File tree

‎asm-llvm.js‎

Lines changed: 87 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,34 @@ define([], function asm_llvm() {
259259
};
260260
test_types();
261261

262+
// ### Use-site coercions.
263+
// The different use types. This is top-down context for
264+
// expression parsing. (See the "Parser" section below.)
265+
var Use = {
266+
ToDouble: "ToDouble",
267+
ToInt: "ToInt",
268+
Void: "Void",
269+
NoCoercion: "NoCoercion" // usually works out to "ToInt" in practice
270+
};
271+
// Utility methods.
272+
var Uses = {
273+
toType: (function() {
274+
var map = Object.create(null);
275+
map[Use.ToDouble] = Type.Doublish;
276+
map[Use.ToInt] = Type.Intish;
277+
map[Use.Void] = Type.Void;
278+
// The map of NoCoercion to Intish differs from Mozilla;
279+
// we want to default to Intish so we don't have to lookahead
280+
// to parse the int-coercion suffix. We will fail typechecking
281+
// later if our assumption turns out to be mistaken.
282+
map[Use.NoCoercion] = Type.Intish;
283+
return function(use) {
284+
console.assert(map[use]);
285+
return map[use];
286+
};
287+
})()
288+
};
289+
262290
// ### Operator and standard library type tables.
263291

264292
// Unary operator types, from
@@ -278,6 +306,14 @@ define([], function asm_llvm() {
278306
'~~': Types.FunctionTypes(
279307
[ Types.Arrow([Types.Double], Types.Signed) ])
280308
};
309+
// Use-site coercions.
310+
Uses.unary = {
311+
'+': Use.ToDouble,
312+
'-': Use.ToDouble,
313+
'~': Use.ToInt,
314+
'~~': Use.ToInt,
315+
'!': Use.NoCoercion
316+
};
281317

282318
// Binary operator types, from
283319
// http://asmjs.org/spec/latest/#binary-operators
@@ -299,15 +335,25 @@ define([], function asm_llvm() {
299335
'>>>': Types.FunctionTypes(
300336
[ Types.Arrow([Types.Intish, Types.Intish], Types.Unsigned) ])
301337
};
338+
Uses.binary = {
339+
'+': Use.NoCoercion,
340+
'-': Use.NoCoercion,
341+
'*': Use.ToDouble,
342+
'/': Use.ToDouble,
343+
'%': Use.ToDouble,
344+
'>>>': Use.ToInt
345+
};
302346
['|','&','^','<<','>>'].forEach(function(op) {
303347
Types.binary[op] = Types.FunctionTypes(
304348
[ Types.Arrow([Types.Intish, Types.Intish], Types.Signed) ]);
349+
Uses.binary[op] = Use.ToInt;
305350
});
306351
['<','<=','>','>=','==','!='].forEach(function(op) {
307352
Types.binary[op] = Types.FunctionTypes(
308353
[ Types.Arrow([Types.Signed, Types.Signed], Types.Int),
309354
Types.Arrow([Types.Unsigned, Types.Unsigned], Types.Int),
310355
Types.Arrow([Types.Double, Types.Double], Types.Int) ]);
356+
Uses.binary[op] = Use.NoCoercion;
311357
});
312358

313359
// Standard library member types, from
@@ -1576,7 +1622,13 @@ define([], function asm_llvm() {
15761622
// precedence, for all of the ten binary precedence levels
15771623
// that JavaScript defines.
15781624
//
1625+
// Like the [SpiderMonkey asm.js parser][sm], we pass some coercion
1626+
// information top-down to allow single-pass type checking of
1627+
// call sites (including function table call sites). (Unlike
1628+
// SpiderMonkey, we do additive chain processing bottom-up.)
1629+
15791630
// [opp]: http://en.wikipedia.org/wiki/Operator-precedence_parser
1631+
// [sm]: https://hg.mozilla.org/mozilla-central/file/42bcb974cfdd/js/src/ion/AsmJS.cpp#l552
15801632

15811633
var parseTopLevel; // forward declaration
15821634

@@ -1770,7 +1822,7 @@ define([], function asm_llvm() {
17701822
}
17711823

17721824
if (allowEmpty && tokType === _comma) { elts.push(null); }
1773-
else { elts.push(parseExpression(true)); }
1825+
else { elts.push(parseExpression(true, Use.NoCoercion)); }
17741826
}
17751827
return elts;
17761828
};
@@ -1780,7 +1832,7 @@ define([], function asm_llvm() {
17801832
// `new`, or an expression wrapped in punctuation like `()`, `[]`,
17811833
// or `{}`.
17821834

1783-
var parseExprAtom = function() {
1835+
var parseExprAtom = function(use) {
17841836
if (tokType === _name) {
17851837
var id = parseIdent();
17861838
var binding = moduleLookup(id);
@@ -1800,7 +1852,7 @@ define([], function asm_llvm() {
18001852

18011853
} else if (tokType === _parenL) {
18021854
next();
1803-
var val = parseExpression();
1855+
var val = parseExpression(use);
18041856
expect(_parenR);
18051857
return val;
18061858

@@ -1844,6 +1896,8 @@ define([], function asm_llvm() {
18441896
} else if (property.andy) {
18451897
// Try to parse as a function table lookup:
18461898
// `x:Identifier[index:Expression & n:NumericLiteral](arg:Expression,...)`
1899+
1900+
//return TableBinding.New(basem
18471901
raise(startPos, "unimplemented");
18481902
} else {
18491903
raise(startPos, "bad member expression");
@@ -1852,13 +1906,13 @@ define([], function asm_llvm() {
18521906

18531907
// Parse call, dot, and `[]`-subscript expressions.
18541908

1855-
var parseSubscripts = function(base, noCalls) {
1909+
var parseSubscripts = function(base, use, noCalls) {
18561910
if (eat(_dot)) {
18571911
raise(lastStart, "operator not allowed: .");
18581912
} else if (eat(_bracketL)) {
18591913
base = parseBracketExpression(base);
18601914
expect(_bracketR);
1861-
return parseSubscripts(base, noCalls);
1915+
return parseSubscripts(base, use, noCalls);
18621916
} else if (!noCalls && eat(_parenL)) {
18631917
/* XXX handle base=ForwardRef */
18641918
var startPos = lastStart;
@@ -1883,17 +1937,17 @@ define([], function asm_llvm() {
18831937
} else {
18841938
raise(startPos, "bad call expression");
18851939
}
1886-
return parseSubscripts(binding, noCalls);
1940+
return parseSubscripts(binding, use, noCalls);
18871941
} else { return base; }
18881942
};
18891943

1890-
var parseExprSubscripts = function() {
1891-
return parseSubscripts(parseExprAtom());
1944+
var parseExprSubscripts = function(use) {
1945+
return parseSubscripts(parseExprAtom(use), use);
18921946
};
18931947

18941948
// Parse unary operators, both prefix and postfix.
18951949

1896-
function parseMaybeUnary(noIn) {
1950+
function parseMaybeUnary(use) {
18971951
var node;
18981952
if (tokType.prefix) {
18991953
var opPos = tokStart;
@@ -1905,7 +1959,7 @@ define([], function asm_llvm() {
19051959
}
19061960
console.assert(!update);
19071961
next();
1908-
var argument = parseMaybeUnary(noIn);
1962+
var argument = parseMaybeUnary(Uses.unary[operator]);
19091963
// Special case the negation of a constant.
19101964
if (ConstantBinding.hasInstance(argument) && operator==='-') {
19111965
return argument.negate();
@@ -1917,7 +1971,7 @@ define([], function asm_llvm() {
19171971
}
19181972
return TempBinding.New(ty);
19191973
}
1920-
var expr = parseExprSubscripts();
1974+
var expr = parseExprSubscripts(use);
19211975
if (tokType.postfix && !canInsertSemicolon()) {
19221976
raise(tokStart, "postfix operators not allowed");
19231977
}
@@ -1933,11 +1987,11 @@ define([], function asm_llvm() {
19331987
// defer further parser to one of its callers when it encounters an
19341988
// operator that has a lower precedence than the set it is parsing.
19351989

1936-
var parseExprOp = function(left, minPrec, noIn) {
1990+
var parseExprOp = function(left, minPrec, use) {
19371991
var TWO_TO_THE_TWENTY = 0x100000;
19381992
var prec = tokType.binop;
19391993
console.assert(prec !== null, tokType);
1940-
if (prec !== undefined && (!noIn || tokType !== _in)) {
1994+
if (prec !== undefined) {
19411995
if (prec > minPrec) {
19421996
var additiveChain = 0;
19431997
var opPos = tokStart;
@@ -1946,8 +2000,9 @@ define([], function asm_llvm() {
19462000
if (!ty) {
19472001
raise(opPos, operator+" not allowed");
19482002
}
2003+
use = Uses.binary[operator];//XXXX probably wrong
19492004
next();
1950-
var right = parseExprOp(parseMaybeUnary(noIn), prec, noIn);
2005+
var right = parseExprOp(parseMaybeUnary(use), prec, use);
19512006
ty = ty.apply([left.type, right.type]);
19522007
if (ty===null && (operator==='+' || operator==='-')) {
19532008
/* Special validation for "AdditiveExpression" */
@@ -2001,27 +2056,27 @@ define([], function asm_llvm() {
20012056
binding.andAmount = right.value;
20022057
}
20032058
}
2004-
return parseExprOp(binding, minPrec, noIn);
2059+
return parseExprOp(binding, minPrec, use);
20052060
}
20062061
}
20072062
return left;
20082063
};
20092064

2010-
var parseExprOps = function(noIn) {
2011-
return parseExprOp(parseMaybeUnary(noIn), -1, noIn);
2065+
var parseExprOps = function(use) {
2066+
return parseExprOp(parseMaybeUnary(use), -1, use);
20122067
};
20132068

20142069
// Parse a ternary conditional (`?:`) operator.
20152070

2016-
var parseMaybeConditional = function(noIn) {
2017-
var expr = parseExprOps(noIn);
2071+
var parseMaybeConditional = function(use) {
2072+
var expr = parseExprOps(use);
20182073
var startPos = tokStart;
20192074
if (eat(_question)) {
20202075
var test = expr;
20212076
typecheck(test.type, Types.Int, "conditional test", startPos);
20222077
var consequent = parseExpression(true);
20232078
expect(_colon);
2024-
var alternate = parseExpression(true, noIn);
2079+
var alternate = parseExpression(true, use);
20252080
var ty;
20262081
if (consequent.type.isSubtypeOf(Types.Int) &&
20272082
alternate.type.isSubtypeOf(Types.Int)) {
@@ -2044,16 +2099,16 @@ define([], function asm_llvm() {
20442099
// Parse an assignment expression. This includes applications of
20452100
// operators like `+=`.
20462101

2047-
var parseMaybeAssign = function(noIn) {
2048-
var left = parseMaybeConditional(noIn);
2102+
var parseMaybeAssign = function(use) {
2103+
var left = parseMaybeConditional(use);
20492104
if (tokType.isAssign) {
20502105
var startPos = tokStart;
20512106
var operator = tokVal;
20522107
if (operator !== '=') {
20532108
raise(startPos, "Operator disallowed: "+operator);
20542109
}
20552110
next();
2056-
var right = parseMaybeAssign(noIn);
2111+
var right = parseMaybeAssign(use);
20572112
// Check that `left` is an lval. First, let's check
20582113
// the `x:Identifier = ...` case.
20592114
if (LocalBinding.hasInstance(left)) {
@@ -2081,12 +2136,12 @@ define([], function asm_llvm() {
20812136
// sequences (in argument lists, array literals, or object literals)
20822137
// or the `in` operator (in for loops initalization expressions).
20832138

2084-
parseExpression = function(noComma, noIn) {
2085-
var expr = parseMaybeAssign(noIn);
2139+
parseExpression = function(noComma, use) {
2140+
var expr = parseMaybeAssign(use);
20862141
if (!noComma && tokType === _comma) {
20872142
var expressions = [expr];
20882143
while (eat(_comma)) {
2089-
expressions.push(expr = parseMaybeAssign(noIn));
2144+
expressions.push(expr = parseMaybeAssign(use));
20902145
}
20912146
}
20922147
return expr;
@@ -2095,9 +2150,9 @@ define([], function asm_llvm() {
20952150
// Used for constructs like `switch` and `if` that insist on
20962151
// parentheses around their expression.
20972152

2098-
var parseParenExpression = function() {
2153+
var parseParenExpression = function(use) {
20992154
expect(_parenL);
2100-
var val = parseExpression();
2155+
var val = parseExpression(use);
21012156
expect(_parenR);
21022157
return val;
21032158
};
@@ -2154,7 +2209,7 @@ define([], function asm_llvm() {
21542209
// Parse a while loop.
21552210
next();
21562211
startPos = tokStart;
2157-
var whileTest = parseParenExpression();
2212+
var whileTest = parseParenExpression(Use.NoCoercion);
21582213
typecheck(whileTest.type, Types.Int, "while loop condition",
21592214
startPos);
21602215
module.func.labels.push(loopLabel);
@@ -2170,7 +2225,7 @@ define([], function asm_llvm() {
21702225
module.func.labels.pop();
21712226
expect(_while);
21722227
startPos = tokStart;
2173-
var doTest = parseParenExpression();
2228+
var doTest = parseParenExpression(Use.NoCoercion);
21742229
semicolon();
21752230
typecheck(doTest.type, Types.Int, "do-while loop condition",
21762231
startPos);
@@ -2194,7 +2249,7 @@ define([], function asm_llvm() {
21942249
} else if (starttype===_if) {
21952250
next();
21962251
startPos = tokStart;
2197-
var ifTest = parseParenExpression();
2252+
var ifTest = parseParenExpression(Use.NoCoercion);
21982253
typecheck(ifTest.type, Types.Int, "if statement condition",
21992254
startPos);
22002255
var consequent = parseStatement();
@@ -2225,7 +2280,7 @@ define([], function asm_llvm() {
22252280
} else if (starttype===_switch) {
22262281
next();
22272282
startPos = tokStart;
2228-
var switchTest = parseParenExpression();
2283+
var switchTest = parseParenExpression(Use.NoCoercion);
22292284
typecheck(switchTest, Types.Signed, "switch discriminant",
22302285
startPos);
22312286
var cases = [];

0 commit comments

Comments
 (0)