start_position_(start_position),
end_position_(end_position),
is_expression_(is_expression),
+ loop_nesting_(0),
function_token_position_(RelocInfo::kNoPosition) {
}
bool AllowsLazyCompilation();
+ bool loop_nesting() const { return loop_nesting_; }
+ void set_loop_nesting(int nesting) { loop_nesting_ = nesting; }
+
private:
Handle<String> name_;
Scope* scope_;
int start_position_;
int end_position_;
bool is_expression_;
+ int loop_nesting_;
int function_token_position_;
};
void ProcessDeclarations(ZoneList<Declaration*>* declarations);
Handle<Code> ComputeCallInitialize(int argc);
+ Handle<Code> ComputeCallInitializeInLoop(int argc);
// Declare global variables and functions in the given array of
// name/value pairs.
VirtualFrame virtual_frame(this);
frame_ = &virtual_frame;
cc_reg_ = no_condition;
+
+ // Adjust for function-level loop nesting.
+ loop_nesting_ += fun->loop_nesting();
+
{
CodeGenState state(this);
}
}
+ // Adjust for function-level loop nesting.
+ loop_nesting_ -= fun->loop_nesting();
+
// Code generation state must be reset.
scope_ = NULL;
frame_ = NULL;
ASSERT(!has_cc());
ASSERT(state_ == NULL);
+ ASSERT(loop_nesting() == 0);
}
// patch the stack to use the global proxy as 'this' in the
// invoked function.
LoadGlobal();
-
// Load the arguments.
for (int i = 0; i < args->length(); i++) {
Load(args->at(i));
}
// Setup the receiver register and call the IC initialization code.
- Handle<Code> stub = ComputeCallInitialize(args->length());
+ Handle<Code> stub = (loop_nesting() > 0)
+ ? ComputeCallInitializeInLoop(args->length())
+ : ComputeCallInitialize(args->length());
__ RecordPosition(node->position());
__ call(stub, RelocInfo::CODE_TARGET_CONTEXT);
__ mov(esi, frame_->Context());
for (int i = 0; i < args->length(); i++) Load(args->at(i));
// Call the IC initialization code.
- Handle<Code> stub = ComputeCallInitialize(args->length());
+ Handle<Code> stub = (loop_nesting() > 0)
+ ? ComputeCallInitializeInLoop(args->length())
+ : ComputeCallInitialize(args->length());
__ RecordPosition(node->position());
__ call(stub, RelocInfo::CODE_TARGET);
__ mov(esi, frame_->Context());
void ProcessDeclarations(ZoneList<Declaration*>* declarations);
Handle<Code> ComputeCallInitialize(int argc);
+ Handle<Code> ComputeCallInitializeInLoop(int argc);
// Declare global variables and functions in the given array of
// name/value pairs.
}
+Handle<Code> CodeGenerator::ComputeCallInitializeInLoop(int argc) {
+ // Force the creation of the corresponding stub outside loops,
+ // because it will be used when clearing the ICs later - when we
+ // don't know if we're inside a loop or not.
+ ComputeCallInitialize(argc);
+ CALL_HEAP_FUNCTION(StubCache::ComputeCallInitializeInLoop(argc), Code);
+}
+
+
void CodeGenerator::ProcessDeclarations(ZoneList<Declaration*>* declarations) {
int length = declarations->length();
int globals = 0;
// CodeGenerator::GenCode
// CodeGenerator::BuildBoilerplate
// CodeGenerator::ComputeCallInitialize
+// CodeGenerator::ComputeCallInitializeInLoop
// CodeGenerator::ProcessDeclarations
// CodeGenerator::DeclareGlobals
// CodeGenerator::CheckForInlineRuntimeCall
}
-bool Compiler::CompileLazy(Handle<SharedFunctionInfo> shared) {
+bool Compiler::CompileLazy(Handle<SharedFunctionInfo> shared,
+ int loop_nesting) {
ZoneScope zone_scope(DELETE_ON_EXIT);
// The VM is in the COMPILER state until exiting this function.
return false;
}
+ // Update the loop nesting in the function literal.
+ lit->set_loop_nesting(loop_nesting);
+
// Measure how long it takes to do the lazy compilation; only take
// the rest of the function into account to avoid overlap with the
// lazy parsing statistics.
// 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);
+ static bool CompileLazy(Handle<SharedFunctionInfo> shared, int loop_nesting);
};
} } // namespace v8::internal
bool Debug::EnsureCompiled(Handle<SharedFunctionInfo> shared) {
if (shared->is_compiled()) return true;
- return CompileLazyShared(shared, CLEAR_EXCEPTION);
+ return CompileLazyShared(shared, CLEAR_EXCEPTION, 0);
}
enum InlineCacheState {
// Has never been executed.
UNINITIALIZED,
+ // Has never been executed, but is in a loop.
+ UNINITIALIZED_IN_LOOP,
// Has been executed but monomorhic state has been delayed.
PREMONOMORPHIC,
// Has been executed and only one receiver type has been seen.
bool CompileLazyShared(Handle<SharedFunctionInfo> shared,
- ClearExceptionFlag flag) {
+ ClearExceptionFlag flag,
+ int loop_nesting) {
// Compile the source information to a code object.
ASSERT(!shared->is_compiled());
- bool result = Compiler::CompileLazy(shared);
+ bool result = Compiler::CompileLazy(shared, 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) {
// Compile the source information to a code object.
Handle<SharedFunctionInfo> shared(function->shared());
- return CompileLazyShared(shared, flag);
+ return CompileLazyShared(shared, flag, 0);
}
+bool CompileLazyInLoop(Handle<JSFunction> function, ClearExceptionFlag flag) {
+ // Compile the source information to a code object.
+ Handle<SharedFunctionInfo> shared(function->shared());
+ return CompileLazyShared(shared, flag, 1);
+}
+
OptimizedObjectForAddingMultipleProperties::
OptimizedObjectForAddingMultipleProperties(Handle<JSObject> object,
bool condition) {
// Do lazy compilation of the given function. Returns true on success
// and false if the compilation resulted in a stack overflow.
enum ClearExceptionFlag { KEEP_EXCEPTION, CLEAR_EXCEPTION };
+
bool CompileLazyShared(Handle<SharedFunctionInfo> shared,
- ClearExceptionFlag flag);
+ ClearExceptionFlag flag,
+ int loop_nesting);
+
bool CompileLazy(Handle<JSFunction> function, ClearExceptionFlag flag);
+bool CompileLazyInLoop(Handle<JSFunction> function, ClearExceptionFlag flag);
// These deal with lazily loaded properties.
void SetupLazy(Handle<JSFunction> fun,
static char TransitionMarkFromState(IC::State state) {
switch (state) {
case UNINITIALIZED: return '0';
+ case UNINITIALIZED_IN_LOOP: return 'L';
case PREMONOMORPHIC: return '0';
case MONOMORPHIC: return '1';
case MONOMORPHIC_PROTOTYPE_FAILURE: return '^';
void CallIC::Clear(Address address, Code* target) {
- if (target->ic_state() == UNINITIALIZED) return;
+ State state = target->ic_state();
+ if (state == UNINITIALIZED || state == UNINITIALIZED_IN_LOOP) return;
Code* code = StubCache::FindCallInitialize(target->arguments_count());
SetTargetAtAddress(address, code);
}
if (code->IsFailure()) return;
// Patch the call site depending on the state of the cache.
- if (state == UNINITIALIZED || state == PREMONOMORPHIC ||
- state == MONOMORPHIC || state == MONOMORPHIC_PROTOTYPE_FAILURE) {
+ if (state == UNINITIALIZED || state == UNINITIALIZED_IN_LOOP ||
+ state == PREMONOMORPHIC || state == MONOMORPHIC ||
+ state == MONOMORPHIC_PROTOTYPE_FAILURE) {
set_target(Code::cast(code));
}
ASSERT(args.length() == 2);
CallIC ic;
IC::State state = IC::StateFrom(ic.target(), args[0]);
- return ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1));
+ Object* result =
+ ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1));
+ if (state != UNINITIALIZED_IN_LOOP || !result->IsJSFunction())
+ return result;
+
+ // Compile the function with the knowledge that it's called from
+ // within a loop. This enables further optimization of the function.
+ HandleScope scope;
+ Handle<JSFunction> function = Handle<JSFunction>(JSFunction::cast(result));
+ if (!function->is_compiled()) CompileLazyInLoop(function, CLEAR_EXCEPTION);
+ return *function;
}
const char* Code::ICState2String(InlineCacheState state) {
switch (state) {
case UNINITIALIZED: return "UNINITIALIZED";
+ case UNINITIALIZED_IN_LOOP: return "UNINITIALIZED_IN_LOOP";
case PREMONOMORPHIC: return "PREMONOMORPHIC";
case MONOMORPHIC: return "MONOMORPHIC";
case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
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);
+ CompileLazyShared(target, KEEP_EXCEPTION, 0);
}
}
}
+Object* StubCache::ComputeCallInitializeInLoop(int argc) {
+ Code::Flags flags =
+ Code::ComputeFlags(Code::CALL_IC, UNINITIALIZED_IN_LOOP, NORMAL, argc);
+ Object* probe = ProbeCache(flags);
+ if (!probe->IsUndefined()) return probe;
+ StubCompiler compiler;
+ return FillCache(compiler.CompileCallInitialize(flags));
+}
+
+
+
Object* StubCache::ComputeCallPreMonomorphic(int argc) {
Code::Flags flags =
Code::ComputeFlags(Code::CALL_IC, PREMONOMORPHIC, NORMAL, argc);
// ---
static Object* ComputeCallInitialize(int argc);
+ static Object* ComputeCallInitializeInLoop(int argc);
static Object* ComputeCallPreMonomorphic(int argc);
static Object* ComputeCallNormal(int argc);
static Object* ComputeCallMegamorphic(int argc);