blob: aa76a3b6f51e139865dd766f1845d7301499f0df [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#include "src/compiler/js-operator.h"
6
7#include <limits>
8
9#include "src/base/lazy-instance.h"
10#include "src/compiler/opcodes.h"
11#include "src/compiler/operator.h"
12
13namespace v8 {
14namespace internal {
15namespace compiler {
16
17bool operator==(CallFunctionParameters const& lhs,
18 CallFunctionParameters const& rhs) {
19 return lhs.arity() == rhs.arity() && lhs.flags() == rhs.flags();
20}
21
22
23bool operator!=(CallFunctionParameters const& lhs,
24 CallFunctionParameters const& rhs) {
25 return !(lhs == rhs);
26}
27
28
29size_t hash_value(CallFunctionParameters const& p) {
30 return base::hash_combine(p.arity(), p.flags());
31}
32
33
34std::ostream& operator<<(std::ostream& os, CallFunctionParameters const& p) {
35 return os << p.arity() << ", " << p.flags();
36}
37
38
39const CallFunctionParameters& CallFunctionParametersOf(const Operator* op) {
40 DCHECK_EQ(IrOpcode::kJSCallFunction, op->opcode());
41 return OpParameter<CallFunctionParameters>(op);
42}
43
44
45bool operator==(CallRuntimeParameters const& lhs,
46 CallRuntimeParameters const& rhs) {
47 return lhs.id() == rhs.id() && lhs.arity() == rhs.arity();
48}
49
50
51bool operator!=(CallRuntimeParameters const& lhs,
52 CallRuntimeParameters const& rhs) {
53 return !(lhs == rhs);
54}
55
56
57size_t hash_value(CallRuntimeParameters const& p) {
58 return base::hash_combine(p.id(), p.arity());
59}
60
61
62std::ostream& operator<<(std::ostream& os, CallRuntimeParameters const& p) {
63 return os << p.id() << ", " << p.arity();
64}
65
66
67const CallRuntimeParameters& CallRuntimeParametersOf(const Operator* op) {
68 DCHECK_EQ(IrOpcode::kJSCallRuntime, op->opcode());
69 return OpParameter<CallRuntimeParameters>(op);
70}
71
72
73ContextAccess::ContextAccess(size_t depth, size_t index, bool immutable)
74 : immutable_(immutable),
75 depth_(static_cast<uint16_t>(depth)),
76 index_(static_cast<uint32_t>(index)) {
77 DCHECK(depth <= std::numeric_limits<uint16_t>::max());
78 DCHECK(index <= std::numeric_limits<uint32_t>::max());
79}
80
81
82bool operator==(ContextAccess const& lhs, ContextAccess const& rhs) {
83 return lhs.depth() == rhs.depth() && lhs.index() == rhs.index() &&
84 lhs.immutable() == rhs.immutable();
85}
86
87
88bool operator!=(ContextAccess const& lhs, ContextAccess const& rhs) {
89 return !(lhs == rhs);
90}
91
92
93size_t hash_value(ContextAccess const& access) {
94 return base::hash_combine(access.depth(), access.index(), access.immutable());
95}
96
97
98std::ostream& operator<<(std::ostream& os, ContextAccess const& access) {
99 return os << access.depth() << ", " << access.index() << ", "
100 << access.immutable();
101}
102
103
104ContextAccess const& ContextAccessOf(Operator const* op) {
105 DCHECK(op->opcode() == IrOpcode::kJSLoadContext ||
106 op->opcode() == IrOpcode::kJSStoreContext);
107 return OpParameter<ContextAccess>(op);
108}
109
110
111bool operator==(VectorSlotPair const& lhs, VectorSlotPair const& rhs) {
112 return lhs.slot().ToInt() == rhs.slot().ToInt() &&
113 lhs.vector().is_identical_to(rhs.vector());
114}
115
116
117size_t hash_value(VectorSlotPair const& p) {
118 // TODO(mvstanton): include the vector in the hash.
119 base::hash<int> h;
120 return h(p.slot().ToInt());
121}
122
123
124bool operator==(LoadNamedParameters const& lhs,
125 LoadNamedParameters const& rhs) {
126 return lhs.name() == rhs.name() &&
127 lhs.contextual_mode() == rhs.contextual_mode() &&
128 lhs.feedback() == rhs.feedback();
129}
130
131
132bool operator!=(LoadNamedParameters const& lhs,
133 LoadNamedParameters const& rhs) {
134 return !(lhs == rhs);
135}
136
137
138size_t hash_value(LoadNamedParameters const& p) {
139 return base::hash_combine(p.name(), p.contextual_mode(), p.feedback());
140}
141
142
143std::ostream& operator<<(std::ostream& os, LoadNamedParameters const& p) {
144 return os << Brief(*p.name().handle()) << ", " << p.contextual_mode();
145}
146
147
148std::ostream& operator<<(std::ostream& os, LoadPropertyParameters const& p) {
149 // Nothing special to print.
150 return os;
151}
152
153
154bool operator==(LoadPropertyParameters const& lhs,
155 LoadPropertyParameters const& rhs) {
156 return lhs.feedback() == rhs.feedback();
157}
158
159
160bool operator!=(LoadPropertyParameters const& lhs,
161 LoadPropertyParameters const& rhs) {
162 return !(lhs == rhs);
163}
164
165
166const LoadPropertyParameters& LoadPropertyParametersOf(const Operator* op) {
167 DCHECK_EQ(IrOpcode::kJSLoadProperty, op->opcode());
168 return OpParameter<LoadPropertyParameters>(op);
169}
170
171
172size_t hash_value(LoadPropertyParameters const& p) {
173 return hash_value(p.feedback());
174}
175
176
177const LoadNamedParameters& LoadNamedParametersOf(const Operator* op) {
178 DCHECK_EQ(IrOpcode::kJSLoadNamed, op->opcode());
179 return OpParameter<LoadNamedParameters>(op);
180}
181
182
183bool operator==(StoreNamedParameters const& lhs,
184 StoreNamedParameters const& rhs) {
185 return lhs.strict_mode() == rhs.strict_mode() && lhs.name() == rhs.name();
186}
187
188
189bool operator!=(StoreNamedParameters const& lhs,
190 StoreNamedParameters const& rhs) {
191 return !(lhs == rhs);
192}
193
194
195size_t hash_value(StoreNamedParameters const& p) {
196 return base::hash_combine(p.strict_mode(), p.name());
197}
198
199
200std::ostream& operator<<(std::ostream& os, StoreNamedParameters const& p) {
201 return os << p.strict_mode() << ", " << Brief(*p.name().handle());
202}
203
204
205const StoreNamedParameters& StoreNamedParametersOf(const Operator* op) {
206 DCHECK_EQ(IrOpcode::kJSStoreNamed, op->opcode());
207 return OpParameter<StoreNamedParameters>(op);
208}
209
210
211#define CACHED_OP_LIST(V) \
212 V(Equal, Operator::kNoProperties, 2, 1) \
213 V(NotEqual, Operator::kNoProperties, 2, 1) \
214 V(StrictEqual, Operator::kPure, 2, 1) \
215 V(StrictNotEqual, Operator::kPure, 2, 1) \
216 V(LessThan, Operator::kNoProperties, 2, 1) \
217 V(GreaterThan, Operator::kNoProperties, 2, 1) \
218 V(LessThanOrEqual, Operator::kNoProperties, 2, 1) \
219 V(GreaterThanOrEqual, Operator::kNoProperties, 2, 1) \
220 V(BitwiseOr, Operator::kNoProperties, 2, 1) \
221 V(BitwiseXor, Operator::kNoProperties, 2, 1) \
222 V(BitwiseAnd, Operator::kNoProperties, 2, 1) \
223 V(ShiftLeft, Operator::kNoProperties, 2, 1) \
224 V(ShiftRight, Operator::kNoProperties, 2, 1) \
225 V(ShiftRightLogical, Operator::kNoProperties, 2, 1) \
226 V(Add, Operator::kNoProperties, 2, 1) \
227 V(Subtract, Operator::kNoProperties, 2, 1) \
228 V(Multiply, Operator::kNoProperties, 2, 1) \
229 V(Divide, Operator::kNoProperties, 2, 1) \
230 V(Modulus, Operator::kNoProperties, 2, 1) \
231 V(UnaryNot, Operator::kPure, 1, 1) \
232 V(ToBoolean, Operator::kPure, 1, 1) \
233 V(ToNumber, Operator::kNoProperties, 1, 1) \
234 V(ToString, Operator::kNoProperties, 1, 1) \
235 V(ToName, Operator::kNoProperties, 1, 1) \
236 V(ToObject, Operator::kNoProperties, 1, 1) \
237 V(Yield, Operator::kNoProperties, 1, 1) \
238 V(Create, Operator::kEliminatable, 0, 1) \
239 V(HasProperty, Operator::kNoProperties, 2, 1) \
240 V(TypeOf, Operator::kPure, 1, 1) \
241 V(InstanceOf, Operator::kNoProperties, 2, 1) \
242 V(Debugger, Operator::kNoProperties, 0, 0) \
243 V(CreateFunctionContext, Operator::kNoProperties, 1, 1) \
244 V(CreateWithContext, Operator::kNoProperties, 2, 1) \
245 V(CreateBlockContext, Operator::kNoProperties, 2, 1) \
246 V(CreateModuleContext, Operator::kNoProperties, 2, 1) \
247 V(CreateScriptContext, Operator::kNoProperties, 2, 1)
248
249
250struct JSOperatorGlobalCache FINAL {
251#define CACHED(Name, properties, value_input_count, value_output_count) \
252 struct Name##Operator FINAL : public Operator { \
253 Name##Operator() \
254 : Operator(IrOpcode::kJS##Name, properties, "JS" #Name, \
255 value_input_count, Operator::ZeroIfPure(properties), \
256 Operator::ZeroIfPure(properties), value_output_count, \
257 Operator::ZeroIfPure(properties), 0) {} \
258 }; \
259 Name##Operator k##Name##Operator;
260 CACHED_OP_LIST(CACHED)
261#undef CACHED
262
263 template <StrictMode kStrictMode>
264 struct StorePropertyOperator FINAL : public Operator1<StrictMode> {
265 StorePropertyOperator()
266 : Operator1<StrictMode>(IrOpcode::kJSStoreProperty,
267 Operator::kNoProperties, "JSStoreProperty", 3,
268 1, 1, 0, 1, 0, kStrictMode) {}
269 };
270 StorePropertyOperator<SLOPPY> kStorePropertySloppyOperator;
271 StorePropertyOperator<STRICT> kStorePropertyStrictOperator;
272};
273
274
275static base::LazyInstance<JSOperatorGlobalCache>::type kCache =
276 LAZY_INSTANCE_INITIALIZER;
277
278
279JSOperatorBuilder::JSOperatorBuilder(Zone* zone)
280 : cache_(kCache.Get()), zone_(zone) {}
281
282
283#define CACHED(Name, properties, value_input_count, value_output_count) \
284 const Operator* JSOperatorBuilder::Name() { \
285 return &cache_.k##Name##Operator; \
286 }
287CACHED_OP_LIST(CACHED)
288#undef CACHED
289
290
291const Operator* JSOperatorBuilder::CallFunction(size_t arity,
292 CallFunctionFlags flags) {
293 CallFunctionParameters parameters(arity, flags);
294 return new (zone()) Operator1<CallFunctionParameters>( // --
295 IrOpcode::kJSCallFunction, Operator::kNoProperties, // opcode
296 "JSCallFunction", // name
297 parameters.arity(), 1, 1, 1, 1, 0, // inputs/outputs
298 parameters); // parameter
299}
300
301
302const Operator* JSOperatorBuilder::CallRuntime(Runtime::FunctionId id,
303 size_t arity) {
304 CallRuntimeParameters parameters(id, arity);
305 const Runtime::Function* f = Runtime::FunctionForId(parameters.id());
306 DCHECK(f->nargs == -1 || f->nargs == static_cast<int>(parameters.arity()));
307 return new (zone()) Operator1<CallRuntimeParameters>( // --
308 IrOpcode::kJSCallRuntime, Operator::kNoProperties, // opcode
309 "JSCallRuntime", // name
310 parameters.arity(), 1, 1, f->result_size, 1, 0, // inputs/outputs
311 parameters); // parameter
312}
313
314
315const Operator* JSOperatorBuilder::CallConstruct(int arguments) {
316 return new (zone()) Operator1<int>( // --
317 IrOpcode::kJSCallConstruct, Operator::kNoProperties, // opcode
318 "JSCallConstruct", // name
319 arguments, 1, 1, 1, 1, 0, // counts
320 arguments); // parameter
321}
322
323
324const Operator* JSOperatorBuilder::LoadNamed(const Unique<Name>& name,
325 const VectorSlotPair& feedback,
326 ContextualMode contextual_mode) {
327 LoadNamedParameters parameters(name, feedback, contextual_mode);
328 return new (zone()) Operator1<LoadNamedParameters>( // --
329 IrOpcode::kJSLoadNamed, Operator::kNoProperties, // opcode
330 "JSLoadNamed", // name
331 1, 1, 1, 1, 1, 0, // counts
332 parameters); // parameter
333}
334
335
336const Operator* JSOperatorBuilder::LoadProperty(
337 const VectorSlotPair& feedback) {
338 LoadPropertyParameters parameters(feedback);
339 return new (zone()) Operator1<LoadPropertyParameters>( // --
340 IrOpcode::kJSLoadProperty, Operator::kNoProperties, // opcode
341 "JSLoadProperty", // name
342 2, 1, 1, 1, 1, 0, // counts
343 parameters); // parameter
344}
345
346
347const Operator* JSOperatorBuilder::StoreProperty(StrictMode strict_mode) {
348 switch (strict_mode) {
349 case SLOPPY:
350 return &cache_.kStorePropertySloppyOperator;
351 case STRICT:
352 return &cache_.kStorePropertyStrictOperator;
353 }
354 UNREACHABLE();
355 return nullptr;
356}
357
358
359const Operator* JSOperatorBuilder::StoreNamed(StrictMode strict_mode,
360 const Unique<Name>& name) {
361 StoreNamedParameters parameters(strict_mode, name);
362 return new (zone()) Operator1<StoreNamedParameters>( // --
363 IrOpcode::kJSStoreNamed, Operator::kNoProperties, // opcode
364 "JSStoreNamed", // name
365 2, 1, 1, 0, 1, 0, // counts
366 parameters); // parameter
367}
368
369
370const Operator* JSOperatorBuilder::DeleteProperty(StrictMode strict_mode) {
371 return new (zone()) Operator1<StrictMode>( // --
372 IrOpcode::kJSDeleteProperty, Operator::kNoProperties, // opcode
373 "JSDeleteProperty", // name
374 2, 1, 1, 1, 1, 0, // counts
375 strict_mode); // parameter
376}
377
378
379const Operator* JSOperatorBuilder::LoadContext(size_t depth, size_t index,
380 bool immutable) {
381 ContextAccess access(depth, index, immutable);
382 return new (zone()) Operator1<ContextAccess>( // --
383 IrOpcode::kJSLoadContext, Operator::kNoWrite, // opcode
384 "JSLoadContext", // name
385 1, 1, 0, 1, 1, 0, // counts
386 access); // parameter
387}
388
389
390const Operator* JSOperatorBuilder::StoreContext(size_t depth, size_t index) {
391 ContextAccess access(depth, index, false);
392 return new (zone()) Operator1<ContextAccess>( // --
393 IrOpcode::kJSStoreContext, Operator::kNoRead, // opcode
394 "JSStoreContext", // name
395 2, 1, 1, 0, 1, 0, // counts
396 access); // parameter
397}
398
399
400const Operator* JSOperatorBuilder::CreateCatchContext(
401 const Unique<String>& name) {
402 return new (zone()) Operator1<Unique<String>>( // --
403 IrOpcode::kJSCreateCatchContext, Operator::kNoProperties, // opcode
404 "JSCreateCatchContext", // name
405 1, 1, 1, 1, 1, 0, // counts
406 name); // parameter
407}
408
409} // namespace compiler
410} // namespace internal
411} // namespace v8