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

Unified Diff: runtime/vm/flow_graph_compiler_arm.cc

Issue 12773008: Support checked mode for VM tests on ARM. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 9 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/assembler_arm.cc ('k') | runtime/vm/flow_graph_compiler_ia32.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/flow_graph_compiler_arm.cc
===================================================================
--- runtime/vm/flow_graph_compiler_arm.cc (revision 20622)
+++ runtime/vm/flow_graph_compiler_arm.cc (working copy)
@@ -23,6 +23,7 @@
DECLARE_FLAG(bool, print_ast);
DECLARE_FLAG(bool, print_scopes);
DECLARE_FLAG(bool, enable_type_checks);
+DECLARE_FLAG(bool, eliminate_type_checks);
FlowGraphCompiler::~FlowGraphCompiler() {
@@ -82,17 +83,75 @@
const GrowableArray<intptr_t>& class_ids,
Label* is_equal_lbl,
Label* is_not_equal_lbl) {
- UNIMPLEMENTED();
+ for (intptr_t i = 0; i < class_ids.length(); i++) {
+ __ CompareImmediate(class_id_reg, class_ids[i]);
+ __ b(is_equal_lbl, EQ);
+ }
+ __ b(is_not_equal_lbl);
}
+// Testing against an instantiated type with no arguments, without
+// SubtypeTestCache.
+// R0: instance being type checked (preserved).
+// Clobbers R2, R3.
+// Returns true if there is a fallthrough.
bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
intptr_t token_pos,
const AbstractType& type,
Label* is_instance_lbl,
Label* is_not_instance_lbl) {
- UNIMPLEMENTED();
- return false;
+ __ Comment("InstantiatedTypeNoArgumentsTest");
+ ASSERT(type.IsInstantiated());
+ const Class& type_class = Class::Handle(type.type_class());
+ ASSERT(!type_class.HasTypeArguments());
+
+ const Register kInstanceReg = R0;
+ __ tst(kInstanceReg, ShifterOperand(kSmiTagMask));
+ // If instance is Smi, check directly.
+ const Class& smi_class = Class::Handle(Smi::Class());
+ if (smi_class.IsSubtypeOf(TypeArguments::Handle(),
+ type_class,
+ TypeArguments::Handle(),
+ NULL)) {
+ __ b(is_instance_lbl, EQ);
+ } else {
+ __ b(is_not_instance_lbl, EQ);
+ }
+ // Compare if the classes are equal.
+ const Register kClassIdReg = R2;
+ __ LoadClassId(kClassIdReg, kInstanceReg);
+ __ CompareImmediate(kClassIdReg, type_class.id());
+ __ b(is_instance_lbl, EQ);
+ // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted
+ // interfaces.
+ // Bool interface can be implemented only by core class Bool.
+ if (type.IsBoolType()) {
+ __ CompareImmediate(kClassIdReg, kBoolCid);
+ __ b(is_instance_lbl, EQ);
+ __ b(is_not_instance_lbl);
+ return false;
+ }
+ if (type.IsFunctionType()) {
+ // Check if instance is a closure.
+ __ LoadClassById(R3, kClassIdReg);
+ __ ldr(R3, FieldAddress(R3, Class::signature_function_offset()));
+ __ CompareImmediate(R3, reinterpret_cast<int32_t>(Object::null()));
+ __ b(is_instance_lbl, NE);
+ }
+ // Custom checking for numbers (Smi, Mint, Bigint and Double).
+ // Note that instance is not Smi (checked above).
+ if (type.IsSubtypeOf(Type::Handle(Type::Number()), NULL)) {
+ GenerateNumberTypeCheck(
+ kClassIdReg, type, is_instance_lbl, is_not_instance_lbl);
+ return false;
+ }
+ if (type.IsStringType()) {
+ GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl);
+ return false;
+ }
+ // Otherwise fallthrough.
+ return true;
}
@@ -116,13 +175,70 @@
}
+// Inputs:
+// - R0: instance being type checked (preserved).
+// - R1: optional instantiator type arguments (preserved).
+// Clobbers R2, R3.
+// Returns:
+// - preserved instance in R0 and optional instantiator type arguments in R1.
+// Note that this inlined code must be followed by the runtime_call code, as it
+// may fall through to it. Otherwise, this inline code will jump to the label
+// is_instance or to the label is_not_instance.
RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof(
intptr_t token_pos,
const AbstractType& type,
Label* is_instance_lbl,
Label* is_not_instance_lbl) {
- UNIMPLEMENTED();
- return NULL;
+ __ Comment("InlineInstanceof");
+ if (type.IsVoidType()) {
+ // A non-null value is returned from a void function, which will result in a
+ // type error. A null value is handled prior to executing this inline code.
+ return SubtypeTestCache::null();
+ }
+ if (TypeCheckAsClassEquality(type)) {
+ const intptr_t type_cid = Class::Handle(type.type_class()).id();
+ const Register kInstanceReg = R0;
+ __ tst(kInstanceReg, ShifterOperand(kSmiTagMask));
+ if (type_cid == kSmiCid) {
+ __ b(is_instance_lbl, EQ);
+ } else {
+ __ b(is_not_instance_lbl, EQ);
+ __ CompareClassId(kInstanceReg, type_cid, R3);
+ __ b(is_instance_lbl, EQ);
+ }
+ __ b(is_not_instance_lbl);
+ return SubtypeTestCache::null();
+ }
+ if (type.IsInstantiated()) {
+ const Class& type_class = Class::ZoneHandle(type.type_class());
+ // A Smi object cannot be the instance of a parameterized class.
+ // A class equality check is only applicable with a dst type of a
+ // non-parameterized class or with a raw dst type of a parameterized class.
+ if (type_class.HasTypeArguments()) {
+ return GenerateInstantiatedTypeWithArgumentsTest(token_pos,
+ type,
+ is_instance_lbl,
+ is_not_instance_lbl);
+ // Fall through to runtime call.
+ }
+ const bool has_fall_through =
+ GenerateInstantiatedTypeNoArgumentsTest(token_pos,
+ type,
+ is_instance_lbl,
+ is_not_instance_lbl);
+ if (has_fall_through) {
+ // If test non-conclusive so far, try the inlined type-test cache.
+ // 'type' is known at compile time.
+ return GenerateSubtype1TestCacheLookup(
+ token_pos, type_class, is_instance_lbl, is_not_instance_lbl);
+ } else {
+ return SubtypeTestCache::null();
+ }
+ }
+ return GenerateUninstantiatedTypeTest(token_pos,
+ type,
+ is_instance_lbl,
+ is_not_instance_lbl);
}
@@ -135,12 +251,90 @@
}
+// Optimize assignable type check by adding inlined tests for:
+// - NULL -> return NULL.
+// - Smi -> compile time subtype check (only if dst class is not parameterized).
+// - Class equality (only if class is not parameterized).
+// Inputs:
+// - R0: instance being type checked.
+// - R1: instantiator type arguments or raw_null.
+// - R2: instantiator or raw_null.
+// Returns:
+// - object in R0 for successful assignable check (or throws TypeError).
+// Performance notes: positive checks must be quick, negative checks can be slow
+// as they throw an exception.
void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos,
intptr_t deopt_id,
const AbstractType& dst_type,
const String& dst_name,
LocationSummary* locs) {
- UNIMPLEMENTED();
+ ASSERT(token_pos >= 0);
+ ASSERT(!dst_type.IsNull());
+ ASSERT(dst_type.IsFinalized());
+ // Assignable check is skipped in FlowGraphBuilder, not here.
+ ASSERT(dst_type.IsMalformed() ||
+ (!dst_type.IsDynamicType() && !dst_type.IsObjectType()));
+ // Preserve instantiator and its type arguments.
+ __ PushList((1 << R1) | (1 << R2));
+ // A null object is always assignable and is returned as result.
+ Label is_assignable, runtime_call;
+ __ CompareImmediate(R0, reinterpret_cast<int32_t>(Object::null()));
+ __ b(&is_assignable, EQ);
+
+ if (!FLAG_eliminate_type_checks) {
+ // If type checks are not eliminated during the graph building then
+ // a transition sentinel can be seen here.
+ __ CompareObject(R0, Object::transition_sentinel());
+ __ b(&is_assignable, EQ);
+ }
+
+ // Generate throw new TypeError() if the type is malformed.
+ if (dst_type.IsMalformed()) {
+ const Error& error = Error::Handle(dst_type.malformed_error());
+ const String& error_message = String::ZoneHandle(
+ Symbols::New(error.ToErrorCString()));
+ __ PushObject(Object::ZoneHandle()); // Make room for the result.
+ __ Push(R0); // Push the source object.
+ __ PushObject(dst_name); // Push the name of the destination.
+ __ PushObject(error_message);
+ GenerateCallRuntime(token_pos,
+ deopt_id,
+ kMalformedTypeErrorRuntimeEntry,
+ locs);
+ // We should never return here.
+ __ bkpt(0);
+
+ __ Bind(&is_assignable); // For a null object.
+ // Restore instantiator and its type arguments.
+ __ PopList((1 << R1) | (1 << R2));
+ return;
+ }
+
+ // Generate inline type check, linking to runtime call if not assignable.
+ SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
+ test_cache = GenerateInlineInstanceof(token_pos, dst_type,
+ &is_assignable, &runtime_call);
+
+ __ Bind(&runtime_call);
+ // Load instantiator and its type arguments.
+ __ ldm(IA, SP, (1 << R1) | (1 << R2));
+ __ PushObject(Object::ZoneHandle()); // Make room for the result.
+ __ Push(R0); // Push the source object.
+ __ PushObject(dst_type); // Push the type of the destination.
+ // Push instantiator and its type arguments.
+ __ PushList((1 << R1) | (1 << R2));
+ __ PushObject(dst_name); // Push the name of the destination.
+ __ LoadObject(R0, test_cache);
+ __ Push(R0);
+ GenerateCallRuntime(token_pos, deopt_id, kTypeCheckRuntimeEntry, locs);
+ // Pop the parameters supplied to the runtime entry. The result of the
+ // type check runtime call is the checked value.
+ __ Drop(6);
+ __ Pop(R0);
+
+ __ Bind(&is_assignable);
+ // Restore instantiator and its type arguments.
+ __ PopList((1 << R1) | (1 << R2));
}
« no previous file with comments | « runtime/vm/assembler_arm.cc ('k') | runtime/vm/flow_graph_compiler_ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698