1 | // Copyright (c) 2012, 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 | #ifndef RUNTIME_VM_NATIVE_ARGUMENTS_H_ |
6 | #define RUNTIME_VM_NATIVE_ARGUMENTS_H_ |
7 | |
8 | #include "platform/assert.h" |
9 | #include "platform/memory_sanitizer.h" |
10 | #include "vm/globals.h" |
11 | #include "vm/simulator.h" |
12 | #include "vm/stub_code.h" |
13 | |
14 | namespace dart { |
15 | |
16 | // Forward declarations. |
17 | class BootstrapNatives; |
18 | class Object; |
19 | class Simulator; |
20 | class Thread; |
21 | |
22 | #if defined(TESTING) || defined(DEBUG) |
23 | |
24 | #if defined(USING_SIMULATOR) |
25 | #define CHECK_STACK_ALIGNMENT \ |
26 | { \ |
27 | uword current_sp = Simulator::Current()->get_register(SPREG); \ |
28 | ASSERT(Utils::IsAligned(current_sp, OS::ActivationFrameAlignment())); \ |
29 | } |
30 | #elif defined(HOST_OS_WINDOWS) |
31 | // The compiler may dynamically align the stack on Windows, so do not check. |
32 | #define CHECK_STACK_ALIGNMENT \ |
33 | {} |
34 | #else |
35 | #define CHECK_STACK_ALIGNMENT \ |
36 | { \ |
37 | uword (*func)() = reinterpret_cast<uword (*)()>( \ |
38 | StubCode::GetCStackPointer().EntryPoint()); \ |
39 | uword current_sp = func(); \ |
40 | ASSERT(Utils::IsAligned(current_sp, OS::ActivationFrameAlignment())); \ |
41 | } |
42 | #endif |
43 | |
44 | void VerifyOnTransition(); |
45 | |
46 | #define DEOPTIMIZE_ALOT \ |
47 | if (FLAG_deoptimize_alot) { \ |
48 | DeoptimizeFunctionsOnStack(); \ |
49 | } |
50 | |
51 | #else |
52 | |
53 | #define CHECK_STACK_ALIGNMENT \ |
54 | {} |
55 | #define DEOPTIMIZE_ALOT \ |
56 | {} |
57 | |
58 | #endif |
59 | |
60 | // Class NativeArguments is used to access arguments passed in from |
61 | // generated dart code to a runtime function or a dart library native |
62 | // function. It is also used to set the return value if any at the slot |
63 | // reserved for return values. |
64 | // All runtime function/dart library native functions have the |
65 | // following signature: |
66 | // void function_name(NativeArguments arguments); |
67 | // Inside the function, arguments are accessed as follows: |
68 | // const Instance& arg0 = Instance::CheckedHandle(arguments.NativeArgAt(0)); |
69 | // const Smi& arg1 = Smi::CheckedHandle(arguments.NativeArgAt(1)); |
70 | // If the function is generic, type arguments are accessed as follows: |
71 | // const TypeArguments& type_args = |
72 | // TypeArguments::Handle(arguments.NativeTypeArgs()); |
73 | // The return value is set as follows: |
74 | // arguments.SetReturn(result); |
75 | // NOTE: Since we pass 'this' as a pass-by-value argument in the stubs we don't |
76 | // have DISALLOW_COPY_AND_ASSIGN in the class definition and do not make it a |
77 | // subclass of ValueObject. |
78 | class NativeArguments { |
79 | public: |
80 | Thread* thread() const { return thread_; } |
81 | |
82 | // Includes type arguments vector. |
83 | int ArgCount() const { return ArgcBits::decode(argc_tag_); } |
84 | |
85 | ObjectPtr ArgAt(int index) const { |
86 | ASSERT((index >= 0) && (index < ArgCount())); |
87 | ObjectPtr* arg_ptr = |
88 | &(argv_[ReverseArgOrderBit::decode(argc_tag_) ? index : -index]); |
89 | // Tell MemorySanitizer the ObjectPtr was initialized (by generated code). |
90 | MSAN_UNPOISON(arg_ptr, kWordSize); |
91 | return *arg_ptr; |
92 | } |
93 | |
94 | void SetArgAt(int index, const Object& value) const { |
95 | ASSERT(thread_->execution_state() == Thread::kThreadInVM); |
96 | ASSERT((index >= 0) && (index < ArgCount())); |
97 | ObjectPtr* arg_ptr = |
98 | &(argv_[ReverseArgOrderBit::decode(argc_tag_) ? index : -index]); |
99 | *arg_ptr = value.raw(); |
100 | } |
101 | |
102 | // Does not include hidden type arguments vector. |
103 | int NativeArgCount() const { |
104 | int function_bits = FunctionBits::decode(argc_tag_); |
105 | return ArgCount() - NumHiddenArgs(function_bits); |
106 | } |
107 | |
108 | ObjectPtr NativeArg0() const { |
109 | int function_bits = FunctionBits::decode(argc_tag_); |
110 | if ((function_bits & (kClosureFunctionBit | kInstanceFunctionBit)) == |
111 | (kClosureFunctionBit | kInstanceFunctionBit)) { |
112 | // Retrieve the receiver from the context. |
113 | const int closure_index = |
114 | (function_bits & kGenericFunctionBit) != 0 ? 1 : 0; |
115 | const Object& closure = Object::Handle(ArgAt(closure_index)); |
116 | const Context& context = |
117 | Context::Handle(Closure::Cast(closure).context()); |
118 | return context.At(0); |
119 | } |
120 | return ArgAt(NumHiddenArgs(function_bits)); |
121 | } |
122 | |
123 | ObjectPtr NativeArgAt(int index) const { |
124 | ASSERT((index >= 0) && (index < NativeArgCount())); |
125 | if (index == 0) { |
126 | return NativeArg0(); |
127 | } |
128 | int function_bits = FunctionBits::decode(argc_tag_); |
129 | const int actual_index = index + NumHiddenArgs(function_bits); |
130 | return ArgAt(actual_index); |
131 | } |
132 | |
133 | TypeArgumentsPtr NativeTypeArgs() const { |
134 | ASSERT(ToGenericFunction()); |
135 | return TypeArguments::RawCast(ArgAt(0)); |
136 | } |
137 | |
138 | int NativeTypeArgCount() const { |
139 | if (ToGenericFunction()) { |
140 | TypeArguments& type_args = TypeArguments::Handle(NativeTypeArgs()); |
141 | if (type_args.IsNull()) { |
142 | // null vector represents infinite list of dynamics |
143 | return INT_MAX; |
144 | } |
145 | return type_args.Length(); |
146 | } |
147 | return 0; |
148 | } |
149 | |
150 | AbstractTypePtr NativeTypeArgAt(int index) const { |
151 | ASSERT((index >= 0) && (index < NativeTypeArgCount())); |
152 | TypeArguments& type_args = TypeArguments::Handle(NativeTypeArgs()); |
153 | if (type_args.IsNull()) { |
154 | // null vector represents infinite list of dynamics |
155 | return Type::dynamic_type().raw(); |
156 | } |
157 | return type_args.TypeAt(index); |
158 | } |
159 | |
160 | void SetReturn(const Object& value) const { |
161 | ASSERT(thread_->execution_state() == Thread::kThreadInVM); |
162 | *retval_ = value.raw(); |
163 | } |
164 | |
165 | ObjectPtr ReturnValue() const { |
166 | // Tell MemorySanitizer the retval_ was initialized (by generated code). |
167 | MSAN_UNPOISON(retval_, kWordSize); |
168 | return *retval_; |
169 | } |
170 | |
171 | static intptr_t thread_offset() { |
172 | return OFFSET_OF(NativeArguments, thread_); |
173 | } |
174 | static intptr_t argc_tag_offset() { |
175 | return OFFSET_OF(NativeArguments, argc_tag_); |
176 | } |
177 | static intptr_t argv_offset() { return OFFSET_OF(NativeArguments, argv_); } |
178 | static intptr_t retval_offset() { |
179 | return OFFSET_OF(NativeArguments, retval_); |
180 | } |
181 | |
182 | static intptr_t ParameterCountForResolution(const Function& function) { |
183 | ASSERT(function.is_native()); |
184 | ASSERT(!function.IsGenerativeConstructor()); // Not supported. |
185 | intptr_t count = function.NumParameters(); |
186 | if (function.is_static() && function.IsClosureFunction()) { |
187 | // The closure object is hidden and not accessible from native code. |
188 | // However, if the function is an instance closure function, the captured |
189 | // receiver located in the context is made accessible in native code at |
190 | // index 0, thereby hiding the closure object at index 0. |
191 | count--; |
192 | } |
193 | return count; |
194 | } |
195 | |
196 | static int ComputeArgcTag(const Function& function) { |
197 | ASSERT(function.is_native()); |
198 | ASSERT(!function.IsGenerativeConstructor()); // Not supported. |
199 | int argc = function.NumParameters(); |
200 | int function_bits = 0; |
201 | if (!function.is_static()) { |
202 | function_bits |= kInstanceFunctionBit; |
203 | } |
204 | if (function.IsClosureFunction()) { |
205 | function_bits |= kClosureFunctionBit; |
206 | } |
207 | if (function.IsGeneric()) { |
208 | function_bits |= kGenericFunctionBit; |
209 | argc++; |
210 | } |
211 | int tag = ArgcBits::encode(argc); |
212 | tag = FunctionBits::update(function_bits, tag); |
213 | return tag; |
214 | } |
215 | |
216 | private: |
217 | enum { |
218 | kInstanceFunctionBit = 1, |
219 | kClosureFunctionBit = 2, |
220 | kGenericFunctionBit = 4, |
221 | }; |
222 | enum ArgcTagBits { |
223 | kArgcBit = 0, |
224 | kArgcSize = 24, |
225 | kFunctionBit = kArgcBit + kArgcSize, |
226 | kFunctionSize = 3, |
227 | kReverseArgOrderBit = kFunctionBit + kFunctionSize, |
228 | kReverseArgOrderSize = 1, |
229 | }; |
230 | class ArgcBits : public BitField<intptr_t, int32_t, kArgcBit, kArgcSize> {}; |
231 | class FunctionBits |
232 | : public BitField<intptr_t, int, kFunctionBit, kFunctionSize> {}; |
233 | class ReverseArgOrderBit |
234 | : public BitField<intptr_t, bool, kReverseArgOrderBit, 1> {}; |
235 | friend class Api; |
236 | friend class NativeEntry; |
237 | friend class Interpreter; |
238 | friend class Simulator; |
239 | |
240 | // Allow simulator and interpreter to create NativeArguments in reverse order |
241 | // on the stack. |
242 | NativeArguments(Thread* thread, |
243 | int argc_tag, |
244 | ObjectPtr* argv, |
245 | ObjectPtr* retval) |
246 | : thread_(thread), |
247 | argc_tag_(ReverseArgOrderBit::update(true, argc_tag)), |
248 | argv_(argv), |
249 | retval_(retval) {} |
250 | |
251 | // Since this function is passed a RawObject directly, we need to be |
252 | // exceedingly careful when we use it. If there are any other side |
253 | // effects in the statement that may cause GC, it could lead to |
254 | // bugs. |
255 | void SetReturnUnsafe(ObjectPtr value) const { |
256 | ASSERT(thread_->execution_state() == Thread::kThreadInVM); |
257 | *retval_ = value; |
258 | } |
259 | |
260 | // Returns true if the arguments are those of an instance function call. |
261 | bool ToInstanceFunction() const { |
262 | return (FunctionBits::decode(argc_tag_) & kInstanceFunctionBit) != 0; |
263 | } |
264 | |
265 | // Returns true if the arguments are those of a closure function call. |
266 | bool ToClosureFunction() const { |
267 | return (FunctionBits::decode(argc_tag_) & kClosureFunctionBit) != 0; |
268 | } |
269 | |
270 | // Returns true if the arguments are those of a generic function call. |
271 | bool ToGenericFunction() const { |
272 | return (FunctionBits::decode(argc_tag_) & kGenericFunctionBit) != 0; |
273 | } |
274 | |
275 | int NumHiddenArgs(int function_bits) const { |
276 | int num_hidden_args = 0; |
277 | // For static closure functions, the closure at index 0 is hidden. |
278 | // In the instance closure function case, the receiver is accessed from |
279 | // the context and the closure at index 0 is hidden, so the apparent |
280 | // argument count remains unchanged. |
281 | if ((function_bits & kClosureFunctionBit) == kClosureFunctionBit) { |
282 | num_hidden_args++; |
283 | } |
284 | if ((function_bits & kGenericFunctionBit) == kGenericFunctionBit) { |
285 | num_hidden_args++; |
286 | } |
287 | return num_hidden_args; |
288 | } |
289 | |
290 | Thread* thread_; // Current thread pointer. |
291 | intptr_t argc_tag_; // Encodes argument count and invoked native call type. |
292 | ObjectPtr* argv_; // Pointer to an array of arguments to runtime call. |
293 | ObjectPtr* retval_; // Pointer to the return value area. |
294 | }; |
295 | |
296 | } // namespace dart |
297 | |
298 | #endif // RUNTIME_VM_NATIVE_ARGUMENTS_H_ |
299 | |