| // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| part of dart2js.ir_pickler; |
| |
| class Unpickler { |
| final Compiler compiler; |
| |
| final IrConstantPool constantPool; |
| |
| Unpickler(this.compiler, this.constantPool); |
| |
| List<int> data; |
| |
| int offset; |
| |
| /** For each entry index, the corresponding unpickled object. */ |
| List<Object> unpickled; |
| |
| /** Counter for entries in [unpickled]. */ |
| int index; |
| |
| /** |
| * This buffer is used in [readConstant] to reconstruct a double value from |
| * a sequence of bytes. |
| */ |
| ByteData doubleData = new ByteData(8); |
| |
| ConstantSystem get constantSystem => compiler.backend.constantSystem; |
| |
| // A partially constructed expression is one that has a single 'hole' where |
| // there is an expression missing. Just like the IR builder, the unpickler |
| // represents such an expression by its root and by the 'current' expression |
| // that immediately contains the hole. If there is no hole (e.g., an |
| // expression in tail position has been seen), then current is null. |
| ir.Expression root; |
| ir.Expression current; |
| |
| ir.Function unpickle(List<int> data) { |
| this.data = data; |
| offset = 0; |
| int numEntries = readInt(); |
| unpickled = new List<Object>(numEntries); |
| index = 0; |
| root = current = null; |
| return readFunctionNode(); |
| } |
| |
| int readByte() { |
| return data[offset++]; |
| } |
| |
| int readInt() { |
| int result = 0; |
| int next; |
| for (int i = 0; true; i += 7) { |
| next = readByte(); |
| result |= (next >> 1) << i; |
| if ((next & 1) == 0) break; |
| } |
| bool isNegative = (result & 1) == 1; |
| result >>= 1; |
| return isNegative ? -result : result; |
| } |
| |
| String readString() { |
| int tag = readByte(); |
| int length = readInt(); |
| List<int> bytes = new Uint8List(length); |
| for (int i = 0; i < length; i++) { |
| bytes[i] = readByte(); |
| } |
| if (tag == Pickles.STRING_ASCII) { |
| return new String.fromCharCodes(bytes); |
| } else if (tag == Pickles.STRING_UTF8) { |
| return UTF8.decode(bytes); |
| } else { |
| compiler.internalError("Unexpected string tag: $tag"); |
| return null; |
| } |
| } |
| |
| Element readElement() { |
| int elementIndex = readInt(); |
| return constantPool.get(elementIndex); |
| } |
| |
| Selector readSelector() { |
| int tag = readByte(); |
| if (tag == Pickles.BACKREFERENCE) { |
| return readBackReference(); |
| } |
| assert(tag == Pickles.SELECTOR_UNTYPED); |
| int entryIndex = index++; |
| SelectorKind kind = Pickles.selectorKindFromId[readInt()]; |
| String name = readString(); |
| Element library = readElement(); |
| int argumentsCount = readInt(); |
| int namedArgumentsCount = readInt(); |
| List<String> namedArguments = new List<String>(namedArgumentsCount); |
| for (int i = 0; i < namedArgumentsCount; i++) { |
| namedArguments[i] = readString(); |
| } |
| Selector result = new Selector( |
| kind, name, library, argumentsCount, namedArguments); |
| unpickled[entryIndex] = result; |
| return result; |
| } |
| |
| void addExpression(ir.Expression expr) { |
| if (root == null) { |
| root = current = expr; |
| } else { |
| current = current.plug(expr); |
| } |
| } |
| |
| // Read a single expression and plug it into the outer context. |
| ir.Expression readExpressionNode() { |
| int tag = readByte(); |
| switch (tag) { |
| case Pickles.NODE_CONSTANT: |
| ir.Definition constant = readConstantNode(); |
| unpickled[index++] = constant; |
| addExpression(new ir.LetVal(constant)); |
| break; |
| case Pickles.NODE_LET_CONT: |
| ir.Parameter parameter = new ir.Parameter(); |
| ir.Continuation continuation = new ir.Continuation(parameter); |
| unpickled[index++] = continuation; |
| ir.Expression body = readDelimitedExpressionNode(); |
| unpickled[index++] = parameter; |
| addExpression(new ir.LetCont(continuation, body)); |
| break; |
| case Pickles.NODE_INVOKE_STATIC: |
| addExpression(readInvokeStaticNode()); |
| current = null; |
| break; |
| case Pickles.NODE_INVOKE_CONTINUATION: |
| addExpression(readInvokeContinuationNode()); |
| current = null; |
| break; |
| default: |
| compiler.internalError("Unexpected expression entry tag: $tag"); |
| break; |
| } |
| } |
| |
| // Iteratively read expressions until an expression in a tail position |
| // (e.g., an invocation) is found. Do not change the outer context. |
| ir.Expression readDelimitedExpressionNode() { |
| ir.Expression previous_root = root; |
| ir.Expression previous_current = current; |
| root = current = null; |
| do { |
| readExpressionNode(); |
| } while (current != null); |
| ir.Expression result = root; |
| root = previous_root; |
| current = previous_current; |
| return result; |
| } |
| |
| Object readBackReference() { |
| int indexDelta = readInt(); |
| int entryIndex = index - indexDelta; |
| assert(unpickled[entryIndex] != null); |
| return unpickled[entryIndex]; |
| } |
| |
| List<ir.Definition> readBackReferenceList() { |
| int length = readInt(); |
| List<ir.Definition> result = new List<ir.Definition>(length); |
| for (int i = 0; i < length; i++) { |
| result[i] = readBackReference(); |
| } |
| return result; |
| } |
| |
| ir.Function readFunctionNode() { |
| int endOffset = readInt(); |
| int namePosition = readInt(); |
| // There is implicitly a return continuation which can be the target of |
| // back references. |
| ir.Continuation continuation = new ir.Continuation.retrn(); |
| unpickled[index++] = continuation; |
| |
| ir.Expression body = readDelimitedExpressionNode(); |
| return new ir.Function(endOffset, namePosition, continuation, body); |
| } |
| |
| ir.Constant readConstantNode() { |
| Constant constant = readConstant(); |
| return new ir.Constant(constant); |
| } |
| |
| ir.InvokeStatic readInvokeStaticNode() { |
| FunctionElement functionElement = readElement(); |
| Selector selector = readSelector(); |
| ir.Continuation continuation = readBackReference(); |
| List<ir.Definition> arguments = readBackReferenceList(); |
| return new ir.InvokeStatic(functionElement, selector, continuation, |
| arguments); |
| } |
| |
| ir.InvokeContinuation readInvokeContinuationNode() { |
| ir.Continuation continuation = readBackReference(); |
| ir.Definition argument = readBackReference(); |
| return new ir.InvokeContinuation(continuation, argument); |
| } |
| |
| Constant readConstant() { |
| int tag = readByte(); |
| switch(tag) { |
| case Pickles.CONST_BOOL: |
| return constantSystem.createBool(readByte() == 1); |
| case Pickles.CONST_INT: |
| return constantSystem.createInt(readInt()); |
| case Pickles.CONST_DOUBLE: |
| for (int i = 0; i < 8; i++) { |
| doubleData.setUint8(i, readByte()); |
| } |
| double value = doubleData.getFloat64(0, Endianness.BIG_ENDIAN); |
| return constantSystem.createDouble(value); |
| case Pickles.CONST_STRING_LITERAL: |
| case Pickles.CONST_STRING_RAW: |
| case Pickles.CONST_STRING_ESCAPED: |
| case Pickles.CONST_STRING_CONS: |
| return constantSystem.createString(readDartString(tag)); |
| case Pickles.CONST_NULL: |
| return constantSystem.createNull(); |
| default: |
| compiler.internalError("Unexpected constant tag: $tag"); |
| return null; |
| } |
| } |
| |
| ast.DartString readDartString(int tag) { |
| switch(tag) { |
| case Pickles.CONST_STRING_LITERAL: |
| return new ast.LiteralDartString(readString()); |
| case Pickles.CONST_STRING_RAW: |
| return new ast.RawSourceDartString(readString(), readInt()); |
| case Pickles.CONST_STRING_ESCAPED: |
| return new ast.EscapedSourceDartString(readString(), readInt()); |
| case Pickles.CONST_STRING_CONS: |
| return new ast.ConsDartString( |
| readDartString(readByte()), readDartString(readByte())); |
| default: |
| compiler.internalError("Unexpected dart string tag: $tag"); |
| return null; |
| } |
| } |
| } |