Version 2.12.0-82.0.dev
Merge commit '7837c384c00eb56058a66dcf72920cf9fc542eed' into 'dev'
diff --git a/DEPS b/DEPS
index 48e6ed1..8dd67be 100644
--- a/DEPS
+++ b/DEPS
@@ -130,7 +130,7 @@
"path_rev": "62ecd5a78ffe5734d14ed0df76d20309084cd04a",
"pedantic_rev": "a884ea2db943b8756cc94385990bd750aec06928",
"ply_rev": "604b32590ffad5cbb82e4afef1d305512d06ae93",
- "pool_rev": "eedbd5fde84f9a1a8da643b475305a81841da599",
+ "pool_rev": "7abe634002a1ba8a0928eded086062f1307ccfae",
"protobuf_rev": "0d03fd588df69e9863e2a2efc0059dee8f18d5b2",
"pub_rev": "228e69e53862879c283c42b98086aa7536012a66",
"pub_semver_rev": "10569a1e867e909cf5db201f73118020453e5db8",
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index e3e32f3..3e25e86 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -139,6 +139,10 @@
[ $nnbd == legacy ]
dart/*: SkipByDesign # Migrated tests are not supposed to run on non-NNBD bots.
+[ $runtime == vm ]
+dart/isolates/*: Pass, Slow # https://dartbug.com/36097: Slower while isolate groups are being gradually enabled in JIT mode.
+dart_2/isolates/*: Pass, Slow # https://dartbug.com/36097: Slower while isolate groups are being gradually enabled in JIT mode.
+
[ $system == android ]
dart/isolates/dart_api_create_lightweight_isolate_test: SkipByDesign # On android this test does not work due to not being able to identify library uri.
dart/sdk_hash_test: SkipByDesign # The test doesn't know location of cross-platform gen_snapshot
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index c06d36d..213bb7a 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -1890,7 +1890,8 @@
const String& target_name,
const Array& arguments_descriptor,
intptr_t num_args_tested,
- const AbstractType& receiver_type) {
+ const AbstractType& receiver_type,
+ const Function& binary_smi_target) {
if ((deopt_id_to_ic_data_ != NULL) &&
((*deopt_id_to_ic_data_)[deopt_id] != NULL)) {
const ICData* res = (*deopt_id_to_ic_data_)[deopt_id];
@@ -1903,10 +1904,24 @@
ASSERT(res->receivers_static_type() == receiver_type.raw());
return res;
}
- const ICData& ic_data = ICData::ZoneHandle(
- zone(), ICData::New(parsed_function().function(), target_name,
+
+ auto& ic_data = ICData::ZoneHandle(zone());
+ if (!binary_smi_target.IsNull()) {
+ ASSERT(num_args_tested == 2);
+ ASSERT(!binary_smi_target.IsNull());
+ GrowableArray<intptr_t> cids(num_args_tested);
+ cids.Add(kSmiCid);
+ cids.Add(kSmiCid);
+ ic_data = ICData::NewWithCheck(parsed_function().function(), target_name,
+ arguments_descriptor, deopt_id,
+ num_args_tested, ICData::kInstance, &cids,
+ binary_smi_target, receiver_type);
+ } else {
+ ic_data = ICData::New(parsed_function().function(), target_name,
arguments_descriptor, deopt_id, num_args_tested,
- ICData::kInstance, receiver_type));
+ ICData::kInstance, receiver_type);
+ }
+
if (deopt_id_to_ic_data_ != NULL) {
(*deopt_id_to_ic_data_)[deopt_id] = &ic_data;
}
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.h b/runtime/vm/compiler/backend/flow_graph_compiler.h
index 729c639..33f2627 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.h
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.h
@@ -911,11 +911,15 @@
bool may_reoptimize() const { return may_reoptimize_; }
// Use in unoptimized compilation to preserve/reuse ICData.
+ //
+ // If [binary_smi_target] is non-null and we have to create the ICData, the
+ // ICData will get an (kSmiCid, kSmiCid, binary_smi_target) entry.
const ICData* GetOrAddInstanceCallICData(intptr_t deopt_id,
const String& target_name,
const Array& arguments_descriptor,
intptr_t num_args_tested,
- const AbstractType& receiver_type);
+ const AbstractType& receiver_type,
+ const Function& binary_smi_target);
const ICData* GetOrAddStaticCallICData(intptr_t deopt_id,
const Function& target,
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index 4042a04..bd8e8b7 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -4815,8 +4815,36 @@
}
}
+static FunctionPtr FindBinarySmiOp(Zone* zone, const String& name) {
+ const auto& smi_class = Class::Handle(zone, Smi::Class());
+ auto& smi_op_target = Function::Handle(
+ zone, Resolver::ResolveDynamicAnyArgs(zone, smi_class, name));
+
+#if !defined(DART_PRECOMPILED_RUNTIME)
+ if (smi_op_target.IsNull() &&
+ Function::IsDynamicInvocationForwarderName(name)) {
+ const String& demangled = String::Handle(
+ zone, Function::DemangleDynamicInvocationForwarderName(name));
+ smi_op_target = Resolver::ResolveDynamicAnyArgs(zone, smi_class, demangled);
+ }
+#endif
+ return smi_op_target.raw();
+}
+
void InstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Zone* zone = compiler->zone();
+
+ UpdateReceiverSminess(zone);
+
+ auto& specialized_binary_smi_ic_stub = Code::ZoneHandle(zone);
+ auto& binary_smi_op_target = Function::Handle(zone);
+ if (!receiver_is_not_smi()) {
+ specialized_binary_smi_ic_stub = TwoArgsSmiOpInlineCacheEntry(token_kind());
+ if (!specialized_binary_smi_ic_stub.IsNull()) {
+ binary_smi_op_target = FindBinarySmiOp(zone, function_name());
+ }
+ }
+
const ICData* call_ic_data = NULL;
if (!FLAG_propagate_ic_data || !compiler->is_optimizing() ||
(ic_data() == NULL)) {
@@ -4830,13 +4858,11 @@
call_ic_data = compiler->GetOrAddInstanceCallICData(
deopt_id(), function_name(), arguments_descriptor,
- checked_argument_count(), receivers_static_type);
+ checked_argument_count(), receivers_static_type, binary_smi_op_target);
} else {
call_ic_data = &ICData::ZoneHandle(zone, ic_data()->raw());
}
- UpdateReceiverSminess(zone);
-
if (compiler->is_optimizing() && HasICData()) {
if (ic_data()->NumberOfUsedChecks() > 0) {
const ICData& unary_ic_data =
@@ -4854,18 +4880,27 @@
// Unoptimized code.
compiler->AddCurrentDescriptor(PcDescriptorsLayout::kRewind, deopt_id(),
token_pos());
- bool is_smi_two_args_op = false;
- const Code& stub =
- Code::ZoneHandle(TwoArgsSmiOpInlineCacheEntry(token_kind()));
- if (!stub.IsNull()) {
- // We have a dedicated inline cache stub for this operation, add an
- // an initial Smi/Smi check with count 0.
- is_smi_two_args_op = call_ic_data->AddSmiSmiCheckForFastSmiStubs();
+
+ // If the ICData contains a (Smi, Smi, <binary-smi-op-target>) stub already
+ // we will call the specialized IC Stub that works as a normal IC Stub but
+ // has inlined fast path for the specific Smi operation.
+ bool use_specialized_smi_ic_stub = false;
+ if (!specialized_binary_smi_ic_stub.IsNull() &&
+ call_ic_data->NumberOfChecksIs(1)) {
+ GrowableArray<intptr_t> class_ids(2);
+ auto& target = Function::Handle();
+ call_ic_data->GetCheckAt(0, &class_ids, &target);
+ if (class_ids[0] == kSmiCid && class_ids[1] == kSmiCid &&
+ target.raw() == binary_smi_op_target.raw()) {
+ use_specialized_smi_ic_stub = true;
+ }
}
- if (is_smi_two_args_op) {
+
+ if (use_specialized_smi_ic_stub) {
ASSERT(ArgumentCount() == 2);
- compiler->EmitInstanceCallJIT(stub, *call_ic_data, deopt_id(),
- token_pos(), locs(), entry_kind());
+ compiler->EmitInstanceCallJIT(specialized_binary_smi_ic_stub,
+ *call_ic_data, deopt_id(), token_pos(),
+ locs(), entry_kind());
} else {
compiler->GenerateInstanceCall(deopt_id(), token_pos(), locs(),
*call_ic_data, entry_kind(),
diff --git a/runtime/vm/flag_list.h b/runtime/vm/flag_list.h
index 022032b..dd6c196 100644
--- a/runtime/vm/flag_list.h
+++ b/runtime/vm/flag_list.h
@@ -119,7 +119,7 @@
P(enable_ffi, bool, true, "Disable to make importing dart:ffi an error.") \
P(fields_may_be_reset, bool, false, \
"Don't optimize away static field initialization") \
- C(force_clone_compiler_objects, false, false, bool, false, \
+ P(force_clone_compiler_objects, bool, false, \
"Force cloning of objects needed in compiler (ICData and Field).") \
P(getter_setter_ratio, int, 13, \
"Ratio of getter/setter usage used for double field unboxing heuristics") \
diff --git a/runtime/vm/flags.cc b/runtime/vm/flags.cc
index 901856c..f3fc0ef 100644
--- a/runtime/vm/flags.cc
+++ b/runtime/vm/flags.cc
@@ -466,6 +466,30 @@
PrintFlags();
}
+ // TODO(dartbug.com/36097): Support for isolate groups in JIT mode is
+ // in-development. We will start with very conservative settings. As we make
+ // more of our compiler, runtime as well as generated code re-entrant we'll
+ // graudally remove those restrictions.
+
+#if !defined(DART_PRCOMPILED_RUNTIME)
+ if (!FLAG_precompiled_mode && FLAG_enable_isolate_groups) {
+ // Our compiler should not make rely on a global field being initialized at
+ // compile-time, since that compiled code might be re-used in another
+ // isolate that has not yet initialized the global field.
+ FLAG_fields_may_be_reset = true;
+
+ // We will start by only allowing compilation to unoptimized code.
+ FLAG_optimization_counter_threshold = -1;
+ FLAG_background_compilation = false;
+ FLAG_force_clone_compiler_objects = true;
+
+ // To eliminate potential flakiness, we will start by disabling field guards
+ // and CHA-based compilations.
+ FLAG_use_field_guards = false;
+ FLAG_use_cha_deopt = false;
+ }
+#endif // !defined(DART_PRCOMPILED_RUNTIME)
+
initialized_ = true;
return NULL;
}
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 9c47fa6..88ec7dc 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -11326,51 +11326,78 @@
#endif // !defined(DART_PRECOMPILED_RUNTIME)
}
+// Returns the index in the given source string for the given (1-based) absolute
+// line and column numbers. The line and column offsets are used to calculate
+// the absolute line and column number for the starting index in the source.
+//
+// If the given line number is outside the range of lines represented by the
+// source, the given column number invalid for the given line, or a negative
+// starting index is given, a negative value is returned to indicate failure.
+static intptr_t GetRelativeSourceIndex(const String& src,
+ intptr_t line,
+ intptr_t line_offset = 0,
+ intptr_t column = 1,
+ intptr_t column_offset = 0,
+ intptr_t starting_index = 0) {
+ if (starting_index < 0 || line < 1 || column < 1) {
+ return -1;
+ }
+ intptr_t len = src.Length();
+ intptr_t current_line = line_offset + 1;
+ intptr_t current_index = starting_index;
+ for (; current_index < len; current_index++) {
+ if (current_line == line) {
+ break;
+ }
+ const uint16_t c = src.CharAt(current_index);
+ if (c == '\n' || c == '\r') {
+ current_line++;
+ }
+ if (c == '\r' && current_index + 1 < len &&
+ src.CharAt(current_index + 1) == '\n') {
+ // \r\n is treated as a single line terminator.
+ current_index++;
+ }
+ }
+ if (current_line != line) {
+ return -1;
+ }
+ // Only adjust with column offset when still on the first line.
+ intptr_t current_column = 1 + (line == line_offset + 1 ? column_offset : 0);
+ for (; current_index < len; current_index++, current_column++) {
+ if (current_column == column) {
+ return current_index;
+ }
+ const uint16_t c = src.CharAt(current_index);
+ if (c == '\n' || c == '\r') {
+ break;
+ }
+ }
+ // Check for a column value representing the source's end.
+ if (current_column == column) {
+ return current_index;
+ }
+ return -1;
+}
+
StringPtr Script::GetLine(intptr_t line_number, Heap::Space space) const {
const String& src = String::Handle(Source());
if (src.IsNull()) {
return Symbols::OptimizedOut().raw();
}
- intptr_t target_line = line_number - line_offset();
- intptr_t current_line = 1;
- intptr_t start = 0;
- // First find the right line, if present...
- for (; start < src.Length(); start++) {
- if (current_line == target_line) {
+ const intptr_t start =
+ GetRelativeSourceIndex(src, line_number, line_offset());
+ if (start < 0) {
+ return Symbols::Empty().raw();
+ }
+ intptr_t end = start;
+ for (; end < src.Length(); end++) {
+ const uint16_t c = src.CharAt(end);
+ if (c == '\n' || c == '\r') {
break;
}
- const uint16_t c = src.CharAt(start);
- // Only count '\r' as a line terminator if not followed by a '\n'.
- if (c == '\n' || (c == '\r' && (start + 1 >= src.Length() ||
- src.CharAt(start + 1) != '\n'))) {
- current_line++;
- }
}
- if (current_line == target_line) {
- // ... and then find its end, excluding any line terminator.
- intptr_t end = start;
- for (; end < src.Length(); end++) {
- const uint16_t c = src.CharAt(end);
- if (c == '\n' || c == '\r') {
- break;
- }
- }
- // Return the contents of the line.
- return String::SubString(src, start, end - start, space);
- }
-
- // Not found, so return the empty string.
- return Symbols::Empty().raw();
-}
-
-StringPtr Script::GetSnippet(TokenPosition from, TokenPosition to) const {
- intptr_t from_line;
- intptr_t from_column;
- intptr_t to_line;
- intptr_t to_column;
- GetTokenLocation(from, &from_line, &from_column);
- GetTokenLocation(to, &to_line, &to_column);
- return GetSnippet(from_line, from_column, to_line, to_column);
+ return String::SubString(src, start, end - start, space);
}
StringPtr Script::GetSnippet(intptr_t from_line,
@@ -11381,49 +11408,17 @@
if (src.IsNull()) {
return Symbols::OptimizedOut().raw();
}
- intptr_t length = src.Length();
- intptr_t line = 1 + line_offset();
- intptr_t column = 1;
- intptr_t scan_position = 0;
- intptr_t snippet_start = -1;
- intptr_t snippet_end = -1;
- if (from_line - line_offset() == 1) {
- column += col_offset();
- }
- while (scan_position != length) {
- if (snippet_start == -1) {
- if ((line == from_line) && (column == from_column)) {
- snippet_start = scan_position;
- }
- }
-
- char c = src.CharAt(scan_position);
- if (c == '\n') {
- line++;
- column = 0;
- } else if (c == '\r') {
- line++;
- column = 0;
- if ((scan_position + 1 != length) &&
- (src.CharAt(scan_position + 1) == '\n')) {
- scan_position++;
- }
- }
- scan_position++;
- column++;
-
- if ((line == to_line) && (column == to_column)) {
- snippet_end = scan_position;
- break;
- }
+ const intptr_t start = GetRelativeSourceIndex(src, from_line, line_offset(),
+ from_column, col_offset());
+ // Lines and columns are 1-based, so need to subtract one to get offsets.
+ const intptr_t end = GetRelativeSourceIndex(
+ src, to_line, from_line - 1, to_column, from_column - 1, start);
+ // Only need to check end, because a negative start results in a negative end.
+ if (end < 0) {
+ return String::null();
}
- String& snippet = String::Handle();
- if ((snippet_start != -1) && (snippet_end != -1)) {
- snippet =
- String::SubString(src, snippet_start, snippet_end - snippet_start);
- }
- return snippet.raw();
+ return String::SubString(src, start, end - start);
}
ScriptPtr Script::New() {
@@ -15215,46 +15210,6 @@
}
}
-// Add an initial Smi/Smi check with count 0.
-bool ICData::AddSmiSmiCheckForFastSmiStubs() const {
- bool is_smi_two_args_op = false;
-
- ASSERT(NumArgsTested() == 2);
- Zone* zone = Thread::Current()->zone();
- const String& name = String::Handle(zone, target_name());
- const Class& smi_class = Class::Handle(zone, Smi::Class());
- Function& smi_op_target = Function::Handle(
- zone, Resolver::ResolveDynamicAnyArgs(zone, smi_class, name));
-
-#if !defined(DART_PRECOMPILED_RUNTIME)
- if (smi_op_target.IsNull() &&
- Function::IsDynamicInvocationForwarderName(name)) {
- const String& demangled = String::Handle(
- zone, Function::DemangleDynamicInvocationForwarderName(name));
- smi_op_target = Resolver::ResolveDynamicAnyArgs(zone, smi_class, demangled);
- }
-#endif
-
- if (NumberOfChecksIs(0)) {
- GrowableArray<intptr_t> class_ids(2);
- class_ids.Add(kSmiCid);
- class_ids.Add(kSmiCid);
- AddCheck(class_ids, smi_op_target);
- // 'AddCheck' sets the initial count to 1.
- SetCountAt(0, 0);
- is_smi_two_args_op = true;
- } else if (NumberOfChecksIs(1)) {
- GrowableArray<intptr_t> class_ids(2);
- Function& target = Function::Handle();
- GetCheckAt(0, &class_ids, &target);
- if ((target.raw() == smi_op_target.raw()) && (class_ids[0] == kSmiCid) &&
- (class_ids[1] == kSmiCid)) {
- is_smi_two_args_op = true;
- }
- }
- return is_smi_two_args_op;
-}
-
bool ICData::ValidateInterceptor(const Function& target) const {
#if !defined(DART_PRECOMPILED_RUNTIME)
const String& name = String::Handle(target_name());
@@ -15847,41 +15802,63 @@
return result.raw();
}
+ICDataPtr ICData::NewWithCheck(const Function& owner,
+ const String& target_name,
+ const Array& arguments_descriptor,
+ intptr_t deopt_id,
+ intptr_t num_args_tested,
+ RebindRule rebind_rule,
+ GrowableArray<intptr_t>* cids,
+ const Function& target,
+ const AbstractType& receiver_type) {
+ ASSERT((cids != nullptr) && !target.IsNull());
+ ASSERT(cids->length() == num_args_tested);
+
+ Zone* zone = Thread::Current()->zone();
+ const auto& result = ICData::Handle(
+ zone,
+ NewDescriptor(zone, owner, target_name, arguments_descriptor, deopt_id,
+ num_args_tested, rebind_rule, receiver_type));
+
+ const intptr_t kNumEntries = 2; // 1 entry and a sentinel.
+ const intptr_t entry_len =
+ TestEntryLengthFor(num_args_tested, result.is_tracking_exactness());
+ const auto& array =
+ Array::Handle(zone, Array::New(kNumEntries * entry_len, Heap::kOld));
+
+ auto& cid = Smi::Handle(zone);
+ for (intptr_t i = 0; i < num_args_tested; ++i) {
+ cid = Smi::New((*cids)[i]);
+ array.SetAt(i, cid);
+ }
+ array.SetAt(CountIndexFor(num_args_tested), Object::smi_zero());
+ array.SetAt(TargetIndexFor(num_args_tested), target);
+ WriteSentinel(array, entry_len);
+ result.set_entries(array);
+
+ return result.raw();
+}
+
ICDataPtr ICData::NewForStaticCall(const Function& owner,
const Function& target,
const Array& arguments_descriptor,
intptr_t deopt_id,
intptr_t num_args_tested,
RebindRule rebind_rule) {
+ // See `MethodRecognizer::NumArgsCheckedForStaticCall`.
+ ASSERT(num_args_tested == 0 || num_args_tested == 2);
ASSERT(!target.IsNull());
Zone* zone = Thread::Current()->zone();
const auto& target_name = String::Handle(zone, target.name());
- const auto& result = ICData::Handle(
- zone, NewDescriptor(zone, owner, target_name, arguments_descriptor,
- deopt_id, num_args_tested, rebind_rule,
- Object::null_abstract_type()));
-
- const intptr_t kNumEntries = 2; // 1 entry and a sentinel.
- const intptr_t entry_len =
- TestEntryLengthFor(num_args_tested, /*tracking_exactness=*/false);
- const auto& array =
- Array::Handle(zone, Array::New(kNumEntries * entry_len, Heap::kOld));
-
- // See `MethodRecognizer::NumArgsCheckedForStaticCall`.
- ASSERT(num_args_tested == 0 || num_args_tested == 2);
+ GrowableArray<intptr_t> cids(num_args_tested);
if (num_args_tested == 2) {
- const auto& object_cid = Smi::Handle(zone, Smi::New(kObjectCid));
- array.SetAt(0, object_cid);
- array.SetAt(1, object_cid);
+ cids.Add(kObjectCid);
+ cids.Add(kObjectCid);
}
- array.SetAt(CountIndexFor(num_args_tested), Object::smi_zero());
- array.SetAt(TargetIndexFor(num_args_tested), target);
- WriteSentinel(array, entry_len);
-
- result.set_entries(array);
-
- return result.raw();
+ return ICData::NewWithCheck(owner, target_name, arguments_descriptor,
+ deopt_id, num_args_tested, rebind_rule, &cids,
+ target, Object::null_abstract_type());
}
#if !defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index d9429bb..df9585d 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2086,9 +2086,6 @@
void DebugDump() const;
- // Returns true if this is a two arg smi operation.
- bool AddSmiSmiCheckForFastSmiStubs() const;
-
// Adding checks.
// Adds one more class test to ICData. Length of 'classes' must be equal to
@@ -2159,6 +2156,19 @@
intptr_t num_args_tested,
RebindRule rebind_rule,
const AbstractType& receiver_type = Object::null_abstract_type());
+
+ // Similar to [New] makes the ICData have an initial (cids, target) entry.
+ static ICDataPtr NewWithCheck(
+ const Function& owner,
+ const String& target_name,
+ const Array& arguments_descriptor,
+ intptr_t deopt_id,
+ intptr_t num_args_tested,
+ RebindRule rebind_rule,
+ GrowableArray<intptr_t>* cids,
+ const Function& target,
+ const AbstractType& receiver_type = Object::null_abstract_type());
+
static ICDataPtr NewForStaticCall(const Function& owner,
const Function& target,
const Array& arguments_descriptor,
@@ -4487,7 +4497,6 @@
LibraryPtr FindLibrary() const;
StringPtr GetLine(intptr_t line_number, Heap::Space space = Heap::kNew) const;
- StringPtr GetSnippet(TokenPosition from, TokenPosition to) const;
StringPtr GetSnippet(intptr_t from_line,
intptr_t from_column,
intptr_t to_line,
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index 47f28ff..94e3747 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -2356,9 +2356,11 @@
static void CheckLinesWithOffset(Zone* zone, const intptr_t offset) {
const char* url_chars = "";
- // Eight lines, mix of \n, \r, \r\n line terminators, lines 3, 4, 7, and 8
+ // Nine lines, mix of \n, \r, \r\n line terminators, lines 3, 4, 7, and 8
// are non-empty. Ends with a \r as a double-check that the \r followed by
// \n check doesn't go out of bounds.
+ //
+ // Line starts: 1 2 3 4 5 6 7 8 9
const char* source_chars = "\n\nxyz\nabc\r\n\n\r\ndef\rghi\r";
const String& url = String::Handle(zone, String::New(url_chars));
const String& source = String::Handle(zone, String::New(source_chars));
@@ -2383,6 +2385,11 @@
EXPECT_STREQ("def", str.ToCString());
str = script.GetLine(offset + 8);
EXPECT_STREQ("ghi", str.ToCString());
+ str = script.GetLine(offset + 9);
+ EXPECT_STREQ("", str.ToCString());
+ // Using "column" of \r at end of line for to_column.
+ str = script.GetSnippet(offset + 3, 1, offset + 7, 4);
+ EXPECT_STREQ("xyz\nabc\r\n\n\r\ndef", str.ToCString());
// Lines not in the range of (1-based) line indices in the source should
// return the empty string.
str = script.GetLine(-500);
@@ -2397,12 +2404,23 @@
str = script.GetLine(3); // Absolute, not relative to offset.
EXPECT_STREQ("", str.ToCString());
}
+ str = script.GetLine(offset - 500);
+ EXPECT_STREQ("", str.ToCString());
str = script.GetLine(offset);
EXPECT_STREQ("", str.ToCString());
- str = script.GetLine(offset + 9);
+ str = script.GetLine(offset + 10);
EXPECT_STREQ("", str.ToCString());
str = script.GetLine(offset + 10000);
EXPECT_STREQ("", str.ToCString());
+ // Snippets not contained within the source should be the null string.
+ str = script.GetSnippet(-1, 1, 2, 2);
+ EXPECT(str.IsNull());
+ str = script.GetSnippet(offset - 1, 1, offset + 2, 2);
+ EXPECT(str.IsNull());
+ str = script.GetSnippet(offset + 5, 15, offset + 6, 2);
+ EXPECT(str.IsNull());
+ str = script.GetSnippet(offset + 20, 1, offset + 30, 1);
+ EXPECT(str.IsNull());
}
ISOLATE_UNIT_TEST_CASE(Script) {
@@ -2442,6 +2460,10 @@
auto& str = String::Handle(Z);
str = script.GetLine(1);
EXPECT_STREQ("abc", str.ToCString());
+ str = script.GetSnippet(1, 1, 1, 2);
+ EXPECT_STREQ("a", str.ToCString());
+ str = script.GetSnippet(1, 2, 1, 4);
+ EXPECT_STREQ("bc", str.ToCString());
// Lines not in the source should return the empty string.
str = script.GetLine(-500);
EXPECT_STREQ("", str.ToCString());
@@ -2451,6 +2473,13 @@
EXPECT_STREQ("", str.ToCString());
str = script.GetLine(10000);
EXPECT_STREQ("", str.ToCString());
+ // Snippets not contained within the source should be the null string.
+ str = script.GetSnippet(-1, 1, 1, 2);
+ EXPECT(str.IsNull());
+ str = script.GetSnippet(2, 1, 2, 2);
+ EXPECT(str.IsNull());
+ str = script.GetSnippet(1, 1, 1, 5);
+ EXPECT(str.IsNull());
}
TransitionVMToNative transition(thread);
diff --git a/tests/lib/lib_vm.status b/tests/lib/lib_vm.status
index b28a2fa..c693924 100644
--- a/tests/lib/lib_vm.status
+++ b/tests/lib/lib_vm.status
@@ -2,6 +2,9 @@
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
+[ $runtime == vm ]
+isolate/*: Pass, Slow # https://dartbug.com/36097: Slower while isolate groups are being gradually enabled in JIT mode.
+
[ $runtime != vm ]
isolate/native_wrapper_message_test: Skip # A VM specific test.
diff --git a/tests/lib_2/lib_2_vm.status b/tests/lib_2/lib_2_vm.status
index 68e3420..4820450 100644
--- a/tests/lib_2/lib_2_vm.status
+++ b/tests/lib_2/lib_2_vm.status
@@ -2,6 +2,9 @@
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
+[ $runtime == vm ]
+isolate/*: Pass, Slow # https://dartbug.com/36097: Slower while isolate groups are being gradually enabled in JIT mode.
+
[ $runtime != vm ]
isolate/native_wrapper_message_test: Skip # A VM specific test.
diff --git a/tools/VERSION b/tools/VERSION
index 5c1cbeb..127cde4 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 12
PATCH 0
-PRERELEASE 81
+PRERELEASE 82
PRERELEASE_PATCH 0
\ No newline at end of file