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