Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(70)

Unified Diff: runtime/vm/object.h

Issue 1149403005: Prevent excessive deoptimization when optimistically assuming Smi in typed data stores. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: ws Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/flow_graph_optimizer.cc ('k') | runtime/vm/object.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
};
« no previous file with comments | « runtime/vm/flow_graph_optimizer.cc ('k') | runtime/vm/object.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698