Commit 961add84 authored by Franziska Hinkelmann's avatar Franziska Hinkelmann Committed by Commit Bot

[type-profile] Collect types for parameters.

Add the source position to variables if they are parameters.

Collect type information for parameters and return values. 
Index the types by their corresponding source position. For the
types of return values, use the function end as source position.


Sample output for a function with 2 parameters (at source
position 252 and 258, and function end at 443)
*************
Function: testFunction
252:
Object
number
string
number
258:
undefined
boolean
undefined
undefined
443:
Object
number
string
number
*************



BUG=v8:5933

Change-Id: I3b8749afcac706c1834146abf1b5b4a3fd130fb6
Reviewed-on: https://chromium-review.googlesource.com/461919Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Reviewed-by: 's avatarMarja Hölttä <marja@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Commit-Queue: Franziska Hinkelmann <franzih@chromium.org>
Cr-Commit-Position: refs/heads/master@{#44299}
parent 2a7ab875
...@@ -1008,7 +1008,7 @@ Variable* Scope::Lookup(const AstRawString* name) { ...@@ -1008,7 +1008,7 @@ Variable* Scope::Lookup(const AstRawString* name) {
Variable* DeclarationScope::DeclareParameter( Variable* DeclarationScope::DeclareParameter(
const AstRawString* name, VariableMode mode, bool is_optional, bool is_rest, const AstRawString* name, VariableMode mode, bool is_optional, bool is_rest,
bool* is_duplicate, AstValueFactory* ast_value_factory) { bool* is_duplicate, AstValueFactory* ast_value_factory, int position) {
DCHECK(!already_resolved_); DCHECK(!already_resolved_);
DCHECK(is_function_scope() || is_module_scope()); DCHECK(is_function_scope() || is_module_scope());
DCHECK(!has_rest_); DCHECK(!has_rest_);
...@@ -1025,6 +1025,7 @@ Variable* DeclarationScope::DeclareParameter( ...@@ -1025,6 +1025,7 @@ Variable* DeclarationScope::DeclareParameter(
*is_duplicate = IsDeclaredParameter(name); *is_duplicate = IsDeclaredParameter(name);
} }
has_rest_ = is_rest; has_rest_ = is_rest;
var->set_initializer_position(position);
params_.Add(var, zone()); params_.Add(var, zone());
if (name == ast_value_factory->arguments_string()) { if (name == ast_value_factory->arguments_string()) {
has_arguments_parameter_ = true; has_arguments_parameter_ = true;
......
...@@ -710,7 +710,7 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { ...@@ -710,7 +710,7 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
// expects all parameters to be declared and from left to right. // expects all parameters to be declared and from left to right.
Variable* DeclareParameter(const AstRawString* name, VariableMode mode, Variable* DeclareParameter(const AstRawString* name, VariableMode mode,
bool is_optional, bool is_rest, bool* is_duplicate, bool is_optional, bool is_rest, bool* is_duplicate,
AstValueFactory* ast_value_factory); AstValueFactory* ast_value_factory, int position);
// Declares that a parameter with the name exists. Creates a Variable and // Declares that a parameter with the name exists. Creates a Variable and
// returns it if FLAG_preparser_scope_analysis is on. // returns it if FLAG_preparser_scope_analysis is on.
......
...@@ -910,26 +910,68 @@ InlineCacheState CollectTypeProfileNexus::StateFromFeedback() const { ...@@ -910,26 +910,68 @@ InlineCacheState CollectTypeProfileNexus::StateFromFeedback() const {
return MONOMORPHIC; return MONOMORPHIC;
} }
void CollectTypeProfileNexus::Collect(Handle<Name> type, int position) { void CollectTypeProfileNexus::Collect(Handle<String> type, int position) {
DCHECK_GT(position, 0);
Isolate* isolate = GetIsolate(); Isolate* isolate = GetIsolate();
Object* const feedback = GetFeedback(); Object* const feedback = GetFeedback();
Handle<ArrayList> types;
// Map source position to collection of types
Handle<UnseededNumberDictionary> types;
if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) { if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
types = ArrayList::New(isolate, 1); types = UnseededNumberDictionary::NewEmpty(isolate);
} else { } else {
types = Handle<ArrayList>(ArrayList::cast(feedback), isolate); types = Handle<UnseededNumberDictionary>(
UnseededNumberDictionary::cast(feedback), isolate);
} }
Handle<Tuple2> entry = isolate->factory()->NewTuple2( Handle<ArrayList> types_for_position;
type, Handle<Smi>(Smi::FromInt(position), isolate));
if (types->Has(position)) {
int entry = types->FindEntry(position);
DCHECK(types->ValueAt(entry)->IsArrayList());
types_for_position =
Handle<ArrayList>(ArrayList::cast(types->ValueAt(entry)));
} else {
types_for_position = ArrayList::New(isolate, 1);
}
// TODO(franzih): Somehow sort this list. Either avoid duplicates types = UnseededNumberDictionary::Set(
// or use the common base type. types, position, ArrayList::Add(types_for_position, type));
SetFeedback(*ArrayList::Add(types, entry)); SetFeedback(*types);
} }
namespace {
void PrintTypes(Handle<ArrayList> s) {
for (int i = 0; i < s->Length(); i++) {
Object* entry = s->Get(i);
if (entry->IsString()) {
PrintF("%s\n", String::cast(entry)->ToCString().get());
}
}
}
void SortTypes(Isolate* isolate,
Handle<UnseededNumberDictionary> unsorted_types,
std::map<int, Handle<ArrayList>>* types) {
for (int index = UnseededNumberDictionary::kElementsStartIndex;
index < unsorted_types->length();
index += UnseededNumberDictionary::kEntrySize) {
int key_index = index + UnseededNumberDictionary::kEntryKeyIndex;
Object* key = unsorted_types->get(key_index);
if (key->IsSmi()) {
int value_index = index + UnseededNumberDictionary::kEntryValueIndex;
Handle<ArrayList> types_for_position = Handle<ArrayList>(
ArrayList::cast(unsorted_types->get(value_index)), isolate);
(*types)[Smi::cast(key)->value()] = types_for_position;
}
}
}
} // namespace
void CollectTypeProfileNexus::Print() const { void CollectTypeProfileNexus::Print() const {
Isolate* isolate = GetIsolate(); Isolate* isolate = GetIsolate();
...@@ -939,17 +981,16 @@ void CollectTypeProfileNexus::Print() const { ...@@ -939,17 +981,16 @@ void CollectTypeProfileNexus::Print() const {
return; return;
} }
Handle<ArrayList> list; Handle<UnseededNumberDictionary> unsorted_types =
list = Handle<ArrayList>(ArrayList::cast(feedback), isolate); Handle<UnseededNumberDictionary>(UnseededNumberDictionary::cast(feedback),
isolate);
std::map<int, Handle<ArrayList>> types;
SortTypes(isolate, unsorted_types, &types);
for (int i = 0; i < list->Length(); i++) { for (const auto& entry : types) {
Handle<Object> maybe_entry = Handle<Object>(list->Get(i), isolate); PrintF("%d:\n", entry.first);
DCHECK(maybe_entry->IsTuple2()); PrintTypes(entry.second);
Handle<Tuple2> entry = Handle<Tuple2>::cast(maybe_entry);
Handle<String> type =
Handle<String>(String::cast(entry->value1()), isolate);
int position = Smi::cast(entry->value2())->value();
PrintF("%d: %s\n", position, type->ToCString().get());
} }
} }
......
...@@ -760,7 +760,7 @@ class CollectTypeProfileNexus : public FeedbackNexus { ...@@ -760,7 +760,7 @@ class CollectTypeProfileNexus : public FeedbackNexus {
} }
// Add a type to the list of types. // Add a type to the list of types.
void Collect(Handle<Name> type, int position); void Collect(Handle<String> type, int position);
// Dump the types to stdout. // Dump the types to stdout.
// TODO(franzih): pass this information to the debugger protocol instead of // TODO(franzih): pass this information to the debugger protocol instead of
......
...@@ -762,6 +762,16 @@ void BytecodeGenerator::GenerateBytecodeBody() { ...@@ -762,6 +762,16 @@ void BytecodeGenerator::GenerateBytecodeBody() {
// Emit tracing call if requested to do so. // Emit tracing call if requested to do so.
if (FLAG_trace) builder()->CallRuntime(Runtime::kTraceEnter); if (FLAG_trace) builder()->CallRuntime(Runtime::kTraceEnter);
// Emit type profile call.
if (info()->literal()->feedback_vector_spec()->HasTypeProfileSlot()) {
int num_parameters = closure_scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
Register parameter(builder()->Parameter(i));
builder()->LoadAccumulatorWithRegister(parameter).CollectTypeProfile(
closure_scope()->parameter(i)->initializer_position());
}
}
// Visit declarations within the function scope. // Visit declarations within the function scope.
VisitDeclarations(closure_scope()->declarations()); VisitDeclarations(closure_scope()->declarations());
...@@ -2025,7 +2035,7 @@ void BytecodeGenerator::BuildReturn() { ...@@ -2025,7 +2035,7 @@ void BytecodeGenerator::BuildReturn() {
Runtime::kTraceExit, result); Runtime::kTraceExit, result);
} }
if (info()->literal()->feedback_vector_spec()->HasTypeProfileSlot()) { if (info()->literal()->feedback_vector_spec()->HasTypeProfileSlot()) {
builder()->CollectTypeProfile(info()->literal()->position()); builder()->CollectTypeProfile(info()->literal()->return_position());
} }
builder()->Return(); builder()->Return();
} }
......
...@@ -16754,6 +16754,10 @@ template Handle<SeededNumberDictionary> ...@@ -16754,6 +16754,10 @@ template Handle<SeededNumberDictionary>
Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape,
uint32_t>::NewEmpty(Isolate*, PretenureFlag pretenure); uint32_t>::NewEmpty(Isolate*, PretenureFlag pretenure);
template Handle<UnseededNumberDictionary>
Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
uint32_t>::NewEmpty(Isolate*, PretenureFlag pretenure);
template Handle<UnseededNumberDictionary> template Handle<UnseededNumberDictionary>
Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
uint32_t>::New(Isolate*, int at_least_space_for, uint32_t>::New(Isolate*, int at_least_space_for,
......
...@@ -192,7 +192,7 @@ FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name, ...@@ -192,7 +192,7 @@ FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name,
bool is_optional = false; bool is_optional = false;
Variable* constructor_args = function_scope->DeclareParameter( Variable* constructor_args = function_scope->DeclareParameter(
constructor_args_name, TEMPORARY, is_optional, is_rest, &is_duplicate, constructor_args_name, TEMPORARY, is_optional, is_rest, &is_duplicate,
ast_value_factory()); ast_value_factory(), pos);
ZoneList<Expression*>* args = ZoneList<Expression*>* args =
new (zone()) ZoneList<Expression*>(1, zone()); new (zone()) ZoneList<Expression*>(1, zone());
...@@ -707,8 +707,9 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) { ...@@ -707,8 +707,9 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) {
bool is_duplicate; bool is_duplicate;
bool is_rest = false; bool is_rest = false;
bool is_optional = false; bool is_optional = false;
auto var = scope->DeclareParameter(name, VAR, is_optional, is_rest, auto var =
&is_duplicate, ast_value_factory()); scope->DeclareParameter(name, VAR, is_optional, is_rest,
&is_duplicate, ast_value_factory(), beg_pos);
DCHECK(!is_duplicate); DCHECK(!is_duplicate);
var->AllocateTo(VariableLocation::PARAMETER, 0); var->AllocateTo(VariableLocation::PARAMETER, 0);
...@@ -892,7 +893,7 @@ FunctionLiteral* Parser::DoParseFunction(ParseInfo* info, ...@@ -892,7 +893,7 @@ FunctionLiteral* Parser::DoParseFunction(ParseInfo* info,
ParserFormalParameters formals(scope); ParserFormalParameters formals(scope);
{ {
// Parsing patterns as variable reference expression creates // Parsing patterns as variable reference expression creates
// NewUnresolved references in current scope. Entrer arrow function // NewUnresolved references in current scope. Enter arrow function
// scope for formal parameter parsing. // scope for formal parameter parsing.
BlockState block_state(&scope_, scope); BlockState block_state(&scope_, scope);
if (Check(Token::LPAREN)) { if (Check(Token::LPAREN)) {
......
...@@ -133,16 +133,18 @@ class Parser; ...@@ -133,16 +133,18 @@ class Parser;
struct ParserFormalParameters : FormalParametersBase { struct ParserFormalParameters : FormalParametersBase {
struct Parameter : public ZoneObject { struct Parameter : public ZoneObject {
Parameter(const AstRawString* name, Expression* pattern, Parameter(const AstRawString* name, Expression* pattern,
Expression* initializer, int initializer_end_position, Expression* initializer, int position,
bool is_rest) int initializer_end_position, bool is_rest)
: name(name), : name(name),
pattern(pattern), pattern(pattern),
initializer(initializer), initializer(initializer),
position(position),
initializer_end_position(initializer_end_position), initializer_end_position(initializer_end_position),
is_rest(is_rest) {} is_rest(is_rest) {}
const AstRawString* name; const AstRawString* name;
Expression* pattern; Expression* pattern;
Expression* initializer; Expression* initializer;
int position;
int initializer_end_position; int initializer_end_position;
bool is_rest; bool is_rest;
Parameter* next_parameter = nullptr; Parameter* next_parameter = nullptr;
...@@ -1081,9 +1083,10 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -1081,9 +1083,10 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
const AstRawString* name = has_simple_name const AstRawString* name = has_simple_name
? pattern->AsVariableProxy()->raw_name() ? pattern->AsVariableProxy()->raw_name()
: ast_value_factory()->empty_string(); : ast_value_factory()->empty_string();
auto parameter = auto parameter = new (parameters->scope->zone())
new (parameters->scope->zone()) ParserFormalParameters::Parameter( ParserFormalParameters::Parameter(name, pattern, initializer,
name, pattern, initializer, initializer_end_position, is_rest); scanner()->location().beg_pos,
initializer_end_position, is_rest);
parameters->params.Add(parameter); parameters->params.Add(parameter);
} }
...@@ -1103,7 +1106,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -1103,7 +1106,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
scope->DeclareParameter( scope->DeclareParameter(
is_simple ? parameter->name : ast_value_factory()->empty_string(), is_simple ? parameter->name : ast_value_factory()->empty_string(),
is_simple ? VAR : TEMPORARY, is_optional, parameter->is_rest, is_simple ? VAR : TEMPORARY, is_optional, parameter->is_rest,
&is_duplicate, ast_value_factory()); &is_duplicate, ast_value_factory(), parameter->position);
if (is_duplicate && if (is_duplicate &&
classifier()->is_valid_formal_parameter_list_without_duplicates()) { classifier()->is_valid_formal_parameter_list_without_duplicates()) {
classifier()->RecordDuplicateFormalParameterError( classifier()->RecordDuplicateFormalParameterError(
......
...@@ -707,7 +707,7 @@ RUNTIME_FUNCTION(Runtime_CollectTypeProfile) { ...@@ -707,7 +707,7 @@ RUNTIME_FUNCTION(Runtime_CollectTypeProfile) {
DCHECK(FLAG_type_profile); DCHECK(FLAG_type_profile);
Handle<Name> type = Object::TypeOf(isolate, value); Handle<String> type = Object::TypeOf(isolate, value);
if (value->IsJSReceiver()) { if (value->IsJSReceiver()) {
Handle<JSReceiver> object = Handle<JSReceiver>::cast(value); Handle<JSReceiver> object = Handle<JSReceiver>::cast(value);
type = JSReceiver::GetConstructorName(object); type = JSReceiver::GetConstructorName(object);
......
...@@ -60,4 +60,11 @@ testReturnOfNonVariable(); ...@@ -60,4 +60,11 @@ testReturnOfNonVariable();
function never_call() {} function never_call() {}
%PrintTypeProfile(never_call); %PrintTypeProfile(never_call);
throw "throw otherwise test fails with --stress-opt"; function check_param(a, bbb, ccccccccc, dddddddddddddddd) {
//nothing
}
check_param(2, 'foo', {}, new MyClass());
%PrintTypeProfile(check_param);
throw "end";
Function: testFunction Function: testFunction
246: Object 247:
246: number Object
246: string number
246: number string
number
254:
undefined
boolean
undefined
undefined
443:
Object
number
string
number
Function: testFunction Function: testFunction
246: Object 247:
246: number Object
246: string number
246: number string
246: undefined number
246: string undefined
246: Object string
246: Object Object
246: MyClass Object
MyClass
254:
undefined
boolean
undefined
undefined
undefined
boolean
boolean
undefined
undefined
443:
Object
number
string
number
undefined
string
Object
Object
MyClass
Function: try_finally Function: try_finally
956: string 1038:
string
Function: fall_off Function: fall_off
1105: undefined 1122:
undefined
*%(basename)s:63: throw otherwise test fails with --stress-opt Function: check_param
throw "throw otherwise test fails with --stress-opt"; 1272:
number
1275:
string
1280:
Object
1291:
MyClass
1323:
undefined
*%(basename)s:70: end
throw "end";
^ ^
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