From c446c19fb72684b8e532f6f6d73133b4e1f005a1 Mon Sep 17 00:00:00 2001 From: "srdjan@google.com" Date: Thu, 29 Mar 2012 17:05:00 +0000 Subject: [PATCH] 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 --- runtime/vm/code_generator_ia32.cc | 67 +++++++++++++++++++++++++++ runtime/vm/code_generator_ia32.h | 11 +++-- runtime/vm/intrinsifier_ia32.cc | 12 ++++- runtime/vm/opt_code_generator_ia32.cc | 61 ------------------------ runtime/vm/opt_code_generator_ia32.h | 7 --- tests/co19/co19-runtime.status | 2 +- 6 files changed, 86 insertions(+), 74 deletions(-) diff --git a/runtime/vm/code_generator_ia32.cc b/runtime/vm/code_generator_ia32.cc index d6957f23e10..5f385e11c7f 100644 --- a/runtime/vm/code_generator_ia32.cc +++ b/runtime/vm/code_generator_ia32.cc @@ -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(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); } diff --git a/runtime/vm/code_generator_ia32.h b/runtime/vm/code_generator_ia32.h index ceb17b2b993..df38e6db197 100644 --- a/runtime/vm/code_generator_ia32.h +++ b/runtime/vm/code_generator_ia32.h @@ -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(); diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc index d66393a60bf..e6e05dd8f4c 100644 --- a/runtime/vm/intrinsifier_ia32.cc +++ b/runtime/vm/intrinsifier_ia32.cc @@ -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); diff --git a/runtime/vm/opt_code_generator_ia32.cc b/runtime/vm/opt_code_generator_ia32.cc index cbaaf77b82e..b3c4b091521 100644 --- a/runtime/vm/opt_code_generator_ia32.cc +++ b/runtime/vm/opt_code_generator_ia32.cc @@ -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(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 diff --git a/runtime/vm/opt_code_generator_ia32.h b/runtime/vm/opt_code_generator_ia32.h index b8f8e94303c..36d9b6570f6 100644 --- a/runtime/vm/opt_code_generator_ia32.h +++ b/runtime/vm/opt_code_generator_ia32.h @@ -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, diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status index e3d75ebbf92..c943c68cf55 100644 --- a/tests/co19/co19-runtime.status +++ b/tests/co19/co19-runtime.status @@ -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