Skip to content

Commit

Permalink
[vm/compiler] Tweaks and additions to IL serializer/S-expressions.
Browse files Browse the repository at this point in the history
* 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: #36882
Change-Id: Iede3865ec64f81955a87fd57b10e74d49ee8414c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/110917
Commit-Queue: Teagan Strickland <[email protected]>
Reviewed-by: Martin Kustermann <[email protected]>
  • Loading branch information
sstrickl authored and [email protected] committed Jul 31, 2019
1 parent 2875b1b commit 2e197ae
Show file tree
Hide file tree
Showing 10 changed files with 460 additions and 142 deletions.
3 changes: 3 additions & 0 deletions runtime/vm/compiler/backend/il.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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_;
Expand Down Expand Up @@ -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_;
Expand Down
99 changes: 81 additions & 18 deletions runtime/vm/compiler/backend/il_deserializer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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) {
Expand Down
10 changes: 9 additions & 1 deletion runtime/vm/compiler/backend/il_deserializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -59,7 +66,8 @@ class SExpParser : public ValueObject {
M(LeftCurly) \
M(RightCurly) \
M(QuotedString) \
M(Number) \
M(Integer) \
M(Double) \
M(Boolean) \
M(Symbol)

Expand Down
71 changes: 71 additions & 0 deletions runtime/vm/compiler/backend/il_deserializer_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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);
Expand Down
Loading

0 comments on commit 2e197ae

Please sign in to comment.