Revision: 17343
Author:   [email protected]
Date:     Wed Oct 23 13:48:04 2013 UTC
Log:      Enable preaging of code objects when --optimize-for-size.

This change means that code which is never executed is garbage collected immediately, and code which is only executed once is collected more quickly (limiting heap growth), however, code which is re-executed is reset to the young age, thus being kept around for the same number of GC generations as currently.

BUG=280984
[email protected], [email protected]

Review URL: https://codereview.chromium.org/23480031

Patch from Ross McIlroy <[email protected]>.
http://code.google.com/p/v8/source/detail?r=17343

Modified:
 /branches/bleeding_edge/src/arm/assembler-arm-inl.h
 /branches/bleeding_edge/src/arm/builtins-arm.cc
 /branches/bleeding_edge/src/arm/full-codegen-arm.cc
 /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
 /branches/bleeding_edge/src/arm/macro-assembler-arm.cc
 /branches/bleeding_edge/src/arm/macro-assembler-arm.h
 /branches/bleeding_edge/src/assembler.cc
 /branches/bleeding_edge/src/assembler.h
 /branches/bleeding_edge/src/builtins.h
 /branches/bleeding_edge/src/codegen.cc
 /branches/bleeding_edge/src/compiler.cc
 /branches/bleeding_edge/src/compiler.h
 /branches/bleeding_edge/src/factory.cc
 /branches/bleeding_edge/src/factory.h
 /branches/bleeding_edge/src/frames.h
 /branches/bleeding_edge/src/full-codegen.cc
 /branches/bleeding_edge/src/heap.cc
 /branches/bleeding_edge/src/heap.h
 /branches/bleeding_edge/src/ia32/assembler-ia32-inl.h
 /branches/bleeding_edge/src/ia32/assembler-ia32.cc
 /branches/bleeding_edge/src/ia32/builtins-ia32.cc
 /branches/bleeding_edge/src/ia32/codegen-ia32.cc
 /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc
 /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
 /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc
 /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h
 /branches/bleeding_edge/src/mips/assembler-mips-inl.h
 /branches/bleeding_edge/src/mips/builtins-mips.cc
 /branches/bleeding_edge/src/mips/full-codegen-mips.cc
 /branches/bleeding_edge/src/mips/lithium-codegen-mips.cc
 /branches/bleeding_edge/src/mips/macro-assembler-mips.cc
 /branches/bleeding_edge/src/mips/macro-assembler-mips.h
 /branches/bleeding_edge/src/objects.cc
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/src/serialize.cc
 /branches/bleeding_edge/src/x64/assembler-x64-inl.h
 /branches/bleeding_edge/src/x64/assembler-x64.cc
 /branches/bleeding_edge/src/x64/builtins-x64.cc
 /branches/bleeding_edge/src/x64/codegen-x64.cc
 /branches/bleeding_edge/src/x64/full-codegen-x64.cc
 /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
 /branches/bleeding_edge/src/x64/macro-assembler-x64.cc
 /branches/bleeding_edge/src/x64/macro-assembler-x64.h
 /branches/bleeding_edge/test/cctest/test-heap.cc

=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm-inl.h Wed Sep 11 10:51:06 2013 UTC +++ /branches/bleeding_edge/src/arm/assembler-arm-inl.h Wed Oct 23 13:48:04 2013 UTC
@@ -208,6 +208,13 @@

 static const int kNoCodeAgeSequenceLength = 3;

+
+Handle<Object> RelocInfo::code_age_stub_handle(Assembler* origin) {
+  UNREACHABLE();  // This should never be reached on Arm.
+  return Handle<Object>();
+}
+
+
 Code* RelocInfo::code_age_stub() {
   ASSERT(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
   return Code::GetCodeFromTargetAddress(
=======================================
--- /branches/bleeding_edge/src/arm/builtins-arm.cc Wed Sep 25 08:26:11 2013 UTC +++ /branches/bleeding_edge/src/arm/builtins-arm.cc Wed Oct 23 13:48:04 2013 UTC
@@ -826,6 +826,39 @@
 #undef DEFINE_CODE_AGE_BUILTIN_GENERATOR


+void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
+ // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact + // that make_code_young doesn't do any garbage collection which allows us to + // save/restore the registers without worrying about which of them contain
+  // pointers.
+
+ // The following registers must be saved and restored when calling through to
+  // the runtime:
+  //   r0 - contains return address (beginning of patch sequence)
+  //   r1 - isolate
+  FrameScope scope(masm, StackFrame::MANUAL);
+  __ stm(db_w, sp, r0.bit() | r1.bit() | fp.bit() | lr.bit());
+  __ PrepareCallCFunction(1, 0, r2);
+  __ mov(r1, Operand(ExternalReference::isolate_address(masm->isolate())));
+  __ CallCFunction(ExternalReference::get_mark_code_as_executed_function(
+        masm->isolate()), 2);
+  __ ldm(ia_w, sp, r0.bit() | r1.bit() | fp.bit() | lr.bit());
+
+  // Perform prologue operations usually performed by the young code stub.
+  __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
+  __ add(fp, sp, Operand(2 * kPointerSize));
+
+  // Jump to point after the code-age stub.
+ __ add(r0, r0, Operand(kNoCodeAgeSequenceLength * Assembler::kInstrSize));
+  __ mov(pc, r0);
+}
+
+
+void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
+  GenerateMakeCodeYoungAgainCommon(masm);
+}
+
+
 void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
   {
     FrameScope scope(masm, StackFrame::INTERNAL);
=======================================
--- /branches/bleeding_edge/src/arm/full-codegen-arm.cc Wed Sep 25 08:26:11 2013 UTC +++ /branches/bleeding_edge/src/arm/full-codegen-arm.cc Wed Oct 23 13:48:04 2013 UTC
@@ -163,16 +163,7 @@
   FrameScope frame_scope(masm_, StackFrame::MANUAL);

   info->set_prologue_offset(masm_->pc_offset());
-  {
-    PredictableCodeSizeScope predictible_code_size_scope(
-        masm_, kNoCodeAgeSequenceLength * Assembler::kInstrSize);
-    // The following three instructions must remain together and unmodified
-    // for code aging to work properly.
-    __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
-    __ nop(ip.code());
-    // Adjust FP to point to saved FP.
-    __ add(fp, sp, Operand(2 * kPointerSize));
-  }
+  __ Prologue(BUILD_FUNCTION_FRAME);
   info->AddNoFrameRange(0, masm_->pc_offset());

   { Comment cmnt(masm_, "[ Allocate locals");
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Mon Oct 21 13:35:48 2013 UTC +++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Wed Oct 23 13:48:04 2013 UTC
@@ -133,21 +133,7 @@

   info()->set_prologue_offset(masm_->pc_offset());
   if (NeedsEagerFrame()) {
-    if (info()->IsStub()) {
-      __ stm(db_w, sp, cp.bit() | fp.bit() | lr.bit());
-      __ Push(Smi::FromInt(StackFrame::STUB));
-      // Adjust FP to point to saved FP.
-      __ add(fp, sp, Operand(2 * kPointerSize));
-    } else {
-      PredictableCodeSizeScope predictible_code_size_scope(
-          masm_, kNoCodeAgeSequenceLength * Assembler::kInstrSize);
- // The following three instructions must remain together and unmodified
-      // for code aging to work properly.
-      __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
-      __ nop(ip.code());
-      // Adjust FP to point to saved FP.
-      __ add(fp, sp, Operand(2 * kPointerSize));
-    }
+ __ Prologue(info()->IsStub() ? BUILD_STUB_FRAME : BUILD_FUNCTION_FRAME);
     frame_is_built_ = true;
     info_->AddNoFrameRange(0, masm_->pc_offset());
   }
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Tue Oct 15 15:04:29 2013 UTC +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Wed Oct 23 13:48:04 2013 UTC
@@ -914,6 +914,33 @@

   bind(&done);
 }
+
+
+void MacroAssembler::Prologue(PrologueFrameMode frame_mode) {
+  if (frame_mode == BUILD_STUB_FRAME) {
+    stm(db_w, sp, cp.bit() | fp.bit() | lr.bit());
+    Push(Smi::FromInt(StackFrame::STUB));
+    // Adjust FP to point to saved FP.
+    add(fp, sp, Operand(2 * kPointerSize));
+  } else {
+    PredictableCodeSizeScope predictible_code_size_scope(
+        this, kNoCodeAgeSequenceLength * Assembler::kInstrSize);
+    // The following three instructions must remain together and unmodified
+    // for code aging to work properly.
+    if (FLAG_optimize_for_size && FLAG_age_code) {
+      // Pre-age the code.
+      Code* stub = Code::GetPreAgedCodeAgeStub(isolate());
+      add(r0, pc, Operand(-8));
+      ldr(pc, MemOperand(pc, -4));
+      dd(reinterpret_cast<uint32_t>(stub->instruction_start()));
+    } else {
+      stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
+      nop(ip.code());
+      // Adjust FP to point to saved FP.
+      add(fp, sp, Operand(2 * kPointerSize));
+    }
+  }
+}


 void MacroAssembler::EnterFrame(StackFrame::Type type) {
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.h Tue Oct 15 15:04:29 2013 UTC +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.h Wed Oct 23 13:48:04 2013 UTC
@@ -539,6 +539,8 @@
                          LowDwVfpRegister double_scratch1,
                          Label* not_int32);

+  // Generates function and stub prologue code.
+  void Prologue(PrologueFrameMode frame_mode);

   // Enter exit frame.
   // stack_space - extra stack space, used for alignment before call to C.
=======================================
--- /branches/bleeding_edge/src/assembler.cc    Tue Oct 15 16:12:25 2013 UTC
+++ /branches/bleeding_edge/src/assembler.cc    Wed Oct 23 13:48:04 2013 UTC
@@ -1086,6 +1086,13 @@
   return ExternalReference(Redirect(
       isolate, FUNCTION_ADDR(Code::MakeCodeAgeSequenceYoung)));
 }
+
+
+ExternalReference ExternalReference::get_mark_code_as_executed_function(
+    Isolate* isolate) {
+  return ExternalReference(Redirect(
+      isolate, FUNCTION_ADDR(Code::MarkCodeAsExecuted)));
+}


 ExternalReference ExternalReference::date_cache_stamp(Isolate* isolate) {
=======================================
--- /branches/bleeding_edge/src/assembler.h     Tue Oct 15 16:12:25 2013 UTC
+++ /branches/bleeding_edge/src/assembler.h     Wed Oct 23 13:48:04 2013 UTC
@@ -401,6 +401,7 @@
   INLINE(Handle<Cell> target_cell_handle());
   INLINE(void set_target_cell(Cell* cell,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER));
+  INLINE(Handle<Object> code_age_stub_handle(Assembler* origin));
   INLINE(Code* code_age_stub());
   INLINE(void set_code_age_stub(Code* stub));

@@ -727,6 +728,7 @@
   static ExternalReference date_cache_stamp(Isolate* isolate);

   static ExternalReference get_make_code_young_function(Isolate* isolate);
+ static ExternalReference get_mark_code_as_executed_function(Isolate* isolate);

   // New heap objects tracking support.
static ExternalReference record_object_allocation_function(Isolate* isolate);
=======================================
--- /branches/bleeding_edge/src/builtins.h      Fri Oct 11 10:50:26 2013 UTC
+++ /branches/bleeding_edge/src/builtins.h      Wed Oct 23 13:48:04 2013 UTC
@@ -204,6 +204,11 @@
                                     Code::kNoExtraICState)              \
   V(StackCheck,                     BUILTIN, UNINITIALIZED,             \
                                     Code::kNoExtraICState)              \
+                                                                        \
+  V(MarkCodeAsExecutedOnce,         BUILTIN, UNINITIALIZED,             \
+                                    Code::kNoExtraICState)              \
+  V(MarkCodeAsExecutedTwice,        BUILTIN, UNINITIALIZED,             \
+                                    Code::kNoExtraICState)              \
   CODE_AGE_LIST_WITH_ARG(DECLARE_CODE_AGE_BUILTIN, V)

 // Define list of builtin handlers implemented in assembly.
@@ -413,6 +418,9 @@
   CODE_AGE_LIST(DECLARE_CODE_AGE_BUILTIN_GENERATOR)
 #undef DECLARE_CODE_AGE_BUILTIN_GENERATOR

+  static void Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm);
+  static void Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm);
+
   static void InitBuiltinFunctionTable();

   bool initialized_;
=======================================
--- /branches/bleeding_edge/src/codegen.cc      Mon Oct 21 13:35:48 2013 UTC
+++ /branches/bleeding_edge/src/codegen.cc      Wed Oct 23 13:48:04 2013 UTC
@@ -113,12 +113,12 @@
   masm->GetCode(&desc);
   Handle<Code> code =
       isolate->factory()->NewCode(desc, flags, masm->CodeObject(),
-                                  false, is_crankshafted);
+                                  false, is_crankshafted,
+                                  info->prologue_offset());
   isolate->counters()->total_compiled_code_size()->Increment(
       code->instruction_size());
   isolate->heap()->IncrementCodeGeneratedBytes(is_crankshafted,
       code->instruction_size());
-  code->set_prologue_offset(info->prologue_offset());
   return code;
 }

=======================================
--- /branches/bleeding_edge/src/compiler.cc     Wed Oct 23 08:57:54 2013 UTC
+++ /branches/bleeding_edge/src/compiler.cc     Wed Oct 23 13:48:04 2013 UTC
@@ -112,7 +112,7 @@
   zone_ = zone;
   deferred_handles_ = NULL;
   code_stub_ = NULL;
-  prologue_offset_ = kPrologueOffsetNotSet;
+  prologue_offset_ = Code::kPrologueOffsetNotSet;
   opt_count_ = shared_info().is_null() ? 0 : shared_info()->opt_count();
   no_frame_ranges_ = isolate->cpu_profiler()->is_profiling()
                    ? new List<OffsetRange>(2) : NULL;
=======================================
--- /branches/bleeding_edge/src/compiler.h      Tue Oct  1 08:40:33 2013 UTC
+++ /branches/bleeding_edge/src/compiler.h      Wed Oct 23 13:48:04 2013 UTC
@@ -35,8 +35,6 @@
 namespace v8 {
 namespace internal {

-static const int kPrologueOffsetNotSet = -1;
-
 class ScriptDataImpl;
 class HydrogenCodeStub;

@@ -269,12 +267,12 @@
void set_bailout_reason(BailoutReason reason) { bailout_reason_ = reason; }

   int prologue_offset() const {
-    ASSERT_NE(kPrologueOffsetNotSet, prologue_offset_);
+    ASSERT_NE(Code::kPrologueOffsetNotSet, prologue_offset_);
     return prologue_offset_;
   }

   void set_prologue_offset(int prologue_offset) {
-    ASSERT_EQ(kPrologueOffsetNotSet, prologue_offset_);
+    ASSERT_EQ(Code::kPrologueOffsetNotSet, prologue_offset_);
     prologue_offset_ = prologue_offset;
   }

=======================================
--- /branches/bleeding_edge/src/factory.cc      Mon Oct 21 13:55:24 2013 UTC
+++ /branches/bleeding_edge/src/factory.cc      Wed Oct 23 13:48:04 2013 UTC
@@ -1015,10 +1015,12 @@
                               Code::Flags flags,
                               Handle<Object> self_ref,
                               bool immovable,
-                              bool crankshafted) {
+                              bool crankshafted,
+                              int prologue_offset) {
   CALL_HEAP_FUNCTION(isolate(),
                      isolate()->heap()->CreateCode(
-                         desc, flags, self_ref, immovable, crankshafted),
+                         desc, flags, self_ref, immovable, crankshafted,
+                         prologue_offset),
                      Code);
 }

=======================================
--- /branches/bleeding_edge/src/factory.h       Mon Oct 21 13:55:24 2013 UTC
+++ /branches/bleeding_edge/src/factory.h       Wed Oct 23 13:48:04 2013 UTC
@@ -380,7 +380,8 @@
                        Code::Flags flags,
                        Handle<Object> self_reference,
                        bool immovable = false,
-                       bool crankshafted = false);
+                       bool crankshafted = false,
+                       int prologue_offset = Code::kPrologueOffsetNotSet);

   Handle<Code> CopyCode(Handle<Code> code);

=======================================
--- /branches/bleeding_edge/src/frames.h        Tue Jul 30 23:59:55 2013 UTC
+++ /branches/bleeding_edge/src/frames.h        Wed Oct 23 13:48:04 2013 UTC
@@ -922,6 +922,13 @@
 };


+// Used specify the type of prologue to generate.
+enum PrologueFrameMode {
+  BUILD_FUNCTION_FRAME,
+  BUILD_STUB_FRAME
+};
+
+
 // Reads all frames on the current stack and copies them into the current
 // zone memory.
 Vector<StackFrame*> CreateStackMap(Isolate* isolate, Zone* zone);
=======================================
--- /branches/bleeding_edge/src/full-codegen.cc Mon Oct 14 11:06:15 2013 UTC
+++ /branches/bleeding_edge/src/full-codegen.cc Wed Oct 23 13:48:04 2013 UTC
@@ -345,8 +345,6 @@
   code->set_has_deoptimization_support(info->HasDeoptimizationSupport());
   code->set_handler_table(*cgen.handler_table());
 #ifdef ENABLE_DEBUGGER_SUPPORT
-  code->set_has_debug_break_slots(
-      info->isolate()->debugger()->IsDebuggerActive());
   code->set_compiled_optimizable(info->IsOptimizable());
 #endif  // ENABLE_DEBUGGER_SUPPORT
   code->set_allow_osr_at_loop_nesting_level(0);
=======================================
--- /branches/bleeding_edge/src/heap.cc Wed Oct 23 12:49:27 2013 UTC
+++ /branches/bleeding_edge/src/heap.cc Wed Oct 23 13:48:04 2013 UTC
@@ -4140,7 +4140,8 @@
                               Code::Flags flags,
                               Handle<Object> self_reference,
                               bool immovable,
-                              bool crankshafted) {
+                              bool crankshafted,
+                              int prologue_offset) {
   // Allocate ByteArray before the Code object, so that we do not risk
   // leaving uninitialized Code object (and breaking the heap).
   ByteArray* reloc_info;
@@ -4190,10 +4191,18 @@
   code->set_handler_table(empty_fixed_array(), SKIP_WRITE_BARRIER);
   code->set_gc_metadata(Smi::FromInt(0));
   code->set_ic_age(global_ic_age_);
-  code->set_prologue_offset(kPrologueOffsetNotSet);
+  code->set_prologue_offset(prologue_offset);
   if (code->kind() == Code::OPTIMIZED_FUNCTION) {
     code->set_marked_for_deoptimization(false);
   }
+
+#ifdef ENABLE_DEBUGGER_SUPPORT
+  if (code->kind() == Code::FUNCTION) {
+    code->set_has_debug_break_slots(
+        isolate_->debugger()->IsDebuggerActive());
+  }
+#endif
+
   // Allow self references to created code object by patching the handle to
   // point to the newly allocated Code object.
   if (!self_reference.is_null()) {
=======================================
--- /branches/bleeding_edge/src/heap.h  Mon Oct 21 13:55:24 2013 UTC
+++ /branches/bleeding_edge/src/heap.h  Wed Oct 23 13:48:04 2013 UTC
@@ -1125,11 +1125,13 @@
   // self_reference. This allows generated code to reference its own Code
   // object by containing this pointer.
   // Please note this function does not perform a garbage collection.
-  MUST_USE_RESULT MaybeObject* CreateCode(const CodeDesc& desc,
-                                          Code::Flags flags,
-                                          Handle<Object> self_reference,
-                                          bool immovable = false,
-                                          bool crankshafted = false);
+  MUST_USE_RESULT MaybeObject* CreateCode(
+      const CodeDesc& desc,
+      Code::Flags flags,
+      Handle<Object> self_reference,
+      bool immovable = false,
+      bool crankshafted = false,
+      int prologue_offset = Code::kPrologueOffsetNotSet);

   MUST_USE_RESULT MaybeObject* CopyCode(Code* code);

=======================================
--- /branches/bleeding_edge/src/ia32/assembler-ia32-inl.h Wed Sep 11 10:51:06 2013 UTC +++ /branches/bleeding_edge/src/ia32/assembler-ia32-inl.h Wed Oct 23 13:48:04 2013 UTC
@@ -47,6 +47,7 @@


 static const byte kCallOpcode = 0xE8;
+static const int kNoCodeAgeSequenceLength = 5;


 // The modes possibly affected by apply must be in kApplyMask.
@@ -188,6 +189,13 @@
         host(), NULL, cell);
   }
 }
+
+
+Handle<Object> RelocInfo::code_age_stub_handle(Assembler* origin) {
+  ASSERT(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
+  ASSERT(*pc_ == kCallOpcode);
+  return Memory::Object_Handle_at(pc_ + 1);
+}


 Code* RelocInfo::code_age_stub() {
@@ -379,7 +387,8 @@
void Assembler::emit(uint32_t x, RelocInfo::Mode rmode, TypeFeedbackId id) {
   if (rmode == RelocInfo::CODE_TARGET && !id.IsNone()) {
     RecordRelocInfo(RelocInfo::CODE_TARGET_WITH_ID, id.ToInt());
-  } else if (!RelocInfo::IsNone(rmode)) {
+  } else if (!RelocInfo::IsNone(rmode)
+      && rmode != RelocInfo::CODE_AGE_SEQUENCE) {
     RecordRelocInfo(rmode);
   }
   emit(x);
=======================================
--- /branches/bleeding_edge/src/ia32/assembler-ia32.cc Fri Oct 18 10:54:45 2013 UTC +++ /branches/bleeding_edge/src/ia32/assembler-ia32.cc Wed Oct 23 13:48:04 2013 UTC
@@ -1414,7 +1414,8 @@
                      TypeFeedbackId ast_id) {
   positions_recorder()->WriteRecordedPositions();
   EnsureSpace ensure_space(this);
-  ASSERT(RelocInfo::IsCodeTarget(rmode));
+  ASSERT(RelocInfo::IsCodeTarget(rmode)
+      || rmode == RelocInfo::CODE_AGE_SEQUENCE);
   EMIT(0xE8);
   emit(code, rmode, ast_id);
 }
=======================================
--- /branches/bleeding_edge/src/ia32/builtins-ia32.cc Wed Sep 25 08:26:11 2013 UTC +++ /branches/bleeding_edge/src/ia32/builtins-ia32.cc Wed Oct 23 13:48:04 2013 UTC
@@ -563,6 +563,44 @@
 #undef DEFINE_CODE_AGE_BUILTIN_GENERATOR


+void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
+ // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact + // that make_code_young doesn't do any garbage collection which allows us to + // save/restore the registers without worrying about which of them contain
+  // pointers.
+  __ pushad();
+  __ mov(eax, Operand(esp, 8 * kPointerSize));
+  __ sub(eax, Immediate(Assembler::kCallInstructionLength));
+  {  // NOLINT
+    FrameScope scope(masm, StackFrame::MANUAL);
+    __ PrepareCallCFunction(2, ebx);
+    __ mov(Operand(esp, 1 * kPointerSize),
+           Immediate(ExternalReference::isolate_address(masm->isolate())));
+    __ mov(Operand(esp, 0), eax);
+    __ CallCFunction(
+ ExternalReference::get_mark_code_as_executed_function(masm->isolate()),
+        2);
+  }
+  __ popad();
+
+  // Perform prologue operations usually performed by the young code stub.
+  __ pop(eax);   // Pop return address into scratch register.
+  __ push(ebp);  // Caller's frame pointer.
+  __ mov(ebp, esp);
+  __ push(esi);  // Callee's context.
+  __ push(edi);  // Callee's JS Function.
+  __ push(eax);  // Push return address after frame prologue.
+
+  // Jump to point after the code-age stub.
+  __ ret(0);
+}
+
+
+void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
+  GenerateMakeCodeYoungAgainCommon(masm);
+}
+
+
 void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
   // Enter an internal frame.
   {
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.cc Fri Oct 18 10:54:45 2013 UTC +++ /branches/bleeding_edge/src/ia32/codegen-ia32.cc Wed Oct 23 13:48:04 2013 UTC
@@ -1117,7 +1117,6 @@

 #undef __

-static const int kNoCodeAgeSequenceLength = 5;

 static byte* GetNoCodeAgeSequence(uint32_t* length) {
   static bool initialized = false;
=======================================
--- /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Fri Oct 18 10:54:45 2013 UTC +++ /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Wed Oct 23 13:48:04 2013 UTC
@@ -158,10 +158,7 @@
   FrameScope frame_scope(masm_, StackFrame::MANUAL);

   info->set_prologue_offset(masm_->pc_offset());
-  __ push(ebp);  // Caller's frame pointer.
-  __ mov(ebp, esp);
-  __ push(esi);  // Callee's context.
-  __ push(edi);  // Callee's JS Function.
+  __ Prologue(BUILD_FUNCTION_FRAME);
   info->AddNoFrameRange(0, masm_->pc_offset());

   { Comment cmnt(masm_, "[ Allocate locals");
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Mon Oct 21 13:35:48 2013 UTC +++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Wed Oct 23 13:48:04 2013 UTC
@@ -188,15 +188,8 @@
   if (NeedsEagerFrame()) {
     ASSERT(!frame_is_built_);
     frame_is_built_ = true;
-    __ push(ebp);  // Caller's frame pointer.
-    __ mov(ebp, esp);
+ __ Prologue(info()->IsStub() ? BUILD_STUB_FRAME : BUILD_FUNCTION_FRAME);
     info()->AddNoFrameRange(0, masm_->pc_offset());
-    __ push(esi);  // Callee's context.
-    if (info()->IsStub()) {
-      __ push(Immediate(Smi::FromInt(StackFrame::STUB)));
-    } else {
-      __ push(edi);  // Callee's JS function.
-    }
   }

   if (info()->IsOptimizing() &&
=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Fri Oct 18 10:54:45 2013 UTC +++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Wed Oct 23 13:48:04 2013 UTC
@@ -1011,6 +1011,30 @@
     Check(not_equal, kOperandIsASmi);
   }
 }
+
+
+void MacroAssembler::Prologue(PrologueFrameMode frame_mode) {
+  if (frame_mode == BUILD_STUB_FRAME) {
+    push(ebp);  // Caller's frame pointer.
+    mov(ebp, esp);
+    push(esi);  // Callee's context.
+    push(Immediate(Smi::FromInt(StackFrame::STUB)));
+  } else {
+    PredictableCodeSizeScope predictible_code_size_scope(this,
+        kNoCodeAgeSequenceLength);
+    if (FLAG_optimize_for_size && FLAG_age_code) {
+        // Pre-age the code.
+      call(isolate()->builtins()->MarkCodeAsExecutedOnce(),
+          RelocInfo::CODE_AGE_SEQUENCE);
+      Nop(kNoCodeAgeSequenceLength - Assembler::kCallInstructionLength);
+    } else {
+      push(ebp);  // Caller's frame pointer.
+      mov(ebp, esp);
+      push(esi);  // Callee's context.
+      push(edi);  // Callee's JS function.
+    }
+  }
+}


 void MacroAssembler::EnterFrame(StackFrame::Type type) {
=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h Tue Oct 15 15:04:29 2013 UTC +++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h Wed Oct 23 13:48:04 2013 UTC
@@ -225,6 +225,9 @@
   void DebugBreak();
 #endif

+  // Generates function and stub prologue code.
+  void Prologue(PrologueFrameMode frame_mode);
+
   // Enter specific kind of exit frame. Expects the number of
   // arguments in register eax and sets up the number of arguments in
   // register edi and the pointer to the first argument in register
=======================================
--- /branches/bleeding_edge/src/mips/assembler-mips-inl.h Wed Sep 11 14:36:27 2013 UTC +++ /branches/bleeding_edge/src/mips/assembler-mips-inl.h Wed Oct 23 13:48:04 2013 UTC
@@ -261,6 +261,13 @@

 static const int kNoCodeAgeSequenceLength = 7;

+
+Handle<Object> RelocInfo::code_age_stub_handle(Assembler* origin) {
+  UNREACHABLE();  // This should never be reached on Arm.
+  return Handle<Object>();
+}
+
+
 Code* RelocInfo::code_age_stub() {
   ASSERT(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
   return Code::GetCodeFromTargetAddress(
=======================================
--- /branches/bleeding_edge/src/mips/builtins-mips.cc Wed Sep 25 16:27:52 2013 UTC +++ /branches/bleeding_edge/src/mips/builtins-mips.cc Wed Oct 23 13:48:04 2013 UTC
@@ -857,6 +857,49 @@
 #undef DEFINE_CODE_AGE_BUILTIN_GENERATOR


+void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
+ // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact + // that make_code_young doesn't do any garbage collection which allows us to + // save/restore the registers without worrying about which of them contain
+  // pointers.
+
+  __ mov(a0, ra);
+  // Adjust a0 to point to the head of the PlatformCodeAge sequence
+  __ Subu(a0, a0,
+      Operand((kNoCodeAgeSequenceLength - 1) * Assembler::kInstrSize));
+  // Restore the original return address of the function
+  __ mov(ra, at);
+
+ // The following registers must be saved and restored when calling through to
+  // the runtime:
+  //   a0 - contains return address (beginning of patch sequence)
+  //   a1 - isolate
+  RegList saved_regs =
+      (a0.bit() | a1.bit() | ra.bit() | fp.bit()) & ~sp.bit();
+  FrameScope scope(masm, StackFrame::MANUAL);
+  __ MultiPush(saved_regs);
+  __ PrepareCallCFunction(1, 0, a2);
+  __ li(a1, Operand(ExternalReference::isolate_address(masm->isolate())));
+  __ CallCFunction(
+ ExternalReference::get_mark_code_as_executed_function(masm->isolate()),
+      2);
+  __ MultiPop(saved_regs);
+
+  // Perform prologue operations usually performed by the young code stub.
+  __ Push(ra, fp, cp, a1);
+  __ Addu(fp, sp, Operand(2 * kPointerSize));
+
+  // Jump to point after the code-age stub.
+ __ Addu(a0, a0, Operand((kNoCodeAgeSequenceLength) * Assembler::kInstrSize));
+  __ Jump(a0);
+}
+
+
+void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
+  GenerateMakeCodeYoungAgainCommon(masm);
+}
+
+
 void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
   {
     FrameScope scope(masm, StackFrame::INTERNAL);
=======================================
--- /branches/bleeding_edge/src/mips/full-codegen-mips.cc Wed Sep 25 16:27:52 2013 UTC +++ /branches/bleeding_edge/src/mips/full-codegen-mips.cc Wed Oct 23 13:48:04 2013 UTC
@@ -171,12 +171,7 @@
   FrameScope frame_scope(masm_, StackFrame::MANUAL);

   info->set_prologue_offset(masm_->pc_offset());
- // The following three instructions must remain together and unmodified for
-  // code aging to work properly.
-  __ Push(ra, fp, cp, a1);
-  __ nop(Assembler::CODE_AGE_SEQUENCE_NOP);
-  // Adjust fp to point to caller's fp.
-  __ Addu(fp, sp, Operand(2 * kPointerSize));
+  __ Prologue(BUILD_FUNCTION_FRAME);
   info->AddNoFrameRange(0, masm_->pc_offset());

   { Comment cmnt(masm_, "[ Allocate locals");
=======================================
--- /branches/bleeding_edge/src/mips/lithium-codegen-mips.cc Mon Oct 21 22:20:45 2013 UTC +++ /branches/bleeding_edge/src/mips/lithium-codegen-mips.cc Wed Oct 23 13:48:04 2013 UTC
@@ -133,21 +133,7 @@

   info()->set_prologue_offset(masm_->pc_offset());
   if (NeedsEagerFrame()) {
-    if (info()->IsStub()) {
-      __ Push(ra, fp, cp);
-      __ Push(Smi::FromInt(StackFrame::STUB));
-      // Adjust FP to point to saved FP.
-      __ Addu(fp, sp, Operand(2 * kPointerSize));
-    } else {
- // The following three instructions must remain together and unmodified
-      // for code aging to work properly.
-      __ Push(ra, fp, cp, a1);
-      // Add unused nop to ensure prologue sequence is identical for
-      // full-codegen and lithium-codegen.
-      __ nop(Assembler::CODE_AGE_SEQUENCE_NOP);
-      // Adj. FP to point to saved FP.
-      __ Addu(fp, sp, Operand(2 * kPointerSize));
-    }
+ __ Prologue(info()->IsStub() ? BUILD_STUB_FRAME : BUILD_FUNCTION_FRAME);
     frame_is_built_ = true;
     info_->AddNoFrameRange(0, masm_->pc_offset());
   }
=======================================
--- /branches/bleeding_edge/src/mips/macro-assembler-mips.cc Tue Oct 15 23:12:15 2013 UTC +++ /branches/bleeding_edge/src/mips/macro-assembler-mips.cc Wed Oct 23 13:48:04 2013 UTC
@@ -4583,6 +4583,40 @@

   bind(&done);
 }
+
+
+void MacroAssembler::Prologue(PrologueFrameMode frame_mode) {
+  if (frame_mode == BUILD_STUB_FRAME) {
+    Push(ra, fp, cp);
+    Push(Smi::FromInt(StackFrame::STUB));
+    // Adjust FP to point to saved FP.
+    Addu(fp, sp, Operand(2 * kPointerSize));
+  } else {
+    PredictableCodeSizeScope predictible_code_size_scope(
+      this, kNoCodeAgeSequenceLength * Assembler::kInstrSize);
+    // The following three instructions must remain together and unmodified
+    // for code aging to work properly.
+    if (FLAG_optimize_for_size && FLAG_age_code) {
+      // Pre-age the code.
+      Code* stub = Code::GetPreAgedCodeAgeStub(isolate());
+      nop(Assembler::CODE_AGE_MARKER_NOP);
+      // Save the function's original return address
+      // (it will be clobbered by Call(t9))
+      mov(at, ra);
+      // Load the stub address to t9 and call it
+      li(t9,
+         Operand(reinterpret_cast<uint32_t>(stub->instruction_start())));
+      Call(t9);
+ // Record the stub address in the empty space for GetCodeAgeAndParity()
+      dd(reinterpret_cast<uint32_t>(stub->instruction_start()));
+    } else {
+      Push(ra, fp, cp, a1);
+      nop(Assembler::CODE_AGE_SEQUENCE_NOP);
+      // Adjust fp to point to caller's fp.
+      Addu(fp, sp, Operand(2 * kPointerSize));
+    }
+  }
+}


 void MacroAssembler::EnterFrame(StackFrame::Type type) {
=======================================
--- /branches/bleeding_edge/src/mips/macro-assembler-mips.h Tue Oct 15 23:12:15 2013 UTC +++ /branches/bleeding_edge/src/mips/macro-assembler-mips.h Wed Oct 23 13:48:04 2013 UTC
@@ -1497,6 +1497,9 @@
     srl(reg, reg, shift);
     And(reg, reg, Operand(mask));
   }
+
+  // Generates function and stub prologue code.
+  void Prologue(PrologueFrameMode frame_mode);

   // Activation support.
   void EnterFrame(StackFrame::Type type);
=======================================
--- /branches/bleeding_edge/src/objects.cc      Wed Oct 23 10:47:51 2013 UTC
+++ /branches/bleeding_edge/src/objects.cc      Wed Oct 23 13:48:04 2013 UTC
@@ -10384,6 +10384,10 @@
     } else if (RelocInfo::IsRuntimeEntry(mode)) {
       Address p = it.rinfo()->target_runtime_entry(origin);
       it.rinfo()->set_target_runtime_entry(p, SKIP_WRITE_BARRIER);
+    } else if (mode == RelocInfo::CODE_AGE_SEQUENCE) {
+      Handle<Object> p = it.rinfo()->code_age_stub_handle(origin);
+      Code* code = Code::cast(*p);
+      it.rinfo()->set_code_age_stub(code);
     } else {
       it.rinfo()->apply(delta);
     }
@@ -10623,6 +10627,12 @@
 void Code::MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate) {
   PatchPlatformCodeAge(isolate, sequence, kNoAge, NO_MARKING_PARITY);
 }
+
+
+void Code::MarkCodeAsExecuted(byte* sequence, Isolate* isolate) {
+  PatchPlatformCodeAge(isolate, sequence, kExecutedOnceCodeAge,
+      NO_MARKING_PARITY);
+}


 void Code::MakeOlder(MarkingParity current_parity) {
@@ -10642,18 +10652,14 @@


 bool Code::IsOld() {
-  byte* sequence = FindCodeAgeSequence();
-  if (sequence == NULL) return false;
-  Age age;
-  MarkingParity parity;
-  GetCodeAgeAndParity(sequence, &age, &parity);
-  return age >= kSexagenarianCodeAge;
+  Age age = GetAge();
+  return age >= kIsOldCodeAge;
 }


 byte* Code::FindCodeAgeSequence() {
   return FLAG_age_code &&
-      prologue_offset() != kPrologueOffsetNotSet &&
+      prologue_offset() != Code::kPrologueOffsetNotSet &&
       (kind() == OPTIMIZED_FUNCTION ||
        (kind() == FUNCTION && !has_debug_break_slots()))
       ? instruction_start() + prologue_offset()
@@ -10661,7 +10667,7 @@
 }


-int Code::GetAge() {
+Code::Age Code::GetAge() {
   byte* sequence = FindCodeAgeSequence();
   if (sequence == NULL) {
     return Code::kNoAge;
@@ -10693,6 +10699,20 @@
   }
   CODE_AGE_LIST(HANDLE_CODE_AGE)
 #undef HANDLE_CODE_AGE
+  stub = *builtins->MarkCodeAsExecutedOnce();
+  if (code == stub) {
+    // Treat that's never been executed as old immediatly.
+    *age = kIsOldCodeAge;
+    *parity = NO_MARKING_PARITY;
+    return;
+  }
+  stub = *builtins->MarkCodeAsExecutedTwice();
+  if (code == stub) {
+    // Pre-age code that has only been executed once.
+    *age = kPreAgedCodeAge;
+    *parity = NO_MARKING_PARITY;
+    return;
+  }
   UNREACHABLE();
 }

@@ -10709,6 +10729,14 @@
     }
     CODE_AGE_LIST(HANDLE_CODE_AGE)
 #undef HANDLE_CODE_AGE
+    case kNotExecutedCodeAge: {
+      ASSERT(parity == NO_MARKING_PARITY);
+      return *builtins->MarkCodeAsExecutedOnce();
+    }
+    case kExecutedOnceCodeAge: {
+      ASSERT(parity == NO_MARKING_PARITY);
+      return *builtins->MarkCodeAsExecutedTwice();
+    }
     default:
       UNREACHABLE();
       break;
=======================================
--- /branches/bleeding_edge/src/objects.h       Wed Oct 23 10:47:51 2013 UTC
+++ /branches/bleeding_edge/src/objects.h       Wed Oct 23 13:48:04 2013 UTC
@@ -4978,6 +4978,8 @@

   static const ExtraICState kNoExtraICState = 0;

+  static const int kPrologueOffsetNotSet = -1;
+
 #ifdef ENABLE_DISASSEMBLER
   // Printing
   static const char* ICState2String(InlineCacheState state);
@@ -5297,11 +5299,15 @@

 #define DECLARE_CODE_AGE_ENUM(X) k##X##CodeAge,
   enum Age {
+    kNotExecutedCodeAge = -2,
+    kExecutedOnceCodeAge = -1,
     kNoAge = 0,
     CODE_AGE_LIST(DECLARE_CODE_AGE_ENUM)
     kAfterLastCodeAge,
     kLastCodeAge = kAfterLastCodeAge - 1,
-    kCodeAgeCount = kAfterLastCodeAge - 1
+    kCodeAgeCount = kAfterLastCodeAge - 1,
+    kIsOldCodeAge = kSexagenarianCodeAge,
+    kPreAgedCodeAge = kIsOldCodeAge - 1
   };
 #undef DECLARE_CODE_AGE_ENUM

@@ -5310,10 +5316,14 @@
   // relatively safe to flush this code object and replace it with the lazy
   // compilation stub.
   static void MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate);
+  static void MarkCodeAsExecuted(byte* sequence, Isolate* isolate);
   void MakeOlder(MarkingParity);
   static bool IsYoungSequence(byte* sequence);
   bool IsOld();
-  int GetAge();
+  Age GetAge();
+  static inline Code* GetPreAgedCodeAgeStub(Isolate* isolate) {
+    return GetCodeAgeStub(isolate, kNotExecutedCodeAge, NO_MARKING_PARITY);
+  }

   void PrintDeoptLocation(int bailout_id);
   bool CanDeoptAt(Address pc);
=======================================
--- /branches/bleeding_edge/src/serialize.cc    Wed Oct 23 10:47:51 2013 UTC
+++ /branches/bleeding_edge/src/serialize.cc    Wed Oct 23 13:48:04 2013 UTC
@@ -589,6 +589,10 @@
       UNCLASSIFIED,
       65,
       "uint32_bias");
+ Add(ExternalReference::get_mark_code_as_executed_function(isolate).address(),
+      UNCLASSIFIED,
+      66,
+      "Code::MarkCodeAsExecuted");

// Add a small set of deopt entry addresses to encoder without generating the
   // deopt table code, which isn't possible at deserialization time.
=======================================
--- /branches/bleeding_edge/src/x64/assembler-x64-inl.h Wed Sep 11 10:51:06 2013 UTC +++ /branches/bleeding_edge/src/x64/assembler-x64-inl.h Wed Oct 23 13:48:04 2013 UTC
@@ -43,6 +43,7 @@


 static const byte kCallOpcode = 0xE8;
+static const int kNoCodeAgeSequenceLength = 6;


 void Assembler::emitl(uint32_t x) {
@@ -79,7 +80,8 @@
 void Assembler::emit_code_target(Handle<Code> target,
                                  RelocInfo::Mode rmode,
                                  TypeFeedbackId ast_id) {
-  ASSERT(RelocInfo::IsCodeTarget(rmode));
+  ASSERT(RelocInfo::IsCodeTarget(rmode) ||
+      rmode == RelocInfo::CODE_AGE_SEQUENCE);
   if (rmode == RelocInfo::CODE_TARGET && !ast_id.IsNone()) {
     RecordRelocInfo(RelocInfo::CODE_TARGET_WITH_ID, ast_id.ToInt());
   } else {
@@ -390,6 +392,13 @@
 bool RelocInfo::IsPatchedDebugBreakSlotSequence() {
   return !Assembler::IsNop(pc());
 }
+
+
+Handle<Object> RelocInfo::code_age_stub_handle(Assembler* origin) {
+  ASSERT(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
+  ASSERT(*pc_ == kCallOpcode);
+  return origin->code_target_object_handle_at(pc_ + 1);
+}


 Code* RelocInfo::code_age_stub() {
=======================================
--- /branches/bleeding_edge/src/x64/assembler-x64.cc Tue Oct 15 12:51:58 2013 UTC +++ /branches/bleeding_edge/src/x64/assembler-x64.cc Wed Oct 23 13:48:04 2013 UTC
@@ -3004,8 +3004,8 @@

 void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
   ASSERT(!RelocInfo::IsNone(rmode));
-  // Don't record external references unless the heap will be serialized.
   if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
+    // Don't record external references unless the heap will be serialized.
 #ifdef DEBUG
     if (!Serializer::enabled()) {
       Serializer::TooLateToEnableNow();
@@ -3014,6 +3014,9 @@
     if (!Serializer::enabled() && !emit_debug_code()) {
       return;
     }
+  } else if (rmode == RelocInfo::CODE_AGE_SEQUENCE) {
+    // Don't record psuedo relocation info for code age sequence mode.
+    return;
   }
   RelocInfo rinfo(pc_, rmode, data, NULL);
   reloc_info_writer.Write(&rinfo);
=======================================
--- /branches/bleeding_edge/src/x64/builtins-x64.cc Thu Oct 3 01:22:25 2013 UTC +++ /branches/bleeding_edge/src/x64/builtins-x64.cc Wed Oct 23 13:48:04 2013 UTC
@@ -627,6 +627,42 @@
 #undef DEFINE_CODE_AGE_BUILTIN_GENERATOR


+void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
+ // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact + // that make_code_young doesn't do any garbage collection which allows us to + // save/restore the registers without worrying about which of them contain
+  // pointers.
+  __ Pushad();
+  __ movq(arg_reg_2, ExternalReference::isolate_address(masm->isolate()));
+  __ movq(arg_reg_1, Operand(rsp, kNumSafepointRegisters * kPointerSize));
+  __ subq(arg_reg_1, Immediate(Assembler::kShortCallInstructionLength));
+  {  // NOLINT
+    FrameScope scope(masm, StackFrame::MANUAL);
+    __ PrepareCallCFunction(1);
+    __ CallCFunction(
+ ExternalReference::get_mark_code_as_executed_function(masm->isolate()),
+        1);
+  }
+  __ Popad();
+
+  // Perform prologue operations usually performed by the young code stub.
+  __ pop(r10);   // Pop return address into scratch register.
+  __ push(rbp);  // Caller's frame pointer.
+  __ movq(rbp, rsp);
+  __ push(rsi);  // Callee's context.
+  __ push(rdi);  // Callee's JS Function.
+  __ push(r10);  // Push return address after frame prologue.
+
+  // Jump to point after the code-age stub.
+  __ ret(0);
+}
+
+
+void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
+  GenerateMakeCodeYoungAgainCommon(masm);
+}
+
+
 void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
   // Enter an internal frame.
   {
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.cc Tue Oct 15 15:04:29 2013 UTC +++ /branches/bleeding_edge/src/x64/codegen-x64.cc Wed Oct 23 13:48:04 2013 UTC
@@ -675,8 +675,6 @@
 #undef __


-static const int kNoCodeAgeSequenceLength = 6;
-
 static byte* GetNoCodeAgeSequence(uint32_t* length) {
   static bool initialized = false;
   static byte sequence[kNoCodeAgeSequenceLength];
@@ -733,11 +731,8 @@
     Code* stub = GetCodeAgeStub(isolate, age, parity);
     CodePatcher patcher(sequence, young_length);
     patcher.masm()->call(stub->instruction_start());
-    for (int i = 0;
- i < kNoCodeAgeSequenceLength - Assembler::kShortCallInstructionLength;
-         i++) {
-      patcher.masm()->nop();
-    }
+    patcher.masm()->Nop(
+        kNoCodeAgeSequenceLength - Assembler::kShortCallInstructionLength);
   }
 }

=======================================
--- /branches/bleeding_edge/src/x64/full-codegen-x64.cc Wed Oct 23 08:47:15 2013 UTC +++ /branches/bleeding_edge/src/x64/full-codegen-x64.cc Wed Oct 23 13:48:04 2013 UTC
@@ -152,10 +152,7 @@
   FrameScope frame_scope(masm_, StackFrame::MANUAL);

   info->set_prologue_offset(masm_->pc_offset());
-  __ push(rbp);  // Caller's frame pointer.
-  __ movq(rbp, rsp);
-  __ push(rsi);  // Callee's context.
-  __ push(rdi);  // Callee's JS Function.
+  __ Prologue(BUILD_FUNCTION_FRAME);
   info->AddNoFrameRange(0, masm_->pc_offset());

   { Comment cmnt(masm_, "[ Allocate locals");
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Wed Oct 23 08:57:54 2013 UTC +++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Wed Oct 23 13:48:04 2013 UTC
@@ -143,14 +143,7 @@
   if (NeedsEagerFrame()) {
     ASSERT(!frame_is_built_);
     frame_is_built_ = true;
-    __ push(rbp);  // Caller's frame pointer.
-    __ movq(rbp, rsp);
-    __ push(rsi);  // Callee's context.
-    if (info()->IsStub()) {
-      __ Push(Smi::FromInt(StackFrame::STUB));
-    } else {
-      __ push(rdi);  // Callee's JS function.
-    }
+ __ Prologue(info()->IsStub() ? BUILD_STUB_FRAME : BUILD_FUNCTION_FRAME);
     info()->AddNoFrameRange(0, masm_->pc_offset());
   }

=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Wed Oct 23 08:47:15 2013 UTC +++ /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Wed Oct 23 13:48:04 2013 UTC
@@ -2635,7 +2635,8 @@
 #ifdef DEBUG
   int end_position = pc_offset() + CallSize(code_object);
 #endif
-  ASSERT(RelocInfo::IsCodeTarget(rmode));
+  ASSERT(RelocInfo::IsCodeTarget(rmode) ||
+      rmode == RelocInfo::CODE_AGE_SEQUENCE);
   call(code_object, rmode, ast_id);
 #ifdef DEBUG
   CHECK_EQ(end_position, pc_offset());
@@ -3647,6 +3648,30 @@
     bind(&invoke);
   }
 }
+
+
+void MacroAssembler::Prologue(PrologueFrameMode frame_mode) {
+  if (frame_mode == BUILD_STUB_FRAME) {
+    push(rbp);  // Caller's frame pointer.
+    movq(rbp, rsp);
+    push(rsi);  // Callee's context.
+    Push(Smi::FromInt(StackFrame::STUB));
+  } else {
+    PredictableCodeSizeScope predictible_code_size_scope(this,
+        kNoCodeAgeSequenceLength);
+    if (FLAG_optimize_for_size && FLAG_age_code) {
+        // Pre-age the code.
+      Call(isolate()->builtins()->MarkCodeAsExecutedOnce(),
+           RelocInfo::CODE_AGE_SEQUENCE);
+ Nop(kNoCodeAgeSequenceLength - Assembler::kShortCallInstructionLength);
+    } else {
+      push(rbp);  // Caller's frame pointer.
+      movq(rbp, rsp);
+      push(rsi);  // Callee's context.
+      push(rdi);  // Callee's JS function.
+    }
+  }
+}


 void MacroAssembler::EnterFrame(StackFrame::Type type) {
=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.h Wed Oct 23 08:47:15 2013 UTC +++ /branches/bleeding_edge/src/x64/macro-assembler-x64.h Wed Oct 23 13:48:04 2013 UTC
@@ -282,6 +282,9 @@
   void DebugBreak();
 #endif

+  // Generates function and stub prologue code.
+  void Prologue(PrologueFrameMode frame_mode);
+
   // Enter specific kind of exit frame; either in normal or
   // debug mode. Expects the number of arguments in register rax and
   // sets up the number of arguments in register rdi and the pointer
=======================================
--- /branches/bleeding_edge/test/cctest/test-heap.cc Wed Sep 25 09:25:39 2013 UTC +++ /branches/bleeding_edge/test/cctest/test-heap.cc Wed Oct 23 13:48:04 2013 UTC
@@ -1031,6 +1031,7 @@
   // If we do not flush code this test is invalid.
   if (!FLAG_flush_code) return;
   i::FLAG_allow_natives_syntax = true;
+  i::FLAG_optimize_for_size = false;
   CcTest::InitializeVM();
   Isolate* isolate = CcTest::i_isolate();
   Factory* factory = isolate->factory();
@@ -1065,6 +1066,71 @@
   for (int i = 0; i < kAgingThreshold; i++) {
     CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   }
+
+  // foo should no longer be in the compilation cache
+  CHECK(!function->shared()->is_compiled() || function->IsOptimized());
+  CHECK(!function->is_compiled() || function->IsOptimized());
+  // Call foo to get it recompiled.
+  CompileRun("foo()");
+  CHECK(function->shared()->is_compiled());
+  CHECK(function->is_compiled());
+}
+
+
+TEST(TestCodeFlushingPreAged) {
+  // If we do not flush code this test is invalid.
+  if (!FLAG_flush_code) return;
+  i::FLAG_allow_natives_syntax = true;
+  i::FLAG_optimize_for_size = true;
+  CcTest::InitializeVM();
+  Isolate* isolate = Isolate::Current();
+  Factory* factory = isolate->factory();
+  v8::HandleScope scope(CcTest::isolate());
+  const char* source = "function foo() {"
+                       "  var x = 42;"
+                       "  var y = 42;"
+                       "  var z = x + y;"
+                       "};"
+                       "foo()";
+  Handle<String> foo_name = factory->InternalizeUtf8String("foo");
+
+  // Compile foo, but don't run it.
+  { v8::HandleScope scope(CcTest::isolate());
+    CompileRun(source);
+  }
+
+  // Check function is compiled.
+  Object* func_value = Isolate::Current()->context()->global_object()->
+      GetProperty(*foo_name)->ToObjectChecked();
+  CHECK(func_value->IsJSFunction());
+  Handle<JSFunction> function(JSFunction::cast(func_value));
+  CHECK(function->shared()->is_compiled());
+
+  // The code has been run so will survive at least one GC.
+  CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
+  CHECK(function->shared()->is_compiled());
+
+ // The code was only run once, so it should be pre-aged and collected on the
+  // next GC.
+  CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
+  CHECK(!function->shared()->is_compiled() || function->IsOptimized());
+
+ // Execute the function again twice, and ensure it is reset to the young age.
+  { v8::HandleScope scope(CcTest::isolate());
+    CompileRun("foo();"
+               "foo();");
+  }
+
+  // The code will survive at least two GC now that it is young again.
+  CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
+  CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
+  CHECK(function->shared()->is_compiled());
+
+  // Simulate several GCs that use full marking.
+  const int kAgingThreshold = 6;
+  for (int i = 0; i < kAgingThreshold; i++) {
+    CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
+  }

   // foo should no longer be in the compilation cache
   CHECK(!function->shared()->is_compiled() || function->IsOptimized());
@@ -1080,6 +1146,7 @@
   // If we do not flush code this test is invalid.
   if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
   i::FLAG_allow_natives_syntax = true;
+  i::FLAG_optimize_for_size = false;
   CcTest::InitializeVM();
   Isolate* isolate = CcTest::i_isolate();
   Factory* factory = isolate->factory();
@@ -1148,6 +1215,7 @@
   // If we do not flush code this test is invalid.
   if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
   i::FLAG_allow_natives_syntax = true;
+  i::FLAG_optimize_for_size = false;
   CcTest::InitializeVM();
   Isolate* isolate = CcTest::i_isolate();
   Factory* factory = isolate->factory();
@@ -1216,6 +1284,7 @@
   // If we do not flush code this test is invalid.
   if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
   i::FLAG_allow_natives_syntax = true;
+  i::FLAG_optimize_for_size = false;
   CcTest::InitializeVM();
   Isolate* isolate = CcTest::i_isolate();
   Factory* factory = isolate->factory();

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to