// Copyright 2014 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/compiler/common-operator.h" #include "src/assembler.h" #include "src/base/lazy-instance.h" #include "src/compiler/linkage.h" #include "src/compiler/opcodes.h" #include "src/compiler/operator.h" #include "src/handles-inl.h" #include "src/zone.h" namespace v8 { namespace internal { namespace compiler { std::ostream& operator<<(std::ostream& os, BranchHint hint) { switch (hint) { case BranchHint::kNone: return os << "None"; case BranchHint::kTrue: return os << "True"; case BranchHint::kFalse: return os << "False"; } UNREACHABLE(); return os; } BranchHint BranchHintOf(const Operator* const op) { DCHECK_EQ(IrOpcode::kBranch, op->opcode()); return OpParameter(op); } size_t hash_value(DeoptimizeKind kind) { return static_cast(kind); } std::ostream& operator<<(std::ostream& os, DeoptimizeKind kind) { switch (kind) { case DeoptimizeKind::kEager: return os << "Eager"; case DeoptimizeKind::kSoft: return os << "Soft"; } UNREACHABLE(); return os; } DeoptimizeKind DeoptimizeKindOf(const Operator* const op) { DCHECK_EQ(IrOpcode::kDeoptimize, op->opcode()); return OpParameter(op); } size_t hash_value(IfExceptionHint hint) { return static_cast(hint); } std::ostream& operator<<(std::ostream& os, IfExceptionHint hint) { switch (hint) { case IfExceptionHint::kLocallyCaught: return os << "Caught"; case IfExceptionHint::kLocallyUncaught: return os << "Uncaught"; } UNREACHABLE(); return os; } bool operator==(SelectParameters const& lhs, SelectParameters const& rhs) { return lhs.representation() == rhs.representation() && lhs.hint() == rhs.hint(); } bool operator!=(SelectParameters const& lhs, SelectParameters const& rhs) { return !(lhs == rhs); } size_t hash_value(SelectParameters const& p) { return base::hash_combine(p.representation(), p.hint()); } std::ostream& operator<<(std::ostream& os, SelectParameters const& p) { return os << p.representation() << "|" << p.hint(); } SelectParameters const& SelectParametersOf(const Operator* const op) { DCHECK_EQ(IrOpcode::kSelect, op->opcode()); return OpParameter(op); } size_t ProjectionIndexOf(const Operator* const op) { DCHECK_EQ(IrOpcode::kProjection, op->opcode()); return OpParameter(op); } MachineRepresentation PhiRepresentationOf(const Operator* const op) { DCHECK_EQ(IrOpcode::kPhi, op->opcode()); return OpParameter(op); } int ParameterIndexOf(const Operator* const op) { DCHECK_EQ(IrOpcode::kParameter, op->opcode()); return OpParameter(op).index(); } const ParameterInfo& ParameterInfoOf(const Operator* const op) { DCHECK_EQ(IrOpcode::kParameter, op->opcode()); return OpParameter(op); } bool operator==(ParameterInfo const& lhs, ParameterInfo const& rhs) { return lhs.index() == rhs.index(); } bool operator!=(ParameterInfo const& lhs, ParameterInfo const& rhs) { return !(lhs == rhs); } size_t hash_value(ParameterInfo const& p) { return p.index(); } std::ostream& operator<<(std::ostream& os, ParameterInfo const& i) { if (i.debug_name()) os << i.debug_name() << '#'; os << i.index(); return os; } #define CACHED_OP_LIST(V) \ V(Dead, Operator::kFoldable, 0, 0, 0, 1, 1, 1) \ V(IfTrue, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \ V(IfFalse, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \ V(IfSuccess, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \ V(IfDefault, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \ V(Throw, Operator::kKontrol, 1, 1, 1, 0, 0, 1) \ V(Terminate, Operator::kKontrol, 0, 1, 1, 0, 0, 1) \ V(OsrNormalEntry, Operator::kFoldable, 0, 1, 1, 0, 1, 1) \ V(OsrLoopEntry, Operator::kFoldable, 0, 1, 1, 0, 1, 1) \ V(BeginRegion, Operator::kNoThrow, 0, 1, 0, 0, 1, 0) \ V(FinishRegion, Operator::kNoThrow, 1, 1, 0, 1, 1, 0) #define CACHED_RETURN_LIST(V) \ V(1) \ V(2) \ V(3) #define CACHED_END_LIST(V) \ V(1) \ V(2) \ V(3) \ V(4) \ V(5) \ V(6) \ V(7) \ V(8) #define CACHED_EFFECT_PHI_LIST(V) \ V(1) \ V(2) \ V(3) \ V(4) \ V(5) \ V(6) #define CACHED_LOOP_LIST(V) \ V(1) \ V(2) #define CACHED_MERGE_LIST(V) \ V(1) \ V(2) \ V(3) \ V(4) \ V(5) \ V(6) \ V(7) \ V(8) #define CACHED_PARAMETER_LIST(V) \ V(0) \ V(1) \ V(2) \ V(3) \ V(4) \ V(5) \ V(6) #define CACHED_PHI_LIST(V) \ V(kTagged, 1) \ V(kTagged, 2) \ V(kTagged, 3) \ V(kTagged, 4) \ V(kTagged, 5) \ V(kTagged, 6) \ V(kBit, 2) \ V(kFloat64, 2) \ V(kWord32, 2) #define CACHED_PROJECTION_LIST(V) \ V(0) \ V(1) #define CACHED_STATE_VALUES_LIST(V) \ V(0) \ V(1) \ V(2) \ V(3) \ V(4) \ V(5) \ V(6) \ V(7) \ V(8) \ V(10) \ V(11) \ V(12) \ V(13) \ V(14) struct CommonOperatorGlobalCache final { #define CACHED(Name, properties, value_input_count, effect_input_count, \ control_input_count, value_output_count, effect_output_count, \ control_output_count) \ struct Name##Operator final : public Operator { \ Name##Operator() \ : Operator(IrOpcode::k##Name, properties, #Name, value_input_count, \ effect_input_count, control_input_count, \ value_output_count, effect_output_count, \ control_output_count) {} \ }; \ Name##Operator k##Name##Operator; CACHED_OP_LIST(CACHED) #undef CACHED template struct DeoptimizeOperator final : public Operator1 { DeoptimizeOperator() : Operator1( // -- IrOpcode::kDeoptimize, Operator::kNoThrow, // opcode "Deoptimize", // name 1, 1, 1, 0, 0, 1, // counts kKind) {} // parameter }; DeoptimizeOperator kDeoptimizeEagerOperator; DeoptimizeOperator kDeoptimizeSoftOperator; template struct IfExceptionOperator final : public Operator1 { IfExceptionOperator() : Operator1( // -- IrOpcode::kIfException, Operator::kKontrol, // opcode "IfException", // name 0, 1, 1, 1, 1, 1, // counts kCaughtLocally) {} // parameter }; IfExceptionOperator kIfExceptionCOperator; IfExceptionOperator kIfExceptionUOperator; template struct EndOperator final : public Operator { EndOperator() : Operator( // -- IrOpcode::kEnd, Operator::kKontrol, // opcode "End", // name 0, 0, kInputCount, 0, 0, 0) {} // counts }; #define CACHED_END(input_count) \ EndOperator kEnd##input_count##Operator; CACHED_END_LIST(CACHED_END) #undef CACHED_END template struct ReturnOperator final : public Operator { ReturnOperator() : Operator( // -- IrOpcode::kReturn, Operator::kNoThrow, // opcode "Return", // name kInputCount, 1, 1, 0, 0, 1) {} // counts }; #define CACHED_RETURN(input_count) \ ReturnOperator kReturn##input_count##Operator; CACHED_RETURN_LIST(CACHED_RETURN) #undef CACHED_RETURN template struct BranchOperator final : public Operator1 { BranchOperator() : Operator1( // -- IrOpcode::kBranch, Operator::kKontrol, // opcode "Branch", // name 1, 0, 1, 0, 0, 2, // counts kBranchHint) {} // parameter }; BranchOperator kBranchNoneOperator; BranchOperator kBranchTrueOperator; BranchOperator kBranchFalseOperator; template struct EffectPhiOperator final : public Operator { EffectPhiOperator() : Operator( // -- IrOpcode::kEffectPhi, Operator::kPure, // opcode "EffectPhi", // name 0, kEffectInputCount, 1, 0, 1, 0) {} // counts }; #define CACHED_EFFECT_PHI(input_count) \ EffectPhiOperator kEffectPhi##input_count##Operator; CACHED_EFFECT_PHI_LIST(CACHED_EFFECT_PHI) #undef CACHED_EFFECT_PHI template struct LoopOperator final : public Operator { LoopOperator() : Operator( // -- IrOpcode::kLoop, Operator::kKontrol, // opcode "Loop", // name 0, 0, kInputCount, 0, 0, 1) {} // counts }; #define CACHED_LOOP(input_count) \ LoopOperator kLoop##input_count##Operator; CACHED_LOOP_LIST(CACHED_LOOP) #undef CACHED_LOOP template struct MergeOperator final : public Operator { MergeOperator() : Operator( // -- IrOpcode::kMerge, Operator::kKontrol, // opcode "Merge", // name 0, 0, kInputCount, 0, 0, 1) {} // counts }; #define CACHED_MERGE(input_count) \ MergeOperator kMerge##input_count##Operator; CACHED_MERGE_LIST(CACHED_MERGE) #undef CACHED_MERGE template struct PhiOperator final : public Operator1 { PhiOperator() : Operator1( //-- IrOpcode::kPhi, Operator::kPure, // opcode "Phi", // name kInputCount, 0, 1, 1, 0, 0, // counts kRep) {} // parameter }; #define CACHED_PHI(rep, input_count) \ PhiOperator \ kPhi##rep##input_count##Operator; CACHED_PHI_LIST(CACHED_PHI) #undef CACHED_PHI template struct ParameterOperator final : public Operator1 { ParameterOperator() : Operator1( // -- IrOpcode::kParameter, Operator::kPure, // opcode "Parameter", // name 1, 0, 0, 1, 0, 0, // counts, ParameterInfo(kIndex, nullptr)) {} // parameter and name }; #define CACHED_PARAMETER(index) \ ParameterOperator kParameter##index##Operator; CACHED_PARAMETER_LIST(CACHED_PARAMETER) #undef CACHED_PARAMETER template struct ProjectionOperator final : public Operator1 { ProjectionOperator() : Operator1( // -- IrOpcode::kProjection, // opcode Operator::kPure, // flags "Projection", // name 1, 0, 0, 1, 0, 0, // counts, kIndex) {} // parameter }; #define CACHED_PROJECTION(index) \ ProjectionOperator kProjection##index##Operator; CACHED_PROJECTION_LIST(CACHED_PROJECTION) #undef CACHED_PROJECTION template struct StateValuesOperator final : public Operator { StateValuesOperator() : Operator( // -- IrOpcode::kStateValues, // opcode Operator::kPure, // flags "StateValues", // name kInputCount, 0, 0, 1, 0, 0) {} // counts }; #define CACHED_STATE_VALUES(input_count) \ StateValuesOperator kStateValues##input_count##Operator; CACHED_STATE_VALUES_LIST(CACHED_STATE_VALUES) #undef CACHED_STATE_VALUES }; static base::LazyInstance::type kCache = LAZY_INSTANCE_INITIALIZER; CommonOperatorBuilder::CommonOperatorBuilder(Zone* zone) : cache_(kCache.Get()), zone_(zone) {} #define CACHED(Name, properties, value_input_count, effect_input_count, \ control_input_count, value_output_count, effect_output_count, \ control_output_count) \ const Operator* CommonOperatorBuilder::Name() { \ return &cache_.k##Name##Operator; \ } CACHED_OP_LIST(CACHED) #undef CACHED const Operator* CommonOperatorBuilder::End(size_t control_input_count) { switch (control_input_count) { #define CACHED_END(input_count) \ case input_count: \ return &cache_.kEnd##input_count##Operator; CACHED_END_LIST(CACHED_END) #undef CACHED_END default: break; } // Uncached. return new (zone()) Operator( //-- IrOpcode::kEnd, Operator::kKontrol, // opcode "End", // name 0, 0, control_input_count, 0, 0, 0); // counts } const Operator* CommonOperatorBuilder::Return(int value_input_count) { switch (value_input_count) { #define CACHED_RETURN(input_count) \ case input_count: \ return &cache_.kReturn##input_count##Operator; CACHED_RETURN_LIST(CACHED_RETURN) #undef CACHED_RETURN default: break; } // Uncached. return new (zone()) Operator( //-- IrOpcode::kReturn, Operator::kNoThrow, // opcode "Return", // name value_input_count, 1, 1, 0, 0, 1); // counts } const Operator* CommonOperatorBuilder::Branch(BranchHint hint) { switch (hint) { case BranchHint::kNone: return &cache_.kBranchNoneOperator; case BranchHint::kTrue: return &cache_.kBranchTrueOperator; case BranchHint::kFalse: return &cache_.kBranchFalseOperator; } UNREACHABLE(); return nullptr; } const Operator* CommonOperatorBuilder::Deoptimize(DeoptimizeKind kind) { switch (kind) { case DeoptimizeKind::kEager: return &cache_.kDeoptimizeEagerOperator; case DeoptimizeKind::kSoft: return &cache_.kDeoptimizeSoftOperator; } UNREACHABLE(); return nullptr; } const Operator* CommonOperatorBuilder::IfException(IfExceptionHint hint) { switch (hint) { case IfExceptionHint::kLocallyCaught: return &cache_.kIfExceptionCOperator; case IfExceptionHint::kLocallyUncaught: return &cache_.kIfExceptionUOperator; } UNREACHABLE(); return nullptr; } const Operator* CommonOperatorBuilder::Switch(size_t control_output_count) { return new (zone()) Operator( // -- IrOpcode::kSwitch, Operator::kKontrol, // opcode "Switch", // name 1, 0, 1, 0, 0, control_output_count); // counts } const Operator* CommonOperatorBuilder::IfValue(int32_t index) { return new (zone()) Operator1( // -- IrOpcode::kIfValue, Operator::kKontrol, // opcode "IfValue", // name 0, 0, 1, 0, 0, 1, // counts index); // parameter } const Operator* CommonOperatorBuilder::Start(int value_output_count) { return new (zone()) Operator( // -- IrOpcode::kStart, Operator::kFoldable, // opcode "Start", // name 0, 0, 0, value_output_count, 1, 1); // counts } const Operator* CommonOperatorBuilder::Loop(int control_input_count) { switch (control_input_count) { #define CACHED_LOOP(input_count) \ case input_count: \ return &cache_.kLoop##input_count##Operator; CACHED_LOOP_LIST(CACHED_LOOP) #undef CACHED_LOOP default: break; } // Uncached. return new (zone()) Operator( // -- IrOpcode::kLoop, Operator::kKontrol, // opcode "Loop", // name 0, 0, control_input_count, 0, 0, 1); // counts } const Operator* CommonOperatorBuilder::Merge(int control_input_count) { switch (control_input_count) { #define CACHED_MERGE(input_count) \ case input_count: \ return &cache_.kMerge##input_count##Operator; CACHED_MERGE_LIST(CACHED_MERGE) #undef CACHED_MERGE default: break; } // Uncached. return new (zone()) Operator( // -- IrOpcode::kMerge, Operator::kKontrol, // opcode "Merge", // name 0, 0, control_input_count, 0, 0, 1); // counts } const Operator* CommonOperatorBuilder::Parameter(int index, const char* debug_name) { if (!debug_name) { switch (index) { #define CACHED_PARAMETER(index) \ case index: \ return &cache_.kParameter##index##Operator; CACHED_PARAMETER_LIST(CACHED_PARAMETER) #undef CACHED_PARAMETER default: break; } } // Uncached. return new (zone()) Operator1( // -- IrOpcode::kParameter, Operator::kPure, // opcode "Parameter", // name 1, 0, 0, 1, 0, 0, // counts ParameterInfo(index, debug_name)); // parameter info } const Operator* CommonOperatorBuilder::OsrValue(int index) { return new (zone()) Operator1( // -- IrOpcode::kOsrValue, Operator::kNoProperties, // opcode "OsrValue", // name 0, 0, 1, 1, 0, 0, // counts index); // parameter } const Operator* CommonOperatorBuilder::Int32Constant(int32_t value) { return new (zone()) Operator1( // -- IrOpcode::kInt32Constant, Operator::kPure, // opcode "Int32Constant", // name 0, 0, 0, 1, 0, 0, // counts value); // parameter } const Operator* CommonOperatorBuilder::Int64Constant(int64_t value) { return new (zone()) Operator1( // -- IrOpcode::kInt64Constant, Operator::kPure, // opcode "Int64Constant", // name 0, 0, 0, 1, 0, 0, // counts value); // parameter } const Operator* CommonOperatorBuilder::Float32Constant(volatile float value) { return new (zone()) Operator1( // -- IrOpcode::kFloat32Constant, Operator::kPure, // opcode "Float32Constant", // name 0, 0, 0, 1, 0, 0, // counts value); // parameter } const Operator* CommonOperatorBuilder::Float64Constant(volatile double value) { return new (zone()) Operator1( // -- IrOpcode::kFloat64Constant, Operator::kPure, // opcode "Float64Constant", // name 0, 0, 0, 1, 0, 0, // counts value); // parameter } const Operator* CommonOperatorBuilder::ExternalConstant( const ExternalReference& value) { return new (zone()) Operator1( // -- IrOpcode::kExternalConstant, Operator::kPure, // opcode "ExternalConstant", // name 0, 0, 0, 1, 0, 0, // counts value); // parameter } const Operator* CommonOperatorBuilder::NumberConstant(volatile double value) { return new (zone()) Operator1( // -- IrOpcode::kNumberConstant, Operator::kPure, // opcode "NumberConstant", // name 0, 0, 0, 1, 0, 0, // counts value); // parameter } const Operator* CommonOperatorBuilder::HeapConstant( const Handle& value) { return new (zone()) Operator1>( // -- IrOpcode::kHeapConstant, Operator::kPure, // opcode "HeapConstant", // name 0, 0, 0, 1, 0, 0, // counts value); // parameter } const Operator* CommonOperatorBuilder::Select(MachineRepresentation rep, BranchHint hint) { return new (zone()) Operator1( // -- IrOpcode::kSelect, Operator::kPure, // opcode "Select", // name 3, 0, 0, 1, 0, 0, // counts SelectParameters(rep, hint)); // parameter } const Operator* CommonOperatorBuilder::Phi(MachineRepresentation rep, int value_input_count) { DCHECK(value_input_count > 0); // Disallow empty phis. #define CACHED_PHI(kRep, kValueInputCount) \ if (MachineRepresentation::kRep == rep && \ kValueInputCount == value_input_count) { \ return &cache_.kPhi##kRep##kValueInputCount##Operator; \ } CACHED_PHI_LIST(CACHED_PHI) #undef CACHED_PHI // Uncached. return new (zone()) Operator1( // -- IrOpcode::kPhi, Operator::kPure, // opcode "Phi", // name value_input_count, 0, 1, 1, 0, 0, // counts rep); // parameter } const Operator* CommonOperatorBuilder::EffectPhi(int effect_input_count) { DCHECK(effect_input_count > 0); // Disallow empty effect phis. switch (effect_input_count) { #define CACHED_EFFECT_PHI(input_count) \ case input_count: \ return &cache_.kEffectPhi##input_count##Operator; CACHED_EFFECT_PHI_LIST(CACHED_EFFECT_PHI) #undef CACHED_EFFECT_PHI default: break; } // Uncached. return new (zone()) Operator( // -- IrOpcode::kEffectPhi, Operator::kPure, // opcode "EffectPhi", // name 0, effect_input_count, 1, 0, 1, 0); // counts } const Operator* CommonOperatorBuilder::Guard(Type* type) { return new (zone()) Operator1( // -- IrOpcode::kGuard, Operator::kKontrol, // opcode "Guard", // name 1, 0, 1, 1, 0, 0, // counts type); // parameter } const Operator* CommonOperatorBuilder::EffectSet(int arguments) { DCHECK(arguments > 1); // Disallow empty/singleton sets. return new (zone()) Operator( // -- IrOpcode::kEffectSet, Operator::kPure, // opcode "EffectSet", // name 0, arguments, 0, 0, 1, 0); // counts } const Operator* CommonOperatorBuilder::StateValues(int arguments) { switch (arguments) { #define CACHED_STATE_VALUES(arguments) \ case arguments: \ return &cache_.kStateValues##arguments##Operator; CACHED_STATE_VALUES_LIST(CACHED_STATE_VALUES) #undef CACHED_STATE_VALUES default: break; } // Uncached. return new (zone()) Operator( // -- IrOpcode::kStateValues, Operator::kPure, // opcode "StateValues", // name arguments, 0, 0, 1, 0, 0); // counts } const Operator* CommonOperatorBuilder::ObjectState(int pointer_slots, int id) { return new (zone()) Operator1( // -- IrOpcode::kObjectState, Operator::kPure, // opcode "ObjectState", // name pointer_slots, 0, 0, 1, 0, 0, id); // counts } const Operator* CommonOperatorBuilder::TypedStateValues( const ZoneVector* types) { return new (zone()) Operator1*>( // -- IrOpcode::kTypedStateValues, Operator::kPure, // opcode "TypedStateValues", // name static_cast(types->size()), 0, 0, 1, 0, 0, types); // counts } const Operator* CommonOperatorBuilder::FrameState( BailoutId bailout_id, OutputFrameStateCombine state_combine, const FrameStateFunctionInfo* function_info) { FrameStateInfo state_info(bailout_id, state_combine, function_info); return new (zone()) Operator1( // -- IrOpcode::kFrameState, Operator::kPure, // opcode "FrameState", // name 5, 0, 0, 1, 0, 0, // counts state_info); // parameter } const Operator* CommonOperatorBuilder::Call(const CallDescriptor* descriptor) { class CallOperator final : public Operator1 { public: explicit CallOperator(const CallDescriptor* descriptor) : Operator1( IrOpcode::kCall, descriptor->properties(), "Call", descriptor->InputCount() + descriptor->FrameStateCount(), Operator::ZeroIfPure(descriptor->properties()), Operator::ZeroIfEliminatable(descriptor->properties()), descriptor->ReturnCount(), Operator::ZeroIfPure(descriptor->properties()), Operator::ZeroIfNoThrow(descriptor->properties()), descriptor) {} void PrintParameter(std::ostream& os) const override { os << "[" << *parameter() << "]"; } }; return new (zone()) CallOperator(descriptor); } const Operator* CommonOperatorBuilder::LazyBailout() { return Call(Linkage::GetLazyBailoutDescriptor(zone())); } const Operator* CommonOperatorBuilder::TailCall( const CallDescriptor* descriptor) { class TailCallOperator final : public Operator1 { public: explicit TailCallOperator(const CallDescriptor* descriptor) : Operator1( IrOpcode::kTailCall, descriptor->properties(), "TailCall", descriptor->InputCount() + descriptor->FrameStateCount(), 1, 1, 0, 0, 1, descriptor) {} void PrintParameter(std::ostream& os) const override { os << "[" << *parameter() << "]"; } }; return new (zone()) TailCallOperator(descriptor); } const Operator* CommonOperatorBuilder::Projection(size_t index) { switch (index) { #define CACHED_PROJECTION(index) \ case index: \ return &cache_.kProjection##index##Operator; CACHED_PROJECTION_LIST(CACHED_PROJECTION) #undef CACHED_PROJECTION default: break; } // Uncached. return new (zone()) Operator1( // -- IrOpcode::kProjection, // opcode Operator::kFoldable | Operator::kNoThrow, // flags "Projection", // name 1, 0, 0, 1, 0, 0, // counts index); // parameter } const Operator* CommonOperatorBuilder::ResizeMergeOrPhi(const Operator* op, int size) { if (op->opcode() == IrOpcode::kPhi) { return Phi(PhiRepresentationOf(op), size); } else if (op->opcode() == IrOpcode::kEffectPhi) { return EffectPhi(size); } else if (op->opcode() == IrOpcode::kMerge) { return Merge(size); } else if (op->opcode() == IrOpcode::kLoop) { return Loop(size); } else { UNREACHABLE(); return nullptr; } } const FrameStateFunctionInfo* CommonOperatorBuilder::CreateFrameStateFunctionInfo( FrameStateType type, int parameter_count, int local_count, Handle shared_info, ContextCallingMode context_calling_mode) { return new (zone()->New(sizeof(FrameStateFunctionInfo))) FrameStateFunctionInfo(type, parameter_count, local_count, shared_info, context_calling_mode); } } // namespace compiler } // namespace internal } // namespace v8