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 
14 namespace v8 {
15 namespace internal {
16 namespace 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.
21 class ContextAccess {
22  public:
ContextAccess(int depth,int index,bool immutable)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   }
depth()28   int depth() const { return depth_; }
index()29   int index() const { return index_; }
immutable()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.
42 struct 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.
49 struct 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.
56 struct 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.
64 class JSOperatorBuilder {
65  public:
JSOperatorBuilder(Zone * zone)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 
Equal()84   const Operator* Equal() { BINOP(JSEqual); }
NotEqual()85   const Operator* NotEqual() { BINOP(JSNotEqual); }
StrictEqual()86   const Operator* StrictEqual() { PURE_BINOP(JSStrictEqual); }
StrictNotEqual()87   const Operator* StrictNotEqual() { PURE_BINOP(JSStrictNotEqual); }
LessThan()88   const Operator* LessThan() { BINOP(JSLessThan); }
GreaterThan()89   const Operator* GreaterThan() { BINOP(JSGreaterThan); }
LessThanOrEqual()90   const Operator* LessThanOrEqual() { BINOP(JSLessThanOrEqual); }
GreaterThanOrEqual()91   const Operator* GreaterThanOrEqual() { BINOP(JSGreaterThanOrEqual); }
BitwiseOr()92   const Operator* BitwiseOr() { BINOP(JSBitwiseOr); }
BitwiseXor()93   const Operator* BitwiseXor() { BINOP(JSBitwiseXor); }
BitwiseAnd()94   const Operator* BitwiseAnd() { BINOP(JSBitwiseAnd); }
ShiftLeft()95   const Operator* ShiftLeft() { BINOP(JSShiftLeft); }
ShiftRight()96   const Operator* ShiftRight() { BINOP(JSShiftRight); }
ShiftRightLogical()97   const Operator* ShiftRightLogical() { BINOP(JSShiftRightLogical); }
Add()98   const Operator* Add() { BINOP(JSAdd); }
Subtract()99   const Operator* Subtract() { BINOP(JSSubtract); }
Multiply()100   const Operator* Multiply() { BINOP(JSMultiply); }
Divide()101   const Operator* Divide() { BINOP(JSDivide); }
Modulus()102   const Operator* Modulus() { BINOP(JSModulus); }
103 
UnaryNot()104   const Operator* UnaryNot() { UNOP(JSUnaryNot); }
ToBoolean()105   const Operator* ToBoolean() { UNOP(JSToBoolean); }
ToNumber()106   const Operator* ToNumber() { UNOP(JSToNumber); }
ToString()107   const Operator* ToString() { UNOP(JSToString); }
ToName()108   const Operator* ToName() { UNOP(JSToName); }
ToObject()109   const Operator* ToObject() { UNOP(JSToObject); }
Yield()110   const Operator* Yield() { UNOP(JSYield); }
111 
Create()112   const Operator* Create() { SIMPLE(JSCreate, Operator::kEliminatable, 0, 1); }
113 
Call(int arguments,CallFunctionFlags flags)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 
CallNew(int arguments)120   const Operator* CallNew(int arguments) {
121     return new (zone_)
122         Operator1<int>(IrOpcode::kJSCallConstruct, Operator::kNoProperties,
123                        arguments, 1, "JSCallConstruct", arguments);
124   }
125 
LoadProperty()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 
StoreProperty(StrictMode strict_mode)134   const Operator* StoreProperty(StrictMode strict_mode) {
135     OP1(JSStoreProperty, StrictMode, strict_mode, Operator::kNoProperties, 3,
136         0);
137   }
138 
StoreNamed(StrictMode strict_mode,Unique<Name> name)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 
DeleteProperty(StrictMode strict_mode)145   const Operator* DeleteProperty(StrictMode strict_mode) {
146     OP1(JSDeleteProperty, StrictMode, strict_mode, Operator::kNoProperties, 2,
147         1);
148   }
149 
HasProperty()150   const Operator* HasProperty() { NOPROPS(JSHasProperty, 2, 1); }
151 
LoadContext(uint16_t depth,uint32_t index,bool immutable)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   }
StoreContext(uint16_t depth,uint32_t index)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 
TypeOf()162   const Operator* TypeOf() { SIMPLE(JSTypeOf, Operator::kPure, 1, 1); }
InstanceOf()163   const Operator* InstanceOf() { NOPROPS(JSInstanceOf, 2, 1); }
Debugger()164   const Operator* Debugger() { NOPROPS(JSDebugger, 0, 0); }
165 
166   // TODO(titzer): nail down the static parts of each of these context flavors.
CreateFunctionContext()167   const Operator* CreateFunctionContext() {
168     NOPROPS(JSCreateFunctionContext, 1, 1);
169   }
CreateCatchContext(Unique<String> name)170   const Operator* CreateCatchContext(Unique<String> name) {
171     OP1(JSCreateCatchContext, Unique<String>, name, Operator::kNoProperties, 1,
172         1);
173   }
CreateWithContext()174   const Operator* CreateWithContext() { NOPROPS(JSCreateWithContext, 2, 1); }
CreateBlockContext()175   const Operator* CreateBlockContext() { NOPROPS(JSCreateBlockContext, 2, 1); }
CreateModuleContext()176   const Operator* CreateModuleContext() {
177     NOPROPS(JSCreateModuleContext, 2, 1);
178   }
CreateGlobalContext()179   const Operator* CreateGlobalContext() {
180     NOPROPS(JSCreateGlobalContext, 2, 1);
181   }
182 
Runtime(Runtime::FunctionId function,int arguments)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}.
201 template <>
202 struct 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}.
217 template <>
218 struct 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