Propagate receiver from initial call site to code generator.
authorkmillikin@chromium.org <kmillikin@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 29 Jan 2010 09:52:51 +0000 (09:52 +0000)
committerkmillikin@chromium.org <kmillikin@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 29 Jan 2010 09:52:51 +0000 (09:52 +0000)
When doing lazy compilation of methods, allow the code generator to know the
(initial) receiver at the (initial) call site.

Review URL: http://codereview.chromium.org/551189

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3739 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

13 files changed:
src/accessors.cc
src/bootstrapper.cc
src/builtins.cc
src/compiler.cc
src/compiler.h
src/debug.cc
src/debug.h
src/fast-codegen.cc
src/fast-codegen.h
src/handles.cc
src/handles.h
src/ic.cc
src/runtime.cc

index 56cf135..5a02928 100644 (file)
@@ -493,11 +493,11 @@ Object* Accessors::FunctionGetLength(Object* object, void*) {
     // If the function isn't compiled yet, the length is not computed
     // correctly yet. Compile it now and return the right length.
     HandleScope scope;
-    Handle<JSFunction> function_handle(function);
-    if (!CompileLazy(function_handle, KEEP_EXCEPTION)) {
+    Handle<SharedFunctionInfo> shared(function->shared());
+    if (!CompileLazyShared(shared, KEEP_EXCEPTION)) {
       return Failure::Exception();
     }
-    return Smi::FromInt(function_handle->shared()->length());
+    return Smi::FromInt(shared->length());
   } else {
     return Smi::FromInt(function->shared()->length());
   }
index 6b84e2b..78d0995 100644 (file)
@@ -249,26 +249,24 @@ bool PendingFixups::Process(Handle<JSBuiltinsObject> builtins) {
       V8_Fatal(__FILE__, __LINE__, "Cannot resolve call to builtin %s", name);
     }
 #endif
-    Handle<JSFunction> f = Handle<JSFunction>(JSFunction::cast(o));
+    Handle<SharedFunctionInfo> shared(JSFunction::cast(o)->shared());
     // Make sure the number of parameters match the formal parameter count.
     int argc = Bootstrapper::FixupFlagsArgumentsCount::decode(flags);
     USE(argc);
-    ASSERT(f->shared()->formal_parameter_count() == argc);
-    if (!f->is_compiled()) {
-      // Do lazy compilation and check for stack overflows.
-      if (!CompileLazy(f, CLEAR_EXCEPTION)) {
-        Clear();
-        return false;
-      }
+    ASSERT(shared->formal_parameter_count() == argc);
+    // Do lazy compilation if necessary and check for stack overflows.
+    if (!EnsureCompiled(shared, CLEAR_EXCEPTION)) {
+      Clear();
+      return false;
     }
     Code* code = Code::cast(code_[i]);
     Address pc = code->instruction_start() + pc_[i];
     RelocInfo target(pc, RelocInfo::CODE_TARGET, 0);
     bool use_code_object = Bootstrapper::FixupFlagsUseCodeObject::decode(flags);
     if (use_code_object) {
-      target.set_target_object(f->code());
+      target.set_target_object(shared->code());
     } else {
-      target.set_target_address(f->code()->instruction_start());
+      target.set_target_address(shared->code()->instruction_start());
     }
     LOG(StringEvent("resolved", name));
   }
index 9db2230..41682bd 100644 (file)
@@ -175,12 +175,12 @@ Handle<Code> Builtins::GetCode(JavaScript id, bool* resolved) {
   if (Top::context() != NULL) {
     Object* object = Top::builtins()->javascript_builtin(id);
     if (object->IsJSFunction()) {
-      Handle<JSFunction> function(JSFunction::cast(object));
+      Handle<SharedFunctionInfo> shared(JSFunction::cast(object)->shared());
       // Make sure the number of parameters match the formal parameter count.
-      ASSERT(function->shared()->formal_parameter_count() ==
+      ASSERT(shared->formal_parameter_count() ==
              Builtins::GetArgumentsCount(id));
-      if (function->is_compiled() || CompileLazy(function, CLEAR_EXCEPTION)) {
-        code = function->code();
+      if (EnsureCompiled(shared, CLEAR_EXCEPTION)) {
+        code = shared->code();
         *resolved = true;
       }
     }
index 9512e42..8671640 100644 (file)
@@ -48,7 +48,8 @@ static Handle<Code> MakeCode(FunctionLiteral* literal,
                              Handle<Script> script,
                              Handle<Context> context,
                              bool is_eval,
-                             Handle<SharedFunctionInfo> shared) {
+                             Handle<SharedFunctionInfo> shared,
+                             Handle<Object> receiver) {
   ASSERT(literal != NULL);
 
   // Rewrite the AST by introducing .result assignments where needed.
@@ -109,7 +110,7 @@ static Handle<Code> MakeCode(FunctionLiteral* literal,
     }
   } else if (FLAG_always_fast_compiler ||
              (FLAG_fast_compiler && !is_run_once)) {
-    FastCodeGenSyntaxChecker checker;
+    FastCodeGenSyntaxChecker checker(receiver);
     checker.Check(literal);
     if (checker.has_supported_syntax()) {
       AstLabeler labeler;
@@ -203,8 +204,12 @@ static Handle<JSFunction> MakeFunction(bool is_global,
   HistogramTimerScope timer(rate);
 
   // Compile the code.
-  Handle<Code> code = MakeCode(lit, script, context, is_eval,
-                               Handle<SharedFunctionInfo>::null());
+  Handle<Code> code = MakeCode(lit,
+                               script,
+                               context,
+                               is_eval,
+                               Handle<SharedFunctionInfo>::null(),
+                               Handle<Object>::null());  // No receiver.
 
   // Check for stack-overflow exceptions.
   if (code.is_null()) {
@@ -366,6 +371,7 @@ Handle<JSFunction> Compiler::CompileEval(Handle<String> source,
 
 
 bool Compiler::CompileLazy(Handle<SharedFunctionInfo> shared,
+                           Handle<Object> receiver,
                            int loop_nesting) {
   CompilationZoneScope zone_scope(DELETE_ON_EXIT);
 
@@ -405,8 +411,12 @@ bool Compiler::CompileLazy(Handle<SharedFunctionInfo> shared,
   HistogramTimerScope timer(&Counters::compile_lazy);
 
   // Compile the code.
-  Handle<Code> code = MakeCode(lit, script, Handle<Context>::null(), false,
-                               shared);
+  Handle<Code> code = MakeCode(lit,
+                               script,
+                               Handle<Context>::null(),
+                               false,
+                               shared,
+                               receiver);
 
   // Check for stack-overflow exception.
   if (code.is_null()) {
@@ -501,7 +511,9 @@ Handle<JSFunction> Compiler::BuildBoilerplate(FunctionLiteral* literal,
       }
     } else if (FLAG_always_fast_compiler ||
                (FLAG_fast_compiler && !is_run_once)) {
-      FastCodeGenSyntaxChecker checker;
+      // Since we are not lazily compiling we do not have a receiver to
+      // specialize for.
+      FastCodeGenSyntaxChecker checker(Handle<Object>::null());
       checker.Check(literal);
       if (checker.has_supported_syntax()) {
         AstLabeler label_nodes;
index 546e446..74c7ffb 100644 (file)
@@ -70,7 +70,9 @@ class Compiler : public AllStatic {
   // Compile from function info (used for lazy compilation). Returns
   // true on success and false if the compilation resulted in a stack
   // overflow.
-  static bool CompileLazy(Handle<SharedFunctionInfo> shared, int loop_nesting);
+  static bool CompileLazy(Handle<SharedFunctionInfo> shared,
+                          Handle<Object> receiver,
+                          int loop_nesting);
 
   // Compile a function boilerplate object (the function is possibly
   // lazily compiled). Called recursively from a backend code
index fc809c5..e66c30d 100644 (file)
@@ -1526,19 +1526,13 @@ void Debug::ClearStepNext() {
 }
 
 
-bool Debug::EnsureCompiled(Handle<SharedFunctionInfo> shared) {
-  if (shared->is_compiled()) return true;
-  return CompileLazyShared(shared, CLEAR_EXCEPTION, 0);
-}
-
-
 // Ensures the debug information is present for shared.
 bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) {
   // Return if we already have the debug info for shared.
   if (HasDebugInfo(shared)) return true;
 
   // Ensure shared in compiled. Return false if this failed.
-  if (!EnsureCompiled(shared)) return false;
+  if (!EnsureCompiled(shared, CLEAR_EXCEPTION)) return false;
 
   // Create the debug info object.
   Handle<DebugInfo> debug_info = Factory::NewDebugInfo(shared);
index 5ea2e52..576be93 100644 (file)
@@ -391,7 +391,6 @@ class Debug {
   static void ClearStepOut();
   static void ClearStepNext();
   // Returns whether the compile succeeded.
-  static bool EnsureCompiled(Handle<SharedFunctionInfo> shared);
   static void RemoveDebugInfo(Handle<DebugInfo> debug_info);
   static void SetAfterBreakTarget(JavaScriptFrame* frame);
   static Handle<Object> CheckBreakPoints(Handle<Object> break_point);
index 4e2df74..adca990 100644 (file)
@@ -50,10 +50,12 @@ namespace internal {
 
 
 void FastCodeGenSyntaxChecker::Check(FunctionLiteral* fun) {
-  Scope* scope = fun->scope();
+  // We do not specialize if we do not have a receiver.
+  if (receiver().is_null()) BAILOUT("No receiver");
 
   // We do not support stack or heap slots (both of which require
   // allocation).
+  Scope* scope = fun->scope();
   if (scope->num_stack_slots() > 0) {
     BAILOUT("Function has stack-allocated locals");
   }
@@ -246,6 +248,21 @@ void FastCodeGenSyntaxChecker::VisitAssignment(Assignment* expr) {
     BAILOUT("Non-named-property assignment");
   }
 
+  // We will only specialize for fields on the object itself.
+  // Expression::IsPropertyName implies that the name is a literal
+  // symbol but we do not assume that.
+  Literal* key = prop->key()->AsLiteral();
+  if (key != NULL && key->handle()->IsString()) {
+    Handle<String> name = Handle<String>::cast(key->handle());
+    LookupResult lookup;
+    receiver()->Lookup(*name, &lookup);
+    if (lookup.holder() != *receiver()) BAILOUT("Non-own property assignment");
+    if (!lookup.type() == FIELD) BAILOUT("Non-field property assignment");
+  } else {
+    UNREACHABLE();
+    BAILOUT("Unexpected non-string-literal property key");
+  }
+
   Visit(expr->value());
 }
 
index 3e0bb41..1ac60ac 100644 (file)
@@ -37,10 +37,13 @@ namespace internal {
 
 class FastCodeGenSyntaxChecker: public AstVisitor {
  public:
-  FastCodeGenSyntaxChecker() : has_supported_syntax_(true) {}
+  explicit FastCodeGenSyntaxChecker(Handle<Object> receiver)
+      : receiver_(receiver), has_supported_syntax_(true) {
+  }
 
   void Check(FunctionLiteral* fun);
 
+  Handle<Object> receiver() { return receiver_; }
   bool has_supported_syntax() { return has_supported_syntax_; }
 
  private:
@@ -52,6 +55,7 @@ class FastCodeGenSyntaxChecker: public AstVisitor {
   AST_NODE_LIST(DECLARE_VISIT)
 #undef DECLARE_VISIT
 
+  Handle<Object> receiver_;
   bool has_supported_syntax_;
 
   DISALLOW_COPY_AND_ASSIGN(FastCodeGenSyntaxChecker);
index 3156670..cfe4dd7 100644 (file)
@@ -666,35 +666,53 @@ Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
 }
 
 
-bool CompileLazyShared(Handle<SharedFunctionInfo> shared,
-                       ClearExceptionFlag flag,
-                       int loop_nesting) {
+bool EnsureCompiled(Handle<SharedFunctionInfo> shared,
+                    ClearExceptionFlag flag) {
+  return shared->is_compiled() || CompileLazyShared(shared, flag);
+}
+
+
+static bool CompileLazyHelper(Handle<SharedFunctionInfo> shared,
+                              Handle<Object> receiver,
+                              ClearExceptionFlag flag,
+                              int loop_nesting) {
   // Compile the source information to a code object.
   ASSERT(!shared->is_compiled());
-  bool result = Compiler::CompileLazy(shared, loop_nesting);
+  bool result = Compiler::CompileLazy(shared, receiver, loop_nesting);
   ASSERT(result != Top::has_pending_exception());
   if (!result && flag == CLEAR_EXCEPTION) Top::clear_pending_exception();
   return result;
 }
 
 
-bool CompileLazy(Handle<JSFunction> function, ClearExceptionFlag flag) {
+bool CompileLazyShared(Handle<SharedFunctionInfo> shared,
+                       ClearExceptionFlag flag) {
+  return CompileLazyHelper(shared, Handle<Object>::null(), flag, 0);
+}
+
+
+bool CompileLazy(Handle<JSFunction> function,
+                 Handle<Object> receiver,
+                 ClearExceptionFlag flag) {
   // Compile the source information to a code object.
   Handle<SharedFunctionInfo> shared(function->shared());
-  bool result = CompileLazyShared(shared, flag, 0);
+  bool result = CompileLazyHelper(shared, receiver, flag, 0);
   LOG(FunctionCreateEvent(*function));
   return result;
 }
 
 
-bool CompileLazyInLoop(Handle<JSFunction> function, ClearExceptionFlag flag) {
+bool CompileLazyInLoop(Handle<JSFunction> function,
+                       Handle<Object> receiver,
+                       ClearExceptionFlag flag) {
   // Compile the source information to a code object.
   Handle<SharedFunctionInfo> shared(function->shared());
-  bool result = CompileLazyShared(shared, flag, 1);
+  bool result = CompileLazyHelper(shared, receiver, flag, 1);
   LOG(FunctionCreateEvent(*function));
   return result;
 }
 
+
 OptimizedObjectForAddingMultipleProperties::
 OptimizedObjectForAddingMultipleProperties(Handle<JSObject> object,
                                            int expected_additional_properties,
index fe820d5..04f087b 100644 (file)
@@ -313,12 +313,19 @@ Handle<Object> SetPrototype(Handle<JSFunction> function,
 // false if the compilation resulted in a stack overflow.
 enum ClearExceptionFlag { KEEP_EXCEPTION, CLEAR_EXCEPTION };
 
+bool EnsureCompiled(Handle<SharedFunctionInfo> shared,
+                    ClearExceptionFlag flag);
+
 bool CompileLazyShared(Handle<SharedFunctionInfo> shared,
-                       ClearExceptionFlag flag,
-                       int loop_nesting);
+                       ClearExceptionFlag flag);
+
+bool CompileLazy(Handle<JSFunction> function,
+                 Handle<Object> receiver,
+                 ClearExceptionFlag flag);
 
-bool CompileLazy(Handle<JSFunction> function, ClearExceptionFlag flag);
-bool CompileLazyInLoop(Handle<JSFunction> function, ClearExceptionFlag flag);
+bool CompileLazyInLoop(Handle<JSFunction> function,
+                       Handle<Object> receiver,
+                       ClearExceptionFlag flag);
 
 // Returns the lazy compilation stub for argc arguments.
 Handle<Code> ComputeLazyCompile(int argc);
index d823c91..85d7a5b 100644 (file)
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -1302,9 +1302,9 @@ Object* CallIC_Miss(Arguments args) {
   Handle<JSFunction> function = Handle<JSFunction>(JSFunction::cast(result));
   InLoopFlag in_loop = ic.target()->ic_in_loop();
   if (in_loop == IN_LOOP) {
-    CompileLazyInLoop(function, CLEAR_EXCEPTION);
+    CompileLazyInLoop(function, args.at<Object>(0), CLEAR_EXCEPTION);
   } else {
-    CompileLazy(function, CLEAR_EXCEPTION);
+    CompileLazy(function, args.at<Object>(0), CLEAR_EXCEPTION);
   }
   return *function;
 }
index 51c1ba2..4f68a65 100644 (file)
@@ -1405,16 +1405,18 @@ static Object* Runtime_SetCode(Arguments args) {
   if (!code->IsNull()) {
     RUNTIME_ASSERT(code->IsJSFunction());
     Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
-    SetExpectedNofProperties(target, fun->shared()->expected_nof_properties());
-    if (!fun->is_compiled() && !CompileLazy(fun, KEEP_EXCEPTION)) {
+    Handle<SharedFunctionInfo> shared(fun->shared());
+    SetExpectedNofProperties(target, shared->expected_nof_properties());
+
+    if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
       return Failure::Exception();
     }
     // Set the code, formal parameter count, and the length of the target
     // function.
     target->set_code(fun->code());
-    target->shared()->set_length(fun->shared()->length());
+    target->shared()->set_length(shared->length());
     target->shared()->set_formal_parameter_count(
-        fun->shared()->formal_parameter_count());
+        shared->formal_parameter_count());
     // Set the source code of the target function to undefined.
     // SetCode is only used for built-in constructors like String,
     // Array, and Object, and some web code
@@ -4826,12 +4828,8 @@ static Object* Runtime_NewObject(Arguments args) {
   }
 
   // The function should be compiled for the optimization hints to be available.
-  if (!function->shared()->is_compiled()) {
-    CompileLazyShared(Handle<SharedFunctionInfo>(function->shared()),
-                                                 CLEAR_EXCEPTION,
-                                                 0);
-    LOG(FunctionCreateEvent(*function));
-  }
+  Handle<SharedFunctionInfo> shared(function->shared());
+  EnsureCompiled(shared, CLEAR_EXCEPTION);
 
   bool first_allocation = !function->has_initial_map();
   Handle<JSObject> result = Factory::NewJSObject(function);
@@ -4870,7 +4868,7 @@ static Object* Runtime_LazyCompile(Arguments args) {
   // this means that things called through constructors are never known to
   // be in loops.  We compile them as if they are in loops here just in case.
   ASSERT(!function->is_compiled());
-  if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
+  if (!CompileLazyInLoop(function, Handle<Object>::null(), KEEP_EXCEPTION)) {
     return Failure::Exception();
   }
 
@@ -7278,7 +7276,7 @@ Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
     if (!done) {
       // If the candidate is not compiled compile it to reveal any inner
       // functions which might contain the requested source position.
-      CompileLazyShared(target, KEEP_EXCEPTION, 0);
+      CompileLazyShared(target, KEEP_EXCEPTION);
     }
   }
 
@@ -7864,7 +7862,8 @@ static Object* Runtime_DebugDisassembleFunction(Arguments args) {
   ASSERT(args.length() == 1);
   // Get the function and make sure it is compiled.
   CONVERT_ARG_CHECKED(JSFunction, func, 0);
-  if (!func->is_compiled() && !CompileLazy(func, KEEP_EXCEPTION)) {
+  Handle<SharedFunctionInfo> shared(func->shared());
+  if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
     return Failure::Exception();
   }
   func->code()->PrintLn();
@@ -7879,10 +7878,11 @@ static Object* Runtime_DebugDisassembleConstructor(Arguments args) {
   ASSERT(args.length() == 1);
   // Get the function and make sure it is compiled.
   CONVERT_ARG_CHECKED(JSFunction, func, 0);
-  if (!func->is_compiled() && !CompileLazy(func, KEEP_EXCEPTION)) {
+  Handle<SharedFunctionInfo> shared(func->shared());
+  if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
     return Failure::Exception();
   }
-  func->shared()->construct_stub()->PrintLn();
+  shared->construct_stub()->PrintLn();
 #endif  // DEBUG
   return Heap::undefined_value();
 }