| 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 dart._js_names; | 5 library dart._js_names; |
| 6 | 6 |
| 7 import 'dart:_js_embedded_names' show | 7 import 'dart:_js_embedded_names' show |
| 8 JsGetName, | 8 JsGetName, |
| 9 MANGLED_GLOBAL_NAMES, | 9 MANGLED_GLOBAL_NAMES, |
| 10 MANGLED_NAMES; | 10 MANGLED_NAMES; |
| 11 | 11 |
| 12 import 'dart:_foreign_helper' show | 12 import 'dart:_foreign_helper' show |
| 13 JS, | 13 JS, |
| 14 JS_EMBEDDED_GLOBAL, | 14 JS_EMBEDDED_GLOBAL, |
| 15 JS_GET_NAME; | 15 JS_GET_NAME; |
| 16 | 16 |
| 17 import 'dart:_js_helper' show | 17 import 'dart:_js_helper' show |
| 18 JsCache, | 18 JsCache, |
| 19 NoInline; | 19 NoInline; |
| 20 | 20 |
| 21 import 'dart:_interceptors' show JSArray; | 21 import 'dart:_interceptors' show JSArray; |
| 22 | 22 |
| 23 /// No-op method that is called to inform the compiler that unmangled named | 23 /// No-op method that is called to inform the compiler that unmangled named |
| 24 /// must be preserved. | 24 /// must be preserved. |
| 25 preserveNames() {} | 25 preserveNames() {} |
| 26 | 26 |
| 27 /// A map from mangled names to "reflective" names, that is, unmangled names | 27 /// A map from mangled names to "reflective" names, that is, unmangled names |
| 28 /// with some additional information, such as, number of required arguments. | 28 /// with some additional information, such as, number of required arguments. |
| 29 /// This map is for mangled names used as instance members. | 29 /// This map is for mangled names used as instance members. |
| 30 final Map<String, String> mangledNames = | 30 final _LazyMangledNamesMap mangledNames = new _LazyMangledInstanceNamesMap( |
| 31 computeMangledNames( | 31 JS_EMBEDDED_GLOBAL('=Object', MANGLED_NAMES)); |
| 32 JS_EMBEDDED_GLOBAL('=Object', MANGLED_NAMES), | |
| 33 false); | |
| 34 | 32 |
| 35 /// A map from "reflective" names to mangled names (the reverse of | 33 /// A map from "reflective" names to mangled names (the reverse of |
| 36 /// [mangledNames]). | 34 /// [mangledNames]). |
| 37 final Map<String, String> reflectiveNames = | 35 final _LazyReflectiveNamesMap reflectiveNames = |
| 38 computeReflectiveNames(mangledNames); | 36 new _LazyReflectiveNamesMap(JS_EMBEDDED_GLOBAL('=Object', MANGLED_NAMES), |
| 37 true); |
| 39 | 38 |
| 40 /// A map from mangled names to "reflective" names (see [mangledNames]). This | 39 /// A map from mangled names to "reflective" names (see [mangledNames]). This |
| 41 /// map is for globals, that is, static and top-level members. | 40 /// map is for globals, that is, static and top-level members. |
| 42 final Map<String, String> mangledGlobalNames = computeMangledNames( | 41 final _LazyMangledNamesMap mangledGlobalNames = new _LazyMangledNamesMap( |
| 43 JS_EMBEDDED_GLOBAL('=Object', MANGLED_GLOBAL_NAMES), | 42 JS_EMBEDDED_GLOBAL('=Object', MANGLED_GLOBAL_NAMES)); |
| 44 true); | |
| 45 | 43 |
| 46 /// A map from "reflective" names to mangled names (the reverse of | 44 /// A map from "reflective" names to mangled names (the reverse of |
| 47 /// [mangledGlobalNames]). | 45 /// [mangledGlobalNames]). |
| 48 final Map<String, String> reflectiveGlobalNames = | 46 final _LazyReflectiveNamesMap reflectiveGlobalNames = |
| 49 computeReflectiveNames(mangledGlobalNames); | 47 new _LazyReflectiveNamesMap( |
| 48 JS_EMBEDDED_GLOBAL('=Object', MANGLED_GLOBAL_NAMES), false); |
| 50 | 49 |
| 51 /// [jsMangledNames] is a JavaScript object literal. The keys are the mangled | 50 /// Implements a mapping from mangled names to their reflective counterparts. |
| 52 /// names, and the values are the "reflective" names. | 51 /// The propertiy names of [_jsMangledNames] are the mangled names, and the |
| 53 Map<String, String> computeMangledNames(jsMangledNames, bool isGlobal) { | 52 /// values are the "reflective" names. |
| 54 preserveNames(); | 53 class _LazyMangledNamesMap { |
| 55 var keys = extractKeys(jsMangledNames); | 54 /// [_jsMangledNames] is a JavaScript object literal. |
| 56 var result = <String, String>{}; | 55 var _jsMangledNames; |
| 57 String getterPrefix = JS_GET_NAME(JsGetName.GETTER_PREFIX); | 56 |
| 58 int getterPrefixLength = getterPrefix.length; | 57 _LazyMangledNamesMap(this._jsMangledNames); |
| 59 String setterPrefix = JS_GET_NAME(JsGetName.SETTER_PREFIX); | 58 |
| 60 for (String key in keys) { | 59 String operator[](String key) { |
| 61 String value = JS('String', '#[#]', jsMangledNames, key); | 60 String result = JS('var', '#[#]', _jsMangledNames, key); |
| 62 result[key] = value; | 61 // Filter out all non-string values to protect against polution from |
| 63 if (!isGlobal) { | 62 // anciliary fields in [_jsMangledNames]. |
| 64 if (key.startsWith(getterPrefix)) { | 63 bool filter = |
| 65 result['$setterPrefix${key.substring(getterPrefixLength)}'] = '$value='; | 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)}'; |
| 66 } | 128 } |
| 67 } | 129 } |
| 130 return result; |
| 68 } | 131 } |
| 69 return result; | |
| 70 } | |
| 71 | 132 |
| 72 Map<String, String> computeReflectiveNames(Map<String, String> map) { | 133 int get _jsMangledNamesLength => JS('int', '#.length', _jsMangledNames); |
| 73 preserveNames(); | 134 |
| 74 var result = <String, String>{}; | 135 String operator[](String key) { |
| 75 map.forEach((String mangledName, String reflectiveName) { | 136 if (_cache == null || _jsMangledNamesLength != _cacheLength) { |
| 76 result[reflectiveName] = mangledName; | 137 _cache = _updateReflectiveNames(); |
| 77 }); | 138 _cacheLength = _jsMangledNamesLength; |
| 78 return result; | 139 } |
| 140 return _cache[key]; |
| 141 } |
| 79 } | 142 } |
| 80 | 143 |
| 81 @NoInline() | 144 @NoInline() |
| 82 List extractKeys(victim) { | 145 List extractKeys(victim) { |
| 83 var result = JS('', '# ? Object.keys(#) : []', victim, victim); | 146 var result = JS('', '# ? Object.keys(#) : []', victim, victim); |
| 84 return new JSArray.markFixed(result); | 147 return new JSArray.markFixed(result); |
| 85 } | 148 } |
| 86 | 149 |
| 87 /** | 150 /** |
| 88 * Returns the (global) unmangled version of [name]. | 151 * Returns the (global) unmangled version of [name]. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 100 return JsCache.fetch(names, name); | 163 return JsCache.fetch(names, name); |
| 101 } | 164 } |
| 102 | 165 |
| 103 String unmangleAllIdentifiersIfPreservedAnyways(String str) { | 166 String unmangleAllIdentifiersIfPreservedAnyways(String str) { |
| 104 return JS("String", | 167 return JS("String", |
| 105 r"(#).replace(/[^<,> ]+/g," | 168 r"(#).replace(/[^<,> ]+/g," |
| 106 r"function(m) { return #[m] || m; })", | 169 r"function(m) { return #[m] || m; })", |
| 107 str, | 170 str, |
| 108 JS_EMBEDDED_GLOBAL('', MANGLED_GLOBAL_NAMES)); | 171 JS_EMBEDDED_GLOBAL('', MANGLED_GLOBAL_NAMES)); |
| 109 } | 172 } |
| OLD | NEW |