'codegen.cc', 'compilation-cache.cc', 'compiler.cc', 'contexts.cc',
'conversions.cc', 'counters.cc', 'dateparser.cc', 'debug.cc',
'debug-agent.cc', 'disassembler.cc', 'execution.cc', 'factory.cc',
- 'flags.cc', 'frames.cc', 'global-handles.cc', 'handles.cc', 'hashmap.cc',
+ 'flags.cc', 'frames.cc', 'func-name-inferrer.cc',
+ 'global-handles.cc', 'handles.cc', 'hashmap.cc',
'heap.cc', 'ic.cc', 'interpreter-irregexp.cc', 'jsregexp.cc',
'jump-target.cc', 'log.cc', 'mark-compact.cc', 'messages.cc', 'objects.cc',
'oprofile-agent.cc', 'parser.cc', 'property.cc', 'regexp-macro-assembler.cc',
end_position_(end_position),
is_expression_(is_expression),
loop_nesting_(0),
- function_token_position_(RelocInfo::kNoPosition) {
+ function_token_position_(RelocInfo::kNoPosition),
+ inferred_name_(Heap::empty_string()) {
#ifdef DEBUG
already_compiled_ = false;
#endif
bool loop_nesting() const { return loop_nesting_; }
void set_loop_nesting(int nesting) { loop_nesting_ = nesting; }
+ Handle<String> inferred_name() const { return inferred_name_; }
+ void set_inferred_name(Handle<String> inferred_name) {
+ inferred_name_ = inferred_name;
+ }
+
#ifdef DEBUG
void mark_as_compiled() {
ASSERT(!already_compiled_);
bool is_expression_;
int loop_nesting_;
int function_token_position_;
+ Handle<String> inferred_name_;
#ifdef DEBUG
bool already_compiled_;
#endif
int end_position,
bool is_expression,
bool is_toplevel,
- Handle<Script> script);
+ Handle<Script> script,
+ Handle<String> inferred_name);
// Accessors
MacroAssembler* masm() { return masm_; }
int end_position,
bool is_expression,
bool is_toplevel,
- Handle<Script> script);
+ Handle<Script> script,
+ Handle<String> inferred_name);
// Accessors
MacroAssembler* masm() { return masm_; }
int end_position,
bool is_expression,
bool is_toplevel,
- Handle<Script> script) {
+ Handle<Script> script,
+ Handle<String> inferred_name) {
fun->shared()->set_length(length);
fun->shared()->set_formal_parameter_count(length);
fun->shared()->set_script(*script);
fun->shared()->set_end_position(end_position);
fun->shared()->set_is_expression(is_expression);
fun->shared()->set_is_toplevel(is_toplevel);
+ fun->shared()->set_inferred_name(*inferred_name);
}
CodeGenerator::SetFunctionInfo(function, node->num_parameters(),
node->function_token_position(),
node->start_position(), node->end_position(),
- node->is_expression(), false, script_);
+ node->is_expression(), false, script_,
+ node->inferred_name());
// Notify debugger that a new function has been added.
Debugger::OnNewFunction(function);
CodeGenerator::SetFunctionInfo(fun, lit->scope()->num_parameters(),
RelocInfo::kNoPosition,
lit->start_position(), lit->end_position(),
- lit->is_expression(), true, script);
+ lit->is_expression(), true, script,
+ lit->inferred_name());
// Hint to the runtime system used when allocating space for initial
// property space by setting the expected number of properties for
// name and line number. Check explicit whether logging is enabled as finding
// the line number is not for free.
if (Logger::is_enabled() || OProfileAgent::is_enabled()) {
+ Handle<String> func_name(lit->name()->length() > 0 ?
+ *lit->name() : shared->inferred_name());
if (script->name()->IsString()) {
int line_num = GetScriptLineNumber(script, start_position);
if (line_num > 0) {
line_num += script->line_offset()->value() + 1;
}
- LOG(CodeCreateEvent("LazyCompile", *code, *lit->name(),
+ LOG(CodeCreateEvent("LazyCompile", *code, *func_name,
String::cast(script->name()), line_num));
- OProfileAgent::CreateNativeCodeRegion(*lit->name(),
+ OProfileAgent::CreateNativeCodeRegion(*func_name,
String::cast(script->name()),
line_num, code->address(),
code->ExecutableSize());
} else {
- LOG(CodeCreateEvent("LazyCompile", *code, *lit->name()));
- OProfileAgent::CreateNativeCodeRegion(*lit->name(), code->address(),
+ LOG(CodeCreateEvent("LazyCompile", *code, *func_name));
+ OProfileAgent::CreateNativeCodeRegion(*func_name, code->address(),
code->ExecutableSize());
}
}
--- /dev/null
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "ast.h"
+#include "func-name-inferrer.h"
+
+namespace v8 { namespace internal {
+
+
+void FuncNameInferrer::PushEnclosingName(Handle<String> name) {
+ // Enclosing name is a name of a constructor function. To check
+ // that it is really a constructor, we check that it is not empty
+ // and starts with a capital letter.
+ if (name->length() > 0 && Runtime::IsUpperCaseChar(name->Get(0))) {
+ names_stack_.Add(name);
+ }
+}
+
+
+Handle<String> FuncNameInferrer::MakeNameFromStack() {
+ if (names_stack_.is_empty()) {
+ return Factory::empty_string();
+ } else {
+ return MakeNameFromStackHelper(1, names_stack_.at(0));
+ }
+}
+
+
+Handle<String> FuncNameInferrer::MakeNameFromStackHelper(int pos,
+ Handle<String> prev) {
+ if (pos >= names_stack_.length()) {
+ return prev;
+ } else {
+ Handle<String> curr = Factory::NewConsString(dot_, names_stack_.at(pos));
+ return MakeNameFromStackHelper(pos + 1, Factory::NewConsString(prev, curr));
+ }
+}
+
+
+void FuncNameInferrer::MaybeInferFunctionName() {
+ if (func_to_infer_ != NULL) {
+ func_to_infer_->set_inferred_name(MakeNameFromStack());
+ func_to_infer_ = NULL;
+ }
+}
+
+
+} } // namespace v8::internal
--- /dev/null
+// Copyright 2006-2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_FUNC_NAME_INFERRER_H_
+#define V8_FUNC_NAME_INFERRER_H_
+
+namespace v8 { namespace internal {
+
+// FuncNameInferrer is a stateful class that is used to perform name
+// inference for anonymous functions during static analysis of source code.
+// Inference is performed in cases when an anonymous function is assigned
+// to a variable or a property (see test-func-name-inference.cc for examples.)
+
+// The basic idea is that during AST traversal LHSs of expressions are
+// always visited before RHSs. Thus, during visiting the LHS, a name can be
+// collected, and during visiting the RHS, a function literal can be collected.
+// Inference is performed while leaving the assignment node.
+
+class FuncNameInferrer BASE_EMBEDDED {
+ public:
+ FuncNameInferrer() :
+ entries_stack_(10),
+ names_stack_(5),
+ func_to_infer_(NULL),
+ dot_(Factory::NewStringFromAscii(CStrVector("."))) {
+ }
+
+ bool IsOpen() const { return !entries_stack_.is_empty(); }
+
+ void PushEnclosingName(Handle<String> name);
+
+ void Enter() {
+ entries_stack_.Add(names_stack_.length());
+ }
+
+ void Leave() {
+ ASSERT(IsOpen());
+ names_stack_.Rewind(entries_stack_.RemoveLast());
+ }
+
+ void PushName(Handle<String> name) {
+ if (IsOpen()) {
+ names_stack_.Add(name);
+ }
+ }
+
+ void SetFuncToInfer(FunctionLiteral* func_to_infer) {
+ if (IsOpen()) {
+ ASSERT(func_to_infer_ == NULL);
+ func_to_infer_ = func_to_infer;
+ }
+ }
+
+ void InferAndLeave() {
+ ASSERT(IsOpen());
+ MaybeInferFunctionName();
+ Leave();
+ }
+
+ private:
+ Handle<String> MakeNameFromStack();
+ Handle<String> MakeNameFromStackHelper(int pos, Handle<String> prev);
+ void MaybeInferFunctionName();
+
+ List<int> entries_stack_;
+ List<Handle<String> > names_stack_;
+ FunctionLiteral* func_to_infer_;
+ Handle<String> dot_;
+
+ DISALLOW_COPY_AND_ASSIGN(FuncNameInferrer);
+};
+
+
+// A wrapper class that automatically calls InferAndLeave when
+// leaving scope.
+class ScopedFuncNameInferrer BASE_EMBEDDED {
+ public:
+ ScopedFuncNameInferrer(FuncNameInferrer* inferrer) : inferrer_(inferrer),
+ is_entered_(false) {};
+ ~ScopedFuncNameInferrer() {
+ if (is_entered_) {
+ inferrer_->InferAndLeave();
+ }
+ }
+
+ void Enter() {
+ inferrer_->Enter();
+ is_entered_ = true;
+ }
+
+ private:
+ FuncNameInferrer* inferrer_;
+ bool is_entered_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedFuncNameInferrer);
+};
+
+
+} } // namespace v8::internal
+
+#endif // V8_FUNC_NAME_INFERRER_H_
share->set_script(undefined_value());
share->set_start_position_and_type(0);
share->set_debug_info(undefined_value());
+ share->set_inferred_name(empty_string());
return result;
}
ACCESSORS(SharedFunctionInfo, lazy_load_data, Object, kLazyLoadDataOffset)
ACCESSORS(SharedFunctionInfo, script, Object, kScriptOffset)
ACCESSORS(SharedFunctionInfo, debug_info, Object, kDebugInfoOffset)
+ACCESSORS(SharedFunctionInfo, inferred_name, String, kInferredNameOffset)
BOOL_ACCESSORS(FunctionTemplateInfo, flag, hidden_prototype,
kHiddenPrototypeBit)
void SharedFunctionInfo::SharedFunctionInfoIterateBody(ObjectVisitor* v) {
IteratePointers(v, kNameOffset, kCodeOffset + kPointerSize);
IteratePointers(v, kInstanceClassNameOffset, kScriptOffset + kPointerSize);
- IteratePointer(v, kDebugInfoOffset);
+ IteratePointers(v, kDebugInfoOffset, kInferredNameOffset + kPointerSize);
}
// [debug info]: Debug information.
DECL_ACCESSORS(debug_info, Object)
+ // [inferred name]: Name inferred from variable or property
+ // assignment of this function. Used to facilitate debugging and
+ // profiling of JavaScript code written in OO style, where almost
+ // all functions are anonymous but are assigned to object
+ // properties.
+ DECL_ACCESSORS(inferred_name, String)
+
// Position of the 'function' token in the script source.
inline int function_token_position();
inline void set_function_token_position(int function_token_position);
static const int kEndPositionOffset = kStartPositionAndTypeOffset + kIntSize;
static const int kFunctionTokenPositionOffset = kEndPositionOffset + kIntSize;
static const int kDebugInfoOffset = kFunctionTokenPositionOffset + kIntSize;
- static const int kSize = kDebugInfoOffset + kPointerSize;
+ static const int kInferredNameOffset = kDebugInfoOffset + kPointerSize;
+ static const int kSize = kInferredNameOffset + kPointerSize;
private:
// Bit positions in length_and_flg.
Init();
{ IndentedScope indent("FUNC");
PrintLiteralIndented("NAME", program->name(), true);
+ PrintLiteralIndented("INFERRED NAME", program->inferred_name(), true);
PrintParameters(program->scope());
PrintDeclarations(program->scope()->declarations());
PrintStatements(program->body());
void AstPrinter::VisitFunctionLiteral(FunctionLiteral* node) {
IndentedScope indent("FUNC LITERAL");
PrintLiteralIndented("NAME", node->name(), false);
+ PrintLiteralIndented("INFERRED NAME", node->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
#include "v8.h"
#include "ast.h"
+#include "func-name-inferrer.h"
#include "scopes.h"
#include "rewriter.h"
class AstOptimizer: public AstVisitor {
public:
- explicit AstOptimizer() {
+ explicit AstOptimizer() {}
+ explicit AstOptimizer(Handle<String> enclosing_name) {
+ func_name_inferrer_.PushEnclosingName(enclosing_name);
}
void Optimize(ZoneList<Statement*>* statements);
// Used for loop condition analysis. Cleared before visiting a loop
// condition, set when a function literal is visited.
bool has_function_literal_;
+ // Helper object for function name inferring.
+ FuncNameInferrer func_name_inferrer_;
// Helpers
void OptimizeArguments(ZoneList<Expression*>* arguments);
void AstOptimizer::VisitFunctionLiteral(FunctionLiteral* node) {
- USE(node);
has_function_literal_ = true;
+
+ if (node->name()->length() == 0) {
+ // Anonymous function.
+ func_name_inferrer_.SetFuncToInfer(node);
+ }
}
} else if (node->type()->IsLikelySmi()) {
var->type()->SetAsLikelySmi();
}
+
+ if (!var->is_this() &&
+ !Heap::result_symbol()->Equals(*var->name())) {
+ func_name_inferrer_.PushName(var->name());
+ }
}
}
Handle<Object> literal = node->handle();
if (literal->IsSmi()) {
node->type()->SetAsLikelySmi();
+ } else if (literal->IsString()) {
+ Handle<String> lit_str(Handle<String>::cast(literal));
+ if (!Heap::prototype_symbol()->Equals(*lit_str)) {
+ func_name_inferrer_.PushName(lit_str);
+ }
}
}
}
}
-
void AstOptimizer::VisitObjectLiteral(ObjectLiteral* node) {
for (int i = 0; i < node->properties()->length(); i++) {
+ ScopedFuncNameInferrer scoped_fni(&func_name_inferrer_);
+ scoped_fni.Enter();
Visit(node->properties()->at(i)->key());
Visit(node->properties()->at(i)->value());
}
void AstOptimizer::VisitAssignment(Assignment* node) {
+ ScopedFuncNameInferrer scoped_fni(&func_name_inferrer_);
switch (node->op()) {
case Token::INIT_VAR:
case Token::INIT_CONST:
case Token::ASSIGN:
// No type can be infered from the general assignment.
+
+ if (node->value()->AsFunctionLiteral() != NULL ||
+ node->value()->AsObjectLiteral() != NULL) {
+ scoped_fni.Enter();
+ }
break;
case Token::ASSIGN_BIT_OR:
case Token::ASSIGN_BIT_XOR:
void AstOptimizer::VisitCallRuntime(CallRuntime* node) {
+ ScopedFuncNameInferrer scoped_fni(&func_name_inferrer_);
+ if (Factory::InitializeVarGlobal_symbol()->Equals(*node->name()) &&
+ node->arguments()->length() >= 2 &&
+ node->arguments()->at(1)->AsFunctionLiteral() != NULL) {
+ scoped_fni.Enter();
+ }
OptimizeArguments(node->arguments());
}
ZoneList<Statement*>* body = function->body();
if (FLAG_optimize_ast && !body->is_empty()) {
- Scope* scope = function->scope();
- if (!scope->is_global_scope()) {
- AstOptimizer optimizer;
- optimizer.Optimize(body);
- if (optimizer.HasStackOverflow()) {
- return false;
- }
+ AstOptimizer optimizer(function->name());
+ optimizer.Optimize(body);
+ if (optimizer.HasStackOverflow()) {
+ return false;
}
}
return true;
}
+bool Runtime::IsUpperCaseChar(uint16_t ch) {
+ unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
+ int char_length = to_upper_mapping.get(ch, 0, chars);
+ return char_length == 0;
+}
+
+
static Object* Runtime_NumberToString(Arguments args) {
NoHandleAllocation ha;
ASSERT(args.length() == 1);
}
-static Object* FindSharedFunctionInfoInScript(Handle<Script> script,
- int position) {
+Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
+ int position) {
// Iterate the heap looking for SharedFunctionInfo generated from the
// script. The inner most SharedFunctionInfo containing the source position
// for the requested break point is found.
RUNTIME_ASSERT(wrapper->value()->IsScript());
Handle<Script> script(Script::cast(wrapper->value()));
- Object* result = FindSharedFunctionInfoInScript(script, source_position);
+ Object* result = Runtime::FindSharedFunctionInfoInScript(
+ script, source_position);
if (!result->IsUndefined()) {
Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
// Find position within function. The script position might be before the
static int StringMatch(Handle<String> sub, Handle<String> pat, int index);
+ static bool IsUpperCaseChar(uint16_t ch);
+
// TODO(1240886): The following three methods are *not* handle safe,
// but accept handle arguments. This seems fragile.
static Object* GetObjectProperty(Handle<Object> object, Handle<Object> key);
+ // This function is used in FunctionNameUsing* tests.
+ static Object* FindSharedFunctionInfoInScript(Handle<Script> script,
+ int position);
+
// Helper functions used stubs.
static void PerformGC(Object* result);
};
'test-debug.cc',
'test-decls.cc',
'test-flags.cc',
+ 'test-func-name-inference.cc',
'test-hashmap.cc',
'test-heap.cc',
'test-list.cc',
--- /dev/null
+// Copyright 2007-2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "api.h"
+#include "runtime.h"
+#include "cctest.h"
+
+
+using ::v8::internal::Handle;
+using ::v8::internal::JSFunction;
+using ::v8::internal::Object;
+using ::v8::internal::Script;
+using ::v8::internal::SharedFunctionInfo;
+using ::v8::internal::String;
+
+namespace i = ::v8::internal;
+
+
+static v8::Persistent<v8::Context> env;
+
+
+static void InitializeVM() {
+ if (env.IsEmpty()) {
+ v8::HandleScope scope;
+ env = v8::Context::New();
+ }
+ v8::HandleScope scope;
+ env->Enter();
+}
+
+
+static void CheckFunctionName(v8::Handle<v8::Script> script,
+ const char* func_pos_src,
+ const char* ref_inferred_name) {
+ // Get script source.
+ Handle<JSFunction> fun = v8::Utils::OpenHandle(*script);
+ Handle<Script> i_script(Script::cast(fun->shared()->script()));
+ CHECK(i_script->source()->IsString());
+ Handle<String> script_src(String::cast(i_script->source()));
+
+ // Find the position of a given func source substring in the source.
+ Handle<String> func_pos_str =
+ i::Factory::NewStringFromAscii(i::CStrVector(func_pos_src));
+ int func_pos = i::Runtime::StringMatch(script_src, func_pos_str, 0);
+ CHECK_NE(0, func_pos);
+
+ // Obtain SharedFunctionInfo for the function.
+ Object* shared_func_info_ptr =
+ i::Runtime::FindSharedFunctionInfoInScript(i_script, func_pos);
+ CHECK(shared_func_info_ptr != i::Heap::undefined_value());
+ Handle<SharedFunctionInfo> shared_func_info(
+ SharedFunctionInfo::cast(shared_func_info_ptr));
+
+ // Verify inferred function name.
+ i::SmartPointer<char> inferred_name =
+ shared_func_info->inferred_name()->ToCString();
+ CHECK_EQ(ref_inferred_name, *inferred_name);
+}
+
+
+static v8::Handle<v8::Script> Compile(const char* src) {
+ return v8::Script::Compile(v8::String::New(src));
+}
+
+
+TEST(GlobalProperty) {
+ InitializeVM();
+ v8::HandleScope scope;
+
+ v8::Handle<v8::Script> script = Compile(
+ "fun1 = function() { return 1; }\n"
+ "fun2 = function() { return 2; }\n");
+ CheckFunctionName(script, "return 1", "fun1");
+ CheckFunctionName(script, "return 2", "fun2");
+}
+
+
+TEST(GlobalVar) {
+ InitializeVM();
+ v8::HandleScope scope;
+
+ v8::Handle<v8::Script> script = Compile(
+ "var fun1 = function() { return 1; }\n"
+ "var fun2 = function() { return 2; }\n");
+ CheckFunctionName(script, "return 1", "fun1");
+ CheckFunctionName(script, "return 2", "fun2");
+}
+
+
+TEST(LocalVar) {
+ InitializeVM();
+ v8::HandleScope scope;
+
+ v8::Handle<v8::Script> script = Compile(
+ "function outer() {\n"
+ " var fun1 = function() { return 1; }\n"
+ " var fun2 = function() { return 2; }\n"
+ "}");
+ CheckFunctionName(script, "return 1", "fun1");
+ CheckFunctionName(script, "return 2", "fun2");
+}
+
+
+TEST(InConstructor) {
+ InitializeVM();
+ v8::HandleScope scope;
+
+ v8::Handle<v8::Script> script = Compile(
+ "function MyClass() {\n"
+ " this.method1 = function() { return 1; }\n"
+ " this.method2 = function() { return 2; }\n"
+ "}");
+ CheckFunctionName(script, "return 1", "MyClass.method1");
+ CheckFunctionName(script, "return 2", "MyClass.method2");
+}
+
+
+TEST(Factory) {
+ InitializeVM();
+ v8::HandleScope scope;
+
+ v8::Handle<v8::Script> script = Compile(
+ "function createMyObj() {\n"
+ " var obj = {};\n"
+ " obj.method1 = function() { return 1; }\n"
+ " obj.method2 = function() { return 2; }\n"
+ " return obj;\n"
+ "}");
+ CheckFunctionName(script, "return 1", "obj.method1");
+ CheckFunctionName(script, "return 2", "obj.method2");
+}
+
+
+TEST(Static) {
+ InitializeVM();
+ v8::HandleScope scope;
+
+ v8::Handle<v8::Script> script = Compile(
+ "function MyClass() {}\n"
+ "MyClass.static1 = function() { return 1; }\n"
+ "MyClass.static2 = function() { return 2; }\n"
+ "MyClass.MyInnerClass = {}\n"
+ "MyClass.MyInnerClass.static3 = function() { return 3; }\n"
+ "MyClass.MyInnerClass.static4 = function() { return 4; }");
+ CheckFunctionName(script, "return 1", "MyClass.static1");
+ CheckFunctionName(script, "return 2", "MyClass.static2");
+ CheckFunctionName(script, "return 3", "MyClass.MyInnerClass.static3");
+ CheckFunctionName(script, "return 4", "MyClass.MyInnerClass.static4");
+}
+
+
+TEST(Prototype) {
+ InitializeVM();
+ v8::HandleScope scope;
+
+ v8::Handle<v8::Script> script = Compile(
+ "function MyClass() {}\n"
+ "MyClass.prototype.method1 = function() { return 1; }\n"
+ "MyClass.prototype.method2 = function() { return 2; }\n"
+ "MyClass.MyInnerClass = function() {}\n"
+ "MyClass.MyInnerClass.prototype.method3 = function() { return 3; }\n"
+ "MyClass.MyInnerClass.prototype.method4 = function() { return 4; }");
+ CheckFunctionName(script, "return 1", "MyClass.method1");
+ CheckFunctionName(script, "return 2", "MyClass.method2");
+ CheckFunctionName(script, "return 3", "MyClass.MyInnerClass.method3");
+ CheckFunctionName(script, "return 4", "MyClass.MyInnerClass.method4");
+}
+
+
+TEST(ObjectLiteral) {
+ InitializeVM();
+ v8::HandleScope scope;
+
+ v8::Handle<v8::Script> script = Compile(
+ "function MyClass() {}\n"
+ "MyClass.prototype = {\n"
+ " method1: function() { return 1; },\n"
+ " method2: function() { return 2; } }");
+ CheckFunctionName(script, "return 1", "MyClass.method1");
+ CheckFunctionName(script, "return 2", "MyClass.method2");
+}
+
+
+TEST(AsParameter) {
+ InitializeVM();
+ v8::HandleScope scope;
+
+ v8::Handle<v8::Script> script = Compile(
+ "function f1(a) { return a(); }\n"
+ "function f2(a, b) { return a() + b(); }\n"
+ "var result1 = f1(function() { return 1; })\n"
+ "var result2 = f2(function() { return 2; }, function() { return 3; })");
+ // Can't infer names here.
+ CheckFunctionName(script, "return 1", "");
+ CheckFunctionName(script, "return 2", "");
+ CheckFunctionName(script, "return 3", "");
+}
89F23C9F0E78D604006B2466 /* simulator-arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF17D0E719B8F00D62E90 /* simulator-arm.cc */; };
89F23CA00E78D609006B2466 /* stub-cache-arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF18A0E719B8F00D62E90 /* stub-cache-arm.cc */; };
89FB0E3A0F8E533F00B04B3C /* d8-posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = 89FB0E360F8E531900B04B3C /* d8-posix.cc */; };
+ 9F92FAA90F8F28AD0089F02C /* func-name-inferrer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F92FAA70F8F28AD0089F02C /* func-name-inferrer.cc */; };
+ 9F92FAAA0F8F28AD0089F02C /* func-name-inferrer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F92FAA70F8F28AD0089F02C /* func-name-inferrer.cc */; };
9FC86ABD0F5FEDAC00F22668 /* oprofile-agent.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9FC86ABB0F5FEDAC00F22668 /* oprofile-agent.cc */; };
9FC86ABE0F5FEDAC00F22668 /* oprofile-agent.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9FC86ABB0F5FEDAC00F22668 /* oprofile-agent.cc */; };
/* End PBXBuildFile section */
89F23C950E78D5B6006B2466 /* v8_shell-arm */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "v8_shell-arm"; sourceTree = BUILT_PRODUCTS_DIR; };
89FB0E360F8E531900B04B3C /* d8-posix.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "d8-posix.cc"; path = "../src/d8-posix.cc"; sourceTree = "<group>"; };
89FB0E370F8E531900B04B3C /* d8-windows.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "d8-windows.cc"; path = "../src/d8-windows.cc"; sourceTree = "<group>"; };
+ 9F92FAA70F8F28AD0089F02C /* func-name-inferrer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "func-name-inferrer.cc"; sourceTree = "<group>"; };
+ 9F92FAA80F8F28AD0089F02C /* func-name-inferrer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "func-name-inferrer.h"; sourceTree = "<group>"; };
9FC86ABB0F5FEDAC00F22668 /* oprofile-agent.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "oprofile-agent.cc"; sourceTree = "<group>"; };
9FC86ABC0F5FEDAC00F22668 /* oprofile-agent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "oprofile-agent.h"; sourceTree = "<group>"; };
/* End PBXFileReference section */
897FF13B0E719B8F00D62E90 /* frames-inl.h */,
897FF13C0E719B8F00D62E90 /* frames.cc */,
897FF13D0E719B8F00D62E90 /* frames.h */,
+ 9F92FAA70F8F28AD0089F02C /* func-name-inferrer.cc */,
+ 9F92FAA80F8F28AD0089F02C /* func-name-inferrer.h */,
897FF13E0E719B8F00D62E90 /* global-handles.cc */,
897FF13F0E719B8F00D62E90 /* global-handles.h */,
897FF1400E719B8F00D62E90 /* globals.h */,
89A88E050E71A65D0043BA31 /* flags.cc in Sources */,
89A88E060E71A6600043BA31 /* frames-ia32.cc in Sources */,
89A88E070E71A6610043BA31 /* frames.cc in Sources */,
+ 9F92FAA90F8F28AD0089F02C /* func-name-inferrer.cc in Sources */,
89A88E080E71A6620043BA31 /* global-handles.cc in Sources */,
89A88E090E71A6640043BA31 /* handles.cc in Sources */,
89A88E0A0E71A6650043BA31 /* hashmap.cc in Sources */,
89F23C580E78D5B2006B2466 /* flags.cc in Sources */,
89F23C9C0E78D5F1006B2466 /* frames-arm.cc in Sources */,
89F23C5A0E78D5B2006B2466 /* frames.cc in Sources */,
+ 9F92FAAA0F8F28AD0089F02C /* func-name-inferrer.cc in Sources */,
89F23C5B0E78D5B2006B2466 /* global-handles.cc in Sources */,
89F23C5C0E78D5B2006B2466 /* handles.cc in Sources */,
89F23C5D0E78D5B2006B2466 /* hashmap.cc in Sources */,
RelativePath="..\..\src\frames.h"
>
</File>
+ <File
+ RelativePath="..\..\src\func-name-inferrer.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\func-name-inferrer.h"
+ >
+ </File>
<File
RelativePath="..\..\src\global-handles.cc"
>
RelativePath="..\..\src\frames.h"
>
</File>
+ <File
+ RelativePath="..\..\src\func-name-inferrer.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\func-name-inferrer.h"
+ >
+ </File>
<File
RelativePath="..\..\src\global-handles.cc"
>
RelativePath="..\..\test\cctest\test-flags.cc"
>
</File>
+ <File
+ RelativePath="..\..\test\cctest\test-func-name-inference.cc"
+ >
+ </File>
<File
RelativePath="..\..\test\cctest\test-hashmap.cc"
>