| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library dart2js.ir_pickler; | 5 library dart2js.ir_pickler; |
| 6 | 6 |
| 7 import 'ir_nodes.dart' as ir; | 7 import 'ir_nodes.dart' as ir; |
| 8 import '../dart2jslib.dart' show | 8 import '../dart2jslib.dart' show |
| 9 Constant, FalseConstant, TrueConstant, IntConstant, DoubleConstant, | 9 Constant, FalseConstant, TrueConstant, IntConstant, DoubleConstant, |
| 10 StringConstant, NullConstant, ListConstant, MapConstant, | 10 StringConstant, NullConstant, ListConstant, MapConstant, |
| (...skipping 22 matching lines...) Expand all Loading... |
| 33 * int ::= see [writeInt] for number encoding | 33 * int ::= see [writeInt] for number encoding |
| 34 * | 34 * |
| 35 * string ::= byte(STRING_ASCII) int(length) {byte(ascii)} | 35 * string ::= byte(STRING_ASCII) int(length) {byte(ascii)} |
| 36 * | byte(STRING_UTF8) int(length) {byte(utf8)} | 36 * | byte(STRING_UTF8) int(length) {byte(utf8)} |
| 37 * | 37 * |
| 38 * node ::= byte(NODE_CONSTANT) constant node(next) | 38 * node ::= byte(NODE_CONSTANT) constant node(next) |
| 39 * | byte(NODE_LET_CONT) int(parameter count) node(next) node(body) | 39 * | byte(NODE_LET_CONT) int(parameter count) node(next) node(body) |
| 40 * | byte(NODE_INVOKE_STATIC) element selector | 40 * | byte(NODE_INVOKE_STATIC) element selector |
| 41 * reference(continuation) {reference(argument)} | 41 * reference(continuation) {reference(argument)} |
| 42 * | byte(NODE_INVOKE_CONTINUATION) reference(continuation) | 42 * | byte(NODE_INVOKE_CONTINUATION) reference(continuation) |
| 43 * reference(argument) | 43 * {reference(argument)} |
| 44 * | 44 * |
| 45 * reference ::= int(indexDelta) | 45 * reference ::= int(indexDelta) |
| 46 * | 46 * |
| 47 * constant ::= byte(CONST_BOOL) byte(0 or 1) | 47 * constant ::= byte(CONST_BOOL) byte(0 or 1) |
| 48 * | byte(CONST_DOUBLE) byte{8} | 48 * | byte(CONST_DOUBLE) byte{8} |
| 49 * | byte(CONST_INT) int(value) | 49 * | byte(CONST_INT) int(value) |
| 50 * | byte(CONST_STRING_LITERAL) string | 50 * | byte(CONST_STRING_LITERAL) string |
| 51 * | byte(CONST_STRING_RAW) string int(length) | 51 * | byte(CONST_STRING_RAW) string int(length) |
| 52 * | byte(CONST_STRING_ESCAPED) string int(length) | 52 * | byte(CONST_STRING_ESCAPED) string int(length) |
| 53 * | byte(CONST_STRING_CONS) constant(left) constant(right) | 53 * | byte(CONST_STRING_CONS) constant(left) constant(right) |
| 54 * | byte(CONST_NULL) | 54 * | byte(CONST_NULL) |
| 55 * | 55 * |
| 56 * selector ::= byte(BACKREFERENCE) reference | 56 * selector ::= byte(BACKREFERENCE) reference |
| 57 * | byte(SELECTOR_UNTYPED) int(kind) string(name) element(library) | 57 * | byte(SELECTOR_UNTYPED) int(kind) string(name) element(library) |
| 58 * int(argumentsCount) int(namedArgumentsCount) | 58 * int(argumentsCount) int(namedArgumentsCount) |
| 59 * {string(parameterName)} | 59 * {string(parameterName)} |
| 60 * | 60 * |
| 61 * element ::= int(constantPoolIndex) | 61 * element ::= int(constantPoolIndex) |
| 62 */ | 62 */ |
| 63 class Pickles { | 63 class Pickles { |
| 64 static const int BACKREFERENCE = 1; | 64 static const int BACKREFERENCE = 1; |
| 65 | 65 |
| 66 static const int STRING_ASCII = BACKREFERENCE + 1; | 66 static const int STRING_ASCII = BACKREFERENCE + 1; |
| 67 static const int STRING_UTF8 = STRING_ASCII + 1; | 67 static const int STRING_UTF8 = STRING_ASCII + 1; |
| 68 | 68 |
| 69 static const int FIRST_NODE_TAG = STRING_UTF8 + 1; | 69 static const int FIRST_NODE_TAG = STRING_UTF8 + 1; |
| 70 static const int NODE_CONSTANT = FIRST_NODE_TAG; | 70 static const int NODE_CONSTANT = FIRST_NODE_TAG; |
| 71 static const int NODE_LET_CONT = NODE_CONSTANT + 1; | 71 static const int NODE_IS_TRUE = NODE_CONSTANT + 1; |
| 72 static const int NODE_LET_CONT = NODE_IS_TRUE + 1; |
| 72 static const int NODE_INVOKE_STATIC = NODE_LET_CONT + 1; | 73 static const int NODE_INVOKE_STATIC = NODE_LET_CONT + 1; |
| 73 static const int NODE_INVOKE_CONTINUATION = NODE_INVOKE_STATIC + 1; | 74 static const int NODE_INVOKE_CONTINUATION = NODE_INVOKE_STATIC + 1; |
| 74 static const int LAST_NODE_TAG = NODE_INVOKE_CONTINUATION; | 75 static const int NODE_BRANCH = NODE_INVOKE_CONTINUATION + 1; |
| 76 static const int LAST_NODE_TAG = NODE_BRANCH; |
| 75 | 77 |
| 76 static const int FIRST_CONST_TAG = LAST_NODE_TAG + 1; | 78 static const int FIRST_CONST_TAG = LAST_NODE_TAG + 1; |
| 77 static const int CONST_BOOL = FIRST_CONST_TAG; | 79 static const int CONST_BOOL = FIRST_CONST_TAG; |
| 78 static const int CONST_INT = CONST_BOOL + 1; | 80 static const int CONST_INT = CONST_BOOL + 1; |
| 79 static const int CONST_DOUBLE = CONST_INT + 1; | 81 static const int CONST_DOUBLE = CONST_INT + 1; |
| 80 static const int CONST_STRING_LITERAL = CONST_DOUBLE + 1; | 82 static const int CONST_STRING_LITERAL = CONST_DOUBLE + 1; |
| 81 static const int CONST_STRING_RAW = CONST_STRING_LITERAL + 1; | 83 static const int CONST_STRING_RAW = CONST_STRING_LITERAL + 1; |
| 82 static const int CONST_STRING_ESCAPED = CONST_STRING_RAW + 1; | 84 static const int CONST_STRING_ESCAPED = CONST_STRING_RAW + 1; |
| 83 static const int CONST_STRING_CONS = CONST_STRING_ESCAPED + 1; | 85 static const int CONST_STRING_CONS = CONST_STRING_ESCAPED + 1; |
| 84 static const int CONST_NULL = CONST_STRING_CONS + 1; | 86 static const int CONST_NULL = CONST_STRING_CONS + 1; |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 166 * This buffer is used in [writeConstDouble] to obtain a byte representation | 168 * This buffer is used in [writeConstDouble] to obtain a byte representation |
| 167 * for doubles. | 169 * for doubles. |
| 168 */ | 170 */ |
| 169 ByteData doubleData = new ByteData(8); | 171 ByteData doubleData = new ByteData(8); |
| 170 | 172 |
| 171 List<int> pickle(ir.FunctionDefinition function) { | 173 List<int> pickle(ir.FunctionDefinition function) { |
| 172 data = new Uint8List(INITIAL_SIZE); | 174 data = new Uint8List(INITIAL_SIZE); |
| 173 offset = 0; | 175 offset = 0; |
| 174 emitted = <Object, int>{}; | 176 emitted = <Object, int>{}; |
| 175 index = 0; | 177 index = 0; |
| 176 function.accept(this); | 178 visit(function); |
| 177 | 179 |
| 178 int sizeOffset = offset; | 180 int sizeOffset = offset; |
| 179 writeInt(emitted.length); | 181 writeInt(emitted.length); |
| 180 int sizeBytes = offset - sizeOffset; | 182 int sizeBytes = offset - sizeOffset; |
| 181 | 183 |
| 182 // The array is longer than necessary, create a copy with the actual size. | 184 // The array is longer than necessary, create a copy with the actual size. |
| 183 Uint8List result = new Uint8List(offset); | 185 Uint8List result = new Uint8List(offset); |
| 184 // Emit the number or entries in the beginning. | 186 // Emit the number or entries in the beginning. |
| 185 for (int i = 0, j = sizeOffset; i < sizeBytes; i++, j++) { | 187 for (int i = 0, j = sizeOffset; i < sizeBytes; i++, j++) { |
| 186 result[i] = data[j]; | 188 result[i] = data[j]; |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 275 void recordForBackReference(Object entry) { | 277 void recordForBackReference(Object entry) { |
| 276 assert(emitted[entry] == null); | 278 assert(emitted[entry] == null); |
| 277 emitted[entry] = index++; | 279 emitted[entry] = index++; |
| 278 } | 280 } |
| 279 | 281 |
| 280 void writeBackReference(Object entry) { | 282 void writeBackReference(Object entry) { |
| 281 int entryIndex = emitted[entry]; | 283 int entryIndex = emitted[entry]; |
| 282 writeInt(index - entryIndex); | 284 writeInt(index - entryIndex); |
| 283 } | 285 } |
| 284 | 286 |
| 285 void writeBackReferenceList(List entries) { | 287 void writeBackReferenceList(int length, Iterable entries) { |
| 286 writeInt(entries.length); | 288 writeInt(length); |
| 287 for (int i = 0; i < entries.length; i++) { | 289 for (var x in entries) { |
| 288 writeBackReference(entries[i]); | 290 writeBackReference(x); |
| 289 } | 291 } |
| 290 } | 292 } |
| 291 | 293 |
| 292 void writeConstBool(bool b) { | 294 void writeConstBool(bool b) { |
| 293 writeByte(Pickles.CONST_BOOL); | 295 writeByte(Pickles.CONST_BOOL); |
| 294 writeByte(b ? 1 : 0); | 296 writeByte(b ? 1 : 0); |
| 295 } | 297 } |
| 296 | 298 |
| 297 void writeConstInt(int n) { | 299 void writeConstInt(int n) { |
| 298 writeByte(Pickles.CONST_INT); | 300 writeByte(Pickles.CONST_INT); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 357 } | 359 } |
| 358 | 360 |
| 359 void visitFunctionDefinition(ir.FunctionDefinition node) { | 361 void visitFunctionDefinition(ir.FunctionDefinition node) { |
| 360 // The continuation parameter is bound in the body. | 362 // The continuation parameter is bound in the body. |
| 361 recordForBackReference(node.returnContinuation); | 363 recordForBackReference(node.returnContinuation); |
| 362 writeInt(node.parameters.length); | 364 writeInt(node.parameters.length); |
| 363 for (var parameter in node.parameters) { | 365 for (var parameter in node.parameters) { |
| 364 recordForBackReference(parameter); | 366 recordForBackReference(parameter); |
| 365 writeElement(parameter.element); | 367 writeElement(parameter.element); |
| 366 } | 368 } |
| 367 node.body.accept(this); | 369 visit(node.body); |
| 368 } | 370 } |
| 369 | 371 |
| 370 void visitLetPrim(ir.LetPrim node) { | 372 void visitLetPrim(ir.LetPrim node) { |
| 371 node.primitive.accept(this); | 373 visit(node.primitive); |
| 372 // The right-hand side is bound in the body. | 374 // The right-hand side is bound in the body. |
| 373 recordForBackReference(node.primitive); | 375 recordForBackReference(node.primitive); |
| 374 node.body.accept(this); | 376 visit(node.body); |
| 375 } | 377 } |
| 376 | 378 |
| 377 void visitLetCont(ir.LetCont node) { | 379 void visitLetCont(ir.LetCont node) { |
| 378 // There are two choices of which expression tree to write first---the | 380 // There are two choices of which expression tree to write first---the |
| 379 // continuation body or the LetCont body. The unpickler will unpickle the | 381 // continuation body or the LetCont body. The unpickler will unpickle the |
| 380 // the first recursively and the second iteratively. Since the hole in | 382 // the first recursively and the second iteratively. Since the hole in |
| 381 // LetCont contexts is in the continuation body, the continuation should be | 383 // LetCont contexts is in the continuation body, the continuation should be |
| 382 // written second. | 384 // written second. |
| 383 writeByte(Pickles.NODE_LET_CONT); | 385 writeByte(Pickles.NODE_LET_CONT); |
| 384 writeInt(node.continuation.parameters.length); | 386 writeInt(node.continuation.parameters.length); |
| 385 // The continuation is bound in the body. | 387 // The continuation is bound in the body. |
| 386 recordForBackReference(node.continuation); | 388 recordForBackReference(node.continuation); |
| 387 node.body.accept(this); | 389 visit(node.body); |
| 388 // The continuation parameters are bound in the continuation's body. | 390 // The continuation parameters are bound in the continuation's body. |
| 389 node.continuation.parameters.forEach(recordForBackReference); | 391 node.continuation.parameters.forEach(recordForBackReference); |
| 390 node.continuation.body.accept(this); | 392 visit(node.continuation.body); |
| 391 } | 393 } |
| 392 | 394 |
| 393 void visitInvokeStatic(ir.InvokeStatic node) { | 395 void visitInvokeStatic(ir.InvokeStatic node) { |
| 394 writeByte(Pickles.NODE_INVOKE_STATIC); | 396 writeByte(Pickles.NODE_INVOKE_STATIC); |
| 395 writeElement(node.target); | 397 writeElement(node.target); |
| 396 writeSelector(node.selector); | 398 writeSelector(node.selector); |
| 397 // TODO(lry): compact encoding when the arity of the selector and the | 399 // TODO(lry): compact encoding when the arity of the selector and the |
| 398 // arguments list are the same | 400 // arguments list are the same |
| 399 writeBackReference(node.continuation.definition); | 401 writeBackReference(node.continuation.definition); |
| 400 writeBackReferenceList(node.arguments.map( | 402 writeBackReferenceList(node.arguments.length, |
| 401 (a) => a.definition).toList(growable: false)); | 403 node.arguments.map((a) => a.definition)); |
| 402 } | 404 } |
| 403 | 405 |
| 404 void visitInvokeContinuation(ir.InvokeContinuation node) { | 406 void visitInvokeContinuation(ir.InvokeContinuation node) { |
| 405 writeByte(Pickles.NODE_INVOKE_CONTINUATION); | 407 writeByte(Pickles.NODE_INVOKE_CONTINUATION); |
| 406 writeBackReference(node.continuation.definition); | 408 writeBackReference(node.continuation.definition); |
| 407 writeBackReference(node.argument.definition); | 409 writeBackReferenceList(node.arguments.length, |
| 410 node.arguments.map((a) => a.definition)); |
| 411 } |
| 412 |
| 413 void visitBranch(ir.Branch node) { |
| 414 writeByte(Pickles.NODE_BRANCH); |
| 415 visit(node.condition); |
| 416 writeBackReference(node.trueContinuation.definition); |
| 417 writeBackReference(node.falseContinuation.definition); |
| 408 } | 418 } |
| 409 | 419 |
| 410 void visitConstant(ir.Constant node) { | 420 void visitConstant(ir.Constant node) { |
| 411 writeByte(Pickles.NODE_CONSTANT); | 421 writeByte(Pickles.NODE_CONSTANT); |
| 412 node.value.accept(constantPickler); | 422 node.value.accept(constantPickler); |
| 413 } | 423 } |
| 414 | 424 |
| 425 void visitIsTrue(ir.IsTrue node) { |
| 426 writeByte(Pickles.NODE_IS_TRUE); |
| 427 writeBackReference(node.value.definition); |
| 428 } |
| 429 |
| 415 void visitNode(ir.Node node) { | 430 void visitNode(ir.Node node) { |
| 416 throw "Unexpected $node in pickler."; | 431 throw "Unexpected $node in pickler."; |
| 417 } | 432 } |
| 418 } | 433 } |
| 419 | 434 |
| 420 /** | 435 /** |
| 421 * A visitor for constants which writes the constant values to its [Pickler]. | 436 * A visitor for constants which writes the constant values to its [Pickler]. |
| 422 */ | 437 */ |
| 423 class ConstantPickler extends ConstantVisitor { | 438 class ConstantPickler extends ConstantVisitor { |
| 424 | 439 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 452 void visitList(ListConstant constant) => abort(constant); | 467 void visitList(ListConstant constant) => abort(constant); |
| 453 void visitMap(MapConstant constant) => abort(constant); | 468 void visitMap(MapConstant constant) => abort(constant); |
| 454 void visitInterceptor(InterceptorConstant constant) => abort(constant); | 469 void visitInterceptor(InterceptorConstant constant) => abort(constant); |
| 455 void visitDummy(DummyConstant constant) => abort(constant); | 470 void visitDummy(DummyConstant constant) => abort(constant); |
| 456 void visitFunction(FunctionConstant constant) => abort(constant); | 471 void visitFunction(FunctionConstant constant) => abort(constant); |
| 457 void visitType(TypeConstant constant) => abort(constant); | 472 void visitType(TypeConstant constant) => abort(constant); |
| 458 void visitConstructed(ConstructedConstant constant) => abort(constant); | 473 void visitConstructed(ConstructedConstant constant) => abort(constant); |
| 459 | 474 |
| 460 void abort(Constant value) => throw "Can not pickle constant $value"; | 475 void abort(Constant value) => throw "Can not pickle constant $value"; |
| 461 } | 476 } |
| OLD | NEW |