Initial implementation of a flow-graph builder for Dart's AST.
Visit the AST and generate an instruction (ie, not basic-block) flow
graph.
The flow graph for the simple function:
main() {
var f = 1;
var n = 5;
while (n > 0) {
f = f * n;
n = n - 1;
}
print(f);
}
is:
1: StoreLocal(f, #1)
2: StoreLocal(n, #5)
3: [join]
4: t0 <-LoadLocal(n)
5: t0 <-InstanceCall(>, t0, #0)
6: if t0 goto(7, 15)
7: [target]
8: t0 <-LoadLocal(f)
9: t1 <-LoadLocal(n)
10: t0 <-InstanceCall(*, t0, t1)
11: StoreLocal(f, t0)
12: t0 <-LoadLocal(n)
13: t0 <-InstanceCall(-, t0, #1)
14: StoreLocal(n, t0) goto 3
15: [target]
16: t0 <-LoadLocal(f)
17: StaticCall(print, t0)
18: return #null
BUG=
TEST=
Review URL: https://chromiumcodereview.appspot.com//9414003
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@4460 260f80e4-7a28-3924-810f-c04153c831b5
2012-02-22 15:20:13 +00:00
|
|
|
// Copyright (c) 2012, 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/intermediate_language.h"
|
|
|
|
|
2012-05-16 13:28:02 +00:00
|
|
|
#include "vm/bit_vector.h"
|
2012-06-26 17:43:44 +00:00
|
|
|
#include "vm/dart_entry.h"
|
2012-08-07 15:53:02 +00:00
|
|
|
#include "vm/flow_graph_allocator.h"
|
2012-05-18 01:04:56 +00:00
|
|
|
#include "vm/flow_graph_builder.h"
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
#include "vm/flow_graph_compiler.h"
|
2012-09-19 14:10:14 +00:00
|
|
|
#include "vm/flow_graph_optimizer.h"
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
#include "vm/locations.h"
|
Initial implementation of a flow-graph builder for Dart's AST.
Visit the AST and generate an instruction (ie, not basic-block) flow
graph.
The flow graph for the simple function:
main() {
var f = 1;
var n = 5;
while (n > 0) {
f = f * n;
n = n - 1;
}
print(f);
}
is:
1: StoreLocal(f, #1)
2: StoreLocal(n, #5)
3: [join]
4: t0 <-LoadLocal(n)
5: t0 <-InstanceCall(>, t0, #0)
6: if t0 goto(7, 15)
7: [target]
8: t0 <-LoadLocal(f)
9: t1 <-LoadLocal(n)
10: t0 <-InstanceCall(*, t0, t1)
11: StoreLocal(f, t0)
12: t0 <-LoadLocal(n)
13: t0 <-InstanceCall(-, t0, #1)
14: StoreLocal(n, t0) goto 3
15: [target]
16: t0 <-LoadLocal(f)
17: StaticCall(print, t0)
18: return #null
BUG=
TEST=
Review URL: https://chromiumcodereview.appspot.com//9414003
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@4460 260f80e4-7a28-3924-810f-c04153c831b5
2012-02-22 15:20:13 +00:00
|
|
|
#include "vm/object.h"
|
2012-08-11 00:09:12 +00:00
|
|
|
#include "vm/object_store.h"
|
Initial implementation of a flow-graph builder for Dart's AST.
Visit the AST and generate an instruction (ie, not basic-block) flow
graph.
The flow graph for the simple function:
main() {
var f = 1;
var n = 5;
while (n > 0) {
f = f * n;
n = n - 1;
}
print(f);
}
is:
1: StoreLocal(f, #1)
2: StoreLocal(n, #5)
3: [join]
4: t0 <-LoadLocal(n)
5: t0 <-InstanceCall(>, t0, #0)
6: if t0 goto(7, 15)
7: [target]
8: t0 <-LoadLocal(f)
9: t1 <-LoadLocal(n)
10: t0 <-InstanceCall(*, t0, t1)
11: StoreLocal(f, t0)
12: t0 <-LoadLocal(n)
13: t0 <-InstanceCall(-, t0, #1)
14: StoreLocal(n, t0) goto 3
15: [target]
16: t0 <-LoadLocal(f)
17: StaticCall(print, t0)
18: return #null
BUG=
TEST=
Review URL: https://chromiumcodereview.appspot.com//9414003
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@4460 260f80e4-7a28-3924-810f-c04153c831b5
2012-02-22 15:20:13 +00:00
|
|
|
#include "vm/os.h"
|
|
|
|
#include "vm/scopes.h"
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
#include "vm/stub_code.h"
|
2012-07-24 00:01:50 +00:00
|
|
|
#include "vm/symbols.h"
|
Initial implementation of a flow-graph builder for Dart's AST.
Visit the AST and generate an instruction (ie, not basic-block) flow
graph.
The flow graph for the simple function:
main() {
var f = 1;
var n = 5;
while (n > 0) {
f = f * n;
n = n - 1;
}
print(f);
}
is:
1: StoreLocal(f, #1)
2: StoreLocal(n, #5)
3: [join]
4: t0 <-LoadLocal(n)
5: t0 <-InstanceCall(>, t0, #0)
6: if t0 goto(7, 15)
7: [target]
8: t0 <-LoadLocal(f)
9: t1 <-LoadLocal(n)
10: t0 <-InstanceCall(*, t0, t1)
11: StoreLocal(f, t0)
12: t0 <-LoadLocal(n)
13: t0 <-InstanceCall(-, t0, #1)
14: StoreLocal(n, t0) goto 3
15: [target]
16: t0 <-LoadLocal(f)
17: StaticCall(print, t0)
18: return #null
BUG=
TEST=
Review URL: https://chromiumcodereview.appspot.com//9414003
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@4460 260f80e4-7a28-3924-810f-c04153c831b5
2012-02-22 15:20:13 +00:00
|
|
|
|
|
|
|
namespace dart {
|
|
|
|
|
2012-07-26 16:04:36 +00:00
|
|
|
DECLARE_FLAG(bool, enable_type_checks);
|
|
|
|
|
2012-08-20 12:40:14 +00:00
|
|
|
|
2012-09-19 14:10:14 +00:00
|
|
|
Definition::Definition()
|
2012-09-21 20:06:31 +00:00
|
|
|
: range_(NULL),
|
|
|
|
temp_index_(-1),
|
2012-09-19 14:10:14 +00:00
|
|
|
ssa_temp_index_(-1),
|
|
|
|
propagated_type_(AbstractType::Handle()),
|
|
|
|
propagated_cid_(kIllegalCid),
|
|
|
|
input_use_list_(NULL),
|
|
|
|
env_use_list_(NULL),
|
|
|
|
use_kind_(kValue), // Phis and parameters rely on this default.
|
|
|
|
constant_value_(Object::ZoneHandle(ConstantPropagator::Unknown())) {
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-19 14:38:31 +00:00
|
|
|
intptr_t Instruction::Hashcode() const {
|
2012-09-05 17:04:49 +00:00
|
|
|
intptr_t result = tag();
|
2012-08-20 12:40:14 +00:00
|
|
|
for (intptr_t i = 0; i < InputCount(); ++i) {
|
2012-08-30 09:08:27 +00:00
|
|
|
Value* value = InputAt(i);
|
|
|
|
intptr_t j = value->definition()->ssa_temp_index();
|
2012-08-20 12:40:14 +00:00
|
|
|
result = result * 31 + j;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-19 14:38:31 +00:00
|
|
|
bool Instruction::Equals(Instruction* other) const {
|
2012-09-05 17:04:49 +00:00
|
|
|
if (tag() != other->tag()) return false;
|
2012-08-20 12:40:14 +00:00
|
|
|
for (intptr_t i = 0; i < InputCount(); ++i) {
|
|
|
|
if (!InputAt(i)->Equals(other->InputAt(i))) return false;
|
|
|
|
}
|
|
|
|
return AttributesEqual(other);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-30 09:08:27 +00:00
|
|
|
bool Value::Equals(Value* other) const {
|
|
|
|
return definition() == other->definition();
|
2012-08-21 13:07:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-19 14:38:31 +00:00
|
|
|
bool CheckClassInstr::AttributesEqual(Instruction* other) const {
|
2012-09-05 17:04:49 +00:00
|
|
|
CheckClassInstr* other_check = other->AsCheckClass();
|
|
|
|
ASSERT(other_check != NULL);
|
2012-09-03 11:27:09 +00:00
|
|
|
if (unary_checks().NumberOfChecks() !=
|
|
|
|
other_check->unary_checks().NumberOfChecks()) {
|
2012-08-20 12:40:14 +00:00
|
|
|
return false;
|
|
|
|
}
|
2012-09-03 11:27:09 +00:00
|
|
|
for (intptr_t i = 0; i < unary_checks().NumberOfChecks(); ++i) {
|
2012-08-20 12:40:14 +00:00
|
|
|
// TODO(fschneider): Make sure ic_data are sorted to hit more cases.
|
2012-09-03 11:27:09 +00:00
|
|
|
if (unary_checks().GetReceiverClassIdAt(i) !=
|
|
|
|
other_check->unary_checks().GetReceiverClassIdAt(i)) {
|
2012-08-20 12:40:14 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-19 14:38:31 +00:00
|
|
|
bool CheckArrayBoundInstr::AttributesEqual(Instruction* other) const {
|
2012-09-05 17:04:49 +00:00
|
|
|
CheckArrayBoundInstr* other_check = other->AsCheckArrayBound();
|
|
|
|
ASSERT(other_check != NULL);
|
2012-08-28 09:14:57 +00:00
|
|
|
return array_type() == other_check->array_type();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-19 14:38:31 +00:00
|
|
|
bool StrictCompareInstr::AttributesEqual(Instruction* other) const {
|
2012-09-17 14:27:45 +00:00
|
|
|
StrictCompareInstr* other_op = other->AsStrictCompare();
|
|
|
|
ASSERT(other_op != NULL);
|
|
|
|
return kind() == other_op->kind();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-19 14:38:31 +00:00
|
|
|
bool BinarySmiOpInstr::AttributesEqual(Instruction* other) const {
|
2012-09-17 11:33:48 +00:00
|
|
|
BinarySmiOpInstr* other_op = other->AsBinarySmiOp();
|
|
|
|
ASSERT(other_op != NULL);
|
2012-09-21 20:06:31 +00:00
|
|
|
return (op_kind() == other_op->op_kind()) &&
|
|
|
|
(overflow_ == other_op->overflow_);
|
2012-09-17 11:33:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-19 14:38:31 +00:00
|
|
|
bool LoadFieldInstr::AttributesEqual(Instruction* other) const {
|
2012-09-12 17:43:37 +00:00
|
|
|
LoadFieldInstr* other_load = other->AsLoadField();
|
2012-09-12 08:45:02 +00:00
|
|
|
ASSERT(other_load != NULL);
|
|
|
|
ASSERT((offset_in_bytes() != other_load->offset_in_bytes()) ||
|
|
|
|
((immutable_ == other_load->immutable_) &&
|
2012-09-26 08:28:45 +00:00
|
|
|
((ResultCid() == other_load->ResultCid()) ||
|
|
|
|
(ResultCid() == kDynamicCid) ||
|
|
|
|
(other_load->ResultCid() == kDynamicCid))));
|
2012-09-12 08:45:02 +00:00
|
|
|
return offset_in_bytes() == other_load->offset_in_bytes();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-19 14:38:31 +00:00
|
|
|
bool LoadStaticFieldInstr::AttributesEqual(Instruction* other) const {
|
2012-09-14 12:08:31 +00:00
|
|
|
LoadStaticFieldInstr* other_load = other->AsLoadStaticField();
|
|
|
|
ASSERT(other_load != NULL);
|
|
|
|
// Assert that the field is initialized.
|
|
|
|
ASSERT(field().value() != Object::sentinel());
|
|
|
|
ASSERT(field().value() != Object::transition_sentinel());
|
|
|
|
return field().raw() == other_load->field().raw();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-19 14:38:31 +00:00
|
|
|
bool ConstantInstr::AttributesEqual(Instruction* other) const {
|
2012-09-14 12:08:31 +00:00
|
|
|
ConstantInstr* other_constant = other->AsConstant();
|
|
|
|
ASSERT(other_constant != NULL);
|
|
|
|
return (value().raw() == other_constant->value().raw());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-15 23:49:12 +00:00
|
|
|
// Returns true if the value represents a constant.
|
2012-08-30 09:08:27 +00:00
|
|
|
bool Value::BindsToConstant() const {
|
2012-09-05 17:04:49 +00:00
|
|
|
return definition()->IsConstant();
|
2012-08-15 23:49:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Returns true if the value represents constant null.
|
2012-08-30 09:08:27 +00:00
|
|
|
bool Value::BindsToConstantNull() const {
|
2012-09-05 17:04:49 +00:00
|
|
|
ConstantInstr* constant = definition()->AsConstant();
|
2012-08-29 12:56:57 +00:00
|
|
|
return (constant != NULL) && constant->value().IsNull();
|
2012-08-15 23:49:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-30 09:08:27 +00:00
|
|
|
const Object& Value::BoundConstant() const {
|
2012-08-16 22:22:57 +00:00
|
|
|
ASSERT(BindsToConstant());
|
2012-09-05 17:04:49 +00:00
|
|
|
ConstantInstr* constant = definition()->AsConstant();
|
2012-08-16 22:22:57 +00:00
|
|
|
ASSERT(constant != NULL);
|
2012-08-29 12:56:57 +00:00
|
|
|
return constant->value();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GraphEntryInstr::GraphEntryInstr(TargetEntryInstr* normal_entry)
|
2012-09-24 07:27:36 +00:00
|
|
|
: BlockEntryInstr(0, CatchClauseNode::kInvalidTryIndex),
|
2012-08-29 12:56:57 +00:00
|
|
|
normal_entry_(normal_entry),
|
|
|
|
catch_entries_(),
|
2012-09-19 12:37:57 +00:00
|
|
|
initial_definitions_(),
|
2012-08-29 12:56:57 +00:00
|
|
|
spill_slot_count_(0) {
|
2012-08-16 22:22:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-19 12:37:57 +00:00
|
|
|
ConstantInstr* GraphEntryInstr::constant_null() {
|
|
|
|
ASSERT(initial_definitions_.length() > 0 &&
|
|
|
|
initial_definitions_[0]->IsConstant() &&
|
|
|
|
initial_definitions_[0]->AsConstant()->value().IsNull());
|
|
|
|
return initial_definitions_[0]->AsConstant();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-17 09:50:21 +00:00
|
|
|
static bool CompareNames(const Library& lib,
|
|
|
|
const char* test_name,
|
|
|
|
const String& name) {
|
|
|
|
// If both names are private mangle test_name before comparison.
|
|
|
|
if ((name.CharAt(0) == '_') && (test_name[0] == '_')) {
|
|
|
|
const String& test_name_symbol = String::Handle(Symbols::New(test_name));
|
|
|
|
return String::Handle(lib.PrivateName(test_name_symbol)).Equals(name);
|
|
|
|
}
|
|
|
|
return name.Equals(test_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-15 00:56:25 +00:00
|
|
|
MethodRecognizer::Kind MethodRecognizer::RecognizeKind(
|
|
|
|
const Function& function) {
|
2012-08-23 01:10:47 +00:00
|
|
|
// Only core and math library methods can be recognized.
|
2012-06-15 00:56:25 +00:00
|
|
|
const Library& core_lib = Library::Handle(Library::CoreLibrary());
|
|
|
|
const Library& core_impl_lib = Library::Handle(Library::CoreImplLibrary());
|
2012-08-23 01:10:47 +00:00
|
|
|
const Library& math_lib = Library::Handle(Library::MathLibrary());
|
2012-08-14 00:38:01 +00:00
|
|
|
const Class& function_class = Class::Handle(function.Owner());
|
2012-06-15 00:56:25 +00:00
|
|
|
if ((function_class.library() != core_lib.raw()) &&
|
2012-08-23 01:10:47 +00:00
|
|
|
(function_class.library() != core_impl_lib.raw()) &&
|
|
|
|
(function_class.library() != math_lib.raw())) {
|
2012-06-15 00:56:25 +00:00
|
|
|
return kUnknown;
|
|
|
|
}
|
2012-09-17 09:50:21 +00:00
|
|
|
const Library& lib = Library::Handle(function_class.library());
|
|
|
|
const String& function_name = String::Handle(function.name());
|
|
|
|
const String& class_name = String::Handle(function_class.Name());
|
|
|
|
|
|
|
|
#define RECOGNIZE_FUNCTION(test_class_name, test_function_name, enum_name) \
|
|
|
|
if (CompareNames(lib, #test_function_name, function_name) && \
|
|
|
|
CompareNames(lib, #test_class_name, class_name)) { \
|
2012-06-15 00:56:25 +00:00
|
|
|
return k##enum_name; \
|
|
|
|
}
|
|
|
|
RECOGNIZED_LIST(RECOGNIZE_FUNCTION)
|
|
|
|
#undef RECOGNIZE_FUNCTION
|
|
|
|
return kUnknown;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const char* MethodRecognizer::KindToCString(Kind kind) {
|
|
|
|
#define KIND_TO_STRING(class_name, function_name, enum_name) \
|
|
|
|
if (kind == k##enum_name) return #enum_name;
|
|
|
|
RECOGNIZED_LIST(KIND_TO_STRING)
|
|
|
|
#undef KIND_TO_STRING
|
|
|
|
return "?";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-02-28 08:58:49 +00:00
|
|
|
// ==== Support for visiting flow graphs.
|
2012-05-15 08:55:56 +00:00
|
|
|
#define DEFINE_ACCEPT(ShortName) \
|
2012-07-09 12:58:36 +00:00
|
|
|
void ShortName##Instr::Accept(FlowGraphVisitor* visitor) { \
|
2012-05-15 08:55:56 +00:00
|
|
|
visitor->Visit##ShortName(this); \
|
2012-02-23 18:29:58 +00:00
|
|
|
}
|
|
|
|
|
2012-05-15 08:55:56 +00:00
|
|
|
FOR_EACH_INSTRUCTION(DEFINE_ACCEPT)
|
2012-02-23 18:29:58 +00:00
|
|
|
|
2012-05-15 08:55:56 +00:00
|
|
|
#undef DEFINE_ACCEPT
|
Initial implementation of a flow-graph builder for Dart's AST.
Visit the AST and generate an instruction (ie, not basic-block) flow
graph.
The flow graph for the simple function:
main() {
var f = 1;
var n = 5;
while (n > 0) {
f = f * n;
n = n - 1;
}
print(f);
}
is:
1: StoreLocal(f, #1)
2: StoreLocal(n, #5)
3: [join]
4: t0 <-LoadLocal(n)
5: t0 <-InstanceCall(>, t0, #0)
6: if t0 goto(7, 15)
7: [target]
8: t0 <-LoadLocal(f)
9: t1 <-LoadLocal(n)
10: t0 <-InstanceCall(*, t0, t1)
11: StoreLocal(f, t0)
12: t0 <-LoadLocal(n)
13: t0 <-InstanceCall(-, t0, #1)
14: StoreLocal(n, t0) goto 3
15: [target]
16: t0 <-LoadLocal(f)
17: StaticCall(print, t0)
18: return #null
BUG=
TEST=
Review URL: https://chromiumcodereview.appspot.com//9414003
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@4460 260f80e4-7a28-3924-810f-c04153c831b5
2012-02-22 15:20:13 +00:00
|
|
|
|
|
|
|
|
2012-07-30 13:26:31 +00:00
|
|
|
Instruction* Instruction::RemoveFromGraph(bool return_previous) {
|
|
|
|
ASSERT(!IsBlockEntry());
|
2012-08-27 09:30:20 +00:00
|
|
|
ASSERT(!IsControl());
|
2012-07-30 13:26:31 +00:00
|
|
|
ASSERT(!IsThrow());
|
|
|
|
ASSERT(!IsReturn());
|
|
|
|
ASSERT(!IsReThrow());
|
|
|
|
ASSERT(!IsGoto());
|
|
|
|
ASSERT(previous() != NULL);
|
|
|
|
Instruction* prev_instr = previous();
|
|
|
|
Instruction* next_instr = next();
|
|
|
|
ASSERT(next_instr != NULL);
|
|
|
|
ASSERT(!next_instr->IsBlockEntry());
|
2012-10-03 15:05:27 +00:00
|
|
|
prev_instr->LinkTo(next_instr);
|
2012-07-09 20:31:25 +00:00
|
|
|
// Reset successor and previous instruction to indicate
|
|
|
|
// that the instruction is removed from the graph.
|
2012-07-30 13:26:31 +00:00
|
|
|
set_previous(NULL);
|
|
|
|
set_next(NULL);
|
|
|
|
return return_previous ? prev_instr : next_instr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-19 14:38:31 +00:00
|
|
|
void Instruction::InsertBefore(Instruction* next) {
|
2012-08-20 12:40:14 +00:00
|
|
|
ASSERT(previous_ == NULL);
|
|
|
|
ASSERT(next_ == NULL);
|
|
|
|
next_ = next;
|
|
|
|
previous_ = next->previous_;
|
|
|
|
next->previous_ = this;
|
|
|
|
previous_->next_ = this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-19 14:38:31 +00:00
|
|
|
void Instruction::InsertAfter(Instruction* prev) {
|
2012-08-24 14:45:42 +00:00
|
|
|
ASSERT(previous_ == NULL);
|
|
|
|
ASSERT(next_ == NULL);
|
|
|
|
previous_ = prev;
|
|
|
|
next_ = prev->next_;
|
|
|
|
next_->previous_ = this;
|
|
|
|
previous_->next_ = this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-19 14:38:31 +00:00
|
|
|
BlockEntryInstr* Instruction::GetBlock() const {
|
2012-09-06 13:21:20 +00:00
|
|
|
// TODO(fschneider): Implement a faster way to get the block of an
|
|
|
|
// instruction.
|
|
|
|
ASSERT(previous() != NULL);
|
|
|
|
Instruction* result = previous();
|
|
|
|
while (!result->IsBlockEntry()) result = result->previous();
|
|
|
|
return result->AsBlockEntry();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void ForwardInstructionIterator::RemoveCurrentFromGraph() {
|
|
|
|
current_ = current_->RemoveFromGraph(true); // Set current_ to previous.
|
2012-09-04 09:58:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void ForwardInstructionIterator::ReplaceCurrentWith(Definition* other) {
|
|
|
|
Definition* defn = current_->AsDefinition();
|
|
|
|
ASSERT(defn != NULL);
|
|
|
|
defn->ReplaceUsesWith(other);
|
|
|
|
ASSERT(other->env() == NULL);
|
|
|
|
other->set_env(defn->env());
|
|
|
|
defn->set_env(NULL);
|
|
|
|
ASSERT(!other->HasSSATemp());
|
|
|
|
if (defn->HasSSATemp()) other->set_ssa_temp_index(defn->ssa_temp_index());
|
|
|
|
|
|
|
|
other->InsertBefore(current_); // So other will be current.
|
|
|
|
RemoveCurrentFromGraph();
|
2012-07-09 20:31:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-02-23 18:29:58 +00:00
|
|
|
// Default implementation of visiting basic blocks. Can be overridden.
|
2012-03-16 22:20:04 +00:00
|
|
|
void FlowGraphVisitor::VisitBlocks() {
|
2012-08-15 23:49:12 +00:00
|
|
|
ASSERT(current_iterator_ == NULL);
|
2012-03-16 22:20:04 +00:00
|
|
|
for (intptr_t i = 0; i < block_order_.length(); ++i) {
|
2012-07-09 12:58:36 +00:00
|
|
|
BlockEntryInstr* entry = block_order_[i];
|
|
|
|
entry->Accept(this);
|
2012-08-15 23:49:12 +00:00
|
|
|
ForwardInstructionIterator it(entry);
|
|
|
|
current_iterator_ = ⁢
|
|
|
|
for (; !it.Done(); it.Advance()) {
|
2012-07-09 12:58:36 +00:00
|
|
|
it.Current()->Accept(this);
|
2012-02-23 18:29:58 +00:00
|
|
|
}
|
2012-08-15 23:49:12 +00:00
|
|
|
current_iterator_ = NULL;
|
2012-02-23 18:29:58 +00:00
|
|
|
}
|
Initial implementation of a flow-graph builder for Dart's AST.
Visit the AST and generate an instruction (ie, not basic-block) flow
graph.
The flow graph for the simple function:
main() {
var f = 1;
var n = 5;
while (n > 0) {
f = f * n;
n = n - 1;
}
print(f);
}
is:
1: StoreLocal(f, #1)
2: StoreLocal(n, #5)
3: [join]
4: t0 <-LoadLocal(n)
5: t0 <-InstanceCall(>, t0, #0)
6: if t0 goto(7, 15)
7: [target]
8: t0 <-LoadLocal(f)
9: t1 <-LoadLocal(n)
10: t0 <-InstanceCall(*, t0, t1)
11: StoreLocal(f, t0)
12: t0 <-LoadLocal(n)
13: t0 <-InstanceCall(-, t0, #1)
14: StoreLocal(n, t0) goto 3
15: [target]
16: t0 <-LoadLocal(f)
17: StaticCall(print, t0)
18: return #null
BUG=
TEST=
Review URL: https://chromiumcodereview.appspot.com//9414003
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@4460 260f80e4-7a28-3924-810f-c04153c831b5
2012-02-22 15:20:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-10 01:26:13 +00:00
|
|
|
// TODO(regis): Support a set of compile types for the given value.
|
2012-09-18 15:12:43 +00:00
|
|
|
bool Value::CanComputeIsNull(bool* is_null) const {
|
|
|
|
ASSERT(is_null != NULL);
|
|
|
|
// For now, we can only return a meaningful result if the value is constant.
|
|
|
|
if (!BindsToConstant()) {
|
2012-08-15 23:49:12 +00:00
|
|
|
return false;
|
|
|
|
}
|
2012-08-01 17:15:55 +00:00
|
|
|
|
2012-09-18 15:12:43 +00:00
|
|
|
// Return true if the constant value is Object::null.
|
2012-08-15 23:49:12 +00:00
|
|
|
if (BindsToConstantNull()) {
|
2012-09-18 15:12:43 +00:00
|
|
|
*is_null = true;
|
2012-08-01 17:15:55 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-09-18 15:12:43 +00:00
|
|
|
// Consider the compile type of the value to check for sentinels, which are
|
|
|
|
// also treated as null.
|
|
|
|
const AbstractType& compile_type = AbstractType::Handle(CompileType());
|
|
|
|
ASSERT(!compile_type.IsMalformed());
|
|
|
|
ASSERT(!compile_type.IsVoidType());
|
|
|
|
|
|
|
|
// There are only three instances that can be of type Null:
|
|
|
|
// Object::null(), Object::sentinel(), and Object::transition_sentinel().
|
|
|
|
// The inline code and run time code performing the type check will only
|
|
|
|
// encounter the 2 sentinel values if type check elimination was disabled.
|
|
|
|
// Otherwise, the type check of a sentinel value will be eliminated here,
|
|
|
|
// because these sentinel values can only be encountered as constants, never
|
|
|
|
// as actual value of a heap object being type checked.
|
|
|
|
if (compile_type.IsNullType()) {
|
|
|
|
*is_null = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TODO(regis): Support a set of compile types for the given value.
|
|
|
|
bool Value::CanComputeIsInstanceOf(const AbstractType& type,
|
|
|
|
bool* is_instance) const {
|
|
|
|
ASSERT(is_instance != NULL);
|
|
|
|
// We cannot give an answer if the given type is malformed.
|
|
|
|
if (type.IsMalformed()) {
|
2012-08-01 17:15:55 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-09-18 15:12:43 +00:00
|
|
|
// We should never test for an instance of null.
|
|
|
|
ASSERT(!type.IsNullType());
|
|
|
|
|
2012-08-10 01:26:13 +00:00
|
|
|
// Consider the compile type of the value.
|
|
|
|
const AbstractType& compile_type = AbstractType::Handle(CompileType());
|
|
|
|
ASSERT(!compile_type.IsMalformed());
|
2012-08-01 17:15:55 +00:00
|
|
|
|
2012-08-10 01:26:13 +00:00
|
|
|
// If the compile type of the value is void, we are type checking the result
|
|
|
|
// of a void function, which was checked to be null at the return statement
|
2012-08-01 17:15:55 +00:00
|
|
|
// inside the function.
|
2012-08-10 01:26:13 +00:00
|
|
|
if (compile_type.IsVoidType()) {
|
2012-09-18 15:12:43 +00:00
|
|
|
ASSERT(FLAG_enable_type_checks);
|
|
|
|
*is_instance = true;
|
2012-08-01 17:15:55 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-09-18 15:12:43 +00:00
|
|
|
// The Null type is only a subtype of Object and of Dynamic.
|
|
|
|
// Functions that do not explicitly return a value, implicitly return null,
|
|
|
|
// except generative constructors, which return the object being constructed.
|
|
|
|
// It is therefore acceptable for void functions to return null.
|
2012-08-10 01:26:13 +00:00
|
|
|
if (compile_type.IsNullType()) {
|
2012-09-18 15:12:43 +00:00
|
|
|
*is_instance =
|
|
|
|
type.IsObjectType() || type.IsDynamicType() || type.IsVoidType();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Until we support a set of compile types, we can only give answers for
|
|
|
|
// constant values. Indeed, a variable of the proper compile time type may
|
|
|
|
// still hold null at run time and therefore fail the test.
|
|
|
|
if (!BindsToConstant()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// A non-null constant is not an instance of void.
|
|
|
|
if (type.IsVoidType()) {
|
|
|
|
*is_instance = false;
|
2012-08-01 17:15:55 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-09-18 15:12:43 +00:00
|
|
|
// Since the value is a constant, its type is instantiated.
|
|
|
|
ASSERT(compile_type.IsInstantiated());
|
|
|
|
|
2012-08-01 17:15:55 +00:00
|
|
|
// The run time type of the value is guaranteed to be a subtype of the
|
2012-09-18 15:12:43 +00:00
|
|
|
// compile time type of the value. However, establishing here that the
|
|
|
|
// compile time type is a subtype of the given type does not guarantee that
|
|
|
|
// the run time type will also be a subtype of the given type, because the
|
|
|
|
// subtype relation is not transitive when an uninstantiated type is
|
|
|
|
// involved.
|
|
|
|
Error& malformed_error = Error::Handle();
|
|
|
|
if (type.IsInstantiated()) {
|
|
|
|
// Perform the test on the compile-time type and provide the answer, unless
|
|
|
|
// the type test produced a malformed error (e.g. an upper bound error).
|
|
|
|
*is_instance = compile_type.IsSubtypeOf(type, &malformed_error);
|
|
|
|
} else {
|
|
|
|
// However, the 'more specific than' relation is transitive and used here.
|
|
|
|
// In other words, if the compile type of the value is more specific than
|
|
|
|
// the given type, the run time type of the value, which is guaranteed to be
|
|
|
|
// a subtype of the compile type, is also guaranteed to be a subtype of the
|
|
|
|
// given type.
|
|
|
|
*is_instance = compile_type.IsMoreSpecificThan(type, &malformed_error);
|
|
|
|
}
|
|
|
|
return malformed_error.IsNull();
|
2012-08-01 17:15:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-25 00:27:07 +00:00
|
|
|
bool Value::NeedsStoreBuffer() const {
|
|
|
|
const intptr_t cid = ResultCid();
|
|
|
|
if ((cid == kSmiCid) || (cid == kBoolCid) || (cid == kNullCid)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return !BindsToConstant();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-10 01:26:13 +00:00
|
|
|
RawAbstractType* PhiInstr::CompileType() const {
|
2012-08-13 16:56:10 +00:00
|
|
|
ASSERT(!HasPropagatedType());
|
|
|
|
// Since type propagation has not yet occured, we are reaching this phi via a
|
2012-08-10 01:26:13 +00:00
|
|
|
// back edge phi input. Return null as compile type so that this input is
|
|
|
|
// ignored in the first iteration of type propagation.
|
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* PhiInstr::LeastSpecificInputType() const {
|
|
|
|
AbstractType& least_specific_type = AbstractType::Handle();
|
2012-08-01 17:15:55 +00:00
|
|
|
AbstractType& input_type = AbstractType::Handle();
|
2012-08-10 01:26:13 +00:00
|
|
|
for (intptr_t i = 0; i < InputCount(); i++) {
|
|
|
|
input_type = InputAt(i)->CompileType();
|
|
|
|
if (input_type.IsNull()) {
|
|
|
|
// This input is on a back edge and we are in the first iteration of type
|
|
|
|
// propagation. Ignore it.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ASSERT(!input_type.IsNull());
|
|
|
|
if (least_specific_type.IsNull() ||
|
|
|
|
least_specific_type.IsMoreSpecificThan(input_type, NULL)) {
|
2012-08-01 17:15:55 +00:00
|
|
|
// Type input_type is less specific than the current least_specific_type.
|
|
|
|
least_specific_type = input_type.raw();
|
2012-08-10 01:26:13 +00:00
|
|
|
} else if (input_type.IsMoreSpecificThan(least_specific_type, NULL)) {
|
|
|
|
// Type least_specific_type is less specific than input_type. No change.
|
2012-08-01 17:15:55 +00:00
|
|
|
} else {
|
|
|
|
// The types are unrelated. No need to continue.
|
|
|
|
least_specific_type = Type::ObjectType();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return least_specific_type.raw();
|
2012-07-26 16:04:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-10 01:26:13 +00:00
|
|
|
RawAbstractType* ParameterInstr::CompileType() const {
|
2012-08-13 16:56:10 +00:00
|
|
|
ASSERT(!HasPropagatedType());
|
2012-08-10 01:26:13 +00:00
|
|
|
// Note that returning the declared type of the formal parameter would be
|
|
|
|
// incorrect, because ParameterInstr is used as input to the type check
|
|
|
|
// verifying the run time type of the passed-in parameter and this check would
|
|
|
|
// always be wrongly eliminated.
|
2012-07-26 16:04:36 +00:00
|
|
|
return Type::DynamicType();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-10 14:28:02 +00:00
|
|
|
RawAbstractType* PushArgumentInstr::CompileType() const {
|
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-24 07:27:36 +00:00
|
|
|
void JoinEntryInstr::AddPredecessor(BlockEntryInstr* predecessor) {
|
|
|
|
// Require the predecessors to be sorted by block_id to make managing
|
|
|
|
// their corresponding phi inputs simpler.
|
|
|
|
intptr_t pred_id = predecessor->block_id();
|
|
|
|
intptr_t index = 0;
|
|
|
|
while ((index < predecessors_.length()) &&
|
|
|
|
(predecessors_[index]->block_id() < pred_id)) {
|
|
|
|
++index;
|
2012-09-19 14:10:14 +00:00
|
|
|
}
|
2012-09-24 07:27:36 +00:00
|
|
|
#if defined(DEBUG)
|
|
|
|
for (intptr_t i = index; i < predecessors_.length(); ++i) {
|
|
|
|
ASSERT(predecessors_[i]->block_id() != pred_id);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
predecessors_.InsertAt(index, predecessor);
|
2012-09-19 14:10:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-24 07:27:36 +00:00
|
|
|
intptr_t JoinEntryInstr::IndexOfPredecessor(BlockEntryInstr* pred) const {
|
|
|
|
for (intptr_t i = 0; i < predecessors_.length(); ++i) {
|
|
|
|
if (predecessors_[i] == pred) return i;
|
2012-09-20 09:11:44 +00:00
|
|
|
}
|
2012-09-24 07:27:36 +00:00
|
|
|
return -1;
|
2012-09-20 09:11:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-16 13:28:02 +00:00
|
|
|
// ==== Recording assigned variables.
|
2012-09-05 17:04:49 +00:00
|
|
|
void Definition::RecordAssignedVars(BitVector* assigned_vars,
|
|
|
|
intptr_t fixed_parameter_count) {
|
2012-05-16 13:28:02 +00:00
|
|
|
// Nothing to do for the base class.
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void StoreLocalInstr::RecordAssignedVars(BitVector* assigned_vars,
|
|
|
|
intptr_t fixed_parameter_count) {
|
2012-05-16 13:28:02 +00:00
|
|
|
if (!local().is_captured()) {
|
2012-07-26 13:21:39 +00:00
|
|
|
assigned_vars->Add(local().BitIndexIn(fixed_parameter_count));
|
2012-05-16 13:28:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-26 13:21:39 +00:00
|
|
|
void Instruction::RecordAssignedVars(BitVector* assigned_vars,
|
|
|
|
intptr_t fixed_parameter_count) {
|
2012-05-16 13:28:02 +00:00
|
|
|
// Nothing to do for the base class.
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-30 09:08:27 +00:00
|
|
|
void Value::AddToInputUseList() {
|
2012-08-23 16:23:05 +00:00
|
|
|
set_next_use(definition()->input_use_list());
|
|
|
|
definition()->set_input_use_list(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-30 09:08:27 +00:00
|
|
|
void Value::AddToEnvUseList() {
|
2012-08-23 16:23:05 +00:00
|
|
|
set_next_use(definition()->env_use_list());
|
|
|
|
definition()->set_env_use_list(this);
|
|
|
|
}
|
2012-08-13 13:10:00 +00:00
|
|
|
|
2012-08-23 16:23:05 +00:00
|
|
|
|
2012-09-21 20:06:31 +00:00
|
|
|
void Value::RemoveFromInputUseList() {
|
|
|
|
if (definition_->input_use_list() == this) {
|
|
|
|
definition_->set_input_use_list(next_use_);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Value* prev = definition_->input_use_list();
|
|
|
|
while (prev->next_use_ != this) {
|
|
|
|
prev = prev->next_use_;
|
|
|
|
}
|
|
|
|
prev->next_use_ = next_use_;
|
|
|
|
definition_ = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-23 16:23:05 +00:00
|
|
|
void Definition::ReplaceUsesWith(Definition* other) {
|
|
|
|
ASSERT(other != NULL);
|
2012-08-27 12:17:47 +00:00
|
|
|
ASSERT(this != other);
|
2012-08-23 16:23:05 +00:00
|
|
|
while (input_use_list_ != NULL) {
|
2012-08-30 09:08:27 +00:00
|
|
|
Value* current = input_use_list_;
|
2012-08-23 16:23:05 +00:00
|
|
|
input_use_list_ = input_use_list_->next_use();
|
|
|
|
current->set_definition(other);
|
|
|
|
current->AddToInputUseList();
|
2012-08-13 13:10:00 +00:00
|
|
|
}
|
2012-08-23 16:23:05 +00:00
|
|
|
while (env_use_list_ != NULL) {
|
2012-08-30 09:08:27 +00:00
|
|
|
Value* current = env_use_list_;
|
2012-08-23 16:23:05 +00:00
|
|
|
env_use_list_ = env_use_list_->next_use();
|
|
|
|
current->set_definition(other);
|
|
|
|
current->AddToEnvUseList();
|
|
|
|
}
|
|
|
|
}
|
2012-08-13 13:10:00 +00:00
|
|
|
|
2012-08-23 16:23:05 +00:00
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void Definition::ReplaceWith(Definition* other,
|
|
|
|
ForwardInstructionIterator* iterator) {
|
2012-09-06 08:40:07 +00:00
|
|
|
if ((iterator != NULL) && (this == iterator->Current())) {
|
2012-09-05 17:04:49 +00:00
|
|
|
iterator->ReplaceCurrentWith(other);
|
|
|
|
} else {
|
|
|
|
ReplaceUsesWith(other);
|
|
|
|
ASSERT(other->env() == NULL);
|
|
|
|
other->set_env(env());
|
|
|
|
set_env(NULL);
|
|
|
|
ASSERT(!other->HasSSATemp());
|
|
|
|
if (HasSSATemp()) other->set_ssa_temp_index(ssa_temp_index());
|
|
|
|
|
2012-10-03 15:05:27 +00:00
|
|
|
previous()->LinkTo(other);
|
|
|
|
other->LinkTo(next());
|
2012-09-05 17:04:49 +00:00
|
|
|
|
2012-10-03 15:05:27 +00:00
|
|
|
set_previous(NULL);
|
2012-09-05 17:04:49 +00:00
|
|
|
set_next(NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-16 17:39:37 +00:00
|
|
|
bool Definition::SetPropagatedCid(intptr_t cid) {
|
2012-08-24 21:48:57 +00:00
|
|
|
if (cid == kIllegalCid) {
|
|
|
|
return false;
|
|
|
|
}
|
2012-08-16 17:39:37 +00:00
|
|
|
if (propagated_cid_ == kIllegalCid) {
|
|
|
|
// First setting, nothing has changed.
|
|
|
|
propagated_cid_ = cid;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool has_changed = (propagated_cid_ != cid);
|
|
|
|
propagated_cid_ = cid;
|
|
|
|
return has_changed;
|
|
|
|
}
|
|
|
|
|
2012-08-10 01:26:13 +00:00
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
intptr_t Definition::GetPropagatedCid() {
|
2012-08-16 17:39:37 +00:00
|
|
|
if (has_propagated_cid()) return propagated_cid();
|
2012-09-05 17:04:49 +00:00
|
|
|
intptr_t cid = ResultCid();
|
2012-08-16 17:39:37 +00:00
|
|
|
ASSERT(cid != kIllegalCid);
|
|
|
|
SetPropagatedCid(cid);
|
|
|
|
return cid;
|
|
|
|
}
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
|
|
|
|
intptr_t PhiInstr::GetPropagatedCid() {
|
|
|
|
return propagated_cid();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
intptr_t ParameterInstr::GetPropagatedCid() {
|
|
|
|
return propagated_cid();
|
2012-05-16 13:28:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-02-23 18:29:58 +00:00
|
|
|
// ==== Postorder graph traversal.
|
2012-09-19 14:10:14 +00:00
|
|
|
static bool IsMarked(BlockEntryInstr* block,
|
|
|
|
GrowableArray<BlockEntryInstr*>* preorder) {
|
|
|
|
// Detect that a block has been visited as part of the current
|
|
|
|
// DiscoverBlocks (we can call DiscoverBlocks multiple times). The block
|
|
|
|
// will be 'marked' by (1) having a preorder number in the range of the
|
|
|
|
// preorder array and (2) being in the preorder array at that index.
|
|
|
|
intptr_t i = block->preorder_number();
|
|
|
|
return (i >= 0) && (i < preorder->length()) && ((*preorder)[i] == block);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-16 12:10:02 +00:00
|
|
|
void GraphEntryInstr::DiscoverBlocks(
|
|
|
|
BlockEntryInstr* current_block,
|
|
|
|
GrowableArray<BlockEntryInstr*>* preorder,
|
|
|
|
GrowableArray<BlockEntryInstr*>* postorder,
|
2012-05-16 13:28:02 +00:00
|
|
|
GrowableArray<intptr_t>* parent,
|
|
|
|
GrowableArray<BitVector*>* assigned_vars,
|
2012-07-26 13:21:39 +00:00
|
|
|
intptr_t variable_count,
|
|
|
|
intptr_t fixed_parameter_count) {
|
2012-05-16 12:10:02 +00:00
|
|
|
// We only visit this block once, first of all blocks.
|
2012-09-19 14:10:14 +00:00
|
|
|
ASSERT(!IsMarked(this, preorder));
|
2012-05-16 12:10:02 +00:00
|
|
|
ASSERT(current_block == NULL);
|
|
|
|
ASSERT(preorder->is_empty());
|
|
|
|
ASSERT(postorder->is_empty());
|
|
|
|
ASSERT(parent->is_empty());
|
|
|
|
|
|
|
|
// This node has no parent, indicated by -1. The preorder number is 0.
|
|
|
|
parent->Add(-1);
|
|
|
|
set_preorder_number(0);
|
|
|
|
preorder->Add(this);
|
2012-05-16 13:28:02 +00:00
|
|
|
BitVector* vars =
|
|
|
|
(variable_count == 0) ? NULL : new BitVector(variable_count);
|
|
|
|
assigned_vars->Add(vars);
|
2012-05-16 12:10:02 +00:00
|
|
|
|
2012-06-06 11:09:02 +00:00
|
|
|
// The graph entry consists of only one instruction.
|
|
|
|
set_last_instruction(this);
|
|
|
|
|
2012-05-16 12:10:02 +00:00
|
|
|
// Iteratively traverse all successors. In the unoptimized code, we will
|
|
|
|
// enter the function at the first successor in reverse postorder, so we
|
|
|
|
// must visit the normal entry last.
|
|
|
|
for (intptr_t i = catch_entries_.length() - 1; i >= 0; --i) {
|
2012-05-18 01:04:56 +00:00
|
|
|
catch_entries_[i]->DiscoverBlocks(this, preorder, postorder,
|
2012-07-26 13:21:39 +00:00
|
|
|
parent, assigned_vars,
|
|
|
|
variable_count, fixed_parameter_count);
|
2012-05-16 12:10:02 +00:00
|
|
|
}
|
2012-05-18 01:04:56 +00:00
|
|
|
normal_entry_->DiscoverBlocks(this, preorder, postorder,
|
2012-07-26 13:21:39 +00:00
|
|
|
parent, assigned_vars,
|
|
|
|
variable_count, fixed_parameter_count);
|
2012-05-16 12:10:02 +00:00
|
|
|
|
|
|
|
// Assign postorder number.
|
|
|
|
set_postorder_number(postorder->length());
|
|
|
|
postorder->Add(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-16 13:28:02 +00:00
|
|
|
// Base class implementation used for JoinEntry and TargetEntry.
|
|
|
|
void BlockEntryInstr::DiscoverBlocks(
|
2012-03-19 19:39:14 +00:00
|
|
|
BlockEntryInstr* current_block,
|
2012-03-16 22:20:04 +00:00
|
|
|
GrowableArray<BlockEntryInstr*>* preorder,
|
2012-03-19 19:39:14 +00:00
|
|
|
GrowableArray<BlockEntryInstr*>* postorder,
|
2012-05-16 13:28:02 +00:00
|
|
|
GrowableArray<intptr_t>* parent,
|
|
|
|
GrowableArray<BitVector*>* assigned_vars,
|
2012-07-26 13:21:39 +00:00
|
|
|
intptr_t variable_count,
|
|
|
|
intptr_t fixed_parameter_count) {
|
2012-05-16 12:10:02 +00:00
|
|
|
// We have already visited the graph entry, so we can assume current_block
|
|
|
|
// is non-null and preorder array is non-empty.
|
2012-03-19 19:39:14 +00:00
|
|
|
ASSERT(current_block != NULL);
|
|
|
|
ASSERT(!preorder->is_empty());
|
2012-09-19 14:10:14 +00:00
|
|
|
// Blocks with a single predecessor cannot have been reached before.
|
|
|
|
ASSERT(!IsTargetEntry() || !IsMarked(this, preorder));
|
|
|
|
|
|
|
|
// 1. If the block has already been reached, add current_block as a
|
|
|
|
// basic-block predecessor and we are done.
|
|
|
|
if (IsMarked(this, preorder)) {
|
|
|
|
AddPredecessor(current_block);
|
|
|
|
return;
|
|
|
|
}
|
2012-03-19 19:39:14 +00:00
|
|
|
|
2012-09-19 14:10:14 +00:00
|
|
|
// 2. Otherwise, clear the predecessors which might have been computed on
|
|
|
|
// some earlier call to DiscoverBlocks and record this predecessor. For
|
|
|
|
// joins save the original predecessors, if any, so we can garbage collect
|
|
|
|
// phi inputs from unreachable predecessors without recomputing SSA.
|
|
|
|
ClearPredecessors();
|
2012-05-16 13:28:02 +00:00
|
|
|
AddPredecessor(current_block);
|
2012-03-19 19:39:14 +00:00
|
|
|
|
2012-07-04 10:24:19 +00:00
|
|
|
// 3. The current block is the spanning-tree parent.
|
|
|
|
parent->Add(current_block->preorder_number());
|
2012-03-19 19:39:14 +00:00
|
|
|
|
|
|
|
// 4. Assign preorder number and add the block entry to the list.
|
2012-05-16 13:28:02 +00:00
|
|
|
// Allocate an empty set of assigned variables for the block.
|
2012-07-04 10:24:19 +00:00
|
|
|
set_preorder_number(preorder->length());
|
2012-03-16 22:20:04 +00:00
|
|
|
preorder->Add(this);
|
2012-05-16 13:28:02 +00:00
|
|
|
BitVector* vars =
|
|
|
|
(variable_count == 0) ? NULL : new BitVector(variable_count);
|
|
|
|
assigned_vars->Add(vars);
|
|
|
|
// The preorder, parent, and assigned_vars arrays are all indexed by
|
|
|
|
// preorder block number, so they should stay in lockstep.
|
2012-03-19 19:39:14 +00:00
|
|
|
ASSERT(preorder->length() == parent->length());
|
2012-05-16 13:28:02 +00:00
|
|
|
ASSERT(preorder->length() == assigned_vars->length());
|
2012-03-19 19:39:14 +00:00
|
|
|
|
2012-03-19 21:57:06 +00:00
|
|
|
// 5. Iterate straight-line successors until a branch instruction or
|
|
|
|
// another basic block entry instruction, and visit that instruction.
|
2012-07-09 11:38:29 +00:00
|
|
|
ASSERT(next() != NULL);
|
2012-08-06 10:43:47 +00:00
|
|
|
ASSERT(!next()->IsBlockEntry());
|
2012-07-09 11:38:29 +00:00
|
|
|
Instruction* next_instr = next();
|
2012-08-06 10:43:47 +00:00
|
|
|
while ((next_instr != NULL) &&
|
|
|
|
!next_instr->IsBlockEntry() &&
|
2012-08-27 09:30:20 +00:00
|
|
|
!next_instr->IsControl()) {
|
2012-08-06 10:43:47 +00:00
|
|
|
if (vars != NULL) {
|
|
|
|
next_instr->RecordAssignedVars(vars, fixed_parameter_count);
|
2012-05-16 13:28:02 +00:00
|
|
|
}
|
2012-08-06 10:43:47 +00:00
|
|
|
set_last_instruction(next_instr);
|
|
|
|
GotoInstr* goto_instr = next_instr->AsGoto();
|
|
|
|
next_instr =
|
|
|
|
(goto_instr != NULL) ? goto_instr->successor() : next_instr->next();
|
2012-03-19 21:57:06 +00:00
|
|
|
}
|
2012-07-09 11:38:29 +00:00
|
|
|
if (next_instr != NULL) {
|
|
|
|
next_instr->DiscoverBlocks(this, preorder, postorder,
|
2012-07-26 13:21:39 +00:00
|
|
|
parent, assigned_vars,
|
|
|
|
variable_count, fixed_parameter_count);
|
2012-03-19 21:57:06 +00:00
|
|
|
}
|
2012-03-19 19:39:14 +00:00
|
|
|
|
|
|
|
// 6. Assign postorder number and add the block entry to the list.
|
2012-03-16 22:20:04 +00:00
|
|
|
set_postorder_number(postorder->length());
|
|
|
|
postorder->Add(this);
|
2012-03-07 10:24:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-06 13:21:20 +00:00
|
|
|
bool BlockEntryInstr::Dominates(BlockEntryInstr* other) const {
|
|
|
|
// TODO(fschneider): Make this faster by e.g. storing dominators for each
|
|
|
|
// block while computing the dominator tree.
|
|
|
|
ASSERT(other != NULL);
|
|
|
|
BlockEntryInstr* current = other;
|
|
|
|
while (current != NULL && current != this) {
|
|
|
|
current = current->dominator();
|
|
|
|
}
|
|
|
|
return current == this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-27 09:30:20 +00:00
|
|
|
void ControlInstruction::DiscoverBlocks(
|
2012-03-19 19:39:14 +00:00
|
|
|
BlockEntryInstr* current_block,
|
2012-03-16 22:20:04 +00:00
|
|
|
GrowableArray<BlockEntryInstr*>* preorder,
|
2012-03-19 19:39:14 +00:00
|
|
|
GrowableArray<BlockEntryInstr*>* postorder,
|
2012-05-16 13:28:02 +00:00
|
|
|
GrowableArray<intptr_t>* parent,
|
|
|
|
GrowableArray<BitVector*>* assigned_vars,
|
2012-07-26 13:21:39 +00:00
|
|
|
intptr_t variable_count,
|
|
|
|
intptr_t fixed_parameter_count) {
|
2012-03-19 19:39:14 +00:00
|
|
|
current_block->set_last_instruction(this);
|
Initial implementation of a flow-graph builder for Dart's AST.
Visit the AST and generate an instruction (ie, not basic-block) flow
graph.
The flow graph for the simple function:
main() {
var f = 1;
var n = 5;
while (n > 0) {
f = f * n;
n = n - 1;
}
print(f);
}
is:
1: StoreLocal(f, #1)
2: StoreLocal(n, #5)
3: [join]
4: t0 <-LoadLocal(n)
5: t0 <-InstanceCall(>, t0, #0)
6: if t0 goto(7, 15)
7: [target]
8: t0 <-LoadLocal(f)
9: t1 <-LoadLocal(n)
10: t0 <-InstanceCall(*, t0, t1)
11: StoreLocal(f, t0)
12: t0 <-LoadLocal(n)
13: t0 <-InstanceCall(-, t0, #1)
14: StoreLocal(n, t0) goto 3
15: [target]
16: t0 <-LoadLocal(f)
17: StaticCall(print, t0)
18: return #null
BUG=
TEST=
Review URL: https://chromiumcodereview.appspot.com//9414003
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@4460 260f80e4-7a28-3924-810f-c04153c831b5
2012-02-22 15:20:13 +00:00
|
|
|
// Visit the false successor before the true successor so they appear in
|
2012-03-16 22:20:04 +00:00
|
|
|
// true/false order in reverse postorder used as the block ordering in the
|
|
|
|
// nonoptimizing compiler.
|
2012-03-09 21:34:58 +00:00
|
|
|
ASSERT(true_successor_ != NULL);
|
2012-03-16 22:20:04 +00:00
|
|
|
ASSERT(false_successor_ != NULL);
|
2012-05-18 01:04:56 +00:00
|
|
|
false_successor_->DiscoverBlocks(current_block, preorder, postorder,
|
2012-07-26 13:21:39 +00:00
|
|
|
parent, assigned_vars,
|
|
|
|
variable_count, fixed_parameter_count);
|
2012-05-18 01:04:56 +00:00
|
|
|
true_successor_->DiscoverBlocks(current_block, preorder, postorder,
|
2012-07-26 13:21:39 +00:00
|
|
|
parent, assigned_vars,
|
|
|
|
variable_count, fixed_parameter_count);
|
Initial implementation of a flow-graph builder for Dart's AST.
Visit the AST and generate an instruction (ie, not basic-block) flow
graph.
The flow graph for the simple function:
main() {
var f = 1;
var n = 5;
while (n > 0) {
f = f * n;
n = n - 1;
}
print(f);
}
is:
1: StoreLocal(f, #1)
2: StoreLocal(n, #5)
3: [join]
4: t0 <-LoadLocal(n)
5: t0 <-InstanceCall(>, t0, #0)
6: if t0 goto(7, 15)
7: [target]
8: t0 <-LoadLocal(f)
9: t1 <-LoadLocal(n)
10: t0 <-InstanceCall(*, t0, t1)
11: StoreLocal(f, t0)
12: t0 <-LoadLocal(n)
13: t0 <-InstanceCall(-, t0, #1)
14: StoreLocal(n, t0) goto 3
15: [target]
16: t0 <-LoadLocal(f)
17: StaticCall(print, t0)
18: return #null
BUG=
TEST=
Review URL: https://chromiumcodereview.appspot.com//9414003
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@4460 260f80e4-7a28-3924-810f-c04153c831b5
2012-02-22 15:20:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-13 13:36:04 +00:00
|
|
|
void JoinEntryInstr::InsertPhi(intptr_t var_index, intptr_t var_count) {
|
|
|
|
// Lazily initialize the array of phis.
|
|
|
|
// Currently, phis are stored in a sparse array that holds the phi
|
|
|
|
// for variable with index i at position i.
|
|
|
|
// TODO(fschneider): Store phis in a more compact way.
|
|
|
|
if (phis_ == NULL) {
|
|
|
|
phis_ = new ZoneGrowableArray<PhiInstr*>(var_count);
|
|
|
|
for (intptr_t i = 0; i < var_count; i++) {
|
|
|
|
phis_->Add(NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ASSERT((*phis_)[var_index] == NULL);
|
2012-08-30 20:39:48 +00:00
|
|
|
(*phis_)[var_index] = new PhiInstr(this, PredecessorCount());
|
2012-06-13 13:36:04 +00:00
|
|
|
phi_count_++;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-08 12:38:21 +00:00
|
|
|
void JoinEntryInstr::RemoveDeadPhis() {
|
|
|
|
if (phis_ == NULL) return;
|
|
|
|
|
|
|
|
for (intptr_t i = 0; i < phis_->length(); i++) {
|
|
|
|
PhiInstr* phi = (*phis_)[i];
|
|
|
|
if ((phi != NULL) && !phi->is_alive()) {
|
|
|
|
(*phis_)[i] = NULL;
|
|
|
|
phi_count_--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if we removed all phis.
|
|
|
|
if (phi_count_ == 0) phis_ = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-06 11:09:02 +00:00
|
|
|
intptr_t Instruction::SuccessorCount() const {
|
2012-07-18 13:44:12 +00:00
|
|
|
return 0;
|
2012-06-06 11:09:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BlockEntryInstr* Instruction::SuccessorAt(intptr_t index) const {
|
2012-07-18 13:44:12 +00:00
|
|
|
// Called only if index is in range. Only control-transfer instructions
|
|
|
|
// can have non-zero successor counts and they override this function.
|
|
|
|
UNREACHABLE();
|
|
|
|
return NULL;
|
2012-07-02 16:08:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-06 11:09:02 +00:00
|
|
|
intptr_t GraphEntryInstr::SuccessorCount() const {
|
|
|
|
return 1 + catch_entries_.length();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BlockEntryInstr* GraphEntryInstr::SuccessorAt(intptr_t index) const {
|
|
|
|
if (index == 0) return normal_entry_;
|
|
|
|
return catch_entries_[index - 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-27 09:30:20 +00:00
|
|
|
intptr_t ControlInstruction::SuccessorCount() const {
|
2012-06-06 11:09:02 +00:00
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-27 09:30:20 +00:00
|
|
|
BlockEntryInstr* ControlInstruction::SuccessorAt(intptr_t index) const {
|
2012-06-06 11:09:02 +00:00
|
|
|
if (index == 0) return true_successor_;
|
|
|
|
if (index == 1) return false_successor_;
|
|
|
|
UNREACHABLE();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-18 13:44:12 +00:00
|
|
|
intptr_t GotoInstr::SuccessorCount() const {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BlockEntryInstr* GotoInstr::SuccessorAt(intptr_t index) const {
|
|
|
|
ASSERT(index == 0);
|
|
|
|
return successor();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Instruction::Goto(JoinEntryInstr* entry) {
|
2012-10-03 15:05:27 +00:00
|
|
|
LinkTo(new GotoInstr(entry));
|
2012-07-18 13:44:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-30 09:08:27 +00:00
|
|
|
RawAbstractType* Value::CompileType() const {
|
2012-08-13 16:56:10 +00:00
|
|
|
if (definition()->HasPropagatedType()) {
|
|
|
|
return definition()->PropagatedType();
|
|
|
|
}
|
|
|
|
// The compile type may be requested when building the flow graph, i.e. before
|
|
|
|
// type propagation has occurred. To avoid repeatedly computing the compile
|
|
|
|
// type of the definition, we store it as initial propagated type.
|
|
|
|
AbstractType& type = AbstractType::Handle(definition()->CompileType());
|
|
|
|
definition()->SetPropagatedType(type);
|
|
|
|
return type.raw();
|
2012-05-16 23:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-30 09:08:27 +00:00
|
|
|
intptr_t Value::ResultCid() const {
|
2012-09-12 17:38:23 +00:00
|
|
|
if (reaching_cid() == kIllegalCid) {
|
|
|
|
return definition()->GetPropagatedCid();
|
|
|
|
}
|
|
|
|
return reaching_cid();
|
2012-08-16 17:39:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-21 13:36:36 +00:00
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* ConstantInstr::CompileType() const {
|
2012-08-29 12:56:57 +00:00
|
|
|
if (value().IsNull()) {
|
|
|
|
return Type::NullType();
|
|
|
|
}
|
|
|
|
if (value().IsInstance()) {
|
|
|
|
return Instance::Cast(value()).GetType();
|
|
|
|
} else {
|
|
|
|
ASSERT(value().IsAbstractTypeArguments());
|
|
|
|
return AbstractType::null();
|
|
|
|
}
|
2012-08-21 13:36:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
intptr_t ConstantInstr::ResultCid() const {
|
2012-08-29 12:56:57 +00:00
|
|
|
if (value().IsNull()) {
|
|
|
|
return kNullCid;
|
|
|
|
}
|
|
|
|
if (value().IsInstance()) {
|
|
|
|
return Class::Handle(value().clazz()).id();
|
|
|
|
} else {
|
|
|
|
ASSERT(value().IsAbstractTypeArguments());
|
|
|
|
return kDynamicCid;
|
|
|
|
}
|
2012-08-21 13:36:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* AssertAssignableInstr::CompileType() const {
|
2012-08-10 01:26:13 +00:00
|
|
|
const AbstractType& value_compile_type =
|
|
|
|
AbstractType::Handle(value()->CompileType());
|
|
|
|
if (!value_compile_type.IsNull() &&
|
|
|
|
value_compile_type.IsMoreSpecificThan(dst_type(), NULL)) {
|
|
|
|
return value_compile_type.raw();
|
2012-07-26 16:04:36 +00:00
|
|
|
}
|
2012-05-16 23:21:24 +00:00
|
|
|
return dst_type().raw();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* AssertBooleanInstr::CompileType() const {
|
2012-08-27 21:09:23 +00:00
|
|
|
return Type::BoolType();
|
2012-05-16 23:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* ArgumentDefinitionTestInstr::CompileType() const {
|
2012-08-30 22:46:44 +00:00
|
|
|
return Type::BoolType();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* CurrentContextInstr::CompileType() const {
|
2012-05-16 23:21:24 +00:00
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* StoreContextInstr::CompileType() const {
|
2012-05-16 23:21:24 +00:00
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* ClosureCallInstr::CompileType() const {
|
2012-08-10 01:26:13 +00:00
|
|
|
// Because of function subtyping rules, the declared return type of a closure
|
|
|
|
// call cannot be relied upon for compile type analysis. For example, a
|
2012-07-09 18:02:40 +00:00
|
|
|
// function returning Dynamic can be assigned to a closure variable declared
|
|
|
|
// to return int and may actually return a double at run-time.
|
|
|
|
return Type::DynamicType();
|
2012-05-16 23:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* InstanceCallInstr::CompileType() const {
|
2012-07-26 16:04:36 +00:00
|
|
|
// TODO(regis): Return a more specific type than Dynamic for recognized
|
2012-08-10 01:26:13 +00:00
|
|
|
// combinations of receiver type and method name.
|
2012-05-16 23:21:24 +00:00
|
|
|
return Type::DynamicType();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* PolymorphicInstanceCallInstr::CompileType() const {
|
2012-06-13 18:48:46 +00:00
|
|
|
return Type::DynamicType();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* StaticCallInstr::CompileType() const {
|
2012-08-15 23:49:12 +00:00
|
|
|
if (FLAG_enable_type_checks) {
|
|
|
|
return function().result_type();
|
|
|
|
}
|
|
|
|
return Type::DynamicType();
|
2012-05-16 23:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* LoadLocalInstr::CompileType() const {
|
2012-07-26 16:04:36 +00:00
|
|
|
if (FLAG_enable_type_checks) {
|
|
|
|
return local().type().raw();
|
|
|
|
}
|
|
|
|
return Type::DynamicType();
|
2012-05-16 23:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* StoreLocalInstr::CompileType() const {
|
2012-08-10 01:26:13 +00:00
|
|
|
return value()->CompileType();
|
2012-05-16 23:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* StrictCompareInstr::CompileType() const {
|
2012-08-27 21:09:23 +00:00
|
|
|
return Type::BoolType();
|
2012-05-16 23:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-13 23:44:07 +00:00
|
|
|
// Only known == targets return a Boolean.
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* EqualityCompareInstr::CompileType() const {
|
2012-08-13 23:44:07 +00:00
|
|
|
if ((receiver_class_id() == kSmiCid) ||
|
|
|
|
(receiver_class_id() == kDoubleCid) ||
|
|
|
|
(receiver_class_id() == kNumberCid)) {
|
2012-08-27 21:09:23 +00:00
|
|
|
return Type::BoolType();
|
2012-08-13 23:44:07 +00:00
|
|
|
}
|
|
|
|
return Type::DynamicType();
|
2012-05-16 23:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
intptr_t EqualityCompareInstr::ResultCid() const {
|
2012-08-16 22:22:57 +00:00
|
|
|
if ((receiver_class_id() == kSmiCid) ||
|
|
|
|
(receiver_class_id() == kDoubleCid) ||
|
|
|
|
(receiver_class_id() == kNumberCid)) {
|
|
|
|
// Known/library equalities that are guaranteed to return Boolean.
|
|
|
|
return kBoolCid;
|
|
|
|
}
|
|
|
|
return kDynamicCid;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* RelationalOpInstr::CompileType() const {
|
2012-08-13 23:44:07 +00:00
|
|
|
if ((operands_class_id() == kSmiCid) ||
|
|
|
|
(operands_class_id() == kDoubleCid) ||
|
|
|
|
(operands_class_id() == kNumberCid)) {
|
2012-08-16 22:22:57 +00:00
|
|
|
// Known/library relational ops that are guaranteed to return Boolean.
|
2012-08-27 21:09:23 +00:00
|
|
|
return Type::BoolType();
|
2012-08-13 23:44:07 +00:00
|
|
|
}
|
|
|
|
return Type::DynamicType();
|
2012-06-11 17:02:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
intptr_t RelationalOpInstr::ResultCid() const {
|
2012-08-16 22:22:57 +00:00
|
|
|
if ((operands_class_id() == kSmiCid) ||
|
|
|
|
(operands_class_id() == kDoubleCid) ||
|
|
|
|
(operands_class_id() == kNumberCid)) {
|
|
|
|
// Known/library relational ops that are guaranteed to return Boolean.
|
|
|
|
return kBoolCid;
|
|
|
|
}
|
|
|
|
return kDynamicCid;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* NativeCallInstr::CompileType() const {
|
2012-05-16 23:21:24 +00:00
|
|
|
// The result type of the native function is identical to the result type of
|
2012-05-17 18:47:45 +00:00
|
|
|
// the enclosing native Dart function. However, we prefer to check the type
|
|
|
|
// of the value returned from the native call.
|
2012-05-16 23:21:24 +00:00
|
|
|
return Type::DynamicType();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* LoadIndexedInstr::CompileType() const {
|
2012-06-08 19:36:26 +00:00
|
|
|
return Type::DynamicType();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* StoreIndexedInstr::CompileType() const {
|
2012-05-30 15:55:46 +00:00
|
|
|
return AbstractType::null();
|
2012-05-16 23:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* StoreInstanceFieldInstr::CompileType() const {
|
2012-08-10 01:26:13 +00:00
|
|
|
return value()->CompileType();
|
2012-05-16 23:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* LoadStaticFieldInstr::CompileType() const {
|
2012-07-26 16:04:36 +00:00
|
|
|
if (FLAG_enable_type_checks) {
|
|
|
|
return field().type();
|
|
|
|
}
|
|
|
|
return Type::DynamicType();
|
2012-05-16 23:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* StoreStaticFieldInstr::CompileType() const {
|
2012-08-10 01:26:13 +00:00
|
|
|
return value()->CompileType();
|
2012-05-16 23:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* BooleanNegateInstr::CompileType() const {
|
2012-08-27 21:09:23 +00:00
|
|
|
return Type::BoolType();
|
2012-05-16 23:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* InstanceOfInstr::CompileType() const {
|
2012-08-27 21:09:23 +00:00
|
|
|
return Type::BoolType();
|
2012-05-16 23:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* CreateArrayInstr::CompileType() const {
|
2012-08-24 18:17:11 +00:00
|
|
|
return type().raw();
|
2012-05-16 23:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* CreateClosureInstr::CompileType() const {
|
2012-05-16 23:21:24 +00:00
|
|
|
const Function& fun = function();
|
|
|
|
const Class& signature_class = Class::Handle(fun.signature_class());
|
2012-07-20 16:08:43 +00:00
|
|
|
return signature_class.SignatureType();
|
2012-05-16 23:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* AllocateObjectInstr::CompileType() const {
|
2012-08-01 17:15:55 +00:00
|
|
|
// TODO(regis): Be more specific.
|
|
|
|
return Type::DynamicType();
|
2012-05-16 23:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* AllocateObjectWithBoundsCheckInstr::CompileType() const {
|
2012-08-10 01:26:13 +00:00
|
|
|
// TODO(regis): Be more specific.
|
|
|
|
return Type::DynamicType();
|
2012-05-16 23:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-12 17:43:37 +00:00
|
|
|
RawAbstractType* LoadFieldInstr::CompileType() const {
|
2012-08-10 01:26:13 +00:00
|
|
|
// Type may be null if the field is a VM field, e.g. context parent.
|
2012-08-23 21:04:13 +00:00
|
|
|
// Keep it as null for debug purposes and do not return Dynamic in production
|
|
|
|
// mode, since misuse of the type would remain undetected.
|
|
|
|
if (type().IsNull()) {
|
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
if (FLAG_enable_type_checks) {
|
|
|
|
return type().raw();
|
|
|
|
}
|
|
|
|
return Type::DynamicType();
|
2012-05-16 23:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* StoreVMFieldInstr::CompileType() const {
|
2012-08-10 01:26:13 +00:00
|
|
|
return value()->CompileType();
|
2012-05-16 23:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* InstantiateTypeArgumentsInstr::CompileType() const {
|
2012-05-16 23:21:24 +00:00
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* ExtractConstructorTypeArgumentsInstr::CompileType() const {
|
2012-05-16 23:21:24 +00:00
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* ExtractConstructorInstantiatorInstr::CompileType() const {
|
2012-05-16 23:21:24 +00:00
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* AllocateContextInstr::CompileType() const {
|
2012-05-16 23:21:24 +00:00
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* ChainContextInstr::CompileType() const {
|
2012-05-16 23:21:24 +00:00
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* CloneContextInstr::CompileType() const {
|
2012-05-16 23:21:24 +00:00
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* CatchEntryInstr::CompileType() const {
|
2012-05-16 23:21:24 +00:00
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* CheckStackOverflowInstr::CompileType() const {
|
2012-08-11 00:09:12 +00:00
|
|
|
return AbstractType::null();
|
2012-06-11 17:02:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* BinarySmiOpInstr::CompileType() const {
|
2012-09-13 07:17:27 +00:00
|
|
|
return (op_kind() == Token::kSHL) ? Type::IntType() : Type::SmiType();
|
2012-08-16 22:22:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
intptr_t BinarySmiOpInstr::ResultCid() const {
|
2012-08-16 22:22:57 +00:00
|
|
|
return (op_kind() == Token::kSHL) ? kDynamicCid : kSmiCid;
|
2012-05-24 16:50:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
bool BinarySmiOpInstr::CanDeoptimize() const {
|
2012-08-23 08:24:29 +00:00
|
|
|
switch (op_kind()) {
|
|
|
|
case Token::kBIT_AND:
|
|
|
|
case Token::kBIT_OR:
|
|
|
|
case Token::kBIT_XOR:
|
|
|
|
return false;
|
|
|
|
default:
|
2012-09-21 20:06:31 +00:00
|
|
|
return overflow_;
|
2012-08-23 08:24:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-04 15:54:16 +00:00
|
|
|
RawAbstractType* BinaryMintOpInstr::CompileType() const {
|
2012-10-02 11:25:53 +00:00
|
|
|
return Type::IntType();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-04 15:54:16 +00:00
|
|
|
intptr_t BinaryMintOpInstr::ResultCid() const {
|
2012-10-02 11:25:53 +00:00
|
|
|
return kDynamicCid;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-05 14:42:00 +00:00
|
|
|
RawAbstractType* ShiftMintOpInstr::CompileType() const {
|
|
|
|
return Type::IntType();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
intptr_t ShiftMintOpInstr::ResultCid() const {
|
|
|
|
return kDynamicCid;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-04 15:54:16 +00:00
|
|
|
RawAbstractType* UnaryMintOpInstr::CompileType() const {
|
2012-10-04 12:01:12 +00:00
|
|
|
return Type::IntType();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-04 15:54:16 +00:00
|
|
|
intptr_t UnaryMintOpInstr::ResultCid() const {
|
2012-10-04 12:01:12 +00:00
|
|
|
return kDynamicCid;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-04 15:54:16 +00:00
|
|
|
RawAbstractType* BinaryDoubleOpInstr::CompileType() const {
|
2012-08-30 17:29:49 +00:00
|
|
|
return Type::Double();
|
2012-08-24 14:45:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-04 15:54:16 +00:00
|
|
|
intptr_t BinaryDoubleOpInstr::ResultCid() const {
|
|
|
|
// The output is not an instance but when it is boxed it becomes double.
|
|
|
|
return kDoubleCid;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-11 14:52:32 +00:00
|
|
|
RawAbstractType* MathSqrtInstr::CompileType() const {
|
|
|
|
return Type::Double();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* UnboxDoubleInstr::CompileType() const {
|
2012-08-24 14:45:42 +00:00
|
|
|
return Type::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
intptr_t BoxDoubleInstr::ResultCid() const {
|
2012-08-24 14:45:42 +00:00
|
|
|
return kDoubleCid;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* BoxDoubleInstr::CompileType() const {
|
2012-08-30 17:29:49 +00:00
|
|
|
return Type::Double();
|
2012-08-24 14:45:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-02 11:25:53 +00:00
|
|
|
intptr_t BoxIntegerInstr::ResultCid() const {
|
|
|
|
return kDynamicCid;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* BoxIntegerInstr::CompileType() const {
|
|
|
|
return Type::IntType();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
intptr_t UnboxIntegerInstr::ResultCid() const {
|
|
|
|
return kDynamicCid;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* UnboxIntegerInstr::CompileType() const {
|
|
|
|
return Type::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* UnarySmiOpInstr::CompileType() const {
|
2012-08-23 21:04:13 +00:00
|
|
|
return Type::SmiType();
|
2012-05-31 20:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* DoubleToDoubleInstr::CompileType() const {
|
2012-08-30 17:29:49 +00:00
|
|
|
return Type::Double();
|
2012-08-15 11:31:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* SmiToDoubleInstr::CompileType() const {
|
2012-08-30 17:29:49 +00:00
|
|
|
return Type::Double();
|
2012-06-13 08:29:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* CheckClassInstr::CompileType() const {
|
2012-08-20 12:40:14 +00:00
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* CheckSmiInstr::CompileType() const {
|
2012-08-23 08:24:29 +00:00
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* CheckArrayBoundInstr::CompileType() const {
|
2012-08-28 09:14:57 +00:00
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
RawAbstractType* CheckEitherNonSmiInstr::CompileType() const {
|
2012-08-24 14:45:42 +00:00
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-19 14:38:31 +00:00
|
|
|
// Optimizations that eliminate or simplify individual instructions.
|
|
|
|
Instruction* Instruction::Canonicalize() {
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
Definition* Definition::Canonicalize() {
|
|
|
|
return this;
|
2012-08-23 08:24:29 +00:00
|
|
|
}
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
Definition* StrictCompareInstr::Canonicalize() {
|
|
|
|
if (!right()->BindsToConstant()) return this;
|
2012-08-30 09:08:27 +00:00
|
|
|
const Object& right_constant = right()->BoundConstant();
|
|
|
|
Definition* left_defn = left()->definition();
|
2012-08-23 08:24:29 +00:00
|
|
|
// TODO(fschneider): Handle other cases: e === false and e !== true/false.
|
|
|
|
// Handles e === true.
|
|
|
|
if ((kind() == Token::kEQ_STRICT) &&
|
|
|
|
(right_constant.raw() == Bool::True()) &&
|
2012-08-30 09:08:27 +00:00
|
|
|
(left()->ResultCid() == kBoolCid)) {
|
2012-08-23 08:24:29 +00:00
|
|
|
// Return left subexpression as the replacement for this instruction.
|
2012-08-30 09:08:27 +00:00
|
|
|
return left_defn;
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
}
|
2012-09-05 17:04:49 +00:00
|
|
|
return this;
|
2012-08-27 14:01:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-19 14:38:31 +00:00
|
|
|
Instruction* CheckClassInstr::Canonicalize() {
|
2012-08-27 14:01:27 +00:00
|
|
|
const intptr_t v_cid = value()->ResultCid();
|
2012-09-03 11:27:09 +00:00
|
|
|
const intptr_t num_checks = unary_checks().NumberOfChecks();
|
2012-08-27 14:01:27 +00:00
|
|
|
if ((num_checks == 1) &&
|
2012-09-03 11:27:09 +00:00
|
|
|
(v_cid == unary_checks().GetReceiverClassIdAt(0))) {
|
2012-08-27 14:01:27 +00:00
|
|
|
// No checks needed.
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-09-05 17:04:49 +00:00
|
|
|
return this;
|
2012-08-23 08:24:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-19 14:38:31 +00:00
|
|
|
Instruction* CheckSmiInstr::Canonicalize() {
|
2012-09-05 17:04:49 +00:00
|
|
|
return (value()->ResultCid() == kSmiCid) ? NULL : this;
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-19 14:38:31 +00:00
|
|
|
Instruction* CheckEitherNonSmiInstr::Canonicalize() {
|
2012-08-24 14:45:42 +00:00
|
|
|
if ((left()->ResultCid() == kDoubleCid) ||
|
|
|
|
(right()->ResultCid() == kDoubleCid)) {
|
|
|
|
return NULL; // Remove from the graph.
|
|
|
|
}
|
2012-09-05 17:04:49 +00:00
|
|
|
return this;
|
2012-08-24 14:45:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-23 08:24:29 +00:00
|
|
|
// Shared code generation methods (EmitNativeCode, MakeLocationSummary, and
|
|
|
|
// PrepareEntry). Only assembly code that can be shared across all architectures
|
|
|
|
// can be used. Machine specific register allocation and code generation
|
|
|
|
// is located in intermediate_language_<arch>.cc
|
|
|
|
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
#define __ compiler->assembler()->
|
|
|
|
|
|
|
|
void GraphEntryInstr::PrepareEntry(FlowGraphCompiler* compiler) {
|
|
|
|
// Nothing to do.
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void JoinEntryInstr::PrepareEntry(FlowGraphCompiler* compiler) {
|
|
|
|
__ Bind(compiler->GetBlockLabel(this));
|
2012-07-31 16:28:09 +00:00
|
|
|
if (HasParallelMove()) {
|
|
|
|
compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
|
|
|
|
}
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TargetEntryInstr::PrepareEntry(FlowGraphCompiler* compiler) {
|
|
|
|
__ Bind(compiler->GetBlockLabel(this));
|
2012-08-29 16:44:18 +00:00
|
|
|
if (IsCatchEntry()) {
|
|
|
|
compiler->AddExceptionHandler(catch_try_index(),
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
compiler->assembler()->CodeSize());
|
|
|
|
}
|
2012-07-31 16:28:09 +00:00
|
|
|
if (HasParallelMove()) {
|
|
|
|
compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
|
|
|
|
}
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
LocationSummary* GraphEntryInstr::MakeLocationSummary() const {
|
|
|
|
UNREACHABLE();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void GraphEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* JoinEntryInstr::MakeLocationSummary() const {
|
|
|
|
UNREACHABLE();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void JoinEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* TargetEntryInstr::MakeLocationSummary() const {
|
|
|
|
UNREACHABLE();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TargetEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* PhiInstr::MakeLocationSummary() const {
|
|
|
|
UNREACHABLE();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void PhiInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* ParameterInstr::MakeLocationSummary() const {
|
|
|
|
UNREACHABLE();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ParameterInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* ParallelMoveInstr::MakeLocationSummary() const {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ParallelMoveInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-21 20:06:31 +00:00
|
|
|
LocationSummary* ConstraintInstr::MakeLocationSummary() const {
|
|
|
|
UNREACHABLE();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ConstraintInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
LocationSummary* ThrowInstr::MakeLocationSummary() const {
|
2012-08-02 15:54:42 +00:00
|
|
|
return new LocationSummary(0, 0, LocationSummary::kCall);
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ThrowInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-08-31 15:46:10 +00:00
|
|
|
compiler->GenerateCallRuntime(token_pos(),
|
2012-08-14 06:59:24 +00:00
|
|
|
kThrowRuntimeEntry,
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
__ int3();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* ReThrowInstr::MakeLocationSummary() const {
|
2012-08-02 15:54:42 +00:00
|
|
|
return new LocationSummary(0, 0, LocationSummary::kCall);
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ReThrowInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-08-31 15:46:10 +00:00
|
|
|
compiler->GenerateCallRuntime(token_pos(),
|
2012-08-14 06:59:24 +00:00
|
|
|
kReThrowRuntimeEntry,
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
__ int3();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-18 13:44:12 +00:00
|
|
|
LocationSummary* GotoInstr::MakeLocationSummary() const {
|
2012-07-31 11:51:47 +00:00
|
|
|
return new LocationSummary(0, 0, LocationSummary::kNoCall);
|
2012-07-18 13:44:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void GotoInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-09-06 13:21:20 +00:00
|
|
|
// Add deoptimization descriptor for deoptimizing instructions
|
|
|
|
// that may be inserted before this instruction.
|
2012-09-24 21:54:51 +00:00
|
|
|
if (!compiler->is_optimizing()) {
|
|
|
|
compiler->AddCurrentDescriptor(PcDescriptors::kDeoptBefore,
|
|
|
|
GetDeoptId(),
|
|
|
|
0); // No token position.
|
|
|
|
}
|
2012-09-06 13:21:20 +00:00
|
|
|
|
2012-07-31 16:28:09 +00:00
|
|
|
if (HasParallelMove()) {
|
|
|
|
compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
|
|
|
|
}
|
|
|
|
|
2012-07-18 13:44:12 +00:00
|
|
|
// We can fall through if the successor is the next block in the list.
|
|
|
|
// Otherwise, we need a jump.
|
|
|
|
if (!compiler->IsNextBlock(successor())) {
|
|
|
|
__ jmp(compiler->GetBlockLabel(successor()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-13 16:23:14 +00:00
|
|
|
static Condition NegateCondition(Condition condition) {
|
|
|
|
switch (condition) {
|
|
|
|
case EQUAL: return NOT_EQUAL;
|
|
|
|
case NOT_EQUAL: return EQUAL;
|
|
|
|
case LESS: return GREATER_EQUAL;
|
|
|
|
case LESS_EQUAL: return GREATER;
|
|
|
|
case GREATER: return LESS_EQUAL;
|
|
|
|
case GREATER_EQUAL: return LESS;
|
|
|
|
case BELOW: return ABOVE_EQUAL;
|
|
|
|
case BELOW_EQUAL: return ABOVE;
|
|
|
|
case ABOVE: return BELOW_EQUAL;
|
|
|
|
case ABOVE_EQUAL: return BELOW;
|
|
|
|
default:
|
|
|
|
OS::Print("Error %d\n", condition);
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
return EQUAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-06 13:27:30 +00:00
|
|
|
void ControlInstruction::EmitBranchOnValue(FlowGraphCompiler* compiler,
|
|
|
|
bool value) {
|
|
|
|
if (value && compiler->IsNextBlock(false_successor())) {
|
|
|
|
__ jmp(compiler->GetBlockLabel(true_successor()));
|
|
|
|
} else if (!value && compiler->IsNextBlock(true_successor())) {
|
|
|
|
__ jmp(compiler->GetBlockLabel(false_successor()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-27 09:30:20 +00:00
|
|
|
void ControlInstruction::EmitBranchOnCondition(FlowGraphCompiler* compiler,
|
|
|
|
Condition true_condition) {
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
if (compiler->IsNextBlock(false_successor())) {
|
2012-06-13 16:23:14 +00:00
|
|
|
// If the next block is the false successor we will fall through to it.
|
|
|
|
__ j(true_condition, compiler->GetBlockLabel(true_successor()));
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
} else {
|
|
|
|
// If the next block is the true successor we negate comparison and fall
|
|
|
|
// through to it.
|
2012-06-13 16:23:14 +00:00
|
|
|
ASSERT(compiler->IsNextBlock(true_successor()));
|
|
|
|
Condition false_condition = NegateCondition(true_condition);
|
|
|
|
__ j(false_condition, compiler->GetBlockLabel(false_successor()));
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
LocationSummary* CurrentContextInstr::MakeLocationSummary() const {
|
2012-07-31 11:51:47 +00:00
|
|
|
return LocationSummary::Make(0,
|
|
|
|
Location::RequiresRegister(),
|
|
|
|
LocationSummary::kNoCall);
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void CurrentContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
__ MoveRegister(locs()->out().reg(), CTX);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
LocationSummary* StoreContextInstr::MakeLocationSummary() const {
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2012-07-31 11:51:47 +00:00
|
|
|
LocationSummary* summary =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
summary->set_in(0, Location::RegisterLocation(CTX));
|
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void StoreContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
// Nothing to do. Context register were loaded by register allocator.
|
|
|
|
ASSERT(locs()->in(0).reg() == CTX);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
LocationSummary* StrictCompareInstr::MakeLocationSummary() const {
|
2012-09-25 20:34:15 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
|
|
|
const intptr_t kNumTemps = 0;
|
|
|
|
LocationSummary* locs =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
|
|
|
locs->set_in(0, Location::RegisterOrConstant(left()));
|
|
|
|
locs->set_in(1, Location::RegisterOrConstant(right()));
|
|
|
|
locs->set_out(Location::RequiresRegister());
|
|
|
|
return locs;
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void StrictCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-06-13 16:23:14 +00:00
|
|
|
ASSERT(kind() == Token::kEQ_STRICT || kind() == Token::kNE_STRICT);
|
2012-09-25 20:34:15 +00:00
|
|
|
Location left = locs()->in(0);
|
|
|
|
Location right = locs()->in(1);
|
|
|
|
if (left.IsConstant() && right.IsConstant()) {
|
|
|
|
// TODO(vegorov): should be eliminated earlier by constant propagation.
|
2012-09-25 20:59:37 +00:00
|
|
|
const bool result = (kind() == Token::kEQ_STRICT) ?
|
|
|
|
left.constant().raw() == right.constant().raw() :
|
|
|
|
left.constant().raw() != right.constant().raw();
|
2012-09-25 20:34:15 +00:00
|
|
|
__ LoadObject(locs()->out().reg(), result ? compiler->bool_true() :
|
|
|
|
compiler->bool_false());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (left.IsConstant()) {
|
2012-09-26 21:00:51 +00:00
|
|
|
compiler->EmitEqualityRegConstCompare(right.reg(), left.constant());
|
2012-09-25 20:34:15 +00:00
|
|
|
} else if (right.IsConstant()) {
|
2012-09-26 21:00:51 +00:00
|
|
|
compiler->EmitEqualityRegConstCompare(left.reg(), right.constant());
|
2012-09-25 20:34:15 +00:00
|
|
|
} else {
|
|
|
|
__ CompareRegisters(left.reg(), right.reg());
|
|
|
|
}
|
2012-06-13 16:23:14 +00:00
|
|
|
|
2012-07-19 15:52:44 +00:00
|
|
|
Register result = locs()->out().reg();
|
|
|
|
Label load_true, done;
|
2012-09-25 20:59:37 +00:00
|
|
|
Condition true_condition = (kind() == Token::kEQ_STRICT) ? EQUAL : NOT_EQUAL;
|
2012-07-19 15:52:44 +00:00
|
|
|
__ j(true_condition, &load_true, Assembler::kNearJump);
|
|
|
|
__ LoadObject(result, compiler->bool_false());
|
|
|
|
__ jmp(&done, Assembler::kNearJump);
|
|
|
|
__ Bind(&load_true);
|
|
|
|
__ LoadObject(result, compiler->bool_true());
|
|
|
|
__ Bind(&done);
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void StrictCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler,
|
2012-09-25 20:34:15 +00:00
|
|
|
BranchInstr* branch) {
|
2012-08-29 09:07:11 +00:00
|
|
|
ASSERT(kind() == Token::kEQ_STRICT || kind() == Token::kNE_STRICT);
|
2012-09-25 20:34:15 +00:00
|
|
|
Location left = locs()->in(0);
|
|
|
|
Location right = locs()->in(1);
|
|
|
|
if (left.IsConstant() && right.IsConstant()) {
|
|
|
|
// TODO(vegorov): should be eliminated earlier by constant propagation.
|
2012-09-25 20:59:37 +00:00
|
|
|
const bool result = (kind() == Token::kEQ_STRICT) ?
|
|
|
|
left.constant().raw() == right.constant().raw() :
|
|
|
|
left.constant().raw() != right.constant().raw();
|
2012-09-25 20:34:15 +00:00
|
|
|
branch->EmitBranchOnValue(compiler, result);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (left.IsConstant()) {
|
2012-09-26 21:00:51 +00:00
|
|
|
compiler->EmitEqualityRegConstCompare(right.reg(), left.constant());
|
2012-09-25 20:34:15 +00:00
|
|
|
} else if (right.IsConstant()) {
|
2012-09-26 21:00:51 +00:00
|
|
|
compiler->EmitEqualityRegConstCompare(left.reg(), right.constant());
|
2012-09-25 20:34:15 +00:00
|
|
|
} else {
|
|
|
|
__ CompareRegisters(left.reg(), right.reg());
|
|
|
|
}
|
|
|
|
|
2012-09-25 20:59:37 +00:00
|
|
|
Condition true_condition = (kind() == Token::kEQ_STRICT) ? EQUAL : NOT_EQUAL;
|
2012-08-29 09:07:11 +00:00
|
|
|
branch->EmitBranchOnCondition(compiler, true_condition);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void ClosureCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
// The arguments to the stub include the closure. The arguments
|
|
|
|
// descriptor describes the closure's arguments (and so does not include
|
|
|
|
// the closure).
|
|
|
|
Register temp_reg = locs()->temp(0).reg();
|
|
|
|
int argument_count = ArgumentCount();
|
|
|
|
const Array& arguments_descriptor =
|
2012-06-26 17:43:44 +00:00
|
|
|
DartEntry::ArgumentsDescriptor(argument_count - 1,
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
argument_names());
|
|
|
|
__ LoadObject(temp_reg, arguments_descriptor);
|
2012-08-30 18:53:46 +00:00
|
|
|
compiler->GenerateDartCall(deopt_id(),
|
|
|
|
token_pos(),
|
|
|
|
&StubCode::CallClosureFunctionLabel(),
|
|
|
|
PcDescriptors::kOther,
|
|
|
|
locs());
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
__ Drop(argument_count);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
LocationSummary* InstanceCallInstr::MakeLocationSummary() const {
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
return MakeCallSummary();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void InstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-09-24 21:54:51 +00:00
|
|
|
if (!compiler->is_optimizing()) {
|
|
|
|
compiler->AddCurrentDescriptor(PcDescriptors::kDeoptBefore,
|
|
|
|
deopt_id(),
|
|
|
|
token_pos());
|
|
|
|
}
|
2012-08-06 20:24:03 +00:00
|
|
|
compiler->GenerateInstanceCall(deopt_id(),
|
2012-06-22 20:37:01 +00:00
|
|
|
token_pos(),
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
function_name(),
|
|
|
|
ArgumentCount(),
|
|
|
|
argument_names(),
|
2012-08-14 06:59:24 +00:00
|
|
|
checked_argument_count(),
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
LocationSummary* StaticCallInstr::MakeLocationSummary() const {
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
return MakeCallSummary();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void StaticCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-08-06 20:24:03 +00:00
|
|
|
compiler->GenerateStaticCall(deopt_id(),
|
2012-06-22 20:37:01 +00:00
|
|
|
token_pos(),
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
function(),
|
|
|
|
ArgumentCount(),
|
2012-08-14 06:59:24 +00:00
|
|
|
argument_names(),
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void AssertAssignableInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-08-13 22:37:22 +00:00
|
|
|
if (!is_eliminated()) {
|
2012-08-31 15:46:10 +00:00
|
|
|
compiler->GenerateAssertAssignable(token_pos(),
|
2012-08-10 01:26:13 +00:00
|
|
|
dst_type(),
|
2012-08-14 06:59:24 +00:00
|
|
|
dst_name(),
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
2012-08-10 01:26:13 +00:00
|
|
|
}
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
ASSERT(locs()->in(0).reg() == locs()->out().reg());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
LocationSummary* BooleanNegateInstr::MakeLocationSummary() const {
|
2012-07-31 11:51:47 +00:00
|
|
|
return LocationSummary::Make(1,
|
|
|
|
Location::RequiresRegister(),
|
|
|
|
LocationSummary::kNoCall);
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void BooleanNegateInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
Register value = locs()->in(0).reg();
|
|
|
|
Register result = locs()->out().reg();
|
|
|
|
|
|
|
|
Label done;
|
2012-06-13 16:23:14 +00:00
|
|
|
__ LoadObject(result, compiler->bool_true());
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
__ CompareRegisters(result, value);
|
|
|
|
__ j(NOT_EQUAL, &done, Assembler::kNearJump);
|
2012-06-13 16:23:14 +00:00
|
|
|
__ LoadObject(result, compiler->bool_false());
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
__ Bind(&done);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
LocationSummary* ChainContextInstr::MakeLocationSummary() const {
|
2012-07-31 11:51:47 +00:00
|
|
|
return LocationSummary::Make(1,
|
|
|
|
Location::NoLocation(),
|
|
|
|
LocationSummary::kNoCall);
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void ChainContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
Register context_value = locs()->in(0).reg();
|
|
|
|
|
|
|
|
// Chain the new context in context_value to its parent in CTX.
|
|
|
|
__ StoreIntoObject(context_value,
|
|
|
|
FieldAddress(context_value, Context::parent_offset()),
|
|
|
|
CTX);
|
|
|
|
// Set new context as current context.
|
|
|
|
__ MoveRegister(CTX, context_value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
LocationSummary* StoreVMFieldInstr::MakeLocationSummary() const {
|
2012-09-11 12:50:52 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
|
|
|
const intptr_t kNumTemps = 0;
|
|
|
|
LocationSummary* locs =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
|
|
|
locs->set_in(0, value()->NeedsStoreBuffer() ? Location::WritableRegister()
|
|
|
|
: Location::RequiresRegister());
|
|
|
|
locs->set_in(1, Location::RequiresRegister());
|
|
|
|
return locs;
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void StoreVMFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
Register value_reg = locs()->in(0).reg();
|
|
|
|
Register dest_reg = locs()->in(1).reg();
|
|
|
|
|
2012-08-25 00:27:07 +00:00
|
|
|
if (value()->NeedsStoreBuffer()) {
|
|
|
|
__ StoreIntoObject(dest_reg, FieldAddress(dest_reg, offset_in_bytes()),
|
|
|
|
value_reg);
|
|
|
|
} else {
|
|
|
|
__ StoreIntoObjectNoBarrier(
|
|
|
|
dest_reg, FieldAddress(dest_reg, offset_in_bytes()), value_reg);
|
|
|
|
}
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
LocationSummary* AllocateObjectInstr::MakeLocationSummary() const {
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
return MakeCallSummary();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void AllocateObjectInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-08-14 00:38:01 +00:00
|
|
|
const Class& cls = Class::ZoneHandle(constructor().Owner());
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
const Code& stub = Code::Handle(StubCode::GetAllocationStubForClass(cls));
|
|
|
|
const ExternalLabel label(cls.ToCString(), stub.EntryPoint());
|
2012-06-22 20:37:01 +00:00
|
|
|
compiler->GenerateCall(token_pos(),
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
&label,
|
2012-08-14 06:59:24 +00:00
|
|
|
PcDescriptors::kOther,
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
2012-08-09 19:34:41 +00:00
|
|
|
__ Drop(ArgumentCount()); // Discard arguments.
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
LocationSummary* CreateClosureInstr::MakeLocationSummary() const {
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
return MakeCallSummary();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void CreateClosureInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
const Function& closure_function = function();
|
|
|
|
const Code& stub = Code::Handle(
|
|
|
|
StubCode::GetAllocationStubForClosure(closure_function));
|
|
|
|
const ExternalLabel label(closure_function.ToCString(), stub.EntryPoint());
|
2012-08-29 16:44:18 +00:00
|
|
|
compiler->GenerateCall(token_pos(),
|
|
|
|
&label,
|
2012-08-14 06:59:24 +00:00
|
|
|
PcDescriptors::kOther,
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
__ Drop(2); // Discard type arguments and receiver.
|
|
|
|
}
|
|
|
|
|
2012-06-14 18:07:43 +00:00
|
|
|
|
2012-07-26 14:10:29 +00:00
|
|
|
LocationSummary* PushArgumentInstr::MakeLocationSummary() const {
|
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps= 0;
|
2012-07-31 11:51:47 +00:00
|
|
|
LocationSummary* locs =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2012-07-26 14:10:29 +00:00
|
|
|
// TODO(fschneider): Use Any() once it is supported by all code generators.
|
|
|
|
locs->set_in(0, Location::RequiresRegister());
|
|
|
|
return locs;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void PushArgumentInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
// In SSA mode, we need an explicit push. Nothing to do in non-SSA mode
|
2012-08-21 13:58:57 +00:00
|
|
|
// where PushArgument is handled by BindInstr::EmitNativeCode.
|
2012-07-26 14:10:29 +00:00
|
|
|
// TODO(fschneider): Avoid special-casing for SSA mode here.
|
2012-08-21 13:58:57 +00:00
|
|
|
if (compiler->is_optimizing()) {
|
2012-07-26 14:10:29 +00:00
|
|
|
ASSERT(locs()->in(0).IsRegister());
|
|
|
|
__ PushRegister(locs()->in(0).reg());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-11 12:30:21 +00:00
|
|
|
Environment* Environment::From(const GrowableArray<Definition*>& definitions,
|
|
|
|
intptr_t fixed_parameter_count,
|
2012-09-18 13:41:20 +00:00
|
|
|
const Function& function) {
|
2012-09-11 12:30:21 +00:00
|
|
|
Environment* env =
|
|
|
|
new Environment(definitions.length(),
|
|
|
|
fixed_parameter_count,
|
|
|
|
Isolate::kNoDeoptId,
|
2012-09-18 13:41:20 +00:00
|
|
|
function,
|
|
|
|
NULL);
|
2012-08-17 13:06:08 +00:00
|
|
|
for (intptr_t i = 0; i < definitions.length(); ++i) {
|
2012-09-11 12:30:21 +00:00
|
|
|
env->values_.Add(new Value(definitions[i]));
|
2012-08-17 13:06:08 +00:00
|
|
|
}
|
2012-09-11 12:30:21 +00:00
|
|
|
return env;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Environment* Environment::DeepCopy() const {
|
|
|
|
Environment* copy =
|
|
|
|
new Environment(values_.length(),
|
|
|
|
fixed_parameter_count_,
|
|
|
|
deopt_id_,
|
2012-09-18 13:41:20 +00:00
|
|
|
function_,
|
2012-09-11 12:30:21 +00:00
|
|
|
(outer_ == NULL) ? NULL : outer_->DeepCopy());
|
|
|
|
for (intptr_t i = 0; i < values_.length(); ++i) {
|
|
|
|
copy->values_.Add(values_[i]->Copy());
|
|
|
|
}
|
|
|
|
return copy;
|
2012-08-17 13:06:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-27 14:16:02 +00:00
|
|
|
// Copies the environment and updates the environment use lists.
|
2012-09-11 12:30:21 +00:00
|
|
|
void Environment::DeepCopyTo(Instruction* instr) const {
|
|
|
|
Environment* copy = DeepCopy();
|
|
|
|
intptr_t use_index = 0;
|
|
|
|
for (Environment::DeepIterator it(copy); !it.Done(); it.Advance()) {
|
|
|
|
Value* value = it.CurrentValue();
|
2012-08-30 09:08:27 +00:00
|
|
|
value->set_instruction(instr);
|
2012-09-11 12:30:21 +00:00
|
|
|
value->set_use_index(use_index++);
|
2012-08-30 09:08:27 +00:00
|
|
|
value->AddToEnvUseList();
|
2012-08-23 08:24:29 +00:00
|
|
|
}
|
2012-08-27 14:16:02 +00:00
|
|
|
instr->set_env(copy);
|
2012-08-23 08:24:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-18 13:41:20 +00:00
|
|
|
// Copies the environment as outer on an inlined instruction and updates the
|
|
|
|
// environment use lists.
|
|
|
|
void Environment::DeepCopyToOuter(Instruction* instr) const {
|
|
|
|
ASSERT(instr->env()->outer() == NULL);
|
2012-09-24 13:01:55 +00:00
|
|
|
// Create a deep copy removing caller arguments from the environment.
|
|
|
|
intptr_t argument_count = instr->env()->fixed_parameter_count();
|
|
|
|
Environment* copy =
|
|
|
|
new Environment(values_.length() - argument_count,
|
|
|
|
fixed_parameter_count_,
|
|
|
|
deopt_id_,
|
|
|
|
function_,
|
|
|
|
(outer_ == NULL) ? NULL : outer_->DeepCopy());
|
|
|
|
for (intptr_t i = 0; i < values_.length() - argument_count; ++i) {
|
|
|
|
copy->values_.Add(values_[i]->Copy());
|
|
|
|
}
|
2012-09-18 13:41:20 +00:00
|
|
|
intptr_t use_index = instr->env()->Length(); // Start index after inner.
|
|
|
|
for (Environment::DeepIterator it(copy); !it.Done(); it.Advance()) {
|
|
|
|
Value* value = it.CurrentValue();
|
|
|
|
value->set_instruction(instr);
|
|
|
|
value->set_use_index(use_index++);
|
|
|
|
value->AddToEnvUseList();
|
|
|
|
}
|
|
|
|
instr->env()->outer_ = copy;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
Fix convergence issues in range analysis.
Split it into three phases: initialization, widening and narrowing.
During widening and narrowing phi-ranges change according to classical widening and narrowing operators defined as:
Widening:
[_|_, _|_] v [a, b] = [a, b]
[a, b] v [c, d] = [c < a ? -inf : a, d > b ? +inf : b]
Narrowing:
[a, b] ^ [c, d] = [(a == -inf) ? c : min(a, c), (b == +inf) ? d : max(b, d)]
R=fschneider@google.com
Review URL: https://codereview.chromium.org//10972003
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@12772 260f80e4-7a28-3924-810f-c04153c831b5
2012-09-24 12:00:19 +00:00
|
|
|
RangeBoundary RangeBoundary::LowerBound() const {
|
|
|
|
if (IsConstant()) return *this;
|
|
|
|
if (symbol()->range() == NULL) return MinSmi();
|
|
|
|
return Add(symbol()->range()->min().LowerBound(),
|
|
|
|
RangeBoundary::FromConstant(offset_),
|
|
|
|
MinSmi());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RangeBoundary RangeBoundary::UpperBound() const {
|
|
|
|
if (IsConstant()) return *this;
|
|
|
|
if (symbol()->range() == NULL) return MaxSmi();
|
|
|
|
return Add(symbol()->range()->max().UpperBound(),
|
|
|
|
RangeBoundary::FromConstant(offset_),
|
|
|
|
MaxSmi());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Definition::InferRange(RangeOperator op) {
|
2012-09-21 20:06:31 +00:00
|
|
|
ASSERT(GetPropagatedCid() == kSmiCid); // Has meaning only for smis.
|
|
|
|
if (range_ == NULL) {
|
|
|
|
range_ = Range::Unknown();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
Fix convergence issues in range analysis.
Split it into three phases: initialization, widening and narrowing.
During widening and narrowing phi-ranges change according to classical widening and narrowing operators defined as:
Widening:
[_|_, _|_] v [a, b] = [a, b]
[a, b] v [c, d] = [c < a ? -inf : a, d > b ? +inf : b]
Narrowing:
[a, b] ^ [c, d] = [(a == -inf) ? c : min(a, c), (b == +inf) ? d : max(b, d)]
R=fschneider@google.com
Review URL: https://codereview.chromium.org//10972003
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@12772 260f80e4-7a28-3924-810f-c04153c831b5
2012-09-24 12:00:19 +00:00
|
|
|
bool ConstantInstr::InferRange(RangeOperator op) {
|
2012-09-21 20:06:31 +00:00
|
|
|
ASSERT(value_.IsSmi());
|
|
|
|
if (range_ == NULL) {
|
|
|
|
intptr_t value = Smi::Cast(value_).Value();
|
|
|
|
range_ = new Range(RangeBoundary::FromConstant(value),
|
|
|
|
RangeBoundary::FromConstant(value));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
Fix convergence issues in range analysis.
Split it into three phases: initialization, widening and narrowing.
During widening and narrowing phi-ranges change according to classical widening and narrowing operators defined as:
Widening:
[_|_, _|_] v [a, b] = [a, b]
[a, b] v [c, d] = [c < a ? -inf : a, d > b ? +inf : b]
Narrowing:
[a, b] ^ [c, d] = [(a == -inf) ? c : min(a, c), (b == +inf) ? d : max(b, d)]
R=fschneider@google.com
Review URL: https://codereview.chromium.org//10972003
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@12772 260f80e4-7a28-3924-810f-c04153c831b5
2012-09-24 12:00:19 +00:00
|
|
|
bool ConstraintInstr::InferRange(RangeOperator op) {
|
2012-09-21 20:06:31 +00:00
|
|
|
Range* value_range = value()->definition()->range();
|
|
|
|
|
|
|
|
// Compute intersection of constraint and value ranges.
|
|
|
|
return Range::Update(&range_,
|
|
|
|
RangeBoundary::Max(Range::ConstantMin(value_range),
|
|
|
|
Range::ConstantMin(constraint())),
|
|
|
|
RangeBoundary::Min(Range::ConstantMax(value_range),
|
|
|
|
Range::ConstantMax(constraint())));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
Fix convergence issues in range analysis.
Split it into three phases: initialization, widening and narrowing.
During widening and narrowing phi-ranges change according to classical widening and narrowing operators defined as:
Widening:
[_|_, _|_] v [a, b] = [a, b]
[a, b] v [c, d] = [c < a ? -inf : a, d > b ? +inf : b]
Narrowing:
[a, b] ^ [c, d] = [(a == -inf) ? c : min(a, c), (b == +inf) ? d : max(b, d)]
R=fschneider@google.com
Review URL: https://codereview.chromium.org//10972003
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@12772 260f80e4-7a28-3924-810f-c04153c831b5
2012-09-24 12:00:19 +00:00
|
|
|
bool PhiInstr::InferRange(RangeOperator op) {
|
2012-09-21 20:06:31 +00:00
|
|
|
RangeBoundary new_min;
|
|
|
|
RangeBoundary new_max;
|
|
|
|
|
|
|
|
for (intptr_t i = 0; i < InputCount(); i++) {
|
|
|
|
Range* input_range = InputAt(i)->definition()->range();
|
|
|
|
if (input_range == NULL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (new_min.IsUnknown()) {
|
|
|
|
new_min = Range::ConstantMin(input_range);
|
|
|
|
} else {
|
|
|
|
new_min = RangeBoundary::Min(new_min, Range::ConstantMin(input_range));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (new_max.IsUnknown()) {
|
|
|
|
new_max = Range::ConstantMax(input_range);
|
|
|
|
} else {
|
|
|
|
new_max = RangeBoundary::Max(new_max, Range::ConstantMax(input_range));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ASSERT(new_min.IsUnknown() == new_max.IsUnknown());
|
|
|
|
if (new_min.IsUnknown()) {
|
Fix convergence issues in range analysis.
Split it into three phases: initialization, widening and narrowing.
During widening and narrowing phi-ranges change according to classical widening and narrowing operators defined as:
Widening:
[_|_, _|_] v [a, b] = [a, b]
[a, b] v [c, d] = [c < a ? -inf : a, d > b ? +inf : b]
Narrowing:
[a, b] ^ [c, d] = [(a == -inf) ? c : min(a, c), (b == +inf) ? d : max(b, d)]
R=fschneider@google.com
Review URL: https://codereview.chromium.org//10972003
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@12772 260f80e4-7a28-3924-810f-c04153c831b5
2012-09-24 12:00:19 +00:00
|
|
|
range_ = Range::Unknown();
|
2012-09-21 20:06:31 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
Fix convergence issues in range analysis.
Split it into three phases: initialization, widening and narrowing.
During widening and narrowing phi-ranges change according to classical widening and narrowing operators defined as:
Widening:
[_|_, _|_] v [a, b] = [a, b]
[a, b] v [c, d] = [c < a ? -inf : a, d > b ? +inf : b]
Narrowing:
[a, b] ^ [c, d] = [(a == -inf) ? c : min(a, c), (b == +inf) ? d : max(b, d)]
R=fschneider@google.com
Review URL: https://codereview.chromium.org//10972003
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@12772 260f80e4-7a28-3924-810f-c04153c831b5
2012-09-24 12:00:19 +00:00
|
|
|
if (op == Definition::kRangeWiden) {
|
|
|
|
// Apply widening operator.
|
2012-09-21 20:06:31 +00:00
|
|
|
new_min = RangeBoundary::WidenMin(range_->min(), new_min);
|
|
|
|
new_max = RangeBoundary::WidenMax(range_->max(), new_max);
|
Fix convergence issues in range analysis.
Split it into three phases: initialization, widening and narrowing.
During widening and narrowing phi-ranges change according to classical widening and narrowing operators defined as:
Widening:
[_|_, _|_] v [a, b] = [a, b]
[a, b] v [c, d] = [c < a ? -inf : a, d > b ? +inf : b]
Narrowing:
[a, b] ^ [c, d] = [(a == -inf) ? c : min(a, c), (b == +inf) ? d : max(b, d)]
R=fschneider@google.com
Review URL: https://codereview.chromium.org//10972003
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@12772 260f80e4-7a28-3924-810f-c04153c831b5
2012-09-24 12:00:19 +00:00
|
|
|
} else if (op == Definition::kRangeNarrow) {
|
|
|
|
// Apply narrowing operator.
|
|
|
|
new_min = RangeBoundary::NarrowMin(range_->min(), new_min);
|
|
|
|
new_max = RangeBoundary::NarrowMax(range_->max(), new_max);
|
2012-09-21 20:06:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return Range::Update(&range_, new_min, new_max);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
Fix convergence issues in range analysis.
Split it into three phases: initialization, widening and narrowing.
During widening and narrowing phi-ranges change according to classical widening and narrowing operators defined as:
Widening:
[_|_, _|_] v [a, b] = [a, b]
[a, b] v [c, d] = [c < a ? -inf : a, d > b ? +inf : b]
Narrowing:
[a, b] ^ [c, d] = [(a == -inf) ? c : min(a, c), (b == +inf) ? d : max(b, d)]
R=fschneider@google.com
Review URL: https://codereview.chromium.org//10972003
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@12772 260f80e4-7a28-3924-810f-c04153c831b5
2012-09-24 12:00:19 +00:00
|
|
|
bool BinarySmiOpInstr::InferRange(RangeOperator op) {
|
2012-09-21 20:06:31 +00:00
|
|
|
Range* left_range = left()->definition()->range();
|
|
|
|
Range* right_range = right()->definition()->range();
|
|
|
|
|
|
|
|
if ((left_range == NULL) || (right_range == NULL)) {
|
|
|
|
return Range::Update(&range_,
|
|
|
|
RangeBoundary::MinSmi(),
|
|
|
|
RangeBoundary::MaxSmi());
|
|
|
|
}
|
|
|
|
|
|
|
|
RangeBoundary new_min;
|
|
|
|
RangeBoundary new_max;
|
|
|
|
switch (op_kind()) {
|
|
|
|
case Token::kADD:
|
|
|
|
new_min =
|
|
|
|
RangeBoundary::Add(Range::ConstantMin(left_range),
|
|
|
|
Range::ConstantMin(right_range),
|
|
|
|
RangeBoundary::OverflowedMinSmi());
|
|
|
|
new_max =
|
|
|
|
RangeBoundary::Add(Range::ConstantMax(left_range),
|
|
|
|
Range::ConstantMax(right_range),
|
|
|
|
RangeBoundary::OverflowedMaxSmi());
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Token::kSUB:
|
|
|
|
new_min =
|
|
|
|
RangeBoundary::Sub(Range::ConstantMin(left_range),
|
|
|
|
Range::ConstantMax(right_range),
|
|
|
|
RangeBoundary::OverflowedMinSmi());
|
|
|
|
new_max =
|
|
|
|
RangeBoundary::Sub(Range::ConstantMax(left_range),
|
|
|
|
Range::ConstantMin(right_range),
|
|
|
|
RangeBoundary::OverflowedMaxSmi());
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
if (range_ == NULL) {
|
|
|
|
range_ = Range::Unknown();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ASSERT(!new_min.IsUnknown() && !new_max.IsUnknown());
|
|
|
|
set_overflow(new_min.Overflowed() || new_max.Overflowed());
|
Fix convergence issues in range analysis.
Split it into three phases: initialization, widening and narrowing.
During widening and narrowing phi-ranges change according to classical widening and narrowing operators defined as:
Widening:
[_|_, _|_] v [a, b] = [a, b]
[a, b] v [c, d] = [c < a ? -inf : a, d > b ? +inf : b]
Narrowing:
[a, b] ^ [c, d] = [(a == -inf) ? c : min(a, c), (b == +inf) ? d : max(b, d)]
R=fschneider@google.com
Review URL: https://codereview.chromium.org//10972003
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@12772 260f80e4-7a28-3924-810f-c04153c831b5
2012-09-24 12:00:19 +00:00
|
|
|
|
|
|
|
if (op == Definition::kRangeNarrow) {
|
|
|
|
new_min = new_min.Clamp();
|
|
|
|
new_max = new_max.Clamp();
|
|
|
|
}
|
|
|
|
|
2012-09-21 20:06:31 +00:00
|
|
|
return Range::Update(&range_, new_min, new_max);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
#undef __
|
2012-05-31 20:38:55 +00:00
|
|
|
|
Initial implementation of a flow-graph builder for Dart's AST.
Visit the AST and generate an instruction (ie, not basic-block) flow
graph.
The flow graph for the simple function:
main() {
var f = 1;
var n = 5;
while (n > 0) {
f = f * n;
n = n - 1;
}
print(f);
}
is:
1: StoreLocal(f, #1)
2: StoreLocal(n, #5)
3: [join]
4: t0 <-LoadLocal(n)
5: t0 <-InstanceCall(>, t0, #0)
6: if t0 goto(7, 15)
7: [target]
8: t0 <-LoadLocal(f)
9: t1 <-LoadLocal(n)
10: t0 <-InstanceCall(*, t0, t1)
11: StoreLocal(f, t0)
12: t0 <-LoadLocal(n)
13: t0 <-InstanceCall(-, t0, #1)
14: StoreLocal(n, t0) goto 3
15: [target]
16: t0 <-LoadLocal(f)
17: StaticCall(print, t0)
18: return #null
BUG=
TEST=
Review URL: https://chromiumcodereview.appspot.com//9414003
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@4460 260f80e4-7a28-3924-810f-c04153c831b5
2012-02-22 15:20:13 +00:00
|
|
|
} // namespace dart
|