Intrinsify methods early. Fix some bugs in trinsified code, mark one precision-related bug as SKIP since sometimes it may pass sometimes not.

Review URL: https://chromiumcodereview.appspot.com//9921017

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@5985 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
srdjan@google.com
2012-03-29 17:05:00 +00:00
parent 12d57c09ae
commit c446c19fb7
6 changed files with 86 additions and 74 deletions
+67
View File
@@ -13,6 +13,7 @@
#include "vm/code_descriptors.h"
#include "vm/dart_entry.h"
#include "vm/debugger.h"
#include "vm/intrinsifier.h"
#include "vm/longjump.h"
#include "vm/object.h"
#include "vm/object_store.h"
@@ -30,6 +31,9 @@ DEFINE_FLAG(bool, print_ic_in_optimized, false,
DECLARE_FLAG(int, optimization_counter_threshold);
DECLARE_FLAG(bool, enable_type_checks);
DECLARE_FLAG(bool, trace_compiler);
DECLARE_FLAG(bool, intrinsify);
DECLARE_FLAG(bool, trace_functions);
#define __ assembler_->
@@ -122,6 +126,69 @@ CodeGenerator::CodeGenerator(Assembler* assembler,
}
void CodeGenerator::IntrinsifyGetter() {
// TOS: return address.
// +1 : receiver.
// Sequence node has one return node, its input is oad field node.
const SequenceNode& sequence_node = *parsed_function_.node_sequence();
ASSERT(sequence_node.length() == 1);
ASSERT(sequence_node.NodeAt(0)->IsReturnNode());
const ReturnNode& return_node = *sequence_node.NodeAt(0)->AsReturnNode();
ASSERT(return_node.value()->IsLoadInstanceFieldNode());
const LoadInstanceFieldNode& load_node =
*return_node.value()->AsLoadInstanceFieldNode();
__ movl(EAX, Address(ESP, 1 * kWordSize));
__ movl(EAX, FieldAddress(EAX, load_node.field().Offset()));
__ ret();
}
void CodeGenerator::IntrinsifySetter() {
// TOS: return address.
// +1 : value
// +2 : receiver.
// Sequence node has one store node and one return NULL node.
const SequenceNode& sequence_node = *parsed_function_.node_sequence();
ASSERT(sequence_node.length() == 2);
ASSERT(sequence_node.NodeAt(0)->IsStoreInstanceFieldNode());
ASSERT(sequence_node.NodeAt(1)->IsReturnNode());
const StoreInstanceFieldNode& store_node =
*sequence_node.NodeAt(0)->AsStoreInstanceFieldNode();
__ movl(EAX, Address(ESP, 2 * kWordSize)); // Receiver.
__ movl(EBX, Address(ESP, 1 * kWordSize)); // Value.
__ StoreIntoObject(EAX, FieldAddress(EAX, store_node.field().Offset()), EBX);
const Immediate raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ movl(EAX, raw_null);
__ ret();
}
bool CodeGenerator::TryIntrinsify() {
if (!CanOptimize()) return false;
if (FLAG_intrinsify && !FLAG_trace_functions) {
if ((parsed_function_.function().kind() == RawFunction::kImplicitGetter)) {
IntrinsifyGetter();
return true;
}
// Intrinsification skips arguments checks, therefore disable if in checked
// mode.
if ((parsed_function_.function().kind() == RawFunction::kImplicitSetter) &&
!FLAG_enable_type_checks) {
IntrinsifySetter();
return true;
}
}
// Even if an intrinsified version of the function was successfully
// generated, it may fall through to the non-intrinsified method body.
if (!FLAG_trace_functions) {
return Intrinsifier::Intrinsify(parsed_function().function(), assembler_);
}
return false;
}
bool CodeGenerator::IsResultNeeded(AstNode* node) const {
return !state()->IsRootNode(node);
}
+8 -3
View File
@@ -122,9 +122,14 @@ NODE_LIST(DEFINE_VISITOR_FUNCTION)
// Forward declarations.
class HandlerList;
// Return true if intrinsification was completed and no other code
// needs to be generated.
virtual bool TryIntrinsify() { return false; }
// Return true if intrinsification succeeded and no more code is needed.
// Returns false if either no intrinsification occured or if intrinsified
// code needs the rest for slow case execution.
bool TryIntrinsify();
void IntrinsifyGetter();
void IntrinsifySetter();
virtual void GeneratePreEntryCode();
void GenerateLegacyEntryCode();
void GenerateEntryCode();
+10 -2
View File
@@ -105,6 +105,8 @@ static bool ObjectArray_Allocate(Assembler* assembler) {
// Assert that length is a Smi.
__ testl(EDI, Immediate(kSmiTagSize));
__ j(NOT_ZERO, &fall_through);
__ cmpl(EDI, Immediate(0));
__ j(LESS, &fall_through, Assembler::kNearJump);
intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1;
__ leal(EDI, Address(EDI, TIMES_2, fixed_size)); // EDI is a Smi.
ASSERT(kSmiTagShift == 1);
@@ -121,7 +123,7 @@ static bool ObjectArray_Allocate(Assembler* assembler) {
// EBX: potential next object start.
// EDI: allocation size.
__ cmpl(EBX, Address::Absolute(heap->EndAddress()));
__ j(ABOVE_EQUAL, &fall_through);
__ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump);
// Successfully allocated the object(s), now update top to point to
// next object start and initialize the object.
@@ -138,7 +140,7 @@ static bool ObjectArray_Allocate(Assembler* assembler) {
__ j(ABOVE, &size_tag_overflow, Assembler::kNearJump);
__ shll(EDI, Immediate(RawObject::kSizeTagBit - kObjectAlignmentLog2));
__ movl(FieldAddress(EAX, Array::tags_offset()), EDI); // Tags.
__ jmp(&done);
__ jmp(&done, Assembler::kNearJump);
__ Bind(&size_tag_overflow);
__ movl(FieldAddress(EAX, Array::tags_offset()), Immediate(0));
@@ -487,6 +489,9 @@ static bool Integer_modulo(Assembler* assembler) {
Label fall_through, return_zero;
TestBothArgumentsSmis(assembler, &fall_through);
// EAX: right argument (divisor)
// Check if modulo by zero -> exception thrown in main function.
__ cmpl(EAX, Immediate(0));
__ j(EQUAL, &fall_through, Assembler::kNearJump);
__ movl(EBX, Address(ESP, + 2 * kWordSize)); // Left argument (dividend).
__ cmpl(EBX, Immediate(0));
__ j(LESS, &fall_through, Assembler::kNearJump);
@@ -735,6 +740,9 @@ static bool Integer_sar(Assembler* assembler) {
// For shifting right a Smi the result is the same for all numbers
// >= count_limit.
__ SmiUntag(EAX);
// Negative counts throw exception.
__ cmpl(EAX, Immediate(0));
__ j(LESS, &fall_through, Assembler::kNearJump);
__ cmpl(EAX, count_limit);
__ j(LESS_EQUAL, &shift_count_ok, Assembler::kNearJump);
__ movl(EAX, count_limit);
-61
View File
@@ -9,7 +9,6 @@
#include "vm/assembler_macros.h"
#include "vm/ast_printer.h"
#include "vm/intrinsifier.h"
#include "vm/object.h"
#include "vm/object_store.h"
#include "vm/resolver.h"
@@ -21,8 +20,6 @@ namespace dart {
DEFINE_FLAG(bool, trace_optimization, false, "Trace optimizations.");
DECLARE_FLAG(bool, enable_type_checks);
DECLARE_FLAG(bool, intrinsify);
DECLARE_FLAG(bool, trace_functions);
// Property list to be used in CodeGenInfo. Each property has a setter
@@ -369,64 +366,6 @@ void OptimizingCodeGenerator::TraceNotOpt(AstNode* node, const char* message) {
}
void OptimizingCodeGenerator::IntrinsifyGetter() {
// TOS: return address.
// +1 : receiver.
// Sequence node has one return node, its input is oad field node.
const SequenceNode& sequence_node = *parsed_function_.node_sequence();
ASSERT(sequence_node.length() == 1);
ASSERT(sequence_node.NodeAt(0)->IsReturnNode());
const ReturnNode& return_node = *sequence_node.NodeAt(0)->AsReturnNode();
ASSERT(return_node.value()->IsLoadInstanceFieldNode());
const LoadInstanceFieldNode& load_node =
*return_node.value()->AsLoadInstanceFieldNode();
__ movl(EAX, Address(ESP, 1 * kWordSize));
__ movl(EAX, FieldAddress(EAX, load_node.field().Offset()));
__ ret();
}
void OptimizingCodeGenerator::IntrinsifySetter() {
// TOS: return address.
// +1 : value
// +2 : receiver.
// Sequence node has one store node and one return NULL node.
const SequenceNode& sequence_node = *parsed_function_.node_sequence();
ASSERT(sequence_node.length() == 2);
ASSERT(sequence_node.NodeAt(0)->IsStoreInstanceFieldNode());
ASSERT(sequence_node.NodeAt(1)->IsReturnNode());
const StoreInstanceFieldNode& store_node =
*sequence_node.NodeAt(0)->AsStoreInstanceFieldNode();
__ movl(EAX, Address(ESP, 2 * kWordSize)); // Receiver.
__ movl(EBX, Address(ESP, 1 * kWordSize)); // Value.
__ StoreIntoObject(EAX, FieldAddress(EAX, store_node.field().Offset()), EBX);
const Immediate raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ movl(EAX, raw_null);
__ ret();
}
bool OptimizingCodeGenerator::TryIntrinsify() {
if (FLAG_intrinsify && !FLAG_trace_functions) {
if ((parsed_function_.function().kind() == RawFunction::kImplicitGetter)) {
IntrinsifyGetter();
return true;
}
if ((parsed_function_.function().kind() == RawFunction::kImplicitSetter)) {
IntrinsifySetter();
return true;
}
}
// Even if an intrinsified version of the function was successfully
// generated, it may fall through to the non-intrinsified method body.
if (!FLAG_trace_functions) {
return Intrinsifier::Intrinsify(parsed_function().function(), assembler_);
}
return false;
}
// Check for stack overflow.
// Note that first 5 bytes may be patched with a jump.
// TODO(srdjan): Add check that no object is inlined in the first
-7
View File
@@ -49,10 +49,6 @@ class OptimizingCodeGenerator : public CodeGenerator {
virtual void VisitTryCatchNode(TryCatchNode* node);
virtual void VisitUnaryOpNode(UnaryOpNode* node);
// Return true if intrinsification succeeded and no more code is needed.
// Returns false if either no intrinsification occured or if intrinsified
// code needs the rest for slow case execution.
virtual bool TryIntrinsify();
virtual void GeneratePreEntryCode();
virtual bool IsOptimizing() const { return true; }
@@ -76,9 +72,6 @@ class OptimizingCodeGenerator : public CodeGenerator {
Register reg3,
DeoptReasonId reason_id);
void IntrinsifyGetter();
void IntrinsifySetter();
void InlineInstanceGettersWithSameTarget(AstNode* node,
intptr_t id,
AstNode* receiver,
+1 -1
View File
@@ -99,7 +99,7 @@ LibTest/core/int/toStringAsPrecision_A01_t01: Fail, Crash # Issue 460
LibTest/core/Math/acos_A01_t01: Fail # Issue co19 - 44
LibTest/core/Math/asin_A01_t01: Fail # Issue co19 - 44
LibTest/core/Math/atan_A01_t01: Fail # Issue co19 - 44
LibTest/core/Math/cos_A01_t01: Fail # Issue co19 - 44
LibTest/core/Math/cos_A01_t01: Skip # Issue co19 - 44
LibTest/core/Math/exp_A01_t01: Fail # Issue co19 - 44
LibTest/core/Math/sin_A01_t01: Fail # Issue co19 - 44
LibTest/core/Math/tan_A01_t01: Fail # Issue co19 - 44