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
14namespace dart {
15
16// Forward declarations.
17class BootstrapNatives;
18class Object;
19class Simulator;
20class 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
44void 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.
78class 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