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
parent 88f6734d
......@@ -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());
}
......
......@@ -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)) {
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));
}
......
......@@ -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;
}
}
......
......@@ -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;
......
......@@ -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
......
......@@ -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);
......
......@@ -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);
......
......@@ -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());
}
......
......@@ -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);
......
......@@ -666,35 +666,53 @@ Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
}
bool CompileLazyShared(Handle<SharedFunctionInfo> shared,
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,
......
......@@ -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);
......
......@@ -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;
}
......
......@@ -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();
}
......
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