Upgrade V8 to 2.1.10
authorRyan Dahl <ry@tinyclouds.org>
Fri, 26 Mar 2010 16:09:40 +0000 (09:09 -0700)
committerRyan Dahl <ry@tinyclouds.org>
Fri, 26 Mar 2010 16:09:40 +0000 (09:09 -0700)
43 files changed:
deps/v8/ChangeLog
deps/v8/SConstruct
deps/v8/include/v8.h
deps/v8/src/SConscript
deps/v8/src/arguments.h
deps/v8/src/arm/codegen-arm.cc
deps/v8/src/arm/codegen-arm.h
deps/v8/src/arm/ic-arm.cc
deps/v8/src/arm/stub-cache-arm.cc
deps/v8/src/code-stubs.cc
deps/v8/src/codegen.h
deps/v8/src/compiler.cc
deps/v8/src/compiler.h
deps/v8/src/conversions.cc
deps/v8/src/data-flow.cc
deps/v8/src/data-flow.h
deps/v8/src/flow-graph.cc [new file with mode: 0644]
deps/v8/src/flow-graph.h [new file with mode: 0644]
deps/v8/src/handles.cc
deps/v8/src/heap.cc
deps/v8/src/heap.h
deps/v8/src/ia32/codegen-ia32.cc
deps/v8/src/ia32/codegen-ia32.h
deps/v8/src/ia32/ic-ia32.cc
deps/v8/src/ia32/stub-cache-ia32.cc
deps/v8/src/oprofile-agent.cc
deps/v8/src/oprofile-agent.h
deps/v8/src/platform.h
deps/v8/src/stub-cache.cc
deps/v8/src/utils.h
deps/v8/src/version.cc
deps/v8/src/x64/codegen-x64.cc
deps/v8/src/x64/codegen-x64.h
deps/v8/src/x64/ic-x64.cc
deps/v8/src/x64/stub-cache-x64.cc
deps/v8/test/cctest/test-api.cc
deps/v8/test/cctest/test-conversions.cc
deps/v8/test/cctest/test-heap.cc
deps/v8/test/mjsunit/str-to-num.js
deps/v8/tools/gyp/v8.gyp
deps/v8/tools/visual_studio/v8_base.vcproj
deps/v8/tools/visual_studio/v8_base_arm.vcproj
deps/v8/tools/visual_studio/v8_base_x64.vcproj

index 5b1240d..0de3308 100644 (file)
@@ -1,3 +1,10 @@
+2010-03-26: Version 2.1.10
+
+        Fixed scons build issues.
+
+        Fixed a couple of minor bugs.
+
+
 2010-03-25: Version 2.1.9
 
         Added API support for reattaching a global object to a context.
index f950409..d33b567 100644 (file)
@@ -275,6 +275,7 @@ V8_EXTRA_FLAGS = {
   'gcc': {
     'all': {
       'WARNINGFLAGS': ['-Wall',
+                       '-Werror',
                        '-W',
                        '-Wno-unused-parameter',
                        '-Wnon-virtual-dtor']
@@ -1008,7 +1009,6 @@ def BuildSpecific(env, mode, env_overrides):
 
   # Link the object files into a library.
   env.Replace(**context.flags['v8'])
-  env.Prepend(LIBS=[library_name])
 
   context.ApplyEnvOverrides(env)
   if context.options['library'] == 'static':
@@ -1043,7 +1043,9 @@ def BuildSpecific(env, mode, env_overrides):
     sample_env.Depends(sample_program, library)
     context.sample_targets.append(sample_program)
 
-  cctest_program = env.SConscript(
+  cctest_env = env.Copy()
+  cctest_env.Prepend(LIBS=[library_name])
+  cctest_program = cctest_env.SConscript(
     join('test', 'cctest', 'SConscript'),
     build_dir=join('obj', 'test', target_id),
     exports='context object_files',
index 7b42178..f64b386 100644 (file)
@@ -3361,7 +3361,7 @@ External* External::Cast(v8::Value* value) {
 
 
 Local<Value> AccessorInfo::Data() const {
-  return Local<Value>(reinterpret_cast<Value*>(&args_[-3]));
+  return Local<Value>(reinterpret_cast<Value*>(&args_[-2]));
 }
 
 
index e7f6efd..a1d4796 100755 (executable)
@@ -61,6 +61,7 @@ SOURCES = {
     execution.cc
     factory.cc
     flags.cc
+    flow-graph.cc
     frame-element.cc
     frames.cc
     full-codegen.cc
index 3fed223..c17f4cf 100644 (file)
@@ -72,7 +72,7 @@ class Arguments BASE_EMBEDDED {
 };
 
 
-// Cursom arguments replicate a small segment of stack that can be
+// Custom arguments replicate a small segment of stack that can be
 // accessed through an Arguments object the same way the actual stack
 // can.
 class CustomArguments : public Relocatable {
@@ -80,15 +80,14 @@ class CustomArguments : public Relocatable {
   inline CustomArguments(Object* data,
                          JSObject* self,
                          JSObject* holder) {
-    values_[3] = self;
-    values_[2] = holder;
-    values_[1] = Smi::FromInt(0);
+    values_[2] = self;
+    values_[1] = holder;
     values_[0] = data;
   }
   void IterateInstance(ObjectVisitor* v);
-  Object** end() { return values_ + 3; }
+  Object** end() { return values_ + ARRAY_SIZE(values_) - 1; }
  private:
-  Object* values_[4];
+  Object* values_[3];
 };
 
 
index 5e00677..0ca4d35 100644 (file)
@@ -3996,14 +3996,7 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
 }
 
 
-void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
-#ifdef DEBUG
-  int original_height = frame_->height();
-#endif
-  VirtualFrame::SpilledScope spilled_scope;
-  Comment cmnt(masm_, "[ BinaryOperation");
-  Token::Value op = node->op();
-
+void CodeGenerator::GenerateLogicalBooleanOperation(BinaryOperation* node) {
   // According to ECMA-262 section 11.11, page 58, the binary logical
   // operators must yield the result of one of the two expressions
   // before any ToBoolean() conversions. This means that the value
@@ -4015,8 +4008,7 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
   // after evaluating the left hand side (due to the shortcut
   // semantics), but the compiler must (statically) know if the result
   // of compiling the binary operation is materialized or not.
-
-  if (op == Token::AND) {
+  if (node->op() == Token::AND) {
     JumpTarget is_true;
     LoadConditionAndSpill(node->left(),
                           &is_true,
@@ -4062,7 +4054,8 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
       ASSERT(!has_valid_frame() && !has_cc() && !is_true.is_linked());
     }
 
-  } else if (op == Token::OR) {
+  } else {
+    ASSERT(node->op() == Token::OR);
     JumpTarget is_false;
     LoadConditionAndSpill(node->left(),
                           true_target(),
@@ -4107,7 +4100,19 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
       // Nothing to do.
       ASSERT(!has_valid_frame() && !has_cc() && !is_false.is_linked());
     }
+  }
+}
+
+
+void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
+#ifdef DEBUG
+  int original_height = frame_->height();
+#endif
+  VirtualFrame::SpilledScope spilled_scope;
+  Comment cmnt(masm_, "[ BinaryOperation");
 
+  if (node->op() == Token::AND || node->op() == Token::OR) {
+    GenerateLogicalBooleanOperation(node);
   } else {
     // Optimize for the case where (at least) one of the expressions
     // is a literal small integer.
index 4bea341..0d1a385 100644 (file)
@@ -306,6 +306,9 @@ class CodeGenerator: public AstVisitor {
 
   void ToBoolean(JumpTarget* true_target, JumpTarget* false_target);
 
+  // Generate code that computes a shortcutting logical operation.
+  void GenerateLogicalBooleanOperation(BinaryOperation* node);
+
   void GenericBinaryOperation(Token::Value op,
                               OverwriteMode overwrite_mode,
                               int known_rhs = kUnknownIntValue);
index 2259aea..cc7cab7 100644 (file)
@@ -65,11 +65,11 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
   // Check for the absence of an interceptor.
   // Load the map into t0.
   __ ldr(t0, FieldMemOperand(t1, JSObject::kMapOffset));
-  // Test the has_named_interceptor bit in the map.
-  __ ldr(r3, FieldMemOperand(t0, Map::kInstanceAttributesOffset));
-  __ tst(r3, Operand(1 << (Map::kHasNamedInterceptor + (3 * 8))));
-  // Jump to miss if the interceptor bit is set.
-  __ b(ne, miss);
+
+  // Bail out if the receiver has a named interceptor.
+  __ ldrb(r3, FieldMemOperand(t0, Map::kBitFieldOffset));
+  __ tst(r3, Operand(1 << Map::kHasNamedInterceptor));
+  __ b(nz, miss);
 
   // Bail out if we have a JS global proxy object.
   __ ldrb(r3, FieldMemOperand(t0, Map::kInstanceTypeOffset));
@@ -144,6 +144,95 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
 }
 
 
+static void GenerateNumberDictionaryLoad(MacroAssembler* masm,
+                                         Label* miss,
+                                         Register elements,
+                                         Register key,
+                                         Register t0,
+                                         Register t1,
+                                         Register t2) {
+  // Register use:
+  //
+  // elements - holds the slow-case elements of the receiver and is unchanged.
+  //
+  // key      - holds the smi key on entry and is unchanged if a branch is
+  //            performed to the miss label.
+  //
+  // Scratch registers:
+  //
+  // t0 - holds the untagged key on entry and holds the hash once computed.
+  //      Holds the result on exit if the load succeeded.
+  //
+  // t1 - used to hold the capacity mask of the dictionary
+  //
+  // t2 - used for the index into the dictionary.
+  Label done;
+
+  // Compute the hash code from the untagged key.  This must be kept in sync
+  // with ComputeIntegerHash in utils.h.
+  //
+  // hash = ~hash + (hash << 15);
+  __ mvn(t1, Operand(t0));
+  __ add(t0, t1, Operand(t0, LSL, 15));
+  // hash = hash ^ (hash >> 12);
+  __ eor(t0, t0, Operand(t0, LSR, 12));
+  // hash = hash + (hash << 2);
+  __ add(t0, t0, Operand(t0, LSL, 2));
+  // hash = hash ^ (hash >> 4);
+  __ eor(t0, t0, Operand(t0, LSR, 4));
+  // hash = hash * 2057;
+  __ mov(t1, Operand(2057));
+  __ mul(t0, t0, t1);
+  // hash = hash ^ (hash >> 16);
+  __ eor(t0, t0, Operand(t0, LSR, 16));
+
+  // Compute the capacity mask.
+  __ ldr(t1, FieldMemOperand(elements, NumberDictionary::kCapacityOffset));
+  __ mov(t1, Operand(t1, ASR, kSmiTagSize));  // convert smi to int
+  __ sub(t1, t1, Operand(1));
+
+  // Generate an unrolled loop that performs a few probes before giving up.
+  static const int kProbes = 4;
+  for (int i = 0; i < kProbes; i++) {
+    // Use t2 for index calculations and keep the hash intact in t0.
+    __ mov(t2, t0);
+    // Compute the masked index: (hash + i + i * i) & mask.
+    if (i > 0) {
+      __ add(t2, t2, Operand(NumberDictionary::GetProbeOffset(i)));
+    }
+    __ and_(t2, t2, Operand(t1));
+
+    // Scale the index by multiplying by the element size.
+    ASSERT(NumberDictionary::kEntrySize == 3);
+    __ add(t2, t2, Operand(t2, LSL, 1));  // t2 = t2 * 3
+
+    // Check if the key is identical to the name.
+    __ add(t2, elements, Operand(t2, LSL, kPointerSizeLog2));
+    __ ldr(ip, FieldMemOperand(t2, NumberDictionary::kElementsStartOffset));
+    __ cmp(key, Operand(ip));
+    if (i != kProbes - 1) {
+      __ b(eq, &done);
+    } else {
+      __ b(ne, miss);
+    }
+  }
+
+  __ bind(&done);
+  // Check that the value is a normal property.
+  // t2: elements + (index * kPointerSize)
+  const int kDetailsOffset =
+      NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
+  __ ldr(t1, FieldMemOperand(t2, kDetailsOffset));
+  __ tst(t1, Operand(Smi::FromInt(PropertyDetails::TypeField::mask())));
+  __ b(ne, miss);
+
+  // Get the value at the masked, scaled index and return.
+  const int kValueOffset =
+      NumberDictionary::kElementsStartOffset + kPointerSize;
+  __ ldr(t0, FieldMemOperand(t2, kValueOffset));
+}
+
+
 void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
   // ----------- S t a t e -------------
   //  -- r2    : name
@@ -530,7 +619,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
   //  -- sp[0]  : key
   //  -- sp[4]  : receiver
   // -----------------------------------
-  Label slow, fast, check_pixel_array;
+  Label slow, fast, check_pixel_array, check_number_dictionary;
 
   // Get the key and receiver object from the stack.
   __ ldm(ia, sp, r0.bit() | r1.bit());
@@ -554,6 +643,8 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
 
   // Check that the key is a smi.
   __ BranchOnNotSmi(r0, &slow);
+  // Save key in r2 in case we want it for the number dictionary case.
+  __ mov(r2, r0);
   __ mov(r0, Operand(r0, ASR, kSmiTagSize));
 
   // Get the elements array of the object.
@@ -562,17 +653,26 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
   __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
   __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
   __ cmp(r3, ip);
-  __ b(ne, &slow);
+  __ b(ne, &check_pixel_array);
   // Check that the key (index) is within bounds.
   __ ldr(r3, FieldMemOperand(r1, Array::kLengthOffset));
   __ cmp(r0, Operand(r3));
-  __ b(lo, &fast);
+  __ b(ge, &slow);
+  // Fast case: Do the load.
+  __ add(r3, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+  __ ldr(r0, MemOperand(r3, r0, LSL, kPointerSizeLog2));
+  __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
+  __ cmp(r0, ip);
+  // In case the loaded value is the_hole we have to consult GetProperty
+  // to ensure the prototype chain is searched.
+  __ b(eq, &slow);
+  __ Ret();
 
   // Check whether the elements is a pixel array.
   __ bind(&check_pixel_array);
   __ LoadRoot(ip, Heap::kPixelArrayMapRootIndex);
   __ cmp(r3, ip);
-  __ b(ne, &slow);
+  __ b(ne, &check_number_dictionary);
   __ ldr(ip, FieldMemOperand(r1, PixelArray::kLengthOffset));
   __ cmp(r0, ip);
   __ b(hs, &slow);
@@ -581,22 +681,21 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
   __ mov(r0, Operand(r0, LSL, kSmiTagSize));  // Tag result as smi.
   __ Ret();
 
+  __ bind(&check_number_dictionary);
+  // Check whether the elements is a number dictionary.
+  // r0: untagged index
+  // r1: elements
+  // r2: key
+  __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
+  __ cmp(r3, ip);
+  __ b(ne, &slow);
+  GenerateNumberDictionaryLoad(masm, &slow, r1, r2, r0, r3, r4);
+  __ Ret();
+
   // Slow case: Push extra copies of the arguments (2).
   __ bind(&slow);
   __ IncrementCounter(&Counters::keyed_load_generic_slow, 1, r0, r1);
   GenerateRuntimeGetProperty(masm);
-
-  // Fast case: Do the load.
-  __ bind(&fast);
-  __ add(r3, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
-  __ ldr(r0, MemOperand(r3, r0, LSL, kPointerSizeLog2));
-  __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
-  __ cmp(r0, ip);
-  // In case the loaded value is the_hole we have to consult GetProperty
-  // to ensure the prototype chain is searched.
-  __ b(eq, &slow);
-
-  __ Ret();
 }
 
 
index abf2f64..bbffef2 100644 (file)
@@ -396,15 +396,14 @@ static void PushInterceptorArguments(MacroAssembler* masm,
                                      Register holder,
                                      Register name,
                                      JSObject* holder_obj) {
-  __ push(receiver);
-  __ push(holder);
   __ push(name);
   InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
   ASSERT(!Heap::InNewSpace(interceptor));
-
-  Register scratch = receiver;
+  Register scratch = name;
   __ mov(scratch, Operand(Handle<Object>(interceptor)));
   __ push(scratch);
+  __ push(receiver);
+  __ push(holder);
   __ ldr(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
   __ push(scratch);
 }
index e42f758..ea74898 100644 (file)
@@ -61,13 +61,9 @@ void CodeStub::GenerateCode(MacroAssembler* masm) {
 void CodeStub::RecordCodeGeneration(Code* code, MacroAssembler* masm) {
   code->set_major_key(MajorKey());
 
-#ifdef ENABLE_OPROFILE_AGENT
-  // Register the generated stub with the OPROFILE agent.
-  OProfileAgent::CreateNativeCodeRegion(GetName(),
-                                        code->instruction_start(),
-                                        code->instruction_size());
-#endif
-
+  OPROFILE(CreateNativeCodeRegion(GetName(),
+                                  code->instruction_start(),
+                                  code->instruction_size()));
   LOG(CodeCreateEvent(Logger::STUB_TAG, code, GetName()));
   Counters::total_stubs_code_size.Increment(code->instruction_size());
 
index 4634f4c..0dfea8d 100644 (file)
@@ -450,7 +450,7 @@ class ApiGetterEntryStub : public CodeStub {
   virtual bool GetCustomCache(Code** code_out);
   virtual void SetCustomCache(Code* value);
 
-  static const int kStackSpace = 6;
+  static const int kStackSpace = 5;
   static const int kArgc = 4;
  private:
   Handle<AccessorInfo> info() { return info_; }
index e2021fa..c9dd107 100755 (executable)
@@ -34,6 +34,7 @@
 #include "data-flow.h"
 #include "debug.h"
 #include "fast-codegen.h"
+#include "flow-graph.h"
 #include "full-codegen.h"
 #include "liveedit.h"
 #include "oprofile-agent.h"
@@ -235,27 +236,19 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(bool is_global,
     return Handle<SharedFunctionInfo>::null();
   }
 
-#if defined ENABLE_LOGGING_AND_PROFILING || defined ENABLE_OPROFILE_AGENT
-  // Log the code generation for the script. Check explicit whether logging is
-  // to avoid allocating when not required.
-  if (Logger::is_logging() || OProfileAgent::is_enabled()) {
-    if (script->name()->IsString()) {
-      SmartPointer<char> data =
-          String::cast(script->name())->ToCString(DISALLOW_NULLS);
-      LOG(CodeCreateEvent(is_eval ? Logger::EVAL_TAG : Logger::SCRIPT_TAG,
-                          *code, *data));
-      OProfileAgent::CreateNativeCodeRegion(*data,
-                                            code->instruction_start(),
-                                            code->instruction_size());
-    } else {
-      LOG(CodeCreateEvent(is_eval ? Logger::EVAL_TAG : Logger::SCRIPT_TAG,
-                          *code, ""));
-      OProfileAgent::CreateNativeCodeRegion(is_eval ? "Eval" : "Script",
-                                            code->instruction_start(),
-                                            code->instruction_size());
-    }
+  if (script->name()->IsString()) {
+    LOG(CodeCreateEvent(is_eval ? Logger::EVAL_TAG : Logger::SCRIPT_TAG,
+                        *code, String::cast(script->name())));
+    OPROFILE(CreateNativeCodeRegion(String::cast(script->name()),
+                                    code->instruction_start(),
+                                    code->instruction_size()));
+  } else {
+    LOG(CodeCreateEvent(is_eval ? Logger::EVAL_TAG : Logger::SCRIPT_TAG,
+                        *code, ""));
+    OPROFILE(CreateNativeCodeRegion(is_eval ? "Eval" : "Script",
+                                    code->instruction_start(),
+                                    code->instruction_size()));
   }
-#endif
 
   // Allocate function.
   Handle<SharedFunctionInfo> result =
@@ -443,14 +436,12 @@ bool Compiler::CompileLazy(CompilationInfo* info) {
     return false;
   }
 
-#if defined ENABLE_LOGGING_AND_PROFILING || defined ENABLE_OPROFILE_AGENT
-  LogCodeCreateEvent(Logger::LAZY_COMPILE_TAG,
-                     name,
-                     Handle<String>(shared->inferred_name()),
-                     start_position,
-                     info->script(),
-                     code);
-#endif
+  RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG,
+                            name,
+                            Handle<String>(shared->inferred_name()),
+                            start_position,
+                            info->script(),
+                            code);
 
   // Update the shared function info with the compiled code.
   shared->set_code(*code);
@@ -578,15 +569,12 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
     }
 
     // Function compilation complete.
-
-#if defined ENABLE_LOGGING_AND_PROFILING || defined ENABLE_OPROFILE_AGENT
-    LogCodeCreateEvent(Logger::FUNCTION_TAG,
-                       literal->name(),
-                       literal->inferred_name(),
-                       literal->start_position(),
-                       script,
-                       code);
-#endif
+    RecordFunctionCompilation(Logger::FUNCTION_TAG,
+                              literal->name(),
+                              literal->inferred_name(),
+                              literal->start_position(),
+                              script,
+                              code);
   }
 
   // Create a boilerplate function.
@@ -628,13 +616,12 @@ void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info,
 }
 
 
-#if defined ENABLE_LOGGING_AND_PROFILING || defined ENABLE_OPROFILE_AGENT
-void Compiler::LogCodeCreateEvent(Logger::LogEventsAndTags tag,
-                                  Handle<String> name,
-                                  Handle<String> inferred_name,
-                                  int start_position,
-                                  Handle<Script> script,
-                                  Handle<Code> code) {
+void Compiler::RecordFunctionCompilation(Logger::LogEventsAndTags tag,
+                                         Handle<String> name,
+                                         Handle<String> inferred_name,
+                                         int start_position,
+                                         Handle<Script> script,
+                                         Handle<Code> code) {
   // Log the code generation. If source information is available
   // include script name and line number. Check explicitly whether
   // logging is enabled as finding the line number is not free.
@@ -642,21 +629,21 @@ void Compiler::LogCodeCreateEvent(Logger::LogEventsAndTags tag,
     Handle<String> func_name(name->length() > 0 ? *name : *inferred_name);
     if (script->name()->IsString()) {
       int line_num = GetScriptLineNumber(script, start_position) + 1;
+      USE(line_num);
       LOG(CodeCreateEvent(tag, *code, *func_name,
                           String::cast(script->name()), line_num));
-      OProfileAgent::CreateNativeCodeRegion(*func_name,
-                                            String::cast(script->name()),
-                                            line_num,
-                                            code->instruction_start(),
-                                            code->instruction_size());
+      OPROFILE(CreateNativeCodeRegion(*func_name,
+                                      String::cast(script->name()),
+                                      line_num,
+                                      code->instruction_start(),
+                                      code->instruction_size()));
     } else {
       LOG(CodeCreateEvent(tag, *code, *func_name));
-      OProfileAgent::CreateNativeCodeRegion(*func_name,
-                                            code->instruction_start(),
-                                            code->instruction_size());
+      OPROFILE(CreateNativeCodeRegion(*func_name,
+                                      code->instruction_start(),
+                                      code->instruction_size()));
     }
   }
 }
-#endif
 
 } }  // namespace v8::internal
index e08e26e..ecc7b1c 100644 (file)
@@ -266,15 +266,12 @@ class Compiler : public AllStatic {
                               Handle<Script> script);
 
  private:
-
-#if defined ENABLE_LOGGING_AND_PROFILING || defined ENABLE_OPROFILE_AGENT
-  static void LogCodeCreateEvent(Logger::LogEventsAndTags tag,
-                                 Handle<String> name,
-                                 Handle<String> inferred_name,
-                                 int start_position,
-                                 Handle<Script> script,
-                                 Handle<Code> code);
-#endif
+  static void RecordFunctionCompilation(Logger::LogEventsAndTags tag,
+                                        Handle<String> name,
+                                        Handle<String> inferred_name,
+                                        int start_position,
+                                        Handle<Script> script,
+                                        Handle<Code> code);
 };
 
 
index d0abc2b..5c46752 100644 (file)
@@ -26,6 +26,7 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <stdarg.h>
+#include <limits.h>
 
 #include "v8.h"
 
@@ -92,80 +93,80 @@ static inline const char* GetCString(String* str, int index) {
 }
 
 
-static inline void ReleaseCString(const char* original, const char* str) {
-}
+namespace {
 
+// C++-style iterator adaptor for StringInputBuffer
+// (unlike C++ iterators the end-marker has different type).
+class StringInputBufferIterator {
+ public:
+  class EndMarker {};
 
-static inline void ReleaseCString(String* original, const char* str) {
-  DeleteArray(const_cast<char *>(str));
-}
+  explicit StringInputBufferIterator(StringInputBuffer* buffer);
 
+  int operator*() const;
+  void operator++();
+  bool operator==(EndMarker const&) const { return end_; }
+  bool operator!=(EndMarker const& m) const { return !end_; }
 
-static inline bool IsSpace(const char* str, int index) {
-  ASSERT(index >= 0 && index < StrLength(str));
-  return Scanner::kIsWhiteSpace.get(str[index]);
-}
+ private:
+  StringInputBuffer* const buffer_;
+  int current_;
+  bool end_;
+};
 
 
-static inline bool IsSpace(String* str, int index) {
-  return Scanner::kIsWhiteSpace.get(str->Get(index));
+StringInputBufferIterator::StringInputBufferIterator(
+    StringInputBuffer* buffer) : buffer_(buffer) {
+  ++(*this);
+}
+
+int StringInputBufferIterator::operator*() const {
+  return current_;
 }
 
 
-static inline bool SubStringEquals(const char* str,
-                                   int index,
-                                   const char* other) {
-  return strncmp(str + index, other, strlen(other)) != 0;
+void StringInputBufferIterator::operator++() {
+  end_ = !buffer_->has_more();
+  if (!end_) {
+    current_ = buffer_->GetNext();
+  }
+}
 }
 
 
-static inline bool SubStringEquals(String* str, int index, const char* other) {
-  HandleScope scope;
-  int str_length = str->length();
-  int other_length = StrLength(other);
-  int end = index + other_length < str_length ?
-            index + other_length :
-            str_length;
-  Handle<String> substring =
-      Factory::NewSubString(Handle<String>(str), index, end);
-  return substring->IsEqualTo(Vector<const char>(other, other_length));
+static inline void ReleaseCString(const char* original, const char* str) {
 }
 
 
-// Check if a string should be parsed as an octal number.  The string
-// can be either a char* or a String*.
-template<class S>
-static bool ShouldParseOctal(S* s, int i) {
-  int index = i;
-  int len = GetLength(s);
-  if (index < len && GetChar(s, index) != '0') return false;
-
-  // If the first real character (following '0') is not an octal
-  // digit, bail out early. This also takes care of numbers of the
-  // forms 0.xxx and 0exxx by not allowing the first 0 to be
-  // interpreted as an octal.
-  index++;
-  if (index < len) {
-    int d = GetChar(s, index) - '0';
-    if (d < 0 || d > 7) return false;
-  } else {
-    return false;
-  }
+static inline void ReleaseCString(String* original, const char* str) {
+  DeleteArray(const_cast<char *>(str));
+}
 
-  // Traverse all digits (including the first). If there is an octal
-  // prefix which is not a part of a longer decimal prefix, we return
-  // true. Otherwise, false is returned.
-  while (index < len) {
-    int d = GetChar(s, index++) - '0';
-    if (d == 8 || d == 9) return false;
-    if (d <  0 || d >  7) return true;
+
+template <class Iterator, class EndMark>
+static bool SubStringEquals(Iterator* current,
+                            EndMark end,
+                            const char* substring) {
+  ASSERT(**current == *substring);
+  for (substring++; *substring != '\0'; substring++) {
+    ++*current;
+    if (*current == end || **current != *substring) return false;
   }
+  ++*current;
   return true;
 }
 
 
 extern "C" double gay_strtod(const char* s00, const char** se);
 
+// Maximum number of significant digits in decimal representation.
+// The longest possible double in decimal representation is
+// (2^53 - 1) * 2 ^ -1074 that is (2 ^ 53 - 1) * 5 ^ 1074 / 10 ^ 1074
+// (768 digits). If we parse a number whose first digits are equal to a
+// mean of 2 adjacent doubles (that could have up to 769 digits) the result
+// must be rounded to the bigger one unless the tail consists of zeros, so
+// we don't need to preserve all the digits.
+const int kMaxSignificantDigits = 772;
 
 // Parse an int from a string starting a given index and in a given
 // radix.  The string can be either a char* or a String*.
@@ -262,95 +263,372 @@ int StringToInt(const char* str, int index, int radix, double* value) {
 static const double JUNK_STRING_VALUE = OS::nan_value();
 
 
-// Convert a string to a double value.  The string can be either a
-// char* or a String*.
-template<class S>
-static double InternalStringToDouble(S* str,
+// Returns true if a nonspace found and false if the end has reached.
+template <class Iterator, class EndMark>
+static inline bool AdvanceToNonspace(Iterator* current, EndMark end) {
+  while (*current != end) {
+    if (!Scanner::kIsWhiteSpace.get(**current)) return true;
+    ++*current;
+  }
+  return false;
+}
+
+
+template <class Iterator, class EndMark>
+static double InternalHexadecimalStringToDouble(Iterator current,
+                                                EndMark end,
+                                                char* buffer,
+                                                bool allow_trailing_junk) {
+  ASSERT(current != end);
+
+  const int max_hex_significant_digits = 52 / 4 + 2;
+  // We reuse the buffer of InternalStringToDouble. Since hexadecimal
+  // numbers may have much less digits than decimal the buffer won't overflow.
+  ASSERT(max_hex_significant_digits < kMaxSignificantDigits);
+
+  int significant_digits = 0;
+  int insignificant_digits = 0;
+  bool leading_zero = false;
+  // A double has a 53bit significand (once the hidden bit has been added).
+  // Halfway cases thus have at most 54bits. Therefore 54/4 + 1 digits are
+  // sufficient to represent halfway cases. By adding another digit we can keep
+  // track of dropped digits.
+  int buffer_pos = 0;
+  bool nonzero_digit_dropped = false;
+
+  // Skip leading 0s.
+  while (*current == '0') {
+    leading_zero = true;
+    ++current;
+    if (current == end) return 0;
+  }
+
+  int begin_pos = buffer_pos;
+  while ((*current >= '0' && *current <= '9')
+         || (*current >= 'a' && *current <= 'f')
+         || (*current >= 'A' && *current <= 'F')) {
+    if (significant_digits <= max_hex_significant_digits) {
+      buffer[buffer_pos++] = static_cast<char>(*current);
+      significant_digits++;
+    } else {
+      insignificant_digits++;
+      nonzero_digit_dropped = nonzero_digit_dropped || *current != '0';
+    }
+    ++current;
+    if (current == end) break;
+  }
+
+  if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
+    return JUNK_STRING_VALUE;
+  }
+
+  if (significant_digits == 0) {
+    return leading_zero ? 0 : JUNK_STRING_VALUE;
+  }
+
+  if (nonzero_digit_dropped) {
+    ASSERT(insignificant_digits > 0);
+    insignificant_digits--;
+    buffer[buffer_pos++] = '1';
+  }
+
+  buffer[buffer_pos] = '\0';
+
+  double result;
+  StringToInt(buffer, begin_pos, 16, &result);
+  if (insignificant_digits > 0) {
+    // Multiplying by a power of 2 doesn't cause a loss of precision.
+    result *= pow(16.0, insignificant_digits);
+  }
+  return result;
+}
+
+
+// Converts a string to a double value. Assumes the Iterator supports
+// the following operations:
+// 1. current == end (other ops are not allowed), current != end.
+// 2. *current - gets the current character in the sequence.
+// 3. ++current (advances the position).
+template <class Iterator, class EndMark>
+static double InternalStringToDouble(Iterator current,
+                                     EndMark end,
                                      int flags,
                                      double empty_string_val) {
-  double result = 0.0;
-  int index = 0;
+  // To make sure that iterator dereferencing is valid the following
+  // convention is used:
+  // 1. Each '++current' statement is followed by check for equality to 'end'.
+  // 2. If AdvanceToNonspace returned false then current == end.
+  // 3. If 'current' becomes be equal to 'end' the function returns or goes to
+  // 'parsing_done'.
+  // 4. 'current' is not dereferenced after the 'parsing_done' label.
+  // 5. Code before 'parsing_done' may rely on 'current != end'.
+  if (!AdvanceToNonspace(&current, end)) return empty_string_val;
+
+  const bool allow_trailing_junk = (flags & ALLOW_TRAILING_JUNK) != 0;
+
+  // The longest form of simplified number is: "-<significant digits>'.1eXXX\0".
+  const int kBufferSize = kMaxSignificantDigits + 10;
+  char buffer[kBufferSize];  // NOLINT: size is known at compile time.
+  int buffer_pos = 0;
+
+  // Exponent will be adjusted if insignificant digits of the integer part
+  // or insignificant leading zeros of the fractional part are dropped.
+  int exponent = 0;
+  int significant_digits = 0;
+  int insignificant_digits = 0;
+  bool nonzero_digit_dropped = false;
+
+  double signed_zero = 0.0;
+
+  if (*current == '+') {
+    // Ignore leading sign; skip following spaces.
+    ++current;
+    if (!AdvanceToNonspace(&current, end)) return JUNK_STRING_VALUE;
+  } else if (*current == '-') {
+    buffer[buffer_pos++] = '-';
+    ++current;
+    if (!AdvanceToNonspace(&current, end)) return JUNK_STRING_VALUE;
+    signed_zero = -0.0;
+  }
 
-  int len = GetLength(str);
+  static const char kInfinitySymbol[] = "Infinity";
+  if (*current == kInfinitySymbol[0]) {
+    if (!SubStringEquals(&current, end, kInfinitySymbol)) {
+      return JUNK_STRING_VALUE;
+    }
 
-  // Skip leading spaces.
-  while ((index < len) && IsSpace(str, index)) index++;
+    if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
+      return JUNK_STRING_VALUE;
+    }
 
-  // Is the string empty?
-  if (index >= len) return empty_string_val;
+    ASSERT(buffer_pos == 0 || buffer[0] == '-');
+    return buffer_pos > 0 ? -V8_INFINITY : V8_INFINITY;
+  }
 
-  // Get the first character.
-  uint16_t first = GetChar(str, index);
+  bool leading_zero = false;
+  if (*current == '0') {
+    ++current;
+    if (current == end) return signed_zero;
 
-  // Numbers can only start with '-', '+', '.', 'I' (Infinity), or a digit.
-  if (first != '-' && first != '+' && first != '.' && first != 'I' &&
-      (first > '9' || first < '0')) {
-    return JUNK_STRING_VALUE;
+    leading_zero = true;
+
+    // It could be hexadecimal value.
+    if ((flags & ALLOW_HEX) && (*current == 'x' || *current == 'X')) {
+      ++current;
+      if (current == end) return JUNK_STRING_VALUE;  // "0x".
+
+      double result = InternalHexadecimalStringToDouble(current,
+                                                        end,
+                                                        buffer + buffer_pos,
+                                                        allow_trailing_junk);
+      return (buffer_pos > 0 && buffer[0] == '-') ? -result : result;
+    }
+
+    // Ignore leading zeros in the integer part.
+    while (*current == '0') {
+      ++current;
+      if (current == end) return signed_zero;
+    }
   }
 
-  // Compute sign of result based on first character.
-  int sign = 1;
-  if (first == '-') {
-    sign = -1;
-    index++;
-    // String only containing a '-' are junk chars.
-    if (index == len) return JUNK_STRING_VALUE;
-  }
-
-  // do we have a hex number?
-  // (since the string is 0-terminated, it's ok to look one char beyond the end)
-  if ((flags & ALLOW_HEX) != 0 &&
-      (index + 1) < len &&
-      GetChar(str, index) == '0' &&
-      (GetChar(str, index + 1) == 'x' || GetChar(str, index + 1) == 'X')) {
-    index += 2;
-    index = StringToInt(str, index, 16, &result);
-  } else if ((flags & ALLOW_OCTALS) != 0 && ShouldParseOctal(str, index)) {
-    // NOTE: We optimistically try to parse the number as an octal (if
-    // we're allowed to), even though this is not as dictated by
-    // ECMA-262. The reason for doing this is compatibility with IE and
-    // Firefox.
-    index = StringToInt(str, index, 8, &result);
-  } else {
-    const char* cstr = GetCString(str, index);
-    const char* end;
-    // Optimistically parse the number and then, if that fails,
-    // check if it might have been {+,-,}Infinity.
-    result = gay_strtod(cstr, &end);
-    ReleaseCString(str, cstr);
-    if (result != 0.0 || end != cstr) {
-      // It appears that strtod worked
-      index += static_cast<int>(end - cstr);
+  bool octal = leading_zero && (flags & ALLOW_OCTALS) != 0;
+
+  // Copy significant digits of the integer part (if any) to the buffer.
+  while (*current >= '0' && *current <= '9') {
+    if (significant_digits < kMaxSignificantDigits) {
+      ASSERT(buffer_pos < kBufferSize);
+      buffer[buffer_pos++] = static_cast<char>(*current);
+      significant_digits++;
+      // Will later check if it's an octal in the buffer.
     } else {
-      // Check for {+,-,}Infinity
-      bool is_negative = (GetChar(str, index) == '-');
-      if (GetChar(str, index) == '+' || GetChar(str, index) == '-')
-        index++;
-      if (!SubStringEquals(str, index, "Infinity"))
+      insignificant_digits++;  // Move the digit into the exponential part.
+      nonzero_digit_dropped = nonzero_digit_dropped || *current != '0';
+    }
+    octal = octal && *current < '8';
+    ++current;
+    if (current == end) goto parsing_done;
+  }
+
+  if (significant_digits == 0) {
+    octal = false;
+  }
+
+  if (*current == '.') {
+    ASSERT(buffer_pos < kBufferSize);
+    buffer[buffer_pos++] = '.';
+    ++current;
+    if (current == end) {
+      if (significant_digits == 0 && !leading_zero) {
         return JUNK_STRING_VALUE;
-      result = is_negative ? -V8_INFINITY : V8_INFINITY;
-      index += 8;
+      } else {
+        goto parsing_done;
+      }
+    }
+
+    if (significant_digits == 0) {
+      // octal = false;
+      // Integer part consists of 0 or is absent. Significant digits start after
+      // leading zeros (if any).
+      while (*current == '0') {
+        ++current;
+        if (current == end) return signed_zero;
+        exponent--;  // Move this 0 into the exponent.
+      }
+    }
+
+    // There is the fractional part.
+    while (*current >= '0' && *current <= '9') {
+      if (significant_digits < kMaxSignificantDigits) {
+        ASSERT(buffer_pos < kBufferSize);
+        buffer[buffer_pos++] = static_cast<char>(*current);
+        significant_digits++;
+      } else {
+        // Ignore insignificant digits in the fractional part.
+        nonzero_digit_dropped = nonzero_digit_dropped || *current != '0';
+      }
+      ++current;
+      if (current == end) goto parsing_done;
     }
   }
 
-  if ((flags & ALLOW_TRAILING_JUNK) == 0) {
-    // skip trailing spaces
-    while ((index < len) && IsSpace(str, index)) index++;
-    // string ending with junk?
-    if (index < len) return JUNK_STRING_VALUE;
+  if (!leading_zero && exponent == 0 && significant_digits == 0) {
+    // If leading_zeros is true then the string contains zeros.
+    // If exponent < 0 then string was [+-]\.0*...
+    // If significant_digits != 0 the string is not equal to 0.
+    // Otherwise there are no digits in the string.
+    return JUNK_STRING_VALUE;
   }
 
-  return sign * result;
-}
+  // Parse exponential part.
+  if (*current == 'e' || *current == 'E') {
+    if (octal) return JUNK_STRING_VALUE;
+    ++current;
+    if (current == end) {
+      if (allow_trailing_junk) {
+        goto parsing_done;
+      } else {
+        return JUNK_STRING_VALUE;
+      }
+    }
+    char sign = '+';
+    if (*current == '+' || *current == '-') {
+      sign = static_cast<char>(*current);
+      ++current;
+      if (current == end) {
+        if (allow_trailing_junk) {
+          goto parsing_done;
+        } else {
+          return JUNK_STRING_VALUE;
+        }
+      }
+    }
+
+    if (current == end || *current < '0' || *current > '9') {
+      if (allow_trailing_junk) {
+        goto parsing_done;
+      } else {
+        return JUNK_STRING_VALUE;
+      }
+    }
+
+    const int max_exponent = INT_MAX / 2;
+    ASSERT(-max_exponent / 2 <= exponent && exponent <= max_exponent / 2);
+    int num = 0;
+    do {
+      // Check overflow.
+      int digit = *current - '0';
+      if (num >= max_exponent / 10
+          && !(num == max_exponent / 10 && digit <= max_exponent % 10)) {
+        num = max_exponent;
+      } else {
+        num = num * 10 + digit;
+      }
+      ++current;
+    } while (current != end && *current >= '0' && *current <= '9');
+
+    exponent += (sign == '-' ? -num : num);
+  }
+
+  if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
+    return JUNK_STRING_VALUE;
+  }
+
+  parsing_done:
+  exponent += insignificant_digits;
+
+  if (octal) {
+    buffer[buffer_pos] = '\0';
+    // ALLOW_OCTALS is set and there is no '8' or '9' in insignificant
+    // digits. Check significant digits now.
+    char sign = '+';
+    const char* s = buffer;
+    if (*s == '-' || *s == '+') sign = *s++;
 
+    double result;
+    s += StringToInt(s, 0, 8, &result);
+    if (!allow_trailing_junk && *s != '\0') return JUNK_STRING_VALUE;
+
+    if (sign == '-') result = -result;
+    if (insignificant_digits > 0) {
+      result *= pow(8.0, insignificant_digits);
+    }
+    return result;
+  }
+
+  if (nonzero_digit_dropped) {
+    if (insignificant_digits) buffer[buffer_pos++] = '.';
+    buffer[buffer_pos++] = '1';
+  }
+
+  if (exponent != 0) {
+    ASSERT(buffer_pos < kBufferSize);
+    buffer[buffer_pos++] = 'e';
+    if (exponent < 0) {
+      ASSERT(buffer_pos < kBufferSize);
+      buffer[buffer_pos++] = '-';
+      exponent = -exponent;
+    }
+    if (exponent > 999) exponent = 999;  // Result will be Infinity or 0 or -0.
+
+    const int exp_digits = 3;
+    for (int i = 0; i < exp_digits; i++) {
+      buffer[buffer_pos + exp_digits - 1 - i] = '0' + exponent % 10;
+      exponent /= 10;
+    }
+    ASSERT(exponent == 0);
+    buffer_pos += exp_digits;
+  }
+
+  ASSERT(buffer_pos < kBufferSize);
+  buffer[buffer_pos] = '\0';
+
+  return gay_strtod(buffer, NULL);
+}
 
 double StringToDouble(String* str, int flags, double empty_string_val) {
-  return InternalStringToDouble(str, flags, empty_string_val);
+  StringShape shape(str);
+  if (shape.IsSequentialAscii()) {
+    const char* begin = SeqAsciiString::cast(str)->GetChars();
+    const char* end = begin + str->length();
+    return InternalStringToDouble(begin, end, flags, empty_string_val);
+  } else if (shape.IsSequentialTwoByte()) {
+    const uc16* begin = SeqTwoByteString::cast(str)->GetChars();
+    const uc16* end = begin + str->length();
+    return InternalStringToDouble(begin, end, flags, empty_string_val);
+  } else {
+    StringInputBuffer buffer(str);
+    return InternalStringToDouble(StringInputBufferIterator(&buffer),
+                                  StringInputBufferIterator::EndMarker(),
+                                  flags,
+                                  empty_string_val);
+  }
 }
 
 
 double StringToDouble(const char* str, int flags, double empty_string_val) {
-  return InternalStringToDouble(str, flags, empty_string_val);
+  const char* end = str + StrLength(str);
+
+  return InternalStringToDouble(str, end, flags, empty_string_val);
 }
 
 
index fe4b3db..1bc77c0 100644 (file)
@@ -28,6 +28,7 @@
 #include "v8.h"
 
 #include "data-flow.h"
+#include "flow-graph.h"
 #include "scopes.h"
 
 namespace v8 {
@@ -50,561 +51,6 @@ void BitVector::Print() {
 #endif
 
 
-void FlowGraph::AppendInstruction(AstNode* instruction) {
-  // Add a (non-null) AstNode to the end of the graph fragment.
-  ASSERT(instruction != NULL);
-  if (exit()->IsExitNode()) return;
-  if (!exit()->IsBlockNode()) AppendNode(new BlockNode());
-  BlockNode::cast(exit())->AddInstruction(instruction);
-}
-
-
-void FlowGraph::AppendNode(Node* node) {
-  // Add a node to the end of the graph.  An empty block is added to
-  // maintain edge-split form (that no join nodes or exit nodes as
-  // successors to branch nodes).
-  ASSERT(node != NULL);
-  if (exit()->IsExitNode()) return;
-  if (exit()->IsBranchNode() && (node->IsJoinNode() || node->IsExitNode())) {
-    AppendNode(new BlockNode());
-  }
-  exit()->AddSuccessor(node);
-  node->AddPredecessor(exit());
-  exit_ = node;
-}
-
-
-void FlowGraph::AppendGraph(FlowGraph* graph) {
-  // Add a flow graph fragment to the end of this one.  An empty block is
-  // added to maintain edge-split form (that no join nodes or exit nodes as
-  // successors to branch nodes).
-  ASSERT(graph != NULL);
-  if (exit()->IsExitNode()) return;
-  Node* node = graph->entry();
-  if (exit()->IsBranchNode() && (node->IsJoinNode() || node->IsExitNode())) {
-    AppendNode(new BlockNode());
-  }
-  exit()->AddSuccessor(node);
-  node->AddPredecessor(exit());
-  exit_ = graph->exit();
-}
-
-
-void FlowGraph::Split(BranchNode* branch,
-                      FlowGraph* left,
-                      FlowGraph* right,
-                      JoinNode* join) {
-  // Add the branch node, left flowgraph, join node.
-  AppendNode(branch);
-  AppendGraph(left);
-  AppendNode(join);
-
-  // Splice in the right flowgraph.
-  right->AppendNode(join);
-  branch->AddSuccessor(right->entry());
-  right->entry()->AddPredecessor(branch);
-}
-
-
-void FlowGraph::Loop(JoinNode* join,
-                     FlowGraph* condition,
-                     BranchNode* branch,
-                     FlowGraph* body) {
-  // Add the join, condition and branch.  Add join's predecessors in
-  // left-to-right order.
-  AppendNode(join);
-  body->AppendNode(join);
-  AppendGraph(condition);
-  AppendNode(branch);
-
-  // Splice in the body flowgraph.
-  branch->AddSuccessor(body->entry());
-  body->entry()->AddPredecessor(branch);
-}
-
-
-void ExitNode::Traverse(bool mark,
-                        ZoneList<Node*>* preorder,
-                        ZoneList<Node*>* postorder) {
-  preorder->Add(this);
-  postorder->Add(this);
-}
-
-
-void BlockNode::Traverse(bool mark,
-                         ZoneList<Node*>* preorder,
-                         ZoneList<Node*>* postorder) {
-  ASSERT(successor_ != NULL);
-  preorder->Add(this);
-  if (!successor_->IsMarkedWith(mark)) {
-    successor_->MarkWith(mark);
-    successor_->Traverse(mark, preorder, postorder);
-  }
-  postorder->Add(this);
-}
-
-
-void BranchNode::Traverse(bool mark,
-                          ZoneList<Node*>* preorder,
-                          ZoneList<Node*>* postorder) {
-  ASSERT(successor0_ != NULL && successor1_ != NULL);
-  preorder->Add(this);
-  if (!successor1_->IsMarkedWith(mark)) {
-    successor1_->MarkWith(mark);
-    successor1_->Traverse(mark, preorder, postorder);
-  }
-  if (!successor0_->IsMarkedWith(mark)) {
-    successor0_->MarkWith(mark);
-    successor0_->Traverse(mark, preorder, postorder);
-  }
-  postorder->Add(this);
-}
-
-
-void JoinNode::Traverse(bool mark,
-                        ZoneList<Node*>* preorder,
-                        ZoneList<Node*>* postorder) {
-  ASSERT(successor_ != NULL);
-  preorder->Add(this);
-  if (!successor_->IsMarkedWith(mark)) {
-    successor_->MarkWith(mark);
-    successor_->Traverse(mark, preorder, postorder);
-  }
-  postorder->Add(this);
-}
-
-
-void FlowGraphBuilder::Build(FunctionLiteral* lit) {
-  global_exit_ = new ExitNode();
-  VisitStatements(lit->body());
-
-  if (HasStackOverflow()) return;
-
-  // The graph can end with a branch node (if the function ended with a
-  // loop).  Maintain edge-split form (no join nodes or exit nodes as
-  // successors to branch nodes).
-  if (graph_.exit()->IsBranchNode()) graph_.AppendNode(new BlockNode());
-  graph_.AppendNode(global_exit_);
-
-  // Build preorder and postorder traversal orders.  All the nodes in
-  // the graph have the same mark flag.  For the traversal, use that
-  // flag's negation.  Traversal will flip all the flags.
-  bool mark = graph_.entry()->IsMarkedWith(false);
-  graph_.entry()->MarkWith(mark);
-  graph_.entry()->Traverse(mark, &preorder_, &postorder_);
-}
-
-
-// This function peels off one iteration of a for-loop. The return value
-// is either a block statement containing the peeled loop or NULL in case
-// there is a stack overflow.
-static Statement* PeelForLoop(ForStatement* stmt) {
-  // Mark this for-statement as processed.
-  stmt->set_peel_this_loop(false);
-
-  // Create new block containing the init statement of the for-loop and
-  // an if-statement containing the peeled iteration and the original
-  // loop without the init-statement.
-  Block* block = new Block(NULL, 2, false);
-  if (stmt->init() != NULL) {
-    Statement* init = stmt->init();
-    // The init statement gets the statement position of the for-loop
-    // to make debugging of peeled loops possible.
-    init->set_statement_pos(stmt->statement_pos());
-    block->AddStatement(init);
-  }
-
-  // Copy the condition.
-  CopyAstVisitor copy_visitor;
-  Expression* cond_copy = stmt->cond() != NULL
-      ? copy_visitor.DeepCopyExpr(stmt->cond())
-      : new Literal(Factory::true_value());
-  if (copy_visitor.HasStackOverflow()) return NULL;
-
-  // Construct a block with the peeled body and the rest of the for-loop.
-  Statement* body_copy = copy_visitor.DeepCopyStmt(stmt->body());
-  if (copy_visitor.HasStackOverflow()) return NULL;
-
-  Statement* next_copy = stmt->next() != NULL
-      ? copy_visitor.DeepCopyStmt(stmt->next())
-      : new EmptyStatement();
-  if (copy_visitor.HasStackOverflow()) return NULL;
-
-  Block* peeled_body = new Block(NULL, 3, false);
-  peeled_body->AddStatement(body_copy);
-  peeled_body->AddStatement(next_copy);
-  peeled_body->AddStatement(stmt);
-
-  // Remove the duplicated init statement from the for-statement.
-  stmt->set_init(NULL);
-
-  // Create new test at the top and add it to the newly created block.
-  IfStatement* test = new IfStatement(cond_copy,
-                                      peeled_body,
-                                      new EmptyStatement());
-  block->AddStatement(test);
-  return block;
-}
-
-
-void FlowGraphBuilder::VisitStatements(ZoneList<Statement*>* stmts) {
-  for (int i = 0, len = stmts->length(); i < len; i++) {
-    stmts->at(i) = ProcessStatement(stmts->at(i));
-  }
-}
-
-
-Statement* FlowGraphBuilder::ProcessStatement(Statement* stmt) {
-  if (FLAG_loop_peeling &&
-      stmt->AsForStatement() != NULL &&
-      stmt->AsForStatement()->peel_this_loop()) {
-    Statement* tmp_stmt = PeelForLoop(stmt->AsForStatement());
-    if (tmp_stmt == NULL) {
-      SetStackOverflow();
-    } else {
-      stmt = tmp_stmt;
-    }
-  }
-  Visit(stmt);
-  return stmt;
-}
-
-
-void FlowGraphBuilder::VisitDeclaration(Declaration* decl) {
-  UNREACHABLE();
-}
-
-
-void FlowGraphBuilder::VisitBlock(Block* stmt) {
-  VisitStatements(stmt->statements());
-}
-
-
-void FlowGraphBuilder::VisitExpressionStatement(ExpressionStatement* stmt) {
-  Visit(stmt->expression());
-}
-
-
-void FlowGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) {
-  // Nothing to do.
-}
-
-
-void FlowGraphBuilder::VisitIfStatement(IfStatement* stmt) {
-  Visit(stmt->condition());
-
-  BranchNode* branch = new BranchNode();
-  FlowGraph original = graph_;
-  graph_ = FlowGraph::Empty();
-  stmt->set_then_statement(ProcessStatement(stmt->then_statement()));
-
-  FlowGraph left = graph_;
-  graph_ = FlowGraph::Empty();
-  stmt->set_else_statement(ProcessStatement(stmt->else_statement()));
-
-  if (HasStackOverflow()) return;
-  JoinNode* join = new JoinNode();
-  original.Split(branch, &left, &graph_, join);
-  graph_ = original;
-}
-
-
-void FlowGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) {
-  SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
-  SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
-  SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) {
-  SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitWithExitStatement(WithExitStatement* stmt) {
-  SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
-  SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
-  SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
-  SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitForStatement(ForStatement* stmt) {
-  if (stmt->init() != NULL) stmt->set_init(ProcessStatement(stmt->init()));
-
-  JoinNode* join = new JoinNode();
-  FlowGraph original = graph_;
-  graph_ = FlowGraph::Empty();
-  if (stmt->cond() != NULL) Visit(stmt->cond());
-
-  BranchNode* branch = new BranchNode();
-  FlowGraph condition = graph_;
-  graph_ = FlowGraph::Empty();
-  stmt->set_body(ProcessStatement(stmt->body()));
-
-  if (stmt->next() != NULL) stmt->set_next(ProcessStatement(stmt->next()));
-
-  if (HasStackOverflow()) return;
-  original.Loop(join, &condition, branch, &graph_);
-  graph_ = original;
-}
-
-
-void FlowGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
-  SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
-  SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
-  SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
-  SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
-  SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitSharedFunctionInfoLiteral(
-    SharedFunctionInfoLiteral* expr) {
-  SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitConditional(Conditional* expr) {
-  SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitSlot(Slot* expr) {
-  UNREACHABLE();
-}
-
-
-void FlowGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
-  graph_.AppendInstruction(expr);
-}
-
-
-void FlowGraphBuilder::VisitLiteral(Literal* expr) {
-  graph_.AppendInstruction(expr);
-}
-
-
-void FlowGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
-  SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
-  SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
-  SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) {
-  SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitAssignment(Assignment* expr) {
-  Variable* var = expr->target()->AsVariableProxy()->AsVariable();
-  Property* prop = expr->target()->AsProperty();
-  // Left-hand side can be a variable or property (or reference error) but
-  // not both.
-  ASSERT(var == NULL || prop == NULL);
-  if (var != NULL) {
-    if (expr->is_compound()) Visit(expr->target());
-    Visit(expr->value());
-    if (var->IsStackAllocated()) {
-      // The first definition in the body is numbered n, where n is the
-      // number of parameters and stack-allocated locals.
-      expr->set_num(body_definitions_.length() + variable_count_);
-      body_definitions_.Add(expr);
-    }
-
-  } else if (prop != NULL) {
-    Visit(prop->obj());
-    if (!prop->key()->IsPropertyName()) Visit(prop->key());
-    Visit(expr->value());
-  }
-
-  if (HasStackOverflow()) return;
-  graph_.AppendInstruction(expr);
-}
-
-
-void FlowGraphBuilder::VisitThrow(Throw* expr) {
-  SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitProperty(Property* expr) {
-  Visit(expr->obj());
-  if (!expr->key()->IsPropertyName()) Visit(expr->key());
-
-  if (HasStackOverflow()) return;
-  graph_.AppendInstruction(expr);
-}
-
-
-void FlowGraphBuilder::VisitCall(Call* expr) {
-  Visit(expr->expression());
-  ZoneList<Expression*>* arguments = expr->arguments();
-  for (int i = 0, len = arguments->length(); i < len; i++) {
-    Visit(arguments->at(i));
-  }
-
-  if (HasStackOverflow()) return;
-  graph_.AppendInstruction(expr);
-}
-
-
-void FlowGraphBuilder::VisitCallNew(CallNew* expr) {
-  SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
-  SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
-  switch (expr->op()) {
-    case Token::NOT:
-    case Token::BIT_NOT:
-    case Token::DELETE:
-    case Token::TYPEOF:
-    case Token::VOID:
-      SetStackOverflow();
-      break;
-
-    case Token::ADD:
-    case Token::SUB:
-      Visit(expr->expression());
-      if (HasStackOverflow()) return;
-      graph_.AppendInstruction(expr);
-      break;
-
-    default:
-      UNREACHABLE();
-  }
-}
-
-
-void FlowGraphBuilder::VisitCountOperation(CountOperation* expr) {
-  Visit(expr->expression());
-  Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
-  if (var != NULL && var->IsStackAllocated()) {
-    // The first definition in the body is numbered n, where n is the number
-    // of parameters and stack-allocated locals.
-    expr->set_num(body_definitions_.length() + variable_count_);
-    body_definitions_.Add(expr);
-  }
-
-  if (HasStackOverflow()) return;
-  graph_.AppendInstruction(expr);
-}
-
-
-void FlowGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
-  switch (expr->op()) {
-    case Token::COMMA:
-    case Token::OR:
-    case Token::AND:
-      SetStackOverflow();
-      break;
-
-    case Token::BIT_OR:
-    case Token::BIT_XOR:
-    case Token::BIT_AND:
-    case Token::SHL:
-    case Token::SHR:
-    case Token::ADD:
-    case Token::SUB:
-    case Token::MUL:
-    case Token::DIV:
-    case Token::MOD:
-    case Token::SAR:
-      Visit(expr->left());
-      Visit(expr->right());
-      if (HasStackOverflow()) return;
-      graph_.AppendInstruction(expr);
-      break;
-
-    default:
-      UNREACHABLE();
-  }
-}
-
-
-void FlowGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
-  switch (expr->op()) {
-    case Token::EQ:
-    case Token::NE:
-    case Token::EQ_STRICT:
-    case Token::NE_STRICT:
-    case Token::INSTANCEOF:
-    case Token::IN:
-      SetStackOverflow();
-      break;
-
-    case Token::LT:
-    case Token::GT:
-    case Token::LTE:
-    case Token::GTE:
-      Visit(expr->left());
-      Visit(expr->right());
-      if (HasStackOverflow()) return;
-      graph_.AppendInstruction(expr);
-      break;
-
-    default:
-      UNREACHABLE();
-  }
-}
-
-
-void FlowGraphBuilder::VisitThisFunction(ThisFunction* expr) {
-  SetStackOverflow();
-}
-
-
 void AstLabeler::Label(CompilationInfo* info) {
   info_ = info;
   VisitStatements(info_->function()->body());
@@ -1300,803 +746,802 @@ void AssignedVariablesAnalyzer::VisitDeclaration(Declaration* decl) {
 }
 
 
-#ifdef DEBUG
+int ReachingDefinitions::IndexFor(Variable* var, int variable_count) {
+  // Parameters are numbered left-to-right from the beginning of the bit
+  // set.  Stack-allocated locals are allocated right-to-left from the end.
+  ASSERT(var != NULL && var->IsStackAllocated());
+  Slot* slot = var->slot();
+  if (slot->type() == Slot::PARAMETER) {
+    return slot->index();
+  } else {
+    return (variable_count - 1) - slot->index();
+  }
+}
 
-// Print a textual representation of an instruction in a flow graph.  Using
-// the AstVisitor is overkill because there is no recursion here.  It is
-// only used for printing in debug mode.
-class TextInstructionPrinter: public AstVisitor {
- public:
-  TextInstructionPrinter() : number_(0) {}
 
-  int NextNumber() { return number_; }
-  void AssignNumber(AstNode* node) { node->set_num(number_++); }
+void Node::InitializeReachingDefinitions(int definition_count,
+                                         List<BitVector*>* variables,
+                                         WorkList<Node>* worklist,
+                                         bool mark) {
+  ASSERT(!IsMarkedWith(mark));
+  rd_.Initialize(definition_count);
+  MarkWith(mark);
+  worklist->Insert(this);
+}
 
- private:
-  // AST node visit functions.
-#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
-  AST_NODE_LIST(DECLARE_VISIT)
-#undef DECLARE_VISIT
 
-  int number_;
-
-  DISALLOW_COPY_AND_ASSIGN(TextInstructionPrinter);
-};
-
-
-void TextInstructionPrinter::VisitDeclaration(Declaration* decl) {
-  UNREACHABLE();
-}
-
-
-void TextInstructionPrinter::VisitBlock(Block* stmt) {
-  PrintF("Block");
-}
+void BlockNode::InitializeReachingDefinitions(int definition_count,
+                                              List<BitVector*>* variables,
+                                              WorkList<Node>* worklist,
+                                              bool mark) {
+  ASSERT(!IsMarkedWith(mark));
+  int instruction_count = instructions_.length();
+  int variable_count = variables->length();
 
+  rd_.Initialize(definition_count);
+  // The RD_in set for the entry node has a definition for each parameter
+  // and local.
+  if (predecessor_ == NULL) {
+    for (int i = 0; i < variable_count; i++) rd_.rd_in()->Add(i);
+  }
 
-void TextInstructionPrinter::VisitExpressionStatement(
-    ExpressionStatement* stmt) {
-  PrintF("ExpressionStatement");
-}
+  for (int i = 0; i < instruction_count; i++) {
+    Expression* expr = instructions_[i]->AsExpression();
+    if (expr == NULL) continue;
+    Variable* var = expr->AssignedVariable();
+    if (var == NULL || !var->IsStackAllocated()) continue;
 
+    // All definitions of this variable are killed.
+    BitVector* def_set =
+        variables->at(ReachingDefinitions::IndexFor(var, variable_count));
+    rd_.kill()->Union(*def_set);
 
-void TextInstructionPrinter::VisitEmptyStatement(EmptyStatement* stmt) {
-  PrintF("EmptyStatement");
-}
+    // All previously generated definitions are not generated.
+    rd_.gen()->Subtract(*def_set);
 
+    // This one is generated.
+    rd_.gen()->Add(expr->num());
+  }
 
-void TextInstructionPrinter::VisitIfStatement(IfStatement* stmt) {
-  PrintF("IfStatement");
+  // Add all blocks except the entry node to the worklist.
+  if (predecessor_ != NULL) {
+    MarkWith(mark);
+    worklist->Insert(this);
+  }
 }
 
 
-void TextInstructionPrinter::VisitContinueStatement(ContinueStatement* stmt) {
+void ExitNode::ComputeRDOut(BitVector* result) {
+  // Should not be the predecessor of any node.
   UNREACHABLE();
 }
 
 
-void TextInstructionPrinter::VisitBreakStatement(BreakStatement* stmt) {
-  UNREACHABLE();
+void BlockNode::ComputeRDOut(BitVector* result) {
+  // All definitions reaching this block ...
+  *result = *rd_.rd_in();
+  // ... except those killed by the block ...
+  result->Subtract(*rd_.kill());
+  // ... but including those generated by the block.
+  result->Union(*rd_.gen());
 }
 
 
-void TextInstructionPrinter::VisitReturnStatement(ReturnStatement* stmt) {
-  PrintF("return @%d", stmt->expression()->num());
+void BranchNode::ComputeRDOut(BitVector* result) {
+  // Branch nodes don't kill or generate definitions.
+  *result = *rd_.rd_in();
 }
 
 
-void TextInstructionPrinter::VisitWithEnterStatement(WithEnterStatement* stmt) {
-  PrintF("WithEnterStatement");
+void JoinNode::ComputeRDOut(BitVector* result) {
+  // Join nodes don't kill or generate definitions.
+  *result = *rd_.rd_in();
 }
 
 
-void TextInstructionPrinter::VisitWithExitStatement(WithExitStatement* stmt) {
-  PrintF("WithExitStatement");
-}
-
+void ExitNode::UpdateRDIn(WorkList<Node>* worklist, bool mark) {
+  // The exit node has no successors so we can just update in place.  New
+  // RD_in is the union over all predecessors.
+  int definition_count = rd_.rd_in()->length();
+  rd_.rd_in()->Clear();
 
-void TextInstructionPrinter::VisitSwitchStatement(SwitchStatement* stmt) {
-  UNREACHABLE();
+  BitVector temp(definition_count);
+  for (int i = 0, len = predecessors_.length(); i < len; i++) {
+    // Because ComputeRDOut always overwrites temp and its value is
+    // always read out before calling ComputeRDOut again, we do not
+    // have to clear it on each iteration of the loop.
+    predecessors_[i]->ComputeRDOut(&temp);
+    rd_.rd_in()->Union(temp);
+  }
 }
 
 
-void TextInstructionPrinter::VisitDoWhileStatement(DoWhileStatement* stmt) {
-  PrintF("DoWhileStatement");
-}
-
+void BlockNode::UpdateRDIn(WorkList<Node>* worklist, bool mark) {
+  // The entry block has no predecessor.  Its RD_in does not change.
+  if (predecessor_ == NULL) return;
 
-void TextInstructionPrinter::VisitWhileStatement(WhileStatement* stmt) {
-  PrintF("WhileStatement");
-}
+  BitVector new_rd_in(rd_.rd_in()->length());
+  predecessor_->ComputeRDOut(&new_rd_in);
 
+  if (rd_.rd_in()->Equals(new_rd_in)) return;
 
-void TextInstructionPrinter::VisitForStatement(ForStatement* stmt) {
-  PrintF("ForStatement");
+  // Update RD_in.
+  *rd_.rd_in() = new_rd_in;
+  // Add the successor to the worklist if not already present.
+  if (!successor_->IsMarkedWith(mark)) {
+    successor_->MarkWith(mark);
+    worklist->Insert(successor_);
+  }
 }
 
 
-void TextInstructionPrinter::VisitForInStatement(ForInStatement* stmt) {
-  PrintF("ForInStatement");
-}
+void BranchNode::UpdateRDIn(WorkList<Node>* worklist, bool mark) {
+  BitVector new_rd_in(rd_.rd_in()->length());
+  predecessor_->ComputeRDOut(&new_rd_in);
 
+  if (rd_.rd_in()->Equals(new_rd_in)) return;
 
-void TextInstructionPrinter::VisitTryCatchStatement(TryCatchStatement* stmt) {
-  UNREACHABLE();
+  // Update RD_in.
+  *rd_.rd_in() = new_rd_in;
+  // Add the successors to the worklist if not already present.
+  if (!successor0_->IsMarkedWith(mark)) {
+    successor0_->MarkWith(mark);
+    worklist->Insert(successor0_);
+  }
+  if (!successor1_->IsMarkedWith(mark)) {
+    successor1_->MarkWith(mark);
+    worklist->Insert(successor1_);
+  }
 }
 
 
-void TextInstructionPrinter::VisitTryFinallyStatement(
-    TryFinallyStatement* stmt) {
-  UNREACHABLE();
-}
-
+void JoinNode::UpdateRDIn(WorkList<Node>* worklist, bool mark) {
+  int definition_count = rd_.rd_in()->length();
+  BitVector new_rd_in(definition_count);
 
-void TextInstructionPrinter::VisitDebuggerStatement(DebuggerStatement* stmt) {
-  PrintF("DebuggerStatement");
-}
+  // New RD_in is the union over all predecessors.
+  BitVector temp(definition_count);
+  for (int i = 0, len = predecessors_.length(); i < len; i++) {
+    predecessors_[i]->ComputeRDOut(&temp);
+    new_rd_in.Union(temp);
+  }
 
+  if (rd_.rd_in()->Equals(new_rd_in)) return;
 
-void TextInstructionPrinter::VisitFunctionLiteral(FunctionLiteral* expr) {
-  PrintF("FunctionLiteral");
+  // Update RD_in.
+  *rd_.rd_in() = new_rd_in;
+  // Add the successor to the worklist if not already present.
+  if (!successor_->IsMarkedWith(mark)) {
+    successor_->MarkWith(mark);
+    worklist->Insert(successor_);
+  }
 }
 
 
-void TextInstructionPrinter::VisitSharedFunctionInfoLiteral(
-    SharedFunctionInfoLiteral* expr) {
-  PrintF("SharedFunctionInfoLiteral");
+void Node::PropagateReachingDefinitions(List<BitVector*>* variables) {
+  // Nothing to do.
 }
 
 
-void TextInstructionPrinter::VisitConditional(Conditional* expr) {
-  PrintF("Conditional");
-}
+void BlockNode::PropagateReachingDefinitions(List<BitVector*>* variables) {
+  // Propagate RD_in from the start of the block to all the variable
+  // references.
+  int variable_count = variables->length();
+  BitVector rd = *rd_.rd_in();
+  for (int i = 0, len = instructions_.length(); i < len; i++) {
+    Expression* expr = instructions_[i]->AsExpression();
+    if (expr == NULL) continue;
 
+    // Look for a variable reference to record its reaching definitions.
+    VariableProxy* proxy = expr->AsVariableProxy();
+    if (proxy == NULL) {
+      // Not a VariableProxy?  Maybe it's a count operation.
+      CountOperation* count_operation = expr->AsCountOperation();
+      if (count_operation != NULL) {
+        proxy = count_operation->expression()->AsVariableProxy();
+      }
+    }
+    if (proxy == NULL) {
+      // OK, Maybe it's a compound assignment.
+      Assignment* assignment = expr->AsAssignment();
+      if (assignment != NULL && assignment->is_compound()) {
+        proxy = assignment->target()->AsVariableProxy();
+      }
+    }
 
-void TextInstructionPrinter::VisitSlot(Slot* expr) {
-  UNREACHABLE();
-}
+    if (proxy != NULL &&
+        proxy->var()->IsStackAllocated() &&
+        !proxy->var()->is_this()) {
+      // All definitions for this variable.
+      BitVector* definitions =
+          variables->at(ReachingDefinitions::IndexFor(proxy->var(),
+                                                      variable_count));
+      BitVector* reaching_definitions = new BitVector(*definitions);
+      // Intersected with all definitions (of any variable) reaching this
+      // instruction.
+      reaching_definitions->Intersect(rd);
+      proxy->set_reaching_definitions(reaching_definitions);
+    }
 
+    // It may instead (or also) be a definition.  If so update the running
+    // value of reaching definitions for the block.
+    Variable* var = expr->AssignedVariable();
+    if (var == NULL || !var->IsStackAllocated()) continue;
 
-void TextInstructionPrinter::VisitVariableProxy(VariableProxy* expr) {
-  Variable* var = expr->AsVariable();
-  if (var != NULL) {
-    PrintF("%s", *var->name()->ToCString());
-    if (var->IsStackAllocated() && expr->reaching_definitions() != NULL) {
-      expr->reaching_definitions()->Print();
-    }
-  } else {
-    ASSERT(expr->AsProperty() != NULL);
-    VisitProperty(expr->AsProperty());
+    // All definitions of this variable are killed.
+    BitVector* def_set =
+        variables->at(ReachingDefinitions::IndexFor(var, variable_count));
+    rd.Subtract(*def_set);
+    // This definition is generated.
+    rd.Add(expr->num());
   }
 }
 
 
-void TextInstructionPrinter::VisitLiteral(Literal* expr) {
-  expr->handle()->ShortPrint();
-}
+void ReachingDefinitions::Compute() {
+  // The definitions in the body plus an implicit definition for each
+  // variable at function entry.
+  int definition_count = body_definitions_->length() + variable_count_;
+  int node_count = postorder_->length();
 
+  // Step 1: For each stack-allocated variable, identify the set of all its
+  // definitions.
+  List<BitVector*> variables;
+  for (int i = 0; i < variable_count_; i++) {
+    // Add the initial definition for each variable.
+    BitVector* initial = new BitVector(definition_count);
+    initial->Add(i);
+    variables.Add(initial);
+  }
+  for (int i = 0, len = body_definitions_->length(); i < len; i++) {
+    // Account for each definition in the body as a definition of the
+    // defined variable.
+    Variable* var = body_definitions_->at(i)->AssignedVariable();
+    variables[IndexFor(var, variable_count_)]->Add(i + variable_count_);
+  }
 
-void TextInstructionPrinter::VisitRegExpLiteral(RegExpLiteral* expr) {
-  PrintF("RegExpLiteral");
-}
-
-
-void TextInstructionPrinter::VisitObjectLiteral(ObjectLiteral* expr) {
-  PrintF("ObjectLiteral");
-}
+  // Step 2: Compute KILL and GEN for each block node, initialize RD_in for
+  // all nodes, and mark and add all nodes to the worklist in reverse
+  // postorder.  All nodes should currently have the same mark.
+  bool mark = postorder_->at(0)->IsMarkedWith(false);  // Negation of current.
+  WorkList<Node> worklist(node_count);
+  for (int i = node_count - 1; i >= 0; i--) {
+    postorder_->at(i)->InitializeReachingDefinitions(definition_count,
+                                                     &variables,
+                                                     &worklist,
+                                                     mark);
+  }
 
+  // Step 3: Until the worklist is empty, remove an item compute and update
+  // its rd_in based on its predecessor's rd_out.  If rd_in has changed, add
+  // all necessary successors to the worklist.
+  while (!worklist.is_empty()) {
+    Node* node = worklist.Remove();
+    node->MarkWith(!mark);
+    node->UpdateRDIn(&worklist, mark);
+  }
 
-void TextInstructionPrinter::VisitArrayLiteral(ArrayLiteral* expr) {
-  PrintF("ArrayLiteral");
+  // Step 4: Based on RD_in for block nodes, propagate reaching definitions
+  // to all variable uses in the block.
+  for (int i = 0; i < node_count; i++) {
+    postorder_->at(i)->PropagateReachingDefinitions(&variables);
+  }
 }
 
 
-void TextInstructionPrinter::VisitCatchExtensionObject(
-    CatchExtensionObject* expr) {
-  PrintF("CatchExtensionObject");
+bool TypeAnalyzer::IsPrimitiveDef(int def_num) {
+  if (def_num < param_count_) return false;
+  if (def_num < variable_count_) return true;
+  return body_definitions_->at(def_num - variable_count_)->IsPrimitive();
 }
 
 
-void TextInstructionPrinter::VisitAssignment(Assignment* expr) {
-  Variable* var = expr->target()->AsVariableProxy()->AsVariable();
-  Property* prop = expr->target()->AsProperty();
+void TypeAnalyzer::Compute() {
+  bool changed;
+  int count = 0;
 
-  if (var == NULL && prop == NULL) {
-    // Throw reference error.
-    Visit(expr->target());
-    return;
-  }
+  do {
+    changed = false;
 
-  // Print the left-hand side.
-  if (var != NULL) {
-    PrintF("%s", *var->name()->ToCString());
-  } else if (prop != NULL) {
-    PrintF("@%d", prop->obj()->num());
-    if (prop->key()->IsPropertyName()) {
-      PrintF(".");
-      ASSERT(prop->key()->AsLiteral() != NULL);
-      prop->key()->AsLiteral()->handle()->Print();
-    } else {
-      PrintF("[@%d]", prop->key()->num());
+    if (FLAG_print_graph_text) {
+      PrintF("TypeAnalyzer::Compute - iteration %d\n", count++);
     }
-  }
 
-  // Print the operation.
-  if (expr->is_compound()) {
-    PrintF(" = ");
-    // Print the left-hand side again when compound.
-    if (var != NULL) {
-      PrintF("@%d", expr->target()->num());
-    } else {
-      PrintF("@%d", prop->obj()->num());
-      if (prop->key()->IsPropertyName()) {
-        PrintF(".");
-        ASSERT(prop->key()->AsLiteral() != NULL);
-        prop->key()->AsLiteral()->handle()->Print();
-      } else {
-        PrintF("[@%d]", prop->key()->num());
+    for (int i = postorder_->length() - 1; i >= 0; --i) {
+      Node* node = postorder_->at(i);
+      if (node->IsBlockNode()) {
+        BlockNode* block = BlockNode::cast(node);
+        for (int j = 0; j < block->instructions()->length(); j++) {
+          Expression* expr = block->instructions()->at(j)->AsExpression();
+          if (expr != NULL) {
+            // For variable uses: Compute new type from reaching definitions.
+            VariableProxy* proxy = expr->AsVariableProxy();
+            if (proxy != NULL && proxy->reaching_definitions() != NULL) {
+              BitVector* rd = proxy->reaching_definitions();
+              bool prim_type = true;
+              // TODO(fsc): A sparse set representation of reaching
+              // definitions would speed up iterating here.
+              for (int k = 0; k < rd->length(); k++) {
+                if (rd->Contains(k) && !IsPrimitiveDef(k)) {
+                  prim_type = false;
+                  break;
+                }
+              }
+              // Reset changed flag if new type information was computed.
+              if (prim_type != proxy->IsPrimitive()) {
+                changed = true;
+                proxy->SetIsPrimitive(prim_type);
+              }
+            }
+          }
+        }
       }
     }
-    // Print the corresponding binary operator.
-    PrintF(" %s ", Token::String(expr->binary_op()));
-  } else {
-    PrintF(" %s ", Token::String(expr->op()));
-  }
-
-  // Print the right-hand side.
-  PrintF("@%d", expr->value()->num());
-
-  if (expr->num() != AstNode::kNoNumber) {
-    PrintF(" ;; D%d", expr->num());
-  }
+  } while (changed);
 }
 
 
-void TextInstructionPrinter::VisitThrow(Throw* expr) {
-  PrintF("throw @%d", expr->exception()->num());
+void Node::MarkCriticalInstructions(
+    List<AstNode*>* stack,
+    ZoneList<Expression*>* body_definitions,
+    int variable_count) {
 }
 
 
-void TextInstructionPrinter::VisitProperty(Property* expr) {
-  if (expr->key()->IsPropertyName()) {
-    PrintF("@%d.", expr->obj()->num());
-    ASSERT(expr->key()->AsLiteral() != NULL);
-    expr->key()->AsLiteral()->handle()->Print();
-  } else {
-    PrintF("@%d[@%d]", expr->obj()->num(), expr->key()->num());
+void BlockNode::MarkCriticalInstructions(
+    List<AstNode*>* stack,
+    ZoneList<Expression*>* body_definitions,
+    int variable_count) {
+  for (int i = instructions_.length() - 1; i >= 0; i--) {
+    // Only expressions can appear in the flow graph for now.
+    Expression* expr = instructions_[i]->AsExpression();
+    if (expr != NULL && !expr->is_live() &&
+        (expr->is_loop_condition() || expr->IsCritical())) {
+      expr->mark_as_live();
+      expr->ProcessNonLiveChildren(stack, body_definitions, variable_count);
+    }
   }
 }
 
 
-void TextInstructionPrinter::VisitCall(Call* expr) {
-  PrintF("@%d(", expr->expression()->num());
-  ZoneList<Expression*>* arguments = expr->arguments();
-  for (int i = 0, len = arguments->length(); i < len; i++) {
-    if (i != 0) PrintF(", ");
-    PrintF("@%d", arguments->at(i)->num());
-  }
-  PrintF(")");
-}
+void MarkLiveCode(ZoneList<Node*>* nodes,
+                  ZoneList<Expression*>* body_definitions,
+                  int variable_count) {
+  List<AstNode*> stack(20);
 
+  // Mark the critical AST nodes as live; mark their dependencies and
+  // add them to the marking stack.
+  for (int i = nodes->length() - 1; i >= 0; i--) {
+    nodes->at(i)->MarkCriticalInstructions(&stack, body_definitions,
+                                           variable_count);
+  }
 
-void TextInstructionPrinter::VisitCallNew(CallNew* expr) {
-  PrintF("new @%d(", expr->expression()->num());
-  ZoneList<Expression*>* arguments = expr->arguments();
-  for (int i = 0, len = arguments->length(); i < len; i++) {
-    if (i != 0) PrintF(", ");
-    PrintF("@%d", arguments->at(i)->num());
+  // Continue marking dependencies until no more.
+  while (!stack.is_empty()) {
+  // Only expressions can appear in the flow graph for now.
+    Expression* expr = stack.RemoveLast()->AsExpression();
+    if (expr != NULL) {
+      expr->ProcessNonLiveChildren(&stack, body_definitions, variable_count);
+    }
   }
-  PrintF(")");
 }
 
 
-void TextInstructionPrinter::VisitCallRuntime(CallRuntime* expr) {
-  PrintF("%s(", *expr->name()->ToCString());
-  ZoneList<Expression*>* arguments = expr->arguments();
-  for (int i = 0, len = arguments->length(); i < len; i++) {
-    if (i != 0) PrintF(", ");
-    PrintF("@%d", arguments->at(i)->num());
-  }
-  PrintF(")");
-}
+#ifdef DEBUG
+
+// Print a textual representation of an instruction in a flow graph.  Using
+// the AstVisitor is overkill because there is no recursion here.  It is
+// only used for printing in debug mode.
+class TextInstructionPrinter: public AstVisitor {
+ public:
+  TextInstructionPrinter() : number_(0) {}
 
+  int NextNumber() { return number_; }
+  void AssignNumber(AstNode* node) { node->set_num(number_++); }
 
-void TextInstructionPrinter::VisitUnaryOperation(UnaryOperation* expr) {
-  PrintF("%s(@%d)", Token::String(expr->op()), expr->expression()->num());
-}
+ private:
+  // AST node visit functions.
+#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
+  AST_NODE_LIST(DECLARE_VISIT)
+#undef DECLARE_VISIT
 
+  int number_;
 
-void TextInstructionPrinter::VisitCountOperation(CountOperation* expr) {
-  if (expr->is_prefix()) {
-    PrintF("%s@%d", Token::String(expr->op()), expr->expression()->num());
-  } else {
-    PrintF("@%d%s", expr->expression()->num(), Token::String(expr->op()));
-  }
+  DISALLOW_COPY_AND_ASSIGN(TextInstructionPrinter);
+};
 
-  if (expr->num() != AstNode::kNoNumber) {
-    PrintF(" ;; D%d", expr->num());
-  }
+
+void TextInstructionPrinter::VisitDeclaration(Declaration* decl) {
+  UNREACHABLE();
 }
 
 
-void TextInstructionPrinter::VisitBinaryOperation(BinaryOperation* expr) {
-  ASSERT(expr->op() != Token::COMMA);
-  ASSERT(expr->op() != Token::OR);
-  ASSERT(expr->op() != Token::AND);
-  PrintF("@%d %s @%d",
-         expr->left()->num(),
-         Token::String(expr->op()),
-         expr->right()->num());
+void TextInstructionPrinter::VisitBlock(Block* stmt) {
+  PrintF("Block");
 }
 
 
-void TextInstructionPrinter::VisitCompareOperation(CompareOperation* expr) {
-  PrintF("@%d %s @%d",
-         expr->left()->num(),
-         Token::String(expr->op()),
-         expr->right()->num());
+void TextInstructionPrinter::VisitExpressionStatement(
+    ExpressionStatement* stmt) {
+  PrintF("ExpressionStatement");
 }
 
 
-void TextInstructionPrinter::VisitThisFunction(ThisFunction* expr) {
-  PrintF("ThisFunction");
+void TextInstructionPrinter::VisitEmptyStatement(EmptyStatement* stmt) {
+  PrintF("EmptyStatement");
 }
 
 
-static int node_count = 0;
-static int instruction_count = 0;
+void TextInstructionPrinter::VisitIfStatement(IfStatement* stmt) {
+  PrintF("IfStatement");
+}
 
 
-void Node::AssignNodeNumber() {
-  set_number(node_count++);
+void TextInstructionPrinter::VisitContinueStatement(ContinueStatement* stmt) {
+  UNREACHABLE();
 }
 
 
-void Node::PrintReachingDefinitions() {
-  if (rd_.rd_in() != NULL) {
-    ASSERT(rd_.kill() != NULL && rd_.gen() != NULL);
-
-    PrintF("RD_in = ");
-    rd_.rd_in()->Print();
-    PrintF("\n");
-
-    PrintF("RD_kill = ");
-    rd_.kill()->Print();
-    PrintF("\n");
-
-    PrintF("RD_gen = ");
-    rd_.gen()->Print();
-    PrintF("\n");
-  }
+void TextInstructionPrinter::VisitBreakStatement(BreakStatement* stmt) {
+  UNREACHABLE();
 }
 
 
-void ExitNode::PrintText() {
-  PrintReachingDefinitions();
-  PrintF("L%d: Exit\n\n", number());
+void TextInstructionPrinter::VisitReturnStatement(ReturnStatement* stmt) {
+  PrintF("return @%d", stmt->expression()->num());
 }
 
 
-void BlockNode::PrintText() {
-  PrintReachingDefinitions();
-  // Print the instructions in the block.
-  PrintF("L%d: Block\n", number());
-  TextInstructionPrinter printer;
-  for (int i = 0, len = instructions_.length(); i < len; i++) {
-    AstNode* instr = instructions_[i];
-    // Print a star next to dead instructions.
-    if (instr->AsExpression() != NULL && instr->AsExpression()->is_live()) {
-      PrintF("  ");
-    } else {
-      PrintF("* ");
-    }
-    PrintF("%d ", printer.NextNumber());
-    printer.Visit(instr);
-    printer.AssignNumber(instr);
-    PrintF("\n");
-  }
-  PrintF("goto L%d\n\n", successor_->number());
+void TextInstructionPrinter::VisitWithEnterStatement(WithEnterStatement* stmt) {
+  PrintF("WithEnterStatement");
 }
 
 
-void BranchNode::PrintText() {
-  PrintReachingDefinitions();
-  PrintF("L%d: Branch\n", number());
-  PrintF("goto (L%d, L%d)\n\n", successor0_->number(), successor1_->number());
+void TextInstructionPrinter::VisitWithExitStatement(WithExitStatement* stmt) {
+  PrintF("WithExitStatement");
 }
 
 
-void JoinNode::PrintText() {
-  PrintReachingDefinitions();
-  PrintF("L%d: Join(", number());
-  for (int i = 0, len = predecessors_.length(); i < len; i++) {
-    if (i != 0) PrintF(", ");
-    PrintF("L%d", predecessors_[i]->number());
-  }
-  PrintF(")\ngoto L%d\n\n", successor_->number());
+void TextInstructionPrinter::VisitSwitchStatement(SwitchStatement* stmt) {
+  UNREACHABLE();
 }
 
 
-void FlowGraph::PrintText(FunctionLiteral* fun, ZoneList<Node*>* postorder) {
-  PrintF("\n========\n");
-  PrintF("name = %s\n", *fun->name()->ToCString());
-
-  // Number nodes and instructions in reverse postorder.
-  node_count = 0;
-  instruction_count = 0;
-  for (int i = postorder->length() - 1; i >= 0; i--) {
-    postorder->at(i)->AssignNodeNumber();
-  }
-
-  // Print basic blocks in reverse postorder.
-  for (int i = postorder->length() - 1; i >= 0; i--) {
-    postorder->at(i)->PrintText();
-  }
+void TextInstructionPrinter::VisitDoWhileStatement(DoWhileStatement* stmt) {
+  PrintF("DoWhileStatement");
 }
 
 
-#endif  // defined(DEBUG)
-
-
-int ReachingDefinitions::IndexFor(Variable* var, int variable_count) {
-  // Parameters are numbered left-to-right from the beginning of the bit
-  // set.  Stack-allocated locals are allocated right-to-left from the end.
-  ASSERT(var != NULL && var->IsStackAllocated());
-  Slot* slot = var->slot();
-  if (slot->type() == Slot::PARAMETER) {
-    return slot->index();
-  } else {
-    return (variable_count - 1) - slot->index();
-  }
+void TextInstructionPrinter::VisitWhileStatement(WhileStatement* stmt) {
+  PrintF("WhileStatement");
 }
 
 
-void Node::InitializeReachingDefinitions(int definition_count,
-                                         List<BitVector*>* variables,
-                                         WorkList<Node>* worklist,
-                                         bool mark) {
-  ASSERT(!IsMarkedWith(mark));
-  rd_.Initialize(definition_count);
-  MarkWith(mark);
-  worklist->Insert(this);
+void TextInstructionPrinter::VisitForStatement(ForStatement* stmt) {
+  PrintF("ForStatement");
 }
 
 
-void BlockNode::InitializeReachingDefinitions(int definition_count,
-                                              List<BitVector*>* variables,
-                                              WorkList<Node>* worklist,
-                                              bool mark) {
-  ASSERT(!IsMarkedWith(mark));
-  int instruction_count = instructions_.length();
-  int variable_count = variables->length();
-
-  rd_.Initialize(definition_count);
-  // The RD_in set for the entry node has a definition for each parameter
-  // and local.
-  if (predecessor_ == NULL) {
-    for (int i = 0; i < variable_count; i++) rd_.rd_in()->Add(i);
-  }
-
-  for (int i = 0; i < instruction_count; i++) {
-    Expression* expr = instructions_[i]->AsExpression();
-    if (expr == NULL) continue;
-    Variable* var = expr->AssignedVariable();
-    if (var == NULL || !var->IsStackAllocated()) continue;
-
-    // All definitions of this variable are killed.
-    BitVector* def_set =
-        variables->at(ReachingDefinitions::IndexFor(var, variable_count));
-    rd_.kill()->Union(*def_set);
-
-    // All previously generated definitions are not generated.
-    rd_.gen()->Subtract(*def_set);
+void TextInstructionPrinter::VisitForInStatement(ForInStatement* stmt) {
+  PrintF("ForInStatement");
+}
 
-    // This one is generated.
-    rd_.gen()->Add(expr->num());
-  }
 
-  // Add all blocks except the entry node to the worklist.
-  if (predecessor_ != NULL) {
-    MarkWith(mark);
-    worklist->Insert(this);
-  }
+void TextInstructionPrinter::VisitTryCatchStatement(TryCatchStatement* stmt) {
+  UNREACHABLE();
 }
 
 
-void ExitNode::ComputeRDOut(BitVector* result) {
-  // Should not be the predecessor of any node.
+void TextInstructionPrinter::VisitTryFinallyStatement(
+    TryFinallyStatement* stmt) {
   UNREACHABLE();
 }
 
 
-void BlockNode::ComputeRDOut(BitVector* result) {
-  // All definitions reaching this block ...
-  *result = *rd_.rd_in();
-  // ... except those killed by the block ...
-  result->Subtract(*rd_.kill());
-  // ... but including those generated by the block.
-  result->Union(*rd_.gen());
+void TextInstructionPrinter::VisitDebuggerStatement(DebuggerStatement* stmt) {
+  PrintF("DebuggerStatement");
 }
 
 
-void BranchNode::ComputeRDOut(BitVector* result) {
-  // Branch nodes don't kill or generate definitions.
-  *result = *rd_.rd_in();
+void TextInstructionPrinter::VisitFunctionLiteral(FunctionLiteral* expr) {
+  PrintF("FunctionLiteral");
 }
 
 
-void JoinNode::ComputeRDOut(BitVector* result) {
-  // Join nodes don't kill or generate definitions.
-  *result = *rd_.rd_in();
+void TextInstructionPrinter::VisitSharedFunctionInfoLiteral(
+    SharedFunctionInfoLiteral* expr) {
+  PrintF("SharedFunctionInfoLiteral");
 }
 
 
-void ExitNode::UpdateRDIn(WorkList<Node>* worklist, bool mark) {
-  // The exit node has no successors so we can just update in place.  New
-  // RD_in is the union over all predecessors.
-  int definition_count = rd_.rd_in()->length();
-  rd_.rd_in()->Clear();
-
-  BitVector temp(definition_count);
-  for (int i = 0, len = predecessors_.length(); i < len; i++) {
-    // Because ComputeRDOut always overwrites temp and its value is
-    // always read out before calling ComputeRDOut again, we do not
-    // have to clear it on each iteration of the loop.
-    predecessors_[i]->ComputeRDOut(&temp);
-    rd_.rd_in()->Union(temp);
-  }
+void TextInstructionPrinter::VisitConditional(Conditional* expr) {
+  PrintF("Conditional");
 }
 
 
-void BlockNode::UpdateRDIn(WorkList<Node>* worklist, bool mark) {
-  // The entry block has no predecessor.  Its RD_in does not change.
-  if (predecessor_ == NULL) return;
-
-  BitVector new_rd_in(rd_.rd_in()->length());
-  predecessor_->ComputeRDOut(&new_rd_in);
+void TextInstructionPrinter::VisitSlot(Slot* expr) {
+  UNREACHABLE();
+}
 
-  if (rd_.rd_in()->Equals(new_rd_in)) return;
 
-  // Update RD_in.
-  *rd_.rd_in() = new_rd_in;
-  // Add the successor to the worklist if not already present.
-  if (!successor_->IsMarkedWith(mark)) {
-    successor_->MarkWith(mark);
-    worklist->Insert(successor_);
+void TextInstructionPrinter::VisitVariableProxy(VariableProxy* expr) {
+  Variable* var = expr->AsVariable();
+  if (var != NULL) {
+    PrintF("%s", *var->name()->ToCString());
+    if (var->IsStackAllocated() && expr->reaching_definitions() != NULL) {
+      expr->reaching_definitions()->Print();
+    }
+  } else {
+    ASSERT(expr->AsProperty() != NULL);
+    VisitProperty(expr->AsProperty());
   }
 }
 
 
-void BranchNode::UpdateRDIn(WorkList<Node>* worklist, bool mark) {
-  BitVector new_rd_in(rd_.rd_in()->length());
-  predecessor_->ComputeRDOut(&new_rd_in);
+void TextInstructionPrinter::VisitLiteral(Literal* expr) {
+  expr->handle()->ShortPrint();
+}
 
-  if (rd_.rd_in()->Equals(new_rd_in)) return;
 
-  // Update RD_in.
-  *rd_.rd_in() = new_rd_in;
-  // Add the successors to the worklist if not already present.
-  if (!successor0_->IsMarkedWith(mark)) {
-    successor0_->MarkWith(mark);
-    worklist->Insert(successor0_);
-  }
-  if (!successor1_->IsMarkedWith(mark)) {
-    successor1_->MarkWith(mark);
-    worklist->Insert(successor1_);
-  }
+void TextInstructionPrinter::VisitRegExpLiteral(RegExpLiteral* expr) {
+  PrintF("RegExpLiteral");
 }
 
 
-void JoinNode::UpdateRDIn(WorkList<Node>* worklist, bool mark) {
-  int definition_count = rd_.rd_in()->length();
-  BitVector new_rd_in(definition_count);
-
-  // New RD_in is the union over all predecessors.
-  BitVector temp(definition_count);
-  for (int i = 0, len = predecessors_.length(); i < len; i++) {
-    predecessors_[i]->ComputeRDOut(&temp);
-    new_rd_in.Union(temp);
-  }
+void TextInstructionPrinter::VisitObjectLiteral(ObjectLiteral* expr) {
+  PrintF("ObjectLiteral");
+}
 
-  if (rd_.rd_in()->Equals(new_rd_in)) return;
 
-  // Update RD_in.
-  *rd_.rd_in() = new_rd_in;
-  // Add the successor to the worklist if not already present.
-  if (!successor_->IsMarkedWith(mark)) {
-    successor_->MarkWith(mark);
-    worklist->Insert(successor_);
-  }
+void TextInstructionPrinter::VisitArrayLiteral(ArrayLiteral* expr) {
+  PrintF("ArrayLiteral");
 }
 
 
-void Node::PropagateReachingDefinitions(List<BitVector*>* variables) {
-  // Nothing to do.
+void TextInstructionPrinter::VisitCatchExtensionObject(
+    CatchExtensionObject* expr) {
+  PrintF("CatchExtensionObject");
 }
 
 
-void BlockNode::PropagateReachingDefinitions(List<BitVector*>* variables) {
-  // Propagate RD_in from the start of the block to all the variable
-  // references.
-  int variable_count = variables->length();
-  BitVector rd = *rd_.rd_in();
-  for (int i = 0, len = instructions_.length(); i < len; i++) {
-    Expression* expr = instructions_[i]->AsExpression();
-    if (expr == NULL) continue;
+void TextInstructionPrinter::VisitAssignment(Assignment* expr) {
+  Variable* var = expr->target()->AsVariableProxy()->AsVariable();
+  Property* prop = expr->target()->AsProperty();
 
-    // Look for a variable reference to record its reaching definitions.
-    VariableProxy* proxy = expr->AsVariableProxy();
-    if (proxy == NULL) {
-      // Not a VariableProxy?  Maybe it's a count operation.
-      CountOperation* count_operation = expr->AsCountOperation();
-      if (count_operation != NULL) {
-        proxy = count_operation->expression()->AsVariableProxy();
-      }
-    }
-    if (proxy == NULL) {
-      // OK, Maybe it's a compound assignment.
-      Assignment* assignment = expr->AsAssignment();
-      if (assignment != NULL && assignment->is_compound()) {
-        proxy = assignment->target()->AsVariableProxy();
-      }
+  if (var == NULL && prop == NULL) {
+    // Throw reference error.
+    Visit(expr->target());
+    return;
+  }
+
+  // Print the left-hand side.
+  if (var != NULL) {
+    PrintF("%s", *var->name()->ToCString());
+  } else if (prop != NULL) {
+    PrintF("@%d", prop->obj()->num());
+    if (prop->key()->IsPropertyName()) {
+      PrintF(".");
+      ASSERT(prop->key()->AsLiteral() != NULL);
+      prop->key()->AsLiteral()->handle()->Print();
+    } else {
+      PrintF("[@%d]", prop->key()->num());
     }
+  }
 
-    if (proxy != NULL &&
-        proxy->var()->IsStackAllocated() &&
-        !proxy->var()->is_this()) {
-      // All definitions for this variable.
-      BitVector* definitions =
-          variables->at(ReachingDefinitions::IndexFor(proxy->var(),
-                                                      variable_count));
-      BitVector* reaching_definitions = new BitVector(*definitions);
-      // Intersected with all definitions (of any variable) reaching this
-      // instruction.
-      reaching_definitions->Intersect(rd);
-      proxy->set_reaching_definitions(reaching_definitions);
+  // Print the operation.
+  if (expr->is_compound()) {
+    PrintF(" = ");
+    // Print the left-hand side again when compound.
+    if (var != NULL) {
+      PrintF("@%d", expr->target()->num());
+    } else {
+      PrintF("@%d", prop->obj()->num());
+      if (prop->key()->IsPropertyName()) {
+        PrintF(".");
+        ASSERT(prop->key()->AsLiteral() != NULL);
+        prop->key()->AsLiteral()->handle()->Print();
+      } else {
+        PrintF("[@%d]", prop->key()->num());
+      }
     }
+    // Print the corresponding binary operator.
+    PrintF(" %s ", Token::String(expr->binary_op()));
+  } else {
+    PrintF(" %s ", Token::String(expr->op()));
+  }
 
-    // It may instead (or also) be a definition.  If so update the running
-    // value of reaching definitions for the block.
-    Variable* var = expr->AssignedVariable();
-    if (var == NULL || !var->IsStackAllocated()) continue;
+  // Print the right-hand side.
+  PrintF("@%d", expr->value()->num());
 
-    // All definitions of this variable are killed.
-    BitVector* def_set =
-        variables->at(ReachingDefinitions::IndexFor(var, variable_count));
-    rd.Subtract(*def_set);
-    // This definition is generated.
-    rd.Add(expr->num());
+  if (expr->num() != AstNode::kNoNumber) {
+    PrintF(" ;; D%d", expr->num());
   }
 }
 
 
-void ReachingDefinitions::Compute() {
-  // The definitions in the body plus an implicit definition for each
-  // variable at function entry.
-  int definition_count = body_definitions_->length() + variable_count_;
-  int node_count = postorder_->length();
+void TextInstructionPrinter::VisitThrow(Throw* expr) {
+  PrintF("throw @%d", expr->exception()->num());
+}
 
-  // Step 1: For each stack-allocated variable, identify the set of all its
-  // definitions.
-  List<BitVector*> variables;
-  for (int i = 0; i < variable_count_; i++) {
-    // Add the initial definition for each variable.
-    BitVector* initial = new BitVector(definition_count);
-    initial->Add(i);
-    variables.Add(initial);
+
+void TextInstructionPrinter::VisitProperty(Property* expr) {
+  if (expr->key()->IsPropertyName()) {
+    PrintF("@%d.", expr->obj()->num());
+    ASSERT(expr->key()->AsLiteral() != NULL);
+    expr->key()->AsLiteral()->handle()->Print();
+  } else {
+    PrintF("@%d[@%d]", expr->obj()->num(), expr->key()->num());
   }
-  for (int i = 0, len = body_definitions_->length(); i < len; i++) {
-    // Account for each definition in the body as a definition of the
-    // defined variable.
-    Variable* var = body_definitions_->at(i)->AssignedVariable();
-    variables[IndexFor(var, variable_count_)]->Add(i + variable_count_);
+}
+
+
+void TextInstructionPrinter::VisitCall(Call* expr) {
+  PrintF("@%d(", expr->expression()->num());
+  ZoneList<Expression*>* arguments = expr->arguments();
+  for (int i = 0, len = arguments->length(); i < len; i++) {
+    if (i != 0) PrintF(", ");
+    PrintF("@%d", arguments->at(i)->num());
   }
+  PrintF(")");
+}
 
-  // Step 2: Compute KILL and GEN for each block node, initialize RD_in for
-  // all nodes, and mark and add all nodes to the worklist in reverse
-  // postorder.  All nodes should currently have the same mark.
-  bool mark = postorder_->at(0)->IsMarkedWith(false);  // Negation of current.
-  WorkList<Node> worklist(node_count);
-  for (int i = node_count - 1; i >= 0; i--) {
-    postorder_->at(i)->InitializeReachingDefinitions(definition_count,
-                                                     &variables,
-                                                     &worklist,
-                                                     mark);
+
+void TextInstructionPrinter::VisitCallNew(CallNew* expr) {
+  PrintF("new @%d(", expr->expression()->num());
+  ZoneList<Expression*>* arguments = expr->arguments();
+  for (int i = 0, len = arguments->length(); i < len; i++) {
+    if (i != 0) PrintF(", ");
+    PrintF("@%d", arguments->at(i)->num());
   }
+  PrintF(")");
+}
 
-  // Step 3: Until the worklist is empty, remove an item compute and update
-  // its rd_in based on its predecessor's rd_out.  If rd_in has changed, add
-  // all necessary successors to the worklist.
-  while (!worklist.is_empty()) {
-    Node* node = worklist.Remove();
-    node->MarkWith(!mark);
-    node->UpdateRDIn(&worklist, mark);
+
+void TextInstructionPrinter::VisitCallRuntime(CallRuntime* expr) {
+  PrintF("%s(", *expr->name()->ToCString());
+  ZoneList<Expression*>* arguments = expr->arguments();
+  for (int i = 0, len = arguments->length(); i < len; i++) {
+    if (i != 0) PrintF(", ");
+    PrintF("@%d", arguments->at(i)->num());
   }
+  PrintF(")");
+}
 
-  // Step 4: Based on RD_in for block nodes, propagate reaching definitions
-  // to all variable uses in the block.
-  for (int i = 0; i < node_count; i++) {
-    postorder_->at(i)->PropagateReachingDefinitions(&variables);
+
+void TextInstructionPrinter::VisitUnaryOperation(UnaryOperation* expr) {
+  PrintF("%s(@%d)", Token::String(expr->op()), expr->expression()->num());
+}
+
+
+void TextInstructionPrinter::VisitCountOperation(CountOperation* expr) {
+  if (expr->is_prefix()) {
+    PrintF("%s@%d", Token::String(expr->op()), expr->expression()->num());
+  } else {
+    PrintF("@%d%s", expr->expression()->num(), Token::String(expr->op()));
+  }
+
+  if (expr->num() != AstNode::kNoNumber) {
+    PrintF(" ;; D%d", expr->num());
   }
 }
 
 
-bool TypeAnalyzer::IsPrimitiveDef(int def_num) {
-  if (def_num < param_count_) return false;
-  if (def_num < variable_count_) return true;
-  return body_definitions_->at(def_num - variable_count_)->IsPrimitive();
+void TextInstructionPrinter::VisitBinaryOperation(BinaryOperation* expr) {
+  ASSERT(expr->op() != Token::COMMA);
+  ASSERT(expr->op() != Token::OR);
+  ASSERT(expr->op() != Token::AND);
+  PrintF("@%d %s @%d",
+         expr->left()->num(),
+         Token::String(expr->op()),
+         expr->right()->num());
 }
 
 
-void TypeAnalyzer::Compute() {
-  bool changed;
-  int count = 0;
+void TextInstructionPrinter::VisitCompareOperation(CompareOperation* expr) {
+  PrintF("@%d %s @%d",
+         expr->left()->num(),
+         Token::String(expr->op()),
+         expr->right()->num());
+}
 
-  do {
-    changed = false;
 
-    if (FLAG_print_graph_text) {
-      PrintF("TypeAnalyzer::Compute - iteration %d\n", count++);
-    }
+void TextInstructionPrinter::VisitThisFunction(ThisFunction* expr) {
+  PrintF("ThisFunction");
+}
 
-    for (int i = postorder_->length() - 1; i >= 0; --i) {
-      Node* node = postorder_->at(i);
-      if (node->IsBlockNode()) {
-        BlockNode* block = BlockNode::cast(node);
-        for (int j = 0; j < block->instructions()->length(); j++) {
-          Expression* expr = block->instructions()->at(j)->AsExpression();
-          if (expr != NULL) {
-            // For variable uses: Compute new type from reaching definitions.
-            VariableProxy* proxy = expr->AsVariableProxy();
-            if (proxy != NULL && proxy->reaching_definitions() != NULL) {
-              BitVector* rd = proxy->reaching_definitions();
-              bool prim_type = true;
-              // TODO(fsc): A sparse set representation of reaching
-              // definitions would speed up iterating here.
-              for (int k = 0; k < rd->length(); k++) {
-                if (rd->Contains(k) && !IsPrimitiveDef(k)) {
-                  prim_type = false;
-                  break;
-                }
-              }
-              // Reset changed flag if new type information was computed.
-              if (prim_type != proxy->IsPrimitive()) {
-                changed = true;
-                proxy->SetIsPrimitive(prim_type);
-              }
-            }
-          }
-        }
-      }
-    }
-  } while (changed);
+
+static int node_count = 0;
+static int instruction_count = 0;
+
+
+void Node::AssignNodeNumber() {
+  set_number(node_count++);
 }
 
 
-void Node::MarkCriticalInstructions(
-    List<AstNode*>* stack,
-    ZoneList<Expression*>* body_definitions,
-    int variable_count) {
+void Node::PrintReachingDefinitions() {
+  if (rd_.rd_in() != NULL) {
+    ASSERT(rd_.kill() != NULL && rd_.gen() != NULL);
+
+    PrintF("RD_in = ");
+    rd_.rd_in()->Print();
+    PrintF("\n");
+
+    PrintF("RD_kill = ");
+    rd_.kill()->Print();
+    PrintF("\n");
+
+    PrintF("RD_gen = ");
+    rd_.gen()->Print();
+    PrintF("\n");
+  }
 }
 
 
-void BlockNode::MarkCriticalInstructions(
-    List<AstNode*>* stack,
-    ZoneList<Expression*>* body_definitions,
-    int variable_count) {
-  for (int i = instructions_.length() - 1; i >= 0; i--) {
-    // Only expressions can appear in the flow graph for now.
-    Expression* expr = instructions_[i]->AsExpression();
-    if (expr != NULL && !expr->is_live() &&
-        (expr->is_loop_condition() || expr->IsCritical())) {
-      expr->mark_as_live();
-      expr->ProcessNonLiveChildren(stack, body_definitions, variable_count);
+void ExitNode::PrintText() {
+  PrintReachingDefinitions();
+  PrintF("L%d: Exit\n\n", number());
+}
+
+
+void BlockNode::PrintText() {
+  PrintReachingDefinitions();
+  // Print the instructions in the block.
+  PrintF("L%d: Block\n", number());
+  TextInstructionPrinter printer;
+  for (int i = 0, len = instructions_.length(); i < len; i++) {
+    AstNode* instr = instructions_[i];
+    // Print a star next to dead instructions.
+    if (instr->AsExpression() != NULL && instr->AsExpression()->is_live()) {
+      PrintF("  ");
+    } else {
+      PrintF("* ");
     }
+    PrintF("%d ", printer.NextNumber());
+    printer.Visit(instr);
+    printer.AssignNumber(instr);
+    PrintF("\n");
   }
+  PrintF("goto L%d\n\n", successor_->number());
 }
 
 
-void MarkLiveCode(ZoneList<Node*>* nodes,
-                  ZoneList<Expression*>* body_definitions,
-                  int variable_count) {
-  List<AstNode*> stack(20);
+void BranchNode::PrintText() {
+  PrintReachingDefinitions();
+  PrintF("L%d: Branch\n", number());
+  PrintF("goto (L%d, L%d)\n\n", successor0_->number(), successor1_->number());
+}
 
-  // Mark the critical AST nodes as live; mark their dependencies and
-  // add them to the marking stack.
-  for (int i = nodes->length() - 1; i >= 0; i--) {
-    nodes->at(i)->MarkCriticalInstructions(&stack, body_definitions,
-                                           variable_count);
+
+void JoinNode::PrintText() {
+  PrintReachingDefinitions();
+  PrintF("L%d: Join(", number());
+  for (int i = 0, len = predecessors_.length(); i < len; i++) {
+    if (i != 0) PrintF(", ");
+    PrintF("L%d", predecessors_[i]->number());
   }
+  PrintF(")\ngoto L%d\n\n", successor_->number());
+}
 
-  // Continue marking dependencies until no more.
-  while (!stack.is_empty()) {
-  // Only expressions can appear in the flow graph for now.
-    Expression* expr = stack.RemoveLast()->AsExpression();
-    if (expr != NULL) {
-      expr->ProcessNonLiveChildren(&stack, body_definitions, variable_count);
-    }
+
+void FlowGraph::PrintText(FunctionLiteral* fun, ZoneList<Node*>* postorder) {
+  PrintF("\n========\n");
+  PrintF("name = %s\n", *fun->name()->ToCString());
+
+  // Number nodes and instructions in reverse postorder.
+  node_count = 0;
+  instruction_count = 0;
+  for (int i = postorder->length() - 1; i >= 0; i--) {
+    postorder->at(i)->AssignNodeNumber();
+  }
+
+  // Print basic blocks in reverse postorder.
+  for (int i = postorder->length() - 1; i >= 0; i--) {
+    postorder->at(i)->PrintText();
   }
 }
 
+#endif  // DEBUG
+
 
 } }  // namespace v8::internal
index 8046e42..66df635 100644 (file)
@@ -37,6 +37,9 @@
 namespace v8 {
 namespace internal {
 
+// Forward declarations.
+class Node;
+
 class BitVector: public ZoneObject {
  public:
   explicit BitVector(int length)
@@ -205,344 +208,6 @@ struct ReachingDefinitionsData BASE_EMBEDDED {
 };
 
 
-// Flow-graph nodes.
-class Node: public ZoneObject {
- public:
-  Node() : number_(-1), mark_(false) {}
-
-  virtual ~Node() {}
-
-  virtual bool IsExitNode() { return false; }
-  virtual bool IsBlockNode() { return false; }
-  virtual bool IsBranchNode() { return false; }
-  virtual bool IsJoinNode() { return false; }
-
-  virtual void AddPredecessor(Node* predecessor) = 0;
-  virtual void AddSuccessor(Node* successor) = 0;
-
-  bool IsMarkedWith(bool mark) { return mark_ == mark; }
-  void MarkWith(bool mark) { mark_ = mark; }
-
-  // Perform a depth first search and record preorder and postorder
-  // traversal orders.
-  virtual void Traverse(bool mark,
-                        ZoneList<Node*>* preorder,
-                        ZoneList<Node*>* postorder) = 0;
-
-  int number() { return number_; }
-  void set_number(int number) { number_ = number; }
-
-  // Functions used by data-flow analyses.
-  virtual void InitializeReachingDefinitions(int definition_count,
-                                             List<BitVector*>* variables,
-                                             WorkList<Node>* worklist,
-                                             bool mark);
-  virtual void ComputeRDOut(BitVector* result) = 0;
-  virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark) = 0;
-  virtual void PropagateReachingDefinitions(List<BitVector*>* variables);
-
-  // Functions used by dead-code elimination.
-  virtual void MarkCriticalInstructions(
-      List<AstNode*>* stack,
-      ZoneList<Expression*>* body_definitions,
-      int variable_count);
-
-#ifdef DEBUG
-  void AssignNodeNumber();
-  void PrintReachingDefinitions();
-  virtual void PrintText() = 0;
-#endif
-
- protected:
-  ReachingDefinitionsData rd_;
-
- private:
-  int number_;
-  bool mark_;
-
-  DISALLOW_COPY_AND_ASSIGN(Node);
-};
-
-
-// An exit node has a arbitrarily many predecessors and no successors.
-class ExitNode: public Node {
- public:
-  ExitNode() : predecessors_(4) {}
-
-  virtual bool IsExitNode() { return true; }
-
-  virtual void AddPredecessor(Node* predecessor) {
-    ASSERT(predecessor != NULL);
-    predecessors_.Add(predecessor);
-  }
-
-  virtual void AddSuccessor(Node* successor) { UNREACHABLE(); }
-
-  virtual void Traverse(bool mark,
-                        ZoneList<Node*>* preorder,
-                        ZoneList<Node*>* postorder);
-
-  virtual void ComputeRDOut(BitVector* result);
-  virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark);
-
-#ifdef DEBUG
-  virtual void PrintText();
-#endif
-
- private:
-  ZoneList<Node*> predecessors_;
-
-  DISALLOW_COPY_AND_ASSIGN(ExitNode);
-};
-
-
-// Block nodes have a single successor and predecessor and a list of
-// instructions.
-class BlockNode: public Node {
- public:
-  BlockNode() : predecessor_(NULL), successor_(NULL), instructions_(4) {}
-
-  static BlockNode* cast(Node* node) {
-    ASSERT(node->IsBlockNode());
-    return reinterpret_cast<BlockNode*>(node);
-  }
-
-  virtual bool IsBlockNode() { return true; }
-
-  bool is_empty() { return instructions_.is_empty(); }
-
-  ZoneList<AstNode*>* instructions() { return &instructions_; }
-
-  virtual void AddPredecessor(Node* predecessor) {
-    ASSERT(predecessor_ == NULL && predecessor != NULL);
-    predecessor_ = predecessor;
-  }
-
-  virtual void AddSuccessor(Node* successor) {
-    ASSERT(successor_ == NULL && successor != NULL);
-    successor_ = successor;
-  }
-
-  void AddInstruction(AstNode* instruction) {
-    instructions_.Add(instruction);
-  }
-
-  virtual void Traverse(bool mark,
-                        ZoneList<Node*>* preorder,
-                        ZoneList<Node*>* postorder);
-
-  virtual void InitializeReachingDefinitions(int definition_count,
-                                             List<BitVector*>* variables,
-                                             WorkList<Node>* worklist,
-                                             bool mark);
-  virtual void ComputeRDOut(BitVector* result);
-  virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark);
-  virtual void PropagateReachingDefinitions(List<BitVector*>* variables);
-
-  virtual void MarkCriticalInstructions(
-      List<AstNode*>* stack,
-      ZoneList<Expression*>* body_definitions,
-      int variable_count);
-
-#ifdef DEBUG
-  virtual void PrintText();
-#endif
-
- private:
-  Node* predecessor_;
-  Node* successor_;
-  ZoneList<AstNode*> instructions_;
-
-  DISALLOW_COPY_AND_ASSIGN(BlockNode);
-};
-
-
-// Branch nodes have a single predecessor and a pair of successors.
-class BranchNode: public Node {
- public:
-  BranchNode() : predecessor_(NULL), successor0_(NULL), successor1_(NULL) {}
-
-  virtual bool IsBranchNode() { return true; }
-
-  virtual void AddPredecessor(Node* predecessor) {
-    ASSERT(predecessor_ == NULL && predecessor != NULL);
-    predecessor_ = predecessor;
-  }
-
-  virtual void AddSuccessor(Node* successor) {
-    ASSERT(successor1_ == NULL && successor != NULL);
-    if (successor0_ == NULL) {
-      successor0_ = successor;
-    } else {
-      successor1_ = successor;
-    }
-  }
-
-  virtual void Traverse(bool mark,
-                        ZoneList<Node*>* preorder,
-                        ZoneList<Node*>* postorder);
-
-  virtual void ComputeRDOut(BitVector* result);
-  virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark);
-
-#ifdef DEBUG
-  virtual void PrintText();
-#endif
-
- private:
-  Node* predecessor_;
-  Node* successor0_;
-  Node* successor1_;
-
-  DISALLOW_COPY_AND_ASSIGN(BranchNode);
-};
-
-
-// Join nodes have arbitrarily many predecessors and a single successor.
-class JoinNode: public Node {
- public:
-  JoinNode() : predecessors_(2), successor_(NULL) {}
-
-  static JoinNode* cast(Node* node) {
-    ASSERT(node->IsJoinNode());
-    return reinterpret_cast<JoinNode*>(node);
-  }
-
-  virtual bool IsJoinNode() { return true; }
-
-  virtual void AddPredecessor(Node* predecessor) {
-    ASSERT(predecessor != NULL);
-    predecessors_.Add(predecessor);
-  }
-
-  virtual void AddSuccessor(Node* successor) {
-    ASSERT(successor_ == NULL && successor != NULL);
-    successor_ = successor;
-  }
-
-  virtual void Traverse(bool mark,
-                        ZoneList<Node*>* preorder,
-                        ZoneList<Node*>* postorder);
-
-  virtual void ComputeRDOut(BitVector* result);
-  virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark);
-
-#ifdef DEBUG
-  virtual void PrintText();
-#endif
-
- private:
-  ZoneList<Node*> predecessors_;
-  Node* successor_;
-
-  DISALLOW_COPY_AND_ASSIGN(JoinNode);
-};
-
-
-// Flow graphs have a single entry and single exit.  The empty flowgraph is
-// represented by both entry and exit being NULL.
-class FlowGraph BASE_EMBEDDED {
- public:
-  static FlowGraph Empty() {
-    FlowGraph graph;
-    graph.entry_ = new BlockNode();
-    graph.exit_ = graph.entry_;
-    return graph;
-  }
-
-  bool is_empty() const {
-    return entry_ == exit_ && BlockNode::cast(entry_)->is_empty();
-  }
-  Node* entry() const { return entry_; }
-  Node* exit() const { return exit_; }
-
-  // Add a single instruction to the end of this flowgraph.
-  void AppendInstruction(AstNode* instruction);
-
-  // Add a single node to the end of this flow graph.
-  void AppendNode(Node* node);
-
-  // Add a flow graph fragment to the end of this one.
-  void AppendGraph(FlowGraph* graph);
-
-  // Concatenate an if-then-else flow-graph to this one.  Control is split
-  // and merged, so the graph remains single-entry, single-exit.
-  void Split(BranchNode* branch,
-             FlowGraph* left,
-             FlowGraph* right,
-             JoinNode* merge);
-
-  // Concatenate a forward loop (e.g., while or for loop) flow-graph to this
-  // one.  Control is split by the condition and merged back from the back
-  // edge at end of the body to the beginning of the condition.  The single
-  // (free) exit of the result graph is the right (false) arm of the branch
-  // node.
-  void Loop(JoinNode* merge,
-            FlowGraph* condition,
-            BranchNode* branch,
-            FlowGraph* body);
-
-#ifdef DEBUG
-  void PrintText(FunctionLiteral* fun, ZoneList<Node*>* postorder);
-#endif
-
- private:
-  FlowGraph() : entry_(NULL), exit_(NULL) {}
-
-  Node* entry_;
-  Node* exit_;
-};
-
-
-// Construct a flow graph from a function literal.  Build pre- and postorder
-// traversal orders as a byproduct.
-class FlowGraphBuilder: public AstVisitor {
- public:
-  explicit FlowGraphBuilder(int variable_count)
-      : graph_(FlowGraph::Empty()),
-        global_exit_(NULL),
-        preorder_(4),
-        postorder_(4),
-        variable_count_(variable_count),
-        body_definitions_(4) {
-  }
-
-  void Build(FunctionLiteral* lit);
-
-  FlowGraph* graph() { return &graph_; }
-  ZoneList<Node*>* preorder() { return &preorder_; }
-  ZoneList<Node*>* postorder() { return &postorder_; }
-  ZoneList<Expression*>* body_definitions() { return &body_definitions_; }
-
- private:
-  ExitNode* global_exit() { return global_exit_; }
-
-  // Helpers to allow tranforming the ast during flow graph construction.
-  void VisitStatements(ZoneList<Statement*>* stmts);
-  Statement* ProcessStatement(Statement* stmt);
-
-  // AST node visit functions.
-#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
-  AST_NODE_LIST(DECLARE_VISIT)
-#undef DECLARE_VISIT
-
-  FlowGraph graph_;
-  ExitNode* global_exit_;
-  ZoneList<Node*> preorder_;
-  ZoneList<Node*> postorder_;
-
-  // The flow graph builder collects a list of explicit definitions
-  // (assignments and count operations) to stack-allocated variables to use
-  // for reaching definitions analysis.  It does not count the implicit
-  // definition at function entry.  AST node numbers in the AST are used to
-  // refer into this list.
-  int variable_count_;
-  ZoneList<Expression*> body_definitions_;
-
-  DISALLOW_COPY_AND_ASSIGN(FlowGraphBuilder);
-};
-
-
 // This class is used to number all expressions in the AST according to
 // their evaluation order (post-order left-to-right traversal).
 class AstLabeler: public AstVisitor {
diff --git a/deps/v8/src/flow-graph.cc b/deps/v8/src/flow-graph.cc
new file mode 100644 (file)
index 0000000..bd9602f
--- /dev/null
@@ -0,0 +1,588 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "flow-graph.h"
+
+namespace v8 {
+namespace internal {
+
+void FlowGraph::AppendInstruction(AstNode* instruction) {
+  // Add a (non-null) AstNode to the end of the graph fragment.
+  ASSERT(instruction != NULL);
+  if (exit()->IsExitNode()) return;
+  if (!exit()->IsBlockNode()) AppendNode(new BlockNode());
+  BlockNode::cast(exit())->AddInstruction(instruction);
+}
+
+
+void FlowGraph::AppendNode(Node* node) {
+  // Add a node to the end of the graph.  An empty block is added to
+  // maintain edge-split form (that no join nodes or exit nodes as
+  // successors to branch nodes).
+  ASSERT(node != NULL);
+  if (exit()->IsExitNode()) return;
+  if (exit()->IsBranchNode() && (node->IsJoinNode() || node->IsExitNode())) {
+    AppendNode(new BlockNode());
+  }
+  exit()->AddSuccessor(node);
+  node->AddPredecessor(exit());
+  exit_ = node;
+}
+
+
+void FlowGraph::AppendGraph(FlowGraph* graph) {
+  // Add a flow graph fragment to the end of this one.  An empty block is
+  // added to maintain edge-split form (that no join nodes or exit nodes as
+  // successors to branch nodes).
+  ASSERT(graph != NULL);
+  if (exit()->IsExitNode()) return;
+  Node* node = graph->entry();
+  if (exit()->IsBranchNode() && (node->IsJoinNode() || node->IsExitNode())) {
+    AppendNode(new BlockNode());
+  }
+  exit()->AddSuccessor(node);
+  node->AddPredecessor(exit());
+  exit_ = graph->exit();
+}
+
+
+void FlowGraph::Split(BranchNode* branch,
+                      FlowGraph* left,
+                      FlowGraph* right,
+                      JoinNode* join) {
+  // Add the branch node, left flowgraph, join node.
+  AppendNode(branch);
+  AppendGraph(left);
+  AppendNode(join);
+
+  // Splice in the right flowgraph.
+  right->AppendNode(join);
+  branch->AddSuccessor(right->entry());
+  right->entry()->AddPredecessor(branch);
+}
+
+
+void FlowGraph::Loop(JoinNode* join,
+                     FlowGraph* condition,
+                     BranchNode* branch,
+                     FlowGraph* body) {
+  // Add the join, condition and branch.  Add join's predecessors in
+  // left-to-right order.
+  AppendNode(join);
+  body->AppendNode(join);
+  AppendGraph(condition);
+  AppendNode(branch);
+
+  // Splice in the body flowgraph.
+  branch->AddSuccessor(body->entry());
+  body->entry()->AddPredecessor(branch);
+}
+
+
+void ExitNode::Traverse(bool mark,
+                        ZoneList<Node*>* preorder,
+                        ZoneList<Node*>* postorder) {
+  preorder->Add(this);
+  postorder->Add(this);
+}
+
+
+void BlockNode::Traverse(bool mark,
+                         ZoneList<Node*>* preorder,
+                         ZoneList<Node*>* postorder) {
+  ASSERT(successor_ != NULL);
+  preorder->Add(this);
+  if (!successor_->IsMarkedWith(mark)) {
+    successor_->MarkWith(mark);
+    successor_->Traverse(mark, preorder, postorder);
+  }
+  postorder->Add(this);
+}
+
+
+void BranchNode::Traverse(bool mark,
+                          ZoneList<Node*>* preorder,
+                          ZoneList<Node*>* postorder) {
+  ASSERT(successor0_ != NULL && successor1_ != NULL);
+  preorder->Add(this);
+  if (!successor1_->IsMarkedWith(mark)) {
+    successor1_->MarkWith(mark);
+    successor1_->Traverse(mark, preorder, postorder);
+  }
+  if (!successor0_->IsMarkedWith(mark)) {
+    successor0_->MarkWith(mark);
+    successor0_->Traverse(mark, preorder, postorder);
+  }
+  postorder->Add(this);
+}
+
+
+void JoinNode::Traverse(bool mark,
+                        ZoneList<Node*>* preorder,
+                        ZoneList<Node*>* postorder) {
+  ASSERT(successor_ != NULL);
+  preorder->Add(this);
+  if (!successor_->IsMarkedWith(mark)) {
+    successor_->MarkWith(mark);
+    successor_->Traverse(mark, preorder, postorder);
+  }
+  postorder->Add(this);
+}
+
+
+void FlowGraphBuilder::Build(FunctionLiteral* lit) {
+  global_exit_ = new ExitNode();
+  VisitStatements(lit->body());
+
+  if (HasStackOverflow()) return;
+
+  // The graph can end with a branch node (if the function ended with a
+  // loop).  Maintain edge-split form (no join nodes or exit nodes as
+  // successors to branch nodes).
+  if (graph_.exit()->IsBranchNode()) graph_.AppendNode(new BlockNode());
+  graph_.AppendNode(global_exit_);
+
+  // Build preorder and postorder traversal orders.  All the nodes in
+  // the graph have the same mark flag.  For the traversal, use that
+  // flag's negation.  Traversal will flip all the flags.
+  bool mark = graph_.entry()->IsMarkedWith(false);
+  graph_.entry()->MarkWith(mark);
+  graph_.entry()->Traverse(mark, &preorder_, &postorder_);
+}
+
+
+// This function peels off one iteration of a for-loop. The return value
+// is either a block statement containing the peeled loop or NULL in case
+// there is a stack overflow.
+static Statement* PeelForLoop(ForStatement* stmt) {
+  // Mark this for-statement as processed.
+  stmt->set_peel_this_loop(false);
+
+  // Create new block containing the init statement of the for-loop and
+  // an if-statement containing the peeled iteration and the original
+  // loop without the init-statement.
+  Block* block = new Block(NULL, 2, false);
+  if (stmt->init() != NULL) {
+    Statement* init = stmt->init();
+    // The init statement gets the statement position of the for-loop
+    // to make debugging of peeled loops possible.
+    init->set_statement_pos(stmt->statement_pos());
+    block->AddStatement(init);
+  }
+
+  // Copy the condition.
+  CopyAstVisitor copy_visitor;
+  Expression* cond_copy = stmt->cond() != NULL
+      ? copy_visitor.DeepCopyExpr(stmt->cond())
+      : new Literal(Factory::true_value());
+  if (copy_visitor.HasStackOverflow()) return NULL;
+
+  // Construct a block with the peeled body and the rest of the for-loop.
+  Statement* body_copy = copy_visitor.DeepCopyStmt(stmt->body());
+  if (copy_visitor.HasStackOverflow()) return NULL;
+
+  Statement* next_copy = stmt->next() != NULL
+      ? copy_visitor.DeepCopyStmt(stmt->next())
+      : new EmptyStatement();
+  if (copy_visitor.HasStackOverflow()) return NULL;
+
+  Block* peeled_body = new Block(NULL, 3, false);
+  peeled_body->AddStatement(body_copy);
+  peeled_body->AddStatement(next_copy);
+  peeled_body->AddStatement(stmt);
+
+  // Remove the duplicated init statement from the for-statement.
+  stmt->set_init(NULL);
+
+  // Create new test at the top and add it to the newly created block.
+  IfStatement* test = new IfStatement(cond_copy,
+                                      peeled_body,
+                                      new EmptyStatement());
+  block->AddStatement(test);
+  return block;
+}
+
+
+void FlowGraphBuilder::VisitStatements(ZoneList<Statement*>* stmts) {
+  for (int i = 0, len = stmts->length(); i < len; i++) {
+    stmts->at(i) = ProcessStatement(stmts->at(i));
+  }
+}
+
+
+Statement* FlowGraphBuilder::ProcessStatement(Statement* stmt) {
+  if (FLAG_loop_peeling &&
+      stmt->AsForStatement() != NULL &&
+      stmt->AsForStatement()->peel_this_loop()) {
+    Statement* tmp_stmt = PeelForLoop(stmt->AsForStatement());
+    if (tmp_stmt == NULL) {
+      SetStackOverflow();
+    } else {
+      stmt = tmp_stmt;
+    }
+  }
+  Visit(stmt);
+  return stmt;
+}
+
+
+void FlowGraphBuilder::VisitDeclaration(Declaration* decl) {
+  UNREACHABLE();
+}
+
+
+void FlowGraphBuilder::VisitBlock(Block* stmt) {
+  VisitStatements(stmt->statements());
+}
+
+
+void FlowGraphBuilder::VisitExpressionStatement(ExpressionStatement* stmt) {
+  Visit(stmt->expression());
+}
+
+
+void FlowGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) {
+  // Nothing to do.
+}
+
+
+void FlowGraphBuilder::VisitIfStatement(IfStatement* stmt) {
+  Visit(stmt->condition());
+
+  BranchNode* branch = new BranchNode();
+  FlowGraph original = graph_;
+  graph_ = FlowGraph::Empty();
+  stmt->set_then_statement(ProcessStatement(stmt->then_statement()));
+
+  FlowGraph left = graph_;
+  graph_ = FlowGraph::Empty();
+  stmt->set_else_statement(ProcessStatement(stmt->else_statement()));
+
+  if (HasStackOverflow()) return;
+  JoinNode* join = new JoinNode();
+  original.Split(branch, &left, &graph_, join);
+  graph_ = original;
+}
+
+
+void FlowGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) {
+  SetStackOverflow();
+}
+
+
+void FlowGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
+  SetStackOverflow();
+}
+
+
+void FlowGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
+  SetStackOverflow();
+}
+
+
+void FlowGraphBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) {
+  SetStackOverflow();
+}
+
+
+void FlowGraphBuilder::VisitWithExitStatement(WithExitStatement* stmt) {
+  SetStackOverflow();
+}
+
+
+void FlowGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
+  SetStackOverflow();
+}
+
+
+void FlowGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
+  SetStackOverflow();
+}
+
+
+void FlowGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
+  SetStackOverflow();
+}
+
+
+void FlowGraphBuilder::VisitForStatement(ForStatement* stmt) {
+  if (stmt->init() != NULL) stmt->set_init(ProcessStatement(stmt->init()));
+
+  JoinNode* join = new JoinNode();
+  FlowGraph original = graph_;
+  graph_ = FlowGraph::Empty();
+  if (stmt->cond() != NULL) Visit(stmt->cond());
+
+  BranchNode* branch = new BranchNode();
+  FlowGraph condition = graph_;
+  graph_ = FlowGraph::Empty();
+  stmt->set_body(ProcessStatement(stmt->body()));
+
+  if (stmt->next() != NULL) stmt->set_next(ProcessStatement(stmt->next()));
+
+  if (HasStackOverflow()) return;
+  original.Loop(join, &condition, branch, &graph_);
+  graph_ = original;
+}
+
+
+void FlowGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
+  SetStackOverflow();
+}
+
+
+void FlowGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
+  SetStackOverflow();
+}
+
+
+void FlowGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
+  SetStackOverflow();
+}
+
+
+void FlowGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
+  SetStackOverflow();
+}
+
+
+void FlowGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
+  SetStackOverflow();
+}
+
+
+void FlowGraphBuilder::VisitSharedFunctionInfoLiteral(
+    SharedFunctionInfoLiteral* expr) {
+  SetStackOverflow();
+}
+
+
+void FlowGraphBuilder::VisitConditional(Conditional* expr) {
+  SetStackOverflow();
+}
+
+
+void FlowGraphBuilder::VisitSlot(Slot* expr) {
+  UNREACHABLE();
+}
+
+
+void FlowGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
+  graph_.AppendInstruction(expr);
+}
+
+
+void FlowGraphBuilder::VisitLiteral(Literal* expr) {
+  graph_.AppendInstruction(expr);
+}
+
+
+void FlowGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
+  SetStackOverflow();
+}
+
+
+void FlowGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
+  SetStackOverflow();
+}
+
+
+void FlowGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
+  SetStackOverflow();
+}
+
+
+void FlowGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) {
+  SetStackOverflow();
+}
+
+
+void FlowGraphBuilder::VisitAssignment(Assignment* expr) {
+  Variable* var = expr->target()->AsVariableProxy()->AsVariable();
+  Property* prop = expr->target()->AsProperty();
+  // Left-hand side can be a variable or property (or reference error) but
+  // not both.
+  ASSERT(var == NULL || prop == NULL);
+  if (var != NULL) {
+    if (expr->is_compound()) Visit(expr->target());
+    Visit(expr->value());
+    if (var->IsStackAllocated()) {
+      // The first definition in the body is numbered n, where n is the
+      // number of parameters and stack-allocated locals.
+      expr->set_num(body_definitions_.length() + variable_count_);
+      body_definitions_.Add(expr);
+    }
+
+  } else if (prop != NULL) {
+    Visit(prop->obj());
+    if (!prop->key()->IsPropertyName()) Visit(prop->key());
+    Visit(expr->value());
+  }
+
+  if (HasStackOverflow()) return;
+  graph_.AppendInstruction(expr);
+}
+
+
+void FlowGraphBuilder::VisitThrow(Throw* expr) {
+  SetStackOverflow();
+}
+
+
+void FlowGraphBuilder::VisitProperty(Property* expr) {
+  Visit(expr->obj());
+  if (!expr->key()->IsPropertyName()) Visit(expr->key());
+
+  if (HasStackOverflow()) return;
+  graph_.AppendInstruction(expr);
+}
+
+
+void FlowGraphBuilder::VisitCall(Call* expr) {
+  Visit(expr->expression());
+  ZoneList<Expression*>* arguments = expr->arguments();
+  for (int i = 0, len = arguments->length(); i < len; i++) {
+    Visit(arguments->at(i));
+  }
+
+  if (HasStackOverflow()) return;
+  graph_.AppendInstruction(expr);
+}
+
+
+void FlowGraphBuilder::VisitCallNew(CallNew* expr) {
+  SetStackOverflow();
+}
+
+
+void FlowGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
+  SetStackOverflow();
+}
+
+
+void FlowGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
+  switch (expr->op()) {
+    case Token::NOT:
+    case Token::BIT_NOT:
+    case Token::DELETE:
+    case Token::TYPEOF:
+    case Token::VOID:
+      SetStackOverflow();
+      break;
+
+    case Token::ADD:
+    case Token::SUB:
+      Visit(expr->expression());
+      if (HasStackOverflow()) return;
+      graph_.AppendInstruction(expr);
+      break;
+
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void FlowGraphBuilder::VisitCountOperation(CountOperation* expr) {
+  Visit(expr->expression());
+  Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
+  if (var != NULL && var->IsStackAllocated()) {
+    // The first definition in the body is numbered n, where n is the number
+    // of parameters and stack-allocated locals.
+    expr->set_num(body_definitions_.length() + variable_count_);
+    body_definitions_.Add(expr);
+  }
+
+  if (HasStackOverflow()) return;
+  graph_.AppendInstruction(expr);
+}
+
+
+void FlowGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
+  switch (expr->op()) {
+    case Token::COMMA:
+    case Token::OR:
+    case Token::AND:
+      SetStackOverflow();
+      break;
+
+    case Token::BIT_OR:
+    case Token::BIT_XOR:
+    case Token::BIT_AND:
+    case Token::SHL:
+    case Token::SHR:
+    case Token::ADD:
+    case Token::SUB:
+    case Token::MUL:
+    case Token::DIV:
+    case Token::MOD:
+    case Token::SAR:
+      Visit(expr->left());
+      Visit(expr->right());
+      if (HasStackOverflow()) return;
+      graph_.AppendInstruction(expr);
+      break;
+
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void FlowGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
+  switch (expr->op()) {
+    case Token::EQ:
+    case Token::NE:
+    case Token::EQ_STRICT:
+    case Token::NE_STRICT:
+    case Token::INSTANCEOF:
+    case Token::IN:
+      SetStackOverflow();
+      break;
+
+    case Token::LT:
+    case Token::GT:
+    case Token::LTE:
+    case Token::GTE:
+      Visit(expr->left());
+      Visit(expr->right());
+      if (HasStackOverflow()) return;
+      graph_.AppendInstruction(expr);
+      break;
+
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void FlowGraphBuilder::VisitThisFunction(ThisFunction* expr) {
+  SetStackOverflow();
+}
+
+
+} }  // namespace v8::internal
diff --git a/deps/v8/src/flow-graph.h b/deps/v8/src/flow-graph.h
new file mode 100644 (file)
index 0000000..183b71d
--- /dev/null
@@ -0,0 +1,379 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_FLOW_GRAPH_H_
+#define V8_FLOW_GRAPH_H_
+
+#include "v8.h"
+
+#include "data-flow.h"
+#include "zone.h"
+
+namespace v8 {
+namespace internal {
+
+// Flow-graph nodes.
+class Node: public ZoneObject {
+ public:
+  Node() : number_(-1), mark_(false) {}
+
+  virtual ~Node() {}
+
+  virtual bool IsExitNode() { return false; }
+  virtual bool IsBlockNode() { return false; }
+  virtual bool IsBranchNode() { return false; }
+  virtual bool IsJoinNode() { return false; }
+
+  virtual void AddPredecessor(Node* predecessor) = 0;
+  virtual void AddSuccessor(Node* successor) = 0;
+
+  bool IsMarkedWith(bool mark) { return mark_ == mark; }
+  void MarkWith(bool mark) { mark_ = mark; }
+
+  // Perform a depth first search and record preorder and postorder
+  // traversal orders.
+  virtual void Traverse(bool mark,
+                        ZoneList<Node*>* preorder,
+                        ZoneList<Node*>* postorder) = 0;
+
+  int number() { return number_; }
+  void set_number(int number) { number_ = number; }
+
+  // Functions used by data-flow analyses.
+  virtual void InitializeReachingDefinitions(int definition_count,
+                                             List<BitVector*>* variables,
+                                             WorkList<Node>* worklist,
+                                             bool mark);
+  virtual void ComputeRDOut(BitVector* result) = 0;
+  virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark) = 0;
+  virtual void PropagateReachingDefinitions(List<BitVector*>* variables);
+
+  // Functions used by dead-code elimination.
+  virtual void MarkCriticalInstructions(
+      List<AstNode*>* stack,
+      ZoneList<Expression*>* body_definitions,
+      int variable_count);
+
+#ifdef DEBUG
+  void AssignNodeNumber();
+  void PrintReachingDefinitions();
+  virtual void PrintText() = 0;
+#endif
+
+ protected:
+  ReachingDefinitionsData rd_;
+
+ private:
+  int number_;
+  bool mark_;
+
+  DISALLOW_COPY_AND_ASSIGN(Node);
+};
+
+
+// An exit node has a arbitrarily many predecessors and no successors.
+class ExitNode: public Node {
+ public:
+  ExitNode() : predecessors_(4) {}
+
+  virtual bool IsExitNode() { return true; }
+
+  virtual void AddPredecessor(Node* predecessor) {
+    ASSERT(predecessor != NULL);
+    predecessors_.Add(predecessor);
+  }
+
+  virtual void AddSuccessor(Node* successor) { UNREACHABLE(); }
+
+  virtual void Traverse(bool mark,
+                        ZoneList<Node*>* preorder,
+                        ZoneList<Node*>* postorder);
+
+  virtual void ComputeRDOut(BitVector* result);
+  virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark);
+
+#ifdef DEBUG
+  virtual void PrintText();
+#endif
+
+ private:
+  ZoneList<Node*> predecessors_;
+
+  DISALLOW_COPY_AND_ASSIGN(ExitNode);
+};
+
+
+// Block nodes have a single successor and predecessor and a list of
+// instructions.
+class BlockNode: public Node {
+ public:
+  BlockNode() : predecessor_(NULL), successor_(NULL), instructions_(4) {}
+
+  static BlockNode* cast(Node* node) {
+    ASSERT(node->IsBlockNode());
+    return reinterpret_cast<BlockNode*>(node);
+  }
+
+  virtual bool IsBlockNode() { return true; }
+
+  bool is_empty() { return instructions_.is_empty(); }
+
+  ZoneList<AstNode*>* instructions() { return &instructions_; }
+
+  virtual void AddPredecessor(Node* predecessor) {
+    ASSERT(predecessor_ == NULL && predecessor != NULL);
+    predecessor_ = predecessor;
+  }
+
+  virtual void AddSuccessor(Node* successor) {
+    ASSERT(successor_ == NULL && successor != NULL);
+    successor_ = successor;
+  }
+
+  void AddInstruction(AstNode* instruction) {
+    instructions_.Add(instruction);
+  }
+
+  virtual void Traverse(bool mark,
+                        ZoneList<Node*>* preorder,
+                        ZoneList<Node*>* postorder);
+
+  virtual void InitializeReachingDefinitions(int definition_count,
+                                             List<BitVector*>* variables,
+                                             WorkList<Node>* worklist,
+                                             bool mark);
+  virtual void ComputeRDOut(BitVector* result);
+  virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark);
+  virtual void PropagateReachingDefinitions(List<BitVector*>* variables);
+
+  virtual void MarkCriticalInstructions(
+      List<AstNode*>* stack,
+      ZoneList<Expression*>* body_definitions,
+      int variable_count);
+
+#ifdef DEBUG
+  virtual void PrintText();
+#endif
+
+ private:
+  Node* predecessor_;
+  Node* successor_;
+  ZoneList<AstNode*> instructions_;
+
+  DISALLOW_COPY_AND_ASSIGN(BlockNode);
+};
+
+
+// Branch nodes have a single predecessor and a pair of successors.
+class BranchNode: public Node {
+ public:
+  BranchNode() : predecessor_(NULL), successor0_(NULL), successor1_(NULL) {}
+
+  virtual bool IsBranchNode() { return true; }
+
+  virtual void AddPredecessor(Node* predecessor) {
+    ASSERT(predecessor_ == NULL && predecessor != NULL);
+    predecessor_ = predecessor;
+  }
+
+  virtual void AddSuccessor(Node* successor) {
+    ASSERT(successor1_ == NULL && successor != NULL);
+    if (successor0_ == NULL) {
+      successor0_ = successor;
+    } else {
+      successor1_ = successor;
+    }
+  }
+
+  virtual void Traverse(bool mark,
+                        ZoneList<Node*>* preorder,
+                        ZoneList<Node*>* postorder);
+
+  virtual void ComputeRDOut(BitVector* result);
+  virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark);
+
+#ifdef DEBUG
+  virtual void PrintText();
+#endif
+
+ private:
+  Node* predecessor_;
+  Node* successor0_;
+  Node* successor1_;
+
+  DISALLOW_COPY_AND_ASSIGN(BranchNode);
+};
+
+
+// Join nodes have arbitrarily many predecessors and a single successor.
+class JoinNode: public Node {
+ public:
+  JoinNode() : predecessors_(2), successor_(NULL) {}
+
+  static JoinNode* cast(Node* node) {
+    ASSERT(node->IsJoinNode());
+    return reinterpret_cast<JoinNode*>(node);
+  }
+
+  virtual bool IsJoinNode() { return true; }
+
+  virtual void AddPredecessor(Node* predecessor) {
+    ASSERT(predecessor != NULL);
+    predecessors_.Add(predecessor);
+  }
+
+  virtual void AddSuccessor(Node* successor) {
+    ASSERT(successor_ == NULL && successor != NULL);
+    successor_ = successor;
+  }
+
+  virtual void Traverse(bool mark,
+                        ZoneList<Node*>* preorder,
+                        ZoneList<Node*>* postorder);
+
+  virtual void ComputeRDOut(BitVector* result);
+  virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark);
+
+#ifdef DEBUG
+  virtual void PrintText();
+#endif
+
+ private:
+  ZoneList<Node*> predecessors_;
+  Node* successor_;
+
+  DISALLOW_COPY_AND_ASSIGN(JoinNode);
+};
+
+
+// Flow graphs have a single entry and single exit.  The empty flowgraph is
+// represented by both entry and exit being NULL.
+class FlowGraph BASE_EMBEDDED {
+ public:
+  static FlowGraph Empty() {
+    FlowGraph graph;
+    graph.entry_ = new BlockNode();
+    graph.exit_ = graph.entry_;
+    return graph;
+  }
+
+  bool is_empty() const {
+    return entry_ == exit_ && BlockNode::cast(entry_)->is_empty();
+  }
+  Node* entry() const { return entry_; }
+  Node* exit() const { return exit_; }
+
+  // Add a single instruction to the end of this flowgraph.
+  void AppendInstruction(AstNode* instruction);
+
+  // Add a single node to the end of this flow graph.
+  void AppendNode(Node* node);
+
+  // Add a flow graph fragment to the end of this one.
+  void AppendGraph(FlowGraph* graph);
+
+  // Concatenate an if-then-else flow-graph to this one.  Control is split
+  // and merged, so the graph remains single-entry, single-exit.
+  void Split(BranchNode* branch,
+             FlowGraph* left,
+             FlowGraph* right,
+             JoinNode* merge);
+
+  // Concatenate a forward loop (e.g., while or for loop) flow-graph to this
+  // one.  Control is split by the condition and merged back from the back
+  // edge at end of the body to the beginning of the condition.  The single
+  // (free) exit of the result graph is the right (false) arm of the branch
+  // node.
+  void Loop(JoinNode* merge,
+            FlowGraph* condition,
+            BranchNode* branch,
+            FlowGraph* body);
+
+#ifdef DEBUG
+  void PrintText(FunctionLiteral* fun, ZoneList<Node*>* postorder);
+#endif
+
+ private:
+  FlowGraph() : entry_(NULL), exit_(NULL) {}
+
+  Node* entry_;
+  Node* exit_;
+};
+
+
+// Construct a flow graph from a function literal.  Build pre- and postorder
+// traversal orders as a byproduct.
+class FlowGraphBuilder: public AstVisitor {
+ public:
+  explicit FlowGraphBuilder(int variable_count)
+      : graph_(FlowGraph::Empty()),
+        global_exit_(NULL),
+        preorder_(4),
+        postorder_(4),
+        variable_count_(variable_count),
+        body_definitions_(4) {
+  }
+
+  void Build(FunctionLiteral* lit);
+
+  FlowGraph* graph() { return &graph_; }
+  ZoneList<Node*>* preorder() { return &preorder_; }
+  ZoneList<Node*>* postorder() { return &postorder_; }
+  ZoneList<Expression*>* body_definitions() { return &body_definitions_; }
+
+ private:
+  ExitNode* global_exit() { return global_exit_; }
+
+  // Helpers to allow tranforming the ast during flow graph construction.
+  void VisitStatements(ZoneList<Statement*>* stmts);
+  Statement* ProcessStatement(Statement* stmt);
+
+  // AST node visit functions.
+#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
+  AST_NODE_LIST(DECLARE_VISIT)
+#undef DECLARE_VISIT
+
+  FlowGraph graph_;
+  ExitNode* global_exit_;
+  ZoneList<Node*> preorder_;
+  ZoneList<Node*> postorder_;
+
+  // The flow graph builder collects a list of explicit definitions
+  // (assignments and count operations) to stack-allocated variables to use
+  // for reaching definitions analysis.  It does not count the implicit
+  // definition at function entry.  AST node numbers in the AST are used to
+  // refer into this list.
+  int variable_count_;
+  ZoneList<Expression*> body_definitions_;
+
+  DISALLOW_COPY_AND_ASSIGN(FlowGraphBuilder);
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_FLOW_GRAPH_H_
index f8a679b..d4c593f 100644 (file)
@@ -541,7 +541,7 @@ int GetScriptLineNumberSafe(Handle<Script> script, int code_pos) {
 
 
 void CustomArguments::IterateInstance(ObjectVisitor* v) {
-  v->VisitPointers(values_, values_ + 4);
+  v->VisitPointers(values_, values_ + ARRAY_SIZE(values_));
 }
 
 
index a9754ce..1f1599a 100644 (file)
@@ -2663,7 +2663,7 @@ Object* Heap::CopyJSObject(JSObject* source) {
   FixedArray* elements = FixedArray::cast(source->elements());
   FixedArray* properties = FixedArray::cast(source->properties());
   // Update elements if necessary.
-  if (elements->length()> 0) {
+  if (elements->length() > 0) {
     Object* elem = CopyFixedArray(elements);
     if (elem->IsFailure()) return elem;
     JSObject::cast(clone)->set_elements(FixedArray::cast(elem));
index d37641c..2a0de23 100644 (file)
@@ -938,6 +938,8 @@ class Heap : public AllStatic {
 
   static void RecordStats(HeapStats* stats);
 
+  static int MaxObjectSizeInNewSpace() { return kMaxObjectSizeInNewSpace; }
+
  private:
   static int reserved_semispace_size_;
   static int max_semispace_size_;
index 20b6463..200e3ef 100644 (file)
@@ -7424,10 +7424,8 @@ void CodeGenerator::Int32BinaryOperation(BinaryOperation* node) {
   }
 }
 
-void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
-  Comment cmnt(masm_, "[ BinaryOperation");
-  Token::Value op = node->op();
 
+void CodeGenerator::GenerateLogicalBooleanOperation(BinaryOperation* node) {
   // According to ECMA-262 section 11.11, page 58, the binary logical
   // operators must yield the result of one of the two expressions
   // before any ToBoolean() conversions. This means that the value
@@ -7437,7 +7435,7 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
   // control flow), we force the right hand side to do the same. This
   // is necessary because we assume that if we get control flow on the
   // last path out of an expression we got it on all paths.
-  if (op == Token::AND) {
+  if (node->op() == Token::AND) {
     ASSERT(!in_safe_int32_mode());
     JumpTarget is_true;
     ControlDestination dest(&is_true, destination()->false_target(), true);
@@ -7501,7 +7499,8 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
       exit.Bind();
     }
 
-  } else if (op == Token::OR) {
+  } else {
+    ASSERT(node->op() == Token::OR);
     ASSERT(!in_safe_int32_mode());
     JumpTarget is_false;
     ControlDestination dest(destination()->true_target(), &is_false, false);
@@ -7563,7 +7562,15 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
       // Exit (always with a materialized value).
       exit.Bind();
     }
+  }
+}
+
+
+void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
+  Comment cmnt(masm_, "[ BinaryOperation");
 
+  if (node->op() == Token::AND || node->op() == Token::OR) {
+    GenerateLogicalBooleanOperation(node);
   } else if (in_safe_int32_mode()) {
     Visit(node->left());
     Visit(node->right());
index ca4a44b..9fcc466 100644 (file)
@@ -489,6 +489,9 @@ class CodeGenerator: public AstVisitor {
   // control destination.
   void ToBoolean(ControlDestination* destination);
 
+  // Generate code that computes a shortcutting logical operation.
+  void GenerateLogicalBooleanOperation(BinaryOperation* node);
+
   void GenericBinaryOperation(
       Token::Value op,
       StaticType* type,
index 8d6c346..cf521a2 100644 (file)
@@ -73,11 +73,10 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
   // Check for the absence of an interceptor.
   // Load the map into r0.
   __ mov(r0, FieldOperand(receiver, JSObject::kMapOffset));
-  // Test the has_named_interceptor bit in the map.
-  __ test(FieldOperand(r0, Map::kInstanceAttributesOffset),
-          Immediate(1 << (Map::kHasNamedInterceptor + (3 * 8))));
 
-  // Jump to miss if the interceptor bit is set.
+  // Bail out if the receiver has a named interceptor.
+  __ test(FieldOperand(r0, Map::kBitFieldOffset),
+          Immediate(1 << Map::kHasNamedInterceptor));
   __ j(not_zero, miss_label, not_taken);
 
   // Bail out if we have a JS global proxy object.
@@ -202,17 +201,10 @@ static void GenerateNumberDictionaryLoad(MacroAssembler* masm,
   __ xor_(r0, Operand(r1));
 
   // Compute capacity mask.
-  const int kCapacityOffset =
-      NumberDictionary::kHeaderSize +
-      NumberDictionary::kCapacityIndex * kPointerSize;
-  __ mov(r1, FieldOperand(elements, kCapacityOffset));
+  __ mov(r1, FieldOperand(elements, NumberDictionary::kCapacityOffset));
   __ shr(r1, kSmiTagSize);  // convert smi to int
   __ dec(r1);
 
-  const int kElementsStartOffset =
-      NumberDictionary::kHeaderSize +
-      NumberDictionary::kElementsStartIndex * kPointerSize;
-
   // Generate an unrolled loop that performs a few probes before giving up.
   const int kProbes = 4;
   for (int i = 0; i < kProbes; i++) {
@@ -232,7 +224,7 @@ static void GenerateNumberDictionaryLoad(MacroAssembler* masm,
     __ cmp(key, FieldOperand(elements,
                              r2,
                              times_pointer_size,
-                             kElementsStartOffset));
+                             NumberDictionary::kElementsStartOffset));
     if (i != (kProbes - 1)) {
       __ j(equal, &done, taken);
     } else {
@@ -242,14 +234,16 @@ static void GenerateNumberDictionaryLoad(MacroAssembler* masm,
 
   __ bind(&done);
   // Check that the value is a normal propety.
-  const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
+  const int kDetailsOffset =
+      NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
   ASSERT_EQ(NORMAL, 0);
   __ test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
           Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize));
   __ j(not_zero, miss);
 
   // Get the value at the masked, scaled index.
-  const int kValueOffset = kElementsStartOffset + kPointerSize;
+  const int kValueOffset =
+      NumberDictionary::kElementsStartOffset + kPointerSize;
   __ mov(key, FieldOperand(elements, r2, times_pointer_size, kValueOffset));
 }
 
index e554a31..315600b 100644 (file)
@@ -276,14 +276,15 @@ static void PushInterceptorArguments(MacroAssembler* masm,
                                      Register holder,
                                      Register name,
                                      JSObject* holder_obj) {
-  __ push(receiver);
-  __ push(holder);
   __ push(name);
   InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
   ASSERT(!Heap::InNewSpace(interceptor));
-  __ mov(receiver, Immediate(Handle<Object>(interceptor)));
+  Register scratch = name;
+  __ mov(scratch, Immediate(Handle<Object>(interceptor)));
+  __ push(scratch);
   __ push(receiver);
-  __ push(FieldOperand(receiver, InterceptorInfo::kDataOffset));
+  __ push(holder);
+  __ push(FieldOperand(scratch, InterceptorInfo::kDataOffset));
 }
 
 
@@ -1045,17 +1046,16 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
   __ push(receiver);  // receiver
   __ push(reg);  // holder
   __ mov(other, Immediate(callback_handle));
-  __ push(other);
   __ push(FieldOperand(other, AccessorInfo::kDataOffset));  // data
   __ push(name_reg);  // name
   // Save a pointer to where we pushed the arguments pointer.
-  // This will be passed as the const Arguments& to the C++ callback.
+  // This will be passed as the const AccessorInfo& to the C++ callback.
   __ mov(eax, esp);
-  __ add(Operand(eax), Immediate(5 * kPointerSize));
+  __ add(Operand(eax), Immediate(4 * kPointerSize));
   __ mov(ebx, esp);
 
   // Do call through the api.
-  ASSERT_EQ(6, ApiGetterEntryStub::kStackSpace);
+  ASSERT_EQ(5, ApiGetterEntryStub::kStackSpace);
   Address getter_address = v8::ToCData<Address>(callback->getter());
   ApiFunction fun(getter_address);
   ApiGetterEntryStub stub(callback_handle, &fun);
@@ -1251,8 +1251,7 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object,
     __ j(not_equal, &miss);
 
     if (argc == 1) {  // Otherwise fall through to call builtin.
-      Label call_builtin, exit, with_rset_update,
-            attempt_to_grow_elements, finish_push;
+      Label call_builtin, exit, with_rset_update, attempt_to_grow_elements;
 
       // Get the array's length into eax and calculate new length.
       __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
@@ -1278,8 +1277,6 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object,
       __ mov(ecx, Operand(esp, argc * kPointerSize));
       __ mov(Operand(edx, 0), ecx);
 
-      __ bind(&finish_push);
-
       // Check if value is a smi.
       __ test(ecx, Immediate(kSmiTagMask));
       __ j(not_zero, &with_rset_update);
@@ -1318,10 +1315,13 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object,
       // We fit and could grow elements.
       __ mov(Operand::StaticVariable(new_space_allocation_top), ecx);
       __ mov(ecx, Operand(esp, argc * kPointerSize));
+
+      // Push the argument...
       __ mov(Operand(edx, 0), ecx);
+      // ... and fill the rest with holes.
       for (int i = 1; i < kAllocationDelta; i++) {
         __ mov(Operand(edx, i * kPointerSize),
-               Immediate(Factory::undefined_value()));
+               Immediate(Factory::the_hole_value()));
       }
 
       // Restore receiver to edx as finish sequence assumes it's here.
@@ -1332,7 +1332,8 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object,
              Immediate(kAllocationDelta));
       __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
 
-      __ jmp(&finish_push);
+      // Elements are in new space, so no remembered set updates are necessary.
+      __ ret((argc + 1) * kPointerSize);
 
       __ bind(&call_builtin);
     }
index 8aa3937..6df8f50 100644 (file)
 namespace v8 {
 namespace internal {
 
-#ifdef ENABLE_OPROFILE_AGENT
-op_agent_t OProfileAgent::handle_ = NULL;
-#endif
-
 
 bool OProfileAgent::Initialize() {
 #ifdef ENABLE_OPROFILE_AGENT
@@ -70,47 +66,43 @@ void OProfileAgent::TearDown() {
 }
 
 
+#ifdef ENABLE_OPROFILE_AGENT
+op_agent_t OProfileAgent::handle_ = NULL;
+
+
 void OProfileAgent::CreateNativeCodeRegion(const char* name,
     const void* ptr, unsigned int size) {
-#ifdef ENABLE_OPROFILE_AGENT
-  if (handle_ == NULL) return;
   op_write_native_code(handle_, name, (uint64_t)ptr, ptr, size);
-#endif
 }
 
 
 void OProfileAgent::CreateNativeCodeRegion(String* name,
     const void* ptr, unsigned int size) {
-#ifdef ENABLE_OPROFILE_AGENT
-  if (handle_ != NULL) {
-    const char* func_name;
-    SmartPointer<char> str =
-        name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
-    func_name = name->length() > 0 ? *str : "<anonymous>";
-    CreateNativeCodeRegion(func_name, ptr, size);
-  }
-#endif
+  const char* func_name;
+  SmartPointer<char> str =
+      name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+  func_name = name->length() > 0 ? *str : "<anonymous>";
+  CreateNativeCodeRegion(func_name, ptr, size);
 }
 
 
 void OProfileAgent::CreateNativeCodeRegion(String* name, String* source,
     int line_num, const void* ptr, unsigned int size) {
-#ifdef ENABLE_OPROFILE_AGENT
-  if (handle_ != NULL) {
-    Vector<char> buf = Vector<char>::New(OProfileAgent::kFormattingBufSize);
-    const char* func_name;
-    SmartPointer<char> str =
-        name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
-    func_name = name->length() > 0 ? *str : "<anonymous>";
-    SmartPointer<char> source_str =
-        source->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
-    if (v8::internal::OS::SNPrintF(buf, "%s %s:%d",
-                                   func_name, *source_str, line_num) != -1) {
-      CreateNativeCodeRegion(buf.start(), ptr, size);
-    } else {
-      CreateNativeCodeRegion("<script/func name too long>", ptr, size);
-    }
+  Vector<char> buf = Vector<char>::New(OProfileAgent::kFormattingBufSize);
+  const char* func_name;
+  SmartPointer<char> str =
+      name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+  func_name = name->length() > 0 ? *str : "<anonymous>";
+  SmartPointer<char> source_str =
+      source->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+  if (v8::internal::OS::SNPrintF(buf, "%s %s:%d",
+                                 func_name, *source_str, line_num) != -1) {
+    CreateNativeCodeRegion(buf.start(), ptr, size);
+  } else {
+    CreateNativeCodeRegion("<script/func name too long>", ptr, size);
   }
-#endif
 }
-} }
+
+#endif  // ENABLE_OPROFILE_AGENT
+
+} }  // namespace v8::internal
index 4c299bf..4c50f0f 100644 (file)
 // system headers (they have __uint64_t), but is defined
 // in V8's headers.
 #include <opagent.h>  // NOLINT
+
+#define OPROFILE(Call)                             \
+  do {                                             \
+    if (v8::internal::OProfileAgent::is_enabled()) \
+      v8::internal::OProfileAgent::Call;           \
+  } while (false)
+#else
+#define OPROFILE(Call) ((void) 0)
 #endif
 
 namespace v8 {
@@ -46,13 +54,13 @@ class OProfileAgent {
  public:
   static bool Initialize();
   static void TearDown();
+#ifdef ENABLE_OPROFILE_AGENT
   static void CreateNativeCodeRegion(const char* name,
                                      const void* ptr, unsigned int size);
   static void CreateNativeCodeRegion(String* name,
                                      const void* ptr, unsigned int size);
   static void CreateNativeCodeRegion(String* name, String* source, int line_num,
                                      const void* ptr, unsigned int size);
-#ifdef ENABLE_OPROFILE_AGENT
   static bool is_enabled() { return handle_ != NULL; }
 
  private:
index f124cf1..76028e6 100644 (file)
@@ -505,7 +505,6 @@ class Socket {
 };
 
 
-#ifdef ENABLE_LOGGING_AND_PROFILING
 // ----------------------------------------------------------------------------
 // Sampler
 //
@@ -533,6 +532,7 @@ class TickSample {
   int frames_count;  // Number of captured frames.
 };
 
+#ifdef ENABLE_LOGGING_AND_PROFILING
 class Sampler {
  public:
   // Initialize sampler.
index c942d9d..ce587bc 100644 (file)
@@ -782,6 +782,10 @@ Object* StoreCallbackProperty(Arguments args) {
   return *value;
 }
 
+
+static const int kAccessorInfoOffsetInInterceptorArgs = 2;
+
+
 /**
  * Attempts to load a property with an interceptor (which must be present),
  * but doesn't search the prototype chain.
@@ -790,11 +794,12 @@ Object* StoreCallbackProperty(Arguments args) {
  * provide any value for the given name.
  */
 Object* LoadPropertyWithInterceptorOnly(Arguments args) {
-  JSObject* receiver_handle = JSObject::cast(args[0]);
-  JSObject* holder_handle = JSObject::cast(args[1]);
-  Handle<String> name_handle = args.at<String>(2);
-  Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(3);
-  Object* data_handle = args[4];
+  Handle<String> name_handle = args.at<String>(0);
+  Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(1);
+  ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
+  ASSERT(args[2]->IsJSObject());  // Receiver.
+  ASSERT(args[3]->IsJSObject());  // Holder.
+  ASSERT(args.length() == 5);  // Last arg is data object.
 
   Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
   v8::NamedPropertyGetter getter =
@@ -803,8 +808,8 @@ Object* LoadPropertyWithInterceptorOnly(Arguments args) {
 
   {
     // Use the interceptor getter.
-    CustomArguments args(data_handle, receiver_handle, holder_handle);
-    v8::AccessorInfo info(args.end());
+    v8::AccessorInfo info(args.arguments() -
+                          kAccessorInfoOffsetInInterceptorArgs);
     HandleScope scope;
     v8::Handle<v8::Value> r;
     {
@@ -842,11 +847,12 @@ static Object* ThrowReferenceError(String* name) {
 
 static Object* LoadWithInterceptor(Arguments* args,
                                    PropertyAttributes* attrs) {
-  Handle<JSObject> receiver_handle = args->at<JSObject>(0);
-  Handle<JSObject> holder_handle = args->at<JSObject>(1);
-  Handle<String> name_handle = args->at<String>(2);
-  Handle<InterceptorInfo> interceptor_info = args->at<InterceptorInfo>(3);
-  Handle<Object> data_handle = args->at<Object>(4);
+  Handle<String> name_handle = args->at<String>(0);
+  Handle<InterceptorInfo> interceptor_info = args->at<InterceptorInfo>(1);
+  ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
+  Handle<JSObject> receiver_handle = args->at<JSObject>(2);
+  Handle<JSObject> holder_handle = args->at<JSObject>(3);
+  ASSERT(args->length() == 5);  // Last arg is data object.
 
   Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
   v8::NamedPropertyGetter getter =
@@ -855,8 +861,8 @@ static Object* LoadWithInterceptor(Arguments* args,
 
   {
     // Use the interceptor getter.
-    CustomArguments args(*data_handle, *receiver_handle, *holder_handle);
-    v8::AccessorInfo info(args.end());
+    v8::AccessorInfo info(args->arguments() -
+                          kAccessorInfoOffsetInInterceptorArgs);
     HandleScope scope;
     v8::Handle<v8::Value> r;
     {
@@ -891,7 +897,7 @@ Object* LoadPropertyWithInterceptorForLoad(Arguments args) {
 
   // If the property is present, return it.
   if (attr != ABSENT) return result;
-  return ThrowReferenceError(String::cast(args[2]));
+  return ThrowReferenceError(String::cast(args[0]));
 }
 
 
index 89cc5ef..8ff1f9b 100644 (file)
@@ -581,11 +581,12 @@ static inline void MemsetPointer(T** dest, T* value, int counter) {
 #endif
 
 #if defined(__GNUC__) && defined(STOS)
-  asm("cld;"
+  asm volatile(
+      "cld;"
       "rep ; " STOS
-      : /* no output */
-      : "c" (counter), "a" (value), "D" (dest)
-      : /* no clobbered list as all inputs are considered clobbered */);
+      : "+&c" (counter), "+&D" (dest)
+      : "a" (value)
+      : "memory", "cc");
 #else
   for (int i = 0; i < counter; i++) {
     dest[i] = value;
index f7116d1..e3d0887 100644 (file)
@@ -34,8 +34,8 @@
 // cannot be changed without changing the SCons build script.
 #define MAJOR_VERSION     2
 #define MINOR_VERSION     1
-#define BUILD_NUMBER      9
-#define PATCH_LEVEL       1
+#define BUILD_NUMBER      10
+#define PATCH_LEVEL       0
 #define CANDIDATE_VERSION false
 
 // Define SONAME to have the SCons build the put a specific SONAME into the
index 108384c..dd8015f 100644 (file)
@@ -3281,13 +3281,7 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
 }
 
 
-void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
-  // TODO(X64): This code was copied verbatim from codegen-ia32.
-  //     Either find a reason to change it or move it to a shared location.
-
-  Comment cmnt(masm_, "[ BinaryOperation");
-  Token::Value op = node->op();
-
+void CodeGenerator::GenerateLogicalBooleanOperation(BinaryOperation* node) {
   // According to ECMA-262 section 11.11, page 58, the binary logical
   // operators must yield the result of one of the two expressions
   // before any ToBoolean() conversions. This means that the value
@@ -3297,7 +3291,7 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
   // control flow), we force the right hand side to do the same. This
   // is necessary because we assume that if we get control flow on the
   // last path out of an expression we got it on all paths.
-  if (op == Token::AND) {
+  if (node->op() == Token::AND) {
     JumpTarget is_true;
     ControlDestination dest(&is_true, destination()->false_target(), true);
     LoadCondition(node->left(), &dest, false);
@@ -3360,7 +3354,8 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
       exit.Bind();
     }
 
-  } else if (op == Token::OR) {
+  } else {
+    ASSERT(node->op() == Token::OR);
     JumpTarget is_false;
     ControlDestination dest(destination()->true_target(), &is_false, false);
     LoadCondition(node->left(), &dest, false);
@@ -3421,7 +3416,14 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
       // Exit (always with a materialized value).
       exit.Bind();
     }
+  }
+}
+
+void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
+  Comment cmnt(masm_, "[ BinaryOperation");
 
+  if (node->op() == Token::AND || node->op() == Token::OR) {
+    GenerateLogicalBooleanOperation(node);
   } else {
     // NOTE: The code below assumes that the slow cases (calls to runtime)
     // never return a constant/immutable object.
index 3f33918..8eea479 100644 (file)
@@ -454,6 +454,9 @@ class CodeGenerator: public AstVisitor {
   // control destination.
   void ToBoolean(ControlDestination* destination);
 
+  // Generate code that computes a shortcutting logical operation.
+  void GenerateLogicalBooleanOperation(BinaryOperation* node);
+
   void GenericBinaryOperation(
       Token::Value op,
       StaticType* type,
index 77043ce..7212c05 100644 (file)
@@ -72,11 +72,10 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
   // Check for the absence of an interceptor.
   // Load the map into r0.
   __ movq(r0, FieldOperand(r1, JSObject::kMapOffset));
-  // Test the has_named_interceptor bit in the map.
-  __ testl(FieldOperand(r0, Map::kInstanceAttributesOffset),
-          Immediate(1 << (Map::kHasNamedInterceptor + (3 * 8))));
 
-  // Jump to miss if the interceptor bit is set.
+  // Bail out if the receiver has a named interceptor.
+  __ testl(FieldOperand(r0, Map::kBitFieldOffset),
+           Immediate(1 << Map::kHasNamedInterceptor));
   __ j(not_zero, miss_label);
 
   // Bail out if we have a JS global proxy object.
@@ -201,17 +200,10 @@ static void GenerateNumberDictionaryLoad(MacroAssembler* masm,
   __ xorl(r0, r1);
 
   // Compute capacity mask.
-  const int kCapacityOffset =
-      StringDictionary::kHeaderSize +
-      StringDictionary::kCapacityIndex * kPointerSize;
-  __ movq(r1, FieldOperand(elements, kCapacityOffset));
+  __ movq(r1, FieldOperand(elements, NumberDictionary::kCapacityOffset));
   __ SmiToInteger32(r1, r1);
   __ decl(r1);
 
-  const int kElementsStartOffset =
-      NumberDictionary::kHeaderSize +
-      NumberDictionary::kElementsStartIndex * kPointerSize;
-
   // Generate an unrolled loop that performs a few probes before giving up.
   const int kProbes = 4;
   for (int i = 0; i < kProbes; i++) {
@@ -231,7 +223,7 @@ static void GenerateNumberDictionaryLoad(MacroAssembler* masm,
     __ cmpq(key, FieldOperand(elements,
                               r2,
                               times_pointer_size,
-                              kElementsStartOffset));
+                              NumberDictionary::kElementsStartOffset));
     if (i != (kProbes - 1)) {
       __ j(equal, &done);
     } else {
@@ -241,14 +233,16 @@ static void GenerateNumberDictionaryLoad(MacroAssembler* masm,
 
   __ bind(&done);
   // Check that the value is a normal propety.
-  const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
+  const int kDetailsOffset =
+      NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
   ASSERT_EQ(NORMAL, 0);
   __ Test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
           Smi::FromInt(PropertyDetails::TypeField::mask()));
   __ j(not_zero, miss);
 
   // Get the value at the masked, scaled index.
-  const int kValueOffset = kElementsStartOffset + kPointerSize;
+  const int kValueOffset =
+      NumberDictionary::kElementsStartOffset + kPointerSize;
   __ movq(r0, FieldOperand(elements, r2, times_pointer_size, kValueOffset));
 }
 
@@ -1404,7 +1398,7 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) {
 
   // Check for non-global object that requires access check.
   __ testl(FieldOperand(rbx, Map::kBitFieldOffset),
-          Immediate(1 << Map::kIsAccessCheckNeeded));
+           Immediate(1 << Map::kIsAccessCheckNeeded));
   __ j(not_zero, &miss);
 
   // Search the dictionary placing the result in rax.
index aa620fc..03b21a5 100644 (file)
@@ -138,14 +138,13 @@ static void PushInterceptorArguments(MacroAssembler* masm,
                                      Register holder,
                                      Register name,
                                      JSObject* holder_obj) {
-  __ push(receiver);
-  __ push(holder);
   __ push(name);
   InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
   ASSERT(!Heap::InNewSpace(interceptor));
-  __ movq(kScratchRegister, Handle<Object>(interceptor),
-          RelocInfo::EMBEDDED_OBJECT);
+  __ Move(kScratchRegister, Handle<Object>(interceptor));
   __ push(kScratchRegister);
+  __ push(receiver);
+  __ push(holder);
   __ push(FieldOperand(kScratchRegister, InterceptorInfo::kDataOffset));
 }
 
index e579143..84fdd68 100644 (file)
@@ -2644,6 +2644,36 @@ THREADED_TEST(NamedInterceptorPropertyRead) {
 }
 
 
+THREADED_TEST(NamedInterceptorDictionaryIC) {
+  v8::HandleScope scope;
+  Local<ObjectTemplate> templ = ObjectTemplate::New();
+  templ->SetNamedPropertyHandler(XPropertyGetter);
+  LocalContext context;
+  // Create an object with a named interceptor.
+  context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
+  Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
+  for (int i = 0; i < 10; i++) {
+    Local<Value> result = script->Run();
+    CHECK_EQ(result, v8_str("x"));
+  }
+  // Create a slow case object and a function accessing a property in
+  // that slow case object (with dictionary probing in generated
+  // code). Then force object with a named interceptor into slow-case,
+  // pass it to the function, and check that the interceptor is called
+  // instead of accessing the local property.
+  Local<Value> result =
+      CompileRun("function get_x(o) { return o.x; };"
+                 "var obj = { x : 42, y : 0 };"
+                 "delete obj.y;"
+                 "for (var i = 0; i < 10; i++) get_x(obj);"
+                 "interceptor_obj.x = 42;"
+                 "interceptor_obj.y = 10;"
+                 "delete interceptor_obj.y;"
+                 "get_x(interceptor_obj)");
+  CHECK_EQ(result, v8_str("x"));
+}
+
+
 static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
                                                const AccessorInfo& info) {
   // Set x on the prototype object and do not handle the get request.
@@ -5974,6 +6004,38 @@ THREADED_TEST(InterceptorLoadICInvalidatedField) {
 }
 
 
+static int interceptor_load_not_handled_calls = 0;
+static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
+                                                   const AccessorInfo& info) {
+  ++interceptor_load_not_handled_calls;
+  return v8::Handle<v8::Value>();
+}
+
+
+// Test how post-interceptor lookups are done in the non-cacheable
+// case: the interceptor should not be invoked during this lookup.
+THREADED_TEST(InterceptorLoadICPostInterceptor) {
+  interceptor_load_not_handled_calls = 0;
+  CheckInterceptorLoadIC(InterceptorLoadNotHandled,
+    "receiver = new Object();"
+    "receiver.__proto__ = o;"
+    "proto = new Object();"
+    "/* Make proto a slow-case object. */"
+    "for (var i = 0; i < 1000; i++) {"
+    "  proto[\"xxxxxxxx\" + i] = [];"
+    "}"
+    "proto.x = 17;"
+    "o.__proto__ = proto;"
+    "var result = 0;"
+    "for (var i = 0; i < 1000; i++) {"
+    "  result += receiver.x;"
+    "}"
+    "result;",
+    17 * 1000);
+  CHECK_EQ(1000, interceptor_load_not_handled_calls);
+}
+
+
 // Test the case when we stored field into
 // a stub, but it got invalidated later on due to override on
 // global object which is between interceptor and fields' holders.
index 35ab46f..abcd426 100644 (file)
@@ -41,6 +41,10 @@ TEST(Octal) {
   CHECK_EQ(7.0, StringToDouble("07", ALLOW_HEX));
   CHECK_EQ(10.0, StringToDouble("010", ALLOW_HEX));
   CHECK_EQ(77.0, StringToDouble("077", ALLOW_HEX));
+
+  const double x = 010000000000;  // Power of 2, no rounding errors.
+  CHECK_EQ(x * x * x * x * x, StringToDouble("01" "0000000000" "0000000000"
+      "0000000000" "0000000000" "0000000000", ALLOW_OCTALS));
 }
 
 
@@ -80,6 +84,8 @@ TEST(MalformedOctal) {
 TEST(TrailingJunk) {
   CHECK_EQ(8.0, StringToDouble("8q", ALLOW_TRAILING_JUNK));
   CHECK_EQ(63.0, StringToDouble("077qqq", ALLOW_OCTALS | ALLOW_TRAILING_JUNK));
+  CHECK_EQ(10.0, StringToDouble("10e", ALLOW_OCTALS | ALLOW_TRAILING_JUNK));
+  CHECK_EQ(10.0, StringToDouble("10e-", ALLOW_OCTALS | ALLOW_TRAILING_JUNK));
 }
 
 
@@ -91,6 +97,87 @@ TEST(NonStrDecimalLiteral) {
   CHECK_EQ(0.0, StringToDouble(" ", NO_FLAGS));
 }
 
+TEST(IntegerStrLiteral) {
+  CHECK_EQ(0.0, StringToDouble("0.0", NO_FLAGS));
+  CHECK_EQ(0.0, StringToDouble("0", NO_FLAGS));
+  CHECK_EQ(0.0, StringToDouble("00", NO_FLAGS));
+  CHECK_EQ(0.0, StringToDouble("000", NO_FLAGS));
+  CHECK_EQ(1.0, StringToDouble("1", NO_FLAGS));
+  CHECK_EQ(-1.0, StringToDouble("-1", NO_FLAGS));
+  CHECK_EQ(-1.0, StringToDouble("  -  1  ", NO_FLAGS));
+  CHECK_EQ(1.0, StringToDouble("  +  1  ", NO_FLAGS));
+
+  CHECK_EQ(0.0, StringToDouble("0e0", ALLOW_HEX | ALLOW_OCTALS));
+  CHECK_EQ(0.0, StringToDouble("0e1", ALLOW_HEX | ALLOW_OCTALS));
+  CHECK_EQ(0.0, StringToDouble("0e-1", ALLOW_HEX | ALLOW_OCTALS));
+  CHECK_EQ(0.0, StringToDouble("0e-100000", ALLOW_HEX | ALLOW_OCTALS));
+  CHECK_EQ(0.0, StringToDouble("0e+100000", ALLOW_HEX | ALLOW_OCTALS));
+  CHECK_EQ(0.0, StringToDouble("0.", ALLOW_HEX | ALLOW_OCTALS));
+}
+
+TEST(LongNumberStr) {
+  CHECK_EQ(1e10, StringToDouble("1" "0000000000", NO_FLAGS));
+  CHECK_EQ(1e20, StringToDouble("1" "0000000000" "0000000000", NO_FLAGS));
+
+  CHECK_EQ(1e60, StringToDouble("1" "0000000000" "0000000000" "0000000000"
+      "0000000000" "0000000000" "0000000000", NO_FLAGS));
+
+  CHECK_EQ(1e-2, StringToDouble("." "0" "1", NO_FLAGS));
+  CHECK_EQ(1e-11, StringToDouble("." "0000000000" "1", NO_FLAGS));
+  CHECK_EQ(1e-21, StringToDouble("." "0000000000" "0000000000" "1", NO_FLAGS));
+
+  CHECK_EQ(1e-61, StringToDouble("." "0000000000" "0000000000" "0000000000"
+      "0000000000" "0000000000" "0000000000" "1", NO_FLAGS));
+
+
+  // x = 24414062505131248.0 and y = 24414062505131252.0 are representable in
+  // double. Check chat z = (x + y) / 2 is rounded to x...
+  CHECK_EQ(24414062505131248.0,
+           StringToDouble("24414062505131250.0", NO_FLAGS));
+
+  // ... and z = (x + y) / 2 + delta is rounded to y.
+  CHECK_EQ(24414062505131252.0,
+           StringToDouble("24414062505131250.000000001", NO_FLAGS));
+}
+
+
+extern "C" double gay_strtod(const char* s00, const char** se);
+
+
+TEST(MaximumSignificantDigits) {
+  char num[] =
+      "4.4501477170144020250819966727949918635852426585926051135169509"
+      "122872622312493126406953054127118942431783801370080830523154578"
+      "251545303238277269592368457430440993619708911874715081505094180"
+      "604803751173783204118519353387964161152051487413083163272520124"
+      "606023105869053620631175265621765214646643181420505164043632222"
+      "668006474326056011713528291579642227455489682133472873831754840"
+      "341397809846934151055619529382191981473003234105366170879223151"
+      "087335413188049110555339027884856781219017754500629806224571029"
+      "581637117459456877330110324211689177656713705497387108207822477"
+      "584250967061891687062782163335299376138075114200886249979505279"
+      "101870966346394401564490729731565935244123171539810221213221201"
+      "847003580761626016356864581135848683152156368691976240370422601"
+      "6998291015625000000000000000000000000000000000e-308";
+
+  CHECK_EQ(gay_strtod(num, NULL), StringToDouble(num, NO_FLAGS));
+
+  // Changes the result of strtod (at least in glibc implementation).
+  num[sizeof(num) - 8] = '1';
+
+  CHECK_EQ(gay_strtod(num, NULL), StringToDouble(num, NO_FLAGS));
+}
+
+
+TEST(ExponentNumberStr) {
+  CHECK_EQ(1e1, StringToDouble("1e1", NO_FLAGS));
+  CHECK_EQ(1e1, StringToDouble("1e+1", NO_FLAGS));
+  CHECK_EQ(1e-1, StringToDouble("1e-1", NO_FLAGS));
+  CHECK_EQ(1e100, StringToDouble("1e+100", NO_FLAGS));
+  CHECK_EQ(1e-100, StringToDouble("1e-100", NO_FLAGS));
+  CHECK_EQ(1e-106, StringToDouble(".000001e-100", NO_FLAGS));
+}
+
 class OneBit1: public BitField<uint32_t, 0, 1> {};
 class OneBit2: public BitField<uint32_t, 7, 1> {};
 class EightBit1: public BitField<uint32_t, 0, 8> {};
index 2b88f0f..bfadd20 100644 (file)
@@ -852,3 +852,115 @@ TEST(LargeObjectSpaceContains) {
   CHECK(Heap::new_space()->Contains(addr));
   CHECK(!Heap::lo_space()->Contains(addr));
 }
+
+
+TEST(EmptyHandleEscapeFrom) {
+  InitializeVM();
+
+  v8::HandleScope scope;
+  Handle<JSObject> runaway;
+
+  {
+      v8::HandleScope nested;
+      Handle<JSObject> empty;
+      runaway = empty.EscapeFrom(&nested);
+  }
+
+  CHECK(runaway.is_null());
+}
+
+
+static int LenFromSize(int size) {
+  return (size - FixedArray::kHeaderSize) / kPointerSize;
+}
+
+
+TEST(Regression39128) {
+  // Test case for crbug.com/39128.
+  InitializeVM();
+
+  // Increase the chance of 'bump-the-pointer' allocation in old space.
+  bool force_compaction = true;
+  Heap::CollectAllGarbage(force_compaction);
+
+  v8::HandleScope scope;
+
+  // The plan: create JSObject which references objects in new space.
+  // Then clone this object (forcing it to go into old space) and check
+  // that only bits pertaining to the object are updated in remembered set.
+
+  // Step 1: prepare a map for the object.  We add 1 inobject property to it.
+  Handle<JSFunction> object_ctor(Top::global_context()->object_function());
+  CHECK(object_ctor->has_initial_map());
+  Handle<Map> object_map(object_ctor->initial_map());
+  // Create a map with single inobject property.
+  Handle<Map> my_map = Factory::CopyMap(object_map, 1);
+  int n_properties = my_map->inobject_properties();
+  CHECK_GT(n_properties, 0);
+
+  int object_size = my_map->instance_size();
+
+  // Step 2: allocate a lot of objects so to almost fill new space: we need
+  // just enough room to allocate JSObject and thus fill the newspace.
+
+  int allocation_amount = Min(FixedArray::kMaxSize,
+                              Heap::MaxObjectSizeInNewSpace());
+  int allocation_len = LenFromSize(allocation_amount);
+  NewSpace* new_space = Heap::new_space();
+  Address* top_addr = new_space->allocation_top_address();
+  Address* limit_addr = new_space->allocation_limit_address();
+  while ((*limit_addr - *top_addr) > allocation_amount) {
+    CHECK(!Heap::always_allocate());
+    Object* array = Heap::AllocateFixedArray(allocation_len);
+    CHECK(!array->IsFailure());
+    CHECK(new_space->Contains(array));
+  }
+
+  // Step 3: now allocate fixed array and JSObject to fill the whole new space.
+  int to_fill = *limit_addr - *top_addr - object_size;
+  int fixed_array_len = LenFromSize(to_fill);
+  CHECK(fixed_array_len < FixedArray::kMaxLength);
+
+  CHECK(!Heap::always_allocate());
+  Object* array = Heap::AllocateFixedArray(fixed_array_len);
+  CHECK(!array->IsFailure());
+  CHECK(new_space->Contains(array));
+
+  Object* object = Heap::AllocateJSObjectFromMap(*my_map);
+  CHECK(!object->IsFailure());
+  CHECK(new_space->Contains(object));
+  JSObject* jsobject = JSObject::cast(object);
+  CHECK_EQ(0, jsobject->elements()->length());
+  CHECK_EQ(0, jsobject->properties()->length());
+  // Create a reference to object in new space in jsobject.
+  jsobject->FastPropertyAtPut(-1, array);
+
+  CHECK_EQ(0L, (*limit_addr - *top_addr));
+
+  // Step 4: clone jsobject, but force always allocate first to create a clone
+  // in old pointer space.
+  Address old_pointer_space_top = Heap::old_pointer_space()->top();
+  AlwaysAllocateScope aa_scope;
+  Object* clone_obj = Heap::CopyJSObject(jsobject);
+  CHECK(!object->IsFailure());
+  JSObject* clone = JSObject::cast(clone_obj);
+  if (clone->address() != old_pointer_space_top) {
+    // Alas, got allocated from free list, we cannot do checks.
+    return;
+  }
+  CHECK(Heap::old_pointer_space()->Contains(clone->address()));
+
+  // Step 5: verify validity of remembered set.
+  Address clone_addr = clone->address();
+  Page* page = Page::FromAddress(clone_addr);
+  // Check that remembered set tracks a reference from inobject property 1.
+  CHECK(page->IsRSetSet(clone_addr, object_size - kPointerSize));
+  // Probe several addresses after the object.
+  for (int i = 0; i < 7; i++) {
+    int offset = object_size + i * kPointerSize;
+    if (clone_addr + offset >= page->ObjectAreaEnd()) {
+      break;
+    }
+    CHECK(!page->IsRSetSet(clone_addr, offset));
+  }
+}
index 12a3716..f7a9c2d 100644 (file)
@@ -29,6 +29,19 @@ function toNumber(val) {
   return Number(val);
 }
 
+function repeat(s, num) {
+  var result = '';
+  while (num > 0) {
+    if ((num & 1) != 0) result += s;
+    s += s;
+    num >>= 1;
+  }
+
+  return result;
+}
+
+assertEquals('0000000000', repeat('0', 10));
+
 // assertEquals(, toNumber());
 
 
@@ -61,6 +74,7 @@ assertEquals(Infinity,  toNumber("+Infinity "), "+Infinity");
 assertEquals(0,  toNumber("0"));
 assertEquals(0,  toNumber("+0"));
 assertEquals(-0, toNumber("-0"));
+assertEquals(-Infinity, 1 / toNumber("-0"));
 
 assertEquals(1,  toNumber("1"));
 assertEquals(1,  toNumber("+1"));
@@ -130,11 +144,16 @@ assertEquals(15, toNumber("0Xf"));
 assertEquals(15, toNumber("0XF"));
 
 assertEquals(0,  toNumber("0x000"));
+assertEquals(-Infinity,  1 / toNumber("-0x000"));
+assertEquals(0,  toNumber("0x000" + repeat('0', 1000)));
 assertEquals(9,  toNumber("0x009"));
 assertEquals(10, toNumber("0x00a"));
 assertEquals(10, toNumber("0x00A"));
 assertEquals(15, toNumber("0x00f"));
 assertEquals(15, toNumber("0x00F"));
+assertEquals(Infinity,  toNumber("0x" + repeat('0', 1000) + '1'
+                        + repeat('0', 1000)));
+assertEquals(-Infinity,  toNumber("-0x1" + repeat('0', 1000)));
 
 assertEquals(0, toNumber("00"));
 assertEquals(1, toNumber("01"));
@@ -156,3 +175,6 @@ assertTrue(isNaN(toNumber("0x100 junk")), "0x100 junk");
 assertTrue(isNaN(toNumber("100.0 junk")), "100.0 junk");
 assertTrue(isNaN(toNumber(".1e4 junk")), ".1e4 junk");
 assertTrue(isNaN(toNumber("Infinity junk")), "Infinity junk");
+assertTrue(isNaN(toNumber("1e")), "1e");
+assertTrue(isNaN(toNumber("1e ")), "1e_");
+assertTrue(isNaN(toNumber("1" + repeat('0', 1000) + 'junk')), "1e1000 junk");
index e12946e..d5bb0cb 100644 (file)
         '../../src/flag-definitions.h',
         '../../src/flags.cc',
         '../../src/flags.h',
+        '../../src/flow-graph.cc',
+        '../../src/flow-graph.h',
         '../../src/frame-element.cc',
         '../../src/frame-element.h',
         '../../src/frames-inl.h',
index fe4d863..58bf92f 100644 (file)
                                >
                        </File>
                        <File
+                               RelativePath="..\..\src\flow-graph.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\flow-graph.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\src\frame-element.cc"
                                >
                        </File>
index 2fc4513..d72b303 100644 (file)
                                >
                        </File>
                        <File
+                               RelativePath="..\..\src\flow-graph.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\flow-graph.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\src\frame-element.cc"
                                >
                        </File>
index 0adf24a..6d43023 100644 (file)
                                >
                        </File>
                        <File
+                               RelativePath="..\..\src\flow-graph.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\flow-graph.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\src\frame-element.cc"
                                >
                        </File>