1// Copyright (c) 2011, 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#include "vm/resolver.h"
6
7#include "vm/dart_entry.h"
8#include "vm/flags.h"
9#include "vm/isolate.h"
10#include "vm/log.h"
11#include "vm/object.h"
12#include "vm/object_store.h"
13#include "vm/symbols.h"
14
15namespace dart {
16
17DEFINE_FLAG(bool, trace_resolving, false, "Trace resolving.");
18
19// The actual names of named arguments are not checked by the dynamic resolver,
20// but by the method entry code. It is important that the dynamic resolver
21// checks that no named arguments are passed to a method that does not accept
22// them, since the entry code of such a method does not check for named
23// arguments. The dynamic resolver actually checks that a valid number of named
24// arguments is passed in.
25FunctionPtr Resolver::ResolveDynamic(const Instance& receiver,
26 const String& function_name,
27 const ArgumentsDescriptor& args_desc) {
28 // Figure out type of receiver first.
29 const Class& cls = Class::Handle(receiver.clazz());
30 return ResolveDynamicForReceiverClass(cls, function_name, args_desc);
31}
32
33static FunctionPtr ResolveDynamicAnyArgsWithCustomLookup(
34 Zone* zone,
35 const Class& receiver_class,
36 const String& function_name,
37 bool allow_add,
38 std::function<FunctionPtr(Class&, const String&)> lookup) {
39 Class& cls = Class::Handle(zone, receiver_class.raw());
40 if (FLAG_trace_resolving) {
41 THR_Print("ResolveDynamic '%s' for class %s\n", function_name.ToCString(),
42 String::Handle(zone, cls.Name()).ToCString());
43 }
44 Function& function = Function::Handle(zone);
45
46 const String& demangled = String::Handle(
47 zone,
48 Function::IsDynamicInvocationForwarderName(function_name)
49 ? Function::DemangleDynamicInvocationForwarderName(function_name)
50 : function_name.raw());
51
52 const bool is_getter = Field::IsGetterName(demangled);
53 String& demangled_getter_name = String::Handle();
54 if (is_getter) {
55 demangled_getter_name = Field::NameFromGetter(demangled);
56 }
57
58 const bool is_dyn_call = demangled.raw() != function_name.raw();
59
60 while (!cls.IsNull()) {
61 if (is_dyn_call) {
62 // Try to find a dyn:* forwarder & return it.
63 function = cls.GetInvocationDispatcher(
64 function_name, Array::null_array(),
65 FunctionLayout::kDynamicInvocationForwarder,
66 /*create_if_absent=*/false);
67 }
68 if (!function.IsNull()) return function.raw();
69
70 function = lookup(cls, demangled);
71#if !defined(DART_PRECOMPILED_RUNTIME)
72 // In JIT we might need to lazily create a dyn:* forwarder.
73 if (is_dyn_call && !function.IsNull()) {
74 function =
75 function.GetDynamicInvocationForwarder(function_name, allow_add);
76 }
77#endif
78 if (!function.IsNull()) return function.raw();
79
80 // Getter invocation might actually be a method extraction.
81 if (is_getter) {
82 function = lookup(cls, demangled_getter_name);
83 if (!function.IsNull()) {
84 if (allow_add && FLAG_lazy_dispatchers) {
85 // We were looking for the getter but found a method with the same
86 // name. Create a method extractor and return it.
87 // The extractor does not exist yet, so using GetMethodExtractor is
88 // not necessary here.
89 function = function.CreateMethodExtractor(demangled);
90 return function.raw();
91 } else {
92 return Function::null();
93 }
94 }
95 }
96 cls = cls.SuperClass();
97 }
98 return function.raw();
99}
100
101static FunctionPtr ResolveDynamicForReceiverClassWithCustomLookup(
102 const Class& receiver_class,
103 const String& function_name,
104 const ArgumentsDescriptor& args_desc,
105 bool allow_add,
106 std::function<FunctionPtr(Class&, const String&)> lookup) {
107 Thread* thread = Thread::Current();
108 Zone* zone = thread->zone();
109
110 Function& function = Function::Handle(
111 zone, ResolveDynamicAnyArgsWithCustomLookup(
112 zone, receiver_class, function_name, allow_add, lookup));
113
114 if (function.IsNull() || !function.AreValidArguments(args_desc, NULL)) {
115 // Return a null function to signal to the upper levels to dispatch to
116 // "noSuchMethod" function.
117 if (FLAG_trace_resolving) {
118 String& error_message =
119 String::Handle(zone, Symbols::New(thread, "function not found"));
120 if (!function.IsNull()) {
121 // Obtain more detailed error message.
122 function.AreValidArguments(args_desc, &error_message);
123 }
124 THR_Print("ResolveDynamic error '%s': %s.\n", function_name.ToCString(),
125 error_message.ToCString());
126 }
127 return Function::null();
128 }
129 return function.raw();
130}
131
132FunctionPtr Resolver::ResolveDynamicForReceiverClass(
133 const Class& receiver_class,
134 const String& function_name,
135 const ArgumentsDescriptor& args_desc,
136 bool allow_add) {
137 return ResolveDynamicForReceiverClassWithCustomLookup(
138 receiver_class, function_name, args_desc, allow_add,
139 std::mem_fn(&Class::LookupDynamicFunction));
140}
141
142FunctionPtr Resolver::ResolveDynamicForReceiverClassAllowPrivate(
143 const Class& receiver_class,
144 const String& function_name,
145 const ArgumentsDescriptor& args_desc,
146 bool allow_add) {
147 return ResolveDynamicForReceiverClassWithCustomLookup(
148 receiver_class, function_name, args_desc, allow_add,
149 std::mem_fn(&Class::LookupDynamicFunctionAllowPrivate));
150}
151
152FunctionPtr Resolver::ResolveDynamicAnyArgs(Zone* zone,
153 const Class& receiver_class,
154 const String& function_name,
155 bool allow_add) {
156 return ResolveDynamicAnyArgsWithCustomLookup(
157 zone, receiver_class, function_name, allow_add,
158 std::mem_fn(&Class::LookupDynamicFunctionAllowPrivate));
159}
160
161FunctionPtr Resolver::ResolveDynamicAnyArgsAllowPrivate(
162 Zone* zone,
163 const Class& receiver_class,
164 const String& function_name,
165 bool allow_add) {
166 return ResolveDynamicAnyArgsWithCustomLookup(
167 zone, receiver_class, function_name, allow_add,
168 std::mem_fn(&Class::LookupDynamicFunctionAllowPrivate));
169}
170
171FunctionPtr Resolver::ResolveStatic(const Library& library,
172 const String& class_name,
173 const String& function_name,
174 intptr_t type_args_len,
175 intptr_t num_arguments,
176 const Array& argument_names) {
177 ASSERT(!library.IsNull());
178 Function& function = Function::Handle();
179 if (class_name.IsNull() || (class_name.Length() == 0)) {
180 // Check if we are referring to a top level function.
181 const Object& object = Object::Handle(library.ResolveName(function_name));
182 if (!object.IsNull() && object.IsFunction()) {
183 function ^= object.raw();
184 if (!function.AreValidArguments(type_args_len, num_arguments,
185 argument_names, NULL)) {
186 if (FLAG_trace_resolving) {
187 String& error_message = String::Handle();
188 // Obtain more detailed error message.
189 function.AreValidArguments(type_args_len, num_arguments,
190 argument_names, &error_message);
191 THR_Print("ResolveStatic error '%s': %s.\n",
192 function_name.ToCString(), error_message.ToCString());
193 }
194 function = Function::null();
195 }
196 } else {
197 if (FLAG_trace_resolving) {
198 THR_Print("ResolveStatic error: function '%s' not found.\n",
199 function_name.ToCString());
200 }
201 }
202 } else {
203 // Lookup class_name in the library's class dictionary to get at
204 // the dart class object. If class_name is not found in the dictionary
205 // ResolveStatic will return a NULL function object.
206 const Class& cls = Class::Handle(library.LookupClass(class_name));
207 if (!cls.IsNull()) {
208 function = ResolveStatic(cls, function_name, type_args_len, num_arguments,
209 argument_names);
210 }
211 if (FLAG_trace_resolving && function.IsNull()) {
212 THR_Print("ResolveStatic error: function '%s.%s' not found.\n",
213 class_name.ToCString(), function_name.ToCString());
214 }
215 }
216 return function.raw();
217}
218
219FunctionPtr Resolver::ResolveStatic(const Class& cls,
220 const String& function_name,
221 intptr_t type_args_len,
222 intptr_t num_arguments,
223 const Array& argument_names) {
224 ASSERT(!cls.IsNull());
225 if (FLAG_trace_resolving) {
226 THR_Print("ResolveStatic '%s'\n", function_name.ToCString());
227 }
228 const Function& function =
229 Function::Handle(cls.LookupStaticFunction(function_name));
230 if (function.IsNull() ||
231 !function.AreValidArguments(type_args_len, num_arguments, argument_names,
232 NULL)) {
233 // Return a null function to signal to the upper levels to throw a
234 // resolution error or maybe throw the error right here.
235 if (FLAG_trace_resolving) {
236 String& error_message = String::Handle(String::New("function not found"));
237 if (!function.IsNull()) {
238 // Obtain more detailed error message.
239 function.AreValidArguments(type_args_len, num_arguments, argument_names,
240 &error_message);
241 }
242 THR_Print("ResolveStatic error '%s': %s.\n", function_name.ToCString(),
243 error_message.ToCString());
244 }
245 return Function::null();
246 }
247 return function.raw();
248}
249
250} // namespace dart
251