OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/object.h" | 5 #include "vm/object.h" |
6 | 6 |
7 #include "include/dart_api.h" | 7 #include "include/dart_api.h" |
8 #include "platform/assert.h" | 8 #include "platform/assert.h" |
9 #include "vm/assembler.h" | 9 #include "vm/assembler.h" |
10 #include "vm/cpu.h" | 10 #include "vm/cpu.h" |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
49 DEFINE_FLAG(int, huge_method_cutoff_in_code_size, 200000, | 49 DEFINE_FLAG(int, huge_method_cutoff_in_code_size, 200000, |
50 "Huge method cutoff in unoptimized code size (in bytes)."); | 50 "Huge method cutoff in unoptimized code size (in bytes)."); |
51 DEFINE_FLAG(int, huge_method_cutoff_in_tokens, 20000, | 51 DEFINE_FLAG(int, huge_method_cutoff_in_tokens, 20000, |
52 "Huge method cutoff in tokens: Disables optimizations for huge methods."); | 52 "Huge method cutoff in tokens: Disables optimizations for huge methods."); |
53 DEFINE_FLAG(bool, overlap_type_arguments, true, | 53 DEFINE_FLAG(bool, overlap_type_arguments, true, |
54 "When possible, partially or fully overlap the type arguments of a type " | 54 "When possible, partially or fully overlap the type arguments of a type " |
55 "with the type arguments of its super type."); | 55 "with the type arguments of its super type."); |
56 DEFINE_FLAG(bool, show_internal_names, false, | 56 DEFINE_FLAG(bool, show_internal_names, false, |
57 "Show names of internal classes (e.g. \"OneByteString\") in error messages " | 57 "Show names of internal classes (e.g. \"OneByteString\") in error messages " |
58 "instead of showing the corresponding interface names (e.g. \"String\")"); | 58 "instead of showing the corresponding interface names (e.g. \"String\")"); |
59 DEFINE_FLAG(bool, throw_on_javascript_int_overflow, false, | |
60 "Throw an exception when the result of an integer calculation will not " | |
61 "fit into a javascript integer."); | |
62 DEFINE_FLAG(bool, trace_cha, false, "Trace CHA operations"); | 59 DEFINE_FLAG(bool, trace_cha, false, "Trace CHA operations"); |
63 DEFINE_FLAG(bool, use_field_guards, true, "Guard field cids."); | 60 DEFINE_FLAG(bool, use_field_guards, true, "Guard field cids."); |
64 DEFINE_FLAG(bool, use_lib_cache, true, "Use library name cache"); | 61 DEFINE_FLAG(bool, use_lib_cache, true, "Use library name cache"); |
65 DEFINE_FLAG(bool, trace_field_guards, false, "Trace changes in field's cids."); | 62 DEFINE_FLAG(bool, trace_field_guards, false, "Trace changes in field's cids."); |
66 DEFINE_FLAG(bool, ignore_patch_signature_mismatch, false, | 63 DEFINE_FLAG(bool, ignore_patch_signature_mismatch, false, |
67 "Ignore patch file member signature mismatch."); | 64 "Ignore patch file member signature mismatch."); |
68 | 65 |
69 DECLARE_FLAG(charp, coverage_dir); | 66 DECLARE_FLAG(charp, coverage_dir); |
70 DECLARE_FLAG(bool, load_deferred_eagerly); | 67 DECLARE_FLAG(bool, load_deferred_eagerly); |
71 DECLARE_FLAG(bool, precompilation); | 68 DECLARE_FLAG(bool, precompilation); |
(...skipping 11666 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11738 } | 11735 } |
11739 | 11736 |
11740 | 11737 |
11741 void ICData::AddDeoptReason(DeoptReasonId reason) const { | 11738 void ICData::AddDeoptReason(DeoptReasonId reason) const { |
11742 if (reason <= kLastRecordedDeoptReason) { | 11739 if (reason <= kLastRecordedDeoptReason) { |
11743 SetDeoptReasons(DeoptReasons() | (1 << reason)); | 11740 SetDeoptReasons(DeoptReasons() | (1 << reason)); |
11744 } | 11741 } |
11745 } | 11742 } |
11746 | 11743 |
11747 | 11744 |
11748 bool ICData::IssuedJSWarning() const { | |
11749 return IssuedJSWarningBit::decode(raw_ptr()->state_bits_); | |
11750 } | |
11751 | |
11752 | |
11753 void ICData::SetIssuedJSWarning() const { | |
11754 StoreNonPointer(&raw_ptr()->state_bits_, | |
11755 IssuedJSWarningBit::update(true, raw_ptr()->state_bits_)); | |
11756 } | |
11757 | |
11758 | |
11759 bool ICData::MayCheckForJSWarning() const { | |
11760 const String& name = String::Handle(target_name()); | |
11761 // Warning issued from native code. | |
11762 // Calling sequence is decoded to obtain ic data in order to check if a | |
11763 // warning has already been issued. | |
11764 if (name.Equals(Library::PrivateCoreLibName(Symbols::_instanceOf())) || | |
11765 name.Equals(Library::PrivateCoreLibName(Symbols::_as()))) { | |
11766 return true; | |
11767 } | |
11768 // Warning issued in ic miss handler. | |
11769 // No decoding necessary, so allow optimization if warning already issued. | |
11770 if (name.Equals(Symbols::toString()) && !IssuedJSWarning()) { | |
11771 return true; | |
11772 } | |
11773 return false; | |
11774 } | |
11775 | |
11776 | |
11777 void ICData::set_state_bits(uint32_t bits) const { | 11745 void ICData::set_state_bits(uint32_t bits) const { |
11778 StoreNonPointer(&raw_ptr()->state_bits_, bits); | 11746 StoreNonPointer(&raw_ptr()->state_bits_, bits); |
11779 } | 11747 } |
11780 | 11748 |
11781 | 11749 |
11782 intptr_t ICData::TestEntryLengthFor(intptr_t num_args) { | 11750 intptr_t ICData::TestEntryLengthFor(intptr_t num_args) { |
11783 return num_args + 1 /* target function*/ + 1 /* frequency */; | 11751 return num_args + 1 /* target function*/ + 1 /* frequency */; |
11784 } | 11752 } |
11785 | 11753 |
11786 | 11754 |
(...skipping 5117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
16904 } | 16872 } |
16905 | 16873 |
16906 | 16874 |
16907 const char* Integer::ToCString() const { | 16875 const char* Integer::ToCString() const { |
16908 // Integer is an interface. No instances of Integer should exist except null. | 16876 // Integer is an interface. No instances of Integer should exist except null. |
16909 ASSERT(IsNull()); | 16877 ASSERT(IsNull()); |
16910 return "NULL Integer"; | 16878 return "NULL Integer"; |
16911 } | 16879 } |
16912 | 16880 |
16913 | 16881 |
16914 // Throw JavascriptIntegerOverflow exception. | |
16915 static void ThrowJavascriptIntegerOverflow(const Integer& i) { | |
16916 const Array& exc_args = Array::Handle(Array::New(1)); | |
16917 const String& i_str = String::Handle(String::New(i.ToCString())); | |
16918 exc_args.SetAt(0, i_str); | |
16919 Exceptions::ThrowByType(Exceptions::kJavascriptIntegerOverflowError, | |
16920 exc_args); | |
16921 } | |
16922 | |
16923 | |
16924 RawInteger* Integer::New(const String& str, Heap::Space space) { | 16882 RawInteger* Integer::New(const String& str, Heap::Space space) { |
16925 // We are not supposed to have integers represented as two byte strings. | 16883 // We are not supposed to have integers represented as two byte strings. |
16926 ASSERT(str.IsOneByteString()); | 16884 ASSERT(str.IsOneByteString()); |
16927 int64_t value; | 16885 int64_t value; |
16928 if (!OS::StringToInt64(str.ToCString(), &value)) { | 16886 if (!OS::StringToInt64(str.ToCString(), &value)) { |
16929 const Bigint& big = Bigint::Handle( | 16887 const Bigint& big = Bigint::Handle( |
16930 Bigint::NewFromCString(str.ToCString(), space)); | 16888 Bigint::NewFromCString(str.ToCString(), space)); |
16931 ASSERT(!big.FitsIntoSmi()); | 16889 ASSERT(!big.FitsIntoSmi()); |
16932 ASSERT(!big.FitsIntoInt64()); | 16890 ASSERT(!big.FitsIntoInt64()); |
16933 if (FLAG_throw_on_javascript_int_overflow) { | |
16934 ThrowJavascriptIntegerOverflow(big); | |
16935 } | |
16936 return big.raw(); | 16891 return big.raw(); |
16937 } | 16892 } |
16938 return Integer::New(value, space); | 16893 return Integer::New(value, space); |
16939 } | 16894 } |
16940 | 16895 |
16941 | 16896 |
16942 // This is called from LiteralToken::New() in the parser, so we can't | |
16943 // raise an exception for javascript overflow here. Instead we do it in | |
16944 // Parser::CurrentIntegerLiteral(), which is the point in the parser where | |
16945 // integer literals escape, so we can call Parser::ErrorMsg(). | |
16946 RawInteger* Integer::NewCanonical(const String& str) { | 16897 RawInteger* Integer::NewCanonical(const String& str) { |
16947 // We are not supposed to have integers represented as two byte strings. | 16898 // We are not supposed to have integers represented as two byte strings. |
16948 ASSERT(str.IsOneByteString()); | 16899 ASSERT(str.IsOneByteString()); |
16949 int64_t value; | 16900 int64_t value; |
16950 if (!OS::StringToInt64(str.ToCString(), &value)) { | 16901 if (!OS::StringToInt64(str.ToCString(), &value)) { |
16951 const Bigint& big = Bigint::Handle(Bigint::NewCanonical(str)); | 16902 const Bigint& big = Bigint::Handle(Bigint::NewCanonical(str)); |
16952 ASSERT(!big.FitsIntoSmi()); | 16903 ASSERT(!big.FitsIntoSmi()); |
16953 ASSERT(!big.FitsIntoInt64()); | 16904 ASSERT(!big.FitsIntoInt64()); |
16954 return big.raw(); | 16905 return big.raw(); |
16955 } | 16906 } |
16956 if (Smi::IsValid(value)) { | 16907 if (Smi::IsValid(value)) { |
16957 return Smi::New(static_cast<intptr_t>(value)); | 16908 return Smi::New(static_cast<intptr_t>(value)); |
16958 } | 16909 } |
16959 return Mint::NewCanonical(value); | 16910 return Mint::NewCanonical(value); |
16960 } | 16911 } |
16961 | 16912 |
16962 | 16913 |
16963 RawInteger* Integer::New(int64_t value, Heap::Space space, const bool silent) { | 16914 RawInteger* Integer::New(int64_t value, Heap::Space space) { |
16964 const bool is_smi = Smi::IsValid(value); | 16915 const bool is_smi = Smi::IsValid(value); |
16965 if (!silent && | |
16966 FLAG_throw_on_javascript_int_overflow && | |
16967 !Utils::IsJavascriptInt(value)) { | |
16968 const Integer& i = is_smi ? | |
16969 Integer::Handle(Smi::New(static_cast<intptr_t>(value))) : | |
16970 Integer::Handle(Mint::New(value, space)); | |
16971 ThrowJavascriptIntegerOverflow(i); | |
16972 } | |
16973 if (is_smi) { | 16916 if (is_smi) { |
16974 return Smi::New(static_cast<intptr_t>(value)); | 16917 return Smi::New(static_cast<intptr_t>(value)); |
16975 } | 16918 } |
16976 return Mint::New(value, space); | 16919 return Mint::New(value, space); |
16977 } | 16920 } |
16978 | 16921 |
16979 | 16922 |
16980 RawInteger* Integer::NewFromUint64(uint64_t value, Heap::Space space) { | 16923 RawInteger* Integer::NewFromUint64(uint64_t value, Heap::Space space) { |
16981 if (value > static_cast<uint64_t>(Mint::kMaxValue)) { | 16924 if (value > static_cast<uint64_t>(Mint::kMaxValue)) { |
16982 if (FLAG_throw_on_javascript_int_overflow) { | |
16983 const Integer &i = Integer::Handle(Bigint::NewFromUint64(value, space)); | |
16984 ThrowJavascriptIntegerOverflow(i); | |
16985 } | |
16986 return Bigint::NewFromUint64(value, space); | 16925 return Bigint::NewFromUint64(value, space); |
16987 } else { | 16926 } else { |
16988 return Integer::New(value, space); | 16927 return Integer::New(value, space); |
16989 } | 16928 } |
16990 } | 16929 } |
16991 | 16930 |
16992 | 16931 |
16993 bool Integer::Equals(const Instance& other) const { | 16932 bool Integer::Equals(const Instance& other) const { |
16994 // Integer is an abstract class. | 16933 // Integer is an abstract class. |
16995 UNREACHABLE(); | 16934 UNREACHABLE(); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
17039 } | 16978 } |
17040 | 16979 |
17041 | 16980 |
17042 int Integer::CompareWith(const Integer& other) const { | 16981 int Integer::CompareWith(const Integer& other) const { |
17043 // Integer is an abstract class. | 16982 // Integer is an abstract class. |
17044 UNREACHABLE(); | 16983 UNREACHABLE(); |
17045 return 0; | 16984 return 0; |
17046 } | 16985 } |
17047 | 16986 |
17048 | 16987 |
17049 // Returns true if the signed Integer does not fit into a | |
17050 // Javascript integer. | |
17051 bool Integer::CheckJavascriptIntegerOverflow() const { | |
17052 // Always overflow if the value doesn't fit into an int64_t. | |
17053 int64_t value = 1ULL << 63; | |
17054 if (IsSmi()) { | |
17055 value = AsInt64Value(); | |
17056 } else if (IsMint()) { | |
17057 Mint& mint = Mint::Handle(); | |
17058 mint ^= raw(); | |
17059 value = mint.value(); | |
17060 } else { | |
17061 if (Bigint::Cast(*this).FitsIntoInt64()) { | |
17062 value = AsInt64Value(); | |
17063 } | |
17064 } | |
17065 return !Utils::IsJavascriptInt(value); | |
17066 } | |
17067 | |
17068 | |
17069 RawInteger* Integer::AsValidInteger() const { | 16988 RawInteger* Integer::AsValidInteger() const { |
17070 if (FLAG_throw_on_javascript_int_overflow && | |
17071 CheckJavascriptIntegerOverflow()) { | |
17072 ThrowJavascriptIntegerOverflow(*this); | |
17073 } | |
17074 if (IsSmi()) return raw(); | 16989 if (IsSmi()) return raw(); |
17075 if (IsMint()) { | 16990 if (IsMint()) { |
17076 Mint& mint = Mint::Handle(); | 16991 Mint& mint = Mint::Handle(); |
17077 mint ^= raw(); | 16992 mint ^= raw(); |
17078 if (Smi::IsValid(mint.value())) { | 16993 if (Smi::IsValid(mint.value())) { |
17079 return Smi::New(static_cast<intptr_t>(mint.value())); | 16994 return Smi::New(static_cast<intptr_t>(mint.value())); |
17080 } else { | 16995 } else { |
17081 return raw(); | 16996 return raw(); |
17082 } | 16997 } |
17083 } | 16998 } |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
17233 UNIMPLEMENTED(); | 17148 UNIMPLEMENTED(); |
17234 } | 17149 } |
17235 } | 17150 } |
17236 return Integer::null(); // Notify caller that a bigint operation is required. | 17151 return Integer::null(); // Notify caller that a bigint operation is required. |
17237 } | 17152 } |
17238 | 17153 |
17239 | 17154 |
17240 // TODO(srdjan): Clarify handling of negative right operand in a shift op. | 17155 // TODO(srdjan): Clarify handling of negative right operand in a shift op. |
17241 RawInteger* Smi::ShiftOp(Token::Kind kind, | 17156 RawInteger* Smi::ShiftOp(Token::Kind kind, |
17242 const Smi& other, | 17157 const Smi& other, |
17243 Heap::Space space, | 17158 Heap::Space space) const { |
17244 const bool silent) const { | |
17245 intptr_t result = 0; | 17159 intptr_t result = 0; |
17246 const intptr_t left_value = Value(); | 17160 const intptr_t left_value = Value(); |
17247 const intptr_t right_value = other.Value(); | 17161 const intptr_t right_value = other.Value(); |
17248 ASSERT(right_value >= 0); | 17162 ASSERT(right_value >= 0); |
17249 switch (kind) { | 17163 switch (kind) { |
17250 case Token::kSHL: { | 17164 case Token::kSHL: { |
17251 if ((left_value == 0) || (right_value == 0)) { | 17165 if ((left_value == 0) || (right_value == 0)) { |
17252 return raw(); | 17166 return raw(); |
17253 } | 17167 } |
17254 { // Check for overflow. | 17168 { // Check for overflow. |
17255 int cnt = Utils::BitLength(left_value); | 17169 int cnt = Utils::BitLength(left_value); |
17256 if ((cnt + right_value) > Smi::kBits) { | 17170 if ((cnt + right_value) > Smi::kBits) { |
17257 if ((cnt + right_value) > Mint::kBits) { | 17171 if ((cnt + right_value) > Mint::kBits) { |
17258 return Bigint::NewFromShiftedInt64(left_value, right_value, space); | 17172 return Bigint::NewFromShiftedInt64(left_value, right_value, space); |
17259 } else { | 17173 } else { |
17260 int64_t left_64 = left_value; | 17174 int64_t left_64 = left_value; |
17261 return Integer::New(left_64 << right_value, space, silent); | 17175 return Integer::New(left_64 << right_value, space); |
17262 } | 17176 } |
17263 } | 17177 } |
17264 } | 17178 } |
17265 result = left_value << right_value; | 17179 result = left_value << right_value; |
17266 break; | 17180 break; |
17267 } | 17181 } |
17268 case Token::kSHR: { | 17182 case Token::kSHR: { |
17269 const intptr_t shift_amount = | 17183 const intptr_t shift_amount = |
17270 (right_value >= kBitsPerWord) ? (kBitsPerWord - 1) : right_value; | 17184 (right_value >= kBitsPerWord) ? (kBitsPerWord - 1) : right_value; |
17271 result = left_value >> shift_amount; | 17185 result = left_value >> shift_amount; |
(...skipping 4220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
21492 return UserTag::null(); | 21406 return UserTag::null(); |
21493 } | 21407 } |
21494 | 21408 |
21495 | 21409 |
21496 const char* UserTag::ToCString() const { | 21410 const char* UserTag::ToCString() const { |
21497 const String& tag_label = String::Handle(label()); | 21411 const String& tag_label = String::Handle(label()); |
21498 return tag_label.ToCString(); | 21412 return tag_label.ToCString(); |
21499 } | 21413 } |
21500 | 21414 |
21501 } // namespace dart | 21415 } // namespace dart |
OLD | NEW |