-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
simple disjoint union perf optimization
Summary: Previously, an object type O1 was checked against a disjoint union by picking each object type O2 in the union and checking *all* properties of O2 in O1. Unfortunately, this approach was quite wasteful. (1) If the name of the sentinel property (whose type would be the main distinguishing factor across the union) came alphabetically towards the end, there would be a ton of work done before getting to that point, often including *more* union checks for recursively defined datatypes. (2) Usually, all but one case would fail simply by checking the sentinel property first, which means that most of the time the additional work done was actually useless! This diff guesses sentinel properties and ensures that they are checked first. This causes drastic perf improvements for even mid-sized recursive disjoint unions: e.g., for the linked issue below, check time goes from ~15s to ~0.5s. Fixes #2153 Reviewed By: bhosmer Differential Revision: D3646993 fbshipit-source-id: 65dbc9665e3b7757cc5c8537992fbf755818d463
- Loading branch information
1 parent
6be9ac3
commit 858ac40
Showing
7 changed files
with
908 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
[ignore] | ||
|
||
[include] | ||
|
||
[libs] | ||
|
||
[options] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
/** | ||
* @flow | ||
*/ | ||
|
||
export type InferredType = | ||
| 'unknown' | ||
| 'gender' | ||
| 'enum' | ||
| 'number-or-string' | ||
| 'number' | ||
| 'string' | ||
| 'error' | ||
; | ||
|
||
export type Pos = { | ||
firstLine: number, | ||
firstColumn: number, | ||
lastLine: number, | ||
lastColumn: number, | ||
}; | ||
|
||
export type TypedBinaryOpNode = { | ||
exprNodeType: 'binary_op', | ||
binaryOp: 'plus' | 'multiply' | 'divide' | 'minus', | ||
lhs: TypedNode, | ||
rhs: TypedNode, | ||
pos: Pos, | ||
exprType: InferredType, | ||
typed: true, | ||
} | ||
|
||
export type TypedUnaryMinusNode = { | ||
exprNodeType: 'unary_minus', | ||
op: TypedNode, | ||
pos: Pos, | ||
exprType: InferredType, | ||
typed: true, | ||
} | ||
|
||
export type TypedNumberNode = { | ||
exprNodeType: 'number', | ||
value: number, | ||
pos: Pos, | ||
exprType: 'number', | ||
typed: true, | ||
} | ||
|
||
export type TypedStringLiteralNode = { | ||
exprNodeType: 'string_literal', | ||
value: string, | ||
pos: Pos, | ||
exprType: 'string', | ||
typed: true, | ||
} | ||
|
||
export type TypedVariableNode = { | ||
exprNodeType: 'variable', | ||
name: string, | ||
pos: Pos, | ||
exprType: InferredType, | ||
typed: true, | ||
}; | ||
|
||
export type TypedFunctionInvocationNode = { | ||
exprNodeType: 'function_invocation', | ||
name: string, | ||
parameters: TypedNode[], | ||
pos: Pos, | ||
exprType: 'error' | 'string', | ||
typed: true, | ||
} | ||
|
||
export type TypedNode = | ||
| TypedBinaryOpNode | ||
| TypedUnaryMinusNode | ||
| TypedNumberNode | ||
| TypedStringLiteralNode | ||
| TypedVariableNode | ||
| TypedFunctionInvocationNode | ||
; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Found 0 errors |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/** | ||
* @flow | ||
*/ | ||
import * as t from './jsAst'; | ||
|
||
const b = t.builders; | ||
|
||
import type { | ||
TypedNode | ||
} from './ast'; | ||
|
||
function getBinaryOp(op: 'plus' | 'minus' | 'divide' | 'multiply') : '+' | '-' | '*' | '/' { | ||
switch (op) { | ||
case 'plus': | ||
return '+'; | ||
case 'minus': | ||
return '-'; | ||
case 'divide': | ||
return '/'; | ||
case 'multiply': | ||
return '*'; | ||
default: | ||
throw new Error('Invalid binary operator: ' + op); | ||
} | ||
} | ||
|
||
export function emitExpression(node: TypedNode) : t.Expression { | ||
switch (node.exprNodeType) { | ||
case 'string_literal': // FALLTHROUGH | ||
case 'number': | ||
return b.literal(node.value); | ||
case 'variable': | ||
return b.memberExpression( | ||
b.identifier('vars'), | ||
b.identifier(node.name), | ||
false | ||
); | ||
case 'binary_op': { | ||
const lhs = emitExpression(node.lhs); | ||
const rhs = emitExpression(node.rhs); | ||
|
||
const op = getBinaryOp(node.binaryOp); | ||
return b.binaryExpression(op, lhs, rhs); | ||
} | ||
case 'unary_minus': { | ||
const operand = emitExpression(node.op); | ||
return b.unaryExpression('-', operand, true); | ||
} | ||
case 'function_invocation': { | ||
const callee = b.memberExpression( | ||
b.identifier('fns'), | ||
b.identifier(node.name), | ||
false | ||
); | ||
|
||
const args = node.parameters.map( | ||
(n) => emitExpression(n) | ||
); | ||
|
||
return b.callExpression(callee, args); | ||
} | ||
default: | ||
throw new Error('Unknown expression type: ' + node.type); | ||
} | ||
} |
Oops, something went wrong.