diff options
Diffstat (limited to 'deps/v8/src/compiler/code-assembler.cc')
-rw-r--r-- | deps/v8/src/compiler/code-assembler.cc | 306 |
1 files changed, 213 insertions, 93 deletions
diff --git a/deps/v8/src/compiler/code-assembler.cc b/deps/v8/src/compiler/code-assembler.cc index 93e384444e..4b1c211084 100644 --- a/deps/v8/src/compiler/code-assembler.cc +++ b/deps/v8/src/compiler/code-assembler.cc @@ -7,8 +7,8 @@ #include <ostream> #include "src/code-factory.h" +#include "src/compiler/backend/instruction-selector.h" #include "src/compiler/graph.h" -#include "src/compiler/instruction-selector.h" #include "src/compiler/linkage.h" #include "src/compiler/node-matchers.h" #include "src/compiler/pipeline.h" @@ -17,11 +17,11 @@ #include "src/frames.h" #include "src/interface-descriptors.h" #include "src/interpreter/bytecodes.h" -#include "src/lsan.h" #include "src/machine-type.h" #include "src/macro-assembler.h" +#include "src/memcopy.h" #include "src/objects-inl.h" -#include "src/utils.h" +#include "src/objects/smi.h" #include "src/zone/zone.h" namespace v8 { @@ -44,7 +44,7 @@ static_assert( CodeAssemblerState::CodeAssemblerState( Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor, Code::Kind kind, const char* name, PoisoningMitigationLevel poisoning_level, - uint32_t stub_key, int32_t builtin_index) + int32_t builtin_index) // TODO(rmcilroy): Should we use Linkage::GetBytecodeDispatchDescriptor for // bytecode handlers? : CodeAssemblerState( @@ -52,7 +52,7 @@ CodeAssemblerState::CodeAssemblerState( Linkage::GetStubCallDescriptor( zone, descriptor, descriptor.GetStackParameterCount(), CallDescriptor::kNoFlags, Operator::kNoProperties), - kind, name, poisoning_level, stub_key, builtin_index) {} + kind, name, poisoning_level, builtin_index) {} CodeAssemblerState::CodeAssemblerState(Isolate* isolate, Zone* zone, int parameter_count, Code::Kind kind, @@ -66,13 +66,13 @@ CodeAssemblerState::CodeAssemblerState(Isolate* isolate, Zone* zone, (kind == Code::BUILTIN ? CallDescriptor::kPushArgumentCount : CallDescriptor::kNoFlags) | CallDescriptor::kCanUseRoots), - kind, name, poisoning_level, 0, builtin_index) {} + kind, name, poisoning_level, builtin_index) {} CodeAssemblerState::CodeAssemblerState(Isolate* isolate, Zone* zone, CallDescriptor* call_descriptor, Code::Kind kind, const char* name, PoisoningMitigationLevel poisoning_level, - uint32_t stub_key, int32_t builtin_index) + int32_t builtin_index) : raw_assembler_(new RawMachineAssembler( isolate, new (zone) Graph(zone), call_descriptor, MachineType::PointerRepresentation(), @@ -80,7 +80,6 @@ CodeAssemblerState::CodeAssemblerState(Isolate* isolate, Zone* zone, InstructionSelector::AlignmentRequirements(), poisoning_level)), kind_(kind), name_(name), - stub_key_(stub_key), builtin_index_(builtin_index), code_generated_(false), variables_(zone) {} @@ -97,15 +96,16 @@ CodeAssembler::~CodeAssembler() = default; void CodeAssemblerState::PrintCurrentBlock(std::ostream& os) { raw_assembler_->PrintCurrentBlock(os); } +#endif bool CodeAssemblerState::InsideBlock() { return raw_assembler_->InsideBlock(); } -#endif void CodeAssemblerState::SetInitialDebugInformation(const char* msg, const char* file, int line) { #if DEBUG AssemblerDebugInfo debug_info = {msg, file, line}; + raw_assembler_->SetSourcePosition(file, line); raw_assembler_->SetInitialDebugInformation(debug_info); #endif // DEBUG } @@ -173,31 +173,15 @@ Handle<Code> CodeAssembler::GenerateCode(CodeAssemblerState* state, DCHECK(!state->code_generated_); RawMachineAssembler* rasm = state->raw_assembler_.get(); - Schedule* schedule = rasm->Export(); - JumpOptimizationInfo jump_opt; - bool should_optimize_jumps = - rasm->isolate()->serializer_enabled() && FLAG_turbo_rewrite_far_jumps; + Handle<Code> code; + Graph* graph = rasm->ExportForOptimization(); - Handle<Code> code = - Pipeline::GenerateCodeForCodeStub( - rasm->isolate(), rasm->call_descriptor(), rasm->graph(), schedule, - state->kind_, state->name_, state->stub_key_, state->builtin_index_, - should_optimize_jumps ? &jump_opt : nullptr, rasm->poisoning_level(), - options) - .ToHandleChecked(); - - if (jump_opt.is_optimizable()) { - jump_opt.set_optimizing(); - - // Regenerate machine code - code = - Pipeline::GenerateCodeForCodeStub( - rasm->isolate(), rasm->call_descriptor(), rasm->graph(), schedule, - state->kind_, state->name_, state->stub_key_, state->builtin_index_, - &jump_opt, rasm->poisoning_level(), options) - .ToHandleChecked(); - } + code = Pipeline::GenerateCodeForCodeStub( + rasm->isolate(), rasm->call_descriptor(), graph, + rasm->source_positions(), state->kind_, state->name_, + state->builtin_index_, rasm->poisoning_level(), options) + .ToHandleChecked(); state->code_generated_ = true; return code; @@ -275,9 +259,9 @@ TNode<Number> CodeAssembler::NumberConstant(double value) { } } -TNode<Smi> CodeAssembler::SmiConstant(Smi* value) { - return UncheckedCast<Smi>( - BitcastWordToTaggedSigned(IntPtrConstant(bit_cast<intptr_t>(value)))); +TNode<Smi> CodeAssembler::SmiConstant(Smi value) { + return UncheckedCast<Smi>(BitcastWordToTaggedSigned( + IntPtrConstant(static_cast<intptr_t>(value.ptr())))); } TNode<Smi> CodeAssembler::SmiConstant(int value) { @@ -296,7 +280,9 @@ TNode<String> CodeAssembler::StringConstant(const char* str) { } TNode<Oddball> CodeAssembler::BooleanConstant(bool value) { - return UncheckedCast<Oddball>(raw_assembler()->BooleanConstant(value)); + Handle<Object> object = isolate()->factory()->ToBoolean(value); + return UncheckedCast<Oddball>( + raw_assembler()->HeapConstant(Handle<HeapObject>::cast(object))); } TNode<ExternalReference> CodeAssembler::ExternalConstant( @@ -340,7 +326,7 @@ bool CodeAssembler::ToInt64Constant(Node* node, int64_t& out_value) { return m.HasValue(); } -bool CodeAssembler::ToSmiConstant(Node* node, Smi*& out_value) { +bool CodeAssembler::ToSmiConstant(Node* node, Smi* out_value) { if (node->opcode() == IrOpcode::kBitcastWordToTaggedSigned) { node = node->InputAt(0); } @@ -349,7 +335,7 @@ bool CodeAssembler::ToSmiConstant(Node* node, Smi*& out_value) { intptr_t value = m.Value(); // Make sure that the value is actually a smi CHECK_EQ(0, value & ((static_cast<intptr_t>(1) << kSmiShiftSize) - 1)); - out_value = Smi::cast(bit_cast<Object*>(value)); + *out_value = Smi(static_cast<Address>(value)); return true; } return false; @@ -434,25 +420,13 @@ void CodeAssembler::Unreachable() { raw_assembler()->Unreachable(); } -void CodeAssembler::Comment(const char* format, ...) { +void CodeAssembler::Comment(std::string str) { if (!FLAG_code_comments) return; - char buffer[4 * KB]; - StringBuilder builder(buffer, arraysize(buffer)); - va_list arguments; - va_start(arguments, format); - builder.AddFormattedList(format, arguments); - va_end(arguments); - - // Copy the string before recording it in the assembler to avoid - // issues when the stack allocated buffer goes out of scope. - const int prefix_len = 2; - int length = builder.position() + 1; - char* copy = reinterpret_cast<char*>(malloc(length + prefix_len)); - LSAN_IGNORE_OBJECT(copy); - MemCopy(copy + prefix_len, builder.Finalize(), length); - copy[0] = ';'; - copy[1] = ' '; - raw_assembler()->Comment(copy); + raw_assembler()->Comment(str); +} + +void CodeAssembler::SetSourcePosition(const char* file, int line) { + raw_assembler()->SetSourcePosition(file, line); } void CodeAssembler::Bind(Label* label) { return label->Bind(); } @@ -514,6 +488,23 @@ TNode<WordT> CodeAssembler::IntPtrAdd(SloppyTNode<WordT> left, return UncheckedCast<WordT>(raw_assembler()->IntPtrAdd(left, right)); } +TNode<IntPtrT> CodeAssembler::IntPtrDiv(TNode<IntPtrT> left, + TNode<IntPtrT> right) { + intptr_t left_constant; + bool is_left_constant = ToIntPtrConstant(left, left_constant); + intptr_t right_constant; + bool is_right_constant = ToIntPtrConstant(right, right_constant); + if (is_right_constant) { + if (is_left_constant) { + return IntPtrConstant(left_constant / right_constant); + } + if (base::bits::IsPowerOfTwo(right_constant)) { + return WordSar(left, WhichPowerOf2(right_constant)); + } + } + return UncheckedCast<IntPtrT>(raw_assembler()->IntPtrDiv(left, right)); +} + TNode<WordT> CodeAssembler::IntPtrSub(SloppyTNode<WordT> left, SloppyTNode<WordT> right) { intptr_t left_constant; @@ -965,8 +956,8 @@ Node* CodeAssembler::AtomicLoad(MachineType rep, Node* base, Node* offset) { } TNode<Object> CodeAssembler::LoadRoot(RootIndex root_index) { - if (isolate()->heap()->RootCanBeTreatedAsConstant(root_index)) { - Handle<Object> root = isolate()->heap()->root_handle(root_index); + if (RootsTable::IsImmortalImmovable(root_index)) { + Handle<Object> root = isolate()->root_handle(root_index); if (root->IsSmi()) { return SmiConstant(Smi::cast(*root)); } else { @@ -977,11 +968,11 @@ TNode<Object> CodeAssembler::LoadRoot(RootIndex root_index) { // TODO(jgruber): In theory we could generate better code for this by // letting the macro assembler decide how to load from the roots list. In most // cases, it would boil down to loading from a fixed kRootRegister offset. - Node* roots_array_start = - ExternalConstant(ExternalReference::roots_array_start(isolate())); - size_t offset = static_cast<size_t>(root_index) * kPointerSize; - return UncheckedCast<Object>(Load(MachineType::AnyTagged(), roots_array_start, - IntPtrConstant(offset))); + Node* isolate_root = + ExternalConstant(ExternalReference::isolate_root(isolate())); + int offset = IsolateData::root_slot_offset(root_index); + return UncheckedCast<Object>( + Load(MachineType::AnyTagged(), isolate_root, IntPtrConstant(offset))); } Node* CodeAssembler::Store(Node* base, Node* value) { @@ -989,15 +980,21 @@ Node* CodeAssembler::Store(Node* base, Node* value) { kFullWriteBarrier); } -Node* CodeAssembler::Store(Node* base, Node* offset, Node* value) { - return raw_assembler()->Store(MachineRepresentation::kTagged, base, offset, - value, kFullWriteBarrier); +void CodeAssembler::OptimizedStoreField(MachineRepresentation rep, + TNode<HeapObject> object, int offset, + Node* value, + WriteBarrierKind write_barrier) { + raw_assembler()->OptimizedStoreField(rep, object, offset, value, + write_barrier); +} +void CodeAssembler::OptimizedStoreMap(TNode<HeapObject> object, + TNode<Map> map) { + raw_assembler()->OptimizedStoreMap(object, map); } -Node* CodeAssembler::StoreWithMapWriteBarrier(Node* base, Node* offset, - Node* value) { +Node* CodeAssembler::Store(Node* base, Node* offset, Node* value) { return raw_assembler()->Store(MachineRepresentation::kTagged, base, offset, - value, kMapWriteBarrier); + value, kFullWriteBarrier); } Node* CodeAssembler::StoreNoWriteBarrier(MachineRepresentation rep, Node* base, @@ -1040,11 +1037,11 @@ Node* CodeAssembler::AtomicCompareExchange(MachineType type, Node* base, } Node* CodeAssembler::StoreRoot(RootIndex root_index, Node* value) { - DCHECK(Heap::RootCanBeWrittenAfterInitialization(root_index)); - Node* roots_array_start = - ExternalConstant(ExternalReference::roots_array_start(isolate())); - size_t offset = static_cast<size_t>(root_index) * kPointerSize; - return StoreNoWriteBarrier(MachineRepresentation::kTagged, roots_array_start, + DCHECK(!RootsTable::IsImmortalImmovable(root_index)); + Node* isolate_root = + ExternalConstant(ExternalReference::isolate_root(isolate())); + int offset = IsolateData::root_slot_offset(root_index); + return StoreNoWriteBarrier(MachineRepresentation::kTagged, isolate_root, IntPtrConstant(offset), value); } @@ -1053,7 +1050,7 @@ Node* CodeAssembler::Retain(Node* value) { } Node* CodeAssembler::Projection(int index, Node* value) { - DCHECK(index < value->op()->ValueOutputCount()); + DCHECK_LT(index, value->op()->ValueOutputCount()); return raw_assembler()->Projection(index, value); } @@ -1064,6 +1061,8 @@ void CodeAssembler::GotoIfException(Node* node, Label* if_exception, return; } + // No catch handlers should be active if we're using catch labels + DCHECK_EQ(state()->exception_handler_labels_.size(), 0); DCHECK(!node->op()->HasProperty(Operator::kNoThrow)); Label success(this), exception(this, Label::kDeferred); @@ -1081,6 +1080,38 @@ void CodeAssembler::GotoIfException(Node* node, Label* if_exception, Goto(if_exception); Bind(&success); + raw_assembler()->AddNode(raw_assembler()->common()->IfSuccess(), node); +} + +TNode<HeapObject> CodeAssembler::OptimizedAllocate(TNode<IntPtrT> size, + PretenureFlag pretenure) { + return UncheckedCast<HeapObject>( + raw_assembler()->OptimizedAllocate(size, pretenure)); +} + +void CodeAssembler::HandleException(Node* node) { + if (state_->exception_handler_labels_.size() == 0) return; + CodeAssemblerExceptionHandlerLabel* label = + state_->exception_handler_labels_.back(); + + if (node->op()->HasProperty(Operator::kNoThrow)) { + return; + } + + Label success(this), exception(this, Label::kDeferred); + success.MergeVariables(); + exception.MergeVariables(); + + raw_assembler()->Continuations(node, success.label_, exception.label_); + + Bind(&exception); + const Operator* op = raw_assembler()->common()->IfException(); + Node* exception_value = raw_assembler()->AddNode(op, node, node); + label->AddInputs({UncheckedCast<Object>(exception_value)}); + Goto(label->plain_label()); + + Bind(&success); + raw_assembler()->AddNode(raw_assembler()->common()->IfSuccess(), node); } namespace { @@ -1133,6 +1164,7 @@ TNode<Object> CodeAssembler::CallRuntimeWithCEntryImpl( CallPrologue(); Node* return_value = raw_assembler()->CallN(call_descriptor, inputs.size(), inputs.data()); + HandleException(return_value); CallEpilogue(); return UncheckedCast<Object>(return_value); } @@ -1168,9 +1200,13 @@ void CodeAssembler::TailCallRuntimeWithCEntryImpl( raw_assembler()->TailCallN(call_descriptor, inputs.size(), inputs.data()); } -Node* CodeAssembler::CallStubN(const CallInterfaceDescriptor& descriptor, +Node* CodeAssembler::CallStubN(StubCallMode call_mode, + const CallInterfaceDescriptor& descriptor, size_t result_size, int input_count, Node* const* inputs) { + DCHECK(call_mode == StubCallMode::kCallCodeObject || + call_mode == StubCallMode::kCallBuiltinPointer); + // implicit nodes are target and optionally context. int implicit_nodes = descriptor.HasContextParameter() ? 2 : 1; DCHECK_LE(implicit_nodes, input_count); @@ -1183,11 +1219,12 @@ Node* CodeAssembler::CallStubN(const CallInterfaceDescriptor& descriptor, auto call_descriptor = Linkage::GetStubCallDescriptor( zone(), descriptor, stack_parameter_count, CallDescriptor::kNoFlags, - Operator::kNoProperties); + Operator::kNoProperties, call_mode); CallPrologue(); Node* return_value = raw_assembler()->CallN(call_descriptor, input_count, inputs); + HandleException(return_value); CallEpilogue(); return return_value; } @@ -1212,10 +1249,14 @@ void CodeAssembler::TailCallStubImpl(const CallInterfaceDescriptor& descriptor, raw_assembler()->TailCallN(call_descriptor, inputs.size(), inputs.data()); } -Node* CodeAssembler::CallStubRImpl(const CallInterfaceDescriptor& descriptor, - size_t result_size, SloppyTNode<Code> target, +Node* CodeAssembler::CallStubRImpl(StubCallMode call_mode, + const CallInterfaceDescriptor& descriptor, + size_t result_size, Node* target, SloppyTNode<Object> context, std::initializer_list<Node*> args) { + DCHECK(call_mode == StubCallMode::kCallCodeObject || + call_mode == StubCallMode::kCallBuiltinPointer); + constexpr size_t kMaxNumArgs = 10; DCHECK_GE(kMaxNumArgs, args.size()); @@ -1226,7 +1267,8 @@ Node* CodeAssembler::CallStubRImpl(const CallInterfaceDescriptor& descriptor, inputs.Add(context); } - return CallStubN(descriptor, result_size, inputs.size(), inputs.data()); + return CallStubN(call_mode, descriptor, result_size, inputs.size(), + inputs.data()); } Node* CodeAssembler::TailCallStubThenBytecodeDispatchImpl( @@ -1484,6 +1526,10 @@ Factory* CodeAssembler::factory() const { return isolate()->factory(); } Zone* CodeAssembler::zone() const { return raw_assembler()->zone(); } +bool CodeAssembler::IsExceptionHandlerActive() const { + return state_->exception_handler_labels_.size() != 0; +} + RawMachineAssembler* CodeAssembler::raw_assembler() const { return state_->raw_assembler_.get(); } @@ -1494,13 +1540,14 @@ RawMachineAssembler* CodeAssembler::raw_assembler() const { // properly be verified. class CodeAssemblerVariable::Impl : public ZoneObject { public: - explicit Impl(MachineRepresentation rep) + explicit Impl(MachineRepresentation rep, CodeAssemblerState::VariableId id) : #if DEBUG debug_info_(AssemblerDebugInfo(nullptr, nullptr, -1)), #endif value_(nullptr), - rep_(rep) { + rep_(rep), + var_id_(id) { } #if DEBUG @@ -1511,13 +1558,25 @@ class CodeAssemblerVariable::Impl : public ZoneObject { AssemblerDebugInfo debug_info_; #endif // DEBUG + bool operator<(const CodeAssemblerVariable::Impl& other) const { + return var_id_ < other.var_id_; + } Node* value_; MachineRepresentation rep_; + CodeAssemblerState::VariableId var_id_; }; +bool CodeAssemblerVariable::ImplComparator::operator()( + const CodeAssemblerVariable::Impl* a, + const CodeAssemblerVariable::Impl* b) const { + return *a < *b; +} + CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler, MachineRepresentation rep) - : impl_(new (assembler->zone()) Impl(rep)), state_(assembler->state()) { + : impl_(new (assembler->zone()) + Impl(rep, assembler->state()->NextVariableId())), + state_(assembler->state()) { state_->variables_.insert(impl_); } @@ -1532,7 +1591,9 @@ CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler, CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler, AssemblerDebugInfo debug_info, MachineRepresentation rep) - : impl_(new (assembler->zone()) Impl(rep)), state_(assembler->state()) { + : impl_(new (assembler->zone()) + Impl(rep, assembler->state()->NextVariableId())), + state_(assembler->state()) { impl_->set_debug_info(debug_info); state_->variables_.insert(impl_); } @@ -1677,6 +1738,7 @@ void CodeAssemblerLabel::Bind(AssemblerDebugInfo debug_info) { << "\n# previous: " << *label_->block(); FATAL("%s", str.str().c_str()); } + state_->raw_assembler_->SetSourcePosition(debug_info.file, debug_info.line); state_->raw_assembler_->Bind(label_, debug_info); UpdateVariablesAfterBind(); } @@ -1791,21 +1853,79 @@ const std::vector<Node*>& CodeAssemblerParameterizedLabelBase::CreatePhis( return phi_nodes_; } +void CodeAssemblerState::PushExceptionHandler( + CodeAssemblerExceptionHandlerLabel* label) { + exception_handler_labels_.push_back(label); +} + +void CodeAssemblerState::PopExceptionHandler() { + exception_handler_labels_.pop_back(); +} + +CodeAssemblerScopedExceptionHandler::CodeAssemblerScopedExceptionHandler( + CodeAssembler* assembler, CodeAssemblerExceptionHandlerLabel* label) + : has_handler_(label != nullptr), + assembler_(assembler), + compatibility_label_(nullptr), + exception_(nullptr) { + if (has_handler_) { + assembler_->state()->PushExceptionHandler(label); + } +} + +CodeAssemblerScopedExceptionHandler::CodeAssemblerScopedExceptionHandler( + CodeAssembler* assembler, CodeAssemblerLabel* label, + TypedCodeAssemblerVariable<Object>* exception) + : has_handler_(label != nullptr), + assembler_(assembler), + compatibility_label_(label), + exception_(exception) { + if (has_handler_) { + label_ = base::make_unique<CodeAssemblerExceptionHandlerLabel>( + assembler, CodeAssemblerLabel::kDeferred); + assembler_->state()->PushExceptionHandler(label_.get()); + } +} + +CodeAssemblerScopedExceptionHandler::~CodeAssemblerScopedExceptionHandler() { + if (has_handler_) { + assembler_->state()->PopExceptionHandler(); + } + if (label_ && label_->is_used()) { + CodeAssembler::Label skip(assembler_); + bool inside_block = assembler_->state()->InsideBlock(); + if (inside_block) { + assembler_->Goto(&skip); + } + TNode<Object> e; + assembler_->Bind(label_.get(), &e); + *exception_ = e; + assembler_->Goto(compatibility_label_); + if (inside_block) { + assembler_->Bind(&skip); + } + } +} + } // namespace compiler -Smi* CheckObjectType(Object* value, Smi* type, String* location) { +Address CheckObjectType(Address raw_value, Address raw_type, + Address raw_location) { #ifdef DEBUG + Object value(raw_value); + Smi type(raw_type); + String location = String::cast(Object(raw_location)); const char* expected; switch (static_cast<ObjectType>(type->value())) { -#define TYPE_CASE(Name) \ - case ObjectType::k##Name: \ - if (value->Is##Name()) return Smi::FromInt(0); \ - expected = #Name; \ +#define TYPE_CASE(Name) \ + case ObjectType::k##Name: \ + if (value->Is##Name()) return Smi::FromInt(0).ptr(); \ + expected = #Name; \ break; -#define TYPE_STRUCT_CASE(NAME, Name, name) \ - case ObjectType::k##Name: \ - if (value->Is##Name()) return Smi::FromInt(0); \ - expected = #Name; \ +#define TYPE_STRUCT_CASE(NAME, Name, name) \ + case ObjectType::k##Name: \ + if (value->Is##Name()) return Smi::FromInt(0).ptr(); \ + expected = #Name; \ break; TYPE_CASE(Object) |