Propagate receiver from initial call site to code generator.

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
This commit is contained in:
kmillikin@chromium.org 2010-01-29 09:52:51 +00:00
parent 88f6734ddb
commit e7528c4ac6
13 changed files with 116 additions and 65 deletions

View 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());
}

View 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));
}

View 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;
}
}

View 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;

View 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

View 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);

View 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);

View 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());
}

View 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);

View 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,

View 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 CompileLazyShared(Handle<SharedFunctionInfo> shared,
ClearExceptionFlag flag,
int loop_nesting);
bool EnsureCompiled(Handle<SharedFunctionInfo> shared,
ClearExceptionFlag flag);
bool CompileLazy(Handle<JSFunction> function, ClearExceptionFlag flag);
bool CompileLazyInLoop(Handle<JSFunction> function, ClearExceptionFlag flag);
bool CompileLazyShared(Handle<SharedFunctionInfo> shared,
ClearExceptionFlag flag);
bool CompileLazy(Handle<JSFunction> function,
Handle<Object> receiver,
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);

View File

@ -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;
}

View 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();
}