1 // Copyright 2015 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_CODE_ASSEMBLER_H_ 6 #define V8_COMPILER_CODE_ASSEMBLER_H_ 7 8 #include <map> 9 #include <memory> 10 11 // Clients of this interface shouldn't depend on lots of compiler internals. 12 // Do not include anything from src/compiler here! 13 #include "src/allocation.h" 14 #include "src/builtins/builtins.h" 15 #include "src/code-factory.h" 16 #include "src/globals.h" 17 #include "src/heap/heap.h" 18 #include "src/machine-type.h" 19 #include "src/runtime/runtime.h" 20 #include "src/zone/zone-containers.h" 21 22 namespace v8 { 23 namespace internal { 24 25 class Callable; 26 class CallInterfaceDescriptor; 27 class Isolate; 28 class Factory; 29 class Zone; 30 31 namespace compiler { 32 33 class CallDescriptor; 34 class CodeAssemblerLabel; 35 class CodeAssemblerVariable; 36 class CodeAssemblerState; 37 class Node; 38 class RawMachineAssembler; 39 class RawMachineLabel; 40 41 typedef ZoneList<CodeAssemblerVariable*> CodeAssemblerVariableList; 42 43 typedef std::function<void()> CodeAssemblerCallback; 44 45 #define CODE_ASSEMBLER_COMPARE_BINARY_OP_LIST(V) \ 46 V(Float32Equal) \ 47 V(Float32LessThan) \ 48 V(Float32LessThanOrEqual) \ 49 V(Float32GreaterThan) \ 50 V(Float32GreaterThanOrEqual) \ 51 V(Float64Equal) \ 52 V(Float64LessThan) \ 53 V(Float64LessThanOrEqual) \ 54 V(Float64GreaterThan) \ 55 V(Float64GreaterThanOrEqual) \ 56 V(Int32GreaterThan) \ 57 V(Int32GreaterThanOrEqual) \ 58 V(Int32LessThan) \ 59 V(Int32LessThanOrEqual) \ 60 V(IntPtrLessThan) \ 61 V(IntPtrLessThanOrEqual) \ 62 V(IntPtrGreaterThan) \ 63 V(IntPtrGreaterThanOrEqual) \ 64 V(IntPtrEqual) \ 65 V(Uint32LessThan) \ 66 V(Uint32LessThanOrEqual) \ 67 V(Uint32GreaterThanOrEqual) \ 68 V(UintPtrLessThan) \ 69 V(UintPtrLessThanOrEqual) \ 70 V(UintPtrGreaterThan) \ 71 V(UintPtrGreaterThanOrEqual) \ 72 V(WordEqual) \ 73 V(WordNotEqual) \ 74 V(Word32Equal) \ 75 V(Word32NotEqual) \ 76 V(Word64Equal) \ 77 V(Word64NotEqual) 78 79 #define CODE_ASSEMBLER_BINARY_OP_LIST(V) \ 80 CODE_ASSEMBLER_COMPARE_BINARY_OP_LIST(V) \ 81 V(Float64Add) \ 82 V(Float64Sub) \ 83 V(Float64Mul) \ 84 V(Float64Div) \ 85 V(Float64Mod) \ 86 V(Float64Atan2) \ 87 V(Float64Pow) \ 88 V(Float64InsertLowWord32) \ 89 V(Float64InsertHighWord32) \ 90 V(IntPtrAddWithOverflow) \ 91 V(IntPtrSubWithOverflow) \ 92 V(IntPtrMul) \ 93 V(Int32Add) \ 94 V(Int32AddWithOverflow) \ 95 V(Int32Sub) \ 96 V(Int32Mul) \ 97 V(Int32MulWithOverflow) \ 98 V(Int32Div) \ 99 V(Int32Mod) \ 100 V(WordOr) \ 101 V(WordAnd) \ 102 V(WordXor) \ 103 V(WordShl) \ 104 V(WordShr) \ 105 V(WordSar) \ 106 V(WordRor) \ 107 V(Word32Or) \ 108 V(Word32And) \ 109 V(Word32Xor) \ 110 V(Word32Shl) \ 111 V(Word32Shr) \ 112 V(Word32Sar) \ 113 V(Word32Ror) \ 114 V(Word64Or) \ 115 V(Word64And) \ 116 V(Word64Xor) \ 117 V(Word64Shr) \ 118 V(Word64Sar) \ 119 V(Word64Ror) 120 121 #define CODE_ASSEMBLER_UNARY_OP_LIST(V) \ 122 V(Float64Abs) \ 123 V(Float64Acos) \ 124 V(Float64Acosh) \ 125 V(Float64Asin) \ 126 V(Float64Asinh) \ 127 V(Float64Atan) \ 128 V(Float64Atanh) \ 129 V(Float64Cos) \ 130 V(Float64Cosh) \ 131 V(Float64Exp) \ 132 V(Float64Expm1) \ 133 V(Float64Log) \ 134 V(Float64Log1p) \ 135 V(Float64Log2) \ 136 V(Float64Log10) \ 137 V(Float64Cbrt) \ 138 V(Float64Neg) \ 139 V(Float64Sin) \ 140 V(Float64Sinh) \ 141 V(Float64Sqrt) \ 142 V(Float64Tan) \ 143 V(Float64Tanh) \ 144 V(Float64ExtractLowWord32) \ 145 V(Float64ExtractHighWord32) \ 146 V(BitcastTaggedToWord) \ 147 V(BitcastWordToTagged) \ 148 V(BitcastWordToTaggedSigned) \ 149 V(TruncateFloat64ToFloat32) \ 150 V(TruncateFloat64ToWord32) \ 151 V(TruncateInt64ToInt32) \ 152 V(ChangeFloat32ToFloat64) \ 153 V(ChangeFloat64ToUint32) \ 154 V(ChangeInt32ToFloat64) \ 155 V(ChangeInt32ToInt64) \ 156 V(ChangeUint32ToFloat64) \ 157 V(ChangeUint32ToUint64) \ 158 V(RoundFloat64ToInt32) \ 159 V(RoundInt32ToFloat32) \ 160 V(Float64SilenceNaN) \ 161 V(Float64RoundDown) \ 162 V(Float64RoundUp) \ 163 V(Float64RoundTiesEven) \ 164 V(Float64RoundTruncate) \ 165 V(Word32Clz) \ 166 V(Word32Not) \ 167 V(Word32BinaryNot) 168 169 // A "public" interface used by components outside of compiler directory to 170 // create code objects with TurboFan's backend. This class is mostly a thin shim 171 // around the RawMachineAssembler, and its primary job is to ensure that the 172 // innards of the RawMachineAssembler and other compiler implementation details 173 // don't leak outside of the the compiler directory.. 174 // 175 // V8 components that need to generate low-level code using this interface 176 // should include this header--and this header only--from the compiler directory 177 // (this is actually enforced). Since all interesting data structures are 178 // forward declared, it's not possible for clients to peek inside the compiler 179 // internals. 180 // 181 // In addition to providing isolation between TurboFan and code generation 182 // clients, CodeAssembler also provides an abstraction for creating variables 183 // and enhanced Label functionality to merge variable values along paths where 184 // they have differing values, including loops. 185 // 186 // The CodeAssembler itself is stateless (and instances are expected to be 187 // temporary-scoped and short-lived); all its state is encapsulated into 188 // a CodeAssemblerState instance. 189 class V8_EXPORT_PRIVATE CodeAssembler { 190 public: CodeAssembler(CodeAssemblerState * state)191 explicit CodeAssembler(CodeAssemblerState* state) : state_(state) {} 192 ~CodeAssembler(); 193 194 static Handle<Code> GenerateCode(CodeAssemblerState* state); 195 196 bool Is64() const; 197 bool IsFloat64RoundUpSupported() const; 198 bool IsFloat64RoundDownSupported() const; 199 bool IsFloat64RoundTiesEvenSupported() const; 200 bool IsFloat64RoundTruncateSupported() const; 201 202 // Shortened aliases for use in CodeAssembler subclasses. 203 typedef CodeAssemblerLabel Label; 204 typedef CodeAssemblerVariable Variable; 205 typedef CodeAssemblerVariableList VariableList; 206 207 // =========================================================================== 208 // Base Assembler 209 // =========================================================================== 210 211 // Constants. 212 Node* Int32Constant(int32_t value); 213 Node* Int64Constant(int64_t value); 214 Node* IntPtrConstant(intptr_t value); 215 Node* NumberConstant(double value); 216 Node* SmiConstant(Smi* value); 217 Node* SmiConstant(int value); 218 Node* HeapConstant(Handle<HeapObject> object); 219 Node* CStringConstant(const char* str); 220 Node* BooleanConstant(bool value); 221 Node* ExternalConstant(ExternalReference address); 222 Node* Float64Constant(double value); 223 Node* NaNConstant(); 224 225 bool ToInt32Constant(Node* node, int32_t& out_value); 226 bool ToInt64Constant(Node* node, int64_t& out_value); 227 bool ToSmiConstant(Node* node, Smi*& out_value); 228 bool ToIntPtrConstant(Node* node, intptr_t& out_value); 229 230 Node* Parameter(int value); 231 Node* GetJSContextParameter(); 232 void Return(Node* value); 233 void Return(Node* value1, Node* value2); 234 void Return(Node* value1, Node* value2, Node* value3); 235 void PopAndReturn(Node* pop, Node* value); 236 237 void DebugBreak(); 238 void Unreachable(); 239 void Comment(const char* format, ...); 240 241 void Bind(Label* label); 242 void Goto(Label* label); 243 void GotoIf(Node* condition, Label* true_label); 244 void GotoIfNot(Node* condition, Label* false_label); 245 void Branch(Node* condition, Label* true_label, Label* false_label); 246 247 void Switch(Node* index, Label* default_label, const int32_t* case_values, 248 Label** case_labels, size_t case_count); 249 250 // Access to the frame pointer 251 Node* LoadFramePointer(); 252 Node* LoadParentFramePointer(); 253 254 // Access to the stack pointer 255 Node* LoadStackPointer(); 256 257 // Load raw memory location. 258 Node* Load(MachineType rep, Node* base); 259 Node* Load(MachineType rep, Node* base, Node* offset); 260 Node* AtomicLoad(MachineType rep, Node* base, Node* offset); 261 262 // Load a value from the root array. 263 Node* LoadRoot(Heap::RootListIndex root_index); 264 265 // Store value to raw memory location. 266 Node* Store(Node* base, Node* value); 267 Node* Store(Node* base, Node* offset, Node* value); 268 Node* StoreWithMapWriteBarrier(Node* base, Node* offset, Node* value); 269 Node* StoreNoWriteBarrier(MachineRepresentation rep, Node* base, Node* value); 270 Node* StoreNoWriteBarrier(MachineRepresentation rep, Node* base, Node* offset, 271 Node* value); 272 Node* AtomicStore(MachineRepresentation rep, Node* base, Node* offset, 273 Node* value); 274 275 // Store a value to the root array. 276 Node* StoreRoot(Heap::RootListIndex root_index, Node* value); 277 278 // Basic arithmetic operations. 279 #define DECLARE_CODE_ASSEMBLER_BINARY_OP(name) Node* name(Node* a, Node* b); 280 CODE_ASSEMBLER_BINARY_OP_LIST(DECLARE_CODE_ASSEMBLER_BINARY_OP) 281 #undef DECLARE_CODE_ASSEMBLER_BINARY_OP 282 283 Node* IntPtrAdd(Node* left, Node* right); 284 Node* IntPtrSub(Node* left, Node* right); 285 286 Node* WordShl(Node* value, int shift); 287 Node* WordShr(Node* value, int shift); 288 Node* Word32Shr(Node* value, int shift); 289 290 // Unary 291 #define DECLARE_CODE_ASSEMBLER_UNARY_OP(name) Node* name(Node* a); 292 CODE_ASSEMBLER_UNARY_OP_LIST(DECLARE_CODE_ASSEMBLER_UNARY_OP) 293 #undef DECLARE_CODE_ASSEMBLER_UNARY_OP 294 295 // Changes an intptr_t to a double, e.g. for storing an element index 296 // outside Smi range in a HeapNumber. Lossless on 32-bit, 297 // rounds on 64-bit (which doesn't affect valid element indices). 298 Node* RoundIntPtrToFloat64(Node* value); 299 // No-op on 32-bit, otherwise zero extend. 300 Node* ChangeUint32ToWord(Node* value); 301 // No-op on 32-bit, otherwise sign extend. 302 Node* ChangeInt32ToIntPtr(Node* value); 303 304 // No-op that guarantees that the value is kept alive till this point even 305 // if GC happens. 306 Node* Retain(Node* value); 307 308 // Projections 309 Node* Projection(int index, Node* value); 310 311 // Calls 312 template <class... TArgs> 313 Node* CallRuntime(Runtime::FunctionId function, Node* context, TArgs... args); 314 315 template <class... TArgs> 316 Node* TailCallRuntime(Runtime::FunctionId function, Node* context, 317 TArgs... args); 318 319 template <class... TArgs> CallStub(Callable const & callable,Node * context,TArgs...args)320 Node* CallStub(Callable const& callable, Node* context, TArgs... args) { 321 Node* target = HeapConstant(callable.code()); 322 return CallStub(callable.descriptor(), target, context, args...); 323 } 324 325 template <class... TArgs> CallStub(const CallInterfaceDescriptor & descriptor,Node * target,Node * context,TArgs...args)326 Node* CallStub(const CallInterfaceDescriptor& descriptor, Node* target, 327 Node* context, TArgs... args) { 328 return CallStubR(descriptor, 1, target, context, args...); 329 } 330 331 template <class... TArgs> 332 Node* CallStubR(const CallInterfaceDescriptor& descriptor, size_t result_size, 333 Node* target, Node* context, TArgs... args); 334 335 Node* CallStubN(const CallInterfaceDescriptor& descriptor, size_t result_size, 336 int input_count, Node* const* inputs); 337 338 template <class... TArgs> TailCallStub(Callable const & callable,Node * context,TArgs...args)339 Node* TailCallStub(Callable const& callable, Node* context, TArgs... args) { 340 Node* target = HeapConstant(callable.code()); 341 return TailCallStub(callable.descriptor(), target, context, args...); 342 } 343 344 template <class... TArgs> 345 Node* TailCallStub(const CallInterfaceDescriptor& descriptor, Node* target, 346 Node* context, TArgs... args); 347 348 template <class... TArgs> 349 Node* TailCallBytecodeDispatch(const CallInterfaceDescriptor& descriptor, 350 Node* target, TArgs... args); 351 352 template <class... TArgs> CallJS(Callable const & callable,Node * context,Node * function,Node * receiver,TArgs...args)353 Node* CallJS(Callable const& callable, Node* context, Node* function, 354 Node* receiver, TArgs... args) { 355 int argc = static_cast<int>(sizeof...(args)); 356 Node* arity = Int32Constant(argc); 357 return CallStub(callable, context, function, arity, receiver, args...); 358 } 359 360 template <class... TArgs> ConstructJS(Callable const & callable,Node * context,Node * new_target,TArgs...args)361 Node* ConstructJS(Callable const& callable, Node* context, Node* new_target, 362 TArgs... args) { 363 int argc = static_cast<int>(sizeof...(args)); 364 Node* arity = Int32Constant(argc); 365 Node* receiver = LoadRoot(Heap::kUndefinedValueRootIndex); 366 367 // Construct(target, new_target, arity, receiver, arguments...) 368 return CallStub(callable, context, new_target, new_target, arity, receiver, 369 args...); 370 } 371 372 Node* CallCFunctionN(Signature<MachineType>* signature, int input_count, 373 Node* const* inputs); 374 375 // Call to a C function with two arguments. 376 Node* CallCFunction2(MachineType return_type, MachineType arg0_type, 377 MachineType arg1_type, Node* function, Node* arg0, 378 Node* arg1); 379 380 // Call to a C function with three arguments. 381 Node* CallCFunction3(MachineType return_type, MachineType arg0_type, 382 MachineType arg1_type, MachineType arg2_type, 383 Node* function, Node* arg0, Node* arg1, Node* arg2); 384 385 // Exception handling support. 386 void GotoIfException(Node* node, Label* if_exception, 387 Variable* exception_var = nullptr); 388 389 // Helpers which delegate to RawMachineAssembler. 390 Factory* factory() const; 391 Isolate* isolate() const; 392 Zone* zone() const; 393 state()394 CodeAssemblerState* state() { return state_; } 395 396 void BreakOnNode(int node_id); 397 398 protected: 399 void RegisterCallGenerationCallbacks( 400 const CodeAssemblerCallback& call_prologue, 401 const CodeAssemblerCallback& call_epilogue); 402 void UnregisterCallGenerationCallbacks(); 403 404 private: 405 RawMachineAssembler* raw_assembler() const; 406 407 // Calls respective callback registered in the state. 408 void CallPrologue(); 409 void CallEpilogue(); 410 411 CodeAssemblerState* state_; 412 413 DISALLOW_COPY_AND_ASSIGN(CodeAssembler); 414 }; 415 416 class CodeAssemblerVariable { 417 public: 418 explicit CodeAssemblerVariable(CodeAssembler* assembler, 419 MachineRepresentation rep); 420 CodeAssemblerVariable(CodeAssembler* assembler, MachineRepresentation rep, 421 Node* initial_value); 422 ~CodeAssemblerVariable(); 423 void Bind(Node* value); 424 Node* value() const; 425 MachineRepresentation rep() const; 426 bool IsBound() const; 427 428 private: 429 friend class CodeAssemblerLabel; 430 friend class CodeAssemblerState; 431 class Impl; 432 Impl* impl_; 433 CodeAssemblerState* state_; 434 }; 435 436 class CodeAssemblerLabel { 437 public: 438 enum Type { kDeferred, kNonDeferred }; 439 440 explicit CodeAssemblerLabel( 441 CodeAssembler* assembler, 442 CodeAssemblerLabel::Type type = CodeAssemblerLabel::kNonDeferred) 443 : CodeAssemblerLabel(assembler, 0, nullptr, type) {} 444 CodeAssemblerLabel( 445 CodeAssembler* assembler, 446 const CodeAssemblerVariableList& merged_variables, 447 CodeAssemblerLabel::Type type = CodeAssemblerLabel::kNonDeferred) 448 : CodeAssemblerLabel(assembler, merged_variables.length(), 449 &(merged_variables[0]), type) {} 450 CodeAssemblerLabel( 451 CodeAssembler* assembler, size_t count, CodeAssemblerVariable** vars, 452 CodeAssemblerLabel::Type type = CodeAssemblerLabel::kNonDeferred); 453 CodeAssemblerLabel( 454 CodeAssembler* assembler, CodeAssemblerVariable* merged_variable, 455 CodeAssemblerLabel::Type type = CodeAssemblerLabel::kNonDeferred) 456 : CodeAssemblerLabel(assembler, 1, &merged_variable, type) {} 457 ~CodeAssemblerLabel(); 458 459 private: 460 friend class CodeAssembler; 461 462 void Bind(); 463 void MergeVariables(); 464 465 bool bound_; 466 size_t merge_count_; 467 CodeAssemblerState* state_; 468 RawMachineLabel* label_; 469 // Map of variables that need to be merged to their phi nodes (or placeholders 470 // for those phis). 471 std::map<CodeAssemblerVariable::Impl*, Node*> variable_phis_; 472 // Map of variables to the list of value nodes that have been added from each 473 // merge path in their order of merging. 474 std::map<CodeAssemblerVariable::Impl*, std::vector<Node*>> variable_merges_; 475 }; 476 477 class V8_EXPORT_PRIVATE CodeAssemblerState { 478 public: 479 // Create with CallStub linkage. 480 // |result_size| specifies the number of results returned by the stub. 481 // TODO(rmcilroy): move result_size to the CallInterfaceDescriptor. 482 CodeAssemblerState(Isolate* isolate, Zone* zone, 483 const CallInterfaceDescriptor& descriptor, 484 Code::Flags flags, const char* name, 485 size_t result_size = 1); 486 487 // Create with JSCall linkage. 488 CodeAssemblerState(Isolate* isolate, Zone* zone, int parameter_count, 489 Code::Flags flags, const char* name); 490 491 ~CodeAssemblerState(); 492 name()493 const char* name() const { return name_; } 494 int parameter_count() const; 495 496 private: 497 friend class CodeAssembler; 498 friend class CodeAssemblerLabel; 499 friend class CodeAssemblerVariable; 500 501 CodeAssemblerState(Isolate* isolate, Zone* zone, 502 CallDescriptor* call_descriptor, Code::Flags flags, 503 const char* name); 504 505 std::unique_ptr<RawMachineAssembler> raw_assembler_; 506 Code::Flags flags_; 507 const char* name_; 508 bool code_generated_; 509 ZoneSet<CodeAssemblerVariable::Impl*> variables_; 510 CodeAssemblerCallback call_prologue_; 511 CodeAssemblerCallback call_epilogue_; 512 513 DISALLOW_COPY_AND_ASSIGN(CodeAssemblerState); 514 }; 515 516 } // namespace compiler 517 } // namespace internal 518 } // namespace v8 519 520 #endif // V8_COMPILER_CODE_ASSEMBLER_H_ 521