Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 library kernel.ast_from_binary; | 4 library kernel.ast_from_binary; |
| 5 | 5 |
| 6 import '../ast.dart'; | 6 import '../ast.dart'; |
| 7 import 'tag.dart'; | 7 import 'tag.dart'; |
| 8 import 'loader.dart'; | |
| 9 import 'dart:convert'; | 8 import 'dart:convert'; |
| 10 import 'package:kernel/transformations/flags.dart'; | 9 import 'package:kernel/transformations/flags.dart'; |
| 11 | 10 |
| 12 class ParseError { | 11 class ParseError { |
| 13 String filename; | 12 String filename; |
| 14 int byteIndex; | 13 int byteIndex; |
| 15 String message; | 14 String message; |
| 16 String path; | 15 String path; |
| 17 | 16 |
| 18 ParseError(this.message, {this.filename, this.byteIndex, this.path}); | 17 ParseError(this.message, {this.filename, this.byteIndex, this.path}); |
| 19 | 18 |
| 20 String toString() => '$filename:$byteIndex: $message at $path'; | 19 String toString() => '$filename:$byteIndex: $message at $path'; |
| 21 } | 20 } |
| 22 | 21 |
| 23 class BinaryBuilder { | 22 class BinaryBuilder { |
| 24 final BinaryReferenceLoader loader; | |
| 25 final List<Library> importTable = <Library>[]; | |
| 26 final List<VariableDeclaration> variableStack = <VariableDeclaration>[]; | 23 final List<VariableDeclaration> variableStack = <VariableDeclaration>[]; |
| 27 final List<LabeledStatement> labelStack = <LabeledStatement>[]; | 24 final List<LabeledStatement> labelStack = <LabeledStatement>[]; |
| 28 int labelStackBase = 0; | 25 int labelStackBase = 0; |
| 29 final List<SwitchCase> switchCaseStack = <SwitchCase>[]; | 26 final List<SwitchCase> switchCaseStack = <SwitchCase>[]; |
| 30 final List<TypeParameter> typeParameterStack = <TypeParameter>[]; | 27 final List<TypeParameter> typeParameterStack = <TypeParameter>[]; |
| 31 final String filename; | 28 final String filename; |
| 32 final List<int> _bytes; | 29 final List<int> _bytes; |
| 33 int _byteIndex = 0; | 30 int _byteIndex = 0; |
| 34 Library _currentLibrary; | |
| 35 List<String> _stringTable; | 31 List<String> _stringTable; |
| 36 List<String> _sourceUriTable; | 32 List<String> _sourceUriTable; |
| 33 List<CanonicalName> _linkTable; | |
| 37 int _transformerFlags = 0; | 34 int _transformerFlags = 0; |
| 38 | 35 |
| 39 // If something goes wrong, this list should indicate what library, | 36 // If something goes wrong, this list should indicate what library, |
| 40 // class, and member was being built. | 37 // class, and member was being built. |
| 41 List<String> debugPath = <String>[]; | 38 List<String> debugPath = <String>[]; |
| 42 | 39 |
| 43 BinaryBuilder(this.loader, this._bytes, [this.filename]); | 40 bool _isReadingLibraryImplementation = false; |
| 41 | |
| 42 BinaryBuilder(this._bytes, [this.filename]); | |
| 44 | 43 |
| 45 fail(String message) { | 44 fail(String message) { |
| 46 throw new ParseError(message, | 45 throw new ParseError(message, |
| 47 byteIndex: _byteIndex, filename: filename, path: debugPath.join('::')); | 46 byteIndex: _byteIndex, filename: filename, path: debugPath.join('::')); |
| 48 } | 47 } |
| 49 | 48 |
| 50 int readByte() => _bytes[_byteIndex++]; | 49 int readByte() => _bytes[_byteIndex++]; |
| 51 | 50 |
| 52 int readUInt() { | 51 int readUInt() { |
| 53 var byte = readByte(); | 52 var byte = readByte(); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 119 return _stringTable[readUInt()]; | 118 return _stringTable[readUInt()]; |
| 120 } | 119 } |
| 121 | 120 |
| 122 String readStringOrNullIfEmpty() { | 121 String readStringOrNullIfEmpty() { |
| 123 var string = readStringReference(); | 122 var string = readStringReference(); |
| 124 return string.isEmpty ? null : string; | 123 return string.isEmpty ? null : string; |
| 125 } | 124 } |
| 126 | 125 |
| 127 InferredValue readOptionalInferredValue() { | 126 InferredValue readOptionalInferredValue() { |
| 128 if (readAndCheckOptionTag()) { | 127 if (readAndCheckOptionTag()) { |
| 129 Class baseClass = readClassReference(allowNull: true); | 128 CanonicalName baseClass = readClassReference(allowNull: true); |
| 130 BaseClassKind baseClassKind = BaseClassKind.values[readByte()]; | 129 BaseClassKind baseClassKind = BaseClassKind.values[readByte()]; |
| 131 int valueBits = readByte(); | 130 int valueBits = readByte(); |
| 132 return new InferredValue(baseClass, baseClassKind, valueBits); | 131 return new InferredValue.byName(baseClass, baseClassKind, valueBits); |
| 133 } | 132 } |
| 134 return null; | 133 return null; |
| 135 } | 134 } |
| 136 | 135 |
| 137 bool readAndCheckOptionTag() { | 136 bool readAndCheckOptionTag() { |
| 138 int tag = readByte(); | 137 int tag = readByte(); |
| 139 if (tag == Tag.Nothing) { | 138 if (tag == Tag.Nothing) { |
| 140 return false; | 139 return false; |
| 141 } else if (tag == Tag.Something) { | 140 } else if (tag == Tag.Something) { |
| 142 return true; | 141 return true; |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 163 } | 162 } |
| 164 } | 163 } |
| 165 | 164 |
| 166 void _fillNonTreeNodeList(List<Node> list, Node buildObject()) { | 165 void _fillNonTreeNodeList(List<Node> list, Node buildObject()) { |
| 167 list.length = readUInt(); | 166 list.length = readUInt(); |
| 168 for (int i = 0; i < list.length; ++i) { | 167 for (int i = 0; i < list.length; ++i) { |
| 169 list[i] = buildObject(); | 168 list[i] = buildObject(); |
| 170 } | 169 } |
| 171 } | 170 } |
| 172 | 171 |
| 173 Program readProgramFile() { | 172 /// Reads a list of linked nodes, reusing any existing objects already in the |
| 173 /// linking tree. The nodes are merged into [list], and if reading the library | |
| 174 /// implementation, the order is corrected. | |
| 175 void _mergeLinkedNodeList( | |
| 176 List<LinkedNode> list, LinkedNode readObject(), TreeNode parent) { | |
| 177 if (_isReadingLibraryImplementation) { | |
| 178 // When reading the library implementation, overwrite the whole list | |
| 179 // with the new one. | |
| 180 _fillTreeNodeList(list, readObject, parent); | |
| 181 } else { | |
| 182 // When reading an external library, the results should either be: | |
| 183 // - merged with the existing external library definition (if any) | |
| 184 // - ignored if the library impementation is already in memory | |
|
ahe
2017/02/13 10:07:08
implementation
asgerf
2017/02/16 14:22:42
Done.
| |
| 185 // | |
| 186 // We use the parent pointer of a node to determine if it already is in | |
| 187 // the AST and hence should not be added again. | |
|
ahe
2017/02/13 10:07:08
I'm not really understanding how this comment rela
asgerf
2017/02/16 14:22:42
Moved the comment down closer to the check.
| |
| 188 int numberOfNodes = readUInt(); | |
| 189 for (int i = 0; i < numberOfNodes; ++i) { | |
| 190 var value = readObject(); | |
| 191 if (value.parent == null) { | |
| 192 list.add(value..parent = parent); | |
| 193 } | |
| 194 } | |
| 195 } | |
| 196 } | |
| 197 | |
| 198 void readLinkTable(CanonicalName linkRoot) { | |
| 199 int length = readUInt(); | |
| 200 _linkTable = new List<CanonicalName>(length); | |
| 201 for (int i = 0; i < length; ++i) { | |
| 202 int biasedParentIndex = readUInt(); | |
| 203 String name = readStringReference(); | |
| 204 var parent = | |
| 205 biasedParentIndex == 0 ? linkRoot : _linkTable[biasedParentIndex - 1]; | |
| 206 _linkTable[i] = parent.getChild(name); | |
| 207 } | |
| 208 } | |
| 209 | |
| 210 /// Deserializes a kernel program and stores it in [program]. | |
| 211 /// | |
| 212 /// The input bytes may contain multiple files concatenated. | |
| 213 void readMultiFile(Program program) { | |
|
ahe
2017/02/13 10:07:08
Suggestion: rename this to readProgram and call th
asgerf
2017/02/16 14:22:42
Done.
| |
| 214 while (_byteIndex < _bytes.length) { | |
| 215 _readProgram(program); | |
| 216 } | |
| 217 } | |
| 218 | |
| 219 /// Reads a single program file from the input and loads it into [program], | |
| 220 /// overwriting and reusing any existing data in the program. | |
| 221 /// | |
| 222 /// This should *only* be used when there is a reason to not allow | |
| 223 /// concatenated files. | |
| 224 void readSingleFile(Program program) { | |
| 225 _readProgram(program); | |
| 226 if (_byteIndex < _bytes.length) { | |
| 227 if (_byteIndex + 3 < _bytes.length) { | |
| 228 int magic = readMagicWord(); | |
| 229 if (magic == Tag.ProgramFile) { | |
| 230 throw 'Concatenated program file given when a single program ' | |
| 231 'was expected.'; | |
| 232 } | |
| 233 } | |
| 234 throw 'Unrecognized bytes following program data'; | |
| 235 } | |
| 236 } | |
| 237 | |
| 238 void _readProgram(Program program) { | |
| 174 int magic = readMagicWord(); | 239 int magic = readMagicWord(); |
| 175 if (magic != Tag.ProgramFile) { | 240 if (magic != Tag.ProgramFile) { |
| 176 throw fail('This is not a binary dart file. ' | 241 throw fail('This is not a binary dart file. ' |
| 177 'Magic number was: ${magic.toRadixString(16)}'); | 242 'Magic number was: ${magic.toRadixString(16)}'); |
| 178 } | 243 } |
| 179 readStringTable(); | 244 readStringTable(); |
| 180 Map<String, Source> uriToSource = readUriToSource(); | 245 Map<String, Source> uriToSource = readUriToSource(); |
| 181 importTable.length = readUInt(); | 246 program.uriToSource.addAll(uriToSource); |
| 182 for (int i = 0; i < importTable.length; ++i) { | 247 readLinkTable(program.root); |
| 183 importTable[i] = new Library(null); | 248 int numberOfLibraries = readUInt(); |
| 184 } | 249 List<Library> libraries = new List<Library>(numberOfLibraries); |
| 185 for (int i = 0; i < importTable.length; ++i) { | 250 for (int i = 0; i < numberOfLibraries; ++i) { |
| 186 _currentLibrary = importTable[i]; | 251 libraries[i] = readLibrary(program); |
| 187 readLibrary(); | |
| 188 } | 252 } |
| 189 var mainMethod = readMemberReference(allowNull: true); | 253 var mainMethod = readMemberReference(allowNull: true); |
| 190 return new Program(importTable, uriToSource) | 254 program.mainMethodName ??= mainMethod; |
| 191 ..mainMethod = mainMethod; | |
| 192 } | 255 } |
| 193 | 256 |
| 194 Map<String, Source> readUriToSource() { | 257 Map<String, Source> readUriToSource() { |
| 195 readSourceUriTable(); | 258 readSourceUriTable(); |
| 196 int length = _sourceUriTable.length; | 259 int length = _sourceUriTable.length; |
| 197 Map<String, Source> uriToLineStarts = <String, Source>{}; | 260 Map<String, Source> uriToSource = <String, Source>{}; |
| 198 for (int i = 0; i < length; ++i) { | 261 for (int i = 0; i < length; ++i) { |
| 199 String uri = _sourceUriTable[i]; | 262 String uri = _sourceUriTable[i]; |
| 200 String sourceCode = readStringEntry(); | 263 String sourceCode = readStringEntry(); |
| 201 int lineCount = readUInt(); | 264 int lineCount = readUInt(); |
| 202 List<int> lineStarts = new List<int>(lineCount); | 265 List<int> lineStarts = new List<int>(lineCount); |
| 203 int previousLineStart = 0; | 266 int previousLineStart = 0; |
| 204 for (int j = 0; j < lineCount; ++j) { | 267 for (int j = 0; j < lineCount; ++j) { |
| 205 int lineStart = readUInt() + previousLineStart; | 268 int lineStart = readUInt() + previousLineStart; |
| 206 lineStarts[j] = lineStart; | 269 lineStarts[j] = lineStart; |
| 207 previousLineStart = lineStart; | 270 previousLineStart = lineStart; |
| 208 } | 271 } |
| 209 uriToLineStarts[uri] = new Source(lineStarts, sourceCode); | 272 uriToSource[uri] = new Source(lineStarts, sourceCode); |
| 210 } | 273 } |
| 211 return uriToLineStarts; | 274 return uriToSource; |
| 212 } | 275 } |
| 213 | 276 |
| 214 void _fillLazilyLoadedList( | 277 CanonicalName readCanonicalNameReference() { |
| 215 List<TreeNode> list, void buildObject(int tag, int index)) { | 278 var index = readUInt(); |
| 216 int length = readUInt(); | 279 if (index == 0) return null; |
| 217 list.length = length; | 280 return _linkTable[index - 1]; |
| 218 for (int i = 0; i < length; ++i) { | |
| 219 int tag = readByte(); | |
| 220 buildObject(tag, i); | |
| 221 } | |
| 222 } | 281 } |
| 223 | 282 |
| 224 Library readLibraryReference() { | 283 CanonicalName readLibraryReference() { |
| 225 int index = readUInt(); | 284 return readCanonicalNameReference(); |
| 226 return importTable[index]; | |
| 227 } | 285 } |
| 228 | 286 |
| 229 Class readClassReference({bool allowNull: false}) { | 287 CanonicalName readClassReference({bool allowNull: false}) { |
| 230 int tag = readByte(); | 288 var name = readCanonicalNameReference(); |
| 231 if (tag == Tag.NullReference) { | 289 if (name == null && !allowNull) { |
| 232 if (!allowNull) { | 290 throw 'Expected a class reference to be valid but was `null`.'; |
| 233 throw 'Expected a class reference to be valid but was `null`.'; | |
| 234 } | |
| 235 return null; | |
| 236 } else { | |
| 237 var library = readLibraryReference(); | |
| 238 int index = readUInt(); | |
| 239 return loader.getClassReference(library, tag, index); | |
| 240 } | 291 } |
| 292 return name; | |
| 241 } | 293 } |
| 242 | 294 |
| 243 Member readMemberReference({bool allowNull: false}) { | 295 CanonicalName readMemberReference({bool allowNull: false}) { |
| 244 int tag = readByte(); | 296 var name = readCanonicalNameReference(); |
| 245 switch (tag) { | 297 if (name == null && !allowNull) { |
| 246 case Tag.LibraryFieldReference: | 298 throw 'Expected a member reference to be valid but was `null`.'; |
| 247 case Tag.LibraryProcedureReference: | |
| 248 var library = readLibraryReference(); | |
| 249 var index = readUInt(); | |
| 250 return loader.getLibraryMemberReference(library, tag, index); | |
| 251 | |
| 252 case Tag.ClassFieldReference: | |
| 253 case Tag.ClassConstructorReference: | |
| 254 case Tag.ClassProcedureReference: | |
| 255 var classNode = readClassReference(); | |
| 256 var index = readUInt(); | |
| 257 return loader.getClassMemberReference(classNode, tag, index); | |
| 258 | |
| 259 case Tag.NullReference: | |
| 260 if (!allowNull) { | |
| 261 throw 'Expected a member reference to be valid but was `null`.'; | |
| 262 } | |
| 263 return null; | |
| 264 | |
| 265 default: | |
| 266 throw fail('Invalid member reference tag: $tag'); | |
| 267 } | 299 } |
| 300 return name; | |
| 268 } | 301 } |
| 269 | 302 |
| 270 Name readName() { | 303 Name readName() { |
| 271 String text = readStringReference(); | 304 String text = readStringReference(); |
| 272 if (text.isNotEmpty && text[0] == '_') { | 305 if (text.isNotEmpty && text[0] == '_') { |
| 273 return new Name(text, readLibraryReference()); | 306 return new Name.byReference(text, readLibraryReference()); |
| 274 } else { | 307 } else { |
| 275 return new Name(text); | 308 return new Name(text); |
| 276 } | 309 } |
| 277 } | 310 } |
| 278 | 311 |
| 279 Uri readImportUri() { | 312 Library readLibrary(Program program) { |
| 280 return Uri.parse(readStringReference()); | 313 int flags = readByte(); |
| 314 bool isExternal = (flags & 0x1) != 0; | |
| 315 _isReadingLibraryImplementation = !isExternal; | |
| 316 var canonicalName = readCanonicalNameReference(); | |
| 317 Library library = canonicalName.definition; | |
| 318 bool shouldWriteData = library == null || _isReadingLibraryImplementation; | |
| 319 if (library == null) { | |
| 320 library = new Library(Uri.parse(canonicalName.name)); | |
| 321 canonicalName.bindTo(library); | |
| 322 program.libraries.add(library..parent = program); | |
| 323 } | |
| 324 String name = readStringOrNullIfEmpty(); | |
| 325 // TODO(jensj): We currently save (almost the same) uri twice. | |
| 326 String fileUri = readUriReference(); | |
| 327 | |
| 328 if (shouldWriteData) { | |
| 329 library.isExternal = isExternal; | |
| 330 library.name = name; | |
| 331 library.fileUri = fileUri; | |
| 332 } | |
| 333 | |
| 334 debugPath.add(library.name ?? library.importUri?.toString() ?? 'library'); | |
| 335 | |
| 336 _mergeLinkedNodeList(library.classes, readClass, library); | |
| 337 _mergeLinkedNodeList(library.fields, readField, library); | |
| 338 _mergeLinkedNodeList(library.procedures, readProcedure, library); | |
| 339 | |
| 340 debugPath.removeLast(); | |
| 341 return library; | |
| 281 } | 342 } |
| 282 | 343 |
| 283 void readLibrary() { | 344 Class readClass() { |
| 284 int flags = readByte(); | 345 int tag = readByte(); |
| 285 _currentLibrary.isExternal = (flags & 0x1) != 0; | 346 assert(tag == Tag.Class); |
| 286 _currentLibrary.name = readStringOrNullIfEmpty(); | 347 var canonicalName = readCanonicalNameReference(); |
| 287 _currentLibrary.importUri = readImportUri(); | 348 Class node = canonicalName.definition; |
| 288 debugPath.add(_currentLibrary.name ?? | 349 bool shouldWriteData = node == null || _isReadingLibraryImplementation; |
| 289 _currentLibrary.importUri?.toString() ?? | 350 if (node == null) { |
| 290 'library'); | 351 node = new Class()..level = ClassLevel.Temporary; |
| 291 | 352 canonicalName.bindTo(node); |
| 292 // TODO(jensj): We currently save (almost the same) uri twice. | |
| 293 _currentLibrary.fileUri = readUriReference(); | |
| 294 | |
| 295 _fillLazilyLoadedList(_currentLibrary.classes, (int tag, int index) { | |
| 296 readClass(loader.getClassReference(_currentLibrary, tag, index), tag); | |
| 297 }); | |
| 298 _fillLazilyLoadedList(_currentLibrary.fields, (int tag, int index) { | |
| 299 readField( | |
| 300 loader.getLibraryMemberReference(_currentLibrary, tag, index), tag); | |
| 301 }); | |
| 302 _fillLazilyLoadedList(_currentLibrary.procedures, (int tag, int index) { | |
| 303 readProcedure( | |
| 304 loader.getLibraryMemberReference(_currentLibrary, tag, index), tag); | |
| 305 }); | |
| 306 debugPath.removeLast(); | |
| 307 } | |
| 308 | |
| 309 void readClass(Class node, int tag) { | |
| 310 assert(node != null); | |
| 311 switch (tag) { | |
| 312 case Tag.NormalClass: | |
| 313 readNormalClass(node); | |
| 314 break; | |
| 315 case Tag.MixinClass: | |
| 316 readMixinClass(node); | |
| 317 break; | |
| 318 default: | |
| 319 throw fail('Invalid class tag: $tag'); | |
| 320 } | 353 } |
| 321 } | |
| 322 | |
| 323 void readNormalClass(Class node) { | |
| 324 node.fileOffset = readOffset(); | 354 node.fileOffset = readOffset(); |
| 325 int flags = readByte(); | 355 int flags = readByte(); |
| 326 node.isAbstract = flags & 0x1 != 0; | 356 node.isAbstract = flags & 0x1 != 0; |
| 327 node.level = _currentLibrary.isExternal | 357 var level = _isReadingLibraryImplementation |
| 328 ? (flags & 0x2 != 0) ? ClassLevel.Type : ClassLevel.Hierarchy | 358 ? ClassLevel.Body |
| 329 : ClassLevel.Body; | 359 : (flags & 0x2 != 0) ? ClassLevel.Type : ClassLevel.Hierarchy; |
| 330 node.name = readStringOrNullIfEmpty(); | 360 if (level.index >= node.level.index) { |
| 331 node.fileUri = readUriReference(); | 361 node.level = level; |
| 332 node.annotations = readAnnotationList(node); | 362 } |
| 363 var name = readStringOrNullIfEmpty(); | |
| 364 var fileUri = readUriReference(); | |
| 365 var annotations = readAnnotationList(node); | |
| 333 debugPath.add(node.name ?? 'normal-class'); | 366 debugPath.add(node.name ?? 'normal-class'); |
| 334 readAndPushTypeParameterList(node.typeParameters, node); | 367 readAndPushTypeParameterList(node.typeParameters, node); |
| 335 node.supertype = readSupertypeOption(); | 368 var supertype = readSupertypeOption(); |
| 369 var mixedInType = readSupertypeOption(); | |
| 336 _fillNonTreeNodeList(node.implementedTypes, readSupertype); | 370 _fillNonTreeNodeList(node.implementedTypes, readSupertype); |
| 337 _fillLazilyLoadedList(node.fields, (int tag, int index) { | 371 _mergeLinkedNodeList(node.fields, readField, node); |
| 338 readField(loader.getClassMemberReference(node, tag, index), tag); | 372 _mergeLinkedNodeList(node.constructors, readConstructor, node); |
| 339 }); | 373 _mergeLinkedNodeList(node.procedures, readProcedure, node); |
| 340 _fillLazilyLoadedList(node.constructors, (int tag, int index) { | |
| 341 readConstructor(loader.getClassMemberReference(node, tag, index), tag); | |
| 342 }); | |
| 343 _fillLazilyLoadedList(node.procedures, (int tag, int index) { | |
| 344 readProcedure(loader.getClassMemberReference(node, tag, index), tag); | |
| 345 }); | |
| 346 typeParameterStack.length = 0; | 374 typeParameterStack.length = 0; |
| 347 debugPath.removeLast(); | 375 debugPath.removeLast(); |
| 348 } | 376 if (shouldWriteData) { |
| 349 | 377 node.name = name; |
| 350 void readMixinClass(Class node) { | 378 node.fileUri = fileUri; |
| 351 node.fileOffset = readOffset(); | 379 node.annotations = annotations; |
| 352 int flags = readByte(); | 380 node.supertype = supertype; |
| 353 node.isAbstract = flags & 0x1 != 0; | 381 node.mixedInType = mixedInType; |
| 354 node.level = _currentLibrary.isExternal | 382 } |
| 355 ? (flags & 0x2 != 0) ? ClassLevel.Type : ClassLevel.Hierarchy | 383 return node; |
| 356 : ClassLevel.Body; | |
| 357 node.name = readStringOrNullIfEmpty(); | |
| 358 node.fileUri = readUriReference(); | |
| 359 node.annotations = readAnnotationList(node); | |
| 360 debugPath.add(node.name ?? 'mixin-class'); | |
| 361 readAndPushTypeParameterList(node.typeParameters, node); | |
| 362 node.supertype = readSupertype(); | |
| 363 node.mixedInType = readSupertype(); | |
| 364 _fillNonTreeNodeList(node.implementedTypes, readDartType); | |
| 365 _fillLazilyLoadedList(node.constructors, (int tag, int index) { | |
| 366 readConstructor(loader.getClassMemberReference(node, tag, index), tag); | |
| 367 }); | |
| 368 typeParameterStack.length = 0; | |
| 369 debugPath.removeLast(); | |
| 370 } | 384 } |
| 371 | 385 |
| 372 int getAndResetTransformerFlags() { | 386 int getAndResetTransformerFlags() { |
| 373 int flags = _transformerFlags; | 387 int flags = _transformerFlags; |
| 374 _transformerFlags = 0; | 388 _transformerFlags = 0; |
| 375 return flags; | 389 return flags; |
| 376 } | 390 } |
| 377 | 391 |
| 378 /// Adds the given flag to the current [Member.transformerFlags]. | 392 /// Adds the given flag to the current [Member.transformerFlags]. |
| 379 void addTransformerFlag(int flags) { | 393 void addTransformerFlag(int flags) { |
| 380 _transformerFlags |= flags; | 394 _transformerFlags |= flags; |
| 381 } | 395 } |
| 382 | 396 |
| 383 void readField(Field node, int tag) { | 397 Field readField() { |
| 384 // Note: as with readProcedure and readConstructor, the tag parameter | 398 int tag = readByte(); |
| 385 // is unused, but we pass it in to clarify that the tag has already been | |
| 386 // consumed from the input. | |
| 387 assert(tag == Tag.Field); | 399 assert(tag == Tag.Field); |
| 388 node.fileOffset = readOffset(); | 400 var canonicalName = readCanonicalNameReference(); |
| 389 node.fileEndOffset = readOffset(); | 401 Field node = canonicalName.definition; |
| 390 node.flags = readByte(); | 402 bool shouldWriteData = node == null || _isReadingLibraryImplementation; |
| 391 node.name = readName(); | 403 if (node == null) { |
| 392 node.fileUri = readUriReference(); | 404 node = new Field(null); |
| 393 node.annotations = readAnnotationList(node); | 405 canonicalName.bindTo(node); |
| 406 } | |
| 407 int fileOffset = readOffset(); | |
| 408 int fileEndOffset = readOffset(); | |
| 409 int flags = readByte(); | |
| 410 var name = readName(); | |
| 411 var fileUri = readUriReference(); | |
| 412 var annotations = readAnnotationList(node); | |
| 394 debugPath.add(node.name?.name ?? 'field'); | 413 debugPath.add(node.name?.name ?? 'field'); |
| 395 node.type = readDartType(); | 414 var type = readDartType(); |
| 396 node.inferredValue = readOptionalInferredValue(); | 415 var inferredValue = readOptionalInferredValue(); |
| 397 node.initializer = readExpressionOption(); | 416 var initializer = readExpressionOption(); |
| 398 node.initializer?.parent = node; | 417 int transformerFlags = getAndResetTransformerFlags(); |
| 399 node.transformerFlags = getAndResetTransformerFlags(); | |
| 400 debugPath.removeLast(); | 418 debugPath.removeLast(); |
| 419 if (shouldWriteData) { | |
| 420 node.fileOffset = fileOffset; | |
| 421 node.fileEndOffset = fileEndOffset; | |
| 422 node.flags = flags; | |
| 423 node.name = name; | |
| 424 node.fileUri = fileUri; | |
| 425 node.annotations = annotations; | |
| 426 node.type = type; | |
| 427 node.inferredValue = inferredValue; | |
| 428 node.initializer = initializer; | |
| 429 node.initializer?.parent = node; | |
| 430 node.transformerFlags = transformerFlags; | |
| 431 } | |
| 432 return node; | |
| 401 } | 433 } |
| 402 | 434 |
| 403 void readConstructor(Constructor node, int tag) { | 435 Constructor readConstructor() { |
| 436 int tag = readByte(); | |
| 404 assert(tag == Tag.Constructor); | 437 assert(tag == Tag.Constructor); |
| 405 node.fileOffset = readOffset(); | 438 var canonicalName = readCanonicalNameReference(); |
| 406 node.fileEndOffset = readOffset(); | 439 Constructor node = canonicalName.definition; |
| 407 node.flags = readByte(); | 440 bool shouldWriteData = node == null || _isReadingLibraryImplementation; |
| 408 node.name = readName(); | 441 if (node == null) { |
| 409 node.annotations = readAnnotationList(node); | 442 node = new Constructor(null); |
| 443 canonicalName.bindTo(node); | |
| 444 } | |
| 445 var fileOffset = readOffset(); | |
| 446 var fileEndOffset = readOffset(); | |
| 447 var flags = readByte(); | |
| 448 var name = readName(); | |
| 449 var annotations = readAnnotationList(node); | |
| 410 debugPath.add(node.name?.name ?? 'constructor'); | 450 debugPath.add(node.name?.name ?? 'constructor'); |
| 411 node.function = readFunctionNode()..parent = node; | 451 var function = readFunctionNode(); |
| 412 pushVariableDeclarations(node.function.positionalParameters); | 452 if (_isReadingLibraryImplementation) { |
| 413 pushVariableDeclarations(node.function.namedParameters); | 453 pushVariableDeclarations(function.positionalParameters); |
| 414 _fillTreeNodeList(node.initializers, readInitializer, node); | 454 pushVariableDeclarations(function.namedParameters); |
| 415 variableStack.length = 0; | 455 _fillTreeNodeList(node.initializers, readInitializer, node); |
| 416 node.transformerFlags = getAndResetTransformerFlags(); | 456 variableStack.length = 0; |
| 457 } else { | |
| 458 // External libraries should not contain constructor initializers. | |
| 459 int numberOfInitializers = readUInt(); | |
| 460 assert(numberOfInitializers == 0); | |
| 461 } | |
| 462 var transformerFlags = getAndResetTransformerFlags(); | |
| 417 debugPath.removeLast(); | 463 debugPath.removeLast(); |
| 464 if (shouldWriteData) { | |
| 465 node.fileOffset = fileOffset; | |
| 466 node.fileEndOffset = fileEndOffset; | |
| 467 node.flags = flags; | |
| 468 node.name = name; | |
| 469 node.annotations = annotations; | |
| 470 node.function = function..parent = node; | |
| 471 node.transformerFlags = transformerFlags; | |
| 472 } | |
| 473 return node; | |
| 418 } | 474 } |
| 419 | 475 |
| 420 void readProcedure(Procedure node, int tag) { | 476 Procedure readProcedure() { |
| 477 int tag = readByte(); | |
| 421 assert(tag == Tag.Procedure); | 478 assert(tag == Tag.Procedure); |
| 422 node.fileOffset = readOffset(); | 479 var canonicalName = readCanonicalNameReference(); |
| 423 node.fileEndOffset = readOffset(); | 480 Procedure node = canonicalName.definition; |
| 481 bool shouldWriteData = node == null || _isReadingLibraryImplementation; | |
| 482 if (node == null) { | |
| 483 node = new Procedure(null, null, null); | |
| 484 canonicalName.bindTo(node); | |
| 485 } | |
| 486 var fileOffset = readOffset(); | |
| 487 var fileEndOffset = readOffset(); | |
| 424 int kindIndex = readByte(); | 488 int kindIndex = readByte(); |
| 425 node.kind = ProcedureKind.values[kindIndex]; | 489 var kind = ProcedureKind.values[kindIndex]; |
| 426 node.flags = readByte(); | 490 var flags = readByte(); |
| 427 node.name = readName(); | 491 var name = readName(); |
| 428 node.fileUri = readUriReference(); | 492 var fileUri = readUriReference(); |
| 429 node.annotations = readAnnotationList(node); | 493 var annotations = readAnnotationList(node); |
| 430 debugPath.add(node.name?.name ?? 'procedure'); | 494 debugPath.add(node.name?.name ?? 'procedure'); |
| 431 node.function = readFunctionNodeOption(); | 495 var function = readFunctionNodeOption(); |
| 432 node.function?.parent = node; | 496 var transformerFlags = getAndResetTransformerFlags(); |
| 433 node.transformerFlags = getAndResetTransformerFlags(); | |
| 434 debugPath.removeLast(); | 497 debugPath.removeLast(); |
| 498 if (shouldWriteData) { | |
| 499 node.fileOffset = fileOffset; | |
| 500 node.fileEndOffset = fileEndOffset; | |
| 501 node.kind = kind; | |
| 502 node.flags = flags; | |
| 503 node.name = name; | |
| 504 node.fileUri = fileUri; | |
| 505 node.annotations = annotations; | |
| 506 node.function = function; | |
| 507 node.function?.parent = node; | |
| 508 node.transformerFlags = transformerFlags; | |
| 509 } | |
| 510 return node; | |
| 435 } | 511 } |
| 436 | 512 |
| 437 Initializer readInitializer() { | 513 Initializer readInitializer() { |
| 438 int tag = readByte(); | 514 int tag = readByte(); |
| 439 switch (tag) { | 515 switch (tag) { |
| 440 case Tag.InvalidInitializer: | 516 case Tag.InvalidInitializer: |
| 441 return new InvalidInitializer(); | 517 return new InvalidInitializer(); |
| 442 case Tag.FieldInitializer: | 518 case Tag.FieldInitializer: |
| 443 return new FieldInitializer(readMemberReference(), readExpression()); | 519 return new FieldInitializer.byName( |
| 520 readMemberReference(), readExpression()); | |
| 444 case Tag.SuperInitializer: | 521 case Tag.SuperInitializer: |
| 445 return new SuperInitializer(readMemberReference(), readArguments()); | 522 return new SuperInitializer.byName( |
| 523 readMemberReference(), readArguments()); | |
| 446 case Tag.RedirectingInitializer: | 524 case Tag.RedirectingInitializer: |
| 447 return new RedirectingInitializer( | 525 return new RedirectingInitializer.byName( |
| 448 readMemberReference(), readArguments()); | 526 readMemberReference(), readArguments()); |
| 449 case Tag.LocalInitializer: | 527 case Tag.LocalInitializer: |
| 450 return new LocalInitializer(readAndPushVariableDeclaration()); | 528 return new LocalInitializer(readAndPushVariableDeclaration()); |
| 451 default: | 529 default: |
| 452 throw fail('Invalid initializer tag: $tag'); | 530 throw fail('Invalid initializer tag: $tag'); |
| 453 } | 531 } |
| 454 } | 532 } |
| 455 | 533 |
| 456 FunctionNode readFunctionNodeOption() { | 534 FunctionNode readFunctionNodeOption() { |
| 457 return readAndCheckOptionTag() ? readFunctionNode() : null; | 535 return readAndCheckOptionTag() ? readFunctionNode() : null; |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 544 int offset = readOffset(); | 622 int offset = readOffset(); |
| 545 return new VariableSet(readVariableReference(), readExpression()) | 623 return new VariableSet(readVariableReference(), readExpression()) |
| 546 ..fileOffset = offset; | 624 ..fileOffset = offset; |
| 547 case Tag.SpecializedVariableSet: | 625 case Tag.SpecializedVariableSet: |
| 548 int index = tagByte & Tag.SpecializedPayloadMask; | 626 int index = tagByte & Tag.SpecializedPayloadMask; |
| 549 int offset = readOffset(); | 627 int offset = readOffset(); |
| 550 return new VariableSet(variableStack[index], readExpression()) | 628 return new VariableSet(variableStack[index], readExpression()) |
| 551 ..fileOffset = offset; | 629 ..fileOffset = offset; |
| 552 case Tag.PropertyGet: | 630 case Tag.PropertyGet: |
| 553 int offset = readOffset(); | 631 int offset = readOffset(); |
| 554 return new PropertyGet( | 632 return new PropertyGet.byName( |
| 555 readExpression(), readName(), readMemberReference(allowNull: true)) | 633 readExpression(), readName(), readMemberReference(allowNull: true)) |
| 556 ..fileOffset = offset; | 634 ..fileOffset = offset; |
| 557 case Tag.PropertySet: | 635 case Tag.PropertySet: |
| 558 int offset = readOffset(); | 636 int offset = readOffset(); |
| 559 return new PropertySet(readExpression(), readName(), readExpression(), | 637 return new PropertySet.byName( |
| 638 readExpression(), | |
| 639 readName(), | |
| 640 readExpression(), | |
| 560 readMemberReference(allowNull: true))..fileOffset = offset; | 641 readMemberReference(allowNull: true))..fileOffset = offset; |
| 561 case Tag.SuperPropertyGet: | 642 case Tag.SuperPropertyGet: |
| 562 addTransformerFlag(TransformerFlag.superCalls); | 643 addTransformerFlag(TransformerFlag.superCalls); |
| 563 return new SuperPropertyGet( | 644 return new SuperPropertyGet.byName( |
| 564 readName(), readMemberReference(allowNull: true)); | 645 readName(), readMemberReference(allowNull: true)); |
| 565 case Tag.SuperPropertySet: | 646 case Tag.SuperPropertySet: |
| 566 addTransformerFlag(TransformerFlag.superCalls); | 647 addTransformerFlag(TransformerFlag.superCalls); |
| 567 return new SuperPropertySet( | 648 return new SuperPropertySet.byName( |
| 568 readName(), readExpression(), readMemberReference(allowNull: true)); | 649 readName(), readExpression(), readMemberReference(allowNull: true)); |
| 569 case Tag.DirectPropertyGet: | 650 case Tag.DirectPropertyGet: |
| 570 return new DirectPropertyGet(readExpression(), readMemberReference()); | 651 return new DirectPropertyGet.byName( |
| 652 readExpression(), readMemberReference()); | |
| 571 case Tag.DirectPropertySet: | 653 case Tag.DirectPropertySet: |
| 572 return new DirectPropertySet( | 654 return new DirectPropertySet.byName( |
| 573 readExpression(), readMemberReference(), readExpression()); | 655 readExpression(), readMemberReference(), readExpression()); |
| 574 case Tag.StaticGet: | 656 case Tag.StaticGet: |
| 575 int offset = readOffset(); | 657 int offset = readOffset(); |
| 576 return new StaticGet(readMemberReference())..fileOffset = offset; | 658 return new StaticGet.byName(readMemberReference())..fileOffset = offset; |
| 577 case Tag.StaticSet: | 659 case Tag.StaticSet: |
| 578 return new StaticSet(readMemberReference(), readExpression()); | 660 return new StaticSet.byName(readMemberReference(), readExpression()); |
| 579 case Tag.MethodInvocation: | 661 case Tag.MethodInvocation: |
| 580 int offset = readOffset(); | 662 int offset = readOffset(); |
| 581 return new MethodInvocation( | 663 return new MethodInvocation.byName( |
| 582 readExpression(), | 664 readExpression(), |
| 583 readName(), | 665 readName(), |
| 584 readArguments(), | 666 readArguments(), |
| 585 readMemberReference(allowNull: true))..fileOffset = offset; | 667 readMemberReference(allowNull: true))..fileOffset = offset; |
| 586 case Tag.SuperMethodInvocation: | 668 case Tag.SuperMethodInvocation: |
| 587 int offset = readOffset(); | 669 int offset = readOffset(); |
| 588 addTransformerFlag(TransformerFlag.superCalls); | 670 addTransformerFlag(TransformerFlag.superCalls); |
| 589 return new SuperMethodInvocation( | 671 return new SuperMethodInvocation.byName( |
| 590 readName(), readArguments(), readMemberReference(allowNull: true)) | 672 readName(), readArguments(), readMemberReference(allowNull: true)) |
| 591 ..fileOffset = offset; | 673 ..fileOffset = offset; |
| 592 case Tag.DirectMethodInvocation: | 674 case Tag.DirectMethodInvocation: |
| 593 return new DirectMethodInvocation( | 675 return new DirectMethodInvocation.byName( |
| 594 readExpression(), readMemberReference(), readArguments()); | 676 readExpression(), readMemberReference(), readArguments()); |
| 595 case Tag.StaticInvocation: | 677 case Tag.StaticInvocation: |
| 596 int offset = readOffset(); | 678 int offset = readOffset(); |
| 597 return new StaticInvocation(readMemberReference(), readArguments(), | 679 return new StaticInvocation.byName( |
| 598 isConst: false)..fileOffset = offset; | 680 readMemberReference(), readArguments(), isConst: false) |
| 681 ..fileOffset = offset; | |
| 599 case Tag.ConstStaticInvocation: | 682 case Tag.ConstStaticInvocation: |
| 600 int offset = readOffset(); | 683 int offset = readOffset(); |
| 601 return new StaticInvocation(readMemberReference(), readArguments(), | 684 return new StaticInvocation.byName( |
| 602 isConst: true)..fileOffset = offset; | 685 readMemberReference(), readArguments(), isConst: true) |
| 686 ..fileOffset = offset; | |
| 603 case Tag.ConstructorInvocation: | 687 case Tag.ConstructorInvocation: |
| 604 int offset = readOffset(); | 688 int offset = readOffset(); |
| 605 return new ConstructorInvocation(readMemberReference(), readArguments(), | 689 return new ConstructorInvocation.byName( |
| 606 isConst: false)..fileOffset = offset; | 690 readMemberReference(), readArguments(), isConst: false) |
| 691 ..fileOffset = offset; | |
| 607 case Tag.ConstConstructorInvocation: | 692 case Tag.ConstConstructorInvocation: |
| 608 int offset = readOffset(); | 693 int offset = readOffset(); |
| 609 return new ConstructorInvocation(readMemberReference(), readArguments(), | 694 return new ConstructorInvocation.byName( |
| 610 isConst: true)..fileOffset = offset; | 695 readMemberReference(), readArguments(), isConst: true) |
| 696 ..fileOffset = offset; | |
| 611 case Tag.Not: | 697 case Tag.Not: |
| 612 return new Not(readExpression()); | 698 return new Not(readExpression()); |
| 613 case Tag.LogicalExpression: | 699 case Tag.LogicalExpression: |
| 614 return new LogicalExpression(readExpression(), | 700 return new LogicalExpression(readExpression(), |
| 615 logicalOperatorToString(readByte()), readExpression()); | 701 logicalOperatorToString(readByte()), readExpression()); |
| 616 case Tag.ConditionalExpression: | 702 case Tag.ConditionalExpression: |
| 617 return new ConditionalExpression(readExpression(), readExpression(), | 703 return new ConditionalExpression(readExpression(), readExpression(), |
| 618 readExpression(), readDartTypeOption()); | 704 readExpression(), readDartTypeOption()); |
| 619 case Tag.StringConcatenation: | 705 case Tag.StringConcatenation: |
| 620 int offset = readOffset(); | 706 int offset = readOffset(); |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 829 | 915 |
| 830 Block readBlock() { | 916 Block readBlock() { |
| 831 int stackHeight = variableStack.length; | 917 int stackHeight = variableStack.length; |
| 832 var body = readStatementList(); | 918 var body = readStatementList(); |
| 833 variableStack.length = stackHeight; | 919 variableStack.length = stackHeight; |
| 834 return new Block(body); | 920 return new Block(body); |
| 835 } | 921 } |
| 836 | 922 |
| 837 Supertype readSupertype() { | 923 Supertype readSupertype() { |
| 838 InterfaceType type = readDartType(); | 924 InterfaceType type = readDartType(); |
| 839 return new Supertype(type.classNode, type.typeArguments); | 925 return new Supertype.byName(type.className, type.typeArguments); |
| 840 } | 926 } |
| 841 | 927 |
| 842 Supertype readSupertypeOption() { | 928 Supertype readSupertypeOption() { |
| 843 return readAndCheckOptionTag() ? readSupertype() : null; | 929 return readAndCheckOptionTag() ? readSupertype() : null; |
| 844 } | 930 } |
| 845 | 931 |
| 846 List<Supertype> readSupertypeList() { | 932 List<Supertype> readSupertypeList() { |
| 847 return new List<Supertype>.generate(readUInt(), (i) => readSupertype()); | 933 return new List<Supertype>.generate(readUInt(), (i) => readSupertype()); |
| 848 } | 934 } |
| 849 | 935 |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 868 switch (tag) { | 954 switch (tag) { |
| 869 case Tag.BottomType: | 955 case Tag.BottomType: |
| 870 return const BottomType(); | 956 return const BottomType(); |
| 871 case Tag.InvalidType: | 957 case Tag.InvalidType: |
| 872 return const InvalidType(); | 958 return const InvalidType(); |
| 873 case Tag.DynamicType: | 959 case Tag.DynamicType: |
| 874 return const DynamicType(); | 960 return const DynamicType(); |
| 875 case Tag.VoidType: | 961 case Tag.VoidType: |
| 876 return const VoidType(); | 962 return const VoidType(); |
| 877 case Tag.InterfaceType: | 963 case Tag.InterfaceType: |
| 878 return new InterfaceType(readClassReference(), readDartTypeList()); | 964 return new InterfaceType.byName( |
| 965 readClassReference(), readDartTypeList()); | |
| 879 case Tag.SimpleInterfaceType: | 966 case Tag.SimpleInterfaceType: |
| 880 return new InterfaceType(readClassReference(), const <DartType>[]); | 967 return new InterfaceType.byName( |
| 968 readClassReference(), const <DartType>[]); | |
| 881 case Tag.FunctionType: | 969 case Tag.FunctionType: |
| 882 int typeParameterStackHeight = typeParameterStack.length; | 970 int typeParameterStackHeight = typeParameterStack.length; |
| 883 var typeParameters = readAndPushTypeParameterList(); | 971 var typeParameters = readAndPushTypeParameterList(); |
| 884 var requiredParameterCount = readUInt(); | 972 var requiredParameterCount = readUInt(); |
| 885 var positional = readDartTypeList(); | 973 var positional = readDartTypeList(); |
| 886 var named = readNamedTypeList(); | 974 var named = readNamedTypeList(); |
| 887 var returnType = readDartType(); | 975 var returnType = readDartType(); |
| 888 typeParameterStack.length = typeParameterStackHeight; | 976 typeParameterStack.length = typeParameterStackHeight; |
| 889 return new FunctionType(positional, returnType, | 977 return new FunctionType(positional, returnType, |
| 890 typeParameters: typeParameters, | 978 typeParameters: typeParameters, |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 902 } | 990 } |
| 903 } | 991 } |
| 904 | 992 |
| 905 List<TypeParameter> readAndPushTypeParameterList( | 993 List<TypeParameter> readAndPushTypeParameterList( |
| 906 [List<TypeParameter> list, TreeNode parent]) { | 994 [List<TypeParameter> list, TreeNode parent]) { |
| 907 int length = readUInt(); | 995 int length = readUInt(); |
| 908 if (length == 0) return list ?? <TypeParameter>[]; | 996 if (length == 0) return list ?? <TypeParameter>[]; |
| 909 if (list == null) { | 997 if (list == null) { |
| 910 list = new List<TypeParameter>.generate( | 998 list = new List<TypeParameter>.generate( |
| 911 length, (i) => new TypeParameter(null, null)..parent = parent); | 999 length, (i) => new TypeParameter(null, null)..parent = parent); |
| 912 } else { | 1000 } else if (list.length != length) { |
| 913 list.length = length; | 1001 list.length = length; |
| 914 for (int i = 0; i < length; ++i) { | 1002 for (int i = 0; i < length; ++i) { |
| 915 list[i] = new TypeParameter(null, null)..parent = parent; | 1003 list[i] = new TypeParameter(null, null)..parent = parent; |
| 916 } | 1004 } |
| 917 } | 1005 } |
| 918 typeParameterStack.addAll(list); | 1006 typeParameterStack.addAll(list); |
| 919 for (int i = 0; i < list.length; ++i) { | 1007 for (int i = 0; i < list.length; ++i) { |
| 920 readTypeParameter(list[i]); | 1008 readTypeParameter(list[i]); |
| 921 } | 1009 } |
| 922 return list; | 1010 return list; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 968 isFinal: flags & 0x1 != 0, | 1056 isFinal: flags & 0x1 != 0, |
| 969 isConst: flags & 0x2 != 0)..fileOffset = offset; | 1057 isConst: flags & 0x2 != 0)..fileOffset = offset; |
| 970 } | 1058 } |
| 971 | 1059 |
| 972 int readOffset() { | 1060 int readOffset() { |
| 973 // Offset is saved as unsigned, | 1061 // Offset is saved as unsigned, |
| 974 // but actually ranges from -1 and up (thus the -1) | 1062 // but actually ranges from -1 and up (thus the -1) |
| 975 return readUInt() - 1; | 1063 return readUInt() - 1; |
| 976 } | 1064 } |
| 977 } | 1065 } |
| OLD | NEW |