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

Unified Diff: runtime/vm/flow_graph_compiler_x64.cc

Issue 9665029: Generate code for instance of: copy from CodeGenerator. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 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/flow_graph_compiler_x64.h ('k') | runtime/vm/intermediate_language.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/flow_graph_compiler_x64.cc
===================================================================
--- runtime/vm/flow_graph_compiler_x64.cc (revision 5328)
+++ runtime/vm/flow_graph_compiler_x64.cc (working copy)
@@ -11,6 +11,7 @@
#include "vm/code_generator.h"
#include "vm/disassembler.h"
#include "vm/longjump.h"
+#include "vm/object_store.h"
#include "vm/parser.h"
#include "vm/stub_code.h"
@@ -327,8 +328,183 @@
}
+static const Class* CoreClass(const char* c_name) {
+ const String& class_name = String::Handle(String::NewSymbol(c_name));
+ const Class& cls = Class::ZoneHandle(Library::Handle(
+ Library::CoreImplLibrary()).LookupClass(class_name));
+ ASSERT(!cls.IsNull());
+ return &cls;
+}
+
+
+void FlowGraphCompiler::GenerateInstantiatorTypeArguments(
+ intptr_t token_index) {
+ Bailout("FlowGraphCompiler::GenerateInstantiatorTypeArguments");
+}
+
+
+// Copied from CodeGenerator.
+// Optimize instanceof type test 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).
+// Inputs:
+// - RAX: object.
+// Destroys RCX.
+// Returns:
+// - true or false in RAX.
+void FlowGraphCompiler::GenerateInstanceOf(intptr_t node_id,
+ intptr_t token_index,
+ 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.
+ const Type& object_type =
+ Type::Handle(Isolate::Current()->object_store()->object_type());
+ Error& malformed_error = Error::Handle();
+ if (type.IsInstantiated() &&
+ object_type.IsSubtypeOf(type, &malformed_error)) {
+ __ LoadObject(RAX, negate_result ? bool_false : bool_true);
+ return;
+ }
+
+ const Immediate raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
+ Label done;
+ // If type is instantiated and non-parameterized, we can inline code
+ // checking whether the tested instance is a Smi.
+ if (type.IsInstantiated()) {
+ // 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).
+ // We can only inline this null check if the type is instantiated at compile
+ // time, since an uninstantiated type at compile time could be Object or
+ // Dynamic at run time.
+ Label non_null;
+ __ cmpq(RAX, raw_null);
+ __ j(NOT_EQUAL, &non_null, Assembler::kNearJump);
+ __ PushObject(negate_result ? bool_true : bool_false);
+ __ jmp(&done);
+
+ __ Bind(&non_null);
+
+ const Class& type_class = Class::ZoneHandle(type.type_class());
+ const bool requires_type_arguments = type_class.HasTypeArguments();
+ // 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 (requires_type_arguments) {
+ const AbstractTypeArguments& type_arguments =
+ AbstractTypeArguments::Handle(type.arguments());
+ const bool is_raw_type = type_arguments.IsNull() ||
+ type_arguments.IsDynamicTypes(type_arguments.Length());
+ Label runtime_call;
+ __ testq(RAX, Immediate(kSmiTagMask));
+ __ j(ZERO, &runtime_call, Assembler::kNearJump);
+ // Object not Smi.
+ if (is_raw_type) {
+ if (type.IsListInterface()) {
+ Label push_result;
+ // TODO(srdjan) also accept List<Object>.
+ __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
+ __ CompareObject(RCX, *CoreClass("ObjectArray"));
+ __ j(EQUAL, &push_result, Assembler::kNearJump);
+ __ CompareObject(RCX, *CoreClass("GrowableObjectArray"));
+ __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump);
+ __ Bind(&push_result);
+ __ PushObject(negate_result ? bool_false : bool_true);
+ __ jmp(&done);
+ } else if (!type_class.is_interface()) {
+ __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
+ __ CompareObject(RCX, type_class);
+ __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump);
+ __ PushObject(negate_result ? bool_false : bool_true);
+ __ jmp(&done);
+ }
+ }
+ __ Bind(&runtime_call);
+ // Fall through to runtime call.
+ } else {
+ Label compare_classes;
+ __ testq(RAX, Immediate(kSmiTagMask));
+ __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump);
+ // Object is Smi.
+ const Class& smi_class = Class::Handle(Smi::Class());
+ // TODO(regis): We should introduce a SmiType.
+ Error& malformed_error = Error::Handle();
+ if (smi_class.IsSubtypeOf(TypeArguments::Handle(),
+ type_class,
+ TypeArguments::Handle(),
+ &malformed_error)) {
+ __ PushObject(negate_result ? bool_false : bool_true);
+ } else {
+ __ PushObject(negate_result ? bool_true : bool_false);
+ }
+ __ jmp(&done);
+
+ // Compare if the classes are equal.
+ __ Bind(&compare_classes);
+ const Class* compare_class = NULL;
+ if (type.IsStringInterface()) {
+ compare_class = &Class::ZoneHandle(
+ Isolate::Current()->object_store()->one_byte_string_class());
+ } else if (type.IsBoolInterface()) {
+ compare_class = &Class::ZoneHandle(
+ Isolate::Current()->object_store()->bool_class());
+ } else if (!type_class.is_interface()) {
+ compare_class = &type_class;
+ }
+ if (compare_class != NULL) {
+ Label runtime_call;
+ __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
+ __ CompareObject(RCX, *compare_class);
+ __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump);
+ __ PushObject(negate_result ? bool_false : bool_true);
+ __ jmp(&done, Assembler::kNearJump);
+ __ Bind(&runtime_call);
+ }
+ }
+ }
+ __ PushObject(Object::ZoneHandle()); // Make room for the result.
+ const Immediate location =
+ Immediate(reinterpret_cast<int64_t>(Smi::New(token_index)));
+ __ pushq(location); // Push the source location.
+ __ pushq(RAX); // Push the instance.
+ __ PushObject(type); // Push the type.
+ if (!type.IsInstantiated()) {
+ GenerateInstantiatorTypeArguments(token_index);
+ } else {
+ __ pushq(raw_null); // Null instantiator.
+ }
+ GenerateCallRuntime(node_id, token_index, kInstanceofRuntimeEntry);
+ // Pop the two parameters supplied to the runtime entry. The result of the
+ // instanceof runtime call will be left as the result of the operation.
+ __ addq(RSP, Immediate(4 * kWordSize));
+ if (negate_result) {
+ Label negate_done;
+ __ popq(RDX);
+ __ LoadObject(RAX, bool_true);
+ __ cmpq(RDX, RAX);
+ __ j(NOT_EQUAL, &negate_done, Assembler::kNearJump);
+ __ LoadObject(RAX, bool_false);
+ __ Bind(&negate_done);
+ __ pushq(RAX);
+ }
+ __ Bind(&done);
+ __ popq(RAX);
+}
+
+
void FlowGraphCompiler::VisitInstanceOf(InstanceOfComp* comp) {
- Bailout("InstanceOf");
+ __ popq(RAX);
+ GenerateInstanceOf(comp->node_id(),
+ comp->token_index(),
+ comp->type(),
+ comp->negate_result());
}
« no previous file with comments | « runtime/vm/flow_graph_compiler_x64.h ('k') | runtime/vm/intermediate_language.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698