Chromium Code Reviews| Index: runtime/vm/object.h |
| diff --git a/runtime/vm/object.h b/runtime/vm/object.h |
| index d7a5cd06b1db26d0075382f1434902251a8e3b5b..39a57ba80d8ff26963d8dbc03075a943054417e9 100644 |
| --- a/runtime/vm/object.h |
| +++ b/runtime/vm/object.h |
| @@ -1706,2156 +1706,2159 @@ class PatchClass : public Object { |
| }; |
| -class Function : public Object { |
| +// Object holding information about an IC: test classes and their |
|
Florian Schneider
2015/06/01 07:50:16
Is there any diff here or did you just move class
srdjan
2015/06/01 15:23:40
Done.
No diffs, ICData moved ahead of class Functi
|
| +// corresponding targets. |
| +class ICData : public Object { |
| public: |
| - RawString* name() const { return raw_ptr()->name_; } |
| - RawString* PrettyName() const; |
| - RawString* UserVisibleName() const; |
| - RawString* QualifiedPrettyName() const; |
| - RawString* QualifiedUserVisibleName() const; |
| - virtual RawString* DictionaryName() const { return name(); } |
| - |
| - RawString* GetSource() const; |
| - |
| - // Build a string of the form 'C<T, R>(T, {b: B, c: C}) => R' representing the |
| - // internal signature of the given function. In this example, T and R are |
| - // type parameters of class C, the owner of the function. |
| - RawString* Signature() const { |
| - const bool instantiate = false; |
| - return BuildSignature(instantiate, kInternalName, TypeArguments::Handle()); |
| + RawFunction* owner() const { |
| + return raw_ptr()->owner_; |
| } |
| - RawString* PrettySignature() const { |
| - const bool instantiate = false; |
| - return BuildSignature( |
| - instantiate, kPrettyName, TypeArguments::Handle()); |
| + RawString* target_name() const { |
| + return raw_ptr()->target_name_; |
| } |
| - // Build a string of the form '(T, {b: B, c: C}) => R' representing the |
| - // user visible signature of the given function. In this example, T and R are |
| - // type parameters of class C, the owner of the function. |
| - // Implicit parameters are hidden, as well as the prefix denoting the |
| - // signature class and its type parameters. |
| - RawString* UserVisibleSignature() const { |
| - const bool instantiate = false; |
| - return BuildSignature( |
| - instantiate, kUserVisibleName, TypeArguments::Handle()); |
| + RawArray* arguments_descriptor() const { |
| + return raw_ptr()->args_descriptor_; |
| } |
| - // Build a string of the form '(A, {b: B, c: C}) => D' representing the |
| - // signature of the given function, where all generic types (e.g. '<T, R>' in |
| - // 'C<T, R>(T, {b: B, c: C}) => R') are instantiated using the given |
| - // instantiator type argument vector of a C instance (e.g. '<A, D>'). |
| - RawString* InstantiatedSignatureFrom(const TypeArguments& instantiator, |
| - NameVisibility name_visibility) const { |
| - const bool instantiate = true; |
| - return BuildSignature(instantiate, name_visibility, instantiator); |
| - } |
| + intptr_t NumArgsTested() const; |
| - // Returns true if the signature of this function is instantiated, i.e. if it |
| - // does not involve generic parameter types or generic result type. |
| - bool HasInstantiatedSignature() const; |
| + intptr_t deopt_id() const { |
| + return raw_ptr()->deopt_id_; |
| + } |
| - // Build a string of the form 'T, {b: B, c: C} representing the user |
| - // visible formal parameters of the function. |
| - RawString* UserVisibleFormalParameters() const; |
| + // Note: only deopts with reasons before Unknown in this list are recorded in |
| + // the ICData. All other reasons are used purely for informational messages |
| + // printed during deoptimization itself. |
| + #define DEOPT_REASONS(V) \ |
| + V(BinarySmiOp) \ |
| + V(BinaryMintOp) \ |
| + V(DoubleToSmi) \ |
| + V(CheckSmi) \ |
| + V(Unknown) \ |
| + V(PolymorphicInstanceCallTestFail) \ |
| + V(UnaryMintOp) \ |
| + V(BinaryDoubleOp) \ |
| + V(UnaryOp) \ |
| + V(UnboxInteger) \ |
| + V(CheckClass) \ |
| + V(CheckArrayBound) \ |
| + V(AtCall) \ |
| + V(Uint32Load) \ |
| + V(GuardField) \ |
| + V(TestCids) \ |
| + V(NumReasons) \ |
| - RawClass* Owner() const; |
| - RawClass* origin() const; |
| - RawScript* script() const; |
| + enum DeoptReasonId { |
| + #define DEFINE_ENUM_LIST(name) kDeopt##name, |
| + DEOPT_REASONS(DEFINE_ENUM_LIST) |
| + #undef DEFINE_ENUM_LIST |
| + }; |
| - void set_regexp(const JSRegExp& value) const; |
| - RawJSRegExp* regexp() const; |
| + static const intptr_t kLastRecordedDeoptReason = kDeoptUnknown - 1; |
| - // Get and set the class id this function is specialized for. Only set for |
| - // irregexp functions. |
| - intptr_t regexp_cid() const { return raw_ptr()->regexp_cid_; } |
| - void set_regexp_cid(intptr_t regexp_cid) const; |
| + enum DeoptFlags { |
| + // Deoptimization is caused by an optimistically hoisted instruction. |
| + kHoisted = 1 << 0, |
| - RawAbstractType* result_type() const { return raw_ptr()->result_type_; } |
| - void set_result_type(const AbstractType& value) const; |
| + // Deoptimization is caused by an optimistically generalized bounds check. |
| + kGeneralized = 1 << 1 |
| + }; |
| - RawAbstractType* ParameterTypeAt(intptr_t index) const; |
| - void SetParameterTypeAt(intptr_t index, const AbstractType& value) const; |
| - RawArray* parameter_types() const { return raw_ptr()->parameter_types_; } |
| - void set_parameter_types(const Array& value) const; |
| + bool HasDeoptReasons() const { return DeoptReasons() != 0; } |
| + uint32_t DeoptReasons() const; |
| + void SetDeoptReasons(uint32_t reasons) const; |
| - // Parameter names are valid for all valid parameter indices, and are not |
| - // limited to named optional parameters. |
| - RawString* ParameterNameAt(intptr_t index) const; |
| - void SetParameterNameAt(intptr_t index, const String& value) const; |
| - RawArray* parameter_names() const { return raw_ptr()->parameter_names_; } |
| - void set_parameter_names(const Array& value) const; |
| + bool HasDeoptReason(ICData::DeoptReasonId reason) const; |
| + void AddDeoptReason(ICData::DeoptReasonId reason) const; |
| - // Sets function's code and code's function. |
| - void AttachCode(const Code& value) const; |
| - void SetInstructions(const Code& value) const; |
| - void ClearCode() const; |
| + bool IssuedJSWarning() const; |
| + void SetIssuedJSWarning() const; |
| - // Disables optimized code and switches to unoptimized code. |
| - void SwitchToUnoptimizedCode() const; |
| + // Return true if the target function of this IC data may check for (and |
| + // possibly issue) a Javascript compatibility warning. |
| + bool MayCheckForJSWarning() const; |
| - // Return the most recently compiled and installed code for this function. |
| - // It is not the only Code object that points to this function. |
| - RawCode* CurrentCode() const { |
| - return raw_ptr()->instructions_->ptr()->code_; |
| - } |
| + intptr_t NumberOfChecks() const; |
| - RawCode* unoptimized_code() const { return raw_ptr()->unoptimized_code_; } |
| - void set_unoptimized_code(const Code& value) const; |
| - bool HasCode() const; |
| + // Discounts any checks with usage of zero. |
| + intptr_t NumberOfUsedChecks() const; |
| - static intptr_t instructions_offset() { |
| - return OFFSET_OF(RawFunction, instructions_); |
| + static intptr_t InstanceSize() { |
| + return RoundedAllocationSize(sizeof(RawICData)); |
| } |
| - // Returns true if there is at least one debugger breakpoint |
| - // set in this function. |
| - bool HasBreakpoint() const; |
| - |
| - RawContextScope* context_scope() const; |
| - void set_context_scope(const ContextScope& value) const; |
| - |
| - // Enclosing function of this local function. |
| - RawFunction* parent_function() const; |
| - |
| - // Signature class of this closure function or signature function. |
| - RawClass* signature_class() const; |
| - void set_signature_class(const Class& value) const; |
| + static intptr_t target_name_offset() { |
| + return OFFSET_OF(RawICData, target_name_); |
| + } |
| - void set_extracted_method_closure(const Function& function) const; |
| - RawFunction* extracted_method_closure() const; |
| + static intptr_t state_bits_offset() { |
| + return OFFSET_OF(RawICData, state_bits_); |
| + } |
| - void set_saved_args_desc(const Array& array) const; |
| - RawArray* saved_args_desc() const; |
| + static intptr_t NumArgsTestedShift() { |
| + return kNumArgsTestedPos; |
| + } |
| - bool IsMethodExtractor() const { |
| - return kind() == RawFunction::kMethodExtractor; |
| + static intptr_t NumArgsTestedMask() { |
| + return ((1 << kNumArgsTestedSize) - 1) << kNumArgsTestedPos; |
| } |
| - bool IsNoSuchMethodDispatcher() const { |
| - return kind() == RawFunction::kNoSuchMethodDispatcher; |
| + static intptr_t arguments_descriptor_offset() { |
| + return OFFSET_OF(RawICData, args_descriptor_); |
| } |
| - bool IsInvokeFieldDispatcher() const { |
| - return kind() == RawFunction::kInvokeFieldDispatcher; |
| + static intptr_t ic_data_offset() { |
| + return OFFSET_OF(RawICData, ic_data_); |
| } |
| - // Returns true iff an implicit closure function has been created |
| - // for this function. |
| - bool HasImplicitClosureFunction() const { |
| - return implicit_closure_function() != null(); |
| + static intptr_t owner_offset() { |
| + return OFFSET_OF(RawICData, owner_); |
| } |
| - // Return the closure function implicitly created for this function. |
| - // If none exists yet, create one and remember it. |
| - RawFunction* ImplicitClosureFunction() const; |
| + // Used for unoptimized static calls when no class-ids are checked. |
| + void AddTarget(const Function& target) const; |
| - // Return the closure implicitly created for this function. |
| - // If none exists yet, create one and remember it. |
| - RawInstance* ImplicitStaticClosure() const; |
| + // Adding checks. |
| - // Redirection information for a redirecting factory. |
| - bool IsRedirectingFactory() const; |
| - RawType* RedirectionType() const; |
| - void SetRedirectionType(const Type& type) const; |
| - RawString* RedirectionIdentifier() const; |
| - void SetRedirectionIdentifier(const String& identifier) const; |
| - RawFunction* RedirectionTarget() const; |
| - void SetRedirectionTarget(const Function& target) const; |
| + // Adds one more class test to ICData. Length of 'classes' must be equal to |
| + // the number of arguments tested. Use only for num_args_tested > 1. |
| + void AddCheck(const GrowableArray<intptr_t>& class_ids, |
| + const Function& target) const; |
| + // Adds sorted so that Smi is the first class-id. Use only for |
| + // num_args_tested == 1. |
| + void AddReceiverCheck(intptr_t receiver_class_id, |
| + const Function& target, |
| + intptr_t count = 1) const; |
| - RawFunction::Kind kind() const { |
| - return KindBits::decode(raw_ptr()->kind_tag_); |
| - } |
| + // Retrieving checks. |
| - RawFunction::AsyncModifier modifier() const { |
| - return ModifierBits::decode(raw_ptr()->kind_tag_); |
| - } |
| + // TODO(srdjan): GetCheckAt without target. |
| + void GetCheckAt(intptr_t index, |
| + GrowableArray<intptr_t>* class_ids, |
| + Function* target) const; |
| + // Only for 'num_args_checked == 1'. |
| + void GetOneClassCheckAt(intptr_t index, |
| + intptr_t* class_id, |
| + Function* target) const; |
| + // Only for 'num_args_checked == 1'. |
| + intptr_t GetCidAt(intptr_t index) const; |
| - static const char* KindToCString(RawFunction::Kind kind); |
| + intptr_t GetReceiverClassIdAt(intptr_t index) const; |
| + intptr_t GetClassIdAt(intptr_t index, intptr_t arg_nr) const; |
| - bool IsGenerativeConstructor() const { |
| - return (kind() == RawFunction::kConstructor) && !is_static(); |
| - } |
| - bool IsImplicitConstructor() const; |
| - bool IsFactory() const { |
| - return (kind() == RawFunction::kConstructor) && is_static(); |
| + RawFunction* GetTargetAt(intptr_t index) const; |
| + RawFunction* GetTargetForReceiverClassId(intptr_t class_id) const; |
| + |
| + void IncrementCountAt(intptr_t index, intptr_t value) const; |
| + void SetCountAt(intptr_t index, intptr_t value) const; |
| + intptr_t GetCountAt(intptr_t index) const; |
| + intptr_t AggregateCount() const; |
| + |
| + // Returns this->raw() if num_args_tested == 1 and arg_nr == 1, otherwise |
| + // returns a new ICData object containing only unique arg_nr checks. |
| + // Returns only used entries. |
| + RawICData* AsUnaryClassChecksForArgNr(intptr_t arg_nr) const; |
| + RawICData* AsUnaryClassChecks() const { |
| + return AsUnaryClassChecksForArgNr(0); |
| } |
| - bool IsDynamicFunction() const { |
| - if (is_static() || is_abstract()) { |
| - return false; |
| - } |
| - switch (kind()) { |
| - case RawFunction::kRegularFunction: |
| - case RawFunction::kGetterFunction: |
| - case RawFunction::kSetterFunction: |
| - case RawFunction::kImplicitGetter: |
| - case RawFunction::kImplicitSetter: |
| - case RawFunction::kMethodExtractor: |
| - case RawFunction::kNoSuchMethodDispatcher: |
| - case RawFunction::kInvokeFieldDispatcher: |
| - return true; |
| - case RawFunction::kClosureFunction: |
| - case RawFunction::kConstructor: |
| - case RawFunction::kImplicitStaticFinalGetter: |
| - case RawFunction::kIrregexpFunction: |
| - return false; |
| - default: |
| - UNREACHABLE(); |
| - return false; |
| - } |
| - } |
| - bool IsStaticFunction() const { |
| - if (!is_static()) { |
| - return false; |
| - } |
| - switch (kind()) { |
| - case RawFunction::kRegularFunction: |
| - case RawFunction::kGetterFunction: |
| - case RawFunction::kSetterFunction: |
| - case RawFunction::kImplicitGetter: |
| - case RawFunction::kImplicitSetter: |
| - case RawFunction::kImplicitStaticFinalGetter: |
| - case RawFunction::kIrregexpFunction: |
| - return true; |
| - case RawFunction::kClosureFunction: |
| - case RawFunction::kConstructor: |
| - return false; |
| - default: |
| - UNREACHABLE(); |
| - return false; |
| - } |
| - } |
| - bool IsInFactoryScope() const; |
| + RawICData* AsUnaryClassChecksForCid( |
| + intptr_t cid, const Function& target) const; |
| - intptr_t token_pos() const { return raw_ptr()->token_pos_; } |
| - void set_token_pos(intptr_t value) const; |
| + // Consider only used entries. |
| + bool AllTargetsHaveSameOwner(intptr_t owner_cid) const; |
| + bool AllReceiversAreNumbers() const; |
| + bool HasOneTarget() const; |
| + bool HasReceiverClassId(intptr_t class_id) const; |
| - intptr_t end_token_pos() const { return raw_ptr()->end_token_pos_; } |
| - void set_end_token_pos(intptr_t value) const { |
| - StoreNonPointer(&raw_ptr()->end_token_pos_, value); |
| - } |
| + static RawICData* New(const Function& owner, |
| + const String& target_name, |
| + const Array& arguments_descriptor, |
| + intptr_t deopt_id, |
| + intptr_t num_args_tested); |
| + static RawICData* NewFrom(const ICData& from, intptr_t num_args_tested); |
| - intptr_t num_fixed_parameters() const { |
| - return raw_ptr()->num_fixed_parameters_; |
| - } |
| - void set_num_fixed_parameters(intptr_t value) const; |
| + static intptr_t TestEntryLengthFor(intptr_t num_args); |
| - bool HasOptionalParameters() const { |
| - return raw_ptr()->num_optional_parameters_ != 0; |
| - } |
| - bool HasOptionalPositionalParameters() const { |
| - return raw_ptr()->num_optional_parameters_ > 0; |
| - } |
| - bool HasOptionalNamedParameters() const { |
| - return raw_ptr()->num_optional_parameters_ < 0; |
| - } |
| - intptr_t NumOptionalParameters() const { |
| - const intptr_t num_opt_params = raw_ptr()->num_optional_parameters_; |
| - return (num_opt_params >= 0) ? num_opt_params : -num_opt_params; |
| + static intptr_t TargetIndexFor(intptr_t num_args) { |
| + return num_args; |
| } |
| - void SetNumOptionalParameters(intptr_t num_optional_parameters, |
| - bool are_optional_positional) const; |
| - intptr_t NumOptionalPositionalParameters() const { |
| - const intptr_t num_opt_params = raw_ptr()->num_optional_parameters_; |
| - return (num_opt_params > 0) ? num_opt_params : 0; |
| - } |
| - intptr_t NumOptionalNamedParameters() const { |
| - const intptr_t num_opt_params = raw_ptr()->num_optional_parameters_; |
| - return (num_opt_params < 0) ? -num_opt_params : 0; |
| + static intptr_t CountIndexFor(intptr_t num_args) { |
| + return (num_args + 1); |
| } |
| - intptr_t NumParameters() const; |
| + bool IsUsedAt(intptr_t i) const; |
| - intptr_t NumImplicitParameters() const; |
| + void GetUsedCidsForTwoArgs(GrowableArray<intptr_t>* first, |
| + GrowableArray<intptr_t>* second) const; |
| - static intptr_t usage_counter_offset() { |
| - return OFFSET_OF(RawFunction, usage_counter_); |
| - } |
| - intptr_t usage_counter() const { |
| - return raw_ptr()->usage_counter_; |
| - } |
| - void set_usage_counter(intptr_t value) const { |
| - StoreNonPointer(&raw_ptr()->usage_counter_, value); |
| - } |
| + // Range feedback tracking functionality. |
| - int16_t deoptimization_counter() const { |
| - return raw_ptr()->deoptimization_counter_; |
| - } |
| - void set_deoptimization_counter(int16_t value) const { |
| - StoreNonPointer(&raw_ptr()->deoptimization_counter_, value); |
| - } |
| + // For arithmetic operations we store range information for inputs and the |
| + // result. The goal is to discover: |
| + // |
| + // - on 32-bit platforms: |
| + // - when Mint operation is actually a int32/uint32 operation; |
| + // - when Smi operation produces non-smi results; |
| + // |
| + // - on 64-bit platforms: |
| + // - when Smi operation is actually int32/uint32 operation; |
| + // - when Mint operation produces non-smi results; |
| + // |
| + enum RangeFeedback { |
| + kSmiRange, |
| + kInt32Range, |
| + kUint32Range, |
| + kInt64Range |
| + }; |
| - static const intptr_t kMaxInstructionCount = (1 << 16) - 1; |
| - intptr_t optimized_instruction_count() const { |
| - return raw_ptr()->optimized_instruction_count_; |
| - } |
| - void set_optimized_instruction_count(intptr_t value) const { |
| - ASSERT(value >= 0); |
| - if (value > kMaxInstructionCount) { |
| - value = kMaxInstructionCount; |
| - } |
| - StoreNonPointer(&raw_ptr()->optimized_instruction_count_, |
| - static_cast<uint16_t>(value)); |
| + // We use 4 bits per operand/result feedback. Our lattice allows us to |
| + // express the following states: |
| + // |
| + // - usmi 0000 [used only on 32bit platforms] |
| + // - smi 0001 |
| + // - uint31 0010 |
| + // - int32 0011 |
| + // - uint32 0100 |
| + // - int33 x1x1 |
| + // - int64 1xxx |
| + // |
| + // DecodeRangeFeedbackAt() helper maps these states into the RangeFeedback |
| + // enumeration. |
| + enum RangeFeedbackLatticeBits { |
| + kSignedRangeBit = 1 << 0, |
| + kInt32RangeBit = 1 << 1, |
| + kUint32RangeBit = 1 << 2, |
| + kInt64RangeBit = 1 << 3, |
| + kBitsPerRangeFeedback = 4, |
| + kRangeFeedbackMask = (1 << kBitsPerRangeFeedback) - 1, |
| + kRangeFeedbackSlots = 3 |
| + }; |
| + |
| + static bool IsValidRangeFeedbackIndex(intptr_t index) { |
| + return (0 <= index) && (index < kRangeFeedbackSlots); |
| } |
| - intptr_t optimized_call_site_count() const { |
| - return raw_ptr()->optimized_call_site_count_; |
| + static intptr_t RangeFeedbackShift(intptr_t index) { |
| + return (index * kBitsPerRangeFeedback) + kRangeFeedbackPos; |
| } |
| - void set_optimized_call_site_count(intptr_t value) const { |
| - ASSERT(value >= 0); |
| - if (value > kMaxInstructionCount) { |
| - value = kMaxInstructionCount; |
| + |
| + static const char* RangeFeedbackToString(RangeFeedback feedback) { |
| + switch (feedback) { |
| + case kSmiRange: |
| + return "smi"; |
| + case kInt32Range: |
| + return "int32"; |
| + case kUint32Range: |
| + return "uint32"; |
| + case kInt64Range: |
| + return "int64"; |
| + default: |
| + UNREACHABLE(); |
| + return "?"; |
| } |
| - StoreNonPointer(&raw_ptr()->optimized_call_site_count_, |
| - static_cast<uint16_t>(value)); |
| } |
| - bool IsOptimizable() const; |
| - bool IsNativeAutoSetupScope() const; |
| - void SetIsOptimizable(bool value) const; |
| - void SetIsNativeAutoSetupScope(bool value) const; |
| + // It is only meaningful to interptret range feedback stored in the ICData |
| + // when all checks are Mint or Smi. |
| + bool HasRangeFeedback() const; |
| + RangeFeedback DecodeRangeFeedbackAt(intptr_t idx) const; |
| - bool CanBeInlined() const; |
| + void PrintToJSONArray(const JSONArray& jsarray, |
| + intptr_t token_pos, |
| + bool is_static_call) const; |
| - MethodRecognizer::Kind recognized_kind() const { |
| - return RecognizedBits::decode(raw_ptr()->kind_tag_); |
| + private: |
| + RawArray* ic_data() const { |
| + return raw_ptr()->ic_data_; |
| } |
| - void set_recognized_kind(MethodRecognizer::Kind value) const; |
| - bool IsRecognized() const { |
| - return recognized_kind() != MethodRecognizer::kUnknown; |
| - } |
| + void set_owner(const Function& value) const; |
| + void set_target_name(const String& value) const; |
| + void set_arguments_descriptor(const Array& value) const; |
| + void set_deopt_id(intptr_t value) const; |
| + void SetNumArgsTested(intptr_t value) const; |
| + void set_ic_data(const Array& value) const; |
| + void set_state_bits(uint32_t bits) const; |
| - bool HasOptimizedCode() const; |
| + enum { |
| + kNumArgsTestedPos = 0, |
| + kNumArgsTestedSize = 2, |
| + kDeoptReasonPos = kNumArgsTestedPos + kNumArgsTestedSize, |
| + kDeoptReasonSize = kLastRecordedDeoptReason + 1, |
| + kIssuedJSWarningBit = kDeoptReasonPos + kDeoptReasonSize, |
| + kRangeFeedbackPos = kIssuedJSWarningBit + 1, |
| + kRangeFeedbackSize = kBitsPerRangeFeedback * kRangeFeedbackSlots |
| + }; |
| - // Returns true if the argument counts are valid for calling this function. |
| - // Otherwise, it returns false and the reason (if error_message is not NULL). |
| - bool AreValidArgumentCounts(intptr_t num_arguments, |
| - intptr_t num_named_arguments, |
| - String* error_message) const; |
| + class NumArgsTestedBits : public BitField<uint32_t, |
| + kNumArgsTestedPos, kNumArgsTestedSize> {}; // NOLINT |
| + class DeoptReasonBits : public BitField<uint32_t, |
| + ICData::kDeoptReasonPos, ICData::kDeoptReasonSize> {}; // NOLINT |
| + class IssuedJSWarningBit : public BitField<bool, kIssuedJSWarningBit, 1> {}; |
| + class RangeFeedbackBits : public BitField<uint32_t, |
| + ICData::kRangeFeedbackPos, ICData::kRangeFeedbackSize> {}; // NOLINT |
| - // Returns true if the total argument count and the names of optional |
| - // arguments are valid for calling this function. |
| - // Otherwise, it returns false and the reason (if error_message is not NULL). |
| - bool AreValidArguments(intptr_t num_arguments, |
| - const Array& argument_names, |
| - String* error_message) const; |
| - bool AreValidArguments(const ArgumentsDescriptor& args_desc, |
| - String* error_message) const; |
| +#if defined(DEBUG) |
| + // Used in asserts to verify that a check is not added twice. |
| + bool HasCheck(const GrowableArray<intptr_t>& cids) const; |
| +#endif // DEBUG |
| - // Fully qualified name uniquely identifying the function under gdb and during |
| - // ast printing. The special ':' character, if present, is replaced by '_'. |
| - const char* ToFullyQualifiedCString() const; |
| + intptr_t TestEntryLength() const; |
| + void WriteSentinel(const Array& data) const; |
| - const char* ToLibNamePrefixedQualifiedCString() const; |
| - |
| - const char* ToQualifiedCString() const; |
| - |
| - // Returns true if this function has parameters that are compatible with the |
| - // parameters of the other function in order for this function to override the |
| - // other function. |
| - bool HasCompatibleParametersWith(const Function& other, |
| - Error* bound_error) const; |
| - |
| - // Returns true if the type of this function is a subtype of the type of |
| - // the other function. |
| - bool IsSubtypeOf(const TypeArguments& type_arguments, |
| - const Function& other, |
| - const TypeArguments& other_type_arguments, |
| - Error* bound_error) const { |
| - return TypeTest(kIsSubtypeOf, |
| - type_arguments, |
| - other, |
| - other_type_arguments, |
| - bound_error); |
| - } |
| - |
| - // Returns true if the type of this function is more specific than the type of |
| - // the other function. |
| - bool IsMoreSpecificThan(const TypeArguments& type_arguments, |
| - const Function& other, |
| - const TypeArguments& other_type_arguments, |
| - Error* bound_error) const { |
| - return TypeTest(kIsMoreSpecificThan, |
| - type_arguments, |
| - other, |
| - other_type_arguments, |
| - bound_error); |
| - } |
| - |
| - // Returns true if this function represents an explicit getter function. |
| - bool IsGetterFunction() const { |
| - return kind() == RawFunction::kGetterFunction; |
| - } |
| - |
| - // Returns true if this function represents an implicit getter function. |
| - bool IsImplicitGetterFunction() const { |
| - return kind() == RawFunction::kImplicitGetter; |
| - } |
| - |
| - // Returns true if this function represents an explicit setter function. |
| - bool IsSetterFunction() const { |
| - return kind() == RawFunction::kSetterFunction; |
| - } |
| - |
| - // Returns true if this function represents an implicit setter function. |
| - bool IsImplicitSetterFunction() const { |
| - return kind() == RawFunction::kImplicitSetter; |
| - } |
| - |
| - // Returns true if this function represents a (possibly implicit) closure |
| - // function. |
| - bool IsClosureFunction() const { |
| - return kind() == RawFunction::kClosureFunction; |
| - } |
| - |
| - // Returns true if this function represents a generated irregexp function. |
| - bool IsIrregexpFunction() const { |
| - return kind() == RawFunction::kIrregexpFunction; |
| - } |
| - |
| - // Returns true if this function represents an implicit closure function. |
| - bool IsImplicitClosureFunction() const; |
| - |
| - // Returns true if this function represents a non implicit closure function. |
| - bool IsNonImplicitClosureFunction() const { |
| - return IsClosureFunction() && !IsImplicitClosureFunction(); |
| - } |
| - |
| - // Returns true if this function represents an implicit static closure |
| - // function. |
| - bool IsImplicitStaticClosureFunction() const { |
| - return is_static() && IsImplicitClosureFunction(); |
| - } |
| - bool static IsImplicitStaticClosureFunction(RawFunction* func); |
| - |
| - // Returns true if this function represents an implicit instance closure |
| - // function. |
| - bool IsImplicitInstanceClosureFunction() const { |
| - return !is_static() && IsImplicitClosureFunction(); |
| - } |
| - |
| - // Returns true if this function represents a local function. |
| - bool IsLocalFunction() const { |
| - return parent_function() != Function::null(); |
| - } |
| - |
| - // Returns true if this function represents a signature function without code. |
| - bool IsSignatureFunction() const { |
| - return kind() == RawFunction::kSignatureFunction; |
| - } |
| - |
| - bool IsAsyncFunction() const { |
| - return modifier() == RawFunction::kAsync; |
| - } |
| - |
| - bool IsAsyncClosure() const { |
| - return is_generated_body() && |
| - Function::Handle(parent_function()).IsAsyncFunction(); |
| - } |
| - |
| - bool IsGenerator() const { |
| - return (modifier() & RawFunction::kGeneratorBit) != 0; |
| - } |
| + FINAL_HEAP_OBJECT_IMPLEMENTATION(ICData, Object); |
| + friend class Class; |
| +}; |
| - bool IsSyncGenerator() const { |
| - return modifier() == RawFunction::kSyncGen; |
| - } |
| - bool IsSyncGenClosure() const { |
| - return is_generated_body() && |
| - Function::Handle(parent_function()).IsSyncGenerator(); |
| - } |
| - |
| - bool IsGeneratorClosure() const { |
| - return is_generated_body() && |
| - Function::Handle(parent_function()).IsGenerator(); |
| - } |
| +class Function : public Object { |
| + public: |
| + RawString* name() const { return raw_ptr()->name_; } |
| + RawString* PrettyName() const; |
| + RawString* UserVisibleName() const; |
| + RawString* QualifiedPrettyName() const; |
| + RawString* QualifiedUserVisibleName() const; |
| + virtual RawString* DictionaryName() const { return name(); } |
| - bool IsAsyncGenerator() const { |
| - return modifier() == RawFunction::kAsyncGen; |
| - } |
| + RawString* GetSource() const; |
| - bool IsAsyncGenClosure() const { |
| - return is_generated_body() && |
| - Function::Handle(parent_function()).IsAsyncGenerator(); |
| + // Build a string of the form 'C<T, R>(T, {b: B, c: C}) => R' representing the |
| + // internal signature of the given function. In this example, T and R are |
| + // type parameters of class C, the owner of the function. |
| + RawString* Signature() const { |
| + const bool instantiate = false; |
| + return BuildSignature(instantiate, kInternalName, TypeArguments::Handle()); |
| } |
| - bool IsAsyncOrGenerator() const { |
| - return modifier() != RawFunction::kNoModifier; |
| + RawString* PrettySignature() const { |
| + const bool instantiate = false; |
| + return BuildSignature( |
| + instantiate, kPrettyName, TypeArguments::Handle()); |
| } |
| - static intptr_t InstanceSize() { |
| - return RoundedAllocationSize(sizeof(RawFunction)); |
| + // Build a string of the form '(T, {b: B, c: C}) => R' representing the |
| + // user visible signature of the given function. In this example, T and R are |
| + // type parameters of class C, the owner of the function. |
| + // Implicit parameters are hidden, as well as the prefix denoting the |
| + // signature class and its type parameters. |
| + RawString* UserVisibleSignature() const { |
| + const bool instantiate = false; |
| + return BuildSignature( |
| + instantiate, kUserVisibleName, TypeArguments::Handle()); |
| } |
| - static RawFunction* New(const String& name, |
| - RawFunction::Kind kind, |
| - bool is_static, |
| - bool is_const, |
| - bool is_abstract, |
| - bool is_external, |
| - bool is_native, |
| - const Object& owner, |
| - intptr_t token_pos); |
| - |
| - // Allocates a new Function object representing a closure function, as well as |
| - // a new associated Class object representing the signature class of the |
| - // function. |
| - // The function and the class share the same given name. |
| - static RawFunction* NewClosureFunction(const String& name, |
| - const Function& parent, |
| - intptr_t token_pos); |
| - |
| - static RawFunction* NewEvalFunction(const Class& owner, |
| - const Script& script, |
| - bool is_static); |
| - |
| - // Allocate new function object, clone values from this function. The |
| - // owner of the clone is new_owner. |
| - RawFunction* Clone(const Class& new_owner) const; |
| - |
| - // Slow function, use in asserts to track changes in important library |
| - // functions. |
| - int32_t SourceFingerprint() const; |
| - |
| - // Return false and report an error if the fingerprint does not match. |
| - bool CheckSourceFingerprint(const char* prefix, int32_t fp) const; |
| - |
| - // Works with map [deopt-id] -> ICData. |
| - void SaveICDataMap( |
| - const ZoneGrowableArray<const ICData*>& deopt_id_to_ic_data) const; |
| - void RestoreICDataMap( |
| - ZoneGrowableArray<const ICData*>* deopt_id_to_ic_data) const; |
| - |
| - RawArray* ic_data_array() const; |
| - void ClearICData() const; |
| - |
| - static const int kCtorPhaseInit = 1 << 0; |
| - static const int kCtorPhaseBody = 1 << 1; |
| - static const int kCtorPhaseAll = (kCtorPhaseInit | kCtorPhaseBody); |
| - |
| - void set_modifier(RawFunction::AsyncModifier value) const; |
| - |
| - // static: Considered during class-side or top-level resolution rather than |
| - // instance-side resolution. |
| - // const: Valid target of a const constructor call. |
| - // abstract: Skipped during instance-side resolution. |
| - // reflectable: Enumerated by mirrors, invocable by mirrors. False for private |
| - // functions of dart: libraries. |
| - // debuggable: Valid location of a breakpoint. Synthetic code is not |
| - // debuggable. |
| - // visible: Frame is included in stack traces. Synthetic code such as |
| - // dispatchers is not visible. Synthetic code that can trigger |
| - // exceptions such as the outer async functions that create Futures |
| - // is visible. |
| - // optimizable: Candidate for going through the optimizing compiler. False for |
| - // some functions known to be execute infrequently and functions |
| - // which have been de-optimized too many times. |
| - // instrinsic: Has a hand-written assembly prologue. |
| - // inlinable: Candidate for inlining. False for functions with features we |
| - // don't support during inlining (e.g., optional parameters), |
| - // functions which are too big, etc. |
| - // native: Bridge to C/C++ code. |
| - // redirecting: Redirecting generative or factory constructor. |
| - // external: Just a declaration that expects to be defined in another patch |
| - // file. |
| - |
| -#define FOR_EACH_FUNCTION_KIND_BIT(V) \ |
| - V(Static, is_static) \ |
| - V(Const, is_const) \ |
| - V(Abstract, is_abstract) \ |
| - V(Reflectable, is_reflectable) \ |
| - V(Visible, is_visible) \ |
| - V(Debuggable, is_debuggable) \ |
| - V(Optimizable, is_optimizable) \ |
| - V(Inlinable, is_inlinable) \ |
| - V(Intrinsic, is_intrinsic) \ |
| - V(Native, is_native) \ |
| - V(Redirecting, is_redirecting) \ |
| - V(External, is_external) \ |
| - V(AllowsHoistingCheckClass, allows_hoisting_check_class) \ |
| - V(AllowsBoundsCheckGeneralization, allows_bounds_check_generalization) \ |
| - V(GeneratedBody, is_generated_body) \ |
| - V(AlwaysInline, always_inline) \ |
| - V(PolymorphicTarget, is_polymorphic_target) \ |
| - |
| -#define DEFINE_ACCESSORS(name, accessor_name) \ |
| - void set_##accessor_name(bool value) const { \ |
| - set_kind_tag(name##Bit::update(value, raw_ptr()->kind_tag_)); \ |
| - } \ |
| - bool accessor_name() const { \ |
| - return name##Bit::decode(raw_ptr()->kind_tag_); \ |
| + // Build a string of the form '(A, {b: B, c: C}) => D' representing the |
| + // signature of the given function, where all generic types (e.g. '<T, R>' in |
| + // 'C<T, R>(T, {b: B, c: C}) => R') are instantiated using the given |
| + // instantiator type argument vector of a C instance (e.g. '<A, D>'). |
| + RawString* InstantiatedSignatureFrom(const TypeArguments& instantiator, |
| + NameVisibility name_visibility) const { |
| + const bool instantiate = true; |
| + return BuildSignature(instantiate, name_visibility, instantiator); |
| } |
| -FOR_EACH_FUNCTION_KIND_BIT(DEFINE_ACCESSORS) |
| -#undef DEFINE_ACCESSORS |
| - private: |
| - void set_ic_data_array(const Array& value) const; |
| - |
| - enum KindTagBits { |
| - kKindTagPos = 0, |
| - kKindTagSize = 4, |
| - kRecognizedTagPos = kKindTagPos + kKindTagSize, |
| - kRecognizedTagSize = 9, |
| - kModifierPos = kRecognizedTagPos + kRecognizedTagSize, |
| - kModifierSize = 2, |
| - kLastModifierBitPos = kModifierPos + (kModifierSize - 1), |
| - // Single bit sized fields start here. |
| -#define DECLARE_BIT(name, _) k##name##Bit, |
| -FOR_EACH_FUNCTION_KIND_BIT(DECLARE_BIT) |
| -#undef DECLARE_BIT |
| - kNumTagBits |
| - }; |
| + // Returns true if the signature of this function is instantiated, i.e. if it |
| + // does not involve generic parameter types or generic result type. |
| + bool HasInstantiatedSignature() const; |
| - COMPILE_ASSERT( |
| - MethodRecognizer::kNumRecognizedMethods < (1 << kRecognizedTagSize)); |
| - COMPILE_ASSERT( |
| - kNumTagBits <= |
| - (kBitsPerByte * sizeof(static_cast<RawFunction*>(0)->kind_tag_))); |
| + // Build a string of the form 'T, {b: B, c: C} representing the user |
| + // visible formal parameters of the function. |
| + RawString* UserVisibleFormalParameters() const; |
| - class KindBits : |
| - public BitField<RawFunction::Kind, kKindTagPos, kKindTagSize> {}; // NOLINT |
| + RawClass* Owner() const; |
| + RawClass* origin() const; |
| + RawScript* script() const; |
| - class RecognizedBits : public BitField<MethodRecognizer::Kind, |
| - kRecognizedTagPos, |
| - kRecognizedTagSize> {}; |
| - class ModifierBits : |
| - public BitField<RawFunction::AsyncModifier, |
| - kModifierPos, |
| - kModifierSize> {}; // NOLINT |
| + void set_regexp(const JSRegExp& value) const; |
| + RawJSRegExp* regexp() const; |
| -#define DEFINE_BIT(name, _) \ |
| - class name##Bit : public BitField<bool, k##name##Bit, 1> {}; |
| -FOR_EACH_FUNCTION_KIND_BIT(DEFINE_BIT) |
| -#undef DEFINE_BIT |
| + // Get and set the class id this function is specialized for. Only set for |
| + // irregexp functions. |
| + intptr_t regexp_cid() const { return raw_ptr()->regexp_cid_; } |
| + void set_regexp_cid(intptr_t regexp_cid) const; |
| - void set_name(const String& value) const; |
| - void set_kind(RawFunction::Kind value) const; |
| - void set_parent_function(const Function& value) const; |
| - void set_owner(const Object& value) const; |
| - RawFunction* implicit_closure_function() const; |
| - void set_implicit_closure_function(const Function& value) const; |
| - RawInstance* implicit_static_closure() const; |
| - void set_implicit_static_closure(const Instance& closure) const; |
| - RawScript* eval_script() const; |
| - void set_eval_script(const Script& value) const; |
| - void set_num_optional_parameters(intptr_t value) const; // Encoded value. |
| - void set_kind_tag(intptr_t value) const; |
| - void set_data(const Object& value) const; |
| + RawAbstractType* result_type() const { return raw_ptr()->result_type_; } |
| + void set_result_type(const AbstractType& value) const; |
| - static RawFunction* New(); |
| + RawAbstractType* ParameterTypeAt(intptr_t index) const; |
| + void SetParameterTypeAt(intptr_t index, const AbstractType& value) const; |
| + RawArray* parameter_types() const { return raw_ptr()->parameter_types_; } |
| + void set_parameter_types(const Array& value) const; |
| - void BuildSignatureParameters(bool instantiate, |
| - NameVisibility name_visibility, |
| - const TypeArguments& instantiator, |
| - const GrowableObjectArray& pieces) const; |
| - RawString* BuildSignature(bool instantiate, |
| - NameVisibility name_visibility, |
| - const TypeArguments& instantiator) const; |
| + // Parameter names are valid for all valid parameter indices, and are not |
| + // limited to named optional parameters. |
| + RawString* ParameterNameAt(intptr_t index) const; |
| + void SetParameterNameAt(intptr_t index, const String& value) const; |
| + RawArray* parameter_names() const { return raw_ptr()->parameter_names_; } |
| + void set_parameter_names(const Array& value) const; |
| - // Check the subtype or 'more specific' relationship. |
| - bool TypeTest(TypeTestKind test_kind, |
| - const TypeArguments& type_arguments, |
| - const Function& other, |
| - const TypeArguments& other_type_arguments, |
| - Error* bound_error) const; |
| + // Sets function's code and code's function. |
| + void AttachCode(const Code& value) const; |
| + void SetInstructions(const Code& value) const; |
| + void ClearCode() const; |
| - // Checks the type of the formal parameter at the given position for |
| - // subtyping or 'more specific' relationship between the type of this function |
| - // and the type of the other function. |
| - bool TestParameterType(TypeTestKind test_kind, |
| - intptr_t parameter_position, |
| - intptr_t other_parameter_position, |
| - const TypeArguments& type_arguments, |
| - const Function& other, |
| - const TypeArguments& other_type_arguments, |
| - Error* bound_error) const; |
| + // Disables optimized code and switches to unoptimized code. |
| + void SwitchToUnoptimizedCode() const; |
| - FINAL_HEAP_OBJECT_IMPLEMENTATION(Function, Object); |
| - friend class Class; |
| - friend class SnapshotWriter; |
| - friend class Parser; // For set_eval_script. |
| - // RawFunction::VisitFunctionPointers accesses the private constructor of |
| - // Function. |
| - friend class RawFunction; |
| -}; |
| + // Return the most recently compiled and installed code for this function. |
| + // It is not the only Code object that points to this function. |
| + RawCode* CurrentCode() const { |
| + return raw_ptr()->instructions_->ptr()->code_; |
| + } |
| + RawCode* unoptimized_code() const { return raw_ptr()->unoptimized_code_; } |
| + void set_unoptimized_code(const Code& value) const; |
| + bool HasCode() const; |
| -class ClosureData: public Object { |
| - public: |
| - static intptr_t InstanceSize() { |
| - return RoundedAllocationSize(sizeof(RawClosureData)); |
| + static intptr_t instructions_offset() { |
| + return OFFSET_OF(RawFunction, instructions_); |
| } |
| - private: |
| - RawContextScope* context_scope() const { return raw_ptr()->context_scope_; } |
| + // Returns true if there is at least one debugger breakpoint |
| + // set in this function. |
| + bool HasBreakpoint() const; |
| + |
| + RawContextScope* context_scope() const; |
| void set_context_scope(const ContextScope& value) const; |
| // Enclosing function of this local function. |
| - RawFunction* parent_function() const { return raw_ptr()->parent_function_; } |
| - void set_parent_function(const Function& value) const; |
| + RawFunction* parent_function() const; |
| // Signature class of this closure function or signature function. |
| - RawClass* signature_class() const { return raw_ptr()->signature_class_; } |
| + RawClass* signature_class() const; |
| void set_signature_class(const Class& value) const; |
| - RawInstance* implicit_static_closure() const { |
| - return raw_ptr()->closure_; |
| - } |
| - void set_implicit_static_closure(const Instance& closure) const; |
| - |
| - static RawClosureData* New(); |
| - |
| - FINAL_HEAP_OBJECT_IMPLEMENTATION(ClosureData, Object); |
| - friend class Class; |
| - friend class Function; |
| - friend class HeapProfiler; |
| -}; |
| + void set_extracted_method_closure(const Function& function) const; |
| + RawFunction* extracted_method_closure() const; |
| + void set_saved_args_desc(const Array& array) const; |
| + RawArray* saved_args_desc() const; |
| -class RedirectionData: public Object { |
| - public: |
| - static intptr_t InstanceSize() { |
| - return RoundedAllocationSize(sizeof(RawRedirectionData)); |
| + bool IsMethodExtractor() const { |
| + return kind() == RawFunction::kMethodExtractor; |
| } |
| - private: |
| - // The type specifies the class and type arguments of the target constructor. |
| - RawType* type() const { return raw_ptr()->type_; } |
| - void set_type(const Type& value) const; |
| - |
| - // The optional identifier specifies a named constructor. |
| - RawString* identifier() const { return raw_ptr()->identifier_; } |
| - void set_identifier(const String& value) const; |
| + bool IsNoSuchMethodDispatcher() const { |
| + return kind() == RawFunction::kNoSuchMethodDispatcher; |
| + } |
| - // The resolved constructor or factory target of the redirection. |
| - RawFunction* target() const { return raw_ptr()->target_; } |
| - void set_target(const Function& value) const; |
| + bool IsInvokeFieldDispatcher() const { |
| + return kind() == RawFunction::kInvokeFieldDispatcher; |
| + } |
| - static RawRedirectionData* New(); |
| + // Returns true iff an implicit closure function has been created |
| + // for this function. |
| + bool HasImplicitClosureFunction() const { |
| + return implicit_closure_function() != null(); |
| + } |
| - FINAL_HEAP_OBJECT_IMPLEMENTATION(RedirectionData, Object); |
| - friend class Class; |
| - friend class Function; |
| - friend class HeapProfiler; |
| -}; |
| + // Return the closure function implicitly created for this function. |
| + // If none exists yet, create one and remember it. |
| + RawFunction* ImplicitClosureFunction() const; |
| + // Return the closure implicitly created for this function. |
| + // If none exists yet, create one and remember it. |
| + RawInstance* ImplicitStaticClosure() const; |
| -class Field : public Object { |
| - public: |
| - RawString* name() const { return raw_ptr()->name_; } |
| - RawString* PrettyName() const; |
| - RawString* UserVisibleName() const; |
| - virtual RawString* DictionaryName() const { return name(); } |
| + // Redirection information for a redirecting factory. |
| + bool IsRedirectingFactory() const; |
| + RawType* RedirectionType() const; |
| + void SetRedirectionType(const Type& type) const; |
| + RawString* RedirectionIdentifier() const; |
| + void SetRedirectionIdentifier(const String& identifier) const; |
| + RawFunction* RedirectionTarget() const; |
| + void SetRedirectionTarget(const Function& target) const; |
| - bool is_static() const { return StaticBit::decode(raw_ptr()->kind_bits_); } |
| - bool is_final() const { return FinalBit::decode(raw_ptr()->kind_bits_); } |
| - bool is_const() const { return ConstBit::decode(raw_ptr()->kind_bits_); } |
| - bool is_synthetic() const { |
| - return SyntheticBit::decode(raw_ptr()->kind_bits_); |
| + RawFunction::Kind kind() const { |
| + return KindBits::decode(raw_ptr()->kind_tag_); |
| } |
| - inline intptr_t Offset() const; |
| - inline void SetOffset(intptr_t value_in_bytes) const; |
| + RawFunction::AsyncModifier modifier() const { |
| + return ModifierBits::decode(raw_ptr()->kind_tag_); |
| + } |
| - RawInstance* value() const; |
| - void set_value(const Instance& value) const; |
| + static const char* KindToCString(RawFunction::Kind kind); |
| - RawClass* owner() const; |
| - RawClass* origin() const; // Either mixin class, or same as owner(). |
| + bool IsGenerativeConstructor() const { |
| + return (kind() == RawFunction::kConstructor) && !is_static(); |
| + } |
| + bool IsImplicitConstructor() const; |
| + bool IsFactory() const { |
| + return (kind() == RawFunction::kConstructor) && is_static(); |
| + } |
| + bool IsDynamicFunction() const { |
| + if (is_static() || is_abstract()) { |
| + return false; |
| + } |
| + switch (kind()) { |
| + case RawFunction::kRegularFunction: |
| + case RawFunction::kGetterFunction: |
| + case RawFunction::kSetterFunction: |
| + case RawFunction::kImplicitGetter: |
| + case RawFunction::kImplicitSetter: |
| + case RawFunction::kMethodExtractor: |
| + case RawFunction::kNoSuchMethodDispatcher: |
| + case RawFunction::kInvokeFieldDispatcher: |
| + return true; |
| + case RawFunction::kClosureFunction: |
| + case RawFunction::kConstructor: |
| + case RawFunction::kImplicitStaticFinalGetter: |
| + case RawFunction::kIrregexpFunction: |
| + return false; |
| + default: |
| + UNREACHABLE(); |
| + return false; |
| + } |
| + } |
| + bool IsStaticFunction() const { |
| + if (!is_static()) { |
| + return false; |
| + } |
| + switch (kind()) { |
| + case RawFunction::kRegularFunction: |
| + case RawFunction::kGetterFunction: |
| + case RawFunction::kSetterFunction: |
| + case RawFunction::kImplicitGetter: |
| + case RawFunction::kImplicitSetter: |
| + case RawFunction::kImplicitStaticFinalGetter: |
| + case RawFunction::kIrregexpFunction: |
| + return true; |
| + case RawFunction::kClosureFunction: |
| + case RawFunction::kConstructor: |
| + return false; |
| + default: |
| + UNREACHABLE(); |
| + return false; |
| + } |
| + } |
| + bool IsInFactoryScope() const; |
| - RawAbstractType* type() const { return raw_ptr()->type_; } |
| - void set_type(const AbstractType& value) const; |
| + intptr_t token_pos() const { return raw_ptr()->token_pos_; } |
| + void set_token_pos(intptr_t value) const; |
| - static intptr_t InstanceSize() { |
| - return RoundedAllocationSize(sizeof(RawField)); |
| + intptr_t end_token_pos() const { return raw_ptr()->end_token_pos_; } |
| + void set_end_token_pos(intptr_t value) const { |
| + StoreNonPointer(&raw_ptr()->end_token_pos_, value); |
| } |
| - static RawField* New(const String& name, |
| - bool is_static, |
| - bool is_final, |
| - bool is_const, |
| - bool is_synthetic, |
| - const Class& owner, |
| - intptr_t token_pos); |
| + intptr_t num_fixed_parameters() const { |
| + return raw_ptr()->num_fixed_parameters_; |
| + } |
| + void set_num_fixed_parameters(intptr_t value) const; |
| - // Allocate new field object, clone values from this field. The |
| - // owner of the clone is new_owner. |
| - RawField* Clone(const Class& new_owner) const; |
| + bool HasOptionalParameters() const { |
| + return raw_ptr()->num_optional_parameters_ != 0; |
| + } |
| + bool HasOptionalPositionalParameters() const { |
| + return raw_ptr()->num_optional_parameters_ > 0; |
| + } |
| + bool HasOptionalNamedParameters() const { |
| + return raw_ptr()->num_optional_parameters_ < 0; |
| + } |
| + intptr_t NumOptionalParameters() const { |
| + const intptr_t num_opt_params = raw_ptr()->num_optional_parameters_; |
| + return (num_opt_params >= 0) ? num_opt_params : -num_opt_params; |
| + } |
| + void SetNumOptionalParameters(intptr_t num_optional_parameters, |
| + bool are_optional_positional) const; |
| - static intptr_t value_offset() { return OFFSET_OF(RawField, value_); } |
| + intptr_t NumOptionalPositionalParameters() const { |
| + const intptr_t num_opt_params = raw_ptr()->num_optional_parameters_; |
| + return (num_opt_params > 0) ? num_opt_params : 0; |
| + } |
| + intptr_t NumOptionalNamedParameters() const { |
| + const intptr_t num_opt_params = raw_ptr()->num_optional_parameters_; |
| + return (num_opt_params < 0) ? -num_opt_params : 0; |
| + } |
| - static intptr_t kind_bits_offset() { return OFFSET_OF(RawField, kind_bits_); } |
| + intptr_t NumParameters() const; |
| - intptr_t token_pos() const { return raw_ptr()->token_pos_; } |
| + intptr_t NumImplicitParameters() const; |
| - bool has_initializer() const { |
| - return HasInitializerBit::decode(raw_ptr()->kind_bits_); |
| + static intptr_t usage_counter_offset() { |
| + return OFFSET_OF(RawFunction, usage_counter_); |
| } |
| - void set_has_initializer(bool has_initializer) const { |
| - set_kind_bits(HasInitializerBit::update(has_initializer, |
| - raw_ptr()->kind_bits_)); |
| + intptr_t usage_counter() const { |
| + return raw_ptr()->usage_counter_; |
| + } |
| + void set_usage_counter(intptr_t value) const { |
| + StoreNonPointer(&raw_ptr()->usage_counter_, value); |
| } |
| - // Return class id that any non-null value read from this field is guaranteed |
| - // to have or kDynamicCid if such class id is not known. |
| - // Stores to this field must update this information hence the name. |
| - intptr_t guarded_cid() const { return raw_ptr()->guarded_cid_; } |
| - |
| - void set_guarded_cid(intptr_t cid) const { |
| - StoreNonPointer(&raw_ptr()->guarded_cid_, cid); |
| + int16_t deoptimization_counter() const { |
| + return raw_ptr()->deoptimization_counter_; |
| } |
| - static intptr_t guarded_cid_offset() { |
| - return OFFSET_OF(RawField, guarded_cid_); |
| + void set_deoptimization_counter(int16_t value) const { |
| + StoreNonPointer(&raw_ptr()->deoptimization_counter_, value); |
| } |
| - // Return the list length that any list stored in this field is guaranteed |
| - // to have. If length is kUnknownFixedLength the length has not |
| - // been determined. If length is kNoFixedLength this field has multiple |
| - // list lengths associated with it and cannot be predicted. |
| - intptr_t guarded_list_length() const; |
| - void set_guarded_list_length(intptr_t list_length) const; |
| - static intptr_t guarded_list_length_offset() { |
| - return OFFSET_OF(RawField, guarded_list_length_); |
| + |
| + static const intptr_t kMaxInstructionCount = (1 << 16) - 1; |
| + intptr_t optimized_instruction_count() const { |
| + return raw_ptr()->optimized_instruction_count_; |
| } |
| - intptr_t guarded_list_length_in_object_offset() const; |
| - void set_guarded_list_length_in_object_offset(intptr_t offset) const; |
| - static intptr_t guarded_list_length_in_object_offset_offset() { |
| - return OFFSET_OF(RawField, guarded_list_length_in_object_offset_); |
| + void set_optimized_instruction_count(intptr_t value) const { |
| + ASSERT(value >= 0); |
| + if (value > kMaxInstructionCount) { |
| + value = kMaxInstructionCount; |
| + } |
| + StoreNonPointer(&raw_ptr()->optimized_instruction_count_, |
| + static_cast<uint16_t>(value)); |
| } |
| - bool needs_length_check() const { |
| - const bool r = guarded_list_length() >= Field::kUnknownFixedLength; |
| - ASSERT(!r || is_final()); |
| - return r; |
| + intptr_t optimized_call_site_count() const { |
| + return raw_ptr()->optimized_call_site_count_; |
| } |
| - |
| - const char* GuardedPropertiesAsCString() const; |
| - |
| - intptr_t UnboxedFieldCid() const { |
| - ASSERT(IsUnboxedField()); |
| - return guarded_cid(); |
| + void set_optimized_call_site_count(intptr_t value) const { |
| + ASSERT(value >= 0); |
| + if (value > kMaxInstructionCount) { |
| + value = kMaxInstructionCount; |
| + } |
| + StoreNonPointer(&raw_ptr()->optimized_call_site_count_, |
| + static_cast<uint16_t>(value)); |
| } |
| - bool IsUnboxedField() const; |
| + bool IsOptimizable() const; |
| + bool IsNativeAutoSetupScope() const; |
| + void SetIsOptimizable(bool value) const; |
| + void SetIsNativeAutoSetupScope(bool value) const; |
| - bool IsPotentialUnboxedField() const; |
| + bool CanBeInlined() const; |
| - bool is_unboxing_candidate() const { |
| - return UnboxingCandidateBit::decode(raw_ptr()->kind_bits_); |
| - } |
| - void set_is_unboxing_candidate(bool b) const { |
| - set_kind_bits(UnboxingCandidateBit::update(b, raw_ptr()->kind_bits_)); |
| + MethodRecognizer::Kind recognized_kind() const { |
| + return RecognizedBits::decode(raw_ptr()->kind_tag_); |
| } |
| + void set_recognized_kind(MethodRecognizer::Kind value) const; |
| - static bool IsExternalizableCid(intptr_t cid) { |
| - return (cid == kOneByteStringCid) || (cid == kTwoByteStringCid); |
| + bool IsRecognized() const { |
| + return recognized_kind() != MethodRecognizer::kUnknown; |
| } |
| - enum { |
| - kUnknownLengthOffset = -1, |
| - kUnknownFixedLength = -1, |
| - kNoFixedLength = -2, |
| - }; |
| - // Returns false if any value read from this field is guaranteed to be |
| - // not null. |
| - // Internally we is_nullable_ field contains either kNullCid (nullable) or |
| - // any other value (non-nullable) instead of boolean. This is done to simplify |
| - // guarding sequence in the generated code. |
| - bool is_nullable() const { |
| - return raw_ptr()->is_nullable_ == kNullCid; |
| - } |
| - void set_is_nullable(bool val) const { |
| - StoreNonPointer(&raw_ptr()->is_nullable_, val ? kNullCid : kIllegalCid); |
| - } |
| - static intptr_t is_nullable_offset() { |
| - return OFFSET_OF(RawField, is_nullable_); |
| - } |
| + bool HasOptimizedCode() const; |
| - // Record store of the given value into this field. May trigger |
| - // deoptimization of dependent optimized code. |
| - void RecordStore(const Object& value) const; |
| + // Returns true if the argument counts are valid for calling this function. |
| + // Otherwise, it returns false and the reason (if error_message is not NULL). |
| + bool AreValidArgumentCounts(intptr_t num_arguments, |
| + intptr_t num_named_arguments, |
| + String* error_message) const; |
| - void InitializeGuardedListLengthInObjectOffset() const; |
| + // Returns true if the total argument count and the names of optional |
| + // arguments are valid for calling this function. |
| + // Otherwise, it returns false and the reason (if error_message is not NULL). |
| + bool AreValidArguments(intptr_t num_arguments, |
| + const Array& argument_names, |
| + String* error_message) const; |
| + bool AreValidArguments(const ArgumentsDescriptor& args_desc, |
| + String* error_message) const; |
| - // Return the list of optimized code objects that were optimized under |
| - // assumptions about guarded class id and nullability of this field. |
| - // These code objects must be deoptimized when field's properties change. |
| - // Code objects are held weakly via an indirection through WeakProperty. |
| - RawArray* dependent_code() const; |
| - void set_dependent_code(const Array& array) const; |
| + // Fully qualified name uniquely identifying the function under gdb and during |
| + // ast printing. The special ':' character, if present, is replaced by '_'. |
| + const char* ToFullyQualifiedCString() const; |
| - // Add the given code object to the list of dependent ones. |
| - void RegisterDependentCode(const Code& code) const; |
| + const char* ToLibNamePrefixedQualifiedCString() const; |
| - // Deoptimize all dependent code objects. |
| - void DeoptimizeDependentCode() const; |
| + const char* ToQualifiedCString() const; |
| - bool IsUninitialized() const; |
| + // Returns true if this function has parameters that are compatible with the |
| + // parameters of the other function in order for this function to override the |
| + // other function. |
| + bool HasCompatibleParametersWith(const Function& other, |
| + Error* bound_error) const; |
| - void EvaluateInitializer() const; |
| + // Returns true if the type of this function is a subtype of the type of |
| + // the other function. |
| + bool IsSubtypeOf(const TypeArguments& type_arguments, |
| + const Function& other, |
| + const TypeArguments& other_type_arguments, |
| + Error* bound_error) const { |
| + return TypeTest(kIsSubtypeOf, |
| + type_arguments, |
| + other, |
| + other_type_arguments, |
| + bound_error); |
| + } |
| - // Constructs getter and setter names for fields and vice versa. |
| - static RawString* GetterName(const String& field_name); |
| - static RawString* GetterSymbol(const String& field_name); |
| - static RawString* SetterName(const String& field_name); |
| - static RawString* SetterSymbol(const String& field_name); |
| - static RawString* NameFromGetter(const String& getter_name); |
| - static RawString* NameFromSetter(const String& setter_name); |
| - static bool IsGetterName(const String& function_name); |
| - static bool IsSetterName(const String& function_name); |
| + // Returns true if the type of this function is more specific than the type of |
| + // the other function. |
| + bool IsMoreSpecificThan(const TypeArguments& type_arguments, |
| + const Function& other, |
| + const TypeArguments& other_type_arguments, |
| + Error* bound_error) const { |
| + return TypeTest(kIsMoreSpecificThan, |
| + type_arguments, |
| + other, |
| + other_type_arguments, |
| + bound_error); |
| + } |
| - private: |
| - friend class StoreInstanceFieldInstr; // Generated code access to bit field. |
| + // Returns true if this function represents an explicit getter function. |
| + bool IsGetterFunction() const { |
| + return kind() == RawFunction::kGetterFunction; |
| + } |
| - enum { |
| - kConstBit = 0, |
| - kStaticBit, |
| - kFinalBit, |
| - kHasInitializerBit, |
| - kUnboxingCandidateBit, |
| - kSyntheticBit |
| - }; |
| - class ConstBit : public BitField<bool, kConstBit, 1> {}; |
| - class StaticBit : public BitField<bool, kStaticBit, 1> {}; |
| - class FinalBit : public BitField<bool, kFinalBit, 1> {}; |
| - class HasInitializerBit : public BitField<bool, kHasInitializerBit, 1> {}; |
| - class UnboxingCandidateBit : public BitField<bool, |
| - kUnboxingCandidateBit, 1> { |
| - }; |
| - class SyntheticBit : public BitField<bool, kSyntheticBit, 1> {}; |
| + // Returns true if this function represents an implicit getter function. |
| + bool IsImplicitGetterFunction() const { |
| + return kind() == RawFunction::kImplicitGetter; |
| + } |
| - // Update guarded cid and guarded length for this field. Returns true, if |
| - // deoptimization of dependent code is required. |
| - bool UpdateGuardedCidAndLength(const Object& value) const; |
| + // Returns true if this function represents an explicit setter function. |
| + bool IsSetterFunction() const { |
| + return kind() == RawFunction::kSetterFunction; |
| + } |
| - void set_name(const String& value) const; |
| - void set_is_static(bool is_static) const { |
| - set_kind_bits(StaticBit::update(is_static, raw_ptr()->kind_bits_)); |
| + // Returns true if this function represents an implicit setter function. |
| + bool IsImplicitSetterFunction() const { |
| + return kind() == RawFunction::kImplicitSetter; |
| + } |
| + |
| + // Returns true if this function represents a (possibly implicit) closure |
| + // function. |
| + bool IsClosureFunction() const { |
| + return kind() == RawFunction::kClosureFunction; |
| + } |
| + |
| + // Returns true if this function represents a generated irregexp function. |
| + bool IsIrregexpFunction() const { |
| + return kind() == RawFunction::kIrregexpFunction; |
| + } |
| + |
| + // Returns true if this function represents an implicit closure function. |
| + bool IsImplicitClosureFunction() const; |
| + |
| + // Returns true if this function represents a non implicit closure function. |
| + bool IsNonImplicitClosureFunction() const { |
| + return IsClosureFunction() && !IsImplicitClosureFunction(); |
| + } |
| + |
| + // Returns true if this function represents an implicit static closure |
| + // function. |
| + bool IsImplicitStaticClosureFunction() const { |
| + return is_static() && IsImplicitClosureFunction(); |
| + } |
| + bool static IsImplicitStaticClosureFunction(RawFunction* func); |
| + |
| + // Returns true if this function represents an implicit instance closure |
| + // function. |
| + bool IsImplicitInstanceClosureFunction() const { |
| + return !is_static() && IsImplicitClosureFunction(); |
| + } |
| + |
| + // Returns true if this function represents a local function. |
| + bool IsLocalFunction() const { |
| + return parent_function() != Function::null(); |
| } |
| - void set_is_final(bool is_final) const { |
| - set_kind_bits(FinalBit::update(is_final, raw_ptr()->kind_bits_)); |
| + |
| + // Returns true if this function represents a signature function without code. |
| + bool IsSignatureFunction() const { |
| + return kind() == RawFunction::kSignatureFunction; |
| } |
| - void set_is_const(bool value) const { |
| - set_kind_bits(ConstBit::update(value, raw_ptr()->kind_bits_)); |
| + |
| + bool IsAsyncFunction() const { |
| + return modifier() == RawFunction::kAsync; |
| } |
| - void set_is_synthetic(bool value) const { |
| - set_kind_bits(SyntheticBit::update(value, raw_ptr()->kind_bits_)); |
| + |
| + bool IsAsyncClosure() const { |
| + return is_generated_body() && |
| + Function::Handle(parent_function()).IsAsyncFunction(); |
| } |
| - void set_owner(const Object& value) const { |
| - StorePointer(&raw_ptr()->owner_, value.raw()); |
| + |
| + bool IsGenerator() const { |
| + return (modifier() & RawFunction::kGeneratorBit) != 0; |
| } |
| - void set_token_pos(intptr_t token_pos) const { |
| - StoreNonPointer(&raw_ptr()->token_pos_, token_pos); |
| + |
| + bool IsSyncGenerator() const { |
| + return modifier() == RawFunction::kSyncGen; |
| } |
| - void set_kind_bits(intptr_t value) const { |
| - StoreNonPointer(&raw_ptr()->kind_bits_, static_cast<uint8_t>(value)); |
| + |
| + bool IsSyncGenClosure() const { |
| + return is_generated_body() && |
| + Function::Handle(parent_function()).IsSyncGenerator(); |
| } |
| - static RawField* New(); |
| + bool IsGeneratorClosure() const { |
| + return is_generated_body() && |
| + Function::Handle(parent_function()).IsGenerator(); |
| + } |
| - FINAL_HEAP_OBJECT_IMPLEMENTATION(Field, Object); |
| - friend class Class; |
| - friend class HeapProfiler; |
| -}; |
| + bool IsAsyncGenerator() const { |
| + return modifier() == RawFunction::kAsyncGen; |
| + } |
| + bool IsAsyncGenClosure() const { |
| + return is_generated_body() && |
| + Function::Handle(parent_function()).IsAsyncGenerator(); |
| + } |
| -class LiteralToken : public Object { |
| - public: |
| - Token::Kind kind() const { return raw_ptr()->kind_; } |
| - RawString* literal() const { return raw_ptr()->literal_; } |
| - RawObject* value() const { return raw_ptr()->value_; } |
| + bool IsAsyncOrGenerator() const { |
| + return modifier() != RawFunction::kNoModifier; |
| + } |
| static intptr_t InstanceSize() { |
| - return RoundedAllocationSize(sizeof(RawLiteralToken)); |
| + return RoundedAllocationSize(sizeof(RawFunction)); |
| } |
| - static RawLiteralToken* New(); |
| - static RawLiteralToken* New(Token::Kind kind, const String& literal); |
| + static RawFunction* New(const String& name, |
| + RawFunction::Kind kind, |
| + bool is_static, |
| + bool is_const, |
| + bool is_abstract, |
| + bool is_external, |
| + bool is_native, |
| + const Object& owner, |
| + intptr_t token_pos); |
| - private: |
| - void set_kind(Token::Kind kind) const { |
| - StoreNonPointer(&raw_ptr()->kind_, kind); |
| - } |
| - void set_literal(const String& literal) const; |
| - void set_value(const Object& value) const; |
| + // Allocates a new Function object representing a closure function, as well as |
| + // a new associated Class object representing the signature class of the |
| + // function. |
| + // The function and the class share the same given name. |
| + static RawFunction* NewClosureFunction(const String& name, |
| + const Function& parent, |
| + intptr_t token_pos); |
| - FINAL_HEAP_OBJECT_IMPLEMENTATION(LiteralToken, Object); |
| - friend class Class; |
| -}; |
| + static RawFunction* NewEvalFunction(const Class& owner, |
| + const Script& script, |
| + bool is_static); |
| + // Allocate new function object, clone values from this function. The |
| + // owner of the clone is new_owner. |
| + RawFunction* Clone(const Class& new_owner) const; |
| -class TokenStream : public Object { |
| - public: |
| - RawArray* TokenObjects() const; |
| - void SetTokenObjects(const Array& value) const; |
| + // Slow function, use in asserts to track changes in important library |
| + // functions. |
| + int32_t SourceFingerprint() const; |
| - RawExternalTypedData* GetStream() const; |
| - void SetStream(const ExternalTypedData& stream) const; |
| + // Return false and report an error if the fingerprint does not match. |
| + bool CheckSourceFingerprint(const char* prefix, int32_t fp) const; |
| - RawString* GenerateSource() const; |
| - RawString* GenerateSource(intptr_t start, intptr_t end) const; |
| - intptr_t ComputeSourcePosition(intptr_t tok_pos) const; |
| + // Works with map [deopt-id] -> ICData. |
| + void SaveICDataMap( |
| + const ZoneGrowableArray<const ICData*>& deopt_id_to_ic_data) const; |
| + void RestoreICDataMap( |
| + ZoneGrowableArray<const ICData*>* deopt_id_to_ic_data) const; |
| - RawString* PrivateKey() const; |
| + RawArray* ic_data_array() const; |
| + void ClearICDataArray() const; |
| - static const intptr_t kBytesPerElement = 1; |
| - static const intptr_t kMaxElements = kSmiMax / kBytesPerElement; |
| + // Sets deopt reason in all ICData-s with given deopt_id. |
| + void SetDeoptReasonForAll(intptr_t deopt_id, ICData::DeoptReasonId reason); |
| - static intptr_t InstanceSize() { |
| - return RoundedAllocationSize(sizeof(RawTokenStream)); |
| - } |
| + static const int kCtorPhaseInit = 1 << 0; |
| + static const int kCtorPhaseBody = 1 << 1; |
| + static const int kCtorPhaseAll = (kCtorPhaseInit | kCtorPhaseBody); |
| - static RawTokenStream* New(intptr_t length); |
| - static RawTokenStream* New(const Scanner::GrowableTokenStream& tokens, |
| - const String& private_key); |
| + void set_modifier(RawFunction::AsyncModifier value) const; |
| - // The class Iterator encapsulates iteration over the tokens |
| - // in a TokenStream object. |
| - class Iterator : ValueObject { |
| - public: |
| - enum StreamType { |
| - kNoNewlines, |
| - kAllTokens |
| - }; |
| + // static: Considered during class-side or top-level resolution rather than |
| + // instance-side resolution. |
| + // const: Valid target of a const constructor call. |
| + // abstract: Skipped during instance-side resolution. |
| + // reflectable: Enumerated by mirrors, invocable by mirrors. False for private |
| + // functions of dart: libraries. |
| + // debuggable: Valid location of a breakpoint. Synthetic code is not |
| + // debuggable. |
| + // visible: Frame is included in stack traces. Synthetic code such as |
| + // dispatchers is not visible. Synthetic code that can trigger |
| + // exceptions such as the outer async functions that create Futures |
| + // is visible. |
| + // optimizable: Candidate for going through the optimizing compiler. False for |
| + // some functions known to be execute infrequently and functions |
| + // which have been de-optimized too many times. |
| + // instrinsic: Has a hand-written assembly prologue. |
| + // inlinable: Candidate for inlining. False for functions with features we |
| + // don't support during inlining (e.g., optional parameters), |
| + // functions which are too big, etc. |
| + // native: Bridge to C/C++ code. |
| + // redirecting: Redirecting generative or factory constructor. |
| + // external: Just a declaration that expects to be defined in another patch |
| + // file. |
| - Iterator(const TokenStream& tokens, |
| - intptr_t token_pos, |
| - Iterator::StreamType stream_type = kNoNewlines); |
| +#define FOR_EACH_FUNCTION_KIND_BIT(V) \ |
| + V(Static, is_static) \ |
| + V(Const, is_const) \ |
| + V(Abstract, is_abstract) \ |
| + V(Reflectable, is_reflectable) \ |
| + V(Visible, is_visible) \ |
| + V(Debuggable, is_debuggable) \ |
| + V(Optimizable, is_optimizable) \ |
| + V(Inlinable, is_inlinable) \ |
| + V(Intrinsic, is_intrinsic) \ |
| + V(Native, is_native) \ |
| + V(Redirecting, is_redirecting) \ |
| + V(External, is_external) \ |
| + V(AllowsHoistingCheckClass, allows_hoisting_check_class) \ |
| + V(AllowsBoundsCheckGeneralization, allows_bounds_check_generalization) \ |
| + V(GeneratedBody, is_generated_body) \ |
| + V(AlwaysInline, always_inline) \ |
| + V(PolymorphicTarget, is_polymorphic_target) \ |
| - void SetStream(const TokenStream& tokens, intptr_t token_pos); |
| - bool IsValid() const; |
| +#define DEFINE_ACCESSORS(name, accessor_name) \ |
| + void set_##accessor_name(bool value) const { \ |
| + set_kind_tag(name##Bit::update(value, raw_ptr()->kind_tag_)); \ |
| + } \ |
| + bool accessor_name() const { \ |
| + return name##Bit::decode(raw_ptr()->kind_tag_); \ |
| + } |
| +FOR_EACH_FUNCTION_KIND_BIT(DEFINE_ACCESSORS) |
| +#undef DEFINE_ACCESSORS |
| - inline Token::Kind CurrentTokenKind() const { |
| - return cur_token_kind_; |
| - } |
| + private: |
| + void set_ic_data_array(const Array& value) const; |
| - Token::Kind LookaheadTokenKind(intptr_t num_tokens); |
| + enum KindTagBits { |
| + kKindTagPos = 0, |
| + kKindTagSize = 4, |
| + kRecognizedTagPos = kKindTagPos + kKindTagSize, |
| + kRecognizedTagSize = 9, |
| + kModifierPos = kRecognizedTagPos + kRecognizedTagSize, |
| + kModifierSize = 2, |
| + kLastModifierBitPos = kModifierPos + (kModifierSize - 1), |
| + // Single bit sized fields start here. |
| +#define DECLARE_BIT(name, _) k##name##Bit, |
| +FOR_EACH_FUNCTION_KIND_BIT(DECLARE_BIT) |
| +#undef DECLARE_BIT |
| + kNumTagBits |
| + }; |
| - intptr_t CurrentPosition() const; |
| - void SetCurrentPosition(intptr_t value); |
| + COMPILE_ASSERT( |
| + MethodRecognizer::kNumRecognizedMethods < (1 << kRecognizedTagSize)); |
| + COMPILE_ASSERT( |
| + kNumTagBits <= |
| + (kBitsPerByte * sizeof(static_cast<RawFunction*>(0)->kind_tag_))); |
| - void Advance(); |
| + class KindBits : |
| + public BitField<RawFunction::Kind, kKindTagPos, kKindTagSize> {}; // NOLINT |
| - RawObject* CurrentToken() const; |
| - RawString* CurrentLiteral() const; |
| - RawString* MakeLiteralToken(const Object& obj) const; |
| + class RecognizedBits : public BitField<MethodRecognizer::Kind, |
| + kRecognizedTagPos, |
| + kRecognizedTagSize> {}; |
| + class ModifierBits : |
| + public BitField<RawFunction::AsyncModifier, |
| + kModifierPos, |
| + kModifierSize> {}; // NOLINT |
| - private: |
| - // Read token from the token stream (could be a simple token or an index |
| - // into the token objects array for IDENT or literal tokens). |
| - intptr_t ReadToken() { |
| - int64_t value = stream_.ReadUnsigned(); |
| - ASSERT((value >= 0) && (value <= kIntptrMax)); |
| - return static_cast<intptr_t>(value); |
| - } |
| +#define DEFINE_BIT(name, _) \ |
| + class name##Bit : public BitField<bool, k##name##Bit, 1> {}; |
| +FOR_EACH_FUNCTION_KIND_BIT(DEFINE_BIT) |
| +#undef DEFINE_BIT |
| + |
| + void set_name(const String& value) const; |
| + void set_kind(RawFunction::Kind value) const; |
| + void set_parent_function(const Function& value) const; |
| + void set_owner(const Object& value) const; |
| + RawFunction* implicit_closure_function() const; |
| + void set_implicit_closure_function(const Function& value) const; |
| + RawInstance* implicit_static_closure() const; |
| + void set_implicit_static_closure(const Instance& closure) const; |
| + RawScript* eval_script() const; |
| + void set_eval_script(const Script& value) const; |
| + void set_num_optional_parameters(intptr_t value) const; // Encoded value. |
| + void set_kind_tag(intptr_t value) const; |
| + void set_data(const Object& value) const; |
| - TokenStream& tokens_; |
| - ExternalTypedData& data_; |
| - ReadStream stream_; |
| - Array& token_objects_; |
| - Object& obj_; |
| - intptr_t cur_token_pos_; |
| - Token::Kind cur_token_kind_; |
| - intptr_t cur_token_obj_index_; |
| - Iterator::StreamType stream_type_; |
| - }; |
| + static RawFunction* New(); |
| - private: |
| - void SetPrivateKey(const String& value) const; |
| + void BuildSignatureParameters(bool instantiate, |
| + NameVisibility name_visibility, |
| + const TypeArguments& instantiator, |
| + const GrowableObjectArray& pieces) const; |
| + RawString* BuildSignature(bool instantiate, |
| + NameVisibility name_visibility, |
| + const TypeArguments& instantiator) const; |
| - static RawTokenStream* New(); |
| - static void DataFinalizer(void* isolate_callback_data, |
| - Dart_WeakPersistentHandle handle, |
| - void *peer); |
| + // Check the subtype or 'more specific' relationship. |
| + bool TypeTest(TypeTestKind test_kind, |
| + const TypeArguments& type_arguments, |
| + const Function& other, |
| + const TypeArguments& other_type_arguments, |
| + Error* bound_error) const; |
| - FINAL_HEAP_OBJECT_IMPLEMENTATION(TokenStream, Object); |
| + // Checks the type of the formal parameter at the given position for |
| + // subtyping or 'more specific' relationship between the type of this function |
| + // and the type of the other function. |
| + bool TestParameterType(TypeTestKind test_kind, |
| + intptr_t parameter_position, |
| + intptr_t other_parameter_position, |
| + const TypeArguments& type_arguments, |
| + const Function& other, |
| + const TypeArguments& other_type_arguments, |
| + Error* bound_error) const; |
| + |
| + FINAL_HEAP_OBJECT_IMPLEMENTATION(Function, Object); |
| friend class Class; |
| + friend class SnapshotWriter; |
| + friend class Parser; // For set_eval_script. |
| + // RawFunction::VisitFunctionPointers accesses the private constructor of |
| + // Function. |
| + friend class RawFunction; |
| }; |
| -class Script : public Object { |
| +class ClosureData: public Object { |
| public: |
| - RawString* url() const { return raw_ptr()->url_; } |
| - bool HasSource() const; |
| - RawString* Source() const; |
| - RawString* GenerateSource() const; // Generates source code from Tokenstream. |
| - RawGrowableObjectArray* GenerateLineNumberArray() const; |
| - RawScript::Kind kind() const { |
| - return static_cast<RawScript::Kind>(raw_ptr()->kind_); |
| + static intptr_t InstanceSize() { |
| + return RoundedAllocationSize(sizeof(RawClosureData)); |
| } |
| - const char* GetKindAsCString() const; |
| - intptr_t line_offset() const { return raw_ptr()->line_offset_; } |
| - intptr_t col_offset() const { return raw_ptr()->col_offset_; } |
| - RawTokenStream* tokens() const { return raw_ptr()->tokens_; } |
| + private: |
| + RawContextScope* context_scope() const { return raw_ptr()->context_scope_; } |
| + void set_context_scope(const ContextScope& value) const; |
| - void Tokenize(const String& private_key) const; |
| + // Enclosing function of this local function. |
| + RawFunction* parent_function() const { return raw_ptr()->parent_function_; } |
| + void set_parent_function(const Function& value) const; |
| - RawLibrary* FindLibrary() const; |
| - RawString* GetLine(intptr_t line_number) const; |
| - RawString* GetSnippet(intptr_t from_line, |
| - intptr_t from_column, |
| - intptr_t to_line, |
| - intptr_t to_column) const; |
| + // Signature class of this closure function or signature function. |
| + RawClass* signature_class() const { return raw_ptr()->signature_class_; } |
| + void set_signature_class(const Class& value) const; |
| - void SetLocationOffset(intptr_t line_offset, intptr_t col_offset) const; |
| + RawInstance* implicit_static_closure() const { |
| + return raw_ptr()->closure_; |
| + } |
| + void set_implicit_static_closure(const Instance& closure) const; |
| - void GetTokenLocation(intptr_t token_pos, |
| - intptr_t* line, intptr_t* column) const; |
| + static RawClosureData* New(); |
| + |
| + FINAL_HEAP_OBJECT_IMPLEMENTATION(ClosureData, Object); |
| + friend class Class; |
| + friend class Function; |
| + friend class HeapProfiler; |
| +}; |
| - // Returns index of first and last token on the given line. Returns both |
| - // indices < 0 if no token exists on or after the line. If a token exists |
| - // after, but not on given line, returns in *first_token_index the index of |
| - // the first token after the line, and a negative value in *last_token_index. |
| - void TokenRangeAtLine(intptr_t line_number, |
| - intptr_t* first_token_index, |
| - intptr_t* last_token_index) const; |
| +class RedirectionData: public Object { |
| + public: |
| static intptr_t InstanceSize() { |
| - return RoundedAllocationSize(sizeof(RawScript)); |
| + return RoundedAllocationSize(sizeof(RawRedirectionData)); |
| } |
| - static RawScript* New(const String& url, |
| - const String& source, |
| - RawScript::Kind kind); |
| - |
| private: |
| - void set_url(const String& value) const; |
| - void set_source(const String& value) const; |
| - void set_kind(RawScript::Kind value) const; |
| - void set_tokens(const TokenStream& value) const; |
| + // The type specifies the class and type arguments of the target constructor. |
| + RawType* type() const { return raw_ptr()->type_; } |
| + void set_type(const Type& value) const; |
| - static RawScript* New(); |
| + // The optional identifier specifies a named constructor. |
| + RawString* identifier() const { return raw_ptr()->identifier_; } |
| + void set_identifier(const String& value) const; |
| - FINAL_HEAP_OBJECT_IMPLEMENTATION(Script, Object); |
| + // The resolved constructor or factory target of the redirection. |
| + RawFunction* target() const { return raw_ptr()->target_; } |
| + void set_target(const Function& value) const; |
| + |
| + static RawRedirectionData* New(); |
| + |
| + FINAL_HEAP_OBJECT_IMPLEMENTATION(RedirectionData, Object); |
| friend class Class; |
| + friend class Function; |
| + friend class HeapProfiler; |
| }; |
| -class DictionaryIterator : public ValueObject { |
| +class Field : public Object { |
| public: |
| - explicit DictionaryIterator(const Library& library); |
| + RawString* name() const { return raw_ptr()->name_; } |
| + RawString* PrettyName() const; |
| + RawString* UserVisibleName() const; |
| + virtual RawString* DictionaryName() const { return name(); } |
| - bool HasNext() const { return next_ix_ < size_; } |
| + bool is_static() const { return StaticBit::decode(raw_ptr()->kind_bits_); } |
| + bool is_final() const { return FinalBit::decode(raw_ptr()->kind_bits_); } |
| + bool is_const() const { return ConstBit::decode(raw_ptr()->kind_bits_); } |
| + bool is_synthetic() const { |
| + return SyntheticBit::decode(raw_ptr()->kind_bits_); |
| + } |
| - // Returns next non-null raw object. |
| - RawObject* GetNext(); |
| + inline intptr_t Offset() const; |
| + inline void SetOffset(intptr_t value_in_bytes) const; |
| - private: |
| - void MoveToNextObject(); |
| + RawInstance* value() const; |
| + void set_value(const Instance& value) const; |
| - const Array& array_; |
| - const int size_; // Number of elements to iterate over. |
| - int next_ix_; // Index of next element. |
| + RawClass* owner() const; |
| + RawClass* origin() const; // Either mixin class, or same as owner(). |
| - friend class ClassDictionaryIterator; |
| - friend class LibraryPrefixIterator; |
| - DISALLOW_COPY_AND_ASSIGN(DictionaryIterator); |
| -}; |
| + RawAbstractType* type() const { return raw_ptr()->type_; } |
| + void set_type(const AbstractType& value) const; |
| + static intptr_t InstanceSize() { |
| + return RoundedAllocationSize(sizeof(RawField)); |
| + } |
| -class ClassDictionaryIterator : public DictionaryIterator { |
| - public: |
| - enum IterationKind { |
| - kIteratePrivate, |
| - kNoIteratePrivate |
| - }; |
| + static RawField* New(const String& name, |
| + bool is_static, |
| + bool is_final, |
| + bool is_const, |
| + bool is_synthetic, |
| + const Class& owner, |
| + intptr_t token_pos); |
| - ClassDictionaryIterator(const Library& library, |
| - IterationKind kind = kNoIteratePrivate); |
| + // Allocate new field object, clone values from this field. The |
| + // owner of the clone is new_owner. |
| + RawField* Clone(const Class& new_owner) const; |
| - bool HasNext() const { return (next_ix_ < size_) || (anon_ix_ < anon_size_); } |
| + static intptr_t value_offset() { return OFFSET_OF(RawField, value_); } |
| - // Returns a non-null raw class. |
| - RawClass* GetNextClass(); |
| + static intptr_t kind_bits_offset() { return OFFSET_OF(RawField, kind_bits_); } |
| - private: |
| - void MoveToNextClass(); |
| + intptr_t token_pos() const { return raw_ptr()->token_pos_; } |
| - const Array& anon_array_; |
| - const int anon_size_; // Number of anonymous classes to iterate over. |
| - int anon_ix_; // Index of next anonymous class. |
| + bool has_initializer() const { |
| + return HasInitializerBit::decode(raw_ptr()->kind_bits_); |
| + } |
| + void set_has_initializer(bool has_initializer) const { |
| + set_kind_bits(HasInitializerBit::update(has_initializer, |
| + raw_ptr()->kind_bits_)); |
| + } |
| - DISALLOW_COPY_AND_ASSIGN(ClassDictionaryIterator); |
| -}; |
| + // Return class id that any non-null value read from this field is guaranteed |
| + // to have or kDynamicCid if such class id is not known. |
| + // Stores to this field must update this information hence the name. |
| + intptr_t guarded_cid() const { return raw_ptr()->guarded_cid_; } |
| + |
| + void set_guarded_cid(intptr_t cid) const { |
| + StoreNonPointer(&raw_ptr()->guarded_cid_, cid); |
| + } |
| + static intptr_t guarded_cid_offset() { |
| + return OFFSET_OF(RawField, guarded_cid_); |
| + } |
| + // Return the list length that any list stored in this field is guaranteed |
| + // to have. If length is kUnknownFixedLength the length has not |
| + // been determined. If length is kNoFixedLength this field has multiple |
| + // list lengths associated with it and cannot be predicted. |
| + intptr_t guarded_list_length() const; |
| + void set_guarded_list_length(intptr_t list_length) const; |
| + static intptr_t guarded_list_length_offset() { |
| + return OFFSET_OF(RawField, guarded_list_length_); |
| + } |
| + intptr_t guarded_list_length_in_object_offset() const; |
| + void set_guarded_list_length_in_object_offset(intptr_t offset) const; |
| + static intptr_t guarded_list_length_in_object_offset_offset() { |
| + return OFFSET_OF(RawField, guarded_list_length_in_object_offset_); |
| + } |
| + bool needs_length_check() const { |
| + const bool r = guarded_list_length() >= Field::kUnknownFixedLength; |
| + ASSERT(!r || is_final()); |
| + return r; |
| + } |
| -class LibraryPrefixIterator : public DictionaryIterator { |
| - public: |
| - explicit LibraryPrefixIterator(const Library& library); |
| - RawLibraryPrefix* GetNext(); |
| - private: |
| - void Advance(); |
| - DISALLOW_COPY_AND_ASSIGN(LibraryPrefixIterator); |
| -}; |
| + const char* GuardedPropertiesAsCString() const; |
| + |
| + intptr_t UnboxedFieldCid() const { |
| + ASSERT(IsUnboxedField()); |
| + return guarded_cid(); |
| + } |
| + bool IsUnboxedField() const; |
| -class Library : public Object { |
| - public: |
| - RawString* name() const { return raw_ptr()->name_; } |
| - void SetName(const String& name) const; |
| + bool IsPotentialUnboxedField() const; |
| + |
| + bool is_unboxing_candidate() const { |
| + return UnboxingCandidateBit::decode(raw_ptr()->kind_bits_); |
| + } |
| + void set_is_unboxing_candidate(bool b) const { |
| + set_kind_bits(UnboxingCandidateBit::update(b, raw_ptr()->kind_bits_)); |
| + } |
| - RawString* url() const { return raw_ptr()->url_; } |
| - RawString* private_key() const { return raw_ptr()->private_key_; } |
| - bool LoadNotStarted() const { |
| - return raw_ptr()->load_state_ == RawLibrary::kAllocated; |
| + static bool IsExternalizableCid(intptr_t cid) { |
| + return (cid == kOneByteStringCid) || (cid == kTwoByteStringCid); |
| } |
| - bool LoadRequested() const { |
| - return raw_ptr()->load_state_ == RawLibrary::kLoadRequested; |
| + |
| + enum { |
| + kUnknownLengthOffset = -1, |
| + kUnknownFixedLength = -1, |
| + kNoFixedLength = -2, |
| + }; |
| + // Returns false if any value read from this field is guaranteed to be |
| + // not null. |
| + // Internally we is_nullable_ field contains either kNullCid (nullable) or |
| + // any other value (non-nullable) instead of boolean. This is done to simplify |
| + // guarding sequence in the generated code. |
| + bool is_nullable() const { |
| + return raw_ptr()->is_nullable_ == kNullCid; |
| } |
| - bool LoadInProgress() const { |
| - return raw_ptr()->load_state_ == RawLibrary::kLoadInProgress; |
| + void set_is_nullable(bool val) const { |
| + StoreNonPointer(&raw_ptr()->is_nullable_, val ? kNullCid : kIllegalCid); |
| } |
| - void SetLoadRequested() const; |
| - void SetLoadInProgress() const; |
| - bool Loaded() const { return raw_ptr()->load_state_ == RawLibrary::kLoaded; } |
| - void SetLoaded() const; |
| - bool LoadFailed() const { |
| - return raw_ptr()->load_state_ == RawLibrary::kLoadError; |
| + static intptr_t is_nullable_offset() { |
| + return OFFSET_OF(RawField, is_nullable_); |
| } |
| - RawInstance* LoadError() const { return raw_ptr()->load_error_; } |
| - void SetLoadError(const Instance& error) const; |
| - RawInstance* TransitiveLoadError() const; |
| - static intptr_t InstanceSize() { |
| - return RoundedAllocationSize(sizeof(RawLibrary)); |
| - } |
| + // Record store of the given value into this field. May trigger |
| + // deoptimization of dependent optimized code. |
| + void RecordStore(const Object& value) const; |
| - static RawLibrary* New(const String& url); |
| + void InitializeGuardedListLengthInObjectOffset() const; |
| - // Evaluate the given expression as if it appeared in an top-level |
| - // method of this library and return the resulting value, or an |
| - // error object if evaluating the expression fails. The method has |
| - // the formal parameters given in param_names, and is invoked with |
| - // the argument values given in param_values. |
| - RawObject* Evaluate(const String& expr, |
| - const Array& param_names, |
| - const Array& param_values) const; |
| + // Return the list of optimized code objects that were optimized under |
| + // assumptions about guarded class id and nullability of this field. |
| + // These code objects must be deoptimized when field's properties change. |
| + // Code objects are held weakly via an indirection through WeakProperty. |
| + RawArray* dependent_code() const; |
| + void set_dependent_code(const Array& array) const; |
| - // Library scope name dictionary. |
| - // |
| - // TODO(turnidge): The Lookup functions are not consistent in how |
| - // they deal with private names. Go through and make them a bit |
| - // more regular. |
| - void AddClass(const Class& cls) const; |
| - void AddObject(const Object& obj, const String& name) const; |
| - void ReplaceObject(const Object& obj, const String& name) const; |
| - RawObject* LookupReExport(const String& name) const; |
| - RawObject* LookupObjectAllowPrivate(const String& name) const; |
| - RawObject* LookupLocalObjectAllowPrivate(const String& name) const; |
| - RawObject* LookupLocalObject(const String& name) const; |
| - RawObject* LookupImportedObject(const String& name) const; |
| - RawClass* LookupClass(const String& name) const; |
| - RawClass* LookupClassAllowPrivate(const String& name) const; |
| - RawClass* LookupLocalClass(const String& name) const; |
| - RawField* LookupFieldAllowPrivate(const String& name) const; |
| - RawField* LookupLocalField(const String& name) const; |
| - RawFunction* LookupFunctionAllowPrivate(const String& name) const; |
| - RawFunction* LookupLocalFunction(const String& name) const; |
| - RawLibraryPrefix* LookupLocalLibraryPrefix(const String& name) const; |
| - RawScript* LookupScript(const String& url) const; |
| - RawArray* LoadedScripts() const; |
| + // Add the given code object to the list of dependent ones. |
| + void RegisterDependentCode(const Code& code) const; |
| - // Resolve name in the scope of this library. First check the cache |
| - // of already resolved names for this library. Then look in the |
| - // local dictionary for the unmangled name N, the getter name get:N |
| - // and setter name set:N. |
| - // If the local dictionary contains no entry for these names, |
| - // look in the scopes of all libraries that are imported |
| - // without a library prefix. |
| - RawObject* ResolveName(const String& name) const; |
| + // Deoptimize all dependent code objects. |
| + void DeoptimizeDependentCode() const; |
| - void AddAnonymousClass(const Class& cls) const; |
| + bool IsUninitialized() const; |
| - void AddExport(const Namespace& ns) const; |
| + void EvaluateInitializer() const; |
| - void AddClassMetadata(const Class& cls, |
| - const Class& toplevel_class, |
| - intptr_t token_pos) const; |
| - void AddFieldMetadata(const Field& field, intptr_t token_pos) const; |
| - void AddFunctionMetadata(const Function& func, intptr_t token_pos) const; |
| - void AddLibraryMetadata(const Class& cls, intptr_t token_pos) const; |
| - void AddTypeParameterMetadata(const TypeParameter& param, |
| - intptr_t token_pos) const; |
| - RawObject* GetMetadata(const Object& obj) const; |
| + // Constructs getter and setter names for fields and vice versa. |
| + static RawString* GetterName(const String& field_name); |
| + static RawString* GetterSymbol(const String& field_name); |
| + static RawString* SetterName(const String& field_name); |
| + static RawString* SetterSymbol(const String& field_name); |
| + static RawString* NameFromGetter(const String& getter_name); |
| + static RawString* NameFromSetter(const String& setter_name); |
| + static bool IsGetterName(const String& function_name); |
| + static bool IsSetterName(const String& function_name); |
| - intptr_t num_anonymous_classes() const { return raw_ptr()->num_anonymous_; } |
| - RawArray* anonymous_classes() const { return raw_ptr()->anonymous_classes_; } |
| + private: |
| + friend class StoreInstanceFieldInstr; // Generated code access to bit field. |
| - // Library imports. |
| - RawArray* imports() const { return raw_ptr()->imports_; } |
| - RawArray* exports() const { return raw_ptr()->exports_; } |
| - void AddImport(const Namespace& ns) const; |
| - intptr_t num_imports() const { return raw_ptr()->num_imports_; } |
| - RawNamespace* ImportAt(intptr_t index) const; |
| - RawLibrary* ImportLibraryAt(intptr_t index) const; |
| - bool ImportsCorelib() const; |
| + enum { |
| + kConstBit = 0, |
| + kStaticBit, |
| + kFinalBit, |
| + kHasInitializerBit, |
| + kUnboxingCandidateBit, |
| + kSyntheticBit |
| + }; |
| + class ConstBit : public BitField<bool, kConstBit, 1> {}; |
| + class StaticBit : public BitField<bool, kStaticBit, 1> {}; |
| + class FinalBit : public BitField<bool, kFinalBit, 1> {}; |
| + class HasInitializerBit : public BitField<bool, kHasInitializerBit, 1> {}; |
| + class UnboxingCandidateBit : public BitField<bool, |
| + kUnboxingCandidateBit, 1> { |
| + }; |
| + class SyntheticBit : public BitField<bool, kSyntheticBit, 1> {}; |
| - RawFunction* LookupFunctionInScript(const Script& script, |
| - intptr_t token_pos) const; |
| + // Update guarded cid and guarded length for this field. Returns true, if |
| + // deoptimization of dependent code is required. |
| + bool UpdateGuardedCidAndLength(const Object& value) const; |
| - // Resolving native methods for script loaded in the library. |
| - Dart_NativeEntryResolver native_entry_resolver() const { |
| - return raw_ptr()->native_entry_resolver_; |
| + void set_name(const String& value) const; |
| + void set_is_static(bool is_static) const { |
| + set_kind_bits(StaticBit::update(is_static, raw_ptr()->kind_bits_)); |
| } |
| - void set_native_entry_resolver(Dart_NativeEntryResolver value) const { |
| - StoreNonPointer(&raw_ptr()->native_entry_resolver_, value); |
| + void set_is_final(bool is_final) const { |
| + set_kind_bits(FinalBit::update(is_final, raw_ptr()->kind_bits_)); |
| } |
| - Dart_NativeEntrySymbol native_entry_symbol_resolver() const { |
| - return raw_ptr()->native_entry_symbol_resolver_; |
| + void set_is_const(bool value) const { |
| + set_kind_bits(ConstBit::update(value, raw_ptr()->kind_bits_)); |
| } |
| - void set_native_entry_symbol_resolver( |
| - Dart_NativeEntrySymbol native_symbol_resolver) const { |
| - StoreNonPointer(&raw_ptr()->native_entry_symbol_resolver_, |
| - native_symbol_resolver); |
| + void set_is_synthetic(bool value) const { |
| + set_kind_bits(SyntheticBit::update(value, raw_ptr()->kind_bits_)); |
| + } |
| + void set_owner(const Object& value) const { |
| + StorePointer(&raw_ptr()->owner_, value.raw()); |
| + } |
| + void set_token_pos(intptr_t token_pos) const { |
| + StoreNonPointer(&raw_ptr()->token_pos_, token_pos); |
| + } |
| + void set_kind_bits(intptr_t value) const { |
| + StoreNonPointer(&raw_ptr()->kind_bits_, static_cast<uint8_t>(value)); |
| } |
| - RawError* Patch(const Script& script) const; |
| + static RawField* New(); |
| - RawString* PrivateName(const String& name) const; |
| + FINAL_HEAP_OBJECT_IMPLEMENTATION(Field, Object); |
| + friend class Class; |
| + friend class HeapProfiler; |
| +}; |
| - intptr_t index() const { return raw_ptr()->index_; } |
| - void set_index(intptr_t value) const { |
| - StoreNonPointer(&raw_ptr()->index_, value); |
| - } |
| - void Register() const; |
| +class LiteralToken : public Object { |
| + public: |
| + Token::Kind kind() const { return raw_ptr()->kind_; } |
| + RawString* literal() const { return raw_ptr()->literal_; } |
| + RawObject* value() const { return raw_ptr()->value_; } |
| - bool IsDebuggable() const { |
| - return raw_ptr()->debuggable_; |
| - } |
| - void set_debuggable(bool value) const { |
| - StoreNonPointer(&raw_ptr()->debuggable_, value); |
| + static intptr_t InstanceSize() { |
| + return RoundedAllocationSize(sizeof(RawLiteralToken)); |
| } |
| - bool is_dart_scheme() const { |
| - return raw_ptr()->is_dart_scheme_; |
| - } |
| - void set_is_dart_scheme(bool value) const { |
| - StoreNonPointer(&raw_ptr()->is_dart_scheme_, value); |
| - } |
| + static RawLiteralToken* New(); |
| + static RawLiteralToken* New(Token::Kind kind, const String& literal); |
| - bool IsCoreLibrary() const { |
| - return raw() == CoreLibrary(); |
| + private: |
| + void set_kind(Token::Kind kind) const { |
| + StoreNonPointer(&raw_ptr()->kind_, kind); |
| } |
| + void set_literal(const String& literal) const; |
| + void set_value(const Object& value) const; |
| - inline intptr_t UrlHash() const; |
| + FINAL_HEAP_OBJECT_IMPLEMENTATION(LiteralToken, Object); |
| + friend class Class; |
| +}; |
| - static RawLibrary* LookupLibrary(const String& url); |
| - static RawLibrary* GetLibrary(intptr_t index); |
| - static void InitCoreLibrary(Isolate* isolate); |
| - static void InitNativeWrappersLibrary(Isolate* isolate); |
| +class TokenStream : public Object { |
| + public: |
| + RawArray* TokenObjects() const; |
| + void SetTokenObjects(const Array& value) const; |
| - static RawLibrary* AsyncLibrary(); |
| - static RawLibrary* ConvertLibrary(); |
| - static RawLibrary* CoreLibrary(); |
| - static RawLibrary* CollectionLibrary(); |
| - static RawLibrary* DeveloperLibrary(); |
| - static RawLibrary* InternalLibrary(); |
| - static RawLibrary* IsolateLibrary(); |
| - static RawLibrary* MathLibrary(); |
| - static RawLibrary* MirrorsLibrary(); |
| - static RawLibrary* NativeWrappersLibrary(); |
| - static RawLibrary* ProfilerLibrary(); |
| - static RawLibrary* TypedDataLibrary(); |
| + RawExternalTypedData* GetStream() const; |
| + void SetStream(const ExternalTypedData& stream) const; |
| - // Eagerly compile all classes and functions in the library. |
| - static RawError* CompileAll(); |
| + RawString* GenerateSource() const; |
| + RawString* GenerateSource(intptr_t start, intptr_t end) const; |
| + intptr_t ComputeSourcePosition(intptr_t tok_pos) const; |
| + |
| + RawString* PrivateKey() const; |
| + |
| + static const intptr_t kBytesPerElement = 1; |
| + static const intptr_t kMaxElements = kSmiMax / kBytesPerElement; |
| -#if defined(DART_NO_SNAPSHOT) |
| - // Checks function fingerprints. Prints mismatches and aborts if |
| - // mismatch found. |
| - static void CheckFunctionFingerprints(); |
| -#endif // defined(DART_NO_SNAPSHOT). |
| + static intptr_t InstanceSize() { |
| + return RoundedAllocationSize(sizeof(RawTokenStream)); |
| + } |
| - static bool IsPrivate(const String& name); |
| - // Construct the full name of a corelib member. |
| - static const String& PrivateCoreLibName(const String& member); |
| - // Lookup class in the core lib which also contains various VM |
| - // helper methods and classes. Allow look up of private classes. |
| - static RawClass* LookupCoreClass(const String& class_name); |
| + static RawTokenStream* New(intptr_t length); |
| + static RawTokenStream* New(const Scanner::GrowableTokenStream& tokens, |
| + const String& private_key); |
| + // The class Iterator encapsulates iteration over the tokens |
| + // in a TokenStream object. |
| + class Iterator : ValueObject { |
| + public: |
| + enum StreamType { |
| + kNoNewlines, |
| + kAllTokens |
| + }; |
| - // Return Function::null() if function does not exist in libs. |
| - static RawFunction* GetFunction(const GrowableArray<Library*>& libs, |
| - const char* class_name, |
| - const char* function_name); |
| + Iterator(const TokenStream& tokens, |
| + intptr_t token_pos, |
| + Iterator::StreamType stream_type = kNoNewlines); |
| - // Character used to indicate a private identifier. |
| - static const char kPrivateIdentifierStart = '_'; |
| + void SetStream(const TokenStream& tokens, intptr_t token_pos); |
| + bool IsValid() const; |
| - // Character used to separate private identifiers from |
| - // the library-specific key. |
| - static const char kPrivateKeySeparator = '@'; |
| + inline Token::Kind CurrentTokenKind() const { |
| + return cur_token_kind_; |
| + } |
| - private: |
| - static const int kInitialImportsCapacity = 4; |
| - static const int kImportsCapacityIncrement = 8; |
| + Token::Kind LookaheadTokenKind(intptr_t num_tokens); |
| - static RawLibrary* New(); |
| + intptr_t CurrentPosition() const; |
| + void SetCurrentPosition(intptr_t value); |
| - void set_num_imports(intptr_t value) const { |
| - StoreNonPointer(&raw_ptr()->num_imports_, value); |
| - } |
| - bool HasExports() const; |
| - RawArray* loaded_scripts() const { return raw_ptr()->loaded_scripts_; } |
| - RawGrowableObjectArray* metadata() const { return raw_ptr()->metadata_; } |
| - RawArray* dictionary() const { return raw_ptr()->dictionary_; } |
| - void InitClassDictionary() const; |
| + void Advance(); |
| - RawArray* resolved_names() const { return raw_ptr()->resolved_names_; } |
| - void InitResolvedNamesCache(intptr_t size) const; |
| - void GrowResolvedNamesCache() const; |
| - bool LookupResolvedNamesCache(const String& name, Object* obj) const; |
| - void AddToResolvedNamesCache(const String& name, const Object& obj) const; |
| - void InvalidateResolvedName(const String& name) const; |
| - void InvalidateResolvedNamesCache() const; |
| + RawObject* CurrentToken() const; |
| + RawString* CurrentLiteral() const; |
| + RawString* MakeLiteralToken(const Object& obj) const; |
| - void InitImportList() const; |
| - void GrowDictionary(const Array& dict, intptr_t dict_size) const; |
| - static RawLibrary* NewLibraryHelper(const String& url, |
| - bool import_core_lib); |
| - RawObject* LookupEntry(const String& name, intptr_t *index) const; |
| + private: |
| + // Read token from the token stream (could be a simple token or an index |
| + // into the token objects array for IDENT or literal tokens). |
| + intptr_t ReadToken() { |
| + int64_t value = stream_.ReadUnsigned(); |
| + ASSERT((value >= 0) && (value <= kIntptrMax)); |
| + return static_cast<intptr_t>(value); |
| + } |
| - static bool IsKeyUsed(intptr_t key); |
| - void AllocatePrivateKey() const; |
| + TokenStream& tokens_; |
| + ExternalTypedData& data_; |
| + ReadStream stream_; |
| + Array& token_objects_; |
| + Object& obj_; |
| + intptr_t cur_token_pos_; |
| + Token::Kind cur_token_kind_; |
| + intptr_t cur_token_obj_index_; |
| + Iterator::StreamType stream_type_; |
| + }; |
| - RawString* MakeMetadataName(const Object& obj) const; |
| - RawField* GetMetadataField(const String& metaname) const; |
| - void AddMetadata(const Class& cls, |
| - const String& name, |
| - intptr_t token_pos) const; |
| + private: |
| + void SetPrivateKey(const String& value) const; |
| - FINAL_HEAP_OBJECT_IMPLEMENTATION(Library, Object); |
| + static RawTokenStream* New(); |
| + static void DataFinalizer(void* isolate_callback_data, |
| + Dart_WeakPersistentHandle handle, |
| + void *peer); |
| - friend class Bootstrap; |
| + FINAL_HEAP_OBJECT_IMPLEMENTATION(TokenStream, Object); |
| friend class Class; |
| - friend class Debugger; |
| - friend class DictionaryIterator; |
| - friend class Namespace; |
| - friend class Object; |
| }; |
| -// A Namespace contains the names in a library dictionary, filtered by |
| -// the show/hide combinators. |
| -class Namespace : public Object { |
| +class Script : public Object { |
| public: |
| - RawLibrary* library() const { return raw_ptr()->library_; } |
| - RawArray* show_names() const { return raw_ptr()->show_names_; } |
| - RawArray* hide_names() const { return raw_ptr()->hide_names_; } |
| + RawString* url() const { return raw_ptr()->url_; } |
| + bool HasSource() const; |
| + RawString* Source() const; |
| + RawString* GenerateSource() const; // Generates source code from Tokenstream. |
| + RawGrowableObjectArray* GenerateLineNumberArray() const; |
| + RawScript::Kind kind() const { |
| + return static_cast<RawScript::Kind>(raw_ptr()->kind_); |
| + } |
| + const char* GetKindAsCString() const; |
| + intptr_t line_offset() const { return raw_ptr()->line_offset_; } |
| + intptr_t col_offset() const { return raw_ptr()->col_offset_; } |
| - void AddMetadata(intptr_t token_pos, const Class& owner_class); |
| - RawObject* GetMetadata() const; |
| + RawTokenStream* tokens() const { return raw_ptr()->tokens_; } |
| + |
| + void Tokenize(const String& private_key) const; |
| + |
| + RawLibrary* FindLibrary() const; |
| + RawString* GetLine(intptr_t line_number) const; |
| + RawString* GetSnippet(intptr_t from_line, |
| + intptr_t from_column, |
| + intptr_t to_line, |
| + intptr_t to_column) const; |
| + |
| + void SetLocationOffset(intptr_t line_offset, intptr_t col_offset) const; |
| + |
| + void GetTokenLocation(intptr_t token_pos, |
| + intptr_t* line, intptr_t* column) const; |
| + |
| + // Returns index of first and last token on the given line. Returns both |
| + // indices < 0 if no token exists on or after the line. If a token exists |
| + // after, but not on given line, returns in *first_token_index the index of |
| + // the first token after the line, and a negative value in *last_token_index. |
| + void TokenRangeAtLine(intptr_t line_number, |
| + intptr_t* first_token_index, |
| + intptr_t* last_token_index) const; |
| static intptr_t InstanceSize() { |
| - return RoundedAllocationSize(sizeof(RawNamespace)); |
| + return RoundedAllocationSize(sizeof(RawScript)); |
| } |
| - bool HidesName(const String& name) const; |
| - RawObject* Lookup(const String& name) const; |
| - |
| - static RawNamespace* New(const Library& library, |
| - const Array& show_names, |
| - const Array& hide_names); |
| + static RawScript* New(const String& url, |
| + const String& source, |
| + RawScript::Kind kind); |
| private: |
| - static RawNamespace* New(); |
| + void set_url(const String& value) const; |
| + void set_source(const String& value) const; |
| + void set_kind(RawScript::Kind value) const; |
| + void set_tokens(const TokenStream& value) const; |
| - RawField* metadata_field() const { return raw_ptr()->metadata_field_; } |
| - void set_metadata_field(const Field& value) const; |
| + static RawScript* New(); |
| - FINAL_HEAP_OBJECT_IMPLEMENTATION(Namespace, Object); |
| + FINAL_HEAP_OBJECT_IMPLEMENTATION(Script, Object); |
| friend class Class; |
| }; |
| -class Instructions : public Object { |
| +class DictionaryIterator : public ValueObject { |
| public: |
| - intptr_t size() const { return raw_ptr()->size_; } // Excludes HeaderSize(). |
| - RawCode* code() const { return raw_ptr()->code_; } |
| - static intptr_t code_offset() { |
| - return OFFSET_OF(RawInstructions, code_); |
| - } |
| - RawArray* object_pool() const { return raw_ptr()->object_pool_; } |
| - static intptr_t object_pool_offset() { |
| - return OFFSET_OF(RawInstructions, object_pool_); |
| - } |
| + explicit DictionaryIterator(const Library& library); |
| - uword EntryPoint() const { |
| - return reinterpret_cast<uword>(raw_ptr()) + HeaderSize(); |
| - } |
| + bool HasNext() const { return next_ix_ < size_; } |
| - static const intptr_t kMaxElements = (kMaxInt32 - |
| - (sizeof(RawInstructions) + |
| - sizeof(RawObject) + |
| - (2 * OS::kMaxPreferredCodeAlignment))); |
| + // Returns next non-null raw object. |
| + RawObject* GetNext(); |
| - static intptr_t InstanceSize() { |
| - ASSERT(sizeof(RawInstructions) == |
| - OFFSET_OF_RETURNED_VALUE(RawInstructions, data)); |
| - return 0; |
| - } |
| + private: |
| + void MoveToNextObject(); |
| - static intptr_t InstanceSize(intptr_t size) { |
| - intptr_t instructions_size = Utils::RoundUp(size, |
| - OS::PreferredCodeAlignment()); |
| - intptr_t result = instructions_size + HeaderSize(); |
| - ASSERT(result % OS::PreferredCodeAlignment() == 0); |
| - return result; |
| - } |
| + const Array& array_; |
| + const int size_; // Number of elements to iterate over. |
| + int next_ix_; // Index of next element. |
| - static intptr_t HeaderSize() { |
| - intptr_t alignment = OS::PreferredCodeAlignment(); |
| - return Utils::RoundUp(sizeof(RawInstructions), alignment); |
| - } |
| + friend class ClassDictionaryIterator; |
| + friend class LibraryPrefixIterator; |
| + DISALLOW_COPY_AND_ASSIGN(DictionaryIterator); |
| +}; |
| - static RawInstructions* FromEntryPoint(uword entry_point) { |
| - return reinterpret_cast<RawInstructions*>( |
| - entry_point - HeaderSize() + kHeapObjectTag); |
| - } |
| - private: |
| - void set_size(intptr_t size) const { |
| - StoreNonPointer(&raw_ptr()->size_, size); |
| - } |
| - void set_code(RawCode* code) const { |
| - StorePointer(&raw_ptr()->code_, code); |
| - } |
| - void set_object_pool(RawArray* object_pool) const { |
| - StorePointer(&raw_ptr()->object_pool_, object_pool); |
| - } |
| +class ClassDictionaryIterator : public DictionaryIterator { |
| + public: |
| + enum IterationKind { |
| + kIteratePrivate, |
| + kNoIteratePrivate |
| + }; |
| - // New is a private method as RawInstruction and RawCode objects should |
| - // only be created using the Code::FinalizeCode method. This method creates |
| - // the RawInstruction and RawCode objects, sets up the pointer offsets |
| - // and links the two in a GC safe manner. |
| - static RawInstructions* New(intptr_t size); |
| + ClassDictionaryIterator(const Library& library, |
| + IterationKind kind = kNoIteratePrivate); |
| + |
| + bool HasNext() const { return (next_ix_ < size_) || (anon_ix_ < anon_size_); } |
| + |
| + // Returns a non-null raw class. |
| + RawClass* GetNextClass(); |
| - FINAL_HEAP_OBJECT_IMPLEMENTATION(Instructions, Object); |
| - friend class Class; |
| - friend class Code; |
| + private: |
| + void MoveToNextClass(); |
| + |
| + const Array& anon_array_; |
| + const int anon_size_; // Number of anonymous classes to iterate over. |
| + int anon_ix_; // Index of next anonymous class. |
| + |
| + DISALLOW_COPY_AND_ASSIGN(ClassDictionaryIterator); |
| }; |
| -class LocalVarDescriptors : public Object { |
| +class LibraryPrefixIterator : public DictionaryIterator { |
| public: |
| - intptr_t Length() const; |
| - |
| - RawString* GetName(intptr_t var_index) const; |
| + explicit LibraryPrefixIterator(const Library& library); |
| + RawLibraryPrefix* GetNext(); |
| + private: |
| + void Advance(); |
| + DISALLOW_COPY_AND_ASSIGN(LibraryPrefixIterator); |
| +}; |
| - void SetVar(intptr_t var_index, |
| - const String& name, |
| - RawLocalVarDescriptors::VarInfo* info) const; |
| - void GetInfo(intptr_t var_index, RawLocalVarDescriptors::VarInfo* info) const; |
| +class Library : public Object { |
| + public: |
| + RawString* name() const { return raw_ptr()->name_; } |
| + void SetName(const String& name) const; |
| - static const intptr_t kBytesPerElement = |
| - sizeof(RawLocalVarDescriptors::VarInfo); |
| - static const intptr_t kMaxElements = RawLocalVarDescriptors::kMaxIndex; |
| + RawString* url() const { return raw_ptr()->url_; } |
| + RawString* private_key() const { return raw_ptr()->private_key_; } |
| + bool LoadNotStarted() const { |
| + return raw_ptr()->load_state_ == RawLibrary::kAllocated; |
| + } |
| + bool LoadRequested() const { |
| + return raw_ptr()->load_state_ == RawLibrary::kLoadRequested; |
| + } |
| + bool LoadInProgress() const { |
| + return raw_ptr()->load_state_ == RawLibrary::kLoadInProgress; |
| + } |
| + void SetLoadRequested() const; |
| + void SetLoadInProgress() const; |
| + bool Loaded() const { return raw_ptr()->load_state_ == RawLibrary::kLoaded; } |
| + void SetLoaded() const; |
| + bool LoadFailed() const { |
| + return raw_ptr()->load_state_ == RawLibrary::kLoadError; |
| + } |
| + RawInstance* LoadError() const { return raw_ptr()->load_error_; } |
| + void SetLoadError(const Instance& error) const; |
| + RawInstance* TransitiveLoadError() const; |
| static intptr_t InstanceSize() { |
| - ASSERT(sizeof(RawLocalVarDescriptors) == |
| - OFFSET_OF_RETURNED_VALUE(RawLocalVarDescriptors, names)); |
| - return 0; |
| - } |
| - static intptr_t InstanceSize(intptr_t len) { |
| - ASSERT(0 <= len && len <= kMaxElements); |
| - return RoundedAllocationSize(sizeof(RawLocalVarDescriptors) |
| - + (len * kWordSize) // RawStrings for names. |
| - + (len * sizeof(RawLocalVarDescriptors::VarInfo))); |
| + return RoundedAllocationSize(sizeof(RawLibrary)); |
| } |
| - static RawLocalVarDescriptors* New(intptr_t num_variables); |
| + static RawLibrary* New(const String& url); |
| - static const char* KindToStr(intptr_t kind); |
| + // Evaluate the given expression as if it appeared in an top-level |
| + // method of this library and return the resulting value, or an |
| + // error object if evaluating the expression fails. The method has |
| + // the formal parameters given in param_names, and is invoked with |
| + // the argument values given in param_values. |
| + RawObject* Evaluate(const String& expr, |
| + const Array& param_names, |
| + const Array& param_values) const; |
| - private: |
| - FINAL_HEAP_OBJECT_IMPLEMENTATION(LocalVarDescriptors, Object); |
| - friend class Class; |
| - friend class Object; |
| -}; |
| + // Library scope name dictionary. |
| + // |
| + // TODO(turnidge): The Lookup functions are not consistent in how |
| + // they deal with private names. Go through and make them a bit |
| + // more regular. |
| + void AddClass(const Class& cls) const; |
| + void AddObject(const Object& obj, const String& name) const; |
| + void ReplaceObject(const Object& obj, const String& name) const; |
| + RawObject* LookupReExport(const String& name) const; |
| + RawObject* LookupObjectAllowPrivate(const String& name) const; |
| + RawObject* LookupLocalObjectAllowPrivate(const String& name) const; |
| + RawObject* LookupLocalObject(const String& name) const; |
| + RawObject* LookupImportedObject(const String& name) const; |
| + RawClass* LookupClass(const String& name) const; |
| + RawClass* LookupClassAllowPrivate(const String& name) const; |
| + RawClass* LookupLocalClass(const String& name) const; |
| + RawField* LookupFieldAllowPrivate(const String& name) const; |
| + RawField* LookupLocalField(const String& name) const; |
| + RawFunction* LookupFunctionAllowPrivate(const String& name) const; |
| + RawFunction* LookupLocalFunction(const String& name) const; |
| + RawLibraryPrefix* LookupLocalLibraryPrefix(const String& name) const; |
| + RawScript* LookupScript(const String& url) const; |
| + RawArray* LoadedScripts() const; |
| + // Resolve name in the scope of this library. First check the cache |
| + // of already resolved names for this library. Then look in the |
| + // local dictionary for the unmangled name N, the getter name get:N |
| + // and setter name set:N. |
| + // If the local dictionary contains no entry for these names, |
| + // look in the scopes of all libraries that are imported |
| + // without a library prefix. |
| + RawObject* ResolveName(const String& name) const; |
| -class PcDescriptors : public Object { |
| - public: |
| - static const intptr_t kBytesPerElement = 1; |
| - static const intptr_t kMaxElements = kMaxInt32 / kBytesPerElement; |
| + void AddAnonymousClass(const Class& cls) const; |
| - static intptr_t InstanceSize() { |
| - ASSERT(sizeof(RawPcDescriptors) == |
| - OFFSET_OF_RETURNED_VALUE(RawPcDescriptors, data)); |
| - return 0; |
| - } |
| - static intptr_t InstanceSize(intptr_t len) { |
| - ASSERT(0 <= len && len <= kMaxElements); |
| - return RoundedAllocationSize(sizeof(RawPcDescriptors) + len); |
| - } |
| + void AddExport(const Namespace& ns) const; |
| - static RawPcDescriptors* New(GrowableArray<uint8_t>* delta_encoded_data); |
| + void AddClassMetadata(const Class& cls, |
| + const Class& toplevel_class, |
| + intptr_t token_pos) const; |
| + void AddFieldMetadata(const Field& field, intptr_t token_pos) const; |
| + void AddFunctionMetadata(const Function& func, intptr_t token_pos) const; |
| + void AddLibraryMetadata(const Class& cls, intptr_t token_pos) const; |
| + void AddTypeParameterMetadata(const TypeParameter& param, |
| + intptr_t token_pos) const; |
| + RawObject* GetMetadata(const Object& obj) const; |
| - // Verify (assert) assumptions about pc descriptors in debug mode. |
| - void Verify(const Function& function) const; |
| + intptr_t num_anonymous_classes() const { return raw_ptr()->num_anonymous_; } |
| + RawArray* anonymous_classes() const { return raw_ptr()->anonymous_classes_; } |
| - static void PrintHeaderString(); |
| + // Library imports. |
| + RawArray* imports() const { return raw_ptr()->imports_; } |
| + RawArray* exports() const { return raw_ptr()->exports_; } |
| + void AddImport(const Namespace& ns) const; |
| + intptr_t num_imports() const { return raw_ptr()->num_imports_; } |
| + RawNamespace* ImportAt(intptr_t index) const; |
| + RawLibrary* ImportLibraryAt(intptr_t index) const; |
| + bool ImportsCorelib() const; |
| - void PrintToJSONObject(JSONObject* jsobj, bool ref) const; |
| + RawFunction* LookupFunctionInScript(const Script& script, |
| + intptr_t token_pos) const; |
| - // Encode integer in SLEB128 format. |
| - static void EncodeInteger(GrowableArray<uint8_t>* data, intptr_t value); |
| + // Resolving native methods for script loaded in the library. |
| + Dart_NativeEntryResolver native_entry_resolver() const { |
| + return raw_ptr()->native_entry_resolver_; |
| + } |
| + void set_native_entry_resolver(Dart_NativeEntryResolver value) const { |
| + StoreNonPointer(&raw_ptr()->native_entry_resolver_, value); |
| + } |
| + Dart_NativeEntrySymbol native_entry_symbol_resolver() const { |
| + return raw_ptr()->native_entry_symbol_resolver_; |
| + } |
| + void set_native_entry_symbol_resolver( |
| + Dart_NativeEntrySymbol native_symbol_resolver) const { |
| + StoreNonPointer(&raw_ptr()->native_entry_symbol_resolver_, |
| + native_symbol_resolver); |
| + } |
| - // Decode SLEB128 encoded integer. Update byte_index to the next integer. |
| - intptr_t DecodeInteger(intptr_t* byte_index) const; |
| + RawError* Patch(const Script& script) const; |
| - // We would have a VisitPointers function here to traverse the |
| - // pc descriptors table to visit objects if any in the table. |
| - // Note: never return a reference to a RawPcDescriptors::PcDescriptorRec |
| - // as the object can move. |
| - class Iterator : ValueObject { |
| - public: |
| - Iterator(const PcDescriptors& descriptors, intptr_t kind_mask) |
| - : descriptors_(descriptors), |
| - kind_mask_(kind_mask), |
| - byte_index_(0), |
| - cur_pc_offset_(0), |
| - cur_kind_(0), |
| - cur_deopt_id_(0), |
| - cur_token_pos_(0), |
| - cur_try_index_(0) { |
| - } |
| + RawString* PrivateName(const String& name) const; |
| - bool MoveNext() { |
| - // Moves to record that matches kind_mask_. |
| - while (byte_index_ < descriptors_.Length()) { |
| - int32_t merged_kind_try = descriptors_.DecodeInteger(&byte_index_); |
| - cur_kind_ = |
| - RawPcDescriptors::MergedKindTry::DecodeKind(merged_kind_try); |
| - cur_try_index_ = |
| - RawPcDescriptors::MergedKindTry::DecodeTryIndex(merged_kind_try); |
| + intptr_t index() const { return raw_ptr()->index_; } |
| + void set_index(intptr_t value) const { |
| + StoreNonPointer(&raw_ptr()->index_, value); |
| + } |
| - cur_pc_offset_ += descriptors_.DecodeInteger(&byte_index_); |
| - cur_deopt_id_ += descriptors_.DecodeInteger(&byte_index_); |
| - cur_token_pos_ += descriptors_.DecodeInteger(&byte_index_); |
| + void Register() const; |
| - if ((cur_kind_ & kind_mask_) != 0) { |
| - return true; // Current is valid. |
| - } |
| - } |
| - return false; |
| - } |
| + bool IsDebuggable() const { |
| + return raw_ptr()->debuggable_; |
| + } |
| + void set_debuggable(bool value) const { |
| + StoreNonPointer(&raw_ptr()->debuggable_, value); |
| + } |
| - uword PcOffset() const { return cur_pc_offset_; } |
| - intptr_t DeoptId() const { return cur_deopt_id_; } |
| - intptr_t TokenPos() const { return cur_token_pos_; } |
| - intptr_t TryIndex() const { return cur_try_index_; } |
| - RawPcDescriptors::Kind Kind() const { |
| - return static_cast<RawPcDescriptors::Kind>(cur_kind_); |
| - } |
| + bool is_dart_scheme() const { |
| + return raw_ptr()->is_dart_scheme_; |
| + } |
| + void set_is_dart_scheme(bool value) const { |
| + StoreNonPointer(&raw_ptr()->is_dart_scheme_, value); |
| + } |
| - private: |
| - friend class PcDescriptors; |
| + bool IsCoreLibrary() const { |
| + return raw() == CoreLibrary(); |
| + } |
| - // For nested iterations, starting at element after. |
| - explicit Iterator(const Iterator& iter) |
| - : ValueObject(), |
| - descriptors_(iter.descriptors_), |
| - kind_mask_(iter.kind_mask_), |
| - byte_index_(iter.byte_index_), |
| - cur_pc_offset_(iter.cur_pc_offset_), |
| - cur_kind_(iter.cur_kind_), |
| - cur_deopt_id_(iter.cur_deopt_id_), |
| - cur_token_pos_(iter.cur_token_pos_), |
| - cur_try_index_(iter.cur_try_index_) {} |
| + inline intptr_t UrlHash() const; |
| - const PcDescriptors& descriptors_; |
| - const intptr_t kind_mask_; |
| - intptr_t byte_index_; |
| + static RawLibrary* LookupLibrary(const String& url); |
| + static RawLibrary* GetLibrary(intptr_t index); |
| + |
| + static void InitCoreLibrary(Isolate* isolate); |
| + static void InitNativeWrappersLibrary(Isolate* isolate); |
| + |
| + static RawLibrary* AsyncLibrary(); |
| + static RawLibrary* ConvertLibrary(); |
| + static RawLibrary* CoreLibrary(); |
| + static RawLibrary* CollectionLibrary(); |
| + static RawLibrary* DeveloperLibrary(); |
| + static RawLibrary* InternalLibrary(); |
| + static RawLibrary* IsolateLibrary(); |
| + static RawLibrary* MathLibrary(); |
| + static RawLibrary* MirrorsLibrary(); |
| + static RawLibrary* NativeWrappersLibrary(); |
| + static RawLibrary* ProfilerLibrary(); |
| + static RawLibrary* TypedDataLibrary(); |
| - intptr_t cur_pc_offset_; |
| - intptr_t cur_kind_; |
| - intptr_t cur_deopt_id_; |
| - intptr_t cur_token_pos_; |
| - intptr_t cur_try_index_; |
| - }; |
| + // Eagerly compile all classes and functions in the library. |
| + static RawError* CompileAll(); |
| - private: |
| - static const char* KindAsStr(RawPcDescriptors::Kind kind); |
| +#if defined(DART_NO_SNAPSHOT) |
| + // Checks function fingerprints. Prints mismatches and aborts if |
| + // mismatch found. |
| + static void CheckFunctionFingerprints(); |
| +#endif // defined(DART_NO_SNAPSHOT). |
| - intptr_t Length() const; |
| - void SetLength(intptr_t value) const; |
| - void CopyData(GrowableArray<uint8_t>* data); |
| + static bool IsPrivate(const String& name); |
| + // Construct the full name of a corelib member. |
| + static const String& PrivateCoreLibName(const String& member); |
| + // Lookup class in the core lib which also contains various VM |
| + // helper methods and classes. Allow look up of private classes. |
| + static RawClass* LookupCoreClass(const String& class_name); |
| - FINAL_HEAP_OBJECT_IMPLEMENTATION(PcDescriptors, Object); |
| - friend class Class; |
| - friend class Object; |
| -}; |
| + // Return Function::null() if function does not exist in libs. |
| + static RawFunction* GetFunction(const GrowableArray<Library*>& libs, |
| + const char* class_name, |
| + const char* function_name); |
| -class Stackmap : public Object { |
| - public: |
| - static const intptr_t kNoMaximum = -1; |
| - static const intptr_t kNoMinimum = -1; |
| + // Character used to indicate a private identifier. |
| + static const char kPrivateIdentifierStart = '_'; |
| - bool IsObject(intptr_t index) const { |
| - ASSERT(InRange(index)); |
| - return GetBit(index); |
| - } |
| + // Character used to separate private identifiers from |
| + // the library-specific key. |
| + static const char kPrivateKeySeparator = '@'; |
| - intptr_t Length() const { return raw_ptr()->length_; } |
| + private: |
| + static const int kInitialImportsCapacity = 4; |
| + static const int kImportsCapacityIncrement = 8; |
| - uint32_t PcOffset() const { return raw_ptr()->pc_offset_; } |
| - void SetPcOffset(uint32_t value) const { |
| - ASSERT(value <= kMaxUint32); |
| - StoreNonPointer(&raw_ptr()->pc_offset_, value); |
| - } |
| + static RawLibrary* New(); |
| - intptr_t RegisterBitCount() const { return raw_ptr()->register_bit_count_; } |
| - void SetRegisterBitCount(intptr_t register_bit_count) const { |
| - ASSERT(register_bit_count < kMaxInt32); |
| - StoreNonPointer(&raw_ptr()->register_bit_count_, register_bit_count); |
| + void set_num_imports(intptr_t value) const { |
| + StoreNonPointer(&raw_ptr()->num_imports_, value); |
| } |
| + bool HasExports() const; |
| + RawArray* loaded_scripts() const { return raw_ptr()->loaded_scripts_; } |
| + RawGrowableObjectArray* metadata() const { return raw_ptr()->metadata_; } |
| + RawArray* dictionary() const { return raw_ptr()->dictionary_; } |
| + void InitClassDictionary() const; |
| - static const intptr_t kMaxLengthInBytes = kSmiMax; |
| + RawArray* resolved_names() const { return raw_ptr()->resolved_names_; } |
| + void InitResolvedNamesCache(intptr_t size) const; |
| + void GrowResolvedNamesCache() const; |
| + bool LookupResolvedNamesCache(const String& name, Object* obj) const; |
| + void AddToResolvedNamesCache(const String& name, const Object& obj) const; |
| + void InvalidateResolvedName(const String& name) const; |
| + void InvalidateResolvedNamesCache() const; |
| - static intptr_t InstanceSize() { |
| - ASSERT(sizeof(RawStackmap) == OFFSET_OF_RETURNED_VALUE(RawStackmap, data)); |
| - return 0; |
| - } |
| - static intptr_t InstanceSize(intptr_t length) { |
| - ASSERT(length >= 0); |
| - // The stackmap payload is in an array of bytes. |
| - intptr_t payload_size = |
| - Utils::RoundUp(length, kBitsPerByte) / kBitsPerByte; |
| - return RoundedAllocationSize(sizeof(RawStackmap) + payload_size); |
| - } |
| - static RawStackmap* New(intptr_t pc_offset, |
| - BitmapBuilder* bmap, |
| - intptr_t register_bit_count); |
| + void InitImportList() const; |
| + void GrowDictionary(const Array& dict, intptr_t dict_size) const; |
| + static RawLibrary* NewLibraryHelper(const String& url, |
| + bool import_core_lib); |
| + RawObject* LookupEntry(const String& name, intptr_t *index) const; |
| - private: |
| - void SetLength(intptr_t length) const { |
| - StoreNonPointer(&raw_ptr()->length_, length); |
| - } |
| + static bool IsKeyUsed(intptr_t key); |
| + void AllocatePrivateKey() const; |
| - bool InRange(intptr_t index) const { return index < Length(); } |
| + RawString* MakeMetadataName(const Object& obj) const; |
| + RawField* GetMetadataField(const String& metaname) const; |
| + void AddMetadata(const Class& cls, |
| + const String& name, |
| + intptr_t token_pos) const; |
| - bool GetBit(intptr_t bit_index) const; |
| - void SetBit(intptr_t bit_index, bool value) const; |
| + FINAL_HEAP_OBJECT_IMPLEMENTATION(Library, Object); |
| - FINAL_HEAP_OBJECT_IMPLEMENTATION(Stackmap, Object); |
| - friend class BitmapBuilder; |
| + friend class Bootstrap; |
| friend class Class; |
| + friend class Debugger; |
| + friend class DictionaryIterator; |
| + friend class Namespace; |
| + friend class Object; |
| }; |
| -class ExceptionHandlers : public Object { |
| +// A Namespace contains the names in a library dictionary, filtered by |
| +// the show/hide combinators. |
| +class Namespace : public Object { |
| public: |
| - static const intptr_t kInvalidPcOffset = 0; |
| - |
| - intptr_t num_entries() const; |
| - |
| - void GetHandlerInfo(intptr_t try_index, |
| - RawExceptionHandlers::HandlerInfo* info) const; |
| - |
| - uword HandlerPCOffset(intptr_t try_index) const; |
| - intptr_t OuterTryIndex(intptr_t try_index) const; |
| - bool NeedsStacktrace(intptr_t try_index) const; |
| - |
| - void SetHandlerInfo(intptr_t try_index, |
| - intptr_t outer_try_index, |
| - uword handler_pc_offset, |
| - bool needs_stacktrace, |
| - bool has_catch_all) const; |
| + RawLibrary* library() const { return raw_ptr()->library_; } |
| + RawArray* show_names() const { return raw_ptr()->show_names_; } |
| + RawArray* hide_names() const { return raw_ptr()->hide_names_; } |
| - RawArray* GetHandledTypes(intptr_t try_index) const; |
| - void SetHandledTypes(intptr_t try_index, const Array& handled_types) const; |
| - bool HasCatchAll(intptr_t try_index) const; |
| + void AddMetadata(intptr_t token_pos, const Class& owner_class); |
| + RawObject* GetMetadata() const; |
| static intptr_t InstanceSize() { |
| - ASSERT(sizeof(RawExceptionHandlers) == |
| - OFFSET_OF_RETURNED_VALUE(RawExceptionHandlers, data)); |
| - return 0; |
| - } |
| - static intptr_t InstanceSize(intptr_t len) { |
| - return RoundedAllocationSize( |
| - sizeof(RawExceptionHandlers) + |
| - (len * sizeof(RawExceptionHandlers::HandlerInfo))); |
| + return RoundedAllocationSize(sizeof(RawNamespace)); |
| } |
| - static RawExceptionHandlers* New(intptr_t num_handlers); |
| + bool HidesName(const String& name) const; |
| + RawObject* Lookup(const String& name) const; |
| - // We would have a VisitPointers function here to traverse the |
| - // exception handler table to visit objects if any in the table. |
| + static RawNamespace* New(const Library& library, |
| + const Array& show_names, |
| + const Array& hide_names); |
| private: |
| - // Pick somewhat arbitrary maximum number of exception handlers |
| - // for a function. This value is used to catch potentially |
| - // malicious code. |
| - static const intptr_t kMaxHandlers = 1024 * 1024; |
| + static RawNamespace* New(); |
| - void set_handled_types_data(const Array& value) const; |
| + RawField* metadata_field() const { return raw_ptr()->metadata_field_; } |
| + void set_metadata_field(const Field& value) const; |
| - FINAL_HEAP_OBJECT_IMPLEMENTATION(ExceptionHandlers, Object); |
| + FINAL_HEAP_OBJECT_IMPLEMENTATION(Namespace, Object); |
| friend class Class; |
| - friend class Object; |
| }; |
| -// Holds deopt information at one deoptimization point. The information consists |
| -// of two parts: |
| -// - first a prefix consiting of kMaterializeObject instructions describing |
| -// objects which had their allocation removed as part of AllocationSinking |
| -// pass and have to be materialized; |
| -// - followed by a list of DeoptInstr objects, specifying transformation |
| -// information for each slot in unoptimized frame(s). |
| -// Arguments for object materialization (class of instance to be allocated and |
| -// field-value pairs) are added as artificial slots to the expression stack |
| -// of the bottom-most frame. They are removed from the stack at the very end |
| -// of deoptimization by the deoptimization stub. |
| -class DeoptInfo : public AllStatic { |
| +class Instructions : public Object { |
| public: |
| - // Size of the frame part of the translation not counting kMaterializeObject |
| - // instructions in the prefix. |
| - static intptr_t FrameSize(const TypedData& packed); |
| + intptr_t size() const { return raw_ptr()->size_; } // Excludes HeaderSize(). |
| + RawCode* code() const { return raw_ptr()->code_; } |
| + static intptr_t code_offset() { |
| + return OFFSET_OF(RawInstructions, code_); |
| + } |
| + RawArray* object_pool() const { return raw_ptr()->object_pool_; } |
| + static intptr_t object_pool_offset() { |
| + return OFFSET_OF(RawInstructions, object_pool_); |
| + } |
| - // Returns the number of kMaterializeObject instructions in the prefix. |
| - static intptr_t NumMaterializations(const GrowableArray<DeoptInstr*>&); |
| + uword EntryPoint() const { |
| + return reinterpret_cast<uword>(raw_ptr()) + HeaderSize(); |
| + } |
| - // Unpack the entire translation into an array of deoptimization |
| - // instructions. This copies any shared suffixes into the array. |
| - static void Unpack(const Array& table, |
| - const TypedData& packed, |
| - GrowableArray<DeoptInstr*>* instructions); |
| + static const intptr_t kMaxElements = (kMaxInt32 - |
| + (sizeof(RawInstructions) + |
| + sizeof(RawObject) + |
| + (2 * OS::kMaxPreferredCodeAlignment))); |
| - // Size of the frame part of the translation not counting kMaterializeObject |
| - // instructions in the prefix. |
| - static const char* ToCString(const Array& table, |
| - const TypedData& packed); |
| + static intptr_t InstanceSize() { |
| + ASSERT(sizeof(RawInstructions) == |
| + OFFSET_OF_RETURNED_VALUE(RawInstructions, data)); |
| + return 0; |
| + } |
| - // Returns true iff decompression yields the same instructions as the |
| - // original. |
| - static bool VerifyDecompression(const GrowableArray<DeoptInstr*>& original, |
| - const Array& deopt_table, |
| - const TypedData& packed); |
| + static intptr_t InstanceSize(intptr_t size) { |
| + intptr_t instructions_size = Utils::RoundUp(size, |
| + OS::PreferredCodeAlignment()); |
| + intptr_t result = instructions_size + HeaderSize(); |
| + ASSERT(result % OS::PreferredCodeAlignment() == 0); |
| + return result; |
| + } |
| + |
| + static intptr_t HeaderSize() { |
| + intptr_t alignment = OS::PreferredCodeAlignment(); |
| + return Utils::RoundUp(sizeof(RawInstructions), alignment); |
| + } |
| + |
| + static RawInstructions* FromEntryPoint(uword entry_point) { |
| + return reinterpret_cast<RawInstructions*>( |
| + entry_point - HeaderSize() + kHeapObjectTag); |
| + } |
| + |
| + private: |
| + void set_size(intptr_t size) const { |
| + StoreNonPointer(&raw_ptr()->size_, size); |
| + } |
| + void set_code(RawCode* code) const { |
| + StorePointer(&raw_ptr()->code_, code); |
| + } |
| + void set_object_pool(RawArray* object_pool) const { |
| + StorePointer(&raw_ptr()->object_pool_, object_pool); |
| + } |
| + // New is a private method as RawInstruction and RawCode objects should |
| + // only be created using the Code::FinalizeCode method. This method creates |
| + // the RawInstruction and RawCode objects, sets up the pointer offsets |
| + // and links the two in a GC safe manner. |
| + static RawInstructions* New(intptr_t size); |
| - private: |
| - static void UnpackInto(const Array& table, |
| - const TypedData& packed, |
| - GrowableArray<DeoptInstr*>* instructions, |
| - intptr_t length); |
| + FINAL_HEAP_OBJECT_IMPLEMENTATION(Instructions, Object); |
| + friend class Class; |
| + friend class Code; |
| }; |
| -// Object holding information about an IC: test classes and their |
| -// corresponding targets. |
| -class ICData : public Object { |
| +class LocalVarDescriptors : public Object { |
| public: |
| - RawFunction* owner() const { |
| - return raw_ptr()->owner_; |
| - } |
| + intptr_t Length() const; |
| - RawString* target_name() const { |
| - return raw_ptr()->target_name_; |
| - } |
| + RawString* GetName(intptr_t var_index) const; |
| - RawArray* arguments_descriptor() const { |
| - return raw_ptr()->args_descriptor_; |
| - } |
| + void SetVar(intptr_t var_index, |
| + const String& name, |
| + RawLocalVarDescriptors::VarInfo* info) const; |
| - intptr_t NumArgsTested() const; |
| + void GetInfo(intptr_t var_index, RawLocalVarDescriptors::VarInfo* info) const; |
| - intptr_t deopt_id() const { |
| - return raw_ptr()->deopt_id_; |
| + static const intptr_t kBytesPerElement = |
| + sizeof(RawLocalVarDescriptors::VarInfo); |
| + static const intptr_t kMaxElements = RawLocalVarDescriptors::kMaxIndex; |
| + |
| + static intptr_t InstanceSize() { |
| + ASSERT(sizeof(RawLocalVarDescriptors) == |
| + OFFSET_OF_RETURNED_VALUE(RawLocalVarDescriptors, names)); |
| + return 0; |
| + } |
| + static intptr_t InstanceSize(intptr_t len) { |
| + ASSERT(0 <= len && len <= kMaxElements); |
| + return RoundedAllocationSize(sizeof(RawLocalVarDescriptors) |
| + + (len * kWordSize) // RawStrings for names. |
| + + (len * sizeof(RawLocalVarDescriptors::VarInfo))); |
| } |
| - // Note: only deopts with reasons before Unknown in this list are recorded in |
| - // the ICData. All other reasons are used purely for informational messages |
| - // printed during deoptimization itself. |
| - #define DEOPT_REASONS(V) \ |
| - V(BinarySmiOp) \ |
| - V(BinaryMintOp) \ |
| - V(DoubleToSmi) \ |
| - V(Unknown) \ |
| - V(PolymorphicInstanceCallTestFail) \ |
| - V(UnaryMintOp) \ |
| - V(BinaryDoubleOp) \ |
| - V(UnaryOp) \ |
| - V(UnboxInteger) \ |
| - V(CheckClass) \ |
| - V(CheckSmi) \ |
| - V(CheckArrayBound) \ |
| - V(AtCall) \ |
| - V(Uint32Load) \ |
| - V(GuardField) \ |
| - V(TestCids) \ |
| - V(NumReasons) \ |
| + static RawLocalVarDescriptors* New(intptr_t num_variables); |
| - enum DeoptReasonId { |
| - #define DEFINE_ENUM_LIST(name) kDeopt##name, |
| - DEOPT_REASONS(DEFINE_ENUM_LIST) |
| - #undef DEFINE_ENUM_LIST |
| - }; |
| + static const char* KindToStr(intptr_t kind); |
| - static const intptr_t kLastRecordedDeoptReason = kDeoptUnknown - 1; |
| + private: |
| + FINAL_HEAP_OBJECT_IMPLEMENTATION(LocalVarDescriptors, Object); |
| + friend class Class; |
| + friend class Object; |
| +}; |
| - enum DeoptFlags { |
| - // Deoptimization is caused by an optimistically hoisted instruction. |
| - kHoisted = 1 << 0, |
| - // Deoptimization is caused by an optimistically generalized bounds check. |
| - kGeneralized = 1 << 1 |
| - }; |
| +class PcDescriptors : public Object { |
| + public: |
| + static const intptr_t kBytesPerElement = 1; |
| + static const intptr_t kMaxElements = kMaxInt32 / kBytesPerElement; |
| - bool HasDeoptReasons() const { return DeoptReasons() != 0; } |
| - uint32_t DeoptReasons() const; |
| - void SetDeoptReasons(uint32_t reasons) const; |
| + static intptr_t InstanceSize() { |
| + ASSERT(sizeof(RawPcDescriptors) == |
| + OFFSET_OF_RETURNED_VALUE(RawPcDescriptors, data)); |
| + return 0; |
| + } |
| + static intptr_t InstanceSize(intptr_t len) { |
| + ASSERT(0 <= len && len <= kMaxElements); |
| + return RoundedAllocationSize(sizeof(RawPcDescriptors) + len); |
| + } |
| - bool HasDeoptReason(ICData::DeoptReasonId reason) const; |
| - void AddDeoptReason(ICData::DeoptReasonId reason) const; |
| + static RawPcDescriptors* New(GrowableArray<uint8_t>* delta_encoded_data); |
| - bool IssuedJSWarning() const; |
| - void SetIssuedJSWarning() const; |
| + // Verify (assert) assumptions about pc descriptors in debug mode. |
| + void Verify(const Function& function) const; |
| - // Return true if the target function of this IC data may check for (and |
| - // possibly issue) a Javascript compatibility warning. |
| - bool MayCheckForJSWarning() const; |
| + static void PrintHeaderString(); |
| - intptr_t NumberOfChecks() const; |
| + void PrintToJSONObject(JSONObject* jsobj, bool ref) const; |
| - // Discounts any checks with usage of zero. |
| - intptr_t NumberOfUsedChecks() const; |
| + // Encode integer in SLEB128 format. |
| + static void EncodeInteger(GrowableArray<uint8_t>* data, intptr_t value); |
| - static intptr_t InstanceSize() { |
| - return RoundedAllocationSize(sizeof(RawICData)); |
| - } |
| + // Decode SLEB128 encoded integer. Update byte_index to the next integer. |
| + intptr_t DecodeInteger(intptr_t* byte_index) const; |
| - static intptr_t target_name_offset() { |
| - return OFFSET_OF(RawICData, target_name_); |
| - } |
| + // We would have a VisitPointers function here to traverse the |
| + // pc descriptors table to visit objects if any in the table. |
| + // Note: never return a reference to a RawPcDescriptors::PcDescriptorRec |
| + // as the object can move. |
| + class Iterator : ValueObject { |
| + public: |
| + Iterator(const PcDescriptors& descriptors, intptr_t kind_mask) |
| + : descriptors_(descriptors), |
| + kind_mask_(kind_mask), |
| + byte_index_(0), |
| + cur_pc_offset_(0), |
| + cur_kind_(0), |
| + cur_deopt_id_(0), |
| + cur_token_pos_(0), |
| + cur_try_index_(0) { |
| + } |
| - static intptr_t state_bits_offset() { |
| - return OFFSET_OF(RawICData, state_bits_); |
| - } |
| + bool MoveNext() { |
| + // Moves to record that matches kind_mask_. |
| + while (byte_index_ < descriptors_.Length()) { |
| + int32_t merged_kind_try = descriptors_.DecodeInteger(&byte_index_); |
| + cur_kind_ = |
| + RawPcDescriptors::MergedKindTry::DecodeKind(merged_kind_try); |
| + cur_try_index_ = |
| + RawPcDescriptors::MergedKindTry::DecodeTryIndex(merged_kind_try); |
| - static intptr_t NumArgsTestedShift() { |
| - return kNumArgsTestedPos; |
| - } |
| + cur_pc_offset_ += descriptors_.DecodeInteger(&byte_index_); |
| + cur_deopt_id_ += descriptors_.DecodeInteger(&byte_index_); |
| + cur_token_pos_ += descriptors_.DecodeInteger(&byte_index_); |
| - static intptr_t NumArgsTestedMask() { |
| - return ((1 << kNumArgsTestedSize) - 1) << kNumArgsTestedPos; |
| - } |
| + if ((cur_kind_ & kind_mask_) != 0) { |
| + return true; // Current is valid. |
| + } |
| + } |
| + return false; |
| + } |
| - static intptr_t arguments_descriptor_offset() { |
| - return OFFSET_OF(RawICData, args_descriptor_); |
| - } |
| + uword PcOffset() const { return cur_pc_offset_; } |
| + intptr_t DeoptId() const { return cur_deopt_id_; } |
| + intptr_t TokenPos() const { return cur_token_pos_; } |
| + intptr_t TryIndex() const { return cur_try_index_; } |
| + RawPcDescriptors::Kind Kind() const { |
| + return static_cast<RawPcDescriptors::Kind>(cur_kind_); |
| + } |
| - static intptr_t ic_data_offset() { |
| - return OFFSET_OF(RawICData, ic_data_); |
| - } |
| + private: |
| + friend class PcDescriptors; |
| - static intptr_t owner_offset() { |
| - return OFFSET_OF(RawICData, owner_); |
| - } |
| + // For nested iterations, starting at element after. |
| + explicit Iterator(const Iterator& iter) |
| + : ValueObject(), |
| + descriptors_(iter.descriptors_), |
| + kind_mask_(iter.kind_mask_), |
| + byte_index_(iter.byte_index_), |
| + cur_pc_offset_(iter.cur_pc_offset_), |
| + cur_kind_(iter.cur_kind_), |
| + cur_deopt_id_(iter.cur_deopt_id_), |
| + cur_token_pos_(iter.cur_token_pos_), |
| + cur_try_index_(iter.cur_try_index_) {} |
| - // Used for unoptimized static calls when no class-ids are checked. |
| - void AddTarget(const Function& target) const; |
| + const PcDescriptors& descriptors_; |
| + const intptr_t kind_mask_; |
| + intptr_t byte_index_; |
| - // Adding checks. |
| + intptr_t cur_pc_offset_; |
| + intptr_t cur_kind_; |
| + intptr_t cur_deopt_id_; |
| + intptr_t cur_token_pos_; |
| + intptr_t cur_try_index_; |
| + }; |
| - // Adds one more class test to ICData. Length of 'classes' must be equal to |
| - // the number of arguments tested. Use only for num_args_tested > 1. |
| - void AddCheck(const GrowableArray<intptr_t>& class_ids, |
| - const Function& target) const; |
| - // Adds sorted so that Smi is the first class-id. Use only for |
| - // num_args_tested == 1. |
| - void AddReceiverCheck(intptr_t receiver_class_id, |
| - const Function& target, |
| - intptr_t count = 1) const; |
| + private: |
| + static const char* KindAsStr(RawPcDescriptors::Kind kind); |
| - // Retrieving checks. |
| + intptr_t Length() const; |
| + void SetLength(intptr_t value) const; |
| + void CopyData(GrowableArray<uint8_t>* data); |
| - // TODO(srdjan): GetCheckAt without target. |
| - void GetCheckAt(intptr_t index, |
| - GrowableArray<intptr_t>* class_ids, |
| - Function* target) const; |
| - // Only for 'num_args_checked == 1'. |
| - void GetOneClassCheckAt(intptr_t index, |
| - intptr_t* class_id, |
| - Function* target) const; |
| - // Only for 'num_args_checked == 1'. |
| - intptr_t GetCidAt(intptr_t index) const; |
| + FINAL_HEAP_OBJECT_IMPLEMENTATION(PcDescriptors, Object); |
| + friend class Class; |
| + friend class Object; |
| +}; |
| - intptr_t GetReceiverClassIdAt(intptr_t index) const; |
| - intptr_t GetClassIdAt(intptr_t index, intptr_t arg_nr) const; |
| - RawFunction* GetTargetAt(intptr_t index) const; |
| - RawFunction* GetTargetForReceiverClassId(intptr_t class_id) const; |
| +class Stackmap : public Object { |
| + public: |
| + static const intptr_t kNoMaximum = -1; |
| + static const intptr_t kNoMinimum = -1; |
| + |
| + bool IsObject(intptr_t index) const { |
| + ASSERT(InRange(index)); |
| + return GetBit(index); |
| + } |
| - void IncrementCountAt(intptr_t index, intptr_t value) const; |
| - void SetCountAt(intptr_t index, intptr_t value) const; |
| - intptr_t GetCountAt(intptr_t index) const; |
| - intptr_t AggregateCount() const; |
| + intptr_t Length() const { return raw_ptr()->length_; } |
| - // Returns this->raw() if num_args_tested == 1 and arg_nr == 1, otherwise |
| - // returns a new ICData object containing only unique arg_nr checks. |
| - // Returns only used entries. |
| - RawICData* AsUnaryClassChecksForArgNr(intptr_t arg_nr) const; |
| - RawICData* AsUnaryClassChecks() const { |
| - return AsUnaryClassChecksForArgNr(0); |
| + uint32_t PcOffset() const { return raw_ptr()->pc_offset_; } |
| + void SetPcOffset(uint32_t value) const { |
| + ASSERT(value <= kMaxUint32); |
| + StoreNonPointer(&raw_ptr()->pc_offset_, value); |
| } |
| - RawICData* AsUnaryClassChecksForCid( |
| - intptr_t cid, const Function& target) const; |
| - // Consider only used entries. |
| - bool AllTargetsHaveSameOwner(intptr_t owner_cid) const; |
| - bool AllReceiversAreNumbers() const; |
| - bool HasOneTarget() const; |
| - bool HasReceiverClassId(intptr_t class_id) const; |
| - |
| - static RawICData* New(const Function& owner, |
| - const String& target_name, |
| - const Array& arguments_descriptor, |
| - intptr_t deopt_id, |
| - intptr_t num_args_tested); |
| - static RawICData* NewFrom(const ICData& from, intptr_t num_args_tested); |
| + intptr_t RegisterBitCount() const { return raw_ptr()->register_bit_count_; } |
| + void SetRegisterBitCount(intptr_t register_bit_count) const { |
| + ASSERT(register_bit_count < kMaxInt32); |
| + StoreNonPointer(&raw_ptr()->register_bit_count_, register_bit_count); |
| + } |
| - static intptr_t TestEntryLengthFor(intptr_t num_args); |
| + static const intptr_t kMaxLengthInBytes = kSmiMax; |
| - static intptr_t TargetIndexFor(intptr_t num_args) { |
| - return num_args; |
| + static intptr_t InstanceSize() { |
| + ASSERT(sizeof(RawStackmap) == OFFSET_OF_RETURNED_VALUE(RawStackmap, data)); |
| + return 0; |
| } |
| + static intptr_t InstanceSize(intptr_t length) { |
| + ASSERT(length >= 0); |
| + // The stackmap payload is in an array of bytes. |
| + intptr_t payload_size = |
| + Utils::RoundUp(length, kBitsPerByte) / kBitsPerByte; |
| + return RoundedAllocationSize(sizeof(RawStackmap) + payload_size); |
| + } |
| + static RawStackmap* New(intptr_t pc_offset, |
| + BitmapBuilder* bmap, |
| + intptr_t register_bit_count); |
| - static intptr_t CountIndexFor(intptr_t num_args) { |
| - return (num_args + 1); |
| + private: |
| + void SetLength(intptr_t length) const { |
| + StoreNonPointer(&raw_ptr()->length_, length); |
| } |
| - bool IsUsedAt(intptr_t i) const; |
| + bool InRange(intptr_t index) const { return index < Length(); } |
| - void GetUsedCidsForTwoArgs(GrowableArray<intptr_t>* first, |
| - GrowableArray<intptr_t>* second) const; |
| + bool GetBit(intptr_t bit_index) const; |
| + void SetBit(intptr_t bit_index, bool value) const; |
| - // Range feedback tracking functionality. |
| + FINAL_HEAP_OBJECT_IMPLEMENTATION(Stackmap, Object); |
| + friend class BitmapBuilder; |
| + friend class Class; |
| +}; |
| - // For arithmetic operations we store range information for inputs and the |
| - // result. The goal is to discover: |
| - // |
| - // - on 32-bit platforms: |
| - // - when Mint operation is actually a int32/uint32 operation; |
| - // - when Smi operation produces non-smi results; |
| - // |
| - // - on 64-bit platforms: |
| - // - when Smi operation is actually int32/uint32 operation; |
| - // - when Mint operation produces non-smi results; |
| - // |
| - enum RangeFeedback { |
| - kSmiRange, |
| - kInt32Range, |
| - kUint32Range, |
| - kInt64Range |
| - }; |
| - // We use 4 bits per operand/result feedback. Our lattice allows us to |
| - // express the following states: |
| - // |
| - // - usmi 0000 [used only on 32bit platforms] |
| - // - smi 0001 |
| - // - uint31 0010 |
| - // - int32 0011 |
| - // - uint32 0100 |
| - // - int33 x1x1 |
| - // - int64 1xxx |
| - // |
| - // DecodeRangeFeedbackAt() helper maps these states into the RangeFeedback |
| - // enumeration. |
| - enum RangeFeedbackLatticeBits { |
| - kSignedRangeBit = 1 << 0, |
| - kInt32RangeBit = 1 << 1, |
| - kUint32RangeBit = 1 << 2, |
| - kInt64RangeBit = 1 << 3, |
| - kBitsPerRangeFeedback = 4, |
| - kRangeFeedbackMask = (1 << kBitsPerRangeFeedback) - 1, |
| - kRangeFeedbackSlots = 3 |
| - }; |
| +class ExceptionHandlers : public Object { |
| + public: |
| + static const intptr_t kInvalidPcOffset = 0; |
| - static bool IsValidRangeFeedbackIndex(intptr_t index) { |
| - return (0 <= index) && (index < kRangeFeedbackSlots); |
| - } |
| + intptr_t num_entries() const; |
| - static intptr_t RangeFeedbackShift(intptr_t index) { |
| - return (index * kBitsPerRangeFeedback) + kRangeFeedbackPos; |
| - } |
| + void GetHandlerInfo(intptr_t try_index, |
| + RawExceptionHandlers::HandlerInfo* info) const; |
| - static const char* RangeFeedbackToString(RangeFeedback feedback) { |
| - switch (feedback) { |
| - case kSmiRange: |
| - return "smi"; |
| - case kInt32Range: |
| - return "int32"; |
| - case kUint32Range: |
| - return "uint32"; |
| - case kInt64Range: |
| - return "int64"; |
| - default: |
| - UNREACHABLE(); |
| - return "?"; |
| - } |
| + uword HandlerPCOffset(intptr_t try_index) const; |
| + intptr_t OuterTryIndex(intptr_t try_index) const; |
| + bool NeedsStacktrace(intptr_t try_index) const; |
| + |
| + void SetHandlerInfo(intptr_t try_index, |
| + intptr_t outer_try_index, |
| + uword handler_pc_offset, |
| + bool needs_stacktrace, |
| + bool has_catch_all) const; |
| + |
| + RawArray* GetHandledTypes(intptr_t try_index) const; |
| + void SetHandledTypes(intptr_t try_index, const Array& handled_types) const; |
| + bool HasCatchAll(intptr_t try_index) const; |
| + |
| + static intptr_t InstanceSize() { |
| + ASSERT(sizeof(RawExceptionHandlers) == |
| + OFFSET_OF_RETURNED_VALUE(RawExceptionHandlers, data)); |
| + return 0; |
| + } |
| + static intptr_t InstanceSize(intptr_t len) { |
| + return RoundedAllocationSize( |
| + sizeof(RawExceptionHandlers) + |
| + (len * sizeof(RawExceptionHandlers::HandlerInfo))); |
| } |
| - // It is only meaningful to interptret range feedback stored in the ICData |
| - // when all checks are Mint or Smi. |
| - bool HasRangeFeedback() const; |
| - RangeFeedback DecodeRangeFeedbackAt(intptr_t idx) const; |
| + static RawExceptionHandlers* New(intptr_t num_handlers); |
| - void PrintToJSONArray(const JSONArray& jsarray, |
| - intptr_t token_pos, |
| - bool is_static_call) const; |
| + // We would have a VisitPointers function here to traverse the |
| + // exception handler table to visit objects if any in the table. |
| private: |
| - RawArray* ic_data() const { |
| - return raw_ptr()->ic_data_; |
| - } |
| + // Pick somewhat arbitrary maximum number of exception handlers |
| + // for a function. This value is used to catch potentially |
| + // malicious code. |
| + static const intptr_t kMaxHandlers = 1024 * 1024; |
| - void set_owner(const Function& value) const; |
| - void set_target_name(const String& value) const; |
| - void set_arguments_descriptor(const Array& value) const; |
| - void set_deopt_id(intptr_t value) const; |
| - void SetNumArgsTested(intptr_t value) const; |
| - void set_ic_data(const Array& value) const; |
| - void set_state_bits(uint32_t bits) const; |
| + void set_handled_types_data(const Array& value) const; |
| - enum { |
| - kNumArgsTestedPos = 0, |
| - kNumArgsTestedSize = 2, |
| - kDeoptReasonPos = kNumArgsTestedPos + kNumArgsTestedSize, |
| - kDeoptReasonSize = kLastRecordedDeoptReason + 1, |
| - kIssuedJSWarningBit = kDeoptReasonPos + kDeoptReasonSize, |
| - kRangeFeedbackPos = kIssuedJSWarningBit + 1, |
| - kRangeFeedbackSize = kBitsPerRangeFeedback * kRangeFeedbackSlots |
| - }; |
| + FINAL_HEAP_OBJECT_IMPLEMENTATION(ExceptionHandlers, Object); |
| + friend class Class; |
| + friend class Object; |
| +}; |
| - class NumArgsTestedBits : public BitField<uint32_t, |
| - kNumArgsTestedPos, kNumArgsTestedSize> {}; // NOLINT |
| - class DeoptReasonBits : public BitField<uint32_t, |
| - ICData::kDeoptReasonPos, ICData::kDeoptReasonSize> {}; // NOLINT |
| - class IssuedJSWarningBit : public BitField<bool, kIssuedJSWarningBit, 1> {}; |
| - class RangeFeedbackBits : public BitField<uint32_t, |
| - ICData::kRangeFeedbackPos, ICData::kRangeFeedbackSize> {}; // NOLINT |
| -#if defined(DEBUG) |
| - // Used in asserts to verify that a check is not added twice. |
| - bool HasCheck(const GrowableArray<intptr_t>& cids) const; |
| -#endif // DEBUG |
| +// Holds deopt information at one deoptimization point. The information consists |
| +// of two parts: |
| +// - first a prefix consiting of kMaterializeObject instructions describing |
| +// objects which had their allocation removed as part of AllocationSinking |
| +// pass and have to be materialized; |
| +// - followed by a list of DeoptInstr objects, specifying transformation |
| +// information for each slot in unoptimized frame(s). |
| +// Arguments for object materialization (class of instance to be allocated and |
| +// field-value pairs) are added as artificial slots to the expression stack |
| +// of the bottom-most frame. They are removed from the stack at the very end |
| +// of deoptimization by the deoptimization stub. |
| +class DeoptInfo : public AllStatic { |
| + public: |
| + // Size of the frame part of the translation not counting kMaterializeObject |
| + // instructions in the prefix. |
| + static intptr_t FrameSize(const TypedData& packed); |
| - intptr_t TestEntryLength() const; |
| - void WriteSentinel(const Array& data) const; |
| + // Returns the number of kMaterializeObject instructions in the prefix. |
| + static intptr_t NumMaterializations(const GrowableArray<DeoptInstr*>&); |
| - FINAL_HEAP_OBJECT_IMPLEMENTATION(ICData, Object); |
| - friend class Class; |
| + // Unpack the entire translation into an array of deoptimization |
| + // instructions. This copies any shared suffixes into the array. |
| + static void Unpack(const Array& table, |
| + const TypedData& packed, |
| + GrowableArray<DeoptInstr*>* instructions); |
| + |
| + // Size of the frame part of the translation not counting kMaterializeObject |
| + // instructions in the prefix. |
| + static const char* ToCString(const Array& table, |
| + const TypedData& packed); |
| + |
| + // Returns true iff decompression yields the same instructions as the |
| + // original. |
| + static bool VerifyDecompression(const GrowableArray<DeoptInstr*>& original, |
| + const Array& deopt_table, |
| + const TypedData& packed); |
| + |
| + |
| + private: |
| + static void UnpackInto(const Array& table, |
| + const TypedData& packed, |
| + GrowableArray<DeoptInstr*>* instructions, |
| + intptr_t length); |
| }; |