Skip to content

Commit 7708989

Browse files
mralephcommit-bot@chromium.org
authored andcommitted
[vm/intrinsics] Introduce dart:_internal.uncheckedCast.
This function can be used to avoid checked down casts in the parts of the code where we know by construction that the type of the value matches expectations. Use it to avoid down-cast in the _LinkedHashMap.operator[]. Bug: #31798 Change-Id: I80949bfb84dde7716fc23aeba311931970ce16aa Reviewed-on: https://dart-review.googlesource.com/70511 Commit-Queue: Vyacheslav Egorov <[email protected]> Reviewed-by: Alexander Markov <[email protected]>
1 parent 1a2532c commit 7708989

File tree

8 files changed

+39
-7
lines changed

8 files changed

+39
-7
lines changed

runtime/lib/compact_hash.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ abstract class _LinkedHashMapMixin<K, V> implements _HashBase {
344344

345345
V operator [](Object key) {
346346
var v = _getValueOrData(key);
347-
return identical(_data, v) ? null : v;
347+
return identical(_data, v) ? null : internal.unsafeCast<V>(v);
348348
}
349349

350350
bool containsValue(Object value) {

runtime/lib/internal_patch.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,10 @@ Int32List _growRegExpStack(Int32List stack) {
110110
}
111111
return newStack;
112112
}
113+
114+
// This function can be used to skip implicit or explicit checked down casts in
115+
// the parts of the core library implementation where we know by construction the
116+
// type of a value.
117+
//
118+
// Important: this is unsafe and must be used with care.
119+
T unsafeCast<T>(Object v) native "Internal_unsafeCast";

runtime/lib/object.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,11 @@ DEFINE_NATIVE_ENTRY(Internal_inquireIs64Bit, 0) {
319319
#endif // defined(ARCH_IS_64_BIT)
320320
}
321321

322+
DEFINE_NATIVE_ENTRY(Internal_unsafeCast, 1) {
323+
UNREACHABLE(); // Should be erased at Kernel translation time.
324+
return arguments->NativeArgAt(0);
325+
}
326+
322327
static bool ExtractInterfaceTypeArgs(Zone* zone,
323328
const Class& instance_cls,
324329
const TypeArguments& instance_type_args,

runtime/vm/bootstrap_natives.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@ namespace dart {
307307
V(GrowableList_getCapacity, 1) \
308308
V(GrowableList_setLength, 2) \
309309
V(GrowableList_setData, 2) \
310+
V(Internal_unsafeCast, 1) \
310311
V(Internal_makeListFixedLength, 1) \
311312
V(Internal_makeFixedListUnmodifiable, 1) \
312313
V(Internal_inquireIs64Bit, 0) \

runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3867,9 +3867,16 @@ Fragment StreamingFlowGraphBuilder::BuildStaticInvocation(bool is_const,
38673867
Fragment instructions;
38683868
LocalVariable* instance_variable = NULL;
38693869

3870-
bool special_case_identical = klass.IsTopLevel() &&
3871-
(klass.library() == Library::CoreLibrary()) &&
3872-
(target.name() == Symbols::Identical().raw());
3870+
const bool special_case_unchecked_cast =
3871+
klass.IsTopLevel() && (klass.library() == Library::InternalLibrary()) &&
3872+
(target.name() == Symbols::UnsafeCast().raw());
3873+
3874+
const bool special_case_identical =
3875+
klass.IsTopLevel() && (klass.library() == Library::CoreLibrary()) &&
3876+
(target.name() == Symbols::Identical().raw());
3877+
3878+
const bool special_case =
3879+
special_case_identical || special_case_unchecked_cast;
38733880

38743881
// If we cross the Kernel -> VM core library boundary, a [StaticInvocation]
38753882
// can appear, but the thing we're calling is not a static method, but a
@@ -3905,7 +3912,7 @@ Fragment StreamingFlowGraphBuilder::BuildStaticInvocation(bool is_const,
39053912
const TypeArguments& type_arguments = PeekArgumentsInstantiatedType(klass);
39063913
instructions += TranslateInstantiatedTypeArguments(type_arguments);
39073914
instructions += PushArgument();
3908-
} else if (!special_case_identical && I->reify_generic_functions()) {
3915+
} else if (!special_case && I->reify_generic_functions()) {
39093916
AlternativeReadingScope alt(&reader_);
39103917
ReadUInt(); // read argument count.
39113918
intptr_t list_length = ReadListLength(); // read types list length.
@@ -3921,7 +3928,7 @@ Fragment StreamingFlowGraphBuilder::BuildStaticInvocation(bool is_const,
39213928
Array& argument_names = Array::ZoneHandle(Z);
39223929
instructions += BuildArguments(&argument_names, NULL /* arg count */,
39233930
NULL /* positional arg count */,
3924-
special_case_identical); // read arguments.
3931+
special_case); // read arguments.
39253932
ASSERT(target.AreValidArguments(type_args_len, argument_count, argument_names,
39263933
NULL));
39273934

@@ -3931,6 +3938,8 @@ Fragment StreamingFlowGraphBuilder::BuildStaticInvocation(bool is_const,
39313938
if (special_case_identical) {
39323939
ASSERT(argument_count == 2);
39333940
instructions += StrictCompare(Token::kEQ_STRICT, /*number_check=*/true);
3941+
} else if (special_case_unchecked_cast) {
3942+
// Simply do nothing: the result value is already pushed on the stack.
39343943
} else {
39353944
instructions += StaticCall(position, target, argument_count, argument_names,
39363945
ICData::kStatic, &result_type, type_args_len);

runtime/vm/kernel_loader.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1652,6 +1652,8 @@ void KernelLoader::LoadProcedure(const Library& library,
16521652
expression_evaluation_function_ = function.raw();
16531653
}
16541654
function.set_kernel_offset(procedure_offset);
1655+
function.set_is_reflectable(function.is_reflectable() &&
1656+
library.raw() != Library::InternalLibrary());
16551657

16561658
ActiveMemberScope active_member(&active_class_, &function);
16571659

runtime/vm/parser.cc

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6100,7 +6100,9 @@ void Parser::ParseTopLevelFunction(TopLevel* top_level,
61006100
result_type.SetScopeFunction(func);
61016101
func.set_end_token_pos(function_end_pos);
61026102
func.set_modifier(func_modifier);
6103-
if (library_.is_dart_scheme() && library_.IsPrivate(func_name)) {
6103+
if (library_.is_dart_scheme() &&
6104+
(library_.IsPrivate(func_name) ||
6105+
library_.raw() == Library::InternalLibrary())) {
61046106
func.set_is_reflectable(false);
61056107
}
61066108
if (is_native) {
@@ -11759,6 +11761,11 @@ AstNode* Parser::ParseStaticCall(const Class& cls,
1175911761
InvocationMirror::kMethod,
1176011762
NULL, // No existing function.
1176111763
prefix);
11764+
} else if (cls.IsTopLevel() &&
11765+
(cls.library() == Library::InternalLibrary()) &&
11766+
(func.name() == Symbols::UnsafeCast().raw())) {
11767+
ASSERT(num_arguments == 1);
11768+
return arguments->NodeAt(0);
1176211769
} else if (cls.IsTopLevel() && (cls.library() == Library::CoreLibrary()) &&
1176311770
(func.name() == Symbols::Identical().raw()) &&
1176411771
func_type_args.IsNull()) {

runtime/vm/symbols.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class ObjectPointerVisitor;
2525
V(TruncDivOperator, "~/") \
2626
V(UnaryMinus, "unary-") \
2727
V(Identical, "identical") \
28+
V(UnsafeCast, "unsafeCast") \
2829
V(Length, "length") \
2930
V(_setLength, "_setLength") \
3031
V(IndexToken, "[]") \

0 commit comments

Comments
 (0)