Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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 const Object& function_or_field) {
82 auto T = Thread::Current();
83 auto Z = T->zone();
84 auto& option = Object::Handle(Z);
85 if (Library::FindPragma(T, /*only_core=*/true, function_or_field,
86 Symbols::vm_non_nullable_result_type(),
87 /*multiple=*/false, &option)) {
88 return true;
89 }
90
91 // If nothing said otherwise, the return type is nullable.
92 return false;
93}
94
96 switch (kind) {
97 case kObjectArrayGetIndexed:
98 case kObjectArraySetIndexed:
99 case kObjectArraySetIndexedUnchecked:
100 return kArrayCid;
101
102 case kGrowableArrayGetIndexed:
103 case kGrowableArraySetIndexed:
104 case kGrowableArraySetIndexedUnchecked:
105 return kGrowableObjectArrayCid;
106
107#define TYPED_DATA_GET_SET_INDEXED_CASES(clazz) \
108 case k##clazz##ArrayGetIndexed: \
109 case k##clazz##ArraySetIndexed: \
110 return kTypedData##clazz##ArrayCid; \
111 case kExternal##clazz##ArrayGetIndexed: \
112 return kExternalTypedData##clazz##ArrayCid; \
113 case k##clazz##ArrayViewGetIndexed: \
114 return kTypedData##clazz##ArrayViewCid;
115
117#undef TYPED_DATA_GET_SET_INDEXED_CASES
118
119 case kExternalUint8ArraySetIndexed:
120 return kExternalTypedDataUint8ArrayCid;
121
122 case kExternalUint8ClampedArraySetIndexed:
123 return kExternalTypedDataUint8ClampedArrayCid;
124
125 default:
126 break;
127 }
128 UNREACHABLE();
129 return kIllegalCid;
130}
131
132static const struct {
133 const char* const class_name;
134 const char* const function_name;
135 const char* const enum_name;
136 const uint32_t fp;
138 {"", "", "Unknown", 0},
139#define RECOGNIZE_METHOD(class_name, function_name, enum_name, fp) \
140 {"" #class_name, "" #function_name, #enum_name, fp},
142#undef RECOGNIZE_METHOD
144
146 if (kind >= kUnknown && kind < kNumRecognizedMethods)
147 return recognized_methods[kind].enum_name;
148 return "?";
149}
150
152 if (kind >= kUnknown && kind < kNumRecognizedMethods)
153 return recognized_methods[kind].function_name;
154 return "?";
155}
156
157// Is this method marked with the vm:recognized pragma?
159 const char* kind) {
160 const Function* functionp =
162 ? &Function::Handle(function.ForwardingTarget())
163 : &function;
165 bool is_recognized = Library::FindPragma(
166 Thread::Current(), /*only_core=*/true, *functionp,
167 Symbols::vm_recognized(), /*multiple=*/false, &options);
168 if (!is_recognized) return false;
169 if (kind == nullptr) return true;
170
171 ASSERT(options.IsString());
172 ASSERT(String::Cast(options).Equals("asm-intrinsic") ||
173 String::Cast(options).Equals("graph-intrinsic") ||
174 String::Cast(options).Equals("other"));
175 return String::Cast(options).Equals(kind);
176}
177
180 Libraries(&libs);
181 Function& func = Function::Handle();
182 bool fingerprints_match = true;
183
184 for (intptr_t i = 1; i < MethodRecognizer::kNumRecognizedMethods; i++) {
185 const MethodRecognizer::Kind kind = static_cast<MethodRecognizer::Kind>(i);
188 if (!func.IsNull()) {
189 fingerprints_match =
191 fingerprints_match;
192 func.set_recognized_kind(kind);
193 switch (kind) {
194#define RECOGNIZE_METHOD(class_name, function_name, enum_name, fp) \
195 case MethodRecognizer::k##enum_name: \
196 func.reset_unboxed_parameters_and_return(); \
197 break;
199#undef RECOGNIZE_METHOD
200 default:
201 break;
202 }
203 } else if (!FLAG_precompiled_mode) {
204 fingerprints_match = false;
205 OS::PrintErr("Missing %s::%s\n", recognized_methods[i].class_name,
207 }
208 }
209
210#define SET_FUNCTION_BIT(class_name, function_name, dest, fp, setter, value) \
211 func = Library::GetFunction(libs, #class_name, #function_name); \
212 if (!func.IsNull()) { \
213 fingerprints_match = \
214 func.CheckSourceFingerprint(fp) && fingerprints_match; \
215 func.setter(value); \
216 } else if (!FLAG_precompiled_mode) { \
217 OS::PrintErr("Missing %s::%s\n", #class_name, #function_name); \
218 fingerprints_match = false; \
219 }
220
221#define SET_IS_POLYMORPHIC_TARGET(class_name, function_name, dest, fp) \
222 SET_FUNCTION_BIT(class_name, function_name, dest, fp, \
223 set_is_polymorphic_target, true)
224
226
227#undef SET_RECOGNIZED_KIND
228#undef SET_IS_POLYMORPHIC_TARGET
229#undef SET_FUNCTION_BIT
230
231 if (!fingerprints_match) {
232 // Private names are mangled. Mangling depends on Library::private_key_.
233 // If registering a new bootstrap library, add at the end.
234 FATAL(
235 "FP mismatch while recognizing methods. If the behavior of "
236 "these functions has changed, then changes are also needed in "
237 "the VM's compiler. Otherwise the fingerprint can simply be "
238 "updated in recognized_methods_list.h\n");
239 }
240}
241
242void MethodRecognizer::Libraries(GrowableArray<Library*>* libs) {
254}
255
257 if (name.ptr() == Symbols::Plus().ptr()) {
258 return Token::kADD;
259 } else if (name.ptr() == Symbols::Minus().ptr()) {
260 return Token::kSUB;
261 } else if (name.ptr() == Symbols::Star().ptr()) {
262 return Token::kMUL;
263 } else if (name.ptr() == Symbols::Slash().ptr()) {
264 return Token::kDIV;
265 } else if (name.ptr() == Symbols::TruncDivOperator().ptr()) {
266 return Token::kTRUNCDIV;
267 } else if (name.ptr() == Symbols::Percent().ptr()) {
268 return Token::kMOD;
269 } else if (name.ptr() == Symbols::BitOr().ptr()) {
270 return Token::kBIT_OR;
271 } else if (name.ptr() == Symbols::Ampersand().ptr()) {
272 return Token::kBIT_AND;
273 } else if (name.ptr() == Symbols::Caret().ptr()) {
274 return Token::kBIT_XOR;
275 } else if (name.ptr() == Symbols::LeftShiftOperator().ptr()) {
276 return Token::kSHL;
277 } else if (name.ptr() == Symbols::RightShiftOperator().ptr()) {
278 return Token::kSHR;
279 } else if (name.ptr() == Symbols::UnsignedRightShiftOperator().ptr()) {
280 return Token::kUSHR;
281 } else if (name.ptr() == Symbols::Tilde().ptr()) {
282 return Token::kBIT_NOT;
283 } else if (name.ptr() == Symbols::UnaryMinus().ptr()) {
284 return Token::kNEGATE;
285 } else if (name.ptr() == Symbols::EqualOperator().ptr()) {
286 return Token::kEQ;
287 } else if (name.ptr() == Symbols::Token(Token::kNE).ptr()) {
288 return Token::kNE;
289 } else if (name.ptr() == Symbols::LAngleBracket().ptr()) {
290 return Token::kLT;
291 } else if (name.ptr() == Symbols::RAngleBracket().ptr()) {
292 return Token::kGT;
293 } else if (name.ptr() == Symbols::LessEqualOperator().ptr()) {
294 return Token::kLTE;
295 } else if (name.ptr() == Symbols::GreaterEqualOperator().ptr()) {
296 return Token::kGTE;
297 } else if (Field::IsGetterName(name)) {
298 return Token::kGET;
299 } else if (Field::IsSetterName(name)) {
300 return Token::kSET;
301 }
302 return Token::kILLEGAL;
303}
304
306 ASSERT(name.IsSymbol());
308 Thread* thread = Thread::Current();
309 const auto& demangled_name = String::Handle(
311 return RecognizeTokenKindHelper(demangled_name);
312 } else {
314 }
315}
316
317#define RECOGNIZE_FACTORY(symbol, class_name, constructor_name, cid, fp) \
318 {Symbols::k##symbol##Id, cid, fp, #symbol ", " #cid}, // NOLINT
319
320static const struct {
321 const intptr_t symbol_id;
322 const intptr_t cid;
323 const uint32_t finger_print;
324 const char* const name;
326 Symbols::kIllegal, -1, 0, nullptr}};
327
328#undef RECOGNIZE_FACTORY
329
330intptr_t FactoryRecognizer::ResultCid(const Function& factory) {
331 ASSERT(factory.IsFactory());
332 const Class& function_class = Class::Handle(factory.Owner());
333 const Library& lib = Library::Handle(function_class.library());
334 ASSERT((lib.ptr() == Library::CoreLibrary()) ||
335 (lib.ptr() == Library::TypedDataLibrary()));
336 const String& factory_name = String::Handle(factory.name());
337 for (intptr_t i = 0;
338 factory_recognizer_list[i].symbol_id != Symbols::kIllegal; i++) {
340 factory_name,
342 return factory_recognizer_list[i].cid;
343 }
344 }
345 return kDynamicCid;
346}
347
349 const Function& function,
350 intptr_t argument_count) {
351 if (!function.IsFactory()) {
352 return kDynamicCid;
353 }
354
355 const Class& owner = Class::Handle(zone, function.Owner());
356 if ((owner.library() != Library::CoreLibrary()) &&
357 (owner.library() != Library::TypedDataLibrary())) {
358 return kDynamicCid;
359 }
360
361 if (owner.Name() == Symbols::List().ptr()) {
362 if (function.name() == Symbols::ListFactory().ptr()) {
364 return (argument_count == 1) ? kGrowableObjectArrayCid : kArrayCid;
365 } else if (function.name() == Symbols::ListFilledFactory().ptr()) {
367 return (argument_count == 3) ? kArrayCid : kDynamicCid;
368 }
369 }
370
371 return ResultCid(function);
372}
373
374} // namespace dart
const char * options
#define UNREACHABLE()
Definition assert.h:248
#define Z
#define DART_CLASS_LIST_TYPED_DATA(V)
Definition class_id.h:177
intptr_t Length() const
Definition object.h:10808
LibraryPtr library() const
Definition object.h:1335
StringPtr Name() const
Definition object.cc:3038
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:11882
static bool IsSetterName(const String &function_name)
Definition object.cc:11886
static bool IsDynamicInvocationForwarderName(const String &name)
Definition object.cc:4240
StringPtr name() const
Definition object.h:2972
static StringPtr DemangleDynamicInvocationForwarderName(const String &name)
Definition object.cc:4248
bool CheckSourceFingerprint(int32_t fp, const char *kind=nullptr) const
Definition object.cc:11362
bool IsFactory() const
Definition object.h:3347
ClassPtr Owner() const
Definition object.cc:10899
bool IsDynamicInvocationForwarder() const
Definition object.h:3294
void set_recognized_kind(MethodRecognizer::Kind value) const
Definition object.cc:8953
@ kOld
Definition heap.h:39
static LibraryPtr CoreLibrary()
Definition object.cc:14834
static LibraryPtr IsolateLibrary()
Definition object.cc:14854
static LibraryPtr ConvertLibrary()
Definition object.cc:14830
static LibraryPtr NativeWrappersLibrary()
Definition object.cc:14868
static LibraryPtr CollectionLibrary()
Definition object.cc:14838
static bool FindPragma(Thread *T, bool only_core, const Object &object, const String &pragma_name, bool multiple=false, Object *options=nullptr)
Definition object.cc:4201
static LibraryPtr AsyncLibrary()
Definition object.cc:14826
static LibraryPtr LookupLibrary(Thread *thread, const String &url)
Definition object.cc:14646
static FunctionPtr GetFunction(const GrowableArray< Library * > &libs, const char *class_name, const char *function_name)
Definition object.cc:15352
static LibraryPtr InternalLibrary()
Definition object.cc:14850
static LibraryPtr FfiLibrary()
Definition object.cc:14846
static LibraryPtr MathLibrary()
Definition object.cc:14858
static LibraryPtr DeveloperLibrary()
Definition object.cc:14842
static LibraryPtr TypedDataLibrary()
Definition object.cc:14872
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 bool HasNonNullableResultTypeFromPragma(const Object &function_or_field)
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:24159
static bool EqualsIgnoringPrivateKey(const String &str1, const String &str2)
Definition object.cc:24378
static const String & Percent()
Definition symbols.h:678
static const String & Symbol(intptr_t index)
Definition symbols.h:606
static const String & Plus()
Definition symbols.h:616
static const String & LAngleBracket()
Definition symbols.h:622
static const String & BitOr()
Definition symbols.h:618
static const String & Caret()
Definition symbols.h:684
static const String & Tilde()
Definition symbols.h:685
static const String & RAngleBracket()
Definition symbols.h:625
static const String & Ampersand()
Definition symbols.h:663
static const String & Star()
Definition symbols.h:677
static const String & Slash()
Definition symbols.h:669
static const String & Minus()
Definition symbols.h:617
static const String & Token(Token::Kind token)
Definition symbols.cc:71
Zone * zone() const
static Thread * Current()
Definition thread.h:361
#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)
static bool Equals(const Object &expected, const Object &actual)
static const struct dart::@132 factory_recognizer_list[]
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
static const struct dart::@131 recognized_methods[MethodRecognizer::kNumRecognizedMethods]
const uint32_t fp
const char *const enum_name
const intptr_t cid
const char *const function_name
#define T
#define ALL_INTRINSICS_LIST(V)
#define POLYMORPHIC_TARGET_LIST(V)
#define RECOGNIZED_LIST_FACTORY_LIST(V)
#define RECOGNIZED_LIST(V)