Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(351)

Side by Side Diff: dart/sdk/lib/_internal/lib/js_helper.dart

Issue 125033003: Version 1.1.0-dev.5.1 (Closed) Base URL: http://dart.googlecode.com/svn/trunk/
Patch Set: Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « dart/sdk/lib/_internal/lib/foreign_helper.dart ('k') | dart/sdk/lib/_internal/lib/js_rti.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 _js_helper; 5 library _js_helper;
6 6
7 import 'dart:collection'; 7 import 'dart:collection';
8 import 'dart:_foreign_helper' show DART_CLOSURE_TO_JS, 8
9 JS, 9 import 'dart:_foreign_helper' show
10 JS_CALL_IN_ISOLATE, 10 DART_CLOSURE_TO_JS,
11 JS_CONST, 11 JS,
12 JS_CURRENT_ISOLATE, 12 JS_CALL_IN_ISOLATE,
13 JS_CURRENT_ISOLATE_CONTEXT, 13 JS_CONST,
14 JS_DART_OBJECT_CONSTRUCTOR, 14 JS_CURRENT_ISOLATE,
15 JS_FUNCTION_CLASS_NAME, 15 JS_CURRENT_ISOLATE_CONTEXT,
16 JS_FUNCTION_TYPE_NAMED_PARAMETERS_TAG, 16 JS_DART_OBJECT_CONSTRUCTOR,
17 JS_FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG, 17 JS_EFFECT,
18 JS_FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG, 18 JS_FUNCTION_CLASS_NAME,
19 JS_FUNCTION_TYPE_RETURN_TYPE_TAG, 19 JS_FUNCTION_TYPE_NAMED_PARAMETERS_TAG,
20 JS_FUNCTION_TYPE_TAG, 20 JS_FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG,
21 JS_FUNCTION_TYPE_VOID_RETURN_TAG, 21 JS_FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG,
22 JS_GET_NAME, 22 JS_FUNCTION_TYPE_RETURN_TYPE_TAG,
23 JS_HAS_EQUALS, 23 JS_FUNCTION_TYPE_TAG,
24 JS_IS_INDEXABLE_FIELD_NAME, 24 JS_FUNCTION_TYPE_VOID_RETURN_TAG,
25 JS_OBJECT_CLASS_NAME, 25 JS_GET_NAME,
26 JS_NULL_CLASS_NAME, 26 JS_HAS_EQUALS,
27 JS_OPERATOR_AS_PREFIX, 27 JS_IS_INDEXABLE_FIELD_NAME,
28 JS_OPERATOR_IS_PREFIX, 28 JS_NULL_CLASS_NAME,
29 JS_SIGNATURE_NAME, 29 JS_OBJECT_CLASS_NAME,
30 RAW_DART_FUNCTION_REF; 30 JS_OPERATOR_AS_PREFIX,
31 JS_OPERATOR_IS_PREFIX,
32 JS_SIGNATURE_NAME,
33 RAW_DART_FUNCTION_REF;
34
31 import 'dart:_interceptors'; 35 import 'dart:_interceptors';
32 import 'dart:_collection-dev' as _symbol_dev; 36 import 'dart:_collection-dev' as _symbol_dev;
33 import 'dart:_collection-dev' show MappedIterable; 37 import 'dart:_collection-dev' show MappedIterable;
34 38
35 import 'dart:_js_names' show 39 import 'dart:_js_names' show
36 extractKeys, 40 extractKeys,
37 mangledNames, 41 mangledNames,
38 unmangleGlobalNameIfPreservedAnyways; 42 unmangleGlobalNameIfPreservedAnyways;
39 43
40 part 'annotations.dart'; 44 part 'annotations.dart';
(...skipping 1693 matching lines...) Expand 10 before | Expand all | Expand 10 after
1734 abstract class Closure implements Function { 1738 abstract class Closure implements Function {
1735 // TODO(ahe): These constants must be in sync with 1739 // TODO(ahe): These constants must be in sync with
1736 // reflection_data_parser.dart. 1740 // reflection_data_parser.dart.
1737 static const FUNCTION_INDEX = 0; 1741 static const FUNCTION_INDEX = 0;
1738 static const NAME_INDEX = 1; 1742 static const NAME_INDEX = 1;
1739 static const CALL_NAME_INDEX = 2; 1743 static const CALL_NAME_INDEX = 2;
1740 static const REQUIRED_PARAMETER_INDEX = 3; 1744 static const REQUIRED_PARAMETER_INDEX = 3;
1741 static const OPTIONAL_PARAMETER_INDEX = 4; 1745 static const OPTIONAL_PARAMETER_INDEX = 4;
1742 static const DEFAULT_ARGUMENTS_INDEX = 5; 1746 static const DEFAULT_ARGUMENTS_INDEX = 5;
1743 1747
1748 /**
1749 * Global counter to prevent reusing function code objects.
1750 *
1751 * V8 will share the underlying function code objects when the same string is
1752 * passed to "new Function". Shared function code objects can lead to
1753 * sub-optimal performance due to polymorhism, and can be prevented by
1754 * ensuring the strings are different.
1755 */
1756 static int functionCounter = 0;
1757
1744 Closure(); 1758 Closure();
1745 1759
1746 /** 1760 /**
1747 * Creates a closure for use by implicit getters associated with a method. 1761 * Creates a new closure class for use by implicit getters associated with a
1762 * method.
1748 * 1763 *
1749 * In other words, creates a tear-off closure. 1764 * In other words, creates a tear-off closure.
1750 * 1765 *
1751 * Called from [closureFromTearOff] as well as from reflection when tearing 1766 * Called from [closureFromTearOff] as well as from reflection when tearing
1752 * of a method via [:getField:]. 1767 * of a method via [:getField:].
1753 * 1768 *
1754 * This method assumes that [functions] was created by the JavaScript function 1769 * This method assumes that [functions] was created by the JavaScript function
1755 * `addStubs` in `reflection_data_parser.dart`. That is, a list of JavaScript 1770 * `addStubs` in `reflection_data_parser.dart`. That is, a list of JavaScript
1756 * function objects with properties `$stubName` and `$callName`. 1771 * function objects with properties `$stubName` and `$callName`.
1757 * 1772 *
1758 * Further assumes that [reflectionInfo] is the end of the array created by 1773 * Further assumes that [reflectionInfo] is the end of the array created by
1759 * [dart2js.js_emitter.ContainerBuilder.addMemberMethod] starting with 1774 * [dart2js.js_emitter.ContainerBuilder.addMemberMethod] starting with
1760 * required parameter count. 1775 * required parameter count.
1761 * 1776 *
1762 * Caution: this function may be called when building constants. 1777 * Caution: this function may be called when building constants.
1763 * TODO(ahe): Don't call this function when building constants. 1778 * TODO(ahe): Don't call this function when building constants.
1764 */ 1779 */
1765 factory Closure.fromTearOff(receiver, 1780 static fromTearOff(receiver,
1766 List functions, 1781 List functions,
1767 List reflectionInfo, 1782 List reflectionInfo,
1768 bool isStatic, 1783 bool isStatic,
1769 jsArguments, 1784 jsArguments,
1770 String propertyName) { 1785 String propertyName) {
1786 JS_EFFECT(() {
1787 BoundClosure.receiverOf(JS('BoundClosure', 'void 0'));
1788 BoundClosure.selfOf(JS('BoundClosure', 'void 0'));
1789 });
1771 // TODO(ahe): All the place below using \$ should be rewritten to go 1790 // TODO(ahe): All the place below using \$ should be rewritten to go
1772 // through the namer. 1791 // through the namer.
1773 var function = JS('', '#[#]', functions, 0); 1792 var function = JS('', '#[#]', functions, 0);
1774 // TODO(ahe): Try fetching the property directly instead of using "in".
1775 if (isStatic && JS('bool', '"\$tearOff" in #', function)) {
1776 // The implicit closure of a static function is always the same.
1777 return JS('Closure', '#.\$tearOff', function);
1778 }
1779
1780 String name = JS('String|Null', '#.\$stubName', function); 1793 String name = JS('String|Null', '#.\$stubName', function);
1781 String callName = JS('String|Null', '#.\$callName', function); 1794 String callName = JS('String|Null', '#.\$callName', function);
1782 1795
1783 JS('', r'#.$reflectionInfo = #', function, reflectionInfo); 1796 JS('', '#.\$reflectionInfo = #', function, reflectionInfo);
1784 ReflectionInfo info = new ReflectionInfo(function); 1797 ReflectionInfo info = new ReflectionInfo(function);
1785 1798
1786 var functionType = info.functionType; 1799 var functionType = info.functionType;
1787 1800
1801 // function tmp() {};
1802 // tmp.prototype = BC.prototype;
1803 // var proto = new tmp;
1804 // for each computed prototype property:
1805 // proto[property] = ...;
1806 // proto._init = BC;
1807 // var dynClosureConstructor =
1808 // new Function('self', 'target', 'receiver', 'name',
1809 // 'this._init(self, target, receiver, name)');
1810 // proto.constructor = dynClosureConstructor; // Necessary?
1811 // dynClosureConstructor.prototype = proto;
1812 // return dynClosureConstructor;
1813
1814 // We need to create a new subclass of either TearOffClosure or
1815 // BoundClosure. For this, we need to create an object whose prototype is
1816 // the prototype is either TearOffClosure.prototype or
1817 // BoundClosure.prototype, respectively in pseudo JavaScript code. The
1818 // simplest way to access the JavaScript construction function of a Dart
1819 // class is to create an instance and access its constructor property. The
1820 // newly created instance could in theory be used directly as the
1821 // prototype, but it might include additional fields that we don't need.
1822 // So we only use the new instance to access the constructor property and
1823 // use Object.create to create the desired prototype.
1824 var prototype = isStatic
1825 // TODO(ahe): Safe to use Object.create?
1826 ? JS('TearOffClosure', 'Object.create(#.constructor.prototype)',
1827 new TearOffClosure())
1828 : JS('BoundClosure', 'Object.create(#.constructor.prototype)',
1829 new BoundClosure(null, null, null, null));
1830
1831 JS('', '#.\$initialize = #', prototype, JS('', '#.constructor', prototype));
1832 var constructor = isStatic
1833 ? JS('', 'function(){this.\$initialize()}')
1834 : isCsp
1835 ? JS('', 'function(a,b,c,d) {this.\$initialize(a,b,c,d)}')
1836 : JS('',
1837 'new Function("a","b","c","d",'
1838 '"this.\$initialize(a,b,c,d);"+#)',
1839 functionCounter++);
1840
1841 // TODO(ahe): Is it necessary to set the constructor property?
1842 JS('', '#.constructor = #', prototype, constructor);
1843
1844 JS('', '#.prototype = #', constructor, prototype);
1845
1788 // Create a closure and "monkey" patch it with call stubs. 1846 // Create a closure and "monkey" patch it with call stubs.
1789 Closure closure;
1790 var trampoline = function; 1847 var trampoline = function;
1848 var isIntercepted = false;
1791 if (!isStatic) { 1849 if (!isStatic) {
1792 if (JS('bool', '#.length == 1', jsArguments)) { 1850 if (JS('bool', '#.length == 1', jsArguments)) {
1793 // Intercepted call. 1851 // Intercepted call.
1794 var argument = JS('', '#[0]', jsArguments); 1852 isIntercepted = true;
1795 trampoline = forwardInterceptedCallTo(argument, receiver, function);
1796 closure = new BoundClosure(receiver, function, argument, name);
1797 } else {
1798 trampoline = forwardTo(receiver, function);
1799 closure = new BoundClosure(receiver, function, null, name);
1800 } 1853 }
1854 trampoline = forwardCallTo(function, isIntercepted);
1801 } else { 1855 } else {
1802 closure = new TearOffClosure(); 1856 JS('', '#.\$name = #', prototype, propertyName);
1803 JS('', '#.\$tearOff = #', function, closure);
1804 JS('', r'#.$name = #', closure, propertyName);
1805 } 1857 }
1806 1858
1807 var signatureFunction; 1859 var signatureFunction;
1808 if (JS('bool', 'typeof # == "number"', functionType)) { 1860 if (JS('bool', 'typeof # == "number"', functionType)) {
1809 signatureFunction = 1861 signatureFunction =
1810 JS('', '(function(s){return function(){return init.metadata[s]}})(#)', 1862 JS('', '(function(s){return function(){return init.metadata[s]}})(#)',
1811 functionType); 1863 functionType);
1812 } else if (!isStatic 1864 } else if (!isStatic
1813 && JS('bool', 'typeof # == "function"', functionType)) { 1865 && JS('bool', 'typeof # == "function"', functionType)) {
1814 signatureFunction = functionType; 1866 var getReceiver = isIntercepted
1815 JS('', r'#.$receiver = #', closure, receiver); 1867 ? RAW_DART_FUNCTION_REF(BoundClosure.receiverOf)
1868 : RAW_DART_FUNCTION_REF(BoundClosure.selfOf);
1869 signatureFunction = JS(
1870 '',
1871 'function(f,r){'
1872 'return function(){'
1873 'return f.apply({\$receiver:r(this)},arguments)'
1874 '}'
1875 '}(#,#)', functionType, getReceiver);
1816 } else { 1876 } else {
1817 throw 'Error in reflectionInfo.'; 1877 throw 'Error in reflectionInfo.';
1818 } 1878 }
1819 1879
1820 JS('', '#.\$signature = #', closure, signatureFunction); 1880 JS('', '#.\$signature = #', prototype, signatureFunction);
1821 1881
1822 JS('', '#[#] = #', closure, callName, trampoline); 1882 JS('', '#[#] = #', prototype, callName, trampoline);
1823 for (int i = 1; i < functions.length; i++) { 1883 for (int i = 1; i < functions.length; i++) {
1824 var stub = functions[i]; 1884 var stub = functions[i];
1825 var stubCallName = JS('String|Null', '#.\$callName', stub); 1885 var stubCallName = JS('String|Null', '#.\$callName', stub);
1826 // TODO(ahe): Support interceptors here. 1886 if (stubCallName != null) {
1827 JS('', '#[#] = #', closure, stubCallName, 1887 JS('', '#[#] = #', prototype, stubCallName,
1828 isStatic ? stub : forwardTo(receiver, stub)); 1888 isStatic ? stub : forwardCallTo(stub, isIntercepted));
1829 } 1889 }
1830 1890 }
1831 JS('', '#["call*"] = #', closure, function); 1891
1832 1892 JS('', '#["call*"] = #', prototype, function);
1833 return closure; 1893
1834 } 1894 return constructor;
1835 1895 }
1836 static forwardTo(receiver, function) { 1896
1837 return JS( 1897 static cspForwardCall(int arity, function) {
1838 '', 1898 var getSelf = RAW_DART_FUNCTION_REF(BoundClosure.selfOf);
1839 'function(r,f){return function(){return f.apply(r,arguments)}}(#,#)', 1899 switch (arity) {
1840 receiver, function); 1900 case 0:
1841 } 1901 return JS(
1842 1902 '',
1843 static forwardInterceptedCallTo(self, interceptor, function) { 1903 'function(F,S){'
1844 return JS( 1904 'return function(){'
1845 '', 1905 'return F.call(S(this))'
1846 'function(i,s,f){return function(){' 1906 '}'
1847 'return f.call.bind(f,i,s).apply(i,arguments)}}(#,#,#)', 1907 '}(#,#)', function, getSelf);
1848 interceptor, self, function); 1908 case 1:
1909 return JS(
1910 '',
1911 'function(F,S){'
1912 'return function(a){'
1913 'return F.call(S(this),a)'
1914 '}'
1915 '}(#,#)', function, getSelf);
1916 case 2:
1917 return JS(
1918 '',
1919 'function(F,S){'
1920 'return function(a,b){'
1921 'return F.call(S(this),a,b)'
1922 '}'
1923 '}(#,#)', function, getSelf);
1924 case 3:
1925 return JS(
1926 '',
1927 'function(F,S){'
1928 'return function(a,b,c){'
1929 'return F.call(S(this),a,b,c)'
1930 '}'
1931 '}(#,#)', function, getSelf);
1932 case 4:
1933 return JS(
1934 '',
1935 'function(F,S){'
1936 'return function(a,b,c,d){'
1937 'return F.call(S(this),a,b,c,d)'
1938 '}'
1939 '}(#,#)', function, getSelf);
1940 case 5:
1941 return JS(
1942 '',
1943 'function(F,S){'
1944 'return function(a,b,c,d,e){'
1945 'return F.call(S(this),a,b,c,d,e)'
1946 '}'
1947 '}(#,#)', function, getSelf);
1948 default:
1949 return JS(
1950 '',
1951 'function(f,s){'
1952 'return function(){'
1953 'return f.apply(s(this),arguments)'
1954 '}'
1955 '}(#,#)', function, getSelf);
1956 }
1957 }
1958
1959 static bool get isCsp => JS('bool', 'typeof dart_precompiled == "function"');
1960
1961 static forwardCallTo(function, bool isIntercepted) {
1962 if (isIntercepted) return forwardInterceptedCallTo(function);
1963 int arity = JS('int', '#.length', function);
1964 if (isCsp) {
1965 return cspForwardCall(arity, function);
1966 } else if (arity == 0) {
1967 return JS(
1968 '',
1969 '(new Function("F",#))(#)',
1970 'return function(){'
1971 'return F.call(this.${BoundClosure.selfFieldName()});${functionCount er++}'
1972 '}',
1973 function);
1974 } else if (1 <= arity && arity < 27) {
1975 String arguments = JS(
1976 'String',
1977 '"abcdefghijklmnopqrstuvwxyz".split("").splice(0,#).join(",")',
1978 arity);
1979 return JS(
1980 '',
1981 '(new Function("F",#))(#)',
1982 'return function($arguments){'
1983 'return F.call(this.${BoundClosure.selfFieldName()},$arguments);'
1984 '${functionCounter++}'
1985 '}',
1986 function);
1987 } else {
1988 return cspForwardCall(arity, function);
1989 }
1990 }
1991
1992 static cspForwardInterceptedCall(int arity, String name, function) {
1993 var getSelf = RAW_DART_FUNCTION_REF(BoundClosure.selfOf);
1994 var getReceiver = RAW_DART_FUNCTION_REF(BoundClosure.receiverOf);
1995 switch (arity) {
1996 case 0:
1997 // Intercepted functions always takes at least one argument (the
1998 // receiver).
1999 throw new RuntimeError('Intercepted function with no arguments.');
2000 case 1:
2001 return JS(
2002 '',
2003 'function(n,s,r){'
2004 'return function(){'
2005 'return s(this)[n](r(this))'
2006 '}'
2007 '}(#,#,#)', name, getSelf, getReceiver);
2008 case 2:
2009 return JS(
2010 '',
2011 'function(n,s,r){'
2012 'return function(a){'
2013 'return s(this)[n](r(this),a)'
2014 '}'
2015 '}(#,#,#)', name, getSelf, getReceiver);
2016 case 3:
2017 return JS(
2018 '',
2019 'function(n,s,r){'
2020 'return function(a,b){'
2021 'return s(this)[n](r(this),a,b)'
2022 '}'
2023 '}(#,#,#)', name, getSelf, getReceiver);
2024 case 4:
2025 return JS(
2026 '',
2027 'function(n,s,r){'
2028 'return function(a,b,c){'
2029 'return s(this)[n](r(this),a,b,c)'
2030 '}'
2031 '}(#,#,#)', name, getSelf, getReceiver);
2032 case 5:
2033 return JS(
2034 '',
2035 'function(n,s,r){'
2036 'return function(a,b,c,d){'
2037 'return s(this)[n](r(this),a,b,c,d)'
2038 '}'
2039 '}(#,#,#)', name, getSelf, getReceiver);
2040 case 6:
2041 return JS(
2042 '',
2043 'function(n,s,r){'
2044 'return function(a,b,c,d,e){'
2045 'return s(this)[n](r(this),a,b,c,d,e)'
2046 '}'
2047 '}(#,#,#)', name, getSelf, getReceiver);
2048 default:
2049 return JS(
2050 '',
2051 'function(f,s,r,a){'
2052 'return function(){'
2053 'a=[r(this)];'
2054 'Array.prototype.push.apply(a,arguments);'
2055 'return f.apply(s(this),a)'
2056 '}'
2057 '}(#,#,#)', function, getSelf, getReceiver);
2058 }
2059 }
2060
2061 static forwardInterceptedCallTo(function) {
2062 String stubName = JS('String|Null', '#.\$stubName', function);
2063 int arity = JS('int', '#.length', function);
2064 bool isCsp = JS('bool', 'typeof dart_precompiled == "function"');
2065 if (isCsp) {
2066 return cspForwardInterceptedCall(arity, stubName, function);
2067 } else if (arity == 1) {
2068 return JS('', 'new Function(#)',
2069 'return this.${BoundClosure.selfFieldName()}.$stubName('
2070 'this.${BoundClosure.receiverFieldName()});'
2071 '${functionCounter++}');
2072 } else if (1 < arity && arity < 28) {
2073 String arguments = JS(
2074 'String',
2075 '"abcdefghijklmnopqrstuvwxyz".split("").splice(0,#).join(",")',
2076 arity - 1);
2077 return JS(
2078 '',
2079 '(new Function(#))()',
2080 'return function($arguments){'
2081 'return this.${BoundClosure.selfFieldName()}.$stubName('
2082 'this.${BoundClosure.receiverFieldName()},$arguments);'
2083 '${functionCounter++}'
2084 '}');
2085 } else {
2086 return cspForwardInterceptedCall(arity, stubName, function);
2087 }
1849 } 2088 }
1850 2089
1851 String toString() => "Closure"; 2090 String toString() => "Closure";
1852 } 2091 }
1853 2092
1854 /// Called from implicit method getter (aka tear-off). 2093 /// Called from implicit method getter (aka tear-off).
1855 Closure closureFromTearOff(receiver, 2094 closureFromTearOff(receiver,
1856 functions, 2095 functions,
1857 reflectionInfo, 2096 reflectionInfo,
1858 isStatic, 2097 isStatic,
1859 jsArguments, 2098 jsArguments,
1860 name) { 2099 name) {
1861 return new Closure.fromTearOff( 2100 return Closure.fromTearOff(
1862 receiver, 2101 receiver,
1863 JSArray.markFixedList(functions), 2102 JSArray.markFixedList(functions),
1864 JSArray.markFixedList(reflectionInfo), 2103 JSArray.markFixedList(reflectionInfo),
1865 JS('bool', '!!#', isStatic), 2104 JS('bool', '!!#', isStatic),
1866 jsArguments, 2105 jsArguments,
1867 JS('String', '#', name)); 2106 JS('String', '#', name));
1868 } 2107 }
1869 2108
1870 /// Represents an implicit closure of a function. 2109 /// Represents an implicit closure of a function.
1871 class TearOffClosure extends Closure { 2110 class TearOffClosure extends Closure {
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
1910 // use the hashCode method we define for those primitive types. 2149 // use the hashCode method we define for those primitive types.
1911 receiverHashCode = _receiver.hashCode; 2150 receiverHashCode = _receiver.hashCode;
1912 } else { 2151 } else {
1913 // A bound closure on an intercepted native class, just use the 2152 // A bound closure on an intercepted native class, just use the
1914 // identity hash code. 2153 // identity hash code.
1915 receiverHashCode = Primitives.objectHashCode(_receiver); 2154 receiverHashCode = Primitives.objectHashCode(_receiver);
1916 } 2155 }
1917 return receiverHashCode ^ Primitives.objectHashCode(_target); 2156 return receiverHashCode ^ Primitives.objectHashCode(_target);
1918 } 2157 }
1919 2158
2159 @NoInline
1920 static selfOf(BoundClosure closure) => closure._self; 2160 static selfOf(BoundClosure closure) => closure._self;
1921 2161
1922 static targetOf(BoundClosure closure) => closure._target; 2162 static targetOf(BoundClosure closure) => closure._target;
1923 2163
2164 @NoInline
1924 static receiverOf(BoundClosure closure) => closure._receiver; 2165 static receiverOf(BoundClosure closure) => closure._receiver;
1925 2166
1926 static nameOf(BoundClosure closure) => closure._name; 2167 static nameOf(BoundClosure closure) => closure._name;
2168
2169 static String selfFieldNameCache;
2170
2171 static String selfFieldName() {
2172 if (selfFieldNameCache == null) {
2173 selfFieldNameCache = computeFieldNamed('self');
2174 }
2175 return selfFieldNameCache;
2176 }
2177
2178 static String receiverFieldNameCache;
2179
2180 static String receiverFieldName() {
2181 if (receiverFieldNameCache == null) {
2182 receiverFieldNameCache = computeFieldNamed('receiver');
2183 }
2184 return receiverFieldNameCache;
2185 }
2186
2187 @NoInline() @NoSideEffects()
2188 static String computeFieldNamed(String fieldName) {
2189 var template = new BoundClosure('self', 'target', 'receiver', 'name');
2190 var names = JSArray.markFixedList(
2191 JS('', 'Object.getOwnPropertyNames(#)', template));
2192 for (int i = 0; i < names.length; i++) {
2193 var name = names[i];
2194 if (JS('bool', '#[#] === #', template, name, fieldName)) {
2195 return JS('String', '#', name);
2196 }
2197 }
2198 }
1927 } 2199 }
1928 2200
1929 bool jsHasOwnProperty(var jsObject, String property) { 2201 bool jsHasOwnProperty(var jsObject, String property) {
1930 return JS('bool', r'#.hasOwnProperty(#)', jsObject, property); 2202 return JS('bool', r'#.hasOwnProperty(#)', jsObject, property);
1931 } 2203 }
1932 2204
1933 jsPropertyAccess(var jsObject, String property) { 2205 jsPropertyAccess(var jsObject, String property) {
1934 return JS('var', r'#[#]', jsObject, property); 2206 return JS('var', r'#[#]', jsObject, property);
1935 } 2207 }
1936 2208
(...skipping 805 matching lines...) Expand 10 before | Expand all | Expand 10 after
2742 3014
2743 // TODO(ahe): Remove this class and call noSuchMethod instead. 3015 // TODO(ahe): Remove this class and call noSuchMethod instead.
2744 class UnimplementedNoSuchMethodError extends Error 3016 class UnimplementedNoSuchMethodError extends Error
2745 implements NoSuchMethodError { 3017 implements NoSuchMethodError {
2746 final String _message; 3018 final String _message;
2747 3019
2748 UnimplementedNoSuchMethodError(this._message); 3020 UnimplementedNoSuchMethodError(this._message);
2749 3021
2750 String toString() => "Unsupported operation: $_message"; 3022 String toString() => "Unsupported operation: $_message";
2751 } 3023 }
OLDNEW
« no previous file with comments | « dart/sdk/lib/_internal/lib/foreign_helper.dart ('k') | dart/sdk/lib/_internal/lib/js_rti.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698