blob: 5cdf0430817a9769e018b3062b2fc1d50a8736e7 [file] [log] [blame]
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001// Copyright 2014 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_RUNTIME_RUNTIME_UTILS_H_
6#define V8_RUNTIME_RUNTIME_UTILS_H_
7
Ben Murdochda12d292016-06-02 14:46:10 +01008#include "src/base/logging.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009#include "src/runtime/runtime.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010
11namespace v8 {
12namespace internal {
13
Ben Murdochda12d292016-06-02 14:46:10 +010014#ifdef DEBUG
15
16#define RUNTIME_ASSERT(value) \
17 do { \
18 if (!(value)) { \
19 V8_RuntimeError(__FILE__, __LINE__, #value); \
20 return isolate->ThrowIllegalOperation(); \
21 } \
22 } while (0)
23
Ben Murdochda12d292016-06-02 14:46:10 +010024#else
25
26#define RUNTIME_ASSERT(value) \
27 do { \
28 if (!(value)) { \
29 return isolate->ThrowIllegalOperation(); \
30 } \
31 } while (0)
Emily Bernierd0a1eb72015-03-24 16:35:39 -040032
Ben Murdochda12d292016-06-02 14:46:10 +010033#endif
Emily Bernierd0a1eb72015-03-24 16:35:39 -040034
35// Cast the given object to a value of the specified type and store
36// it in a variable with the given name. If the object is not of the
37// expected type call IllegalOperation and return.
38#define CONVERT_ARG_CHECKED(Type, name, index) \
39 RUNTIME_ASSERT(args[index]->Is##Type()); \
40 Type* name = Type::cast(args[index]);
41
42#define CONVERT_ARG_HANDLE_CHECKED(Type, name, index) \
43 RUNTIME_ASSERT(args[index]->Is##Type()); \
44 Handle<Type> name = args.at<Type>(index);
45
46#define CONVERT_NUMBER_ARG_HANDLE_CHECKED(name, index) \
47 RUNTIME_ASSERT(args[index]->IsNumber()); \
48 Handle<Object> name = args.at<Object>(index);
49
50// Cast the given object to a boolean and store it in a variable with
51// the given name. If the object is not a boolean call IllegalOperation
52// and return.
53#define CONVERT_BOOLEAN_ARG_CHECKED(name, index) \
54 RUNTIME_ASSERT(args[index]->IsBoolean()); \
Ben Murdoch61f157c2016-09-16 13:49:30 +010055 bool name = args[index]->IsTrue(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040056
57// Cast the given argument to a Smi and store its value in an int variable
58// with the given name. If the argument is not a Smi call IllegalOperation
59// and return.
60#define CONVERT_SMI_ARG_CHECKED(name, index) \
61 RUNTIME_ASSERT(args[index]->IsSmi()); \
62 int name = args.smi_at(index);
63
64// Cast the given argument to a double and store it in a variable with
65// the given name. If the argument is not a number (as opposed to
66// the number not-a-number) call IllegalOperation and return.
67#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
68 RUNTIME_ASSERT(args[index]->IsNumber()); \
69 double name = args.number_at(index);
70
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000071
72// Cast the given argument to a size_t and store its value in a variable with
73// the given name. If the argument is not a size_t call IllegalOperation and
74// return.
75#define CONVERT_SIZE_ARG_CHECKED(name, index) \
76 RUNTIME_ASSERT(args[index]->IsNumber()); \
77 Handle<Object> name##_object = args.at<Object>(index); \
78 size_t name = 0; \
79 RUNTIME_ASSERT(TryNumberToSize(isolate, *name##_object, &name));
80
81
Emily Bernierd0a1eb72015-03-24 16:35:39 -040082// Call the specified converter on the object *comand store the result in
83// a variable of the specified type with the given name. If the
84// object is not a Number call IllegalOperation and return.
85#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
86 RUNTIME_ASSERT(obj->IsNumber()); \
87 type name = NumberTo##Type(obj);
88
89
90// Cast the given argument to PropertyDetails and store its value in a
91// variable with the given name. If the argument is not a Smi call
92// IllegalOperation and return.
93#define CONVERT_PROPERTY_DETAILS_CHECKED(name, index) \
94 RUNTIME_ASSERT(args[index]->IsSmi()); \
95 PropertyDetails name = PropertyDetails(Smi::cast(args[index]));
96
97
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000098// Assert that the given argument has a valid value for a LanguageMode
99// and store it in a LanguageMode variable with the given name.
100#define CONVERT_LANGUAGE_MODE_ARG_CHECKED(name, index) \
101 RUNTIME_ASSERT(args[index]->IsSmi()); \
102 RUNTIME_ASSERT(is_valid_language_mode(args.smi_at(index))); \
103 LanguageMode name = static_cast<LanguageMode>(args.smi_at(index));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400104
105
106// Assert that the given argument is a number within the Int32 range
107// and convert it to int32_t. If the argument is not an Int32 call
108// IllegalOperation and return.
109#define CONVERT_INT32_ARG_CHECKED(name, index) \
110 RUNTIME_ASSERT(args[index]->IsNumber()); \
111 int32_t name = 0; \
112 RUNTIME_ASSERT(args[index]->ToInt32(&name));
113
114
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000115// Cast the given argument to PropertyAttributes and store its value in a
116// variable with the given name. If the argument is not a Smi call or the
117// enum value is out of range, call IllegalOperation and return.
118#define CONVERT_PROPERTY_ATTRIBUTES_CHECKED(name, index) \
119 RUNTIME_ASSERT(args[index]->IsSmi()); \
120 RUNTIME_ASSERT( \
121 (args.smi_at(index) & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); \
122 PropertyAttributes name = static_cast<PropertyAttributes>(args.smi_at(index));
123
124
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400125// A mechanism to return a pair of Object pointers in registers (if possible).
126// How this is achieved is calling convention-dependent.
127// All currently supported x86 compiles uses calling conventions that are cdecl
128// variants where a 64-bit value is returned in two 32-bit registers
129// (edx:eax on ia32, r1:r0 on ARM).
130// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
131// In Win64 calling convention, a struct of two pointers is returned in memory,
132// allocated by the caller, and passed as a pointer in a hidden first parameter.
133#ifdef V8_HOST_ARCH_64_BIT
134struct ObjectPair {
135 Object* x;
136 Object* y;
137};
138
139
140static inline ObjectPair MakePair(Object* x, Object* y) {
141 ObjectPair result = {x, y};
142 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
143 // In Win64 they are assigned to a hidden first argument.
144 return result;
145}
146#elif V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_32_BIT
147// For x32 a 128-bit struct return is done as rax and rdx from the ObjectPair
148// are used in the full codegen and Crankshaft compiler. An alternative is
149// using uint64_t and modifying full codegen and Crankshaft compiler.
150struct ObjectPair {
151 Object* x;
152 uint32_t x_upper;
153 Object* y;
154 uint32_t y_upper;
155};
156
157
158static inline ObjectPair MakePair(Object* x, Object* y) {
159 ObjectPair result = {x, 0, y, 0};
160 // Pointers x and y returned in rax and rdx, in x32-abi.
161 return result;
162}
163#else
164typedef uint64_t ObjectPair;
165static inline ObjectPair MakePair(Object* x, Object* y) {
166#if defined(V8_TARGET_LITTLE_ENDIAN)
167 return reinterpret_cast<uint32_t>(x) |
168 (reinterpret_cast<ObjectPair>(y) << 32);
169#elif defined(V8_TARGET_BIG_ENDIAN)
170 return reinterpret_cast<uint32_t>(y) |
171 (reinterpret_cast<ObjectPair>(x) << 32);
172#else
173#error Unknown endianness
174#endif
175}
176#endif
177
Ben Murdoch097c5b22016-05-18 11:27:45 +0100178
179// A mechanism to return a triple of Object pointers. In all calling
180// conventions, a struct of two pointers is returned in memory,
181// allocated by the caller, and passed as a pointer in a hidden first parameter.
182struct ObjectTriple {
183 Object* x;
184 Object* y;
185 Object* z;
186};
187
188static inline ObjectTriple MakeTriple(Object* x, Object* y, Object* z) {
189 ObjectTriple result = {x, y, z};
190 // ObjectTriple is assigned to a hidden first argument.
191 return result;
192}
193
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000194} // namespace internal
195} // namespace v8
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400196
197#endif // V8_RUNTIME_RUNTIME_UTILS_H_