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/factory.h" 12 #include "src/isolate.h" 13 14 namespace v8 { 15 namespace internal { 16 17 namespace compiler { 18 class CodeAssemblerState; 19 } 20 21 // Arguments object passed to C++ builtins. 22 class BuiltinArguments : public Arguments { 23 public: 24 BuiltinArguments(int length, Object** arguments) 25 : Arguments(length, arguments) { 26 // Check we have at least the receiver. 27 DCHECK_LE(1, this->length()); 28 } 29 30 Object*& operator[](int index) { 31 DCHECK_LT(index, length()); 32 return Arguments::operator[](index); 33 } 34 35 template <class S = Object> 36 Handle<S> at(int index) { 37 DCHECK_LT(index, length()); 38 return Arguments::at<S>(index); 39 } 40 41 Handle<Object> atOrUndefined(Isolate* isolate, int index) { 42 if (index >= length()) { 43 return isolate->factory()->undefined_value(); 44 } 45 return at<Object>(index); 46 } 47 48 Handle<Object> receiver() { return Arguments::at<Object>(0); } 49 50 static const int kNewTargetOffset = 0; 51 static const int kTargetOffset = 1; 52 static const int kArgcOffset = 2; 53 static const int kNumExtraArgs = 3; 54 static const int kNumExtraArgsWithReceiver = 4; 55 56 Handle<JSFunction> target() { 57 return Arguments::at<JSFunction>(Arguments::length() - 1 - kTargetOffset); 58 } 59 Handle<HeapObject> new_target() { 60 return Arguments::at<HeapObject>(Arguments::length() - 1 - 61 kNewTargetOffset); 62 } 63 64 // Gets the total number of arguments including the receiver (but 65 // excluding extra arguments). 66 int length() const { return Arguments::length() - kNumExtraArgs; } 67 }; 68 69 // ---------------------------------------------------------------------------- 70 // Support macro for defining builtins in C++. 71 // ---------------------------------------------------------------------------- 72 // 73 // A builtin function is defined by writing: 74 // 75 // BUILTIN(name) { 76 // ... 77 // } 78 // 79 // In the body of the builtin function the arguments can be accessed 80 // through the BuiltinArguments object args. 81 // TODO(cbruni): add global flag to check whether any tracing events have been 82 // enabled. 83 #define BUILTIN(name) \ 84 MUST_USE_RESULT static Object* Builtin_Impl_##name(BuiltinArguments args, \ 85 Isolate* isolate); \ 86 \ 87 V8_NOINLINE static Object* Builtin_Impl_Stats_##name( \ 88 int args_length, Object** args_object, Isolate* isolate) { \ 89 BuiltinArguments args(args_length, args_object); \ 90 RuntimeCallTimerScope timer(isolate, &RuntimeCallStats::Builtin_##name); \ 91 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.runtime"), \ 92 "V8.Builtin_" #name); \ 93 return Builtin_Impl_##name(args, isolate); \ 94 } \ 95 \ 96 MUST_USE_RESULT Object* Builtin_##name( \ 97 int args_length, Object** args_object, Isolate* isolate) { \ 98 DCHECK(isolate->context() == nullptr || isolate->context()->IsContext()); \ 99 if (V8_UNLIKELY(FLAG_runtime_stats)) { \ 100 return Builtin_Impl_Stats_##name(args_length, args_object, isolate); \ 101 } \ 102 BuiltinArguments args(args_length, args_object); \ 103 return Builtin_Impl_##name(args, isolate); \ 104 } \ 105 \ 106 MUST_USE_RESULT static Object* Builtin_Impl_##name(BuiltinArguments args, \ 107 Isolate* isolate) 108 109 // ---------------------------------------------------------------------------- 110 // Support macro for defining builtins with Turbofan. 111 // ---------------------------------------------------------------------------- 112 // 113 // A builtin function is defined by writing: 114 // 115 // TF_BUILTIN(name, code_assember_base_class) { 116 // ... 117 // } 118 // 119 // In the body of the builtin function the arguments can be accessed 120 // as "Parameter(n)". 121 #define TF_BUILTIN(Name, AssemblerBase) \ 122 class Name##Assembler : public AssemblerBase { \ 123 public: \ 124 explicit Name##Assembler(compiler::CodeAssemblerState* state) \ 125 : AssemblerBase(state) {} \ 126 void Generate##Name##Impl(); \ 127 }; \ 128 void Builtins::Generate_##Name(compiler::CodeAssemblerState* state) { \ 129 Name##Assembler assembler(state); \ 130 assembler.Generate##Name##Impl(); \ 131 } \ 132 void Name##Assembler::Generate##Name##Impl() 133 134 // ---------------------------------------------------------------------------- 135 136 #define CHECK_RECEIVER(Type, name, method) \ 137 if (!args.receiver()->Is##Type()) { \ 138 THROW_NEW_ERROR_RETURN_FAILURE( \ 139 isolate, \ 140 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, \ 141 isolate->factory()->NewStringFromAsciiChecked(method), \ 142 args.receiver())); \ 143 } \ 144 Handle<Type> name = Handle<Type>::cast(args.receiver()) 145 146 // Throws a TypeError for {method} if the receiver is not coercible to Object, 147 // or converts the receiver to a String otherwise and assigns it to a new var 148 // with the given {name}. 149 #define TO_THIS_STRING(name, method) \ 150 if (args.receiver()->IsNullOrUndefined(isolate)) { \ 151 THROW_NEW_ERROR_RETURN_FAILURE( \ 152 isolate, \ 153 NewTypeError(MessageTemplate::kCalledOnNullOrUndefined, \ 154 isolate->factory()->NewStringFromAsciiChecked(method))); \ 155 } \ 156 Handle<String> name; \ 157 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( \ 158 isolate, name, Object::ToString(isolate, args.receiver())) 159 160 } // namespace internal 161 } // namespace v8 162 163 #endif // V8_BUILTINS_BUILTINS_UTILS_H_ 164