blob: 90b58c79cdc585562799d3494fcd709666268e70 [file] [log] [blame]
Ben Murdochf91f0612016-11-29 16:50:11 +00001// 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/code-stub-assembler.h"
12
13namespace v8 {
14namespace internal {
15
16// Arguments object passed to C++ builtins.
17class BuiltinArguments : public Arguments {
18 public:
19 BuiltinArguments(int length, Object** arguments)
20 : Arguments(length, arguments) {
21 // Check we have at least the receiver.
22 DCHECK_LE(1, this->length());
23 }
24
25 Object*& operator[](int index) {
26 DCHECK_LT(index, length());
27 return Arguments::operator[](index);
28 }
29
30 template <class S>
31 Handle<S> at(int index) {
32 DCHECK_LT(index, length());
33 return Arguments::at<S>(index);
34 }
35
36 Handle<Object> atOrUndefined(Isolate* isolate, int index) {
37 if (index >= length()) {
38 return isolate->factory()->undefined_value();
39 }
40 return at<Object>(index);
41 }
42
43 Handle<Object> receiver() { return Arguments::at<Object>(0); }
44
45 static const int kNewTargetOffset = 0;
46 static const int kTargetOffset = 1;
47 static const int kArgcOffset = 2;
48 static const int kNumExtraArgs = 3;
49 static const int kNumExtraArgsWithReceiver = 4;
50
51 template <class S>
52 Handle<S> target() {
53 return Arguments::at<S>(Arguments::length() - 1 - kTargetOffset);
54 }
55 Handle<HeapObject> new_target() {
56 return Arguments::at<HeapObject>(Arguments::length() - 1 -
57 kNewTargetOffset);
58 }
59
60 // Gets the total number of arguments including the receiver (but
61 // excluding extra arguments).
62 int length() const { return Arguments::length() - kNumExtraArgs; }
63};
64
65// ----------------------------------------------------------------------------
66// Support macro for defining builtins in C++.
67// ----------------------------------------------------------------------------
68//
69// A builtin function is defined by writing:
70//
71// BUILTIN(name) {
72// ...
73// }
74//
75// In the body of the builtin function the arguments can be accessed
76// through the BuiltinArguments object args.
77// TODO(cbruni): add global flag to check whether any tracing events have been
78// enabled.
79// TODO(cbruni): Convert the IsContext CHECK back to a DCHECK.
80#define BUILTIN(name) \
81 MUST_USE_RESULT static Object* Builtin_Impl_##name(BuiltinArguments args, \
82 Isolate* isolate); \
83 \
84 V8_NOINLINE static Object* Builtin_Impl_Stats_##name( \
85 int args_length, Object** args_object, Isolate* isolate) { \
86 BuiltinArguments args(args_length, args_object); \
87 RuntimeCallTimerScope timer(isolate, &RuntimeCallStats::Builtin_##name); \
88 TRACE_EVENT_RUNTIME_CALL_STATS_TRACING_SCOPED( \
89 isolate, &tracing::TraceEventStatsTable::Builtin_##name); \
90 return Builtin_Impl_##name(args, isolate); \
91 } \
92 \
93 MUST_USE_RESULT Object* Builtin_##name( \
94 int args_length, Object** args_object, Isolate* isolate) { \
95 CHECK(isolate->context() == nullptr || isolate->context()->IsContext()); \
96 if (V8_UNLIKELY(TRACE_EVENT_RUNTIME_CALL_STATS_TRACING_ENABLED() || \
97 FLAG_runtime_call_stats)) { \
98 return Builtin_Impl_Stats_##name(args_length, args_object, isolate); \
99 } \
100 BuiltinArguments args(args_length, args_object); \
101 return Builtin_Impl_##name(args, isolate); \
102 } \
103 \
104 MUST_USE_RESULT static Object* Builtin_Impl_##name(BuiltinArguments args, \
105 Isolate* isolate)
106
107// ----------------------------------------------------------------------------
108
109#define CHECK_RECEIVER(Type, name, method) \
110 if (!args.receiver()->Is##Type()) { \
111 THROW_NEW_ERROR_RETURN_FAILURE( \
112 isolate, \
113 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, \
114 isolate->factory()->NewStringFromAsciiChecked(method), \
115 args.receiver())); \
116 } \
117 Handle<Type> name = Handle<Type>::cast(args.receiver())
118
119// Throws a TypeError for {method} if the receiver is not coercible to Object,
120// or converts the receiver to a String otherwise and assigns it to a new var
121// with the given {name}.
122#define TO_THIS_STRING(name, method) \
123 if (args.receiver()->IsNull(isolate) || \
124 args.receiver()->IsUndefined(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_