From ff4e4ab4b62d3653942e719947e5b1abb67e7734 Mon Sep 17 00:00:00 2001 From: Ross McIlroy Date: Thu, 9 Nov 2017 16:06:15 +0000 Subject: [PATCH] [Ast] Teach Ast Printer to print raw literal values. Converts the ast prettyprinter to printing literals from the raw values rather than internalized on-heap strings. This enables ast printing before internalizing, and means we can avoid use of the isolate in the interpreter's off-thread phase. Also removes --print-builtin-ast and relies on just --print-ast to print everything. Finally, converts FunctionLiteral's debug_name function to return a char[] which is created from the raw name literal where it exists, rather than relying on the value having been internalized. BUG=v8:5203 Change-Id: Ib69f754e254736f415db38713e6209465817e6f1 Reviewed-on: https://chromium-review.googlesource.com/758681 Reviewed-by: Adam Klein Commit-Queue: Ross McIlroy Cr-Commit-Position: refs/heads/master@{#49276} --- src/ast/ast-value-factory.cc | 14 +++ src/ast/ast-value-factory.h | 4 + src/ast/ast.cc | 29 +++++ src/ast/ast.h | 13 +-- src/ast/prettyprinter.cc | 189 ++++++++++++++++++--------------- src/ast/prettyprinter.h | 16 +-- src/compilation-info.cc | 3 +- src/flag-definitions.h | 1 - src/interpreter/interpreter.cc | 18 +--- src/parsing/parser.cc | 2 +- 10 files changed, 172 insertions(+), 117 deletions(-) diff --git a/src/ast/ast-value-factory.cc b/src/ast/ast-value-factory.cc index 9742af0296..458afb8bc1 100644 --- a/src/ast/ast-value-factory.cc +++ b/src/ast/ast-value-factory.cc @@ -168,6 +168,20 @@ void AstConsString::Internalize(Isolate* isolate) { set_string(tmp); } +std::forward_list AstConsString::ToRawStrings() const { + std::forward_list result; + if (IsEmpty()) { + return result; + } + + result.emplace_front(segment_.string); + for (AstConsString::Segment* current = segment_.next; current != nullptr; + current = current->next) { + result.emplace_front(current->string); + } + return result; +} + AstStringConstants::AstStringConstants(Isolate* isolate, uint32_t hash_seed) : zone_(isolate->allocator(), ZONE_NAME), string_table_(AstRawString::Compare), diff --git a/src/ast/ast-value-factory.h b/src/ast/ast-value-factory.h index 6945c5bb61..643ccfef79 100644 --- a/src/ast/ast-value-factory.h +++ b/src/ast/ast-value-factory.h @@ -28,6 +28,8 @@ #ifndef V8_AST_AST_VALUE_FACTORY_H_ #define V8_AST_AST_VALUE_FACTORY_H_ +#include + #include "src/base/hashmap.h" #include "src/conversions.h" #include "src/factory.h" @@ -151,6 +153,8 @@ class AstConsString final : public ZoneObject { return Handle(string_); } + std::forward_list ToRawStrings() const; + private: friend class AstValueFactory; diff --git a/src/ast/ast.cc b/src/ast/ast.cc index d84c02d763..6f9753ba88 100644 --- a/src/ast/ast.cc +++ b/src/ast/ast.cc @@ -5,6 +5,7 @@ #include "src/ast/ast.h" #include // For isfinite. +#include #include "src/ast/compile-time-value.h" #include "src/ast/prettyprinter.h" @@ -248,6 +249,34 @@ bool FunctionLiteral::NeedsHomeObject(Expression* expr) { return expr->AsFunctionLiteral()->scope()->NeedsHomeObject(); } +std::unique_ptr FunctionLiteral::GetDebugName() const { + const AstConsString* cons_string; + if (raw_name_ != nullptr && !raw_name_->IsEmpty()) { + cons_string = raw_name_; + } else if (raw_inferred_name_ != nullptr && !raw_inferred_name_->IsEmpty()) { + cons_string = raw_inferred_name_; + } else if (!inferred_name_.is_null()) { + AllowHandleDereference allow_deref; + return inferred_name_->ToCString(); + } else { + return std::unique_ptr(new char{'\0'}); + } + + // TODO(rmcilroy): Deal with two-character strings. + std::vector result_vec; + std::forward_list strings = cons_string->ToRawStrings(); + for (const AstRawString* string : strings) { + if (!string->is_one_byte()) break; + for (int i = 0; i < string->length(); i++) { + result_vec.push_back(string->raw_data()[i]); + } + } + std::unique_ptr result(new char[result_vec.size() + 1]); + memcpy(result.get(), result_vec.data(), result_vec.size()); + result[result_vec.size()] = '\0'; + return result; +} + ObjectLiteralProperty::ObjectLiteralProperty(Expression* key, Expression* value, Kind kind, bool is_computed_name) : LiteralProperty(key, value, is_computed_name), diff --git a/src/ast/ast.h b/src/ast/ast.h index 6ddb42b152..3430d1432d 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -5,6 +5,8 @@ #ifndef V8_AST_AST_H_ #define V8_AST_AST_H_ +#include + #include "src/ast/ast-value-factory.h" #include "src/ast/modules.h" #include "src/ast/variables.h" @@ -2266,12 +2268,8 @@ class FunctionLiteral final : public Expression { return false; } - Handle debug_name() const { - if (raw_name_ != nullptr && !raw_name_->IsEmpty()) { - return raw_name_->string(); - } - return inferred_name(); - } + // Returns either name or inferred name as a cstring. + std::unique_ptr GetDebugName() const; Handle inferred_name() const { if (!inferred_name_.is_null()) { @@ -2292,6 +2290,8 @@ class FunctionLiteral final : public Expression { raw_inferred_name_ = nullptr; } + const AstConsString* raw_inferred_name() { return raw_inferred_name_; } + void set_raw_inferred_name(const AstConsString* raw_inferred_name) { DCHECK_NOT_NULL(raw_inferred_name); raw_inferred_name_ = raw_inferred_name; @@ -2550,6 +2550,7 @@ class ClassLiteral final : public Expression { class NativeFunctionLiteral final : public Expression { public: Handle name() const { return name_->string(); } + const AstRawString* raw_name() const { return name_; } v8::Extension* extension() const { return extension_; } private: diff --git a/src/ast/prettyprinter.cc b/src/ast/prettyprinter.cc index 89338ab30c..43b8068b1f 100644 --- a/src/ast/prettyprinter.cc +++ b/src/ast/prettyprinter.cc @@ -562,64 +562,70 @@ void AstPrinter::PrintLabels(ZoneList* labels) { } } -void AstPrinter::PrintLiteral(MaybeHandle maybe_value, bool quote) { - Handle value; - if (!maybe_value.ToHandle(&value)) { - Print(""); - return; - } - Object* object = *value; - if (object->IsString()) { - String* string = String::cast(object); - if (quote) Print("\""); - for (int i = 0; i < string->length(); i++) { - Print("%c", string->Get(i)); - } - if (quote) Print("\""); - } else if (object->IsNull(isolate_)) { - Print("null"); - } else if (object->IsTrue(isolate_)) { - Print("true"); - } else if (object->IsFalse(isolate_)) { - Print("false"); - } else if (object->IsUndefined(isolate_)) { - Print("undefined"); - } else if (object->IsNumber()) { - Print("%g", object->Number()); - } else if (object->IsJSObject()) { - // regular expression - if (object->IsJSFunction()) { - Print("JS-Function"); - } else if (object->IsJSArray()) { - Print("JS-array[%u]", Smi::ToInt(JSArray::cast(object)->length())); - } else if (object->IsJSObject()) { - Print("JS-Object"); - } else { - Print("?UNKNOWN?"); - } - } else if (object->IsFixedArray()) { - Print("FixedArray"); - } else if (object->IsSymbol()) { - // Symbols can only occur as literals if they were inserted by the parser. - Symbol* symbol = Symbol::cast(object); - if (symbol->name()->IsString()) { - int length = 0; - String* string = String::cast(symbol->name()); - std::unique_ptr desc = string->ToCString( - ALLOW_NULLS, FAST_STRING_TRAVERSAL, 0, string->length(), &length); - Print("Symbol(%*s)", length, desc.get()); - } else { - Print("Symbol()"); - } - } else { - Print("", static_cast(object)); +void AstPrinter::PrintLiteral(Literal* literal, bool quote) { + switch (literal->type()) { + case Literal::kString: + PrintLiteral(literal->AsRawString(), quote); + break; + case Literal::kSymbol: + const char* symbol; + switch (literal->AsSymbol()) { + case AstSymbol::kHomeObjectSymbol: + symbol = "HomeObjectSymbol"; + } + Print("%s", symbol); + break; + case Literal::kSmi: + Print("%d", Smi::ToInt(literal->AsSmiLiteral())); + break; + case Literal::kHeapNumber: + Print("%g", literal->AsNumber()); + break; + case Literal::kBigInt: + Print("%sn", literal->AsBigInt().c_str()); + break; + case Literal::kNull: + Print("null"); + break; + case Literal::kUndefined: + Print("undefined"); + break; + case Literal::kTheHole: + Print("the hole"); + break; + case Literal::kBoolean: + if (literal->ToBooleanIsTrue()) { + Print("true"); + } else { + Print("false"); + } + break; } } void AstPrinter::PrintLiteral(const AstRawString* value, bool quote) { - PrintLiteral(value->string(), quote); + if (quote) Print("\""); + if (value != nullptr) { + const char* format = value->is_one_byte() ? "%c" : "%lc"; + const int increment = value->is_one_byte() ? 1 : 2; + const unsigned char* raw_bytes = value->raw_data(); + for (int i = 0; i < value->length(); i += increment) { + Print(format, raw_bytes[i]); + } + } + if (quote) Print("\""); } +void AstPrinter::PrintLiteral(const AstConsString* value, bool quote) { + if (quote) Print("\""); + if (value != nullptr) { + std::forward_list strings = value->ToRawStrings(); + for (const AstRawString* string : strings) { + PrintLiteral(string, false); + } + } + if (quote) Print("\""); +} //----------------------------------------------------------------------------- @@ -650,9 +656,9 @@ class IndentedScope BASE_EMBEDDED { //----------------------------------------------------------------------------- -AstPrinter::AstPrinter(Isolate* isolate) - : isolate_(isolate), output_(nullptr), size_(0), pos_(0), indent_(0) { - InitializeAstVisitor(isolate); +AstPrinter::AstPrinter(uintptr_t stack_limit) + : output_(nullptr), size_(0), pos_(0), indent_(0) { + InitializeAstVisitor(stack_limit); } AstPrinter::~AstPrinter() { @@ -668,19 +674,32 @@ void AstPrinter::PrintIndented(const char* txt) { Print("%s", txt); } -void AstPrinter::PrintLiteralIndented(const char* info, - MaybeHandle maybe_value, +void AstPrinter::PrintLiteralIndented(const char* info, Literal* literal, bool quote) { PrintIndented(info); Print(" "); - PrintLiteral(maybe_value, quote); + PrintLiteral(literal, quote); Print("\n"); } +void AstPrinter::PrintLiteralIndented(const char* info, + const AstRawString* value, bool quote) { + PrintIndented(info); + Print(" "); + PrintLiteral(value, quote); + Print("\n"); +} -void AstPrinter::PrintLiteralWithModeIndented(const char* info, - Variable* var, - Handle value) { +void AstPrinter::PrintLiteralIndented(const char* info, + const AstConsString* value, bool quote) { + PrintIndented(info); + Print(" "); + PrintLiteral(value, quote); + Print("\n"); +} + +void AstPrinter::PrintLiteralWithModeIndented(const char* info, Variable* var, + const AstRawString* value) { if (var == nullptr) { PrintLiteralIndented(info, value, true); } else { @@ -715,8 +734,10 @@ const char* AstPrinter::PrintProgram(FunctionLiteral* program) { Print(" %d\n", program->kind()); PrintIndented("SUSPEND COUNT"); Print(" %d\n", program->suspend_count()); - PrintLiteralIndented("NAME", program->name(), true); - PrintLiteralIndented("INFERRED NAME", program->inferred_name(), true); + PrintLiteralIndented("NAME", program->raw_name(), true); + if (program->raw_inferred_name()) { + PrintLiteralIndented("INFERRED NAME", program->raw_inferred_name(), true); + } PrintParameters(program->scope()); PrintDeclarations(program->scope()->declarations()); PrintStatements(program->body()); @@ -726,7 +747,7 @@ const char* AstPrinter::PrintProgram(FunctionLiteral* program) { void AstPrinter::PrintOut(Isolate* isolate, AstNode* node) { - AstPrinter printer(isolate); + AstPrinter printer(isolate->stack_guard()->real_climit()); printer.Init(); printer.Visit(node); PrintF("%s", printer.output_); @@ -744,7 +765,7 @@ void AstPrinter::PrintParameters(DeclarationScope* scope) { IndentedScope indent(this, "PARAMS"); for (int i = 0; i < scope->num_parameters(); i++) { PrintLiteralWithModeIndented("VAR", scope->parameter(i), - scope->parameter(i)->name()); + scope->parameter(i)->raw_name()); } } } @@ -775,16 +796,16 @@ void AstPrinter::VisitBlock(Block* node) { // TODO(svenpanne) Start with IndentedScope. void AstPrinter::VisitVariableDeclaration(VariableDeclaration* node) { PrintLiteralWithModeIndented("VARIABLE", node->proxy()->var(), - node->proxy()->name()); + node->proxy()->raw_name()); } // TODO(svenpanne) Start with IndentedScope. void AstPrinter::VisitFunctionDeclaration(FunctionDeclaration* node) { PrintIndented("FUNCTION "); - PrintLiteral(node->proxy()->name(), true); + PrintLiteral(node->proxy()->raw_name(), true); Print(" = function "); - PrintLiteral(node->fun()->name(), false); + PrintLiteral(node->fun()->raw_name(), false); Print("\n"); } @@ -937,7 +958,7 @@ void AstPrinter::VisitTryCatchStatement(TryCatchStatement* node) { } Print(" %s\n", prediction); PrintLiteralWithModeIndented("CATCHVAR", node->scope()->catch_variable(), - node->scope()->catch_variable()->name()); + node->scope()->catch_variable()->raw_name()); PrintIndentedVisit("CATCH", node->catch_block()); } @@ -954,8 +975,8 @@ void AstPrinter::VisitDebuggerStatement(DebuggerStatement* node) { void AstPrinter::VisitFunctionLiteral(FunctionLiteral* node) { IndentedScope indent(this, "FUNC LITERAL", node->position()); - PrintLiteralIndented("NAME", node->name(), false); - PrintLiteralIndented("INFERRED NAME", node->inferred_name(), false); + PrintLiteralIndented("NAME", node->raw_name(), false); + PrintLiteralIndented("INFERRED NAME", node->raw_inferred_name(), false); PrintParameters(node->scope()); // We don't want to see the function literal in this case: it // will be printed via PrintProgram when the code for it is @@ -966,7 +987,7 @@ void AstPrinter::VisitFunctionLiteral(FunctionLiteral* node) { void AstPrinter::VisitClassLiteral(ClassLiteral* node) { IndentedScope indent(this, "CLASS LITERAL", node->position()); - PrintLiteralIndented("NAME", node->constructor()->name(), false); + PrintLiteralIndented("NAME", node->constructor()->raw_name(), false); if (node->extends() != nullptr) { PrintIndentedVisit("EXTENDS", node->extends()); } @@ -1010,7 +1031,7 @@ void AstPrinter::PrintClassProperties( void AstPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) { IndentedScope indent(this, "NATIVE FUNC LITERAL", node->position()); - PrintLiteralIndented("NAME", node->name(), false); + PrintLiteralIndented("NAME", node->raw_name(), false); } @@ -1029,15 +1050,13 @@ void AstPrinter::VisitConditional(Conditional* node) { void AstPrinter::VisitLiteral(Literal* node) { - // TODO(adamk): Teach Literal how to print its values without - // allocating on the heap. - PrintLiteralIndented("LITERAL", node->BuildValue(isolate_), true); + PrintLiteralIndented("LITERAL", node, true); } void AstPrinter::VisitRegExpLiteral(RegExpLiteral* node) { IndentedScope indent(this, "REGEXP LITERAL", node->position()); - PrintLiteralIndented("PATTERN", node->pattern(), false); + PrintLiteralIndented("PATTERN", node->raw_pattern(), false); int i = 0; EmbeddedVector buf; if (node->flags() & RegExp::kGlobal) buf[i++] = 'g'; @@ -1111,7 +1130,7 @@ void AstPrinter::VisitVariableProxy(VariableProxy* node) { if (!node->is_resolved()) { SNPrintF(buf + pos, " unresolved"); - PrintLiteralWithModeIndented(buf.start(), nullptr, node->name()); + PrintLiteralWithModeIndented(buf.start(), nullptr, node->raw_name()); } else { Variable* var = node->var(); switch (var->location()) { @@ -1134,7 +1153,7 @@ void AstPrinter::VisitVariableProxy(VariableProxy* node) { SNPrintF(buf + pos, " module"); break; } - PrintLiteralWithModeIndented(buf.start(), var, node->name()); + PrintLiteralWithModeIndented(buf.start(), var, node->raw_name()); } } @@ -1182,13 +1201,13 @@ void AstPrinter::VisitProperty(Property* node) { IndentedScope indent(this, buf.start(), node->position()); Visit(node->obj()); - Literal* literal = node->key()->AsLiteral(); - if (literal != nullptr && - literal->BuildValue(isolate_)->IsInternalizedString()) { - // TODO(adamk): Teach Literal how to print its values without - // allocating on the heap. - PrintLiteralIndented("NAME", literal->BuildValue(isolate_), false); + LhsKind property_kind = Property::GetAssignType(node); + if (property_kind == NAMED_PROPERTY || + property_kind == NAMED_SUPER_PROPERTY) { + PrintLiteralIndented("NAME", node->key()->AsLiteral(), false); } else { + DCHECK(property_kind == KEYED_PROPERTY || + property_kind == KEYED_SUPER_PROPERTY); PrintIndentedVisit("KEY", node->key()); } } diff --git a/src/ast/prettyprinter.h b/src/ast/prettyprinter.h index 58849a6052..97c2437877 100644 --- a/src/ast/prettyprinter.h +++ b/src/ast/prettyprinter.h @@ -64,7 +64,7 @@ class CallPrinter final : public AstVisitor { class AstPrinter final : public AstVisitor { public: - explicit AstPrinter(Isolate* isolate); + explicit AstPrinter(uintptr_t stack_limit); ~AstPrinter(); // The following routines print a node into a string. @@ -89,7 +89,8 @@ class AstPrinter final : public AstVisitor { void PrintLabels(ZoneList* labels); void PrintLiteral(const AstRawString* value, bool quote); - void PrintLiteral(MaybeHandle maybe_value, bool quote); + void PrintLiteral(const AstConsString* value, bool quote); + void PrintLiteral(Literal* literal, bool quote); void PrintIndented(const char* txt); void PrintIndentedVisit(const char* s, AstNode* node); @@ -98,11 +99,13 @@ class AstPrinter final : public AstVisitor { void PrintParameters(DeclarationScope* scope); void PrintArguments(ZoneList* arguments); void PrintCaseClause(CaseClause* clause); - void PrintLiteralIndented(const char* info, MaybeHandle maybe_value, + void PrintLiteralIndented(const char* info, Literal* literal, bool quote); + void PrintLiteralIndented(const char* info, const AstRawString* value, bool quote); - void PrintLiteralWithModeIndented(const char* info, - Variable* var, - Handle value); + void PrintLiteralIndented(const char* info, const AstConsString* value, + bool quote); + void PrintLiteralWithModeIndented(const char* info, Variable* var, + const AstRawString* value); void PrintLabelsIndented(ZoneList* labels); void PrintObjectProperties(ZoneList* properties); void PrintClassProperties(ZoneList* properties); @@ -112,7 +115,6 @@ class AstPrinter final : public AstVisitor { DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); - Isolate* isolate_; char* output_; // output string buffer int size_; // output_ size int pos_; // current printing position diff --git a/src/compilation-info.cc b/src/compilation-info.cc index 46128e729b..4a6562f200 100644 --- a/src/compilation-info.cc +++ b/src/compilation-info.cc @@ -130,8 +130,7 @@ bool CompilationInfo::has_simple_parameters() { std::unique_ptr CompilationInfo::GetDebugName() const { if (literal()) { - AllowHandleDereference allow_deref; - return literal()->debug_name()->ToCString(); + return literal()->GetDebugName(); } if (!shared_info().is_null()) { return shared_info()->DebugName()->ToCString(); diff --git a/src/flag-definitions.h b/src/flag-definitions.h index cc02ee01fa..70a24da7da 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -1042,7 +1042,6 @@ DEFINE_BOOL(enable_slow_asserts, false, // codegen-ia32.cc / codegen-arm.cc / macro-assembler-*.cc DEFINE_BOOL(print_ast, false, "print source AST") -DEFINE_BOOL(print_builtin_ast, false, "print source AST for builtins") DEFINE_BOOL(trap_on_abort, false, "replace aborts by breakpoints") // compiler.cc diff --git a/src/interpreter/interpreter.cc b/src/interpreter/interpreter.cc index 7c8b3b6b1e..4e81ccf660 100644 --- a/src/interpreter/interpreter.cc +++ b/src/interpreter/interpreter.cc @@ -163,20 +163,7 @@ void Interpreter::IterateDispatchTable(RootVisitor* v) { namespace { void MaybePrintAst(ParseInfo* parse_info, CompilationInfo* compilation_info) { - Isolate* isolate = compilation_info->isolate(); - bool print_ast = isolate->bootstrapper()->IsActive() ? FLAG_print_builtin_ast - : FLAG_print_ast; - if (!print_ast) return; - - // Requires internalizing the AST, so make sure we are on the main thread and - // allow handle dereference and allocations. - // TODO(rmcilroy): Make ast-printer print ast raw strings instead of - // internalized strings to avoid internalizing here. - DCHECK(ThreadId::Current().Equals(isolate->thread_id())); - AllowHandleDereference allow_deref; - AllowHandleAllocation allow_handles; - AllowHeapAllocation allow_gc; - parse_info->ast_value_factory()->Internalize(isolate); + if (!FLAG_print_ast) return; OFStream os(stdout); std::unique_ptr name = compilation_info->GetDebugName(); @@ -184,7 +171,8 @@ void MaybePrintAst(ParseInfo* parse_info, CompilationInfo* compilation_info) { << compilation_info->GetDebugName().get() << "]" << std::endl; #ifdef DEBUG os << "--- AST ---" << std::endl - << AstPrinter(isolate).PrintProgram(compilation_info->literal()) + << AstPrinter(parse_info->stack_limit()) + .PrintProgram(compilation_info->literal()) << std::endl; #endif // DEBUG } diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc index 8944686a90..7f0abf680b 100644 --- a/src/parsing/parser.cc +++ b/src/parsing/parser.cc @@ -778,7 +778,7 @@ FunctionLiteral* Parser::ParseFunction(Isolate* isolate, ParseInfo* info, double ms = timer.Elapsed().InMillisecondsF(); // We need to make sure that the debug-name is available. ast_value_factory()->Internalize(isolate); - std::unique_ptr name_chars = result->debug_name()->ToCString(); + std::unique_ptr name_chars = result->GetDebugName(); PrintF("[parsing function: %s - took %0.3f ms]\n", name_chars.get(), ms); } return result;