Chromium Code Reviews| Index: runtime/vm/code_generator_ia32.cc |
| =================================================================== |
| --- runtime/vm/code_generator_ia32.cc (revision 6416) |
| +++ runtime/vm/code_generator_ia32.cc (working copy) |
| @@ -667,7 +667,7 @@ |
| } |
| if (FLAG_trace_functions) { |
| const Function& function = |
| - Function::ZoneHandle(parsed_function_.function().raw()); |
| + Function::ZoneHandle(parsed_function_.function().raw()); |
| __ LoadObject(EBX, function); |
| __ pushl(EAX); // Preserve result. |
| __ pushl(EBX); |
| @@ -723,8 +723,6 @@ |
| // Generate type check. |
| if (FLAG_enable_type_checks) { |
| - const bool returns_null = node->value()->IsLiteralNode() && |
| - node->value()->AsLiteralNode()->literal().IsNull(); |
| const RawFunction::Kind kind = parsed_function().function().kind(); |
| const bool is_implicit_getter = |
| (kind == RawFunction::kImplicitGetter) || |
| @@ -732,10 +730,11 @@ |
| const bool is_static = parsed_function().function().is_static(); |
| // Implicit getters do not need a type check at return, unless they compute |
| // the initial value of a static field. |
| - if (!returns_null && (is_static || !is_implicit_getter)) { |
| + if (is_static || !is_implicit_getter) { |
| GenerateAssertAssignable( |
| node->id(), |
| node->value()->token_index(), |
| + node->value(), |
| AbstractType::ZoneHandle(parsed_function().function().result_type()), |
| String::ZoneHandle(String::NewSymbol("function result"))); |
| } |
| @@ -762,6 +761,7 @@ |
| __ popl(EAX); |
| GenerateAssertAssignable(node->id(), |
| node->token_index(), |
| + node->expr(), |
| node->type(), |
| node->dst_name()); |
| if (IsResultNeeded(node)) { |
| @@ -971,6 +971,7 @@ |
| if (FLAG_enable_type_checks) { |
| GenerateAssertAssignable(node->id(), |
| node->value()->token_index(), |
| + node->value(), |
| node->local().type(), |
| node->local().name()); |
| } |
| @@ -1000,6 +1001,7 @@ |
| if (FLAG_enable_type_checks) { |
| GenerateAssertAssignable(node->id(), |
| node->value()->token_index(), |
| + node->value(), |
| AbstractType::ZoneHandle(node->field().type()), |
| String::ZoneHandle(node->field().name())); |
| } |
| @@ -1103,6 +1105,7 @@ |
| if (FLAG_enable_type_checks) { |
| GenerateAssertAssignable(node->id(), |
| node->value()->token_index(), |
| + node->value(), |
| AbstractType::ZoneHandle(node->field().type()), |
| String::ZoneHandle(node->field().name())); |
| } |
| @@ -1189,6 +1192,7 @@ |
| if (FLAG_enable_type_checks) { |
| GenerateAssertAssignable(node->id(), |
| node->token_index(), |
| + NULL, |
| node->local().type(), |
| node->local().name()); |
| } |
| @@ -1281,7 +1285,8 @@ |
| } |
| -// Optimize instanceof type test by adding inlined tests for: |
| +// If instanceof type test cannot be performed successfully at compile time and |
| +// therefore eliminated, optimize it by adding inlined tests for: |
| // - NULL -> return false. |
| // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| // - Class equality (only if class is not parameterized). |
| @@ -1292,13 +1297,14 @@ |
| // - true or false on stack. |
| void CodeGenerator::GenerateInstanceOf(intptr_t node_id, |
| intptr_t token_index, |
| + AstNode* value, |
| const AbstractType& type, |
| bool negate_result) { |
| ASSERT(type.IsFinalized() && !type.IsMalformed()); |
| const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| - // All instances are of a subtype of the Object type. |
| + // All objects are instances of type T if Object type is a subtype of type T. |
| const Type& object_type = |
| Type::Handle(Isolate::Current()->object_store()->object_type()); |
| Error& malformed_error = Error::Handle(); |
| @@ -1308,6 +1314,30 @@ |
| return; |
| } |
| + // Eliminate the test if it can be performed successfully at compile time. |
| + if ((value != NULL) && value->IsLiteralNode() && type.IsInstantiated()) { |
| + const Instance& literal_value = value->AsLiteralNode()->literal(); |
| + const Class& cls = Class::Handle(literal_value.clazz()); |
| + if (cls.IsNullClass()) { |
| + ASSERT(literal_value.IsNull() || |
| + (literal_value.raw() == Object::sentinel()) || |
| + (literal_value.raw() == Object::transition_sentinel())); |
| + // A null object is only an instance of Object and Dynamic, which has |
| + // already been checked above (if the type is instantiated). So we can |
| + // return false here if the instance is null (and if the type is |
| + // instantiated). |
| + __ PushObject(negate_result ? bool_true : bool_false); |
| + return; |
| + } |
| + Error& malformed_error = Error::Handle(); |
| + if (literal_value.IsInstanceOf(type, |
| + TypeArguments::Handle(), |
| + &malformed_error)) { |
| + __ PushObject(negate_result ? bool_false : bool_true); |
| + return; |
| + } |
|
srdjan
2012/04/11 17:25:08
shouldn't there be an else with __PushObject(negat
regis
2012/04/11 17:42:12
Yes, indeed. I wanted to handle the malformed type
|
| + } |
| + |
| const Immediate raw_null = |
| Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| Label done, check_negate_done; |
| @@ -1488,7 +1518,8 @@ |
| } |
| -// Optimize assignable type check by adding inlined tests for: |
| +// If type check cannot be performed successfully at compile time and therefore |
| +// eliminated, optimize it 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). |
| @@ -1501,6 +1532,7 @@ |
| // as they throw an exception. |
| void CodeGenerator::GenerateAssertAssignable(intptr_t node_id, |
| intptr_t token_index, |
| + AstNode* value, |
| const AbstractType& dst_type, |
| const String& dst_name) { |
| ASSERT(FLAG_enable_type_checks); |
| @@ -1524,6 +1556,26 @@ |
| return; |
| } |
| + // Eliminate the test if it can be performed successfully at compile time. |
| + if ((value != NULL) && value->IsLiteralNode()) { |
| + const Instance& literal_value = value->AsLiteralNode()->literal(); |
| + const Class& cls = Class::Handle(literal_value.clazz()); |
| + if (cls.IsNullClass()) { |
| + ASSERT(literal_value.IsNull() || |
| + (literal_value.raw() == Object::sentinel()) || |
| + (literal_value.raw() == Object::transition_sentinel())); |
| + return; |
| + } |
| + Error& malformed_error = Error::Handle(); |
| + if (!dst_type.IsMalformed() && |
| + dst_type.IsInstantiated() && |
| + literal_value.IsInstanceOf(dst_type, |
| + TypeArguments::Handle(), |
| + &malformed_error)) { |
| + return; |
| + } |
| + } |
| + |
| // A null object is always assignable and is returned as result. |
| const Immediate raw_null = |
| Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| @@ -1748,6 +1800,7 @@ |
| GenerateLoadVariable(EAX, *parameter); |
| GenerateAssertAssignable(AstNode::kNoId, |
| parameter->token_index(), |
| + NULL, |
| parameter->type(), |
| parameter->name()); |
| } |
| @@ -1804,6 +1857,7 @@ |
| ASSERT(node->right()->IsTypeNode()); |
| GenerateInstanceOf(node->id(), |
| node->token_index(), |
| + node->left(), |
| node->right()->AsTypeNode()->type(), |
| (node->kind() == Token::kISNOT)); |
| if (!IsResultNeeded(node)) { |