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