// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #ifndef VM_NATIVE_ARGUMENTS_H_ #define VM_NATIVE_ARGUMENTS_H_ #include "platform/assert.h" #include "vm/globals.h" #include "vm/stub_code.h" namespace dart { // Forward declarations. class BootstrapNatives; class Isolate; class Object; class RawObject; class Simulator; #if defined(TESTING) || defined(DEBUG) #if defined(TARGET_OS_WINDOWS) // The compiler may dynamically align the stack on Windows, so do not check. #define CHECK_STACK_ALIGNMENT { } #else #define CHECK_STACK_ALIGNMENT { \ uword (*func)() = \ reinterpret_cast(StubCode::GetStackPointerEntryPoint()); \ uword current_sp = func(); \ ASSERT((OS::ActivationFrameAlignment() == 0) || \ (Utils::IsAligned(current_sp, OS::ActivationFrameAlignment()))); \ } #endif #else #define CHECK_STACK_ALIGNMENT { } #endif void SetReturnValueHelper(Dart_NativeArguments, Dart_Handle); // Class NativeArguments is used to access arguments passed in from // generated dart code to a runtime function or a dart library native // function. It is also used to set the return value if any at the slot // reserved for return values. // All runtime function/dart library native functions have the // following signature: // void function_name(NativeArguments arguments); // Inside the function, arguments are accessed as follows: // const Instance& arg0 = Instance::CheckedHandle(arguments.ArgAt(0)); // const Smi& arg1 = Smi::CheckedHandle(arguments.ArgAt(1)); // The return value is set as follows: // arguments.SetReturn(result); // NOTE: Since we pass 'this' as a pass-by-value argument in the stubs we don't // have DISALLOW_COPY_AND_ASSIGN in the class definition and do not make it a // subclass of ValueObject. class NativeArguments { public: Isolate* isolate() const { return isolate_; } int ArgCount() const { return ArgcBits::decode(argc_tag_); } // Returns true if the arguments are those of an instance function call. bool ToInstanceFunction() const { return InstanceFunctionBit::decode(argc_tag_); } // Returns true if the arguments are those of a closure function call. bool ToClosureFunction() const { return ClosureFunctionBit::decode(argc_tag_); } RawObject* ArgAt(int index) const { ASSERT((index >= 0) && (index < ArgCount())); return (*argv_)[-index]; } int NumHiddenArgs() const { // For static closure functions, the closure at index 0 is hidden. // In the instance closure function case, the receiver is accessed from // the context and the closure at index 0 is hidden, so the apparent // argument count remains unchanged. if (ToClosureFunction() && !ToInstanceFunction()) { return 1; } return 0; } int NativeArgCount() const { return ArgCount() - NumHiddenArgs(); } RawObject* NativeArgAt(int index) const { ASSERT((index >= 0) && (index < NativeArgCount())); if ((index == 0) && ToClosureFunction() && ToInstanceFunction()) { // Retrieve the receiver from the context. const Context& context = Context::Handle(isolate_->top_context()); return context.At(0); } else { const int actual_index = index + NumHiddenArgs(); return ArgAt(actual_index); } } void SetReturn(const Object& value) const; static intptr_t isolate_offset() { return OFFSET_OF(NativeArguments, isolate_); } static intptr_t argc_tag_offset() { return OFFSET_OF(NativeArguments, argc_tag_); } static intptr_t argv_offset() { return OFFSET_OF(NativeArguments, argv_); } static intptr_t retval_offset() { return OFFSET_OF(NativeArguments, retval_); } static int ParameterCountForResolution(const Function& function) { ASSERT(function.is_native()); ASSERT(!function.IsConstructor()); // Not supported. int count = function.NumParameters(); if (function.is_static() && function.IsClosureFunction()) { // The closure object is hidden and not accessible from native code. // However, if the function is an instance closure function, the captured // receiver located in the context is made accessible in native code at // index 0, thereby hidding the closure object at index 0. count--; } return count; } static int ComputeArgcTag(const Function& function) { ASSERT(function.is_native()); ASSERT(!function.IsConstructor()); // Not supported. int tag = ArgcBits::encode(function.NumParameters()); tag = InstanceFunctionBit::update(!function.is_static(), tag); tag = ClosureFunctionBit::update(function.IsClosureFunction(), tag); return tag; } private: enum ArgcTagBits { kArgcBit = 0, kArgcSize = 24, kInstanceFunctionBit = 24, kClosureFunctionBit = 25, }; class ArgcBits : public BitField {}; class InstanceFunctionBit : public BitField {}; class ClosureFunctionBit : public BitField {}; friend class BootstrapNatives; friend class Simulator; friend void SetReturnValueHelper(Dart_NativeArguments, Dart_Handle); // Since this function is passed a RawObject directly, we need to be // exceedingly careful when we use it. If there are any other side // effects in the statement that may cause GC, it could lead to // bugs. void SetReturnUnsafe(RawObject* value) const; Isolate* isolate_; // Current isolate pointer. int argc_tag_; // Encodes argument count and invoked native call type. RawObject*(*argv_)[]; // Pointer to an array of arguments to runtime call. RawObject** retval_; // Pointer to the return value area. }; } // namespace dart #endif // VM_NATIVE_ARGUMENTS_H_