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 14 namespace v8 { 15 namespace internal { 16 17 // Arguments object passed to C++ builtins. 18 class BuiltinArguments : public JavaScriptArguments { 19 public: BuiltinArguments(int length,Address * arguments)20 BuiltinArguments(int length, Address* arguments) 21 : Arguments(length, arguments) { 22 // Check we have at least the receiver. 23 DCHECK_LE(1, this->length()); 24 } 25 26 Object operator[](int index) const { 27 DCHECK_LT(index, length()); 28 return Object(*address_of_arg_at(index + kArgsOffset)); 29 } 30 31 template <class S = Object> at(int index)32 Handle<S> at(int index) const { 33 DCHECK_LT(index, length()); 34 return Handle<S>(address_of_arg_at(index + kArgsOffset)); 35 } 36 set_at(int index,Object value)37 inline void set_at(int index, Object value) { 38 DCHECK_LT(index, length()); 39 *address_of_arg_at(index + kArgsOffset) = value.ptr(); 40 } 41 42 // Note: this should return the address after the receiver, 43 // even when length() == 1. address_of_first_argument()44 inline Address* address_of_first_argument() const { 45 return address_of_arg_at(kArgsOffset + 1); // Skips receiver. 46 } 47 48 static constexpr int kNewTargetOffset = 0; 49 static constexpr int kTargetOffset = 1; 50 static constexpr int kArgcOffset = 2; 51 static constexpr int kPaddingOffset = 3; 52 53 static constexpr int kNumExtraArgs = 4; 54 static constexpr int kNumExtraArgsWithReceiver = 5; 55 static constexpr int kArgsOffset = 4; 56 57 inline Handle<Object> atOrUndefined(Isolate* isolate, int index) const; 58 inline Handle<Object> receiver() const; 59 inline Handle<JSFunction> target() const; 60 inline Handle<HeapObject> new_target() const; 61 62 // Gets the total number of arguments including the receiver (but 63 // excluding extra arguments). length()64 int length() const { return Arguments::length() - kNumExtraArgs; } 65 }; 66 67 // ---------------------------------------------------------------------------- 68 // Support macro for defining builtins in C++. 69 // ---------------------------------------------------------------------------- 70 // 71 // A builtin function is defined by writing: 72 // 73 // BUILTIN(name) { 74 // ... 75 // } 76 // 77 // In the body of the builtin function the arguments can be accessed 78 // through the BuiltinArguments object args. 79 // TODO(cbruni): add global flag to check whether any tracing events have been 80 // enabled. 81 #define BUILTIN(name) \ 82 V8_WARN_UNUSED_RESULT static Object Builtin_Impl_##name( \ 83 BuiltinArguments args, Isolate* isolate); \ 84 \ 85 V8_NOINLINE static Address Builtin_Impl_Stats_##name( \ 86 int args_length, Address* args_object, Isolate* isolate) { \ 87 BuiltinArguments args(args_length, args_object); \ 88 RuntimeCallTimerScope timer(isolate, \ 89 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 // ---------------------------------------------------------------------------- 109 110 #define CHECK_RECEIVER(Type, name, method) \ 111 if (!args.receiver()->Is##Type()) { \ 112 THROW_NEW_ERROR_RETURN_FAILURE( \ 113 isolate, \ 114 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, \ 115 isolate->factory()->NewStringFromAsciiChecked(method), \ 116 args.receiver())); \ 117 } \ 118 Handle<Type> name = Handle<Type>::cast(args.receiver()) 119 120 // Throws a TypeError for {method} if the receiver is not coercible to Object, 121 // or converts the receiver to a String otherwise and assigns it to a new var 122 // with the given {name}. 123 #define TO_THIS_STRING(name, method) \ 124 if (args.receiver()->IsNullOrUndefined(isolate)) { \ 125 THROW_NEW_ERROR_RETURN_FAILURE( \ 126 isolate, \ 127 NewTypeError(MessageTemplate::kCalledOnNullOrUndefined, \ 128 isolate->factory()->NewStringFromAsciiChecked(method))); \ 129 } \ 130 Handle<String> name; \ 131 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( \ 132 isolate, name, Object::ToString(isolate, args.receiver())) 133 134 } // namespace internal 135 } // namespace v8 136 137 #endif // V8_BUILTINS_BUILTINS_UTILS_H_ 138