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

Side by Side Diff: runtime/vm/object.cc

Issue 21301003: Fixes javascript integer overflow check. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 4 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
45 DEFINE_FLAG(bool, show_internal_names, false, 45 DEFINE_FLAG(bool, show_internal_names, false,
46 "Show names of internal classes (e.g. \"OneByteString\") in error messages " 46 "Show names of internal classes (e.g. \"OneByteString\") in error messages "
47 "instead of showing the corresponding interface names (e.g. \"String\")"); 47 "instead of showing the corresponding interface names (e.g. \"String\")");
48 DEFINE_FLAG(bool, trace_disabling_optimized_code, false, 48 DEFINE_FLAG(bool, trace_disabling_optimized_code, false,
49 "Trace disabling optimized code."); 49 "Trace disabling optimized code.");
50 DEFINE_FLAG(int, huge_method_cutoff_in_tokens, 20000, 50 DEFINE_FLAG(int, huge_method_cutoff_in_tokens, 20000,
51 "Huge method cutoff in tokens: Disables optimizations for huge methods."); 51 "Huge method cutoff in tokens: Disables optimizations for huge methods.");
52 DEFINE_FLAG(int, huge_method_cutoff_in_code_size, 200000, 52 DEFINE_FLAG(int, huge_method_cutoff_in_code_size, 200000,
53 "Huge method cutoff in unoptimized code size (in bytes)."); 53 "Huge method cutoff in unoptimized code size (in bytes).");
54 DEFINE_FLAG(bool, throw_on_javascript_int_overflow, false, 54 DEFINE_FLAG(bool, throw_on_javascript_int_overflow, false,
55 "Throw an exception when integer arithmetic exceeds 53 bits."); 55 "Throw an exception when the result of an integer calculation will not "
56 "fit into a javascript integer.");
56 DECLARE_FLAG(bool, trace_compiler); 57 DECLARE_FLAG(bool, trace_compiler);
57 DECLARE_FLAG(bool, eliminate_type_checks); 58 DECLARE_FLAG(bool, eliminate_type_checks);
58 DECLARE_FLAG(bool, enable_type_checks); 59 DECLARE_FLAG(bool, enable_type_checks);
59 60
60 static const char* kGetterPrefix = "get:"; 61 static const char* kGetterPrefix = "get:";
61 static const intptr_t kGetterPrefixLength = strlen(kGetterPrefix); 62 static const intptr_t kGetterPrefixLength = strlen(kGetterPrefix);
62 static const char* kSetterPrefix = "set:"; 63 static const char* kSetterPrefix = "set:";
63 static const intptr_t kSetterPrefixLength = strlen(kSetterPrefix); 64 static const intptr_t kSetterPrefixLength = strlen(kSetterPrefix);
64 65
65 cpp_vtable Object::handle_vtable_ = 0; 66 cpp_vtable Object::handle_vtable_ = 0;
(...skipping 11160 matching lines...) Expand 10 before | Expand all | Expand 10 after
11226 return "Integer"; 11227 return "Integer";
11227 } 11228 }
11228 11229
11229 11230
11230 void Integer::PrintToJSONStream(JSONStream* stream, bool ref) const { 11231 void Integer::PrintToJSONStream(JSONStream* stream, bool ref) const {
11231 stream->OpenObject(); 11232 stream->OpenObject();
11232 stream->CloseObject(); 11233 stream->CloseObject();
11233 } 11234 }
11234 11235
11235 11236
11236 // Throw FiftyThreeBitOverflow exception. 11237 // Throw JavascriptIntegerOverflow exception.
11237 static void ThrowFiftyThreeBitOverflow(const Integer& i) { 11238 static void ThrowJavascriptIntegerOverflow(const Integer& i) {
11238 const Array& exc_args = Array::Handle(Array::New(1)); 11239 const Array& exc_args = Array::Handle(Array::New(1));
11239 const String& i_str = String::Handle(String::New(i.ToCString())); 11240 const String& i_str = String::Handle(String::New(i.ToCString()));
11240 exc_args.SetAt(0, i_str); 11241 exc_args.SetAt(0, i_str);
11241 Exceptions::ThrowByType(Exceptions::kFiftyThreeBitOverflowError, exc_args); 11242 Exceptions::ThrowByType(Exceptions::kJavascriptIntegerOverflowError,
11243 exc_args);
11242 } 11244 }
11243 11245
11244 11246
11245 RawInteger* Integer::New(const String& str, Heap::Space space) { 11247 RawInteger* Integer::New(const String& str, Heap::Space space) {
11246 // We are not supposed to have integers represented as two byte strings. 11248 // We are not supposed to have integers represented as two byte strings.
11247 ASSERT(str.IsOneByteString()); 11249 ASSERT(str.IsOneByteString());
11248 int64_t value; 11250 int64_t value;
11249 if (!OS::StringToInt64(str.ToCString(), &value)) { 11251 if (!OS::StringToInt64(str.ToCString(), &value)) {
11250 const Bigint& big = Bigint::Handle(Bigint::New(str, space)); 11252 const Bigint& big = Bigint::Handle(Bigint::New(str, space));
11251 ASSERT(!BigintOperations::FitsIntoSmi(big)); 11253 ASSERT(!BigintOperations::FitsIntoSmi(big));
11252 ASSERT(!BigintOperations::FitsIntoInt64(big)); 11254 ASSERT(!BigintOperations::FitsIntoInt64(big));
11253 if (FLAG_throw_on_javascript_int_overflow) { 11255 if (FLAG_throw_on_javascript_int_overflow) {
11254 ThrowFiftyThreeBitOverflow(big); 11256 ThrowJavascriptIntegerOverflow(big);
11255 } 11257 }
11256 return big.raw(); 11258 return big.raw();
11257 } 11259 }
11258 return Integer::New(value, space); 11260 return Integer::New(value, space);
11259 } 11261 }
11260 11262
11261 11263
11262 // This is called from LiteralToken::New() in the parser, so we can't 11264 // This is called from LiteralToken::New() in the parser, so we can't
11263 // raise an exception for 53-bit overflow here. Instead we do it in 11265 // raise an exception for 54-bit overflow here. Instead we do it in
11264 // Parser::CurrentIntegerLiteral(), which is the point in the parser where 11266 // Parser::CurrentIntegerLiteral(), which is the point in the parser where
11265 // integer literals escape, so we can call Parser::ErrorMsg(). 11267 // integer literals escape, so we can call Parser::ErrorMsg().
11266 RawInteger* Integer::NewCanonical(const String& str) { 11268 RawInteger* Integer::NewCanonical(const String& str) {
11267 // We are not supposed to have integers represented as two byte strings. 11269 // We are not supposed to have integers represented as two byte strings.
11268 ASSERT(str.IsOneByteString()); 11270 ASSERT(str.IsOneByteString());
11269 int64_t value; 11271 int64_t value;
11270 if (!OS::StringToInt64(str.ToCString(), &value)) { 11272 if (!OS::StringToInt64(str.ToCString(), &value)) {
11271 const Bigint& big = Bigint::Handle(Bigint::NewCanonical(str)); 11273 const Bigint& big = Bigint::Handle(Bigint::NewCanonical(str));
11272 ASSERT(!BigintOperations::FitsIntoSmi(big)); 11274 ASSERT(!BigintOperations::FitsIntoSmi(big));
11273 ASSERT(!BigintOperations::FitsIntoInt64(big)); 11275 ASSERT(!BigintOperations::FitsIntoInt64(big));
11274 return big.raw(); 11276 return big.raw();
11275 } 11277 }
11276 if ((value <= Smi::kMaxValue) && (value >= Smi::kMinValue)) { 11278 if ((value <= Smi::kMaxValue) && (value >= Smi::kMinValue)) {
11277 return Smi::New(value); 11279 return Smi::New(value);
11278 } 11280 }
11279 return Mint::NewCanonical(value); 11281 return Mint::NewCanonical(value);
11280 } 11282 }
11281 11283
11282 11284
11285 // dart2js represents integers as double precision floats. It does this using
11286 // a sign bit and 53 fraction bits. This gives us the range
11287 // -2^54 - 1 ... 2^54 - 1, i.e. the same as a 54-bit signed integer
Florian Schneider 2013/08/01 15:45:03 Something is slightly off here: a int54_t has a ra
11288 // without the most negative number. Thus, here we check if the value is
11289 // a 54-bit signed integer and not -2^54
11290 static bool Is54BitNoMinInt(int64_t value) {
11291 return (Utils::IsInt(54, value)) && (value != (-0x1FFFFFFFFFFFFF - 1));
Florian Schneider 2013/08/02 10:24:17 I think this should be return Utils::IsInt(54, va
11292 }
11293
11294
11283 RawInteger* Integer::New(int64_t value, Heap::Space space) { 11295 RawInteger* Integer::New(int64_t value, Heap::Space space) {
11284 if ((value <= Smi::kMaxValue) && (value >= Smi::kMinValue)) { 11296 if ((value <= Smi::kMaxValue) && (value >= Smi::kMinValue)) {
11285 return Smi::New(value); 11297 return Smi::New(value);
11286 } 11298 }
11287 if (FLAG_throw_on_javascript_int_overflow && !Utils::IsInt(53, value)) { 11299 if (FLAG_throw_on_javascript_int_overflow && !Is54BitNoMinInt(value)) {
11288 const Integer &i = Integer::Handle(Mint::New(value)); 11300 const Integer &i = Integer::Handle(Mint::New(value));
11289 ThrowFiftyThreeBitOverflow(i); 11301 ThrowJavascriptIntegerOverflow(i);
11290 } 11302 }
11291 return Mint::New(value, space); 11303 return Mint::New(value, space);
11292 } 11304 }
11293 11305
11294 11306
11295 RawInteger* Integer::NewFromUint64(uint64_t value, Heap::Space space) { 11307 RawInteger* Integer::NewFromUint64(uint64_t value, Heap::Space space) {
11296 if (value > static_cast<uint64_t>(Mint::kMaxValue)) { 11308 if (value > static_cast<uint64_t>(Mint::kMaxValue)) {
11297 if (FLAG_throw_on_javascript_int_overflow) { 11309 if (FLAG_throw_on_javascript_int_overflow) {
11298 const Integer &i = 11310 const Integer &i =
11299 Integer::Handle(BigintOperations::NewFromUint64(value)); 11311 Integer::Handle(BigintOperations::NewFromUint64(value));
11300 ThrowFiftyThreeBitOverflow(i); 11312 ThrowJavascriptIntegerOverflow(i);
11301 } 11313 }
11302 return BigintOperations::NewFromUint64(value); 11314 return BigintOperations::NewFromUint64(value);
11303 } else { 11315 } else {
11304 return Integer::New(value); 11316 return Integer::New(value);
11305 } 11317 }
11306 } 11318 }
11307 11319
11308 11320
11309 double Integer::AsDoubleValue() const { 11321 double Integer::AsDoubleValue() const {
11310 UNIMPLEMENTED(); 11322 UNIMPLEMENTED();
11311 return 0.0; 11323 return 0.0;
11312 } 11324 }
11313 11325
11314 11326
11315 int64_t Integer::AsInt64Value() const { 11327 int64_t Integer::AsInt64Value() const {
11316 UNIMPLEMENTED(); 11328 UNIMPLEMENTED();
11317 return 0; 11329 return 0;
11318 } 11330 }
11319 11331
11320 11332
11321 int Integer::CompareWith(const Integer& other) const { 11333 int Integer::CompareWith(const Integer& other) const {
11322 UNIMPLEMENTED(); 11334 UNIMPLEMENTED();
11323 return 0; 11335 return 0;
11324 } 11336 }
11325 11337
11326 11338
11327 // Returns true if the signed Integer requires more than 53 bits. 11339 // Returns true if the signed Integer does not fit into a
11328 bool Integer::CheckFiftyThreeBitOverflow() const { 11340 // Javascript (54-bit) integer.
11341 bool Integer::CheckJavascriptIntegerOverflow() const {
11329 // Always overflow if the value doesn't fit into an int64_t. 11342 // Always overflow if the value doesn't fit into an int64_t.
11330 int64_t value = 1ULL << 63; 11343 int64_t value = 1ULL << 63;
11331 if (IsSmi()) { 11344 if (IsSmi()) {
11332 value = AsInt64Value(); 11345 value = AsInt64Value();
11333 } else if (IsMint()) { 11346 } else if (IsMint()) {
11334 Mint& mint = Mint::Handle(); 11347 Mint& mint = Mint::Handle();
11335 mint ^= raw(); 11348 mint ^= raw();
11336 value = mint.value(); 11349 value = mint.value();
11337 } else { 11350 } else {
11338 ASSERT(IsBigint()); 11351 ASSERT(IsBigint());
11339 Bigint& big_value = Bigint::Handle(); 11352 Bigint& big_value = Bigint::Handle();
11340 big_value ^= raw(); 11353 big_value ^= raw();
11341 if (BigintOperations::FitsIntoInt64(big_value)) { 11354 if (BigintOperations::FitsIntoInt64(big_value)) {
11342 value = BigintOperations::ToInt64(big_value); 11355 value = BigintOperations::ToInt64(big_value);
11343 } 11356 }
11344 } 11357 }
11345 return !Utils::IsInt(53, value); 11358 return !Is54BitNoMinInt(value);
11346 } 11359 }
11347 11360
11348 11361
11349 RawInteger* Integer::AsValidInteger() const { 11362 RawInteger* Integer::AsValidInteger() const {
11350 if (FLAG_throw_on_javascript_int_overflow && 11363 if (FLAG_throw_on_javascript_int_overflow &&
11351 CheckFiftyThreeBitOverflow()) { 11364 CheckJavascriptIntegerOverflow()) {
11352 ThrowFiftyThreeBitOverflow(*this); 11365 ThrowJavascriptIntegerOverflow(*this);
11353 } 11366 }
11354 if (IsSmi()) return raw(); 11367 if (IsSmi()) return raw();
11355 if (IsMint()) { 11368 if (IsMint()) {
11356 Mint& mint = Mint::Handle(); 11369 Mint& mint = Mint::Handle();
11357 mint ^= raw(); 11370 mint ^= raw();
11358 if (Smi::IsValid64(mint.value())) { 11371 if (Smi::IsValid64(mint.value())) {
11359 return Smi::New(mint.value()); 11372 return Smi::New(mint.value());
11360 } else { 11373 } else {
11361 return raw(); 11374 return raw();
11362 } 11375 }
(...skipping 3019 matching lines...) Expand 10 before | Expand all | Expand 10 after
14382 } 14395 }
14383 14396
14384 14397
14385 void MirrorReference::PrintToJSONStream(JSONStream* stream, bool ref) const { 14398 void MirrorReference::PrintToJSONStream(JSONStream* stream, bool ref) const {
14386 stream->OpenObject(); 14399 stream->OpenObject();
14387 stream->CloseObject(); 14400 stream->CloseObject();
14388 } 14401 }
14389 14402
14390 14403
14391 } // namespace dart 14404 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698