Commit a6ed24d6 authored by verwaest's avatar verwaest Committed by Commit bot

Improve rendering of callsite with non-function target.

This hackily disambiguates multiple calls for the iterator protocols in ForOf / Yield* by adding -2 / -1 to the pos.

BUG=v8:3953
LOG=y

Review URL: https://codereview.chromium.org/1491923003

Cr-Commit-Position: refs/heads/master@{#32527}
parent 37c14558
...@@ -13,13 +13,14 @@ ...@@ -13,13 +13,14 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
CallPrinter::CallPrinter(Isolate* isolate) { CallPrinter::CallPrinter(Isolate* isolate, bool is_builtin) {
output_ = NULL; output_ = NULL;
size_ = 0; size_ = 0;
pos_ = 0; pos_ = 0;
position_ = 0; position_ = 0;
found_ = false; found_ = false;
done_ = false; done_ = false;
is_builtin_ = is_builtin;
InitializeAstVisitor(isolate); InitializeAstVisitor(isolate);
} }
...@@ -192,8 +193,9 @@ void CallPrinter::VisitForInStatement(ForInStatement* node) { ...@@ -192,8 +193,9 @@ void CallPrinter::VisitForInStatement(ForInStatement* node) {
void CallPrinter::VisitForOfStatement(ForOfStatement* node) { void CallPrinter::VisitForOfStatement(ForOfStatement* node) {
Find(node->each()); Find(node->each());
Find(node->iterable()); Find(node->assign_iterator());
Find(node->body()); Find(node->body());
Find(node->next_result());
} }
...@@ -239,13 +241,13 @@ void CallPrinter::VisitConditional(Conditional* node) { ...@@ -239,13 +241,13 @@ void CallPrinter::VisitConditional(Conditional* node) {
void CallPrinter::VisitLiteral(Literal* node) { void CallPrinter::VisitLiteral(Literal* node) {
PrintLiteral(node->value(), true); PrintLiteral(*node->value(), true);
} }
void CallPrinter::VisitRegExpLiteral(RegExpLiteral* node) { void CallPrinter::VisitRegExpLiteral(RegExpLiteral* node) {
Print("/"); Print("/");
PrintLiteral(node->pattern(), false); PrintLiteral(*node->pattern(), false);
Print("/"); Print("/");
if (node->flags() & RegExp::kGlobal) Print("g"); if (node->flags() & RegExp::kGlobal) Print("g");
if (node->flags() & RegExp::kIgnoreCase) Print("i"); if (node->flags() & RegExp::kIgnoreCase) Print("i");
...@@ -273,7 +275,12 @@ void CallPrinter::VisitArrayLiteral(ArrayLiteral* node) { ...@@ -273,7 +275,12 @@ void CallPrinter::VisitArrayLiteral(ArrayLiteral* node) {
void CallPrinter::VisitVariableProxy(VariableProxy* node) { void CallPrinter::VisitVariableProxy(VariableProxy* node) {
PrintLiteral(node->name(), false); if (is_builtin_) {
// Variable names of builtins are meaningless due to minification.
Print("(var)");
} else {
PrintLiteral(*node->name(), false);
}
} }
...@@ -295,7 +302,7 @@ void CallPrinter::VisitProperty(Property* node) { ...@@ -295,7 +302,7 @@ void CallPrinter::VisitProperty(Property* node) {
if (literal != NULL && literal->value()->IsInternalizedString()) { if (literal != NULL && literal->value()->IsInternalizedString()) {
Find(node->obj(), true); Find(node->obj(), true);
Print("."); Print(".");
PrintLiteral(literal->value(), false); PrintLiteral(*literal->value(), false);
} else { } else {
Find(node->obj(), true); Find(node->obj(), true);
Print("["); Print("[");
...@@ -307,7 +314,15 @@ void CallPrinter::VisitProperty(Property* node) { ...@@ -307,7 +314,15 @@ void CallPrinter::VisitProperty(Property* node) {
void CallPrinter::VisitCall(Call* node) { void CallPrinter::VisitCall(Call* node) {
bool was_found = !found_ && node->position() == position_; bool was_found = !found_ && node->position() == position_;
if (was_found) found_ = true; if (was_found) {
// Bail out if the error is caused by a direct call to a variable in builtin
// code. The variable name is meaningless due to minification.
if (is_builtin_ && node->expression()->IsVariableProxy()) {
done_ = true;
return;
}
found_ = true;
}
Find(node->expression(), true); Find(node->expression(), true);
if (!was_found) Print("(...)"); if (!was_found) Print("(...)");
FindArguments(node->arguments()); FindArguments(node->arguments());
...@@ -317,7 +332,15 @@ void CallPrinter::VisitCall(Call* node) { ...@@ -317,7 +332,15 @@ void CallPrinter::VisitCall(Call* node) {
void CallPrinter::VisitCallNew(CallNew* node) { void CallPrinter::VisitCallNew(CallNew* node) {
bool was_found = !found_ && node->position() == position_; bool was_found = !found_ && node->position() == position_;
if (was_found) found_ = true; if (was_found) {
// Bail out if the error is caused by a direct call to a variable in builtin
// code. The variable name is meaningless due to minification.
if (is_builtin_ && node->expression()->IsVariableProxy()) {
done_ = true;
return;
}
found_ = true;
}
Find(node->expression(), was_found); Find(node->expression(), was_found);
FindArguments(node->arguments()); FindArguments(node->arguments());
if (was_found) done_ = true; if (was_found) done_ = true;
...@@ -413,14 +436,11 @@ void CallPrinter::FindArguments(ZoneList<Expression*>* arguments) { ...@@ -413,14 +436,11 @@ void CallPrinter::FindArguments(ZoneList<Expression*>* arguments) {
} }
void CallPrinter::PrintLiteral(Handle<Object> value, bool quote) { void CallPrinter::PrintLiteral(Object* value, bool quote) {
Object* object = *value; Object* object = value;
if (object->IsString()) { if (object->IsString()) {
String* string = String::cast(object);
if (quote) Print("\""); if (quote) Print("\"");
for (int i = 0; i < string->length(); i++) { Print("%s", String::cast(object)->ToCString().get());
Print("%c", string->Get(i));
}
if (quote) Print("\""); if (quote) Print("\"");
} else if (object->IsNull()) { } else if (object->IsNull()) {
Print("null"); Print("null");
...@@ -432,12 +452,15 @@ void CallPrinter::PrintLiteral(Handle<Object> value, bool quote) { ...@@ -432,12 +452,15 @@ void CallPrinter::PrintLiteral(Handle<Object> value, bool quote) {
Print("undefined"); Print("undefined");
} else if (object->IsNumber()) { } else if (object->IsNumber()) {
Print("%g", object->Number()); Print("%g", object->Number());
} else if (object->IsSymbol()) {
// Symbols can only occur as literals if they were inserted by the parser.
PrintLiteral(Symbol::cast(object)->name(), false);
} }
} }
void CallPrinter::PrintLiteral(const AstRawString* value, bool quote) { void CallPrinter::PrintLiteral(const AstRawString* value, bool quote) {
PrintLiteral(value->string(), quote); PrintLiteral(*value->string(), quote);
} }
......
...@@ -13,7 +13,7 @@ namespace internal { ...@@ -13,7 +13,7 @@ namespace internal {
class CallPrinter : public AstVisitor { class CallPrinter : public AstVisitor {
public: public:
explicit CallPrinter(Isolate* isolate); explicit CallPrinter(Isolate* isolate, bool is_builtin);
virtual ~CallPrinter(); virtual ~CallPrinter();
// The following routine prints the node with position |position| into a // The following routine prints the node with position |position| into a
...@@ -37,11 +37,12 @@ class CallPrinter : public AstVisitor { ...@@ -37,11 +37,12 @@ class CallPrinter : public AstVisitor {
int position_; // position of ast node to print int position_; // position of ast node to print
bool found_; bool found_;
bool done_; bool done_;
bool is_builtin_;
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
protected: protected:
void PrintLiteral(Handle<Object> value, bool quote); void PrintLiteral(Object* value, bool quote);
void PrintLiteral(const AstRawString* value, bool quote); void PrintLiteral(const AstRawString* value, bool quote);
void FindStatements(ZoneList<Statement*>* statements); void FindStatements(ZoneList<Statement*>* statements);
void FindArguments(ZoneList<Expression*>* arguments); void FindArguments(ZoneList<Expression*>* arguments);
......
...@@ -852,10 +852,9 @@ Expression* ParserTraits::ExpressionFromString(int pos, Scanner* scanner, ...@@ -852,10 +852,9 @@ Expression* ParserTraits::ExpressionFromString(int pos, Scanner* scanner,
Expression* ParserTraits::GetIterator(Expression* iterable, Expression* ParserTraits::GetIterator(Expression* iterable,
AstNodeFactory* factory) { AstNodeFactory* factory, int pos) {
Expression* iterator_symbol_literal = Expression* iterator_symbol_literal =
factory->NewSymbolLiteral("iterator_symbol", RelocInfo::kNoPosition); factory->NewSymbolLiteral("iterator_symbol", RelocInfo::kNoPosition);
int pos = iterable->position();
Expression* prop = Expression* prop =
factory->NewProperty(iterable, iterator_symbol_literal, pos); factory->NewProperty(iterable, iterator_symbol_literal, pos);
Zone* zone = parser_->zone(); Zone* zone = parser_->zone();
...@@ -3339,17 +3338,22 @@ void Parser::InitializeForEachStatement(ForEachStatement* stmt, ...@@ -3339,17 +3338,22 @@ void Parser::InitializeForEachStatement(ForEachStatement* stmt,
Expression* assign_each; Expression* assign_each;
// iterator = subject[Symbol.iterator]() // iterator = subject[Symbol.iterator]()
// Hackily disambiguate o from o.next and o [Symbol.iterator]().
// TODO(verwaest): Come up with a better solution.
assign_iterator = factory()->NewAssignment( assign_iterator = factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(iterator), Token::ASSIGN, factory()->NewVariableProxy(iterator),
GetIterator(subject, factory()), subject->position()); GetIterator(subject, factory(), subject->position() - 2),
subject->position());
// !%_IsJSReceiver(result = iterator.next()) && // !%_IsJSReceiver(result = iterator.next()) &&
// %ThrowIteratorResultNotAnObject(result) // %ThrowIteratorResultNotAnObject(result)
{ {
// result = iterator.next() // result = iterator.next()
Expression* iterator_proxy = factory()->NewVariableProxy(iterator); Expression* iterator_proxy = factory()->NewVariableProxy(iterator);
next_result = // Hackily disambiguate o from o.next and o [Symbol.iterator]().
BuildIteratorNextResult(iterator_proxy, result, subject->position()); // TODO(verwaest): Come up with a better solution.
next_result = BuildIteratorNextResult(iterator_proxy, result,
subject->position() - 1);
} }
// result.done // result.done
......
...@@ -784,7 +784,8 @@ class ParserTraits { ...@@ -784,7 +784,8 @@ class ParserTraits {
Scope* scope, AstNodeFactory* factory); Scope* scope, AstNodeFactory* factory);
Expression* ExpressionFromString(int pos, Scanner* scanner, Expression* ExpressionFromString(int pos, Scanner* scanner,
AstNodeFactory* factory); AstNodeFactory* factory);
Expression* GetIterator(Expression* iterable, AstNodeFactory* factory); Expression* GetIterator(Expression* iterable, AstNodeFactory* factory,
int pos);
ZoneList<v8::internal::Expression*>* NewExpressionList(int size, Zone* zone) { ZoneList<v8::internal::Expression*>* NewExpressionList(int size, Zone* zone) {
return new(zone) ZoneList<v8::internal::Expression*>(size, zone); return new(zone) ZoneList<v8::internal::Expression*>(size, zone);
} }
......
...@@ -251,7 +251,7 @@ void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) { ...@@ -251,7 +251,7 @@ void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) {
zone()); zone());
auto iterator = CreateTempVar(descriptor_->parser->GetIterator( auto iterator = CreateTempVar(descriptor_->parser->GetIterator(
factory()->NewVariableProxy(temp), factory())); factory()->NewVariableProxy(temp), factory(), RelocInfo::kNoPosition));
auto done = CreateTempVar( auto done = CreateTempVar(
factory()->NewBooleanLiteral(false, RelocInfo::kNoPosition)); factory()->NewBooleanLiteral(false, RelocInfo::kNoPosition));
auto result = CreateTempVar(); auto result = CreateTempVar();
......
...@@ -1645,7 +1645,7 @@ class PreParserTraits { ...@@ -1645,7 +1645,7 @@ class PreParserTraits {
PreParserFactory* factory = NULL); PreParserFactory* factory = NULL);
PreParserExpression GetIterator(PreParserExpression iterable, PreParserExpression GetIterator(PreParserExpression iterable,
PreParserFactory* factory) { PreParserFactory* factory, int pos) {
return PreParserExpression::Default(); return PreParserExpression::Default();
} }
...@@ -3120,8 +3120,12 @@ ParserBase<Traits>::ParseYieldExpression(ExpressionClassifier* classifier, ...@@ -3120,8 +3120,12 @@ ParserBase<Traits>::ParseYieldExpression(ExpressionClassifier* classifier,
} }
if (kind == Yield::kDelegating) { if (kind == Yield::kDelegating) {
// var iterator = subject[Symbol.iterator](); // var iterator = subject[Symbol.iterator]();
expression = this->GetIterator(expression, factory()); // Hackily disambiguate o from o.next and o [Symbol.iterator]().
// TODO(verwaest): Come up with a better solution.
expression = this->GetIterator(expression, factory(), pos + 1);
} }
// Hackily disambiguate o from o.next and o [Symbol.iterator]().
// TODO(verwaest): Come up with a better solution.
typename Traits::Type::YieldExpression yield = typename Traits::Type::YieldExpression yield =
factory()->NewYield(generator_object, expression, kind, pos); factory()->NewYield(generator_object, expression, kind, pos);
return yield; return yield;
......
...@@ -388,18 +388,44 @@ RUNTIME_FUNCTION(Runtime_HarmonyToString) { ...@@ -388,18 +388,44 @@ RUNTIME_FUNCTION(Runtime_HarmonyToString) {
namespace { namespace {
bool ComputeLocation(Isolate* isolate, MessageLocation* target) {
JavaScriptFrameIterator it(isolate);
if (!it.done()) {
JavaScriptFrame* frame = it.frame();
JSFunction* fun = frame->function();
Object* script = fun->shared()->script();
if (script->IsScript() &&
!(Script::cast(script)->source()->IsUndefined())) {
Handle<Script> casted_script(Script::cast(script));
// Compute the location from the function and the relocation info of the
// baseline code. For optimized code this will use the deoptimization
// information to get canonical location information.
List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
it.frame()->Summarize(&frames);
FrameSummary& summary = frames.last();
int pos = summary.code()->SourcePosition(summary.pc());
*target = MessageLocation(casted_script, pos, pos + 1, handle(fun));
return true;
}
}
return false;
}
Handle<String> RenderCallSite(Isolate* isolate, Handle<Object> object) { Handle<String> RenderCallSite(Isolate* isolate, Handle<Object> object) {
MessageLocation location; MessageLocation location;
if (isolate->ComputeLocation(&location)) { if (ComputeLocation(isolate, &location)) {
Zone zone; Zone zone;
base::SmartPointer<ParseInfo> info( base::SmartPointer<ParseInfo> info(
location.function()->shared()->is_function() location.function()->shared()->is_function()
? new ParseInfo(&zone, location.function()) ? new ParseInfo(&zone, location.function())
: new ParseInfo(&zone, location.script())); : new ParseInfo(&zone, location.script()));
if (Parser::ParseStatic(info.get())) { if (Parser::ParseStatic(info.get())) {
CallPrinter printer(isolate); CallPrinter printer(isolate, location.function()->shared()->IsBuiltin());
const char* string = printer.Print(info->literal(), location.start_pos()); const char* string = printer.Print(info->literal(), location.start_pos());
return isolate->factory()->NewStringFromAsciiChecked(string); if (strlen(string) > 0) {
return isolate->factory()->NewStringFromAsciiChecked(string);
}
} else { } else {
isolate->clear_pending_exception(); isolate->clear_pending_exception();
} }
......
...@@ -48,7 +48,7 @@ function listener(event, exec_state, event_data, data) { ...@@ -48,7 +48,7 @@ function listener(event, exec_state, event_data, data) {
} else if (expected_events == 0) { } else if (expected_events == 0) {
// All of the frames on the stack are from native Javascript. // All of the frames on the stack are from native Javascript.
assertEquals(0, exec_state.frameCount()); assertEquals(0, exec_state.frameCount());
assertEquals("undefined is not a function", assertEquals("(var).reject is not a function",
event_data.exception().message); event_data.exception().message);
} else { } else {
assertUnreachable(); assertUnreachable();
......
...@@ -86,6 +86,9 @@ Debug.setListener(null); // Break z ...@@ -86,6 +86,9 @@ Debug.setListener(null); // Break z
print("log:\n"+ JSON.stringify(log)); print("log:\n"+ JSON.stringify(log));
// The let declaration differs from var in that the loop variable // The let declaration differs from var in that the loop variable
// is declared in every iteration. // is declared in every iteration.
// TODO(verwaest): For-of has hacky position numbers for Symbol.iterator and
// .next. Restore to proper positions once the CallPrinter can disambiguate
// based on other values.
var expected = [ var expected = [
// Entry // Entry
"a2","b2", "a2","b2",
...@@ -99,12 +102,12 @@ var expected = [ ...@@ -99,12 +102,12 @@ var expected = [
"f12","f7","F4","f7","F4","f7","F4","f7", "f12","f7","F4","f7","F4","f7","F4","f7",
// For-in-let: get enumerable, next, body, next, ... // For-in-let: get enumerable, next, body, next, ...
"g16","g11","G4","g11","G4","g11","G4","g11", "g16","g11","G4","g11","G4","g11","G4","g11",
// For-of-var: next(), body, next(), body, ... // For-of-var: [Symbol.iterator](), next(), body, next(), body, ...
"h16","H4","h16","H4","h16","H4","h16", "h16","h14","h15","H4","h15","H4","h15","H4","h15",
// For-of: next(), body, next(), body, ... // For-of: [Symbol.iterator](), next(), body, next(), body, ...
"i12","I4","i12","I4","i12","I4","i12", "i12","i10","i11","I4","i11","I4","i11","I4","i11",
// For-of-let: next(), body, next(), ... // For-of-let: [Symbol.iterator](), next(), body, next(), ...
"j16","J4","j16","J4","j16","J4","j16", "j16","j14","j15","J4","j15","J4","j15","J4","j15",
// For-var: var decl, condition, body, next, condition, body, ... // For-var: var decl, condition, body, next, condition, body, ...
"k7","k20","K4","k26","k20","K4","k26","k20","K4","k26","k20", "k7","k20","K4","k26","k20","K4","k26","k20","K4","k26","k20",
// For: init, condition, body, next, condition, body, ... // For: init, condition, body, next, condition, body, ...
......
...@@ -28,10 +28,10 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE ...@@ -28,10 +28,10 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
PASS [1].toString() is '1' PASS [1].toString() is '1'
PASS [1].toLocaleString() is 'toLocaleString' PASS [1].toLocaleString() is 'toLocaleString'
FAIL [1].toLocaleString() should be 1. Threw exception TypeError: [1].toLocaleString is not a function FAIL [1].toLocaleString() should be 1. Threw exception TypeError: (var).toLocaleString is not a function
PASS [/r/].toString() is 'toString2' PASS [/r/].toString() is 'toString2'
PASS [/r/].toLocaleString() is 'toLocaleString2' PASS [/r/].toLocaleString() is 'toLocaleString2'
FAIL [/r/].toLocaleString() should be toString2. Threw exception TypeError: [/r/].toLocaleString is not a function FAIL [/r/].toLocaleString() should be toString2. Threw exception TypeError: (var).toLocaleString is not a function
PASS caught is true PASS caught is true
PASS successfullyParsed is true PASS successfullyParsed is true
......
...@@ -83,7 +83,7 @@ PASS tests[i](nativeJSON) is tests[i](JSON) ...@@ -83,7 +83,7 @@ PASS tests[i](nativeJSON) is tests[i](JSON)
function (jsonObject){ function (jsonObject){
return jsonObject.stringify({toJSON: Date.prototype.toJSON}); return jsonObject.stringify({toJSON: Date.prototype.toJSON});
} }
PASS tests[i](nativeJSON) threw exception TypeError: jsonObject.stringify is not a function. PASS tests[i](nativeJSON) threw exception TypeError: (var).toISOString is not a function.
function (jsonObject){ function (jsonObject){
return jsonObject.stringify({toJSON: Date.prototype.toJSON, toISOString: function(){ return "custom toISOString"; }}); return jsonObject.stringify({toJSON: Date.prototype.toJSON, toISOString: function(){ return "custom toISOString"; }});
} }
...@@ -101,7 +101,7 @@ function (jsonObject){ ...@@ -101,7 +101,7 @@ function (jsonObject){
d.toISOString = null; d.toISOString = null;
return jsonObject.stringify(d); return jsonObject.stringify(d);
} }
PASS tests[i](nativeJSON) threw exception TypeError: jsonObject.stringify is not a function. PASS tests[i](nativeJSON) threw exception TypeError: (var).toISOString is not a function.
function (jsonObject){ function (jsonObject){
var d = new Date(0); var d = new Date(0);
d.toJSON = undefined; d.toJSON = undefined;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment