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); |
}; |