1 // Copyright 2016 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_BUILTINS_BUILTINS_UTILS_H_ 6 #define V8_BUILTINS_BUILTINS_UTILS_H_ 7 8 #include "src/base/logging.h" 9 #include "src/builtins/builtins.h" 10 #include "src/execution/arguments.h" 11 #include "src/execution/isolate.h" 12 #include "src/heap/factory.h" 13 #include "src/logging/runtime-call-stats-scope.h" 14 15 namespace v8 { 16 namespace internal { 17 18 // Arguments object passed to C++ builtins. 19 class BuiltinArguments : public JavaScriptArguments { 20 public: BuiltinArguments(int length,Address * arguments)21 BuiltinArguments(int length, Address* arguments) 22 : Arguments(length, arguments) { 23 // Check we have at least the receiver. 24 DCHECK_LE(1, this->length()); 25 } 26 27 Object operator[](int index) const { 28 DCHECK_LT(index, length()); 29 return Object(*address_of_arg_at(index + kArgsOffset)); 30 } 31 32 template <class S = Object> at(int index)33 Handle<S> at(int index) const { 34 DCHECK_LT(index, length()); 35 return Handle<S>(address_of_arg_at(index + kArgsOffset)); 36 } 37 set_at(int index,Object value)38 inline void set_at(int index, Object value) { 39 DCHECK_LT(index, length()); 40 *address_of_arg_at(index + kArgsOffset) = value.ptr(); 41 } 42 43 // Note: this should return the address after the receiver, 44 // even when length() == 1. address_of_first_argument()45 inline Address* address_of_first_argument() const { 46 return address_of_arg_at(kArgsOffset + 1); // Skips receiver. 47 } 48 49 static constexpr int kNewTargetOffset = 0; 50 static constexpr int kTargetOffset = 1; 51 static constexpr int kArgcOffset = 2; 52 static constexpr int kPaddingOffset = 3; 53 54 static constexpr int kNumExtraArgs = 4; 55 static constexpr int kNumExtraArgsWithReceiver = 5; 56 static constexpr int kArgsOffset = 4; 57 58 inline Handle<Object> atOrUndefined(Isolate* isolate, int index) const; 59 inline Handle<Object> receiver() const; 60 inline Handle<JSFunction> target() const; 61 inline Handle<HeapObject> new_target() const; 62 63 // Gets the total number of arguments including the receiver (but 64 // excluding extra arguments). length()65 int length() const { return Arguments::length() - kNumExtraArgs; } 66 }; 67 68 // ---------------------------------------------------------------------------- 69 // Support macro for defining builtins in C++. 70 // ---------------------------------------------------------------------------- 71 // 72 // A builtin function is defined by writing: 73 // 74 // BUILTIN(name) { 75 // ... 76 // } 77 // 78 // In the body of the builtin function the arguments can be accessed 79 // through the BuiltinArguments object args. 80 // TODO(cbruni): add global flag to check whether any tracing events have been 81 // enabled. 82 #define BUILTIN_RCS(name) \ 83 V8_WARN_UNUSED_RESULT static Object Builtin_Impl_##name( \ 84 BuiltinArguments args, Isolate* isolate); \ 85 \ 86 V8_NOINLINE static Address Builtin_Impl_Stats_##name( \ 87 int args_length, Address* args_object, Isolate* isolate) { \ 88 BuiltinArguments args(args_length, args_object); \ 89 RCS_SCOPE(isolate, RuntimeCallCounterId::kBuiltin_##name); \ 90 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.runtime"), \ 91 "V8.Builtin_" #name); \ 92 return CONVERT_OBJECT(Builtin_Impl_##name(args, isolate)); \ 93 } \ 94 \ 95 V8_WARN_UNUSED_RESULT Address Builtin_##name( \ 96 int args_length, Address* args_object, Isolate* isolate) { \ 97 DCHECK(isolate->context().is_null() || isolate->context().IsContext()); \ 98 if (V8_UNLIKELY(TracingFlags::is_runtime_stats_enabled())) { \ 99 return Builtin_Impl_Stats_##name(args_length, args_object, isolate); \ 100 } \ 101 BuiltinArguments args(args_length, args_object); \ 102 return CONVERT_OBJECT(Builtin_Impl_##name(args, isolate)); \ 103 } \ 104 \ 105 V8_WARN_UNUSED_RESULT static Object Builtin_Impl_##name( \ 106 BuiltinArguments args, Isolate* isolate) 107 108 #define BUILTIN_NO_RCS(name) \ 109 V8_WARN_UNUSED_RESULT static Object Builtin_Impl_##name( \ 110 BuiltinArguments args, Isolate* isolate); \ 111 \ 112 V8_WARN_UNUSED_RESULT Address Builtin_##name( \ 113 int args_length, Address* args_object, Isolate* isolate) { \ 114 DCHECK(isolate->context().is_null() || isolate->context().IsContext()); \ 115 BuiltinArguments args(args_length, args_object); \ 116 return CONVERT_OBJECT(Builtin_Impl_##name(args, isolate)); \ 117 } \ 118 \ 119 V8_WARN_UNUSED_RESULT static Object Builtin_Impl_##name( \ 120 BuiltinArguments args, Isolate* isolate) 121 122 #ifdef V8_RUNTIME_CALL_STATS 123 #define BUILTIN(name) BUILTIN_RCS(name) 124 #else // V8_RUNTIME_CALL_STATS 125 #define BUILTIN(name) BUILTIN_NO_RCS(name) 126 #endif // V8_RUNTIME_CALL_STATS 127 // ---------------------------------------------------------------------------- 128 129 #define CHECK_RECEIVER(Type, name, method) \ 130 if (!args.receiver()->Is##Type()) { \ 131 THROW_NEW_ERROR_RETURN_FAILURE( \ 132 isolate, \ 133 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, \ 134 isolate->factory()->NewStringFromAsciiChecked(method), \ 135 args.receiver())); \ 136 } \ 137 Handle<Type> name = Handle<Type>::cast(args.receiver()) 138 139 // Throws a TypeError for {method} if the receiver is not coercible to Object, 140 // or converts the receiver to a String otherwise and assigns it to a new var 141 // with the given {name}. 142 #define TO_THIS_STRING(name, method) \ 143 if (args.receiver()->IsNullOrUndefined(isolate)) { \ 144 THROW_NEW_ERROR_RETURN_FAILURE( \ 145 isolate, \ 146 NewTypeError(MessageTemplate::kCalledOnNullOrUndefined, \ 147 isolate->factory()->NewStringFromAsciiChecked(method))); \ 148 } \ 149 Handle<String> name; \ 150 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( \ 151 isolate, name, Object::ToString(isolate, args.receiver())) 152 153 } // namespace internal 154 } // namespace v8 155 156 #endif // V8_BUILTINS_BUILTINS_UTILS_H_ 157