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

Unified Diff: vm/ic_stubs_ia32.cc

Issue 8379013: Implement new inline cache. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/runtime/
Patch Set: '' Created 9 years, 2 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 | « vm/ic_stubs_arm.cc ('k') | vm/ic_stubs_ia32_test.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: vm/ic_stubs_ia32.cc
===================================================================
--- vm/ic_stubs_ia32.cc (revision 700)
+++ vm/ic_stubs_ia32.cc (working copy)
@@ -1,358 +0,0 @@
-// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
-// 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.
-
-#include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32.
-#if defined(TARGET_ARCH_IA32)
-
-#include "vm/ic_stubs.h"
-
-#include "vm/assembler.h"
-#include "vm/code_index_table.h"
-#include "vm/disassembler.h"
-#include "vm/flags.h"
-#include "vm/instructions.h"
-#include "vm/object.h"
-#include "vm/object_store.h"
-#include "vm/stub_code.h"
-
-namespace dart {
-
-DECLARE_FLAG(bool, disassemble_stubs);
-DEFINE_FLAG(bool, enable_polymorphic_ic, true,
- "Enable polymorphic inline caching");
-DEFINE_FLAG(bool, trace_icstub_generation, false,
- "Print every generated IC stub");
-
-
-// TODO(srdjan): Move FindInCode and AppendICStubToTargets into the shared file.
-
-// Add 'classes' and 'ic_stub' to all 'targets'. Each target's code
-// (class RawCode) has an array of (classes-array, ic_stub) pairs.
-void ICStubs::AppendICStubToTargets(
- const GrowableArray<const Function*>& targets,
- const GrowableArray<const Class*>& classes,
- const Code& ic_stub) {
- if (FLAG_trace_icstub_generation) {
- OS::Print("Appending ICstub 0x%x to targets:\n", ic_stub.EntryPoint());
- }
- Code& target = Code::Handle();
- Array& class_ic_stubs_array = Array::Handle();
- Code& test_ic_stub = Code::Handle();
- for (intptr_t i = 0; i < targets.length(); i++) {
- target = Code::Handle(targets[i]->code()).raw();
- if (FLAG_trace_icstub_generation) {
- OS::Print(" * code 0x%x\n", target.EntryPoint());
- }
- // Do not add twice: two different classes may have the same target.
- test_ic_stub = ICStubs::FindInCode(target, classes);
- if (test_ic_stub.IsNull()) {
- // Append one class/ic-stub pair entry.
- // Grow the array by two (one pair).
- class_ic_stubs_array = target.class_ic_stubs();
- intptr_t new_length = class_ic_stubs_array.Length() + 2;
- class_ic_stubs_array = Array::Grow(class_ic_stubs_array, new_length);
- target.set_class_ic_stubs(class_ic_stubs_array);
- // Create classes array out of GrowableArray classes.
- Array& a = Array::Handle(Array::New(classes.length()));
- for (intptr_t i = 0; i < classes.length(); i++) {
- a.SetAt(i, *classes[i]);
- }
- class_ic_stubs_array.SetAt(new_length - 2, a);
- class_ic_stubs_array.SetAt(new_length - 1, ic_stub);
- if (FLAG_trace_icstub_generation) {
- OS::Print(" + icstub 0x%x\n", ic_stub.EntryPoint());
- }
- } else {
- if (FLAG_trace_icstub_generation) {
- OS::Print(" . icstub 0x%x\n", test_ic_stub.EntryPoint());
- }
- }
- }
-}
-
-
-// Return true if class 'test' is contained in array 'classes'.
-static bool IsClassInArray(const Class& test,
- const GrowableArray<const Class*>& classes) {
- for (intptr_t i = 0; i < classes.length(); i++) {
- if (classes[i]->raw() == test.raw()) {
- return true;
- }
- }
- return false;
-}
-
-
-// Linear search for the ic stub with given 'classes'. RawCode::class_ic_stubs()
-// returns an array of (classes-array, ic-stub-code) pairs. Returns
-// RawCode::null() if no stub is found.
-RawCode* ICStubs::FindInCode(const Code& target,
- const GrowableArray<const Class*>& classes) {
- Code& result = Code::Handle();
- if (classes.is_empty()) {
- return result.raw(); // RawCode::null().
- }
- Array& class_ic_stubs = Array::Handle(target.class_ic_stubs());
- const intptr_t len = class_ic_stubs.Length();
- Array& array = Array::Handle();
- Class& cls = Class::Handle();
- // Iterate over all stored IC stubs/array classes pairs until match found.
- for (intptr_t i = 0; i < len; i += 2) {
- // i: array of classes, i + 1: ic stub code.
- array ^= class_ic_stubs.At(i);
- if (array.Length() == classes.length()) {
- bool classes_match = true;
- for (intptr_t k = 0; k < array.Length(); k++) {
- cls ^= array.At(k);
- if (!IsClassInArray(cls, classes)) {
- classes_match = false;
- break;
- }
- }
- if (classes_match) {
- // Found matching stub.
- result ^= class_ic_stubs.At(i + 1);
- break;
- }
- }
- }
- // If no matching stub is found, result.raw() returns null.
- return result.raw();
-}
-
-
-int ICStubs::IndexOfClass(const GrowableArray<const Class*>& classes,
- const Class& cls) {
- for (intptr_t i = 0; i < classes.length(); i++) {
- if (classes[i]->raw() == cls.raw()) {
- return i;
- }
- }
- return -1;
-}
-
-
-// An IC Stub starts with a Smi test, optionally followed by a null test
-// and zero or more class tests. The "StubCode::CallInstanceFunction"
-// corresponds to an IC stub without any classes or targets.
-bool ICStubs::RecognizeICStub(uword ic_entry_point,
- GrowableArray<const Class*>* classes,
- GrowableArray<const Function*>* targets) {
- if (ic_entry_point == StubCode::CallInstanceFunctionLabel().address()) {
- // Unresolved instance call, no classes collected yet.
- return true;
- }
- if (ic_entry_point == StubCode::MegamorphicLookupEntryPoint()) {
- // NoSuchMethod call, no classes collected.
- return true;
- }
- return ParseICStub(ic_entry_point, classes, targets, 0, 0);
-}
-
-
-void ICStubs::PatchTargets(uword ic_entry_point, uword from, uword to) {
- bool is_ok = ParseICStub(ic_entry_point, NULL, NULL, from, to);
- ASSERT(is_ok);
-}
-
-
-// Parse IC stub, collect 'classes' and 'targets' and patches
-// all 'from' targets with 'to' targets. No collection occurs
-// if 'classes' and 'targets' are NULL, no patching occurs if
-// 'from' or 'to' is 0.
-// The IC structure is defined in IcStubs::GetIcStub.
-bool ICStubs::ParseICStub(uword ic_entry_point,
- GrowableArray<const Class*>* classes,
- GrowableArray<const Function*>* targets,
- uword from,
- uword to) {
- uword instruction_address = ic_entry_point;
- bool patch_code = (from != 0) && (to != 0);
- if (classes != NULL) {
- classes->Clear();
- }
- if (targets != NULL) {
- targets->Clear();
- }
-
- // Part A: Load receiver, test if Smi, jump to IC miss or hit.
- ICLoadReceiver load_receiver(instruction_address);
- if (!load_receiver.IsValid()) {
- return false; // Not an an IC stub.
- }
- instruction_address += load_receiver.pattern_length_in_bytes();
-
- TestEaxIsSmi test_smi(instruction_address);
- // The target of the Smi test determines if the test should cause
- // IC miss if successful or jump to target (IC hit). Target of IC miss is the
- // stub code, target of IC success is a code object.
- CodeIndexTable* ci_table = Isolate::Current()->code_index_table();
- ASSERT(ci_table != NULL);
-
- Instructions& inst = Instructions::Handle(
- Instructions::FromEntryPoint(ic_entry_point));
- ASSERT(!inst.IsNull());
-
- if (!StubCode::InCallInstanceFunctionStubCode(test_smi.TargetAddress())) {
- // Jump is an IC success.
- if (patch_code && (test_smi.TargetAddress() == from)) {
- test_smi.SetTargetAddress(to);
- }
- const Class& smi_class =
- Class::ZoneHandle(Isolate::Current()->object_store()->smi_class());
- const Code& smi_code =
- Code::Handle(ci_table->LookupCode(test_smi.TargetAddress()));
- ASSERT(!smi_class.IsNullClass());
- ASSERT(!smi_code.IsNull());
- if (classes != NULL) {
- classes->Add(&smi_class);
- }
- if (targets != NULL) {
- targets->Add(&Function::ZoneHandle(smi_code.function()));
- }
- }
- instruction_address += test_smi.pattern_length_in_bytes();
-
- // TODO(srdjan): Add checks that the IC stub ends with
- // a null check and a jmp.
- // Part B: Load receiver's class, compare with all known classes.
- LoadObjectClass load_object_class(instruction_address);
- if (!load_object_class.IsValid()) {
- return false;
- }
- instruction_address += load_object_class.pattern_length_in_bytes();
- while (true) {
- ICCheckReceiverClass check_class(instruction_address);
- if (!check_class.IsValid()) {
- // Done parsing.
- return true;
- }
- if (patch_code && (check_class.TargetAddress() == from)) {
- check_class.SetTargetAddress(to);
- }
- const Class& cls = Class::ZoneHandle(check_class.TestClass());
- const Code& code = Code::ZoneHandle(
- ci_table->LookupCode(check_class.TargetAddress()));
- ASSERT(!cls.IsNullClass());
- ASSERT(!code.IsNull());
- if (classes != NULL) {
- classes->Add(&cls);
- }
- if (targets != NULL) {
- targets->Add(&Function::ZoneHandle(code.function()));
- }
- instruction_address += check_class.pattern_length_in_bytes();
- }
-}
-
-
-// Generate inline cache stub for given targets and classes.
-// EDX: arguments descriptor array (preserved).
-// ECX: function name (unused, preserved).
-// TOS: return address.
-// Jump to target if the receiver's class matches the 'receiver_class'.
-// Otherwise jump to megamorphic lookup. TODO(srdjan): Patch call site to go to
-// megamorphic instead of going via the IC stub.
-// IC stub structure:
-// A: Get receiver, test if Smi, jump to IC miss or hit.
-// B: Get receiver's class, compare with all known classes.
-RawCode* ICStubs::GetICStub(const GrowableArray<const Class*>& classes,
- const GrowableArray<const Function*>& targets) {
- // Check if a matching IC stub already exists.
- Code& ic_stub_code = Code::Handle();
- for (intptr_t i = 0; i < targets.length(); i++) {
- ic_stub_code =
- ICStubs::FindInCode(Code::Handle(targets[i]->code()), classes);
- if (!ic_stub_code.IsNull()) {
- return ic_stub_code.raw(); // Reusing the previously created IC stub.
- }
- }
-
- // Call IC miss handling only if polymorphic inline caching is on, otherwise
- // continue in megamorphic lookup.
- const ExternalLabel* ic_miss_label =
- FLAG_enable_polymorphic_ic
- ? &StubCode::CallInstanceFunctionLabel()
- : &StubCode::MegamorphicLookupLabel();
-
-#define __ assembler.
- Assembler assembler;
- // Part A: Get receiver, test if Smi.
- // Total number of args is the first Smi in args descriptor array (EDX).
- __ movl(EAX, FieldAddress(EDX, Array::data_offset()));
- __ movl(EAX, Address(ESP, EAX, TIMES_2, 0)); // Get receiver. EAX is a Smi.
- __ testl(EAX, Immediate(kSmiTagMask));
-
- const Class& smi_class = Class::Handle(
- Isolate::Current()->object_store()->smi_class());
- const int smi_class_index = IndexOfClass(classes, smi_class);
- if (smi_class_index >= 0) {
- // Smi is not IC miss.
- const Code& target = Code::Handle(targets[smi_class_index]->code());
- ExternalLabel target_label("ICtoTargetSmi", target.EntryPoint());
- // Always check for Smi first and either go to target or call ic-miss.
- __ j(ZERO, &target_label);
- } else {
- // Smi is IC miss.
- __ j(ZERO, ic_miss_label);
- }
-
- // Part B: Load receiver's class, compare with all known classes.
- __ movl(EBX, FieldAddress(EAX, Object::class_offset()));
- for (int cli = 0; cli < classes.length(); cli++) {
- const Class* test_class = classes[cli];
- ASSERT(!test_class->IsNullClass());
- if (test_class->raw() != smi_class.raw()) {
- const Code& target = Code::Handle(targets[cli]->code());
- ExternalLabel target_label("ICtoTargetClass", target.EntryPoint());
- __ CompareObject(EBX, *test_class);
- __ j(EQUAL, &target_label);
- }
- }
- // IC miss. If null jump to megamorphic (don't trash IC), otherwise to IC
- // miss in order to update the IC.
- const Immediate raw_null =
- Immediate(reinterpret_cast<intptr_t>(Object::null()));
- __ cmpl(EAX, raw_null);
- __ j(EQUAL, &StubCode::MegamorphicLookupLabel());
-
- __ jmp(ic_miss_label);
- ic_stub_code = Code::FinalizeCode("inline cache stub", &assembler);
- ICStubs::AppendICStubToTargets(targets, classes, ic_stub_code);
-
- if (FLAG_trace_icstub_generation) {
- OS::Print("IC Stub code generated at 0x%x: targets: %d, classes: %d\n",
- ic_stub_code.EntryPoint(), targets.length(), classes.length());
- for (intptr_t i = 0; i < targets.length(); i++) {
- OS::Print(" target: 0x%x class: %s\n",
- Code::Handle(targets[i]->code()).EntryPoint(),
- classes[i]->ToCString());
- }
- }
-
- if (FLAG_disassemble_stubs) {
- for (intptr_t i = 0; i < classes.length(); i++) {
- ASSERT(classes[i]->raw() != Object::null_class());
- const String& class_name = String::Handle(classes[i]->Name());
- CodeIndexTable* code_index_table = Isolate::Current()->code_index_table();
- const Code& target = Code::Handle(targets[i]->code());
- const Function& function =
- Function::Handle(
- code_index_table->LookupFunction(target.EntryPoint()));
- OS::Print("%d: Code for inline cache for class '%s' function '%s': {\n",
- i, class_name.ToCString(), function.ToFullyQualifiedCString());
- }
- Disassembler::Disassemble(ic_stub_code.EntryPoint(),
- ic_stub_code.EntryPoint() + assembler.CodeSize());
- OS::Print("}\n");
- }
-
- return ic_stub_code.raw();
-#undef __
-}
-
-
-} // namespace dart
-
-#endif // defined TARGET_ARCH_IA32
« no previous file with comments | « vm/ic_stubs_arm.cc ('k') | vm/ic_stubs_ia32_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698