[vm/compiler] Tweaks and additions to IL serializer/S-expressions.
* Add a new `SExpDouble` atom and change `SExpNumber` to `SExpInteger`. * Allow for negative integers in deserialization. * Add support for `LocalVariable`s and related instructions. * Function objects are now represented by actual S-expressions generated with the new `FunctionToSExp` method. Previously, they were only represented by a symbol containing their canonical name. * The top-level tag for a serialized flow graph is now `FlowGraph`, not `function`. This avoids confusion between serialized flow graphs and serialized function references. Similarly, the old `FunctionToSExp` method is now called `FlowGraphToSExp`. * Made all SExpression* returning functions that take Object (or subclass) instances return nullptr if the passed in instance is the null object, except for ObjectToSExp, which returns the symbol `null`. * Factored out creating tags for the different kind of block/function entry and also created an `Entries` section to the top-level `FlowGraph` form that contains function entry points similar to the `Constants` one instead of inlining entries as separate elements in the `FlowGraph` form. * Additional extra information in verbose mode for some elements. Bug: https://github.com/dart-lang/sdk/issues/36882 Change-Id: Iede3865ec64f81955a87fd57b10e74d49ee8414c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/110917 Commit-Queue: Teagan Strickland <sstrickl@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
2875b1bcce
commit
2e197ae4de
@@ -1295,6 +1295,7 @@ class BlockEntryInstr : public Instruction {
|
||||
|
||||
TO_S_EXPRESSION_SUPPORT
|
||||
ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
|
||||
ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
|
||||
|
||||
protected:
|
||||
BlockEntryInstr(intptr_t block_id, intptr_t try_index, intptr_t deopt_id)
|
||||
@@ -4148,6 +4149,7 @@ class LoadLocalInstr : public TemplateDefinition<0, NoThrow> {
|
||||
virtual TokenPosition token_pos() const { return token_pos_; }
|
||||
|
||||
PRINT_OPERANDS_TO_SUPPORT
|
||||
ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
|
||||
|
||||
private:
|
||||
const LocalVariable& local_;
|
||||
@@ -4281,6 +4283,7 @@ class StoreLocalInstr : public TemplateDefinition<1, NoThrow> {
|
||||
virtual TokenPosition token_pos() const { return token_pos_; }
|
||||
|
||||
PRINT_OPERANDS_TO_SUPPORT
|
||||
ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
|
||||
|
||||
private:
|
||||
const LocalVariable& local_;
|
||||
|
||||
@@ -8,10 +8,20 @@
|
||||
|
||||
#include <ctype.h>
|
||||
#include "platform/utils.h"
|
||||
#include "vm/double_conversion.h"
|
||||
#include "vm/object.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
const char* const SExpParser::kBoolTrueSymbol = "true";
|
||||
const char* const SExpParser::kBoolFalseSymbol = "false";
|
||||
char const SExpParser::kDoubleExponentChar =
|
||||
DoubleToStringConstants::kExponentChar;
|
||||
const char* const SExpParser::kDoubleInfinitySymbol =
|
||||
DoubleToStringConstants::kInfinitySymbol;
|
||||
const char* const SExpParser::kDoubleNaNSymbol =
|
||||
DoubleToStringConstants::kNaNSymbol;
|
||||
|
||||
const char* const SExpParser::ErrorStrings::kOpenString =
|
||||
"unterminated quoted string starting at position %" Pd "";
|
||||
const char* const SExpParser::ErrorStrings::kBadUnicodeEscape =
|
||||
@@ -153,7 +163,8 @@ SExpression* SExpParser::Parse() {
|
||||
break;
|
||||
}
|
||||
case kBoolean:
|
||||
case kNumber:
|
||||
case kInteger:
|
||||
case kDouble:
|
||||
case kQuotedString: {
|
||||
auto sexp = TokenToSExpression(token);
|
||||
// TokenToSExpression has already set the error info, so just return.
|
||||
@@ -190,15 +201,25 @@ SExpression* SExpParser::TokenToSExpression(Token* token) {
|
||||
switch (token->type()) {
|
||||
case kSymbol:
|
||||
return new (zone_) SExpSymbol(token->ToCString(zone_), start_pos);
|
||||
case kNumber: {
|
||||
case kInteger: {
|
||||
const char* cstr = token->ToCString(zone_);
|
||||
int64_t val;
|
||||
if (!OS::StringToInt64(cstr, &val)) return nullptr;
|
||||
return new (zone_) SExpInteger(val, start_pos);
|
||||
}
|
||||
case kBoolean: {
|
||||
const char* cstr = token->ToCString(zone_);
|
||||
return new (zone_) SExpBool(strcmp(cstr, "true") == 0, start_pos);
|
||||
const bool is_true =
|
||||
strncmp(token->cstr(), kBoolTrueSymbol, token->length()) == 0;
|
||||
ASSERT(is_true ||
|
||||
strncmp(token->cstr(), kBoolFalseSymbol, token->length()) == 0);
|
||||
return new (zone_) SExpBool(is_true, start_pos);
|
||||
}
|
||||
case kDouble: {
|
||||
double val;
|
||||
if (!CStringToDouble(token->cstr(), token->length(), &val)) {
|
||||
return nullptr;
|
||||
}
|
||||
return new (zone_) SExpDouble(val, start_pos);
|
||||
}
|
||||
case kQuotedString: {
|
||||
const char* const cstr = token->cstr();
|
||||
@@ -322,27 +343,69 @@ SExpParser::Token* SExpParser::GetNextToken() {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (isdigit(*start)) {
|
||||
intptr_t len = 1;
|
||||
while (start_pos + len < buffer_size_) {
|
||||
if (!isdigit(start[len])) break;
|
||||
len++;
|
||||
intptr_t len = 0;
|
||||
// Start number detection after possible negation sign.
|
||||
if (start[len] == '-') {
|
||||
len++;
|
||||
if ((start_pos + len) >= buffer_size_) {
|
||||
cur_pos_ = start_pos + len;
|
||||
return new (zone_) Token(kSymbol, start, len);
|
||||
}
|
||||
cur_pos_ = start_pos + len;
|
||||
return new (zone_) Token(kNumber, start, len);
|
||||
}
|
||||
intptr_t len = 1;
|
||||
while (start_pos + len < buffer_size_) {
|
||||
// Keep the currently detected token type. Start off by assuming we have
|
||||
// an integer, then fall back to doubles if we see parts appropriate for
|
||||
// those but not integers, and fall back to symbols otherwise.
|
||||
TokenType type = kInteger;
|
||||
bool saw_exponent = false;
|
||||
while ((start_pos + len) < buffer_size_) {
|
||||
// Both numbers and symbols cannot contain these values, so we are at the
|
||||
// end of whichever one we're in.
|
||||
if (!IsSymbolContinue(start[len])) break;
|
||||
if (type == kInteger && start[len] == '.') {
|
||||
type = kDouble;
|
||||
len++;
|
||||
continue;
|
||||
}
|
||||
if (type != kSymbol && !saw_exponent && start[len] == kDoubleExponentChar) {
|
||||
saw_exponent = true;
|
||||
type = kDouble;
|
||||
len++;
|
||||
// Skip past negation in exponent if any.
|
||||
if ((start_pos + len) < buffer_size_ && start[len] == '-') len++;
|
||||
continue;
|
||||
}
|
||||
// If we find a character that can't appear in a number, then fall back
|
||||
// to symbol-ness.
|
||||
if (!isdigit(start[len])) type = kSymbol;
|
||||
len++;
|
||||
}
|
||||
cur_pos_ = start_pos + len;
|
||||
if (len == 4 && strncmp(start, "true", 4) == 0) {
|
||||
return new (zone_) Token(kBoolean, start, len);
|
||||
} else if (len == 5 && strncmp(start, "false", 5) == 0) {
|
||||
return new (zone_) Token(kBoolean, start, len);
|
||||
// Skip special symbol detection if we don't have a symbol.
|
||||
if (type != kSymbol) return new (zone_) Token(type, start, len);
|
||||
// Check for special symbols used for booleans and certain Double values.
|
||||
switch (len) {
|
||||
case 3:
|
||||
if (strncmp(start, kDoubleNaNSymbol, len) == 0) type = kDouble;
|
||||
break;
|
||||
case 4:
|
||||
if (strncmp(start, kBoolTrueSymbol, len) == 0) type = kBoolean;
|
||||
break;
|
||||
case 5:
|
||||
if (strncmp(start, kBoolFalseSymbol, len) == 0) type = kBoolean;
|
||||
break;
|
||||
case 8:
|
||||
if (strncmp(start, kDoubleInfinitySymbol, len) == 0) type = kDouble;
|
||||
break;
|
||||
case 9:
|
||||
if (start[0] == '-' &&
|
||||
strncmp(start + 1, kDoubleInfinitySymbol, len - 1) == 0) {
|
||||
type = kDouble;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return new (zone_) Token(kSymbol, start, len);
|
||||
return new (zone_) Token(type, start, len);
|
||||
}
|
||||
|
||||
bool SExpParser::IsSymbolContinue(char c) {
|
||||
|
||||
@@ -28,6 +28,13 @@ class SExpParser : public ValueObject {
|
||||
cur_label_stack_(zone, 2),
|
||||
error_message_(nullptr) {}
|
||||
|
||||
// Constants used in serializing and deserializing S-expressions.
|
||||
static const char* const kBoolTrueSymbol;
|
||||
static const char* const kBoolFalseSymbol;
|
||||
static char const kDoubleExponentChar;
|
||||
static const char* const kDoubleInfinitySymbol;
|
||||
static const char* const kDoubleNaNSymbol;
|
||||
|
||||
struct ErrorStrings : AllStatic {
|
||||
static const char* const kOpenString;
|
||||
static const char* const kBadUnicodeEscape;
|
||||
@@ -59,7 +66,8 @@ class SExpParser : public ValueObject {
|
||||
M(LeftCurly) \
|
||||
M(RightCurly) \
|
||||
M(QuotedString) \
|
||||
M(Number) \
|
||||
M(Integer) \
|
||||
M(Double) \
|
||||
M(Boolean) \
|
||||
M(Symbol)
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "vm/compiler/backend/il_deserializer.h"
|
||||
#include "vm/compiler/backend/il_serializer.h"
|
||||
|
||||
#include <cmath>
|
||||
#include "platform/assert.h"
|
||||
#include "vm/unit_test.h"
|
||||
|
||||
@@ -80,6 +81,76 @@ ISOLATE_UNIT_TEST_CASE(DeserializeSExp) {
|
||||
}
|
||||
}
|
||||
|
||||
ISOLATE_UNIT_TEST_CASE(DeserializeSExpNumbers) {
|
||||
Zone* const zone = Thread::Current()->zone();
|
||||
|
||||
// Negative integers are handled.
|
||||
{
|
||||
const char* const cstr = "(-4 -50 -1414243)";
|
||||
SExpParser parser(zone, cstr, strlen(cstr));
|
||||
SExpression* const sexp = parser.Parse();
|
||||
EXPECT_NOTNULL(sexp);
|
||||
EXPECT(sexp->IsList());
|
||||
auto list = sexp->AsList();
|
||||
EXPECT_EQ(3, list->Length());
|
||||
EXPECT_EQ(0, list->ExtraLength());
|
||||
for (intptr_t i = 0; i < list->Length(); i++) {
|
||||
EXPECT(list->At(i)->IsInteger());
|
||||
EXPECT(list->At(i)->AsInteger()->value() < 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Various decimal/exponent Doubles are appropriately handled.
|
||||
{
|
||||
const char* const cstr = "(1.05 0.05 .03 1e100 1e-100)";
|
||||
SExpParser parser(zone, cstr, strlen(cstr));
|
||||
SExpression* const sexp = parser.Parse();
|
||||
EXPECT_NOTNULL(sexp);
|
||||
EXPECT(sexp->IsList());
|
||||
auto list = sexp->AsList();
|
||||
EXPECT_EQ(5, list->Length());
|
||||
EXPECT_EQ(0, list->ExtraLength());
|
||||
EXPECT(list->At(0)->IsDouble());
|
||||
double val = list->At(0)->AsDouble()->value();
|
||||
EXPECT(val > 1.04 && val < 1.06);
|
||||
EXPECT(list->At(1)->IsDouble());
|
||||
val = list->At(1)->AsDouble()->value();
|
||||
EXPECT(val > 0.04 && val < 0.06);
|
||||
EXPECT(list->At(2)->IsDouble());
|
||||
val = list->At(2)->AsDouble()->value();
|
||||
EXPECT(val > 0.02 && val < 0.04);
|
||||
EXPECT(list->At(3)->IsDouble());
|
||||
val = list->At(3)->AsDouble()->value();
|
||||
EXPECT(val > 0.9e100 && val < 1.1e100);
|
||||
EXPECT(list->At(4)->IsDouble());
|
||||
val = list->At(4)->AsDouble()->value();
|
||||
EXPECT(val > 0.9e-100 && val < 1.1e-100);
|
||||
}
|
||||
|
||||
// Special Double symbols are appropriately handled.
|
||||
{
|
||||
const char* const cstr = "(NaN Infinity -Infinity)";
|
||||
SExpParser parser(zone, cstr, strlen(cstr));
|
||||
SExpression* const sexp = parser.Parse();
|
||||
EXPECT_NOTNULL(sexp);
|
||||
EXPECT(sexp->IsList());
|
||||
auto list = sexp->AsList();
|
||||
EXPECT_EQ(3, list->Length());
|
||||
EXPECT_EQ(0, list->ExtraLength());
|
||||
EXPECT(list->At(0)->IsDouble());
|
||||
double val = list->At(0)->AsDouble()->value();
|
||||
EXPECT(isnan(val));
|
||||
EXPECT(list->At(1)->IsDouble());
|
||||
val = list->At(1)->AsDouble()->value();
|
||||
EXPECT(val > 0.0);
|
||||
EXPECT(isinf(val));
|
||||
EXPECT(list->At(2)->IsDouble());
|
||||
val = list->At(2)->AsDouble()->value();
|
||||
EXPECT(val < 0.0);
|
||||
EXPECT(isinf(val));
|
||||
}
|
||||
}
|
||||
|
||||
ISOLATE_UNIT_TEST_CASE(DeserializeSExpRoundTrip) {
|
||||
Zone* const zone = Thread::Current()->zone();
|
||||
SExpression* sexp = SExpression::FromCString(zone, shared_sexp_cstr);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "vm/compiler/backend/flow_graph.h"
|
||||
#include "vm/compiler/backend/il.h"
|
||||
#include "vm/compiler/method_recognizer.h"
|
||||
#include "vm/os.h"
|
||||
|
||||
namespace dart {
|
||||
@@ -42,7 +43,7 @@ void FlowGraphSerializer::SerializeToBuffer(Zone* zone,
|
||||
TextBuffer* buffer) {
|
||||
ASSERT(buffer != nullptr);
|
||||
FlowGraphSerializer serializer(zone, flow_graph);
|
||||
auto sexp = serializer.FunctionToSExp();
|
||||
auto const sexp = serializer.FlowGraphToSExp();
|
||||
if (FLAG_pretty_print_serialization) {
|
||||
sexp->SerializeTo(serializer.zone(), buffer, initial_indent);
|
||||
} else {
|
||||
@@ -97,6 +98,7 @@ SExpression* FlowGraphSerializer::BlockIdToSExp(intptr_t block_id) {
|
||||
|
||||
void FlowGraphSerializer::SerializeCanonicalName(TextBuffer* b,
|
||||
const Object& obj) {
|
||||
ASSERT(!obj.IsNull());
|
||||
if (obj.IsFunction()) {
|
||||
const auto& function = Function::Cast(obj);
|
||||
tmp_string_ = function.UserVisibleName();
|
||||
@@ -141,59 +143,102 @@ void FlowGraphSerializer::SerializeCanonicalName(TextBuffer* b,
|
||||
}
|
||||
|
||||
SExpression* FlowGraphSerializer::CanonicalNameToSExp(const Object& obj) {
|
||||
ASSERT(!obj.IsNull());
|
||||
TextBuffer b(100);
|
||||
SerializeCanonicalName(&b, obj);
|
||||
return new (zone()) SExpSymbol(OS::SCreate(zone(), "%s", b.buf()));
|
||||
}
|
||||
|
||||
SExpression* FlowGraphSerializer::BlockEntryToSExp(const char* entry_name,
|
||||
BlockEntryInstr* entry) {
|
||||
SExpSymbol* FlowGraphSerializer::BlockEntryTag(const BlockEntryInstr* entry) {
|
||||
if (entry == nullptr) return nullptr;
|
||||
BlockEntryInstr* const to_test = const_cast<BlockEntryInstr*>(entry);
|
||||
if (to_test->IsGraphEntry()) {
|
||||
return new (zone()) SExpSymbol("Graph");
|
||||
}
|
||||
if (to_test->IsOsrEntry()) {
|
||||
return new (zone()) SExpSymbol("OSR");
|
||||
}
|
||||
if (to_test->IsCatchBlockEntry()) {
|
||||
return new (zone()) SExpSymbol("Catch");
|
||||
}
|
||||
if (to_test->IsIndirectEntry()) {
|
||||
return new (zone()) SExpSymbol("Indirect");
|
||||
}
|
||||
if (to_test->IsFunctionEntry()) {
|
||||
if (entry == flow_graph()->graph_entry()->normal_entry()) {
|
||||
return new (zone()) SExpSymbol("Normal");
|
||||
}
|
||||
if (entry == flow_graph()->graph_entry()->unchecked_entry()) {
|
||||
return new (zone()) SExpSymbol("Unchecked");
|
||||
}
|
||||
}
|
||||
if (to_test->IsJoinEntry()) {
|
||||
return new (zone()) SExpSymbol("Join");
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SExpression* FlowGraphSerializer::FunctionEntryToSExp(BlockEntryInstr* entry) {
|
||||
if (entry == nullptr) return nullptr;
|
||||
auto sexp = new (zone()) SExpList(zone());
|
||||
const auto tag_cstr = OS::SCreate(zone(), "%s-entry", entry_name);
|
||||
sexp->Add(new (zone()) SExpSymbol(tag_cstr));
|
||||
sexp->Add(BlockEntryTag(entry));
|
||||
sexp->Add(BlockIdToSExp(entry->block_id()));
|
||||
if (auto with_defs = entry->AsBlockEntryWithInitialDefs()) {
|
||||
auto initial_defs = with_defs->initial_definitions();
|
||||
for (intptr_t i = 0; i < initial_defs->length(); i++) {
|
||||
sexp->Add(initial_defs->At(i)->ToSExpression(this));
|
||||
}
|
||||
} else if (auto join = entry->AsJoinEntry()) {
|
||||
if (auto phi_list = join->phis()) {
|
||||
for (intptr_t i = 0; i < phi_list->length(); i++) {
|
||||
sexp->Add(phi_list->At(i)->ToSExpression(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
return sexp;
|
||||
}
|
||||
|
||||
SExpression* FlowGraphSerializer::FunctionToSExp() {
|
||||
auto start = flow_graph()->graph_entry();
|
||||
SExpression* FlowGraphSerializer::EntriesToSExp(GraphEntryInstr* start) {
|
||||
auto sexp = new (zone()) SExpList(zone());
|
||||
AddSymbol(sexp, "function");
|
||||
sexp->Add(CanonicalNameToSExp(flow_graph()->function()));
|
||||
AddExtraInteger(sexp, "deopt_id", start->deopt_id());
|
||||
AddConstantPool(sexp);
|
||||
if (start->normal_entry()) {
|
||||
sexp->Add(BlockEntryToSExp("normal", start->normal_entry()));
|
||||
AddSymbol(sexp, "Entries");
|
||||
if (auto const normal = FunctionEntryToSExp(start->normal_entry())) {
|
||||
sexp->Add(normal);
|
||||
}
|
||||
if (start->unchecked_entry()) {
|
||||
sexp->Add(BlockEntryToSExp("unchecked", start->unchecked_entry()));
|
||||
if (auto const unchecked = FunctionEntryToSExp(start->unchecked_entry())) {
|
||||
sexp->Add(unchecked);
|
||||
}
|
||||
if (start->osr_entry()) {
|
||||
sexp->Add(BlockEntryToSExp("osr", start->osr_entry()));
|
||||
if (auto const osr = FunctionEntryToSExp(start->osr_entry())) {
|
||||
sexp->Add(osr);
|
||||
}
|
||||
for (intptr_t i = 0; i < start->catch_entries().length(); i++) {
|
||||
sexp->Add(BlockEntryToSExp("catch", start->catch_entries().At(i)));
|
||||
sexp->Add(FunctionEntryToSExp(start->catch_entries().At(i)));
|
||||
}
|
||||
for (intptr_t i = 0; i < start->indirect_entries().length(); i++) {
|
||||
sexp->Add(BlockEntryToSExp("indirect", start->indirect_entries().At(i)));
|
||||
sexp->Add(FunctionEntryToSExp(start->indirect_entries().At(i)));
|
||||
}
|
||||
return sexp;
|
||||
}
|
||||
|
||||
SExpression* FlowGraphSerializer::FlowGraphToSExp() {
|
||||
auto const start = flow_graph()->graph_entry();
|
||||
auto const sexp = new (zone()) SExpList(zone());
|
||||
AddSymbol(sexp, "FlowGraph");
|
||||
sexp->Add(CanonicalNameToSExp(flow_graph()->function()));
|
||||
AddExtraInteger(sexp, "deopt_id", start->deopt_id());
|
||||
if (start->IsCompiledForOsr()) {
|
||||
AddExtraInteger(sexp, "osr_id", start->osr_id());
|
||||
}
|
||||
if (auto const constants = ConstantPoolToSExp(start)) {
|
||||
sexp->Add(constants);
|
||||
}
|
||||
sexp->Add(EntriesToSExp(start));
|
||||
auto& block_order = flow_graph()->reverse_postorder();
|
||||
// Skip the first block, which will be the graph entry block (B0). We
|
||||
// output all its information as part of the function expression, so it'll
|
||||
// just show up as an empty block here.
|
||||
ASSERT(block_order[0]->IsGraphEntry());
|
||||
for (intptr_t i = 1; i < block_order.length(); ++i) {
|
||||
sexp->Add(block_order[i]->ToSExpression(this));
|
||||
}
|
||||
AddBlocks(sexp);
|
||||
return sexp;
|
||||
}
|
||||
|
||||
SExpression* FlowGraphSerializer::UseToSExp(const Definition* definition) {
|
||||
ASSERT(definition != nullptr);
|
||||
ASSERT(definition->HasSSATemp() || definition->HasTemp());
|
||||
if (definition->HasSSATemp()) {
|
||||
const intptr_t temp_index = definition->ssa_temp_index();
|
||||
@@ -209,12 +254,12 @@ SExpression* FlowGraphSerializer::UseToSExp(const Definition* definition) {
|
||||
} else if (definition->HasTemp()) {
|
||||
const intptr_t temp_index = definition->temp_index();
|
||||
return new (zone()) SExpSymbol(OS::SCreate(zone(), "t%" Pd "", temp_index));
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
SExpression* FlowGraphSerializer::ClassToSExp(const Class& cls) {
|
||||
if (cls.IsNull()) return nullptr;
|
||||
auto sexp = new (zone()) SExpList(zone());
|
||||
AddSymbol(sexp, "Class");
|
||||
AddInteger(sexp, cls.id());
|
||||
@@ -232,6 +277,7 @@ static bool ShouldSerializeType(CompileType* type) {
|
||||
}
|
||||
|
||||
SExpression* FlowGraphSerializer::FieldToSExp(const Field& field) {
|
||||
if (field.IsNull()) return nullptr;
|
||||
auto sexp = new (zone()) SExpList(zone());
|
||||
AddSymbol(sexp, "Field");
|
||||
sexp->Add(CanonicalNameToSExp(field));
|
||||
@@ -243,6 +289,7 @@ SExpression* FlowGraphSerializer::FieldToSExp(const Field& field) {
|
||||
}
|
||||
|
||||
SExpression* FlowGraphSerializer::AbstractTypeToSExp(const AbstractType& t) {
|
||||
if (t.IsNull()) return nullptr;
|
||||
auto sexp = new (zone()) SExpList(zone());
|
||||
if (t.IsTypeParameter()) {
|
||||
const auto& param = TypeParameter::Cast(t);
|
||||
@@ -289,6 +336,7 @@ SExpression* FlowGraphSerializer::AbstractTypeToSExp(const AbstractType& t) {
|
||||
}
|
||||
|
||||
SExpression* FlowGraphSerializer::CodeToSExp(const Code& code) {
|
||||
if (code.IsNull()) return nullptr;
|
||||
auto sexp = new (zone()) SExpList(zone());
|
||||
AddSymbol(sexp, "Code");
|
||||
if (code.IsStubCode()) {
|
||||
@@ -299,27 +347,22 @@ SExpression* FlowGraphSerializer::CodeToSExp(const Code& code) {
|
||||
return sexp;
|
||||
}
|
||||
tmp_object_ = code.owner();
|
||||
if (tmp_object_.IsClass()) {
|
||||
sexp->Add(ClassToSExp(Class::Cast(tmp_object_)));
|
||||
if (FLAG_verbose_flow_graph_serialization) {
|
||||
if (!tmp_object_.IsNull() && FLAG_verbose_flow_graph_serialization) {
|
||||
if (tmp_object_.IsClass()) {
|
||||
AddExtraSymbol(sexp, "kind", "allocate");
|
||||
}
|
||||
} else if (tmp_object_.IsAbstractType()) {
|
||||
sexp->Add(AbstractTypeToSExp(AbstractType::Cast(tmp_object_)));
|
||||
if (FLAG_verbose_flow_graph_serialization) {
|
||||
} else if (tmp_object_.IsAbstractType()) {
|
||||
AddExtraSymbol(sexp, "kind", "type_test");
|
||||
}
|
||||
} else {
|
||||
ASSERT(tmp_object_.IsFunction());
|
||||
sexp->Add(CanonicalNameToSExp(tmp_object_));
|
||||
if (FLAG_verbose_flow_graph_serialization) {
|
||||
} else {
|
||||
ASSERT(tmp_object_.IsFunction());
|
||||
AddExtraSymbol(sexp, "kind", "function");
|
||||
}
|
||||
}
|
||||
sexp->Add(ObjectToSExp(tmp_object_));
|
||||
return sexp;
|
||||
}
|
||||
|
||||
SExpression* FlowGraphSerializer::TypeArgumentsToSExp(const TypeArguments& ta) {
|
||||
if (ta.IsNull()) return nullptr;
|
||||
auto sexp = new (zone()) SExpList(zone());
|
||||
AddSymbol(sexp, "TypeArguments");
|
||||
for (intptr_t i = 0; i < ta.Length(); i++) {
|
||||
@@ -333,7 +376,50 @@ SExpression* FlowGraphSerializer::TypeArgumentsToSExp(const TypeArguments& ta) {
|
||||
return sexp;
|
||||
}
|
||||
|
||||
SExpression* FlowGraphSerializer::DartValueToSExp(const Object& dartval) {
|
||||
SExpression* FlowGraphSerializer::InstanceToSExp(const Instance& inst) {
|
||||
if (inst.IsNull()) return nullptr;
|
||||
auto const sexp = new (zone()) SExpList(zone());
|
||||
AddSymbol(sexp, "Instance");
|
||||
tmp_class_ = inst.clazz();
|
||||
AddInteger(sexp, tmp_class_.id());
|
||||
if (FLAG_verbose_flow_graph_serialization) {
|
||||
AddExtraInteger(sexp, "size", inst.InstanceSize());
|
||||
if (auto const cls = ClassToSExp(tmp_class_)) {
|
||||
sexp->AddExtra("class", cls);
|
||||
}
|
||||
}
|
||||
return sexp;
|
||||
}
|
||||
|
||||
SExpression* FlowGraphSerializer::FunctionToSExp(const Function& func) {
|
||||
if (func.IsNull()) return nullptr;
|
||||
auto const sexp = new (zone()) SExpList(zone());
|
||||
AddSymbol(sexp, "Function");
|
||||
sexp->Add(CanonicalNameToSExp(func));
|
||||
if (func.IsRecognized()) {
|
||||
AddExtraSymbol(sexp, "recognized",
|
||||
MethodRecognizer::KindToCString(func.recognized_kind()));
|
||||
}
|
||||
if (func.is_native()) {
|
||||
tmp_string_ = func.native_name();
|
||||
if (!tmp_string_.IsNull()) {
|
||||
AddExtraSymbol(sexp, "native_name", tmp_string_.ToCString());
|
||||
}
|
||||
}
|
||||
if (FLAG_verbose_flow_graph_serialization) {
|
||||
AddExtraSymbol(sexp, "kind", Function::KindToCString(func.kind()));
|
||||
}
|
||||
tmp_type_args_ = func.type_parameters();
|
||||
if (auto const ta_sexp = TypeArgumentsToSExp(tmp_type_args_)) {
|
||||
sexp->AddExtra("type_params", ta_sexp);
|
||||
}
|
||||
return sexp;
|
||||
}
|
||||
|
||||
SExpression* FlowGraphSerializer::ObjectToSExp(const Object& dartval) {
|
||||
if (dartval.IsNull()) {
|
||||
return new (zone()) SExpSymbol("null");
|
||||
}
|
||||
if (dartval.IsString()) {
|
||||
return new (zone()) SExpString(dartval.ToCString());
|
||||
}
|
||||
@@ -343,8 +429,8 @@ SExpression* FlowGraphSerializer::DartValueToSExp(const Object& dartval) {
|
||||
if (dartval.IsBool()) {
|
||||
return new (zone()) SExpBool(Bool::Cast(dartval).value());
|
||||
}
|
||||
if (dartval.IsNull()) {
|
||||
return new (zone()) SExpSymbol("null");
|
||||
if (dartval.IsDouble()) {
|
||||
return new (zone()) SExpDouble(Double::Cast(dartval).value());
|
||||
}
|
||||
if (dartval.IsField()) {
|
||||
return FieldToSExp(Field::Cast(dartval));
|
||||
@@ -365,51 +451,36 @@ SExpression* FlowGraphSerializer::DartValueToSExp(const Object& dartval) {
|
||||
auto& elem = Object::Handle(zone());
|
||||
for (intptr_t i = 0; i < arr.Length(); i++) {
|
||||
elem = arr.At(i);
|
||||
sexp->Add(DartValueToSExp(elem));
|
||||
sexp->Add(ObjectToSExp(elem));
|
||||
}
|
||||
return sexp;
|
||||
}
|
||||
tmp_class_ = dartval.clazz();
|
||||
auto sexp = new (zone()) SExpList(zone());
|
||||
AddSymbol(sexp, "Instance");
|
||||
AddInteger(sexp, tmp_class_.id());
|
||||
if (FLAG_verbose_flow_graph_serialization) {
|
||||
AddExtraInteger(sexp, "size", dartval.InstanceSize());
|
||||
sexp->AddExtra("class", ClassToSExp(tmp_class_));
|
||||
if (dartval.IsFunction()) {
|
||||
return FunctionToSExp(Function::Cast(dartval));
|
||||
}
|
||||
return sexp;
|
||||
ASSERT(dartval.IsInstance());
|
||||
return InstanceToSExp(Instance::Cast(dartval));
|
||||
}
|
||||
|
||||
void FlowGraphSerializer::AddConstantPool(SExpList* sexp) {
|
||||
auto initial_defs = flow_graph()->graph_entry()->initial_definitions();
|
||||
if (initial_defs->is_empty()) return;
|
||||
SExpression* FlowGraphSerializer::ConstantPoolToSExp(GraphEntryInstr* start) {
|
||||
auto const initial_defs = start->initial_definitions();
|
||||
if (initial_defs == nullptr || initial_defs->is_empty()) return nullptr;
|
||||
auto constant_list = new (zone()) SExpList(zone());
|
||||
AddSymbol(constant_list, "constants");
|
||||
AddSymbol(constant_list, "Constants");
|
||||
for (intptr_t i = 0; i < initial_defs->length(); i++) {
|
||||
ASSERT(initial_defs->At(i)->IsConstant());
|
||||
ConstantInstr* value = initial_defs->At(i)->AsConstant();
|
||||
auto elem = new (zone()) SExpList(zone());
|
||||
AddSymbol(elem, "def");
|
||||
elem->Add(UseToSExp(value->AsDefinition()));
|
||||
elem->Add(DartValueToSExp(value->value()));
|
||||
elem->Add(ObjectToSExp(value->value()));
|
||||
if (ShouldSerializeType(value->AsDefinition()->Type())) {
|
||||
auto val = value->AsDefinition()->Type()->ToSExpression(this);
|
||||
auto const val = value->AsDefinition()->Type()->ToSExpression(this);
|
||||
elem->AddExtra("type", val);
|
||||
}
|
||||
constant_list->Add(elem);
|
||||
}
|
||||
sexp->Add(constant_list);
|
||||
}
|
||||
|
||||
void FlowGraphSerializer::AddBlocks(SExpList* sexp) {
|
||||
auto& block_order = flow_graph()->reverse_postorder();
|
||||
// Skip the first block, which will be the graph entry block (B0). We
|
||||
// output all its information as part of the function expression, so it'll
|
||||
// just show up as an empty block here.
|
||||
ASSERT(block_order[0]->IsGraphEntry());
|
||||
for (intptr_t i = 1; i < block_order.length(); ++i) {
|
||||
sexp->Add(block_order[i]->ToSExpression(this));
|
||||
}
|
||||
return constant_list;
|
||||
}
|
||||
|
||||
SExpression* Instruction::ToSExpression(FlowGraphSerializer* s) const {
|
||||
@@ -422,13 +493,30 @@ SExpression* Instruction::ToSExpression(FlowGraphSerializer* s) const {
|
||||
|
||||
SExpression* BlockEntryInstr::ToSExpression(FlowGraphSerializer* s) const {
|
||||
auto sexp = new (s->zone()) SExpList(s->zone());
|
||||
s->AddSymbol(sexp, "block");
|
||||
s->AddSymbol(sexp, "Block");
|
||||
sexp->Add(s->BlockIdToSExp(block_id()));
|
||||
AddOperandsToSExpression(sexp, s);
|
||||
AddExtraInfoToSExpression(sexp, s);
|
||||
return sexp;
|
||||
}
|
||||
|
||||
void BlockEntryInstr::AddExtraInfoToSExpression(SExpList* sexp,
|
||||
FlowGraphSerializer* s) const {
|
||||
Instruction::AddExtraInfoToSExpression(sexp, s);
|
||||
if (FLAG_verbose_flow_graph_serialization) {
|
||||
if (auto const entry_tag = s->BlockEntryTag(this)) {
|
||||
sexp->AddExtra("block_type", entry_tag);
|
||||
}
|
||||
if (PredecessorCount() > 0) {
|
||||
auto const preds = new (s->zone()) SExpList(s->zone());
|
||||
for (intptr_t i = 0; i < PredecessorCount(); i++) {
|
||||
preds->Add(s->BlockIdToSExp(PredecessorAt(i)->block_id()));
|
||||
}
|
||||
sexp->AddExtra("predecessors", preds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BlockEntryInstr::AddOperandsToSExpression(SExpList* sexp,
|
||||
FlowGraphSerializer* s) const {
|
||||
// We don't use RemoveCurrentFromGraph(), so this cast is safe.
|
||||
@@ -482,7 +570,7 @@ SExpression* Definition::ToSExpression(FlowGraphSerializer* s) const {
|
||||
|
||||
void ConstantInstr::AddOperandsToSExpression(SExpList* sexp,
|
||||
FlowGraphSerializer* s) const {
|
||||
sexp->Add(s->DartValueToSExp(value()));
|
||||
sexp->Add(s->ObjectToSExp(value()));
|
||||
}
|
||||
|
||||
void BranchInstr::AddOperandsToSExpression(SExpList* sexp,
|
||||
@@ -503,22 +591,50 @@ void SpecialParameterInstr::AddOperandsToSExpression(
|
||||
s->AddSymbol(sexp, KindToCString(kind()));
|
||||
}
|
||||
|
||||
SExpression* FlowGraphSerializer::LocalVariableToSExp(const LocalVariable& v) {
|
||||
auto const sexp = new (zone()) SExpList(zone());
|
||||
AddSymbol(sexp, "LocalVariable");
|
||||
if (!v.name().IsNull()) {
|
||||
AddSymbol(sexp, v.name().ToCString());
|
||||
}
|
||||
if (v.index().IsValid()) {
|
||||
AddExtraInteger(sexp, "index", v.index().value());
|
||||
}
|
||||
return sexp;
|
||||
}
|
||||
|
||||
void LoadLocalInstr::AddOperandsToSExpression(SExpList* sexp,
|
||||
FlowGraphSerializer* s) const {
|
||||
sexp->Add(s->LocalVariableToSExp(local()));
|
||||
}
|
||||
|
||||
void StoreLocalInstr::AddOperandsToSExpression(SExpList* sexp,
|
||||
FlowGraphSerializer* s) const {
|
||||
sexp->Add(s->LocalVariableToSExp(local()));
|
||||
}
|
||||
|
||||
static const char* SlotKindToCString(Slot::Kind kind) {
|
||||
switch (kind) {
|
||||
case Slot::Kind::kDartField:
|
||||
return "DartField";
|
||||
case Slot::Kind::kCapturedVariable:
|
||||
return "CapturedVariable";
|
||||
case Slot::Kind::kTypeArguments:
|
||||
return "TypeArguments";
|
||||
default:
|
||||
return "NativeSlot";
|
||||
}
|
||||
}
|
||||
|
||||
SExpression* FlowGraphSerializer::SlotToSExp(const Slot& slot) {
|
||||
auto sexp = new (zone()) SExpList(zone());
|
||||
AddSymbol(sexp, "Slot");
|
||||
AddInteger(sexp, slot.offset_in_bytes());
|
||||
if (FLAG_verbose_flow_graph_serialization) {
|
||||
AddExtraSymbol(sexp, "kind", SlotKindToCString(slot.kind()));
|
||||
if (slot.IsDartField()) {
|
||||
AddExtraSymbol(sexp, "kind", "kDartField");
|
||||
sexp->AddExtra("field", FieldToSExp(slot.field()));
|
||||
} else if (slot.IsLocalVariable()) {
|
||||
AddExtraSymbol(sexp, "kind", "kCapturedVariable");
|
||||
AddExtraString(sexp, "name", slot.Name());
|
||||
} else if (slot.IsTypeArguments()) {
|
||||
AddExtraSymbol(sexp, "kind", "kTypeArguments");
|
||||
AddExtraString(sexp, "name", slot.Name());
|
||||
} else {
|
||||
AddExtraSymbol(sexp, "kind", "kNativeSlot");
|
||||
AddExtraString(sexp, "name", slot.Name());
|
||||
}
|
||||
}
|
||||
@@ -586,14 +702,17 @@ void GotoInstr::AddOperandsToSExpression(SExpList* sexp,
|
||||
|
||||
void TailCallInstr::AddOperandsToSExpression(SExpList* sexp,
|
||||
FlowGraphSerializer* s) const {
|
||||
sexp->Add(s->CodeToSExp(code_));
|
||||
if (auto const code = s->CodeToSExp(code_)) {
|
||||
sexp->Add(code);
|
||||
}
|
||||
Instruction::AddOperandsToSExpression(sexp, s);
|
||||
}
|
||||
|
||||
void NativeCallInstr::AddOperandsToSExpression(SExpList* sexp,
|
||||
FlowGraphSerializer* s) const {
|
||||
sexp->Add(s->CanonicalNameToSExp(function()));
|
||||
s->AddSymbol(sexp, native_name().ToCString());
|
||||
if (auto const func = s->FunctionToSExp(function())) {
|
||||
sexp->Add(func);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
@@ -620,13 +739,15 @@ void TemplateDartCall<1l>::AddExtraInfoToSExpression(
|
||||
|
||||
void StaticCallInstr::AddOperandsToSExpression(SExpList* sexp,
|
||||
FlowGraphSerializer* s) const {
|
||||
sexp->Add(s->CanonicalNameToSExp(function()));
|
||||
if (auto const func = s->FunctionToSExp(function())) {
|
||||
sexp->Add(func);
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceCallInstr::AddOperandsToSExpression(SExpList* sexp,
|
||||
FlowGraphSerializer* s) const {
|
||||
if (!interface_target().IsNull()) {
|
||||
sexp->Add(s->CanonicalNameToSExp(interface_target()));
|
||||
if (auto const target = s->FunctionToSExp(interface_target())) {
|
||||
sexp->Add(target);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -654,7 +775,9 @@ void PolymorphicInstanceCallInstr::AddExtraInfoToSExpression(
|
||||
s->AddInteger(range, ti->cid_end);
|
||||
elem->Add(range);
|
||||
}
|
||||
elem->Add(s->CanonicalNameToSExp(*ti->target));
|
||||
if (auto const target = s->FunctionToSExp(*ti->target)) {
|
||||
elem->Add(target);
|
||||
}
|
||||
elem_list->Add(elem);
|
||||
}
|
||||
sexp->AddExtra("targets", elem_list);
|
||||
@@ -664,7 +787,9 @@ void PolymorphicInstanceCallInstr::AddExtraInfoToSExpression(
|
||||
void AllocateObjectInstr::AddOperandsToSExpression(
|
||||
SExpList* sexp,
|
||||
FlowGraphSerializer* s) const {
|
||||
sexp->Add(s->ClassToSExp(cls()));
|
||||
if (auto const sexp_cls = s->ClassToSExp(cls())) {
|
||||
sexp->Add(sexp_cls);
|
||||
}
|
||||
}
|
||||
|
||||
void AllocateObjectInstr::AddExtraInfoToSExpression(
|
||||
@@ -675,12 +800,8 @@ void AllocateObjectInstr::AddExtraInfoToSExpression(
|
||||
if (ArgumentCount() > 0 || FLAG_verbose_flow_graph_serialization) {
|
||||
s->AddExtraInteger(sexp, "args_len", ArgumentCount());
|
||||
}
|
||||
if (FLAG_verbose_flow_graph_serialization) {
|
||||
if (closure_function().IsNull()) {
|
||||
s->AddSymbol(sexp, "null");
|
||||
} else {
|
||||
sexp->Add(s->CanonicalNameToSExp(closure_function()));
|
||||
}
|
||||
if (auto const closure = s->FunctionToSExp(closure_function())) {
|
||||
sexp->AddExtra("closure_function", closure);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -699,11 +820,14 @@ void CheckedSmiOpInstr::AddOperandsToSExpression(SExpList* sexp,
|
||||
sexp->Add(right()->ToSExpression(s));
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
static const char* simd_op_kind_string[] = {
|
||||
#define CASE(Arity, Mask, Name, ...) #Name,
|
||||
SIMD_OP_LIST(CASE, CASE)
|
||||
SIMD_OP_LIST(CASE, CASE)
|
||||
#undef CASE
|
||||
"IllegalSimdOp",
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
void SimdOpInstr::AddOperandsToSExpression(SExpList* sexp,
|
||||
FlowGraphSerializer* s) const {
|
||||
@@ -792,8 +916,13 @@ void CompileType::AddExtraInfoToSExpression(SExpList* sexp,
|
||||
if (!is_nullable() || FLAG_verbose_flow_graph_serialization) {
|
||||
s->AddExtraBool(sexp, "nullable", is_nullable());
|
||||
}
|
||||
if (FLAG_verbose_flow_graph_serialization) {
|
||||
s->AddExtraString(sexp, "name", ToCString());
|
||||
if (cid_ == kIllegalCid || cid_ == kDynamicCid ||
|
||||
FLAG_verbose_flow_graph_serialization) {
|
||||
if (type_ != nullptr) {
|
||||
sexp->AddExtra("type", s->AbstractTypeToSExp(*type_));
|
||||
} else {
|
||||
s->AddExtraString(sexp, "name", ToCString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#ifndef RUNTIME_VM_COMPILER_BACKEND_IL_SERIALIZER_H_
|
||||
#define RUNTIME_VM_COMPILER_BACKEND_IL_SERIALIZER_H_
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "platform/text_buffer.h"
|
||||
|
||||
#include "vm/allocation.h"
|
||||
@@ -28,23 +29,34 @@ class FlowGraphSerializer : ValueObject {
|
||||
const FlowGraph* flow_graph() const { return flow_graph_; }
|
||||
Zone* zone() const { return zone_; }
|
||||
|
||||
SExpression* FunctionToSExp();
|
||||
SExpression* FlowGraphToSExp();
|
||||
|
||||
SExpSymbol* BlockEntryTag(const BlockEntryInstr* entry);
|
||||
SExpression* BlockIdToSExp(intptr_t block_id);
|
||||
SExpression* BlockEntryToSExp(const char* entry_name, BlockEntryInstr* entry);
|
||||
SExpression* CanonicalNameToSExp(const Object& obj);
|
||||
SExpression* UseToSExp(const Definition* definition);
|
||||
|
||||
// Helper method for creating canonical names.
|
||||
void SerializeCanonicalName(TextBuffer* b, const Object& obj);
|
||||
|
||||
// Methods for serializing Dart values.
|
||||
// Methods for serializing Dart values. If the argument
|
||||
// value is the null object, the null pointer is returned.
|
||||
SExpression* AbstractTypeToSExp(const AbstractType& typ);
|
||||
SExpression* ClassToSExp(const Class& cls);
|
||||
SExpression* CodeToSExp(const Code& c);
|
||||
SExpression* FieldToSExp(const Field& f);
|
||||
SExpression* SlotToSExp(const Slot& s);
|
||||
SExpression* FunctionToSExp(const Function& f);
|
||||
SExpression* InstanceToSExp(const Instance& obj);
|
||||
SExpression* TypeArgumentsToSExp(const TypeArguments& ta);
|
||||
SExpression* DartValueToSExp(const Object& obj);
|
||||
|
||||
// A method for serializing a Dart value of arbitrary type.
|
||||
// Unlike the type-specific methods, this returns the symbol
|
||||
// "null" for the null object.
|
||||
SExpression* ObjectToSExp(const Object& obj);
|
||||
|
||||
// Methods for serializing IL-specific values.
|
||||
SExpression* LocalVariableToSExp(const LocalVariable& v);
|
||||
SExpression* SlotToSExp(const Slot& s);
|
||||
|
||||
// Helper methods for adding atoms to S-expression lists
|
||||
void AddBool(SExpList* sexp, bool b);
|
||||
@@ -58,22 +70,26 @@ class FlowGraphSerializer : ValueObject {
|
||||
|
||||
private:
|
||||
FlowGraphSerializer(Zone* zone, const FlowGraph* flow_graph)
|
||||
: flow_graph_(flow_graph),
|
||||
: flow_graph_(ASSERT_NOTNULL(flow_graph)),
|
||||
zone_(zone),
|
||||
tmp_type_(AbstractType::Handle(zone_)),
|
||||
tmp_class_(Class::Handle(zone_)),
|
||||
tmp_function_(Function::Handle(zone_)),
|
||||
tmp_library_(Library::Handle(zone_)),
|
||||
tmp_object_(Object::Handle(zone_)),
|
||||
tmp_type_args_(TypeArguments::Handle(zone_)),
|
||||
tmp_string_(String::Handle(zone_)) {}
|
||||
|
||||
static const char* const initial_indent;
|
||||
|
||||
void AddConstantPool(SExpList* sexp);
|
||||
void AddBlocks(SExpList* sexp);
|
||||
// Helper methods for the function level that are not used by any
|
||||
// instruction serialization methods.
|
||||
SExpression* FunctionEntryToSExp(BlockEntryInstr* entry);
|
||||
SExpression* EntriesToSExp(GraphEntryInstr* start);
|
||||
SExpression* ConstantPoolToSExp(GraphEntryInstr* start);
|
||||
|
||||
const FlowGraph* flow_graph_;
|
||||
Zone* zone_;
|
||||
const FlowGraph* const flow_graph_;
|
||||
Zone* const zone_;
|
||||
|
||||
// Handles for temporary use.
|
||||
AbstractType& tmp_type_;
|
||||
@@ -81,6 +97,7 @@ class FlowGraphSerializer : ValueObject {
|
||||
Function& tmp_function_;
|
||||
Library& tmp_library_;
|
||||
Object& tmp_object_;
|
||||
TypeArguments& tmp_type_args_;
|
||||
String& tmp_string_;
|
||||
};
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "vm/compiler/backend/sexpression.h"
|
||||
|
||||
#include "vm/compiler/backend/il_deserializer.h"
|
||||
#include "vm/double_conversion.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
@@ -23,7 +24,21 @@ bool SExpBool::Equals(SExpression* sexp) const {
|
||||
}
|
||||
|
||||
void SExpBool::SerializeToLine(TextBuffer* buffer) const {
|
||||
buffer->AddString(value() ? "true" : "false");
|
||||
buffer->AddString(value() ? SExpParser::kBoolTrueSymbol
|
||||
: SExpParser::kBoolFalseSymbol);
|
||||
}
|
||||
|
||||
bool SExpDouble::Equals(SExpression* sexp) const {
|
||||
if (!sexp->IsDouble()) return false;
|
||||
return this->value() == sexp->AsDouble()->value();
|
||||
}
|
||||
|
||||
void SExpDouble::SerializeToLine(TextBuffer* buffer) const {
|
||||
// Use existing Dart serialization for Doubles.
|
||||
const intptr_t kBufSize = 128;
|
||||
char strbuf[kBufSize];
|
||||
DoubleToCString(value(), strbuf, kBufSize);
|
||||
buffer->Printf("%s", strbuf);
|
||||
}
|
||||
|
||||
bool SExpInteger::Equals(SExpression* sexp) const {
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace dart {
|
||||
|
||||
#define FOR_EACH_S_EXPRESSION_ATOM(M) \
|
||||
M(Bool, bool) \
|
||||
M(Double, double) \
|
||||
M(Integer, intptr_t) \
|
||||
M(String, const char*) \
|
||||
M(Symbol, const char*)
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
|
||||
namespace dart {
|
||||
|
||||
static const char kDoubleToStringCommonExponentChar = 'e';
|
||||
static const char* kDoubleToStringCommonInfinitySymbol = "Infinity";
|
||||
static const char* kDoubleToStringCommonNaNSymbol = "NaN";
|
||||
char const DoubleToStringConstants::kExponentChar = 'e';
|
||||
const char* const DoubleToStringConstants::kInfinitySymbol = "Infinity";
|
||||
const char* const DoubleToStringConstants::kNaNSymbol = "NaN";
|
||||
|
||||
void DoubleToCString(double d, char* buffer, int buffer_size) {
|
||||
static const int kDecimalLow = -6;
|
||||
@@ -38,9 +38,9 @@ void DoubleToCString(double d, char* buffer, int buffer_size) {
|
||||
EMIT_TRAILING_ZERO_AFTER_POINT;
|
||||
|
||||
const double_conversion::DoubleToStringConverter converter(
|
||||
kConversionFlags, kDoubleToStringCommonInfinitySymbol,
|
||||
kDoubleToStringCommonNaNSymbol, kDoubleToStringCommonExponentChar,
|
||||
kDecimalLow, kDecimalHigh, 0,
|
||||
kConversionFlags, DoubleToStringConstants::kInfinitySymbol,
|
||||
DoubleToStringConstants::kNaNSymbol,
|
||||
DoubleToStringConstants::kExponentChar, kDecimalLow, kDecimalHigh, 0,
|
||||
0); // Last two values are ignored in shortest mode.
|
||||
|
||||
double_conversion::StringBuilder builder(buffer, buffer_size);
|
||||
@@ -78,9 +78,10 @@ RawString* DoubleToStringAsFixed(double d, int fraction_digits) {
|
||||
fraction_digits <= kMaxFractionDigits);
|
||||
|
||||
const double_conversion::DoubleToStringConverter converter(
|
||||
kConversionFlags, kDoubleToStringCommonInfinitySymbol,
|
||||
kDoubleToStringCommonNaNSymbol, kDoubleToStringCommonExponentChar, 0, 0,
|
||||
0, 0); // Last four values are ignored in fixed mode.
|
||||
kConversionFlags, DoubleToStringConstants::kInfinitySymbol,
|
||||
DoubleToStringConstants::kNaNSymbol,
|
||||
DoubleToStringConstants::kExponentChar, 0, 0, 0,
|
||||
0); // Last four values are ignored in fixed mode.
|
||||
|
||||
char* buffer = Thread::Current()->zone()->Alloc<char>(kBufferSize);
|
||||
buffer[kBufferSize - 1] = '\0';
|
||||
@@ -108,9 +109,10 @@ RawString* DoubleToStringAsExponential(double d, int fraction_digits) {
|
||||
fraction_digits <= kMaxFractionDigits);
|
||||
|
||||
const double_conversion::DoubleToStringConverter converter(
|
||||
kConversionFlags, kDoubleToStringCommonInfinitySymbol,
|
||||
kDoubleToStringCommonNaNSymbol, kDoubleToStringCommonExponentChar, 0, 0,
|
||||
0, 0); // Last four values are ignored in exponential mode.
|
||||
kConversionFlags, DoubleToStringConstants::kInfinitySymbol,
|
||||
DoubleToStringConstants::kNaNSymbol,
|
||||
DoubleToStringConstants::kExponentChar, 0, 0, 0,
|
||||
0); // Last four values are ignored in exponential mode.
|
||||
|
||||
char* buffer = Thread::Current()->zone()->Alloc<char>(kBufferSize);
|
||||
buffer[kBufferSize - 1] = '\0';
|
||||
@@ -143,8 +145,9 @@ RawString* DoubleToStringAsPrecision(double d, int precision) {
|
||||
ASSERT(kMinPrecisionDigits <= precision && precision <= kMaxPrecisionDigits);
|
||||
|
||||
const double_conversion::DoubleToStringConverter converter(
|
||||
kConversionFlags, kDoubleToStringCommonInfinitySymbol,
|
||||
kDoubleToStringCommonNaNSymbol, kDoubleToStringCommonExponentChar, 0,
|
||||
kConversionFlags, DoubleToStringConstants::kInfinitySymbol,
|
||||
DoubleToStringConstants::kNaNSymbol,
|
||||
DoubleToStringConstants::kExponentChar, 0,
|
||||
0, // Ignored in precision mode.
|
||||
kMaxLeadingPaddingZeroes, kMaxTrailingPaddingZeroes);
|
||||
|
||||
@@ -163,7 +166,8 @@ bool CStringToDouble(const char* str, intptr_t length, double* result) {
|
||||
|
||||
double_conversion::StringToDoubleConverter converter(
|
||||
double_conversion::StringToDoubleConverter::NO_FLAGS, 0.0, 0.0,
|
||||
kDoubleToStringCommonInfinitySymbol, kDoubleToStringCommonNaNSymbol);
|
||||
DoubleToStringConstants::kInfinitySymbol,
|
||||
DoubleToStringConstants::kNaNSymbol);
|
||||
|
||||
int parsed_count = 0;
|
||||
*result =
|
||||
|
||||
@@ -5,11 +5,18 @@
|
||||
#ifndef RUNTIME_VM_DOUBLE_CONVERSION_H_
|
||||
#define RUNTIME_VM_DOUBLE_CONVERSION_H_
|
||||
|
||||
#include "vm/allocation.h"
|
||||
#include "vm/globals.h"
|
||||
#include "vm/object.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
struct DoubleToStringConstants : AllStatic {
|
||||
static char const kExponentChar;
|
||||
static const char* const kInfinitySymbol;
|
||||
static const char* const kNaNSymbol;
|
||||
};
|
||||
|
||||
void DoubleToCString(double d, char* buffer, int buffer_size);
|
||||
RawString* DoubleToStringAsFixed(double d, int fraction_digits);
|
||||
RawString* DoubleToStringAsExponential(double d, int fraction_digits);
|
||||
|
||||
Reference in New Issue
Block a user