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-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"
|
|
|
|
#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"
|
|
|
|
#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"
|
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-02-28 08:58:49 +00:00
|
|
|
// ==== Support for visiting flow graphs.
|
|
|
|
#define DEFINE_ACCEPT(ShortName, ClassName) \
|
2012-05-15 08:55:56 +00:00
|
|
|
void ClassName::Accept(FlowGraphVisitor* visitor) { \
|
|
|
|
visitor->Visit##ShortName(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
|
|
|
|
2012-02-28 08:58:49 +00:00
|
|
|
FOR_EACH_COMPUTATION(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-02-28 08:58:49 +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-05-15 08:55:56 +00:00
|
|
|
#define DEFINE_ACCEPT(ShortName) \
|
|
|
|
Instruction* ShortName##Instr::Accept(FlowGraphVisitor* visitor) { \
|
|
|
|
visitor->Visit##ShortName(this); \
|
|
|
|
return StraightLineSuccessor(); \
|
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-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() {
|
|
|
|
for (intptr_t i = 0; i < block_order_.length(); ++i) {
|
|
|
|
Instruction* current = block_order_[i]->Accept(this);
|
2012-02-23 18:29:58 +00:00
|
|
|
while ((current != NULL) && !current->IsBlockEntry()) {
|
|
|
|
current = current->Accept(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
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-03 08:46:10 +00:00
|
|
|
intptr_t InstanceCallComp::InputCount() const {
|
|
|
|
return ArgumentCount();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
intptr_t StaticCallComp::InputCount() const {
|
|
|
|
return ArgumentCount();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
intptr_t ClosureCallComp::InputCount() const {
|
2012-05-21 17:59:02 +00:00
|
|
|
return ArgumentCount();
|
2012-05-03 08:46:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
intptr_t AllocateObjectComp::InputCount() const {
|
|
|
|
return arguments().length();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
intptr_t AllocateObjectWithBoundsCheckComp::InputCount() const {
|
|
|
|
return arguments().length();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
intptr_t CreateArrayComp::InputCount() const {
|
2012-05-04 16:36:27 +00:00
|
|
|
return ElementCount() + 1;
|
2012-05-03 08:46:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
intptr_t BranchInstr::InputCount() const {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
intptr_t ReThrowInstr::InputCount() const {
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
intptr_t ThrowInstr::InputCount() const {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
intptr_t ReturnInstr::InputCount() const {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
intptr_t BindInstr::InputCount() const {
|
|
|
|
return computation()->InputCount();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
intptr_t DoInstr::InputCount() const {
|
|
|
|
return computation()->InputCount();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-16 12:10:02 +00:00
|
|
|
intptr_t GraphEntryInstr::InputCount() const {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-03 08:46:10 +00:00
|
|
|
intptr_t TargetEntryInstr::InputCount() const {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
intptr_t JoinEntryInstr::InputCount() const {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-16 13:28:02 +00:00
|
|
|
// ==== Recording assigned variables.
|
|
|
|
void Computation::RecordAssignedVars(BitVector* assigned_vars) {
|
|
|
|
// Nothing to do for the base class.
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void StoreLocalComp::RecordAssignedVars(BitVector* assigned_vars) {
|
|
|
|
if (!local().is_captured()) {
|
|
|
|
assigned_vars->Add(local().BitIndexIn(assigned_vars));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Instruction::RecordAssignedVars(BitVector* assigned_vars) {
|
|
|
|
// Nothing to do for the base class.
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DoInstr::RecordAssignedVars(BitVector* assigned_vars) {
|
|
|
|
computation()->RecordAssignedVars(assigned_vars);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void BindInstr::RecordAssignedVars(BitVector* assigned_vars) {
|
|
|
|
computation()->RecordAssignedVars(assigned_vars);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-02-23 18:29:58 +00:00
|
|
|
// ==== Postorder graph traversal.
|
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,
|
|
|
|
intptr_t variable_count) {
|
2012-05-16 12:10:02 +00:00
|
|
|
// We only visit this block once, first of all blocks.
|
|
|
|
ASSERT(preorder_number() == -1);
|
|
|
|
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,
|
|
|
|
parent, assigned_vars, variable_count);
|
2012-05-16 12:10:02 +00:00
|
|
|
}
|
2012-05-18 01:04:56 +00:00
|
|
|
normal_entry_->DiscoverBlocks(this, preorder, postorder,
|
|
|
|
parent, assigned_vars, variable_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,
|
|
|
|
intptr_t variable_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());
|
|
|
|
|
|
|
|
// 1. Record control-flow-graph basic-block predecessors.
|
2012-05-16 13:28:02 +00:00
|
|
|
AddPredecessor(current_block);
|
2012-03-19 19:39:14 +00:00
|
|
|
|
2012-05-16 13:28:02 +00:00
|
|
|
// 2. If the block has already been reached by the traversal, we are
|
|
|
|
// done. Blocks with a single predecessor cannot have been reached
|
|
|
|
// before.
|
|
|
|
ASSERT(!IsTargetEntry() || (preorder_number() == -1));
|
2012-03-16 22:20:04 +00:00
|
|
|
if (preorder_number() >= 0) return;
|
2012-03-19 19:39:14 +00:00
|
|
|
|
|
|
|
// 3. The last entry in the preorder array is the spanning-tree parent.
|
2012-03-21 23:45:20 +00:00
|
|
|
intptr_t parent_number = preorder->length() - 1;
|
|
|
|
parent->Add(parent_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-03-21 23:45:20 +00:00
|
|
|
set_preorder_number(parent_number + 1);
|
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-05-16 13:28:02 +00:00
|
|
|
ASSERT(StraightLineSuccessor() != NULL);
|
|
|
|
Instruction* next = StraightLineSuccessor();
|
|
|
|
if (next->IsBlockEntry()) {
|
|
|
|
set_last_instruction(this);
|
|
|
|
} else {
|
|
|
|
while ((next != NULL) && !next->IsBlockEntry() && !next->IsBranch()) {
|
|
|
|
if (vars != NULL) next->RecordAssignedVars(vars);
|
|
|
|
set_last_instruction(next);
|
|
|
|
next = next->StraightLineSuccessor();
|
|
|
|
}
|
2012-03-19 21:57:06 +00:00
|
|
|
}
|
|
|
|
if (next != NULL) {
|
2012-05-18 01:04:56 +00:00
|
|
|
next->DiscoverBlocks(this, preorder, postorder,
|
|
|
|
parent, assigned_vars, variable_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-03-19 19:39:14 +00:00
|
|
|
void BranchInstr::DiscoverBlocks(
|
|
|
|
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,
|
|
|
|
intptr_t variable_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,
|
|
|
|
parent, assigned_vars, variable_count);
|
|
|
|
true_successor_->DiscoverBlocks(current_block, preorder, postorder,
|
|
|
|
parent, assigned_vars, variable_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-06 11:09:02 +00:00
|
|
|
intptr_t Instruction::SuccessorCount() const {
|
|
|
|
ASSERT(!IsBranch());
|
|
|
|
ASSERT(!IsGraphEntry());
|
|
|
|
ASSERT(StraightLineSuccessor() == NULL ||
|
|
|
|
StraightLineSuccessor()->IsBlockEntry());
|
|
|
|
return StraightLineSuccessor() != NULL ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BlockEntryInstr* Instruction::SuccessorAt(intptr_t index) const {
|
|
|
|
return StraightLineSuccessor()->AsBlockEntry();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
intptr_t BranchInstr::SuccessorCount() const {
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BlockEntryInstr* BranchInstr::SuccessorAt(intptr_t index) const {
|
|
|
|
if (index == 0) return true_successor_;
|
|
|
|
if (index == 1) return false_successor_;
|
|
|
|
UNREACHABLE();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-16 23:21:24 +00:00
|
|
|
// ==== Support for propagating static type.
|
|
|
|
RawAbstractType* ConstantVal::StaticType() const {
|
|
|
|
if (value().IsInstance()) {
|
|
|
|
Instance& instance = Instance::Handle();
|
|
|
|
instance ^= value().raw();
|
|
|
|
return instance.GetType();
|
|
|
|
} else {
|
|
|
|
UNREACHABLE();
|
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* UseVal::StaticType() const {
|
|
|
|
return definition()->StaticType();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* AssertAssignableComp::StaticType() const {
|
|
|
|
return dst_type().raw();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* AssertBooleanComp::StaticType() const {
|
|
|
|
return Type::BoolInterface();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* CurrentContextComp::StaticType() const {
|
|
|
|
UNREACHABLE();
|
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* StoreContextComp::StaticType() const {
|
|
|
|
UNREACHABLE();
|
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* ClosureCallComp::StaticType() const {
|
|
|
|
// The closure is the first argument to the call.
|
|
|
|
const AbstractType& function_type =
|
|
|
|
AbstractType::Handle(ArgumentAt(0)->StaticType());
|
|
|
|
if (function_type.IsDynamicType() || function_type.IsFunctionInterface()) {
|
|
|
|
// The function type is not statically known or simply Function.
|
|
|
|
return Type::DynamicType();
|
|
|
|
}
|
|
|
|
const Class& signature_class = Class::Handle(function_type.type_class());
|
|
|
|
ASSERT(signature_class.IsSignatureClass());
|
|
|
|
const Function& signature_function =
|
|
|
|
Function::Handle(signature_class.signature_function());
|
2012-05-17 18:47:45 +00:00
|
|
|
// TODO(regis): The result type may be generic. Consider upper bounds.
|
2012-05-16 23:21:24 +00:00
|
|
|
return signature_function.result_type();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* InstanceCallComp::StaticType() const {
|
|
|
|
return Type::DynamicType();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* StaticCallComp::StaticType() const {
|
|
|
|
return function().result_type();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* LoadLocalComp::StaticType() const {
|
|
|
|
return local().type().raw();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* StoreLocalComp::StaticType() const {
|
|
|
|
const AbstractType& assigned_value_type =
|
|
|
|
AbstractType::Handle(value()->StaticType());
|
|
|
|
if (assigned_value_type.IsDynamicType()) {
|
|
|
|
// Static type of assigned value is unknown, return static type of local.
|
|
|
|
return local().type().raw();
|
|
|
|
}
|
|
|
|
return assigned_value_type.raw();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* StrictCompareComp::StaticType() const {
|
|
|
|
return Type::BoolInterface();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* EqualityCompareComp::StaticType() const {
|
|
|
|
return Type::BoolInterface();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* NativeCallComp::StaticType() const {
|
|
|
|
// 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();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* StoreIndexedComp::StaticType() const {
|
2012-05-30 15:55:46 +00:00
|
|
|
UNREACHABLE();
|
|
|
|
return AbstractType::null();
|
2012-05-16 23:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* InstanceSetterComp::StaticType() const {
|
2012-05-17 18:47:45 +00:00
|
|
|
return value()->StaticType();
|
2012-05-16 23:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* StaticSetterComp::StaticType() const {
|
2012-05-17 18:47:45 +00:00
|
|
|
const AbstractType& assigned_value_type =
|
|
|
|
AbstractType::Handle(value()->StaticType());
|
|
|
|
if (assigned_value_type.IsDynamicType()) {
|
|
|
|
// Static type of assigned value is unknown, return static type of setter
|
|
|
|
// value parameter.
|
|
|
|
return setter_function().ParameterTypeAt(0);
|
|
|
|
}
|
|
|
|
return assigned_value_type.raw();
|
2012-05-16 23:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* LoadInstanceFieldComp::StaticType() const {
|
|
|
|
return field().type();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* StoreInstanceFieldComp::StaticType() const {
|
|
|
|
const AbstractType& assigned_value_type =
|
|
|
|
AbstractType::Handle(value()->StaticType());
|
|
|
|
if (assigned_value_type.IsDynamicType()) {
|
|
|
|
// Static type of assigned value is unknown, return static type of field.
|
|
|
|
return field().type();
|
|
|
|
}
|
|
|
|
return assigned_value_type.raw();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* LoadStaticFieldComp::StaticType() const {
|
|
|
|
return field().type();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* StoreStaticFieldComp::StaticType() const {
|
|
|
|
const AbstractType& assigned_value_type =
|
|
|
|
AbstractType::Handle(value()->StaticType());
|
|
|
|
if (assigned_value_type.IsDynamicType()) {
|
|
|
|
// Static type of assigned value is unknown, return static type of field.
|
|
|
|
return field().type();
|
|
|
|
}
|
|
|
|
return assigned_value_type.raw();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* BooleanNegateComp::StaticType() const {
|
|
|
|
return Type::BoolInterface();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* InstanceOfComp::StaticType() const {
|
|
|
|
return Type::BoolInterface();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* CreateArrayComp::StaticType() const {
|
|
|
|
UNREACHABLE();
|
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* CreateClosureComp::StaticType() const {
|
|
|
|
const Function& fun = function();
|
|
|
|
const Class& signature_class = Class::Handle(fun.signature_class());
|
2012-05-17 18:47:45 +00:00
|
|
|
// TODO(regis): The signature type may be generic. Consider upper bounds.
|
2012-05-16 23:21:24 +00:00
|
|
|
// For now, we return Dynamic (no type test elimination) if the signature
|
|
|
|
// class is parameterized, or a non-parameterized finalized type otherwise.
|
|
|
|
if (signature_class.HasTypeArguments()) {
|
|
|
|
return Type::DynamicType();
|
|
|
|
}
|
|
|
|
// Make sure we use the canonical signature class.
|
|
|
|
const Type& type = Type::Handle(signature_class.SignatureType());
|
|
|
|
const Class& canonical_signature_class = Class::Handle(type.type_class());
|
|
|
|
return Type::NewNonParameterizedType(canonical_signature_class);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* AllocateObjectComp::StaticType() const {
|
|
|
|
UNREACHABLE();
|
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* AllocateObjectWithBoundsCheckComp::StaticType() const {
|
|
|
|
UNREACHABLE();
|
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-24 01:13:04 +00:00
|
|
|
RawAbstractType* LoadVMFieldComp::StaticType() const {
|
2012-05-16 23:21:24 +00:00
|
|
|
ASSERT(!type().IsNull());
|
|
|
|
return type().raw();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-24 01:13:04 +00:00
|
|
|
RawAbstractType* StoreVMFieldComp::StaticType() const {
|
2012-05-17 18:47:45 +00:00
|
|
|
ASSERT(!type().IsNull());
|
|
|
|
const AbstractType& assigned_value_type =
|
|
|
|
AbstractType::Handle(value()->StaticType());
|
|
|
|
if (assigned_value_type.IsDynamicType()) {
|
|
|
|
// Static type of assigned value is unknown, return static type of field.
|
|
|
|
return type().raw();
|
|
|
|
}
|
|
|
|
return assigned_value_type.raw();
|
2012-05-16 23:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* InstantiateTypeArgumentsComp::StaticType() const {
|
|
|
|
UNREACHABLE();
|
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* ExtractConstructorTypeArgumentsComp::StaticType() const {
|
|
|
|
UNREACHABLE();
|
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* ExtractConstructorInstantiatorComp::StaticType() const {
|
|
|
|
UNREACHABLE();
|
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* AllocateContextComp::StaticType() const {
|
|
|
|
UNREACHABLE();
|
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* ChainContextComp::StaticType() const {
|
|
|
|
UNREACHABLE();
|
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* CloneContextComp::StaticType() const {
|
|
|
|
UNREACHABLE();
|
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* CatchEntryComp::StaticType() const {
|
|
|
|
UNREACHABLE();
|
|
|
|
return AbstractType::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-24 16:50:57 +00:00
|
|
|
RawAbstractType* BinaryOpComp::StaticType() const {
|
|
|
|
// TODO(srdjan): Compute based on input types (ICData).
|
|
|
|
return Type::DynamicType();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-31 20:38:55 +00:00
|
|
|
RawAbstractType* UnarySmiOpComp::StaticType() const {
|
|
|
|
return Type::IntInterface();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawAbstractType* NumberNegateComp::StaticType() const {
|
|
|
|
return Type::NumberInterface();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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
|
|
|
// 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
|
|
|
|
|
|
|
|
|
|
|
|
// True iff. the arguments to a call will be properly pushed and can
|
|
|
|
// be popped after the call.
|
|
|
|
template <typename T> static bool VerifyCallComputation(T* comp) {
|
|
|
|
// Argument values should be consecutive temps.
|
|
|
|
//
|
|
|
|
// TODO(kmillikin): implement stack height tracking so we can also assert
|
|
|
|
// they are on top of the stack.
|
|
|
|
intptr_t previous = -1;
|
|
|
|
for (int i = 0; i < comp->ArgumentCount(); ++i) {
|
|
|
|
Value* val = comp->ArgumentAt(i);
|
|
|
|
if (!val->IsUse()) return false;
|
|
|
|
intptr_t current = val->AsUse()->definition()->temp_index();
|
|
|
|
if (i != 0) {
|
|
|
|
if (current != (previous + 1)) return false;
|
|
|
|
}
|
|
|
|
previous = current;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Truee iff. the v2 is above v1 on stack, or one of them is constant.
|
|
|
|
static bool VerifyValues(Value* v1, Value* v2) {
|
|
|
|
ASSERT(v1->IsUse() && v2->IsUse());
|
|
|
|
return (v1->AsUse()->definition()->temp_index() + 1) ==
|
|
|
|
v2->AsUse()->definition()->temp_index();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define __ compiler->assembler()->
|
|
|
|
|
|
|
|
void GraphEntryInstr::PrepareEntry(FlowGraphCompiler* compiler) {
|
|
|
|
// Nothing to do.
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void JoinEntryInstr::PrepareEntry(FlowGraphCompiler* compiler) {
|
|
|
|
__ Bind(compiler->GetBlockLabel(this));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TargetEntryInstr::PrepareEntry(FlowGraphCompiler* compiler) {
|
|
|
|
__ Bind(compiler->GetBlockLabel(this));
|
|
|
|
if (HasTryIndex()) {
|
|
|
|
compiler->AddExceptionHandler(try_index(),
|
|
|
|
compiler->assembler()->CodeSize());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* ThrowInstr::MakeLocationSummary() const {
|
|
|
|
const int kNumInputs = 0;
|
|
|
|
const int kNumTemps = 0;
|
|
|
|
return new LocationSummary(kNumInputs, kNumTemps);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ThrowInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
ASSERT(exception()->IsUse());
|
|
|
|
compiler->GenerateCallRuntime(cid(),
|
|
|
|
token_index(),
|
|
|
|
try_index(),
|
|
|
|
kThrowRuntimeEntry);
|
|
|
|
__ int3();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* ReThrowInstr::MakeLocationSummary() const {
|
|
|
|
const int kNumInputs = 0;
|
|
|
|
const int kNumTemps = 0;
|
|
|
|
return new LocationSummary(kNumInputs, kNumTemps);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ReThrowInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
ASSERT(exception()->IsUse());
|
|
|
|
ASSERT(stack_trace()->IsUse());
|
|
|
|
compiler->GenerateCallRuntime(cid(),
|
|
|
|
token_index(),
|
|
|
|
try_index(),
|
|
|
|
kReThrowRuntimeEntry);
|
|
|
|
__ int3();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* BranchInstr::MakeLocationSummary() const {
|
|
|
|
const int kNumInputs = 1;
|
|
|
|
const int kNumTemps = 0;
|
|
|
|
LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps);
|
|
|
|
locs->set_in(0, Location::RequiresRegister());
|
|
|
|
return locs;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
Register value = locs()->in(0).reg();
|
|
|
|
__ CompareObject(value, Bool::ZoneHandle(Bool::True()));
|
|
|
|
if (compiler->IsNextBlock(false_successor())) {
|
|
|
|
// If the next block is the false successor we will fall through to it if
|
|
|
|
// comparison with true fails.
|
|
|
|
__ j(EQUAL, compiler->GetBlockLabel(true_successor()));
|
|
|
|
} else {
|
|
|
|
ASSERT(compiler->IsNextBlock(true_successor()));
|
|
|
|
// If the next block is the true successor we negate comparison and fall
|
|
|
|
// through to it.
|
|
|
|
__ j(NOT_EQUAL, compiler->GetBlockLabel(false_successor()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* CurrentContextComp::MakeLocationSummary() const {
|
|
|
|
return LocationSummary::Make(0, Location::RequiresRegister());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CurrentContextComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
__ MoveRegister(locs()->out().reg(), CTX);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* StoreContextComp::MakeLocationSummary() const {
|
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
|
|
|
LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps);
|
|
|
|
summary->set_in(0, Location::RegisterLocation(CTX));
|
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void StoreContextComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
// Nothing to do. Context register were loaded by register allocator.
|
|
|
|
ASSERT(locs()->in(0).reg() == CTX);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* StrictCompareComp::MakeLocationSummary() const {
|
|
|
|
return LocationSummary::Make(2, Location::SameAsFirstInput());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void StrictCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
const Bool& bool_true = Bool::ZoneHandle(Bool::True());
|
|
|
|
const Bool& bool_false = Bool::ZoneHandle(Bool::False());
|
|
|
|
|
|
|
|
Register left = locs()->in(0).reg();
|
|
|
|
Register right = locs()->in(1).reg();
|
|
|
|
Register result = locs()->out().reg();
|
|
|
|
|
|
|
|
__ CompareRegisters(left, right);
|
|
|
|
Label load_true, done;
|
|
|
|
if (kind() == Token::kEQ_STRICT) {
|
|
|
|
__ j(EQUAL, &load_true, Assembler::kNearJump);
|
|
|
|
} else {
|
|
|
|
ASSERT(kind() == Token::kNE_STRICT);
|
|
|
|
__ j(NOT_EQUAL, &load_true, Assembler::kNearJump);
|
|
|
|
}
|
|
|
|
__ LoadObject(result, bool_false);
|
|
|
|
__ jmp(&done, Assembler::kNearJump);
|
|
|
|
__ Bind(&load_true);
|
|
|
|
__ LoadObject(result, bool_true);
|
|
|
|
__ Bind(&done);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ClosureCallComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
ASSERT(VerifyCallComputation(this));
|
|
|
|
// 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 =
|
|
|
|
CodeGenerator::ArgumentsDescriptor(argument_count - 1,
|
|
|
|
argument_names());
|
|
|
|
__ LoadObject(temp_reg, arguments_descriptor);
|
|
|
|
|
|
|
|
compiler->GenerateCall(token_index(),
|
|
|
|
try_index(),
|
|
|
|
&StubCode::CallClosureFunctionLabel(),
|
|
|
|
PcDescriptors::kOther);
|
|
|
|
__ Drop(argument_count);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* InstanceCallComp::MakeLocationSummary() const {
|
|
|
|
return MakeCallSummary();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void InstanceCallComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
ASSERT(VerifyCallComputation(this));
|
|
|
|
compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
|
|
|
|
cid(),
|
|
|
|
token_index(),
|
|
|
|
try_index());
|
|
|
|
compiler->GenerateInstanceCall(cid(),
|
|
|
|
token_index(),
|
|
|
|
try_index(),
|
|
|
|
function_name(),
|
|
|
|
ArgumentCount(),
|
|
|
|
argument_names(),
|
|
|
|
checked_argument_count());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* StaticCallComp::MakeLocationSummary() const {
|
|
|
|
return MakeCallSummary();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void StaticCallComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
ASSERT(VerifyCallComputation(this));
|
|
|
|
compiler->GenerateStaticCall(cid(),
|
|
|
|
token_index(),
|
|
|
|
try_index(),
|
|
|
|
function(),
|
|
|
|
ArgumentCount(),
|
|
|
|
argument_names());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* UseVal::MakeLocationSummary() const {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UseVal::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AssertAssignableComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
compiler->GenerateAssertAssignable(cid(),
|
|
|
|
token_index(),
|
|
|
|
try_index(),
|
|
|
|
dst_type(),
|
|
|
|
dst_name());
|
|
|
|
ASSERT(locs()->in(0).reg() == locs()->out().reg());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* AssertBooleanComp::MakeLocationSummary() const {
|
|
|
|
return LocationSummary::Make(1, Location::SameAsFirstInput());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* StoreInstanceFieldComp::MakeLocationSummary() const {
|
|
|
|
return LocationSummary::Make(2, Location::RequiresRegister());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void StoreInstanceFieldComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
ASSERT(VerifyValues(instance(), value()));
|
|
|
|
Register instance = locs()->in(0).reg();
|
|
|
|
Register value = locs()->in(1).reg();
|
|
|
|
Register result = locs()->out().reg();
|
|
|
|
|
|
|
|
__ StoreIntoObject(instance, FieldAddress(instance, field().Offset()),
|
|
|
|
value);
|
|
|
|
// TODO(fschneider): Consider eliminating this move by specifying a
|
|
|
|
// SameAsSecondInput for the result.
|
|
|
|
__ MoveRegister(result, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* StoreStaticFieldComp::MakeLocationSummary() const {
|
|
|
|
LocationSummary* locs = new LocationSummary(1, 1);
|
|
|
|
locs->set_in(0, Location::RequiresRegister());
|
|
|
|
locs->set_temp(0, Location::RequiresRegister());
|
|
|
|
locs->set_out(Location::SameAsFirstInput());
|
|
|
|
return locs;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void StoreStaticFieldComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
Register value = locs()->in(0).reg();
|
|
|
|
Register temp = locs()->temp(0).reg();
|
|
|
|
ASSERT(locs()->out().reg() == value);
|
|
|
|
|
|
|
|
__ LoadObject(temp, field());
|
|
|
|
__ StoreIntoObject(temp, FieldAddress(temp, Field::value_offset()), value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* BooleanNegateComp::MakeLocationSummary() const {
|
|
|
|
return LocationSummary::Make(1, Location::RequiresRegister());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void BooleanNegateComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
Register value = locs()->in(0).reg();
|
|
|
|
Register result = locs()->out().reg();
|
|
|
|
|
|
|
|
const Bool& bool_true = Bool::ZoneHandle(Bool::True());
|
|
|
|
const Bool& bool_false = Bool::ZoneHandle(Bool::False());
|
|
|
|
Label done;
|
|
|
|
__ LoadObject(result, bool_true);
|
|
|
|
__ CompareRegisters(result, value);
|
|
|
|
__ j(NOT_EQUAL, &done, Assembler::kNearJump);
|
|
|
|
__ LoadObject(result, bool_false);
|
|
|
|
__ Bind(&done);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* ChainContextComp::MakeLocationSummary() const {
|
|
|
|
return LocationSummary::Make(1, Location::NoLocation());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ChainContextComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* StoreVMFieldComp::MakeLocationSummary() const {
|
|
|
|
return LocationSummary::Make(2, Location::SameAsFirstInput());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void StoreVMFieldComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
Register value_reg = locs()->in(0).reg();
|
|
|
|
Register dest_reg = locs()->in(1).reg();
|
|
|
|
ASSERT(value_reg == locs()->out().reg());
|
|
|
|
|
|
|
|
__ StoreIntoObject(dest_reg, FieldAddress(dest_reg, offset_in_bytes()),
|
|
|
|
value_reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* AllocateObjectComp::MakeLocationSummary() const {
|
|
|
|
return MakeCallSummary();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AllocateObjectComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
const Class& cls = Class::ZoneHandle(constructor().owner());
|
|
|
|
const Code& stub = Code::Handle(StubCode::GetAllocationStubForClass(cls));
|
|
|
|
const ExternalLabel label(cls.ToCString(), stub.EntryPoint());
|
|
|
|
compiler->GenerateCall(token_index(),
|
|
|
|
try_index(),
|
|
|
|
&label,
|
|
|
|
PcDescriptors::kOther);
|
|
|
|
__ Drop(arguments().length()); // Discard arguments.
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* CreateClosureComp::MakeLocationSummary() const {
|
|
|
|
return MakeCallSummary();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CreateClosureComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
const Function& closure_function = function();
|
|
|
|
const Code& stub = Code::Handle(
|
|
|
|
StubCode::GetAllocationStubForClosure(closure_function));
|
|
|
|
const ExternalLabel label(closure_function.ToCString(), stub.EntryPoint());
|
|
|
|
compiler->GenerateCall(token_index(), try_index(), &label,
|
|
|
|
PcDescriptors::kOther);
|
|
|
|
__ Drop(2); // Discard type arguments and receiver.
|
|
|
|
}
|
|
|
|
|
|
|
|
#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
|