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 @@
namespace v8 {
namespace internal {
CallPrinter::CallPrinter(Isolate* isolate) {
CallPrinter::CallPrinter(Isolate* isolate, bool is_builtin) {
output_ = NULL;
size_ = 0;
pos_ = 0;
position_ = 0;
found_ = false;
done_ = false;
is_builtin_ = is_builtin;
InitializeAstVisitor(isolate);
}
......@@ -192,8 +193,9 @@ void CallPrinter::VisitForInStatement(ForInStatement* node) {
void CallPrinter::VisitForOfStatement(ForOfStatement* node) {
Find(node->each());
Find(node->iterable());
Find(node->assign_iterator());
Find(node->body());
Find(node->next_result());
}
......@@ -239,13 +241,13 @@ void CallPrinter::VisitConditional(Conditional* node) {
void CallPrinter::VisitLiteral(Literal* node) {
PrintLiteral(node->value(), true);
PrintLiteral(*node->value(), true);
}
void CallPrinter::VisitRegExpLiteral(RegExpLiteral* node) {
Print("/");
PrintLiteral(node->pattern(), false);
PrintLiteral(*node->pattern(), false);
Print("/");
if (node->flags() & RegExp::kGlobal) Print("g");
if (node->flags() & RegExp::kIgnoreCase) Print("i");
......@@ -273,7 +275,12 @@ void CallPrinter::VisitArrayLiteral(ArrayLiteral* 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) {
if (literal != NULL && literal->value()->IsInternalizedString()) {
Find(node->obj(), true);
Print(".");
PrintLiteral(literal->value(), false);
PrintLiteral(*literal->value(), false);
} else {
Find(node->obj(), true);
Print("[");
......@@ -307,7 +314,15 @@ void CallPrinter::VisitProperty(Property* node) {
void CallPrinter::VisitCall(Call* node) {
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);
if (!was_found) Print("(...)");
FindArguments(node->arguments());
......@@ -317,7 +332,15 @@ void CallPrinter::VisitCall(Call* node) {
void CallPrinter::VisitCallNew(CallNew* node) {
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);
FindArguments(node->arguments());
if (was_found) done_ = true;
......@@ -413,14 +436,11 @@ void CallPrinter::FindArguments(ZoneList<Expression*>* arguments) {
}
void CallPrinter::PrintLiteral(Handle<Object> value, bool quote) {
Object* object = *value;
void CallPrinter::PrintLiteral(Object* value, bool quote) {
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));
}
Print("%s", String::cast(object)->ToCString().get());
if (quote) Print("\"");
} else if (object->IsNull()) {
Print("null");
......@@ -432,12 +452,15 @@ void CallPrinter::PrintLiteral(Handle<Object> value, bool quote) {
Print("undefined");
} else if (object->IsNumber()) {
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) {
PrintLiteral(value->string(), quote);
PrintLiteral(*value->string(), quote);
}
......
......@@ -13,7 +13,7 @@ namespace internal {
class CallPrinter : public AstVisitor {
public:
explicit CallPrinter(Isolate* isolate);
explicit CallPrinter(Isolate* isolate, bool is_builtin);
virtual ~CallPrinter();
// The following routine prints the node with position |position| into a
......@@ -37,11 +37,12 @@ class CallPrinter : public AstVisitor {
int position_; // position of ast node to print
bool found_;
bool done_;
bool is_builtin_;
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
protected:
void PrintLiteral(Handle<Object> value, bool quote);
void PrintLiteral(Object* value, bool quote);
void PrintLiteral(const AstRawString* value, bool quote);
void FindStatements(ZoneList<Statement*>* statements);
void FindArguments(ZoneList<Expression*>* arguments);
......
......@@ -852,10 +852,9 @@ Expression* ParserTraits::ExpressionFromString(int pos, Scanner* scanner,
Expression* ParserTraits::GetIterator(Expression* iterable,
AstNodeFactory* factory) {
AstNodeFactory* factory, int pos) {
Expression* iterator_symbol_literal =
factory->NewSymbolLiteral("iterator_symbol", RelocInfo::kNoPosition);
int pos = iterable->position();
Expression* prop =
factory->NewProperty(iterable, iterator_symbol_literal, pos);
Zone* zone = parser_->zone();
......@@ -3339,17 +3338,22 @@ void Parser::InitializeForEachStatement(ForEachStatement* stmt,
Expression* assign_each;
// 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(
Token::ASSIGN, factory()->NewVariableProxy(iterator),
GetIterator(subject, factory()), subject->position());
GetIterator(subject, factory(), subject->position() - 2),
subject->position());
// !%_IsJSReceiver(result = iterator.next()) &&
// %ThrowIteratorResultNotAnObject(result)
{
// result = iterator.next()
Expression* iterator_proxy = factory()->NewVariableProxy(iterator);
next_result =
BuildIteratorNextResult(iterator_proxy, result, subject->position());
// Hackily disambiguate o from o.next and o [Symbol.iterator]().
// TODO(verwaest): Come up with a better solution.
next_result = BuildIteratorNextResult(iterator_proxy, result,
subject->position() - 1);
}
// result.done
......
......@@ -784,7 +784,8 @@ class ParserTraits {
Scope* scope, AstNodeFactory* factory);
Expression* ExpressionFromString(int pos, Scanner* scanner,
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) {
return new(zone) ZoneList<v8::internal::Expression*>(size, zone);
}
......
......@@ -251,7 +251,7 @@ void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) {
zone());
auto iterator = CreateTempVar(descriptor_->parser->GetIterator(
factory()->NewVariableProxy(temp), factory()));
factory()->NewVariableProxy(temp), factory(), RelocInfo::kNoPosition));
auto done = CreateTempVar(
factory()->NewBooleanLiteral(false, RelocInfo::kNoPosition));
auto result = CreateTempVar();
......
......@@ -1645,7 +1645,7 @@ class PreParserTraits {
PreParserFactory* factory = NULL);
PreParserExpression GetIterator(PreParserExpression iterable,
PreParserFactory* factory) {
PreParserFactory* factory, int pos) {
return PreParserExpression::Default();
}
......@@ -3120,8 +3120,12 @@ ParserBase<Traits>::ParseYieldExpression(ExpressionClassifier* classifier,
}
if (kind == Yield::kDelegating) {
// 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 =
factory()->NewYield(generator_object, expression, kind, pos);
return yield;
......
......@@ -388,18 +388,44 @@ RUNTIME_FUNCTION(Runtime_HarmonyToString) {
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) {
MessageLocation location;
if (isolate->ComputeLocation(&location)) {
if (ComputeLocation(isolate, &location)) {
Zone zone;
base::SmartPointer<ParseInfo> info(
location.function()->shared()->is_function()
? new ParseInfo(&zone, location.function())
: new ParseInfo(&zone, location.script()));
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());
return isolate->factory()->NewStringFromAsciiChecked(string);
if (strlen(string) > 0) {
return isolate->factory()->NewStringFromAsciiChecked(string);
}
} else {
isolate->clear_pending_exception();
}
......
......@@ -48,7 +48,7 @@ function listener(event, exec_state, event_data, data) {
} else if (expected_events == 0) {
// All of the frames on the stack are from native Javascript.
assertEquals(0, exec_state.frameCount());
assertEquals("undefined is not a function",
assertEquals("(var).reject is not a function",
event_data.exception().message);
} else {
assertUnreachable();
......
......@@ -86,6 +86,9 @@ Debug.setListener(null); // Break z
print("log:\n"+ JSON.stringify(log));
// The let declaration differs from var in that the loop variable
// 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 = [
// Entry
"a2","b2",
......@@ -99,12 +102,12 @@ var expected = [
"f12","f7","F4","f7","F4","f7","F4","f7",
// For-in-let: get enumerable, next, body, next, ...
"g16","g11","G4","g11","G4","g11","G4","g11",
// For-of-var: next(), body, next(), body, ...
"h16","H4","h16","H4","h16","H4","h16",
// For-of: next(), body, next(), body, ...
"i12","I4","i12","I4","i12","I4","i12",
// For-of-let: next(), body, next(), ...
"j16","J4","j16","J4","j16","J4","j16",
// For-of-var: [Symbol.iterator](), next(), body, next(), body, ...
"h16","h14","h15","H4","h15","H4","h15","H4","h15",
// For-of: [Symbol.iterator](), next(), body, next(), body, ...
"i12","i10","i11","I4","i11","I4","i11","I4","i11",
// For-of-let: [Symbol.iterator](), next(), body, next(), ...
"j16","j14","j15","J4","j15","J4","j15","J4","j15",
// For-var: var decl, condition, body, next, condition, body, ...
"k7","k20","K4","k26","k20","K4","k26","k20","K4","k26","k20",
// 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
PASS [1].toString() is '1'
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/].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 successfullyParsed is true
......
......@@ -83,7 +83,7 @@ PASS tests[i](nativeJSON) is tests[i](JSON)
function (jsonObject){
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){
return jsonObject.stringify({toJSON: Date.prototype.toJSON, toISOString: function(){ return "custom toISOString"; }});
}
......@@ -101,7 +101,7 @@ function (jsonObject){
d.toISOString = null;
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){
var d = new Date(0);
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