Flutter Engine
The Flutter Engine
method_recognizer.cc
Go to the documentation of this file.
1// Copyright (c) 2014, 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
6
7#include "vm/log.h"
8#include "vm/object.h"
10#include "vm/symbols.h"
11
12namespace dart {
13
15 const Function& function) {
16 switch (function.recognized_kind()) {
17 case MethodRecognizer::kDoubleFromInteger:
18 case MethodRecognizer::kMathMin:
19 case MethodRecognizer::kMathMax:
20 return 2;
21 default:
22 return 0;
23 }
24}
25
27 const Object& function_or_field) {
28 auto T = Thread::Current();
29 auto Z = T->zone();
30 auto& option = Object::Handle(Z);
31 if (Library::FindPragma(T, /*only_core=*/true, function_or_field,
32 Symbols::vm_exact_result_type(),
33 /*multiple=*/false, &option)) {
34 if (option.IsType()) {
35 return Type::Cast(option).type_class_id();
36 } else if (option.IsString()) {
37 auto& str = String::Cast(option);
38 // 'str' should match the pattern '([^#]+)#([^#\?]+)' where group 1
39 // is the library URI and group 2 is the class name.
40 bool parse_failure = false;
41 intptr_t library_end = -1;
42 for (intptr_t i = 0; i < str.Length(); ++i) {
43 if (str.CharAt(i) == '#') {
44 if (library_end != -1) {
45 parse_failure = true;
46 break;
47 } else {
48 library_end = i;
49 }
50 }
51 }
52 if (!parse_failure && library_end > 0) {
53 auto& tmp =
54 String::Handle(String::SubString(str, 0, library_end, Heap::kOld));
55 const auto& library = Library::Handle(Library::LookupLibrary(T, tmp));
56 if (!library.IsNull()) {
57 tmp = String::SubString(str, library_end + 1,
58 str.Length() - library_end - 1, Heap::kOld);
59 const auto& klass =
60 Class::Handle(library.LookupClassAllowPrivate(tmp));
61 if (!klass.IsNull()) {
62 return klass.id();
63 }
64 }
65 }
66 } else if (option.IsArray()) {
67 const Array& array = Array::Cast(option);
68 if (array.Length() > 0) {
69 const Object& type = Object::Handle(Array::Cast(option).At(0));
70 if (type.IsType()) {
71 return Type::Cast(type).type_class_id();
72 }
73 }
74 }
75 }
76
77 return kDynamicCid;
78}
79
81 switch (kind) {
82 case kObjectArrayGetIndexed:
83 case kObjectArraySetIndexed:
84 case kObjectArraySetIndexedUnchecked:
85 return kArrayCid;
86
87 case kGrowableArrayGetIndexed:
88 case kGrowableArraySetIndexed:
89 case kGrowableArraySetIndexedUnchecked:
90 return kGrowableObjectArrayCid;
91
92#define TYPED_DATA_GET_SET_INDEXED_CASES(clazz) \
93 case k##clazz##ArrayGetIndexed: \
94 case k##clazz##ArraySetIndexed: \
95 return kTypedData##clazz##ArrayCid; \
96 case kExternal##clazz##ArrayGetIndexed: \
97 return kExternalTypedData##clazz##ArrayCid; \
98 case k##clazz##ArrayViewGetIndexed: \
99 return kTypedData##clazz##ArrayViewCid;
100
102#undef TYPED_DATA_GET_SET_INDEXED_CASES
103
104 case kExternalUint8ArraySetIndexed:
105 return kExternalTypedDataUint8ArrayCid;
106
107 case kExternalUint8ClampedArraySetIndexed:
108 return kExternalTypedDataUint8ClampedArrayCid;
109
110 default:
111 break;
112 }
113 UNREACHABLE();
114 return kIllegalCid;
115}
116
117static const struct {
118 const char* const class_name;
119 const char* const function_name;
120 const char* const enum_name;
121 const uint32_t fp;
123 {"", "", "Unknown", 0},
124#define RECOGNIZE_METHOD(class_name, function_name, enum_name, fp) \
125 {"" #class_name, "" #function_name, #enum_name, fp},
127#undef RECOGNIZE_METHOD
129
131 if (kind >= kUnknown && kind < kNumRecognizedMethods)
132 return recognized_methods[kind].enum_name;
133 return "?";
134}
135
137 if (kind >= kUnknown && kind < kNumRecognizedMethods)
138 return recognized_methods[kind].function_name;
139 return "?";
140}
141
142// Is this method marked with the vm:recognized pragma?
144 const char* kind) {
145 const Function* functionp =
146 function.IsDynamicInvocationForwarder()
147 ? &Function::Handle(function.ForwardingTarget())
148 : &function;
150 bool is_recognized = Library::FindPragma(
151 Thread::Current(), /*only_core=*/true, *functionp,
152 Symbols::vm_recognized(), /*multiple=*/false, &options);
153 if (!is_recognized) return false;
154 if (kind == nullptr) return true;
155
156 ASSERT(options.IsString());
157 ASSERT(String::Cast(options).Equals("asm-intrinsic") ||
158 String::Cast(options).Equals("graph-intrinsic") ||
159 String::Cast(options).Equals("other"));
160 return String::Cast(options).Equals(kind);
161}
162
165 Libraries(&libs);
166 Function& func = Function::Handle();
167 bool fingerprints_match = true;
168
169 for (intptr_t i = 1; i < MethodRecognizer::kNumRecognizedMethods; i++) {
170 const MethodRecognizer::Kind kind = static_cast<MethodRecognizer::Kind>(i);
173 if (!func.IsNull()) {
174 fingerprints_match =
176 fingerprints_match;
177 func.set_recognized_kind(kind);
178 switch (kind) {
179#define RECOGNIZE_METHOD(class_name, function_name, enum_name, fp) \
180 case MethodRecognizer::k##enum_name: \
181 func.reset_unboxed_parameters_and_return(); \
182 break;
184#undef RECOGNIZE_METHOD
185 default:
186 break;
187 }
188 } else if (!FLAG_precompiled_mode) {
189 fingerprints_match = false;
190 OS::PrintErr("Missing %s::%s\n", recognized_methods[i].class_name,
192 }
193 }
194
195#define SET_FUNCTION_BIT(class_name, function_name, dest, fp, setter, value) \
196 func = Library::GetFunction(libs, #class_name, #function_name); \
197 if (!func.IsNull()) { \
198 fingerprints_match = \
199 func.CheckSourceFingerprint(fp) && fingerprints_match; \
200 func.setter(value); \
201 } else if (!FLAG_precompiled_mode) { \
202 OS::PrintErr("Missing %s::%s\n", #class_name, #function_name); \
203 fingerprints_match = false; \
204 }
205
206#define SET_IS_POLYMORPHIC_TARGET(class_name, function_name, dest, fp) \
207 SET_FUNCTION_BIT(class_name, function_name, dest, fp, \
208 set_is_polymorphic_target, true)
209
211
212#undef SET_RECOGNIZED_KIND
213#undef SET_IS_POLYMORPHIC_TARGET
214#undef SET_FUNCTION_BIT
215
216 if (!fingerprints_match) {
217 // Private names are mangled. Mangling depends on Library::private_key_.
218 // If registering a new bootstrap library, add at the end.
219 FATAL(
220 "FP mismatch while recognizing methods. If the behavior of "
221 "these functions has changed, then changes are also needed in "
222 "the VM's compiler. Otherwise the fingerprint can simply be "
223 "updated in recognized_methods_list.h\n");
224 }
225}
226
227void MethodRecognizer::Libraries(GrowableArray<Library*>* libs) {
239}
240
242 if (name.ptr() == Symbols::Plus().ptr()) {
243 return Token::kADD;
244 } else if (name.ptr() == Symbols::Minus().ptr()) {
245 return Token::kSUB;
246 } else if (name.ptr() == Symbols::Star().ptr()) {
247 return Token::kMUL;
248 } else if (name.ptr() == Symbols::Slash().ptr()) {
249 return Token::kDIV;
250 } else if (name.ptr() == Symbols::TruncDivOperator().ptr()) {
251 return Token::kTRUNCDIV;
252 } else if (name.ptr() == Symbols::Percent().ptr()) {
253 return Token::kMOD;
254 } else if (name.ptr() == Symbols::BitOr().ptr()) {
255 return Token::kBIT_OR;
256 } else if (name.ptr() == Symbols::Ampersand().ptr()) {
257 return Token::kBIT_AND;
258 } else if (name.ptr() == Symbols::Caret().ptr()) {
259 return Token::kBIT_XOR;
260 } else if (name.ptr() == Symbols::LeftShiftOperator().ptr()) {
261 return Token::kSHL;
262 } else if (name.ptr() == Symbols::RightShiftOperator().ptr()) {
263 return Token::kSHR;
264 } else if (name.ptr() == Symbols::UnsignedRightShiftOperator().ptr()) {
265 return Token::kUSHR;
266 } else if (name.ptr() == Symbols::Tilde().ptr()) {
267 return Token::kBIT_NOT;
268 } else if (name.ptr() == Symbols::UnaryMinus().ptr()) {
269 return Token::kNEGATE;
270 } else if (name.ptr() == Symbols::EqualOperator().ptr()) {
271 return Token::kEQ;
272 } else if (name.ptr() == Symbols::Token(Token::kNE).ptr()) {
273 return Token::kNE;
274 } else if (name.ptr() == Symbols::LAngleBracket().ptr()) {
275 return Token::kLT;
276 } else if (name.ptr() == Symbols::RAngleBracket().ptr()) {
277 return Token::kGT;
278 } else if (name.ptr() == Symbols::LessEqualOperator().ptr()) {
279 return Token::kLTE;
280 } else if (name.ptr() == Symbols::GreaterEqualOperator().ptr()) {
281 return Token::kGTE;
282 } else if (Field::IsGetterName(name)) {
283 return Token::kGET;
284 } else if (Field::IsSetterName(name)) {
285 return Token::kSET;
286 }
287 return Token::kILLEGAL;
288}
289
291 ASSERT(name.IsSymbol());
293 Thread* thread = Thread::Current();
294 const auto& demangled_name = String::Handle(
296 return RecognizeTokenKindHelper(demangled_name);
297 } else {
299 }
300}
301
302#define RECOGNIZE_FACTORY(symbol, class_name, constructor_name, cid, fp) \
303 {Symbols::k##symbol##Id, cid, fp, #symbol ", " #cid}, // NOLINT
304
305static const struct {
306 const intptr_t symbol_id;
307 const intptr_t cid;
308 const uint32_t finger_print;
309 const char* const name;
311 Symbols::kIllegal, -1, 0, nullptr}};
312
313#undef RECOGNIZE_FACTORY
314
315intptr_t FactoryRecognizer::ResultCid(const Function& factory) {
316 ASSERT(factory.IsFactory());
317 const Class& function_class = Class::Handle(factory.Owner());
318 const Library& lib = Library::Handle(function_class.library());
319 ASSERT((lib.ptr() == Library::CoreLibrary()) ||
320 (lib.ptr() == Library::TypedDataLibrary()));
321 const String& factory_name = String::Handle(factory.name());
322 for (intptr_t i = 0;
323 factory_recognizer_list[i].symbol_id != Symbols::kIllegal; i++) {
325 factory_name,
327 return factory_recognizer_list[i].cid;
328 }
329 }
330 return kDynamicCid;
331}
332
334 const Function& function,
335 intptr_t argument_count) {
336 if (!function.IsFactory()) {
337 return kDynamicCid;
338 }
339
340 const Class& owner = Class::Handle(zone, function.Owner());
341 if ((owner.library() != Library::CoreLibrary()) &&
342 (owner.library() != Library::TypedDataLibrary())) {
343 return kDynamicCid;
344 }
345
346 if (owner.Name() == Symbols::List().ptr()) {
347 if (function.name() == Symbols::ListFactory().ptr()) {
349 return (argument_count == 1) ? kGrowableObjectArrayCid : kArrayCid;
350 } else if (function.name() == Symbols::ListFilledFactory().ptr()) {
352 return (argument_count == 3) ? kArrayCid : kDynamicCid;
353 }
354 }
355
356 return ResultCid(function);
357}
358
359} // namespace dart
const char * options
SkIDChangeListener::List List
#define UNREACHABLE()
Definition: assert.h:248
#define Z
GLenum type
#define DART_CLASS_LIST_TYPED_DATA(V)
Definition: class_id.h:177
intptr_t Length() const
Definition: object.h:10829
LibraryPtr library() const
Definition: object.h:1333
StringPtr Name() const
Definition: object.cc:2977
static intptr_t ResultCid(const Function &factory)
static intptr_t GetResultCidOfListFactory(Zone *zone, const Function &function, intptr_t argument_count)
static bool IsGetterName(const String &function_name)
Definition: object.cc:11831
static bool IsSetterName(const String &function_name)
Definition: object.cc:11835
static bool IsDynamicInvocationForwarderName(const String &name)
Definition: object.cc:4190
StringPtr name() const
Definition: object.h:2992
static StringPtr DemangleDynamicInvocationForwarderName(const String &name)
Definition: object.cc:4198
bool CheckSourceFingerprint(int32_t fp, const char *kind=nullptr) const
Definition: object.cc:11304
bool IsFactory() const
Definition: object.h:3367
ClassPtr Owner() const
Definition: object.cc:10841
void set_recognized_kind(MethodRecognizer::Kind value) const
Definition: object.cc:8895
@ kOld
Definition: heap.h:39
static LibraryPtr CoreLibrary()
Definition: object.cc:14787
static LibraryPtr IsolateLibrary()
Definition: object.cc:14807
static LibraryPtr ConvertLibrary()
Definition: object.cc:14783
static LibraryPtr NativeWrappersLibrary()
Definition: object.cc:14821
static LibraryPtr CollectionLibrary()
Definition: object.cc:14791
static bool FindPragma(Thread *T, bool only_core, const Object &object, const String &pragma_name, bool multiple=false, Object *options=nullptr)
Definition: object.cc:4151
static LibraryPtr AsyncLibrary()
Definition: object.cc:14779
static LibraryPtr LookupLibrary(Thread *thread, const String &url)
Definition: object.cc:14599
static FunctionPtr GetFunction(const GrowableArray< Library * > &libs, const char *class_name, const char *function_name)
Definition: object.cc:15305
static LibraryPtr InternalLibrary()
Definition: object.cc:14803
static LibraryPtr FfiLibrary()
Definition: object.cc:14799
static LibraryPtr MathLibrary()
Definition: object.cc:14811
static LibraryPtr DeveloperLibrary()
Definition: object.cc:14795
static LibraryPtr TypedDataLibrary()
Definition: object.cc:14825
static intptr_t ResultCidFromPragma(const Object &function_or_field)
static bool IsMarkedAsRecognized(const Function &function, const char *kind=nullptr)
static intptr_t MethodKindToReceiverCid(Kind kind)
static intptr_t NumArgsCheckedForStaticCall(const Function &function)
static const char * KindToCString(Kind kind)
static const char * KindToFunctionNameCString(Kind kind)
static Token::Kind RecognizeTokenKind(const String &name)
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
ObjectPtr ptr() const
Definition: object.h:332
bool IsNull() const
Definition: object.h:363
static Object & Handle()
Definition: object.h:407
static Object & ZoneHandle()
Definition: object.h:419
static StringPtr SubString(const String &str, intptr_t begin_index, Heap::Space space=Heap::kNew)
Definition: object.cc:24080
static bool EqualsIgnoringPrivateKey(const String &str1, const String &str2)
Definition: object.cc:24299
static const String & Percent()
Definition: symbols.h:679
static const String & Symbol(intptr_t index)
Definition: symbols.h:607
static const String & Plus()
Definition: symbols.h:617
static const String & LAngleBracket()
Definition: symbols.h:623
static const String & BitOr()
Definition: symbols.h:619
static const String & Caret()
Definition: symbols.h:685
static const String & Tilde()
Definition: symbols.h:686
static const String & RAngleBracket()
Definition: symbols.h:626
static const String & Ampersand()
Definition: symbols.h:664
static const String & Star()
Definition: symbols.h:678
static const String & Slash()
Definition: symbols.h:670
static const String & Minus()
Definition: symbols.h:618
static const String & Token(Token::Kind token)
Definition: symbols.cc:71
Zone * zone() const
Definition: thread_state.h:37
static Thread * Current()
Definition: thread.h:362
#define ASSERT(E)
#define FATAL(error)
Dart_NativeFunction function
Definition: fuchsia.cc:51
int argument_count
Definition: fuchsia.cc:52
#define SET_IS_POLYMORPHIC_TARGET(class_name, function_name, dest, fp)
#define RECOGNIZE_METHOD(class_name, function_name, enum_name, fp)
#define TYPED_DATA_GET_SET_INDEXED_CASES(clazz)
#define RECOGNIZE_FACTORY(symbol, class_name, constructor_name, cid, fp)
Definition: dart_vm.cc:33
static bool Equals(const Object &expected, const Object &actual)
const char *const name
const intptr_t symbol_id
static Token::Kind RecognizeTokenKindHelper(const String &name)
const char *const class_name
@ kIllegalCid
Definition: class_id.h:214
@ kDynamicCid
Definition: class_id.h:253
const uint32_t finger_print
const uint32_t fp
static const struct dart::@132 recognized_methods[MethodRecognizer::kNumRecognizedMethods]
static const struct dart::@133 factory_recognizer_list[]
const char *const enum_name
const intptr_t cid
const char *const function_name
#define T
Definition: precompiler.cc:65
#define ALL_INTRINSICS_LIST(V)
#define POLYMORPHIC_TARGET_LIST(V)
#define RECOGNIZED_LIST_FACTORY_LIST(V)
#define RECOGNIZED_LIST(V)