Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1070)

Unified Diff: lib/compiler/implementation/ssa/codegen.dart

Issue 10697031: Generate JS operators using helper functions with thunks for operands. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address review comments. Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | lib/compiler/implementation/ssa/codegen_helpers.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/compiler/implementation/ssa/codegen.dart
diff --git a/lib/compiler/implementation/ssa/codegen.dart b/lib/compiler/implementation/ssa/codegen.dart
index 145761d9419a02556bf47bbec9a9c78c541fdad4..e166566a22a53b24078e8171f9842244cbd40d45 100644
--- a/lib/compiler/implementation/ssa/codegen.dart
+++ b/lib/compiler/implementation/ssa/codegen.dart
@@ -273,15 +273,87 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
}
}
- void withPrecedence(int precedence, void action()) {
+ /**
+ * Adds parenthes around the code generated by [body] if necessary.
+ * The precedence level of the body is assumed to be [precedence].
+ */
+ void parenthesize(int precedence, void body()) {
int oldPrecedence = expectedPrecedence;
beginExpression(precedence);
+ // Raise the expected precedence-level to what the body expects.
expectedPrecedence = precedence;
- action();
+ body();
expectedPrecedence = oldPrecedence;
endExpression(precedence);
}
+ void withPrecedence(int precedence, void action()) {
+ int oldPrecedence = expectedPrecedence;
+ expectedPrecedence = precedence;
+ action();
+ expectedPrecedence = oldPrecedence;
+ }
+
+ /**
+ * Generates code for a JavaScript binary operator.
+ * The code is parenthesized if necessary, and the expected
+ * precedence level of the left- and right-hand sides is set,
+ * based on the operator.
+ */
+ void binary(String operator, void lhs(), void rhs()) {
+ JSBinaryOperatorPrecedence op = JSPrecedence.binary[operator];
+ beginExpression(op.precedence);
+ withPrecedence(op.left, lhs);
+ buffer.add(' ');
+ buffer.add(operator);
+ buffer.add(' ');
+ withPrecedence(op.right, rhs);
+ endExpression(op.precedence);
+ }
+
+ /**
+ * Generate code for a JavaScript postfix operator (only -- and ++
+ * exist).
+ */
+ void PostfixExpression(String operator, void body()) {
+ // Corresponds to a JavaScript production of the form (ES5 11.3):
+ // PostfixExpression ::= LeftHandSideExpression <operator>
+ beginExpression(JSPrecedence.POSTFIX_PRECEDENCE);
+ withPrecedence(JSPrecedence.CALL_PRECEDENCE, body);
+ buffer.add(operator);
+ endExpression(JSPrecedence.PSOTFIX_PRECEDENCE);
+ }
+
+ /**
+ * Generate code for a JavaScript prefix operator.
+ * There are no validation on the operator text. If it is a "word"
+ * operator (e.g., "typeof" or "void") the caller should put in a
+ * trailing space if necessary to delimit it from the following
+ * expression.
+ */
+ void prefix(String operator, void body()) {
+ // Corresponds to a JavaScript production of the form (ES5 11.4):
+ // UnaryExpression ::= <operator> UnaryExpression
+ beginExpression(JSPrecedence.PREFIX_PRECEDENCE);
+ buffer.add(operator);
+ withPrecedence(JSPrecedence.PREFIX_PRECEDENCE, body);
+ endExpression(JSPrecedence.PREFIX_PRECEDENCE);
+ }
+
+ void conditional(void condition(), [void ifTrue(), void ifFalse()]) {
+ beginExpression(JSPrecedence.CONDITIONAL_PRECEDENCE);
+ withPrecedence(JSPrecedence.LOGICAL_OR_PRECEDENCE, condition);
+ buffer.add(" ? ");
+ withPrecedence(JSPrecedence.ASSIGNMENT_PRECEDENCE, ifTrue);
+ buffer.add(" : ");
+ withPrecedence(JSPrecedence.ASSIGNMENT_PRECEDENCE, ifFalse);
+ endExpression(JSPrecedence.CONDITIONAL_PRECEDENCE);
+ }
+
+ void literal(String text) {
+ buffer.add(text);
+ }
+
void preGenerateMethod(HGraph graph) {
new SsaInstructionMerger(generateAtUseSite).visitGraph(graph);
new SsaConditionMerger(generateAtUseSite,
@@ -570,22 +642,14 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
rightIsOne = (numConstant.value == 1);
}
if (binaryInstruction is HAdd && rightIsOne) {
- beginExpression(JSPrecedence.PREFIX_PRECEDENCE);
- buffer.add('++');
- declareVariable(name);
- endExpression(JSPrecedence.PREFIX_PRECEDENCE);
+ prefix('++', () => declareVariable(name));
} else if (binaryInstruction is HSubtract && rightIsOne) {
- beginExpression(JSPrecedence.PREFIX_PRECEDENCE);
- buffer.add('--');
- declareVariable(name);
- endExpression(JSPrecedence.PREFIX_PRECEDENCE);
+ prefix("--", () => declareVariable(name));
} else {
var operation = binaryInstruction.operation.name;
- beginExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE);
- declareVariable(name);
- buffer.add(' ${operation}= ');
- use(right, JSPrecedence.ASSIGNMENT_PRECEDENCE);
- endExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE);
+ binary('$operation=',
+ () => declareVariable(name),
+ () => use(right, expectedPrecedence));
}
return true;
}
@@ -615,11 +679,9 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
var name = variableNames.getName(instruction);
if (!handleSimpleUpdateDefinition(instruction, name)
&& !handleTypeConversion(instruction, name)) {
- withPrecedence(JSPrecedence.ASSIGNMENT_PRECEDENCE, () {
- declareInstruction(instruction);
- buffer.add(" = ");
- visit(instruction, JSPrecedence.ASSIGNMENT_PRECEDENCE);
- });
+ binary("=",
+ () => declareInstruction(instruction),
+ () => visit(instruction, expectedPrecedence));
}
} else {
visit(instruction, expectedPrecedence);
@@ -1165,12 +1227,9 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
visitInvokeBinary(HInvokeBinary node, String op) {
if (node.builtin) {
- JSBinaryOperatorPrecedence operatorPrecedences = JSPrecedence.binary[op];
- beginExpression(operatorPrecedences.precedence);
- use(node.left, operatorPrecedences.left);
- buffer.add(' $op ');
- use(node.right, operatorPrecedences.right);
- endExpression(operatorPrecedences.precedence);
+ binary(op,
+ () => use(node.left, expectedPrecedence),
+ () => use(node.right, expectedPrecedence));
} else {
visitInvokeStatic(node);
}
@@ -1180,13 +1239,9 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
// shift operator to achieve this.
visitBitInvokeBinary(HBinaryBitOp node, String op) {
if (node.builtin && requiresUintConversion(node)) {
- beginExpression(unsignedShiftPrecedences.precedence);
- int oldPrecedence = this.expectedPrecedence;
- this.expectedPrecedence = JSPrecedence.SHIFT_PRECEDENCE;
- visitInvokeBinary(node, op);
- buffer.add(' >>> 0');
- this.expectedPrecedence = oldPrecedence;
- endExpression(unsignedShiftPrecedences.precedence);
+ binary(">>>",
+ () => visitInvokeBinary(node, op),
+ () => literal("0"));
} else {
visitInvokeBinary(node, op);
}
@@ -1194,10 +1249,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
visitInvokeUnary(HInvokeUnary node, String op) {
if (node.builtin) {
- beginExpression(JSPrecedence.PREFIX_PRECEDENCE);
- buffer.add('$op');
- use(node.operand, JSPrecedence.PREFIX_PRECEDENCE);
- endExpression(JSPrecedence.PREFIX_PRECEDENCE);
+ prefix(op, () => use(node.operand, expectedPrecedence));
} else {
visitInvokeStatic(node);
}
@@ -1206,14 +1258,10 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
// We want the outcome of bit-operations to be positive. We use the unsigned
// shift operator to achieve this.
visitBitInvokeUnary(HInvokeUnary node, String op) {
- if (node.builtin && requiresUintConversion(node)) {
- beginExpression(unsignedShiftPrecedences.precedence);
- int oldPrecedence = this.expectedPrecedence;
- this.expectedPrecedence = JSPrecedence.SHIFT_PRECEDENCE;
- visitInvokeUnary(node, op);
- buffer.add(' >>> 0');
- this.expectedPrecedence = oldPrecedence;
- endExpression(unsignedShiftPrecedences.precedence);
+ if (node.builtin && requiresUintConversion(node)){
+ binary(">>>",
+ () => visitInvokeUnary(node, op),
+ () => literal("0"));
} else {
visitInvokeUnary(node, op);
}
@@ -1225,40 +1273,32 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
if (leftType.canBeNull() && rightType.canBeNull()) {
if (left.isConstantNull() || right.isConstantNull() ||
(leftType.isPrimitive() && leftType == rightType)) {
- beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- use(left, JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add(' == ');
- use(right, JSPrecedence.RELATIONAL_PRECEDENCE);
- endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
+ binary("==",
+ () => use(left, expectedPrecedence),
+ () => use(right, expectedPrecedence));
} else {
assert(NullConstant.JsNull == 'null');
- withPrecedence(JSPrecedence.CONDITIONAL_PRECEDENCE, () {
- beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- use(left, JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add(' == null');
- endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add(' ? ');
- this.expectedPrecedence = JSPrecedence.ASSIGNMENT_PRECEDENCE;
- withPrecedence(JSPrecedence.LOGICAL_AND_PRECEDENCE, () {
- beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- use(right, JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add(' == null');
- endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add(" : ");
- beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- use(left, JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add(' === ');
- use(right, JSPrecedence.EQUALITY_PRECEDENCE);
- endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- });
- });
+ void condition() {
+ binary("==",
+ () => use(left, expectedPrecedence),
+ () => literal("null"));
+ }
+ void ifTrue() {
+ binary("==",
+ () => use(right, expectedPrecedence),
+ () => literal("null"));
+ }
+ void ifFalse() {
+ binary("===",
+ () => use(left, expectedPrecedence),
+ () => use(right, expectedPrecedence));
+ }
+ conditional(condition, ifTrue, ifFalse);
}
} else {
- beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- use(left, JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add(' === ');
- use(right, JSPrecedence.RELATIONAL_PRECEDENCE);
- endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
+ binary("===",
+ () => use(left, expectedPrecedence),
+ () => use(right, expectedPrecedence));
}
}
@@ -1538,18 +1578,9 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
buffer.add(') ');
}
- JSBinaryOperatorPrecedence operatorPrecedence = JSPrecedence.binary['&&'];
void generateAnd(HStatementInformation toVisit, Function condition) {
addIndentation();
- beginExpression(operatorPrecedence.precedence);
- var oldPrecedence = expectedPrecedence;
- expectedPrecedence = operatorPrecedence.left;
- condition();
- buffer.add(" && ");
- expectedPrecedence = operatorPrecedence.right;
- visitExpression(toVisit);
- expectedPrecedence = oldPrecedence;
- endExpression(operatorPrecedence.precedence);
+ binary("&&", condition, () => visitExpression(toVisit));
buffer.add(";\n");
}
@@ -1595,8 +1626,8 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
switch (elseKind) {
case EMPTY:
if (thenKind == ONE_EXPRESSION) {
- int precedence = operatorPrecedence.left;
- generateAnd(thenGraph, () { use(node.inputs[0], precedence); });
+ generateAnd(thenGraph,
+ () => use(node.inputs[0], expectedPrecedence));
} else {
emitIf();
visitWithoutIndent(thenGraph);
@@ -1852,19 +1883,19 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
node.value.guaranteedType);
}
String name = compiler.namer.getName(node.element);
- beginExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE);
- use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE);
- buffer.add('.');
- buffer.add(name);
- Type type = node.receiver.propagatedType.computeType(compiler);
- if (type != null) {
- world.registerFieldSetter(node.element.name, type);
- backend.updateFieldIntegerSetters(node.element,
- node.value.isInteger());
- }
- buffer.add(' = ');
- use(node.value, JSPrecedence.ASSIGNMENT_PRECEDENCE);
- endExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE);
+ binary("=", () {
+ use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE);
+ buffer.add('.');
+ buffer.add(name);
+ Type type = node.receiver.propagatedType.computeType(compiler);
+ if (type != null) {
+ world.registerFieldSetter(node.element.name, type);
+ backend.updateFieldIntegerSetters(node.element,
+ node.value.isInteger());
+ }
+ }, () {
+ use(node.value, expectedPrecedence);
+ });
}
visitLocalGet(HLocalGet node) {
@@ -1872,9 +1903,9 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
}
visitLocalSet(HLocalSet node) {
- declareInstruction(node.receiver);
- buffer.add(' = ');
- use(node.value, JSPrecedence.ASSIGNMENT_PRECEDENCE);
+ binary("=",
+ () => declareInstruction(node.receiver),
+ () => use(node.value, expectedPrecedence));
}
visitForeign(HForeign node) {
@@ -1998,10 +2029,9 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
}
if (input is HBoolify && isGenerateAtUseSite(input)) {
- beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- use(input.inputs[0], JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add(' !== true');
- endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
+ binary("!==",
+ () => use(input.inputs[0], JSPrecedence.EQUALITY_PRECEDENCE),
+ () => literal("true"));
} else if (isBuiltinRelational(input) &&
isGenerateAtUseSite(input) &&
input.inputs[0].propagatedType.isUseful() &&
@@ -2024,10 +2054,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
visitInvokeBinary(input,
inverseOperator[relational.operation.name.stringValue]);
} else {
- beginExpression(JSPrecedence.PREFIX_PRECEDENCE);
- buffer.add('!');
- use(input, JSPrecedence.PREFIX_PRECEDENCE);
- endExpression(JSPrecedence.PREFIX_PRECEDENCE);
+ prefix("!", () => use(input, JSPrecedence.PREFIX_PRECEDENCE));
}
}
@@ -2051,29 +2078,24 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
use(node.inputs[0], expectedPrecedence);
} else if (node.inputs[1].isConstantBoolean()) {
String operation = node.inputs[1].isConstantFalse() ? '&&' : '||';
- JSBinaryOperatorPrecedence operatorPrecedence =
- JSPrecedence.binary[operation];
- beginExpression(operatorPrecedence.precedence);
- if (operation == '||') {
- if (input is HNot) {
- use(input.inputs[0], operatorPrecedence.left);
+ binary(operation, () {
+ if (operation == '||') {
+ if (input is HNot) {
+ use(input.inputs[0], expectedPrecedence);
+ } else {
+ generateNot(input);
+ }
} else {
- generateNot(input);
+ use(input, expectedPrecedence);
}
- } else {
- use(input, operatorPrecedence.left);
- }
- buffer.add(" $operation ");
- use(node.inputs[0], operatorPrecedence.right);
- endExpression(operatorPrecedence.precedence);
+ }, () {
+ use(node.inputs[0], expectedPrecedence);
+ });
} else {
- beginExpression(JSPrecedence.CONDITIONAL_PRECEDENCE);
- use(input, JSPrecedence.LOGICAL_OR_PRECEDENCE);
- buffer.add(' ? ');
- use(node.inputs[0], JSPrecedence.ASSIGNMENT_PRECEDENCE);
- buffer.add(' : ');
- use(node.inputs[1], JSPrecedence.ASSIGNMENT_PRECEDENCE);
- endExpression(JSPrecedence.CONDITIONAL_PRECEDENCE);
+ conditional(
+ () => use(input, expectedPrecedence),
+ ifTrue: () => use(node.inputs[0], expectedPrecedence),
+ ifFalse: () => use(node.inputs[1], expectedPrecedence));
}
}
@@ -2113,15 +2135,22 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
// completely.
assert(node.staticChecks != HBoundsCheck.ALWAYS_TRUE);
if (node.staticChecks != HBoundsCheck.ALWAYS_FALSE) {
+ void checkUpperBound() {
+ binary(">=",
+ () => use(node.index, expectedPrecedence),
+ () => use(node.length, expectedPrecedence));
+ }
buffer.add('if (');
if (node.staticChecks != HBoundsCheck.ALWAYS_ABOVE_ZERO) {
assert(node.staticChecks == HBoundsCheck.FULL_CHECK);
- use(node.index, JSPrecedence.RELATIONAL_PRECEDENCE);
- buffer.add(' < 0 || ');
+ binary("||",
+ () => binary("<",
+ () => use(node.index, expectedPrecedence),
+ () => literal("0")),
+ checkUpperBound);
+ } else {
+ checkUpperBound();
}
- use(node.index, JSPrecedence.RELATIONAL_PRECEDENCE);
- buffer.add(' >= ');
- use(node.length, JSPrecedence.SHIFT_PRECEDENCE);
buffer.add(") ");
}
generateThrowWithHelper('ioore', node.index);
@@ -2183,17 +2212,15 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
} else if (isEmptyString(node.right)) {
useStringified(node.left, expectedPrecedence);
} else {
- JSBinaryOperatorPrecedence operatorPrecedences = JSPrecedence.binary['+'];
- beginExpression(operatorPrecedences.precedence);
- useStringified(node.left, operatorPrecedences.left);
- buffer.add(' + ');
// If the right hand side is a string concatenation itself it is
- // safe to make it left associative.
- int rightPrecedence = (node.right is HStringConcat)
- ? JSPrecedence.ADDITIVE_PRECEDENCE
- : operatorPrecedences.right;
- useStringified(node.right, rightPrecedence);
- endExpression(operatorPrecedences.precedence);
+ // safe to make it left associative by omitting parentheses.
+ bool useAdditivePrecedence = node.right is HStringConcat;
+ binary("+",
+ () => useStringified(node.left, expectedPrecedence),
+ () => useStringified(node.right,
+ useAdditivePrecedence
+ ? JSPrecedence.ADDITIVE_PRECEDENCE
+ : expectedPrecedence));
}
}
@@ -2289,11 +2316,9 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
String builtin = builtinJsName(node);
if (builtin !== null) {
if (builtin == '+') {
- beginExpression(JSPrecedence.ADDITIVE_PRECEDENCE);
- use(node.inputs[1], JSPrecedence.ADDITIVE_PRECEDENCE);
- buffer.add(' + ');
- use(node.inputs[2], JSPrecedence.MULTIPLICATIVE_PRECEDENCE);
- endExpression(JSPrecedence.ADDITIVE_PRECEDENCE);
+ binary('+',
+ () => use(node.inputs[1], expectedPrecedence),
+ () => use(node.inputs[2], expectedPrecedence));
} else {
beginExpression(JSPrecedence.CALL_PRECEDENCE);
use(node.inputs[1], JSPrecedence.MEMBER_PRECEDENCE);
@@ -2314,20 +2339,21 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
}
void checkInt(HInstruction input, String cmp) {
- beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- use(input, JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add(' $cmp (');
- use(input, JSPrecedence.BITWISE_OR_PRECEDENCE);
- buffer.add(' | 0)');
- endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
+ binary(cmp,
+ () => use(input, expectedPrecedence),
+ () => binary("|",
+ () => use(input, expectedPrecedence),
+ () => literal("0")));
+ }
+
+ void checkJSType(HInstruction input, String cmp, String type) {
+ binary(cmp,
+ () => prefix("typeof ", () => use(input, expectedPrecedence)),
+ () => literal("'$type'"));
}
void checkNum(HInstruction input, String cmp) {
- beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add('typeof ');
- use(input, JSPrecedence.PREFIX_PRECEDENCE);
- buffer.add(" $cmp 'number'");
- endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
+ checkJSType(input, cmp, "number");
}
void checkDouble(HInstruction input, String cmp) {
@@ -2335,123 +2361,99 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
}
void checkString(HInstruction input, String cmp) {
- beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add('typeof ');
- use(input, JSPrecedence.PREFIX_PRECEDENCE);
- buffer.add(" $cmp 'string'");
- endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
+ checkJSType(input, cmp, "string");
}
void checkBool(HInstruction input, String cmp) {
- beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add('typeof ');
- use(input, JSPrecedence.PREFIX_PRECEDENCE);
- buffer.add(" $cmp 'boolean'");
- endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
+ checkJSType(input, cmp, "boolean");
}
void checkObject(HInstruction input, String cmp) {
assert(NullConstant.JsNull == 'null');
if (cmp == "===") {
- withPrecedence(JSPrecedence.LOGICAL_AND_PRECEDENCE, () {
- beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add('typeof ');
- use(input, JSPrecedence.PREFIX_PRECEDENCE);
- buffer.add(" === 'object'");
- endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add(" && ");
- beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- use(input, JSPrecedence.PREFIX_PRECEDENCE);
- buffer.add(" !== null");
- endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- });
+ binary("&&",
+ () => checkJSType(input, "===", "object"),
+ () => binary("!==",
+ () => use(input, expectedPrecedence),
+ () => literal("null")));
} else {
assert(cmp == "!==");
- withPrecedence(JSPrecedence.LOGICAL_OR_PRECEDENCE, () {
- beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add('typeof ');
- use(input, JSPrecedence.PREFIX_PRECEDENCE);
- buffer.add(" !== 'object'");
- endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add(" || ");
- beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- use(input, JSPrecedence.PREFIX_PRECEDENCE);
- buffer.add(" === null");
- endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- });
+ binary("||",
+ () => checkJSType(input, "!==", "object"),
+ () => binary("===",
+ () => use(input, expectedPrecedence),
+ () => literal("null")));
}
}
void checkArray(HInstruction input, String cmp) {
- beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- use(input, JSPrecedence.MEMBER_PRECEDENCE);
- buffer.add('.constructor $cmp Array');
- endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
+ binary(cmp,
+ () {
+ use(input, JSPrecedence.MEMBER_PRECEDENCE);
+ buffer.add('.constructor');
+ },
+ () => literal("Array"));
}
void checkImmutableArray(HInstruction input) {
- beginExpression(JSPrecedence.PREFIX_PRECEDENCE);
- buffer.add('!!');
- use(input, JSPrecedence.MEMBER_PRECEDENCE);
- buffer.add('.immutable\$list');
- endExpression(JSPrecedence.PREFIX_PRECEDENCE);
+ prefix("!!", () {
+ use(input, JSPrecedence.MEMBER_PRECEDENCE);
+ buffer.add('.immutable\$list');
+ });
}
void checkExtendableArray(HInstruction input) {
- beginExpression(JSPrecedence.PREFIX_PRECEDENCE);
- buffer.add('!!');
- use(input, JSPrecedence.MEMBER_PRECEDENCE);
- buffer.add('.fixed\$length');
- endExpression(JSPrecedence.PREFIX_PRECEDENCE);
+ prefix("!!" , () {
+ use(input, JSPrecedence.MEMBER_PRECEDENCE);
+ buffer.add('.fixed\$length');
+ });
}
void checkFixedArray(HInstruction input) {
- beginExpression(JSPrecedence.PREFIX_PRECEDENCE);
- use(input, JSPrecedence.MEMBER_PRECEDENCE);
- buffer.add('.fixed\$length');
- endExpression(JSPrecedence.PREFIX_PRECEDENCE);
+ parenthesize(JSPrecedence.MEMBER_PRECEDENCE, () {
+ use(input, JSPrecedence.MEMBER_PRECEDENCE);
+ buffer.add('.fixed\$length');
+ });
}
void checkNull(HInstruction input) {
- beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- use(input, JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add(" == null");
- endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
+ binary("==",
+ () => use(input, expectedPrecedence),
+ () => literal("null"));
}
void checkFunction(HInstruction input, Element element) {
- withPrecedence(JSPrecedence.LOGICAL_OR_PRECEDENCE, () {
- beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add('typeof ');
- use(input, JSPrecedence.PREFIX_PRECEDENCE);
- buffer.add(" === 'function'");
- endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add(" || ");
- beginExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
- checkObject(input, '===');
- buffer.add(" && ");
- checkType(input, element);
- endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
- });
+ binary("||",
+ () => checkJSType(input, "===", "function"),
+ () => binary('&&',
+ () => checkObject(input, '==='),
+ () => checkType(input, element)));
}
void checkType(HInstruction input, Element element, [bool negative = false]) {
world.registerIsCheck(element);
bool requiresNativeIsCheck =
backend.emitter.nativeEmitter.requiresNativeIsCheck(element);
+ void body() {
+ assert(JSPrecedence.CALL_PRECEDENCE == JSPrecedence.MEMBER_PRECEDENCE);
+ parenthesize(JSPrecedence.CALL_PRECEDENCE, () {
+ use(input, JSPrecedence.MEMBER_PRECEDENCE);
+ buffer.add('.');
+ buffer.add(compiler.namer.operatorIs(element));
+ if (requiresNativeIsCheck) buffer.add('()');
+ });
+ }
if (!requiresNativeIsCheck) {
if (negative) {
- buffer.add('!');
+ prefix("!", body);
} else {
- buffer.add('!!');
+ prefix("!!", body);
}
} else if (negative) {
- buffer.add('!');
+ prefix("!", body);
+ } else {
+ body();
}
- use(input, JSPrecedence.MEMBER_PRECEDENCE);
- buffer.add('.');
- buffer.add(compiler.namer.operatorIs(element));
- if (requiresNativeIsCheck) buffer.add('()');
}
void handleStringSupertypeCheck(HInstruction input, Element element) {
@@ -2459,15 +2461,11 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
// would need to check for List too.
assert(element !== compiler.listClass
&& !Elements.isListSupertype(element, compiler));
- withPrecedence(JSPrecedence.LOGICAL_OR_PRECEDENCE, () {
- checkString(input, '===');
- buffer.add(' || ');
- withPrecedence(JSPrecedence.LOGICAL_AND_PRECEDENCE, () {
- checkObject(input, '===');
- buffer.add(' && ');
- checkType(input, element);
- });
- });
+ binary("||",
+ () => checkString(input, '==='),
+ () => binary("&&",
+ () => checkObject(input, '==='),
+ () => checkType(input, element)));
}
void handleListOrSupertypeCheck(HInstruction input, Element element) {
@@ -2475,16 +2473,11 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
// would need to check for String too.
assert(element !== compiler.stringClass
&& !Elements.isStringSupertype(element, compiler));
- beginExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
- checkObject(input, '===');
- buffer.add(' && (');
- beginExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE);
- checkArray(input, '===');
- buffer.add(' || ');
- checkType(input, element);
- buffer.add(')');
- endExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE);
- endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
+ binary("&&",
+ () => checkObject(input, '==='),
+ () => binary("||",
+ () => checkArray(input, '==='),
+ () => checkType(input, element)));
}
void visitIs(HIs node) {
@@ -2499,66 +2492,70 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
ClassElement objectClass = compiler.objectClass;
HInstruction input = node.expression;
- int oldPrecedence;
- if (node.nullOk) {
- oldPrecedence = expectedPrecedence;
- beginExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE);
- expectedPrecedence = JSPrecedence.LOGICAL_OR_PRECEDENCE;
- checkNull(input);
- buffer.add(' || ');
- }
- if (element === objectClass || element === compiler.dynamicClass) {
- // The constant folder also does this optimization, but we make
- // it safe by assuming it may have not run.
- buffer.add('true');
- } else if (element == compiler.stringClass) {
- checkString(input, '===');
- } else if (element == compiler.doubleClass) {
- checkDouble(input, '===');
- } else if (element == compiler.numClass) {
- checkNum(input, '===');
- } else if (element == compiler.boolClass) {
- checkBool(input, '===');
- } else if (element == compiler.functionClass) {
- checkFunction(input, element);
- } else if (element == compiler.intClass) {
- beginExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
- checkNum(input, '===');
- buffer.add(' && ');
- checkInt(input, '===');
- endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
- } else if (Elements.isStringSupertype(element, compiler)) {
- handleStringSupertypeCheck(input, element);
- } else if (element === compiler.listClass
- || Elements.isListSupertype(element, compiler)) {
- handleListOrSupertypeCheck(input, element);
- } else if (input.propagatedType.canBePrimitive()
- || input.propagatedType.canBeNull()) {
- beginExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
- checkObject(input, '===');
- buffer.add(' && ');
- checkType(input, element);
- endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
- } else {
- checkType(input, element);
- }
- if (compiler.codegenWorld.rti.hasTypeArguments(type)) {
- InterfaceType interfaceType = type;
- ClassElement cls = type.element;
- Link<Type> arguments = interfaceType.arguments;
- buffer.add(' && ');
- checkObject(node.typeInfoCall, '===');
- cls.typeParameters.forEach((name, _) {
- buffer.add(' && ');
- beginExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
- use(node.typeInfoCall, JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add(".${name.slowToString()} === '${arguments.head}'");
- endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
- });
+ void plainTypeCheck() {
+ if (element === objectClass || element === compiler.dynamicClass) {
+ // The constant folder also does this optimization, but we make
+ // it safe by assuming it may have not run.
+ literal('true');
+ } else if (element == compiler.stringClass) {
+ checkString(input, '===');
+ } else if (element == compiler.doubleClass) {
+ checkDouble(input, '===');
+ } else if (element == compiler.numClass) {
+ checkNum(input, '===');
+ } else if (element == compiler.boolClass) {
+ checkBool(input, '===');
+ } else if (element == compiler.functionClass) {
+ checkFunction(input, element);
+ } else if (element == compiler.intClass) {
+ binary("&&",
+ () => checkNum(input, '==='),
+ () => checkInt(input, '==='));
+ } else if (Elements.isStringSupertype(element, compiler)) {
+ handleStringSupertypeCheck(input, element);
+ } else if (element === compiler.listClass
+ || Elements.isListSupertype(element, compiler)) {
+ handleListOrSupertypeCheck(input, element);
+ } else if (input.propagatedType.canBePrimitive()
+ || input.propagatedType.canBeNull()) {
+ binary("&&",
+ () => checkObject(input, '==='),
+ () => checkType(input, element));
+ } else {
+ checkType(input, element);
+ }
+ }
+
+ void typeArgumentCheck() {
+ if (compiler.codegenWorld.rti.hasTypeArguments(type)) {
+ InterfaceType interfaceType = type;
+ ClassElement cls = type.element;
+ Link<Type> arguments = interfaceType.arguments;
+ binary("&&", plainTypeCheck, () {
+ var base = () => checkObject(node.typeInfoCall, '===');
+ // Do left-fold on elements with [base] as initial value.
+ cls.typeParameters.forEach((name, _) {
+ Type argument = arguments.head;
+ // TODO(lrn): Should we advance arguments here?
+ // What if there aren't any?
+ var oldBase = base;
+ base = () => binary("&&", oldBase, () {
+ parenthesize(JSPrecedence.ASSIGNMENT_PRECEDENCE, () {
+ use(node.typeInfoCall, JSPrecedence.MEMBER_PRECEDENCE);
+ buffer.add(".${name.slowToString()} === '${argument}'");
+ });
+ });
+ });
+ base();
+ });
+ } else {
+ plainTypeCheck();
+ }
}
if (node.nullOk) {
- expectedPrecedence = oldPrecedence;
- endExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE);
+ binary("||", () => checkNull(input), typeArgumentCheck);
+ } else {
+ typeArgumentCheck();
}
}
@@ -2752,11 +2749,11 @@ class SsaOptimizedCodeGenerator extends SsaCodeGenerator {
} else if (node.isExtendableArray()) {
// if (input is !Object || input is !Array || input.isFixed) bailout
buffer.add('if (');
- checkObject(input, '!==');
- buffer.add('||');
- checkArray(input, '!==');
- buffer.add('||');
- checkFixedArray(input);
+ binary("||",
+ () => binary("||",
+ () => checkObject(input, '!=='),
+ () => checkArray(input, '!==')),
+ () => checkFixedArray(input));
buffer.add(') ');
bailout(node, 'Not an extendable array');
} else if (node.isMutableArray()) {
@@ -2764,39 +2761,43 @@ class SsaOptimizedCodeGenerator extends SsaCodeGenerator {
// || ((input is !Array || input.isImmutable)
// && input is !JsIndexingBehavior)) bailout
buffer.add('if (');
- checkObject(input, '!==');
- buffer.add(' || ((');
- checkArray(input, '!==');
- buffer.add(' || ');
- checkImmutableArray(input);
- buffer.add(') && ');
- checkType(input, indexingBehavior, negative: true);
- buffer.add(')) ');
+ binary("||",
+ () => checkObject(input, '!=='),
+ () => binary("&&",
+ () => binary("||",
+ () => checkArray(input, '!=='),
+ () => checkImmutableArray(input)),
+ () => checkType(input, indexingBehavior,
+ negative: true)));
+ buffer.add(") ");
bailout(node, 'Not a mutable array');
} else if (node.isReadableArray()) {
// if (input is !Object
// || (input is !Array && input is !JsIndexingBehavior)) bailout
buffer.add('if (');
- checkObject(input, '!==');
- buffer.add(' || (');
- checkArray(input, '!==');
- buffer.add(' && ');
- checkType(input, indexingBehavior, negative: true);
- buffer.add(')) ');
+ binary("||",
+ () => checkObject(input, '!=='),
+ () => binary("&&",
+ () => checkArray(input, '!=='),
+ () => checkType(input, indexingBehavior,
+ negative: true)));
+ buffer.add(') ');
bailout(node, 'Not an array');
} else if (node.isIndexablePrimitive()) {
// if (input is !String
// && (input is !Object
// || (input is !Array && input is !JsIndexingBehavior))) bailout
buffer.add('if (');
- checkString(input, '!==');
- buffer.add(' && (');
- checkObject(input, '!==');
- buffer.add(' || (');
- checkArray(input, '!==');
- buffer.add(' && ');
- checkType(input, indexingBehavior, negative: true);
- buffer.add('))) ');
+ binary("&&",
+ () => checkString(input, '!=='),
+ () => binary("||",
+ () => checkObject(input, '!=='),
+ () => binary("&&",
+ () => checkArray(input, '!=='),
+ () => checkType(input,
+ indexingBehavior,
+ negative: true))));
+ buffer.add(') ');
bailout(node, 'Not a string or array');
} else {
compiler.internalError('Unexpected type guard', instruction: input);
@@ -3062,15 +3063,33 @@ class SsaUnoptimizedCodeGenerator extends SsaCodeGenerator {
int precedence = JSPrecedence.EXPRESSION_PRECEDENCE;
// TODO(ngeoffray): Put the condition initialization in the
// [setup] buffer.
+
+ void stateTest() {
+ binary("&&",
+ () => binary("==", () => literal("state"), () => literal("0")),
+ () => use(node.inputs[0], expectedPrecedence));
+ }
+
List<HTypeGuard> guards = node.thenBlock.guards;
- for (int i = 0, len = guards.length; i < len; i++) {
- buffer.add('state == ${guards[i].state} || ');
+ if (guards.length > 0) {
+ // Fold guards from the left using '||'.
+ Function buildGuard(int i) => () {
+ binary("==",
+ () => literal("state"),
+ () => literal("${guards[i].state}"));
+ }
+ Function guard = buildGuard(0);
+ for (int i = 1, len = guards.length; i < len; i++) {
+ int index = i;
+ Function oldGuard = guard;
+ guard = () => binary("||", oldGuard, buildGuard(index));
+ }
+ binary("||", guard, stateTest);
+ } else {
+ stateTest();
}
- buffer.add('(state == 0 && ');
- precedence = JSPrecedence.BITWISE_OR_PRECEDENCE;
- use(node.inputs[0], precedence);
- buffer.add(')) {\n');
+ buffer.add(') {\n');
indent++;
if (thenHasGuards) startBailoutSwitch();
« no previous file with comments | « no previous file | lib/compiler/implementation/ssa/codegen_helpers.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698