| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library dart._js_names; | |
| 6 | |
| 7 import 'dart:_js_embedded_names' show | |
| 8 JsGetName, | |
| 9 MANGLED_GLOBAL_NAMES, | |
| 10 MANGLED_NAMES; | |
| 11 | |
| 12 import 'dart:_foreign_helper' show | |
| 13 JS, | |
| 14 JS_EMBEDDED_GLOBAL, | |
| 15 JS_GET_NAME; | |
| 16 | |
| 17 import 'dart:_js_helper' show | |
| 18 JsCache, | |
| 19 NoInline; | |
| 20 | |
| 21 import 'dart:_interceptors' show JSArray; | |
| 22 | |
| 23 /// No-op method that is called to inform the compiler that unmangled named | |
| 24 /// must be preserved. | |
| 25 preserveNames() {} | |
| 26 | |
| 27 /// A map from mangled names to "reflective" names, that is, unmangled names | |
| 28 /// with some additional information, such as, number of required arguments. | |
| 29 /// This map is for mangled names used as instance members. | |
| 30 final _LazyMangledNamesMap mangledNames = new _LazyMangledInstanceNamesMap( | |
| 31 JS_EMBEDDED_GLOBAL('=Object', MANGLED_NAMES)); | |
| 32 | |
| 33 /// A map from "reflective" names to mangled names (the reverse of | |
| 34 /// [mangledNames]). | |
| 35 final _LazyReflectiveNamesMap reflectiveNames = | |
| 36 new _LazyReflectiveNamesMap(JS_EMBEDDED_GLOBAL('=Object', MANGLED_NAMES), | |
| 37 true); | |
| 38 | |
| 39 /// A map from mangled names to "reflective" names (see [mangledNames]). This | |
| 40 /// map is for globals, that is, static and top-level members. | |
| 41 final _LazyMangledNamesMap mangledGlobalNames = new _LazyMangledNamesMap( | |
| 42 JS_EMBEDDED_GLOBAL('=Object', MANGLED_GLOBAL_NAMES)); | |
| 43 | |
| 44 /// A map from "reflective" names to mangled names (the reverse of | |
| 45 /// [mangledGlobalNames]). | |
| 46 final _LazyReflectiveNamesMap reflectiveGlobalNames = | |
| 47 new _LazyReflectiveNamesMap( | |
| 48 JS_EMBEDDED_GLOBAL('=Object', MANGLED_GLOBAL_NAMES), false); | |
| 49 | |
| 50 /// Implements a mapping from mangled names to their reflective counterparts. | |
| 51 /// The propertiy names of [_jsMangledNames] are the mangled names, and the | |
| 52 /// values are the "reflective" names. | |
| 53 class _LazyMangledNamesMap { | |
| 54 /// [_jsMangledNames] is a JavaScript object literal. | |
| 55 var _jsMangledNames; | |
| 56 | |
| 57 _LazyMangledNamesMap(this._jsMangledNames); | |
| 58 | |
| 59 String operator[](String key) { | |
| 60 var result = JS('var', '#[#]', _jsMangledNames, key); | |
| 61 // Filter out all non-string values to protect against polution from | |
| 62 // anciliary fields in [_jsMangledNames]. | |
| 63 bool filter = | |
| 64 JS('bool', 'typeof # !== "string"', result); | |
| 65 // To ensure that the inferrer sees that result is a String, we explicitly | |
| 66 // give it a better type here. | |
| 67 return filter ? null : JS('String', '#', result); | |
| 68 } | |
| 69 } | |
| 70 | |
| 71 /// Extends [_LazyMangledNamesMap] with additional support for adding mappings | |
| 72 /// from mangled setter names to their reflective counterpart by rewriting a | |
| 73 /// corresponding entry for a getter name, if it exists. | |
| 74 class _LazyMangledInstanceNamesMap extends _LazyMangledNamesMap { | |
| 75 _LazyMangledInstanceNamesMap(_jsMangledNames) : super(_jsMangledNames); | |
| 76 | |
| 77 String operator[](String key) { | |
| 78 String result = super[key]; | |
| 79 String setterPrefix = JS_GET_NAME(JsGetName.SETTER_PREFIX); | |
| 80 if (result == null && key.startsWith(setterPrefix)) { | |
| 81 String getterPrefix = JS_GET_NAME(JsGetName.GETTER_PREFIX); | |
| 82 int setterPrefixLength = setterPrefix.length; | |
| 83 | |
| 84 // Generate the setter name from the getter name. | |
| 85 key = '$getterPrefix${key.substring(setterPrefixLength)}'; | |
| 86 result = super[key]; | |
| 87 return (result != null) ? "${result}=" : null; | |
| 88 } | |
| 89 return result; | |
| 90 } | |
| 91 } | |
| 92 | |
| 93 /// Implements the inverse of [_LazyMangledNamesMap]. As it would be too | |
| 94 /// expensive to seach the mangled names map for a value that corresponds to | |
| 95 /// the lookup key on each invocation, we compute the full mapping in demand | |
| 96 /// and cache it. The cache is invalidated when the underlying [_jsMangledNames] | |
| 97 /// object changes its length. This condition is sufficient as the name mapping | |
| 98 /// can only grow over time. | |
| 99 /// When [_isInstance] is true, we also apply the inverse of the setter/getter | |
| 100 /// name conversion implemented by [_LazyMangledInstanceNamesMap]. | |
| 101 class _LazyReflectiveNamesMap { | |
| 102 /// [_jsMangledNames] is a JavaScript object literal. | |
| 103 final _jsMangledNames; | |
| 104 final bool _isInstance; | |
| 105 int _cacheLength = 0; | |
| 106 Map<String, String> _cache; | |
| 107 | |
| 108 _LazyReflectiveNamesMap(this._jsMangledNames, this._isInstance); | |
| 109 | |
| 110 Map<String, String> _updateReflectiveNames() { | |
| 111 preserveNames(); | |
| 112 Map<String, String> result = <String, String>{}; | |
| 113 List keys = JS('List', 'Object.keys(#)', _jsMangledNames); | |
| 114 for (String key in keys) { | |
| 115 var reflectiveName = JS('var', '#[#]', _jsMangledNames, key); | |
| 116 // Filter out all non-string values to protect against polution from | |
| 117 // anciliary fields in [_jsMangledNames]. | |
| 118 bool filter = JS('bool', 'typeof # !== "string"', reflectiveName); | |
| 119 if (filter) continue; | |
| 120 result[reflectiveName] = JS('String', '#', key); | |
| 121 | |
| 122 String getterPrefix = JS_GET_NAME(JsGetName.GETTER_PREFIX); | |
| 123 if (_isInstance && key.startsWith(getterPrefix)) { | |
| 124 int getterPrefixLength = getterPrefix.length; | |
| 125 String setterPrefix = JS_GET_NAME(JsGetName.SETTER_PREFIX); | |
| 126 result['$reflectiveName='] = | |
| 127 '$setterPrefix${key.substring(getterPrefixLength)}'; | |
| 128 } | |
| 129 } | |
| 130 return result; | |
| 131 } | |
| 132 | |
| 133 int get _jsMangledNamesLength => JS('int', 'Object.keys(#).length', | |
| 134 _jsMangledNames); | |
| 135 | |
| 136 String operator[](String key) { | |
| 137 if (_cache == null || _jsMangledNamesLength != _cacheLength) { | |
| 138 _cache = _updateReflectiveNames(); | |
| 139 _cacheLength = _jsMangledNamesLength; | |
| 140 } | |
| 141 return _cache[key]; | |
| 142 } | |
| 143 } | |
| 144 | |
| 145 @NoInline() | |
| 146 List extractKeys(victim) { | |
| 147 var result = JS('', '# ? Object.keys(#) : []', victim, victim); | |
| 148 return new JSArray.markFixed(result); | |
| 149 } | |
| 150 | |
| 151 /** | |
| 152 * Returns the (global) unmangled version of [name]. | |
| 153 * | |
| 154 * Normally, you should use [mangledGlobalNames] directly, but this method | |
| 155 * doesn't tell the compiler to preserve names. So this method only returns a | |
| 156 * non-null value if some other component has made the compiler preserve names. | |
| 157 * | |
| 158 * This is used, for example, to return unmangled names from TypeImpl.toString | |
| 159 * *if* names are being preserved for other reasons (use of dart:mirrors, for | |
| 160 * example). | |
| 161 */ | |
| 162 String unmangleGlobalNameIfPreservedAnyways(String name) { | |
| 163 var names = JS_EMBEDDED_GLOBAL('=Object', MANGLED_GLOBAL_NAMES); | |
| 164 return JsCache.fetch(names, name); | |
| 165 } | |
| 166 | |
| 167 String unmangleAllIdentifiersIfPreservedAnyways(String str) { | |
| 168 return JS("String", | |
| 169 r"(#).replace(/[^<,> ]+/g," | |
| 170 r"function(m) { return #[m] || m; })", | |
| 171 str, | |
| 172 JS_EMBEDDED_GLOBAL('', MANGLED_GLOBAL_NAMES)); | |
| 173 } | |
| OLD | NEW |