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:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user