Version 2.2.16.

Remove the SetExternalStringDiposeCallback API. Changed the disposal of external string resources to call a virtual Dispose method on the resource.

Added support for more precise break points when debugging and stepping.

Memory usage improvements on all platforms.


git-svn-id: http://v8.googlecode.com/svn/trunk@4829 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/full-codegen.cc b/src/full-codegen.cc
index f7a063a..6316158 100644
--- a/src/full-codegen.cc
+++ b/src/full-codegen.cc
@@ -439,6 +439,231 @@
 #undef CHECK_BAILOUT
 
 
+void BreakableStatementChecker::Check(Statement* stmt) {
+  Visit(stmt);
+}
+
+
+void BreakableStatementChecker::Check(Expression* expr) {
+  Visit(expr);
+}
+
+
+void BreakableStatementChecker::VisitDeclaration(Declaration* decl) {
+}
+
+
+void BreakableStatementChecker::VisitBlock(Block* stmt) {
+}
+
+
+void BreakableStatementChecker::VisitExpressionStatement(
+    ExpressionStatement* stmt) {
+  // Check if expression is breakable.
+  Visit(stmt->expression());
+}
+
+
+void BreakableStatementChecker::VisitEmptyStatement(EmptyStatement* stmt) {
+}
+
+
+void BreakableStatementChecker::VisitIfStatement(IfStatement* stmt) {
+  // If the condition is breakable the if statement is breakable.
+  Visit(stmt->condition());
+}
+
+
+void BreakableStatementChecker::VisitContinueStatement(
+    ContinueStatement* stmt) {
+}
+
+
+void BreakableStatementChecker::VisitBreakStatement(BreakStatement* stmt) {
+}
+
+
+void BreakableStatementChecker::VisitReturnStatement(ReturnStatement* stmt) {
+  // Return is breakable if the expression is.
+  Visit(stmt->expression());
+}
+
+
+void BreakableStatementChecker::VisitWithEnterStatement(
+    WithEnterStatement* stmt) {
+  Visit(stmt->expression());
+}
+
+
+void BreakableStatementChecker::VisitWithExitStatement(
+    WithExitStatement* stmt) {
+}
+
+
+void BreakableStatementChecker::VisitSwitchStatement(SwitchStatement* stmt) {
+  // Switch statements breakable if the tag expression is.
+  Visit(stmt->tag());
+}
+
+
+void BreakableStatementChecker::VisitDoWhileStatement(DoWhileStatement* stmt) {
+  // Mark do while as breakable to avoid adding a break slot in front of it.
+  is_breakable_ = true;
+}
+
+
+void BreakableStatementChecker::VisitWhileStatement(WhileStatement* stmt) {
+  // Mark while statements breakable if the condition expression is.
+  Visit(stmt->cond());
+}
+
+
+void BreakableStatementChecker::VisitForStatement(ForStatement* stmt) {
+  // Mark for statements breakable if the condition expression is.
+  if (stmt->cond() != NULL) {
+    Visit(stmt->cond());
+  }
+}
+
+
+void BreakableStatementChecker::VisitForInStatement(ForInStatement* stmt) {
+  // Mark for in statements breakable if the enumerable expression is.
+  Visit(stmt->enumerable());
+}
+
+
+void BreakableStatementChecker::VisitTryCatchStatement(
+    TryCatchStatement* stmt) {
+  // Mark try catch as breakable to avoid adding a break slot in front of it.
+  is_breakable_ = true;
+}
+
+
+void BreakableStatementChecker::VisitTryFinallyStatement(
+    TryFinallyStatement* stmt) {
+  // Mark try finally as breakable to avoid adding a break slot in front of it.
+  is_breakable_ = true;
+}
+
+
+void BreakableStatementChecker::VisitDebuggerStatement(
+    DebuggerStatement* stmt) {
+  // The debugger statement is breakable.
+  is_breakable_ = true;
+}
+
+
+void BreakableStatementChecker::VisitFunctionLiteral(FunctionLiteral* expr) {
+}
+
+
+void BreakableStatementChecker::VisitSharedFunctionInfoLiteral(
+    SharedFunctionInfoLiteral* expr) {
+}
+
+
+void BreakableStatementChecker::VisitConditional(Conditional* expr) {
+}
+
+
+void BreakableStatementChecker::VisitSlot(Slot* expr) {
+}
+
+
+void BreakableStatementChecker::VisitVariableProxy(VariableProxy* expr) {
+}
+
+
+void BreakableStatementChecker::VisitLiteral(Literal* expr) {
+}
+
+
+void BreakableStatementChecker::VisitRegExpLiteral(RegExpLiteral* expr) {
+}
+
+
+void BreakableStatementChecker::VisitObjectLiteral(ObjectLiteral* expr) {
+}
+
+
+void BreakableStatementChecker::VisitArrayLiteral(ArrayLiteral* expr) {
+}
+
+
+void BreakableStatementChecker::VisitCatchExtensionObject(
+    CatchExtensionObject* expr) {
+}
+
+
+void BreakableStatementChecker::VisitAssignment(Assignment* expr) {
+  // If assigning to a property (including a global property) the assignment is
+  // breakable.
+  Variable* var = expr->target()->AsVariableProxy()->AsVariable();
+  Property* prop = expr->target()->AsProperty();
+  if (prop != NULL || (var != NULL && var->is_global())) {
+    is_breakable_ = true;
+    return;
+  }
+
+  // Otherwise the assignment is breakable if the assigned value is.
+  Visit(expr->value());
+}
+
+
+void BreakableStatementChecker::VisitThrow(Throw* expr) {
+  // Throw is breakable if the expression is.
+  Visit(expr->exception());
+}
+
+
+void BreakableStatementChecker::VisitProperty(Property* expr) {
+  // Property load is breakable.
+  is_breakable_ = true;
+}
+
+
+void BreakableStatementChecker::VisitCall(Call* expr) {
+  // Function calls both through IC and call stub are breakable.
+  is_breakable_ = true;
+}
+
+
+void BreakableStatementChecker::VisitCallNew(CallNew* expr) {
+  // Function calls through new are breakable.
+  is_breakable_ = true;
+}
+
+
+void BreakableStatementChecker::VisitCallRuntime(CallRuntime* expr) {
+}
+
+
+void BreakableStatementChecker::VisitUnaryOperation(UnaryOperation* expr) {
+  Visit(expr->expression());
+}
+
+
+void BreakableStatementChecker::VisitCountOperation(CountOperation* expr) {
+  Visit(expr->expression());
+}
+
+
+void BreakableStatementChecker::VisitBinaryOperation(BinaryOperation* expr) {
+  Visit(expr->left());
+  Visit(expr->right());
+}
+
+
+void BreakableStatementChecker::VisitCompareOperation(CompareOperation* expr) {
+  Visit(expr->left());
+  Visit(expr->right());
+}
+
+
+void BreakableStatementChecker::VisitThisFunction(ThisFunction* expr) {
+}
+
+
 #define __ ACCESS_MASM(masm())
 
 Handle<Code> FullCodeGenerator::MakeCode(CompilationInfo* info) {
@@ -552,7 +777,60 @@
 
 void FullCodeGenerator::SetStatementPosition(Statement* stmt) {
   if (FLAG_debug_info) {
+#ifdef ENABLE_DEBUGGER_SUPPORT
+    if (!Debugger::IsDebuggerActive()) {
+      CodeGenerator::RecordPositions(masm_, stmt->statement_pos());
+    } else {
+      // Check if the statement will be breakable without adding a debug break
+      // slot.
+      BreakableStatementChecker checker;
+      checker.Check(stmt);
+      // Record the statement position right here if the statement is not
+      // breakable. For breakable statements the actual recording of the
+      // position will be postponed to the breakable code (typically an IC).
+      bool position_recorded = CodeGenerator::RecordPositions(
+          masm_, stmt->statement_pos(), !checker.is_breakable());
+      // If the position recording did record a new position generate a debug
+      // break slot to make the statement breakable.
+      if (position_recorded) {
+        Debug::GenerateSlot(masm_);
+      }
+    }
+#else
     CodeGenerator::RecordPositions(masm_, stmt->statement_pos());
+#endif
+  }
+}
+
+
+void FullCodeGenerator::SetExpressionPosition(Expression* expr, int pos) {
+  if (FLAG_debug_info) {
+#ifdef ENABLE_DEBUGGER_SUPPORT
+    if (!Debugger::IsDebuggerActive()) {
+      CodeGenerator::RecordPositions(masm_, pos);
+    } else {
+      // Check if the expression will be breakable without adding a debug break
+      // slot.
+      BreakableStatementChecker checker;
+      checker.Check(expr);
+      // Record a statement position right here if the expression is not
+      // breakable. For breakable expressions the actual recording of the
+      // position will be postponed to the breakable code (typically an IC).
+      // NOTE this will record a statement position for something which might
+      // not be a statement. As stepping in the debugger will only stop at
+      // statement positions this is used for e.g. the condition expression of
+      // a do while loop.
+      bool position_recorded = CodeGenerator::RecordPositions(
+          masm_, pos, !checker.is_breakable());
+      // If the position recording did record a new position generate a debug
+      // break slot to make the statement breakable.
+      if (position_recorded) {
+        Debug::GenerateSlot(masm_);
+      }
+    }
+#else
+    CodeGenerator::RecordPositions(masm_, pos);
+#endif
   }
 }
 
@@ -848,7 +1126,11 @@
   __ bind(&stack_check_success);
 
   __ bind(loop_statement.continue_target());
-  SetStatementPosition(stmt->condition_position());
+
+  // Record the position of the do while condition and make sure it is possible
+  // to break on the condition.
+  SetExpressionPosition(stmt->cond(), stmt->condition_position());
+
   VisitForControl(stmt->cond(), &body, loop_statement.break_target());
 
   __ bind(&stack_limit_hit);
@@ -864,7 +1146,6 @@
 
 void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
   Comment cmnt(masm_, "[ WhileStatement");
-  SetStatementPosition(stmt);
   Label body, stack_limit_hit, stack_check_success;
 
   Iteration loop_statement(this, stmt);
@@ -877,6 +1158,9 @@
   Visit(stmt->body());
 
   __ bind(loop_statement.continue_target());
+  // Emit the statement position here as this is where the while statement code
+  // starts.
+  SetStatementPosition(stmt);
 
   // Check stack before looping.
   __ StackLimitCheck(&stack_limit_hit);
@@ -896,7 +1180,6 @@
 
 void FullCodeGenerator::VisitForStatement(ForStatement* stmt) {
   Comment cmnt(masm_, "[ ForStatement");
-  SetStatementPosition(stmt);
   Label test, body, stack_limit_hit, stack_check_success;
 
   Iteration loop_statement(this, stmt);
@@ -919,6 +1202,9 @@
   }
 
   __ bind(&test);
+  // Emit the statement position here as this is where the for statement code
+  // starts.
+  SetStatementPosition(stmt);
 
   // Check stack before looping.
   __ StackLimitCheck(&stack_limit_hit);
@@ -1064,6 +1350,8 @@
   VisitForControl(expr->condition(), &true_case, &false_case);
 
   __ bind(&true_case);
+  SetExpressionPosition(expr->then_expression(),
+                        expr->then_expression_position());
   Visit(expr->then_expression());
   // If control flow falls through Visit, jump to done.
   if (context_ == Expression::kEffect || context_ == Expression::kValue) {
@@ -1071,6 +1359,8 @@
   }
 
   __ bind(&false_case);
+  SetExpressionPosition(expr->else_expression(),
+                        expr->else_expression_position());
   Visit(expr->else_expression());
   // If control flow falls through Visit, merge it with true case here.
   if (context_ == Expression::kEffect || context_ == Expression::kValue) {