1// Copyright 2013 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_COMPILER_JS_OPERATOR_H_
6#define V8_COMPILER_JS_OPERATOR_H_
7
8#include "src/compiler/linkage.h"
9#include "src/compiler/opcodes.h"
10#include "src/compiler/operator.h"
11#include "src/unique.h"
12#include "src/zone.h"
13
14namespace v8 {
15namespace internal {
16namespace compiler {
17
18// Defines the location of a context slot relative to a specific scope. This is
19// used as a parameter by JSLoadContext and JSStoreContext operators and allows
20// accessing a context-allocated variable without keeping track of the scope.
21class ContextAccess {
22 public:
23  ContextAccess(int depth, int index, bool immutable)
24      : immutable_(immutable), depth_(depth), index_(index) {
25    DCHECK(0 <= depth && depth <= kMaxUInt16);
26    DCHECK(0 <= index && static_cast<uint32_t>(index) <= kMaxUInt32);
27  }
28  int depth() const { return depth_; }
29  int index() const { return index_; }
30  bool immutable() const { return immutable_; }
31
32 private:
33  // For space reasons, we keep this tightly packed, otherwise we could just use
34  // a simple int/int/bool POD.
35  const bool immutable_;
36  const uint16_t depth_;
37  const uint32_t index_;
38};
39
40// Defines the property being loaded from an object by a named load. This is
41// used as a parameter by JSLoadNamed operators.
42struct LoadNamedParameters {
43  Unique<Name> name;
44  ContextualMode contextual_mode;
45};
46
47// Defines the arity and the call flags for a JavaScript function call. This is
48// used as a parameter by JSCall operators.
49struct CallParameters {
50  int arity;
51  CallFunctionFlags flags;
52};
53
54// Defines the property being stored to an object by a named store. This is
55// used as a parameter by JSStoreNamed operators.
56struct StoreNamedParameters {
57  StrictMode strict_mode;
58  Unique<Name> name;
59};
60
61// Interface for building JavaScript-level operators, e.g. directly from the
62// AST. Most operators have no parameters, thus can be globally shared for all
63// graphs.
64class JSOperatorBuilder {
65 public:
66  explicit JSOperatorBuilder(Zone* zone) : zone_(zone) {}
67
68#define SIMPLE(name, properties, inputs, outputs) \
69  return new (zone_)                              \
70      SimpleOperator(IrOpcode::k##name, properties, inputs, outputs, #name);
71
72#define NOPROPS(name, inputs, outputs) \
73  SIMPLE(name, Operator::kNoProperties, inputs, outputs)
74
75#define OP1(name, ptype, pname, properties, inputs, outputs)                 \
76  return new (zone_) Operator1<ptype>(IrOpcode::k##name, properties, inputs, \
77                                      outputs, #name, pname)
78
79#define BINOP(name) NOPROPS(name, 2, 1)
80#define UNOP(name) NOPROPS(name, 1, 1)
81
82#define PURE_BINOP(name) SIMPLE(name, Operator::kPure, 2, 1)
83
84  const Operator* Equal() { BINOP(JSEqual); }
85  const Operator* NotEqual() { BINOP(JSNotEqual); }
86  const Operator* StrictEqual() { PURE_BINOP(JSStrictEqual); }
87  const Operator* StrictNotEqual() { PURE_BINOP(JSStrictNotEqual); }
88  const Operator* LessThan() { BINOP(JSLessThan); }
89  const Operator* GreaterThan() { BINOP(JSGreaterThan); }
90  const Operator* LessThanOrEqual() { BINOP(JSLessThanOrEqual); }
91  const Operator* GreaterThanOrEqual() { BINOP(JSGreaterThanOrEqual); }
92  const Operator* BitwiseOr() { BINOP(JSBitwiseOr); }
93  const Operator* BitwiseXor() { BINOP(JSBitwiseXor); }
94  const Operator* BitwiseAnd() { BINOP(JSBitwiseAnd); }
95  const Operator* ShiftLeft() { BINOP(JSShiftLeft); }
96  const Operator* ShiftRight() { BINOP(JSShiftRight); }
97  const Operator* ShiftRightLogical() { BINOP(JSShiftRightLogical); }
98  const Operator* Add() { BINOP(JSAdd); }
99  const Operator* Subtract() { BINOP(JSSubtract); }
100  const Operator* Multiply() { BINOP(JSMultiply); }
101  const Operator* Divide() { BINOP(JSDivide); }
102  const Operator* Modulus() { BINOP(JSModulus); }
103
104  const Operator* UnaryNot() { UNOP(JSUnaryNot); }
105  const Operator* ToBoolean() { UNOP(JSToBoolean); }
106  const Operator* ToNumber() { UNOP(JSToNumber); }
107  const Operator* ToString() { UNOP(JSToString); }
108  const Operator* ToName() { UNOP(JSToName); }
109  const Operator* ToObject() { UNOP(JSToObject); }
110  const Operator* Yield() { UNOP(JSYield); }
111
112  const Operator* Create() { SIMPLE(JSCreate, Operator::kEliminatable, 0, 1); }
113
114  const Operator* Call(int arguments, CallFunctionFlags flags) {
115    CallParameters parameters = {arguments, flags};
116    OP1(JSCallFunction, CallParameters, parameters, Operator::kNoProperties,
117        arguments, 1);
118  }
119
120  const Operator* CallNew(int arguments) {
121    return new (zone_)
122        Operator1<int>(IrOpcode::kJSCallConstruct, Operator::kNoProperties,
123                       arguments, 1, "JSCallConstruct", arguments);
124  }
125
126  const Operator* LoadProperty() { BINOP(JSLoadProperty); }
127  const Operator* LoadNamed(Unique<Name> name,
128                            ContextualMode contextual_mode = NOT_CONTEXTUAL) {
129    LoadNamedParameters parameters = {name, contextual_mode};
130    OP1(JSLoadNamed, LoadNamedParameters, parameters, Operator::kNoProperties,
131        1, 1);
132  }
133
134  const Operator* StoreProperty(StrictMode strict_mode) {
135    OP1(JSStoreProperty, StrictMode, strict_mode, Operator::kNoProperties, 3,
136        0);
137  }
138
139  const Operator* StoreNamed(StrictMode strict_mode, Unique<Name> name) {
140    StoreNamedParameters parameters = {strict_mode, name};
141    OP1(JSStoreNamed, StoreNamedParameters, parameters, Operator::kNoProperties,
142        2, 0);
143  }
144
145  const Operator* DeleteProperty(StrictMode strict_mode) {
146    OP1(JSDeleteProperty, StrictMode, strict_mode, Operator::kNoProperties, 2,
147        1);
148  }
149
150  const Operator* HasProperty() { NOPROPS(JSHasProperty, 2, 1); }
151
152  const Operator* LoadContext(uint16_t depth, uint32_t index, bool immutable) {
153    ContextAccess access(depth, index, immutable);
154    OP1(JSLoadContext, ContextAccess, access,
155        Operator::kEliminatable | Operator::kNoWrite, 1, 1);
156  }
157  const Operator* StoreContext(uint16_t depth, uint32_t index) {
158    ContextAccess access(depth, index, false);
159    OP1(JSStoreContext, ContextAccess, access, Operator::kNoProperties, 2, 0);
160  }
161
162  const Operator* TypeOf() { SIMPLE(JSTypeOf, Operator::kPure, 1, 1); }
163  const Operator* InstanceOf() { NOPROPS(JSInstanceOf, 2, 1); }
164  const Operator* Debugger() { NOPROPS(JSDebugger, 0, 0); }
165
166  // TODO(titzer): nail down the static parts of each of these context flavors.
167  const Operator* CreateFunctionContext() {
168    NOPROPS(JSCreateFunctionContext, 1, 1);
169  }
170  const Operator* CreateCatchContext(Unique<String> name) {
171    OP1(JSCreateCatchContext, Unique<String>, name, Operator::kNoProperties, 1,
172        1);
173  }
174  const Operator* CreateWithContext() { NOPROPS(JSCreateWithContext, 2, 1); }
175  const Operator* CreateBlockContext() { NOPROPS(JSCreateBlockContext, 2, 1); }
176  const Operator* CreateModuleContext() {
177    NOPROPS(JSCreateModuleContext, 2, 1);
178  }
179  const Operator* CreateGlobalContext() {
180    NOPROPS(JSCreateGlobalContext, 2, 1);
181  }
182
183  const Operator* Runtime(Runtime::FunctionId function, int arguments) {
184    const Runtime::Function* f = Runtime::FunctionForId(function);
185    DCHECK(f->nargs == -1 || f->nargs == arguments);
186    OP1(JSCallRuntime, Runtime::FunctionId, function, Operator::kNoProperties,
187        arguments, f->result_size);
188  }
189
190#undef SIMPLE
191#undef NOPROPS
192#undef OP1
193#undef BINOP
194#undef UNOP
195
196 private:
197  Zone* zone_;
198};
199
200// Specialization for static parameters of type {ContextAccess}.
201template <>
202struct StaticParameterTraits<ContextAccess> {
203  static OStream& PrintTo(OStream& os, ContextAccess val) {  // NOLINT
204    return os << val.depth() << "," << val.index()
205              << (val.immutable() ? ",imm" : "");
206  }
207  static int HashCode(ContextAccess val) {
208    return (val.depth() << 16) | (val.index() & 0xffff);
209  }
210  static bool Equals(ContextAccess a, ContextAccess b) {
211    return a.immutable() == b.immutable() && a.depth() == b.depth() &&
212           a.index() == b.index();
213  }
214};
215
216// Specialization for static parameters of type {Runtime::FunctionId}.
217template <>
218struct StaticParameterTraits<Runtime::FunctionId> {
219  static OStream& PrintTo(OStream& os, Runtime::FunctionId val) {  // NOLINT
220    const Runtime::Function* f = Runtime::FunctionForId(val);
221    return os << (f->name ? f->name : "?Runtime?");
222  }
223  static int HashCode(Runtime::FunctionId val) { return static_cast<int>(val); }
224  static bool Equals(Runtime::FunctionId a, Runtime::FunctionId b) {
225    return a == b;
226  }
227};
228
229}  // namespace compiler
230}  // namespace internal
231}  // namespace v8
232
233#endif  // V8_COMPILER_JS_OPERATOR_H_
234