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/arguments.h" 9 #include "src/base/logging.h" 10 #include "src/builtins/builtins.h" 11 #include "src/heap/factory.h" 12 #include "src/isolate.h" 13 14 namespace v8 { 15 namespace internal { 16 17 // Arguments object passed to C++ builtins. 18 class BuiltinArguments : public Arguments { 19 public: BuiltinArguments(int length,Object ** arguments)20 BuiltinArguments(int length, Object** 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) { 27 DCHECK_LT(index, length()); 28 return Arguments::operator[](index); 29 } 30 31 template <class S = Object> at(int index)32 Handle<S> at(int index) { 33 DCHECK_LT(index, length()); 34 return Arguments::at<S>(index); 35 } 36 atOrUndefined(Isolate * isolate,int index)37 Handle<Object> atOrUndefined(Isolate* isolate, int index) { 38 if (index >= length()) { 39 return isolate->factory()->undefined_value(); 40 } 41 return at<Object>(index); 42 } 43 receiver()44 Handle<Object> receiver() { return Arguments::at<Object>(0); } 45 46 static const int kNewTargetOffset = 0; 47 static const int kTargetOffset = 1; 48 static const int kArgcOffset = 2; 49 static const int kPaddingOffset = 3; 50 51 static const int kNumExtraArgs = 4; 52 static const int kNumExtraArgsWithReceiver = 5; 53 target()54 Handle<JSFunction> target() { 55 return Arguments::at<JSFunction>(Arguments::length() - 1 - kTargetOffset); 56 } new_target()57 Handle<HeapObject> new_target() { 58 return Arguments::at<HeapObject>(Arguments::length() - 1 - 59 kNewTargetOffset); 60 } 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 Object* Builtin_Impl_Stats_##name( \ 86 int args_length, Object** 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 Builtin_Impl_##name(args, isolate); \ 93 } \ 94 \ 95 V8_WARN_UNUSED_RESULT Object* Builtin_##name( \ 96 int args_length, Object** args_object, Isolate* isolate) { \ 97 DCHECK(isolate->context() == nullptr || isolate->context()->IsContext()); \ 98 if (V8_UNLIKELY(FLAG_runtime_stats)) { \ 99 return Builtin_Impl_Stats_##name(args_length, args_object, isolate); \ 100 } \ 101 BuiltinArguments args(args_length, args_object); \ 102 return 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