Version 2.1.4

Fixed code cache lookup for keyed IC's (issue http://crbug.com/37853).

Performance improvements on all platforms.



git-svn-id: http://v8.googlecode.com/svn/trunk@4127 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/SConscript b/src/SConscript
index d61da3e..44b6b5b 100755
--- a/src/SConscript
+++ b/src/SConscript
@@ -63,6 +63,7 @@
     full-codegen.cc
     func-name-inferrer.cc
     global-handles.cc
+    grisu3.cc
     handles.cc
     hashmap.cc
     heap-profiler.cc
diff --git a/src/api.cc b/src/api.cc
index 93fce79..af2e7ad 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -3580,6 +3580,7 @@
 
 int V8::GetLogLines(int from_pos, char* dest_buf, int max_size) {
 #ifdef ENABLE_LOGGING_AND_PROFILING
+  ASSERT(max_size >= kMinimumSizeForLogLinesBuffer);
   return i::Logger::GetLogLines(from_pos, dest_buf, max_size);
 #endif
   return 0;
diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc
index 9e59582..3bf3fb8 100644
--- a/src/arm/codegen-arm.cc
+++ b/src/arm/codegen-arm.cc
@@ -2709,18 +2709,20 @@
   Comment cmnt(masm_, "[ ObjectLiteral");
 
   // Load the function of this activation.
-  __ ldr(r2, frame_->Function());
+  __ ldr(r3, frame_->Function());
   // Literal array.
-  __ ldr(r2, FieldMemOperand(r2, JSFunction::kLiteralsOffset));
+  __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
   // Literal index.
-  __ mov(r1, Operand(Smi::FromInt(node->literal_index())));
+  __ mov(r2, Operand(Smi::FromInt(node->literal_index())));
   // Constant properties.
-  __ mov(r0, Operand(node->constant_properties()));
-  frame_->EmitPushMultiple(3, r2.bit() | r1.bit() | r0.bit());
+  __ mov(r1, Operand(node->constant_properties()));
+  // Should the object literal have fast elements?
+  __ mov(r0, Operand(Smi::FromInt(node->fast_elements() ? 1 : 0)));
+  frame_->EmitPushMultiple(4, r3.bit() | r2.bit() | r1.bit() | r0.bit());
   if (node->depth() > 1) {
-    frame_->CallRuntime(Runtime::kCreateObjectLiteral, 3);
+    frame_->CallRuntime(Runtime::kCreateObjectLiteral, 4);
   } else {
-    frame_->CallRuntime(Runtime::kCreateObjectLiteralShallow, 3);
+    frame_->CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
   }
   frame_->EmitPush(r0);  // save the result
   for (int i = 0; i < node->properties()->length(); i++) {
@@ -3597,7 +3599,7 @@
 }
 
 
-void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateArguments(ZoneList<Expression*>* args) {
   VirtualFrame::SpilledScope spilled_scope;
   ASSERT(args->length() == 1);
 
diff --git a/src/arm/codegen-arm.h b/src/arm/codegen-arm.h
index bea98b6..9ade70a 100644
--- a/src/arm/codegen-arm.h
+++ b/src/arm/codegen-arm.h
@@ -197,6 +197,10 @@
 
   static const int kUnknownIntValue = -1;
 
+  // If the name is an inline runtime function call return the number of
+  // expected arguments. Otherwise return -1.
+  static int InlineRuntimeCallArgumentsCount(Handle<String> name);
+
  private:
   // Construction/Destruction
   explicit CodeGenerator(MacroAssembler* masm);
@@ -326,6 +330,7 @@
   struct InlineRuntimeLUT {
     void (CodeGenerator::*method)(ZoneList<Expression*>*);
     const char* name;
+    int nargs;
   };
 
   static InlineRuntimeLUT* FindInlineRuntimeLUT(Handle<String> name);
@@ -360,7 +365,7 @@
 
   // Support for arguments.length and arguments[?].
   void GenerateArgumentsLength(ZoneList<Expression*>* args);
-  void GenerateArgumentsAccess(ZoneList<Expression*>* args);
+  void GenerateArguments(ZoneList<Expression*>* args);
 
   // Support for accessing the class and value fields of an object.
   void GenerateClassOf(ZoneList<Expression*>* args);
@@ -396,14 +401,10 @@
   // Fast support for number to string.
   void GenerateNumberToString(ZoneList<Expression*>* args);
 
-  // Fast support for Math.pow().
+  // Fast call to math functions.
   void GenerateMathPow(ZoneList<Expression*>* args);
-
-  // Fast call to sine function.
   void GenerateMathSin(ZoneList<Expression*>* args);
   void GenerateMathCos(ZoneList<Expression*>* args);
-
-  // Fast support for Math.pow().
   void GenerateMathSqrt(ZoneList<Expression*>* args);
 
   // Simple condition analysis.
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index 230818f..a70cf44 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -783,15 +783,16 @@
 
 void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
   Comment cmnt(masm_, "[ ObjectLiteral");
-  __ ldr(r2, MemOperand(fp,  JavaScriptFrameConstants::kFunctionOffset));
-  __ ldr(r2, FieldMemOperand(r2, JSFunction::kLiteralsOffset));
-  __ mov(r1, Operand(Smi::FromInt(expr->literal_index())));
-  __ mov(r0, Operand(expr->constant_properties()));
-  __ stm(db_w, sp, r2.bit() | r1.bit() | r0.bit());
+  __ ldr(r3, MemOperand(fp,  JavaScriptFrameConstants::kFunctionOffset));
+  __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
+  __ mov(r2, Operand(Smi::FromInt(expr->literal_index())));
+  __ mov(r1, Operand(expr->constant_properties()));
+  __ mov(r0, Operand(Smi::FromInt(expr->fast_elements() ? 1 : 0)));
+  __ stm(db_w, sp, r3.bit() | r2.bit() | r1.bit() | r0.bit());
   if (expr->depth() > 1) {
-    __ CallRuntime(Runtime::kCreateObjectLiteral, 3);
+    __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
   } else {
-    __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 3);
+    __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
   }
 
   // If result_saved is true the result is on top of the stack.  If
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index 36bebdf..bc779eb 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -280,9 +280,9 @@
   // Clobber all input registers when running with the debug-code flag
   // turned on to provoke errors.
   if (FLAG_debug_code) {
-    mov(object, Operand(bit_cast<int32_t>(kZapValue)));
-    mov(offset, Operand(bit_cast<int32_t>(kZapValue)));
-    mov(scratch, Operand(bit_cast<int32_t>(kZapValue)));
+    mov(object, Operand(BitCast<int32_t>(kZapValue)));
+    mov(offset, Operand(BitCast<int32_t>(kZapValue)));
+    mov(scratch, Operand(BitCast<int32_t>(kZapValue)));
   }
 }
 
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index 5d5b2a5..abf2f64 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -815,6 +815,104 @@
 }
 
 
+Object* CallStubCompiler::CompileArrayPushCall(Object* object,
+                                               JSObject* holder,
+                                               JSFunction* function,
+                                               String* name,
+                                               CheckType check) {
+  // ----------- S t a t e -------------
+  //  -- r2    : name
+  //  -- lr    : return address
+  // -----------------------------------
+
+  // TODO(639): faster implementation.
+  ASSERT(check == RECEIVER_MAP_CHECK);
+
+  Label miss;
+
+  // Get the receiver from the stack
+  const int argc = arguments().immediate();
+  __ ldr(r1, MemOperand(sp, argc * kPointerSize));
+
+  // Check that the receiver isn't a smi.
+  __ tst(r1, Operand(kSmiTagMask));
+  __ b(eq, &miss);
+
+  // Check that the maps haven't changed.
+  CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
+
+  if (object->IsGlobalObject()) {
+    __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
+    __ str(r3, MemOperand(sp, argc * kPointerSize));
+  }
+
+  __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush),
+                               argc + 1,
+                               1);
+
+  // Handle call cache miss.
+  __ bind(&miss);
+  Handle<Code> ic = ComputeCallMiss(arguments().immediate());
+  __ Jump(ic, RelocInfo::CODE_TARGET);
+
+  // Return the generated code.
+  String* function_name = NULL;
+  if (function->shared()->name()->IsString()) {
+    function_name = String::cast(function->shared()->name());
+  }
+  return GetCode(CONSTANT_FUNCTION, function_name);
+}
+
+
+Object* CallStubCompiler::CompileArrayPopCall(Object* object,
+                                              JSObject* holder,
+                                              JSFunction* function,
+                                              String* name,
+                                              CheckType check) {
+  // ----------- S t a t e -------------
+  //  -- r2    : name
+  //  -- lr    : return address
+  // -----------------------------------
+
+  // TODO(642): faster implementation.
+  ASSERT(check == RECEIVER_MAP_CHECK);
+
+  Label miss;
+
+  // Get the receiver from the stack
+  const int argc = arguments().immediate();
+  __ ldr(r1, MemOperand(sp, argc * kPointerSize));
+
+  // Check that the receiver isn't a smi.
+  __ tst(r1, Operand(kSmiTagMask));
+  __ b(eq, &miss);
+
+  // Check that the maps haven't changed.
+  CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
+
+  if (object->IsGlobalObject()) {
+    __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
+    __ str(r3, MemOperand(sp, argc * kPointerSize));
+  }
+
+  __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop),
+                               argc + 1,
+                               1);
+
+  // Handle call cache miss.
+  __ bind(&miss);
+  Handle<Code> ic = ComputeCallMiss(arguments().immediate());
+  __ Jump(ic, RelocInfo::CODE_TARGET);
+
+  // Return the generated code.
+  String* function_name = NULL;
+  if (function->shared()->name()->IsString()) {
+    function_name = String::cast(function->shared()->name());
+  }
+  return GetCode(CONSTANT_FUNCTION, function_name);
+}
+
+
 Object* CallStubCompiler::CompileCallConstant(Object* object,
                                               JSObject* holder,
                                               JSFunction* function,
@@ -824,6 +922,13 @@
   //  -- r2    : name
   //  -- lr    : return address
   // -----------------------------------
+  SharedFunctionInfo* function_info = function->shared();
+  if (function_info->HasCustomCallGenerator()) {
+    CustomCallGenerator generator =
+        ToCData<CustomCallGenerator>(function_info->function_data());
+    return generator(this, object, holder, function, name, check);
+  }
+
   Label miss;
 
   // Get the receiver from the stack
@@ -916,18 +1021,6 @@
       break;
     }
 
-    case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
-      CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
-      // Make sure object->HasFastElements().
-      // Get the elements array of the object.
-      __ ldr(r3, FieldMemOperand(r1, JSObject::kElementsOffset));
-      // Check that the object is in fast mode (not dictionary).
-      __ ldr(r0, FieldMemOperand(r3, HeapObject::kMapOffset));
-      __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
-      __ cmp(r0, ip);
-      __ b(ne, &miss);
-      break;
-
     default:
       UNREACHABLE();
   }
diff --git a/src/arm/virtual-frame-arm.h b/src/arm/virtual-frame-arm.h
index 6eb0811..7375b31 100644
--- a/src/arm/virtual-frame-arm.h
+++ b/src/arm/virtual-frame-arm.h
@@ -364,6 +364,8 @@
   // the frame.  Nip(k) is equivalent to x = Pop(), Drop(k), Push(x).
   inline void Nip(int num_dropped);
 
+  inline void SetTypeForLocalAt(int index, NumberInfo info);
+
  private:
   static const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;
   static const int kFunctionOffset = JavaScriptFrameConstants::kFunctionOffset;
diff --git a/src/array.js b/src/array.js
index e33c280..95d4ada 100644
--- a/src/array.js
+++ b/src/array.js
@@ -1088,15 +1088,6 @@
   return IS_ARRAY(obj);
 }
 
-// -------------------------------------------------------------------
-
-
-function UpdateFunctionLengths(lengths) {
-  for (var key in lengths) {
-    %FunctionSetLength(this[key], lengths[key]);
-  }
-}
-
 
 // -------------------------------------------------------------------
 function SetupArray() {
@@ -1109,47 +1100,47 @@
     "isArray", ArrayIsArray
   ));
 
+  var specialFunctions = %SpecialArrayFunctions({});
+
+  function getFunction(name, jsBuiltin, len) {
+    var f = jsBuiltin;
+    if (specialFunctions.hasOwnProperty(name)) {
+      f = specialFunctions[name];
+    }
+    if (!IS_UNDEFINED(len)) {
+      %FunctionSetLength(f, len);
+    }
+    return f;
+  }
+
   // Setup non-enumerable functions of the Array.prototype object and
   // set their names.
-  InstallFunctionsOnHiddenPrototype($Array.prototype, DONT_ENUM, $Array(
-    "toString", ArrayToString,
-    "toLocaleString", ArrayToLocaleString,
-    "join", ArrayJoin,
-    "pop", ArrayPop,
-    "push", ArrayPush,
-    "concat", ArrayConcat,
-    "reverse", ArrayReverse,
-    "shift", ArrayShift,
-    "unshift", ArrayUnshift,
-    "slice", ArraySlice,
-    "splice", ArraySplice,
-    "sort", ArraySort,
-    "filter", ArrayFilter,
-    "forEach", ArrayForEach,
-    "some", ArraySome,
-    "every", ArrayEvery,
-    "map", ArrayMap,
-    "indexOf", ArrayIndexOf,
-    "lastIndexOf", ArrayLastIndexOf,
-    "reduce", ArrayReduce,
-    "reduceRight", ArrayReduceRight
-  ));
-    
   // Manipulate the length of some of the functions to meet
   // expectations set by ECMA-262 or Mozilla.
-  UpdateFunctionLengths({
-    ArrayFilter: 1,
-    ArrayForEach: 1,
-    ArraySome: 1,
-    ArrayEvery: 1,
-    ArrayMap: 1,
-    ArrayIndexOf: 1,
-    ArrayLastIndexOf: 1,
-    ArrayPush: 1,
-    ArrayReduce: 1,
-    ArrayReduceRight: 1
-  });
-
+  InstallFunctionsOnHiddenPrototype($Array.prototype, DONT_ENUM, $Array(
+    "toString", getFunction("toString", ArrayToString),
+    "toLocaleString", getFunction("toLocaleString", ArrayToLocaleString),
+    "join", getFunction("join", ArrayJoin),
+    "pop", getFunction("pop", ArrayPop),
+    "push", getFunction("push", ArrayPush, 1),
+    "concat", getFunction("concat", ArrayConcat),
+    "reverse", getFunction("reverse", ArrayReverse),
+    "shift", getFunction("shift", ArrayShift),
+    "unshift", getFunction("unshift", ArrayUnshift, 1),
+    "slice", getFunction("slice", ArraySlice, 2),
+    "splice", getFunction("splice", ArraySplice, 2),
+    "sort", getFunction("sort", ArraySort),
+    "filter", getFunction("filter", ArrayFilter, 1),
+    "forEach", getFunction("forEach", ArrayForEach, 1),
+    "some", getFunction("some", ArraySome, 1),
+    "every", getFunction("every", ArrayEvery, 1),
+    "map", getFunction("map", ArrayMap, 1),
+    "indexOf", getFunction("indexOf", ArrayIndexOf, 1),
+    "lastIndexOf", getFunction("lastIndexOf", ArrayLastIndexOf, 1),
+    "reduce", getFunction("reduce", ArrayReduce, 1),
+    "reduceRight", getFunction("reduceRight", ArrayReduceRight, 1)
+  ));
+    
   %FinishArrayPrototypeSetup($Array.prototype);
 }
 
diff --git a/src/ast.cc b/src/ast.cc
index 062a5c6..339cfa1 100644
--- a/src/ast.cc
+++ b/src/ast.cc
@@ -58,13 +58,27 @@
 // ----------------------------------------------------------------------------
 // Implementation of other node functionality.
 
+Assignment* ExpressionStatement::StatementAsSimpleAssignment() {
+  return (expression()->AsAssignment() != NULL &&
+          !expression()->AsAssignment()->is_compound())
+      ? expression()->AsAssignment()
+      : NULL;
+}
+
+
+CountOperation* ExpressionStatement::StatementAsCountOperation() {
+  return expression()->AsCountOperation();
+}
+
+
 VariableProxy::VariableProxy(Handle<String> name,
                              bool is_this,
                              bool inside_with)
   : name_(name),
     var_(NULL),
     is_this_(is_this),
-    inside_with_(inside_with) {
+    inside_with_(inside_with),
+    is_trivial_(false) {
   // names must be canonicalized for fast equality checks
   ASSERT(name->IsSymbol());
 }
@@ -484,5 +498,96 @@
   }
 }
 
+// IsPrimitive implementation.  IsPrimitive is true if the value of an
+// expression is known at compile-time to be any JS type other than Object
+// (e.g, it is Undefined, Null, Boolean, String, or Number).
+
+// The following expression types are never primitive because they express
+// Object values.
+bool FunctionLiteral::IsPrimitive() { return false; }
+bool FunctionBoilerplateLiteral::IsPrimitive() { return false; }
+bool RegExpLiteral::IsPrimitive() { return false; }
+bool ObjectLiteral::IsPrimitive() { return false; }
+bool ArrayLiteral::IsPrimitive() { return false; }
+bool CatchExtensionObject::IsPrimitive() { return false; }
+bool CallNew::IsPrimitive() { return false; }
+bool ThisFunction::IsPrimitive() { return false; }
+
+
+// The following expression types are not always primitive because we do not
+// have enough information to conclude that they are.
+bool VariableProxy::IsPrimitive() { return false; }
+bool Property::IsPrimitive() { return false; }
+bool Call::IsPrimitive() { return false; }
+bool CallRuntime::IsPrimitive() { return false; }
+
+
+// The value of a conditional is the value of one of the alternatives.  It's
+// always primitive if both alternatives are always primitive.
+bool Conditional::IsPrimitive() {
+  return then_expression()->IsPrimitive() && else_expression()->IsPrimitive();
+}
+
+
+// A literal is primitive when it is not a JSObject.
+bool Literal::IsPrimitive() { return !handle()->IsJSObject(); }
+
+
+// The value of an assignment is the value of its right-hand side.
+bool Assignment::IsPrimitive() {
+  switch (op()) {
+    case Token::INIT_VAR:
+    case Token::INIT_CONST:
+    case Token::ASSIGN:
+      return value()->IsPrimitive();
+
+    default:
+      // {|=, ^=, &=, <<=, >>=, >>>=, +=, -=, *=, /=, %=}
+      // Arithmetic operations are always primitive.  They express Numbers
+      // with the exception of +, which expresses a Number or a String.
+      return true;
+  }
+}
+
+
+// Throw does not express a value, so it's trivially always primitive.
+bool Throw::IsPrimitive() { return true; }
+
+
+// Unary operations always express primitive values.  delete and ! express
+// Booleans, void Undefined, typeof String, +, -, and ~ Numbers.
+bool UnaryOperation::IsPrimitive() { return true; }
+
+
+// Count operations (pre- and post-fix increment and decrement) always
+// express primitive values (Numbers).  See ECMA-262-3, 11.3.1, 11.3.2,
+// 11.4.4, ane 11.4.5.
+bool CountOperation::IsPrimitive() { return true; }
+
+
+// Binary operations depend on the operator.
+bool BinaryOperation::IsPrimitive() {
+  switch (op()) {
+    case Token::COMMA:
+      // Value is the value of the right subexpression.
+      return right()->IsPrimitive();
+
+    case Token::OR:
+    case Token::AND:
+      // Value is the value one of the subexpressions.
+      return left()->IsPrimitive() && right()->IsPrimitive();
+
+    default:
+      // {|, ^, &, <<, >>, >>>, +, -, *, /, %}
+      // Arithmetic operations are always primitive.  They express Numbers
+      // with the exception of +, which expresses a Number or a String.
+      return true;
+  }
+}
+
+
+// Compare operations always express Boolean values.
+bool CompareOperation::IsPrimitive() { return true; }
+
 
 } }  // namespace v8::internal
diff --git a/src/ast.h b/src/ast.h
index 13502dc..0d654b1 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -137,6 +137,7 @@
   virtual BreakableStatement* AsBreakableStatement() { return NULL; }
   virtual IterationStatement* AsIterationStatement() { return NULL; }
   virtual UnaryOperation* AsUnaryOperation() { return NULL; }
+  virtual CountOperation* AsCountOperation() { return NULL; }
   virtual BinaryOperation* AsBinaryOperation() { return NULL; }
   virtual Assignment* AsAssignment() { return NULL; }
   virtual FunctionLiteral* AsFunctionLiteral() { return NULL; }
@@ -161,6 +162,9 @@
   virtual Statement* AsStatement()  { return this; }
   virtual ReturnStatement* AsReturnStatement() { return NULL; }
 
+  virtual Assignment* StatementAsSimpleAssignment() { return NULL; }
+  virtual CountOperation* StatementAsCountOperation() { return NULL; }
+
   bool IsEmpty() { return AsEmptyStatement() != NULL; }
 
   void set_statement_pos(int statement_pos) { statement_pos_ = statement_pos; }
@@ -200,6 +204,8 @@
 
   virtual bool IsValidLeftHandSide() { return false; }
 
+  virtual Variable* AssignedVar() { return NULL; }
+
   // Symbols that cannot be parsed as array indices are considered property
   // names.  We do not treat symbols that can be array indexes as property
   // names because [] for string objects is handled only by keyed ICs.
@@ -214,6 +220,10 @@
   // evaluate out of order.
   virtual bool IsTrivial() { return false; }
 
+  // True if the expression always has one of the non-Object JS types
+  // (Undefined, Null, Boolean, String, or Number).
+  virtual bool IsPrimitive() = 0;
+
   // Mark the expression as being compiled as an expression
   // statement. This is used to transform postfix increments to
   // (faster) prefix increments.
@@ -274,6 +284,12 @@
   virtual bool IsValidLeftHandSide() { return true; }
   virtual void Accept(AstVisitor* v) { UNREACHABLE(); }
   static ValidLeftHandSideSentinel* instance() { return &instance_; }
+
+  virtual bool IsPrimitive() {
+    UNREACHABLE();
+    return false;
+  }
+
  private:
   static ValidLeftHandSideSentinel instance_;
 };
@@ -321,6 +337,16 @@
 
   virtual void Accept(AstVisitor* v);
 
+  virtual Assignment* StatementAsSimpleAssignment() {
+    if (statements_.length() != 1) return NULL;
+    return statements_[0]->StatementAsSimpleAssignment();
+  }
+
+  virtual CountOperation* StatementAsCountOperation() {
+    if (statements_.length() != 1) return NULL;
+    return statements_[0]->StatementAsCountOperation();
+  }
+
   void AddStatement(Statement* statement) { statements_.Add(statement); }
 
   ZoneList<Statement*>* statements() { return &statements_; }
@@ -442,8 +468,8 @@
         init_(NULL),
         cond_(NULL),
         next_(NULL),
-        may_have_function_literal_(true) {
-  }
+        may_have_function_literal_(true),
+        loop_variable_(NULL) {}
 
   void Initialize(Statement* init,
                   Expression* cond,
@@ -464,12 +490,17 @@
     return may_have_function_literal_;
   }
 
+  bool is_fast_smi_loop() { return loop_variable_ != NULL; }
+  Variable* loop_variable() { return loop_variable_; }
+  void set_loop_variable(Variable* var) { loop_variable_ = var; }
+
  private:
   Statement* init_;
   Expression* cond_;
   Statement* next_;
   // True if there is a function literal subexpression in the condition.
   bool may_have_function_literal_;
+  Variable* loop_variable_;
 
   friend class AstOptimizer;
 };
@@ -507,6 +538,9 @@
   // Type testing & conversion.
   virtual ExpressionStatement* AsExpressionStatement() { return this; }
 
+  virtual Assignment* StatementAsSimpleAssignment();
+  virtual CountOperation* StatementAsCountOperation();
+
   void set_expression(Expression* e) { expression_ = e; }
   Expression* expression() { return expression_; }
 
@@ -774,6 +808,7 @@
 
   virtual bool IsLeaf() { return true; }
   virtual bool IsTrivial() { return true; }
+  virtual bool IsPrimitive();
 
   // Identity testers.
   bool IsNull() const { return handle_.is_identical_to(Factory::null_value()); }
@@ -849,24 +884,31 @@
                 ZoneList<Property*>* properties,
                 int literal_index,
                 bool is_simple,
+                bool fast_elements,
                 int depth)
       : MaterializedLiteral(literal_index, is_simple, depth),
         constant_properties_(constant_properties),
-        properties_(properties) {}
+        properties_(properties),
+        fast_elements_(fast_elements) {}
 
   virtual ObjectLiteral* AsObjectLiteral() { return this; }
   virtual void Accept(AstVisitor* v);
 
   virtual bool IsLeaf() { return properties()->is_empty(); }
 
+  virtual bool IsPrimitive();
+
   Handle<FixedArray> constant_properties() const {
     return constant_properties_;
   }
   ZoneList<Property*>* properties() const { return properties_; }
 
+  bool fast_elements() const { return fast_elements_; }
+
  private:
   Handle<FixedArray> constant_properties_;
   ZoneList<Property*>* properties_;
+  bool fast_elements_;
 };
 
 
@@ -884,6 +926,8 @@
 
   virtual bool IsLeaf() { return true; }
 
+  virtual bool IsPrimitive();
+
   Handle<String> pattern() const { return pattern_; }
   Handle<String> flags() const { return flags_; }
 
@@ -910,6 +954,8 @@
 
   virtual bool IsLeaf() { return values()->is_empty(); }
 
+  virtual bool IsPrimitive();
+
   Handle<FixedArray> constant_elements() const { return constant_elements_; }
   ZoneList<Expression*>* values() const { return values_; }
 
@@ -930,6 +976,8 @@
 
   virtual void Accept(AstVisitor* v);
 
+  virtual bool IsPrimitive();
+
   Literal* key() const { return key_; }
   VariableProxy* value() const { return value_; }
 
@@ -964,7 +1012,9 @@
 
   // Reading from a mutable variable is a side effect, but 'this' is
   // immutable.
-  virtual bool IsTrivial() { return is_this(); }
+  virtual bool IsTrivial() { return is_trivial_; }
+
+  virtual bool IsPrimitive();
 
   bool IsVariable(Handle<String> n) {
     return !is_this() && name().is_identical_to(n);
@@ -979,6 +1029,8 @@
   Variable* var() const  { return var_; }
   bool is_this() const  { return is_this_; }
   bool inside_with() const  { return inside_with_; }
+  bool is_trivial() { return is_trivial_; }
+  void set_is_trivial(bool b) { is_trivial_ = b; }
 
   // Bind this proxy to the variable var.
   void BindTo(Variable* var);
@@ -988,6 +1040,7 @@
   Variable* var_;  // resolved variable, or NULL
   bool is_this_;
   bool inside_with_;
+  bool is_trivial_;
 
   VariableProxy(Handle<String> name, bool is_this, bool inside_with);
   explicit VariableProxy(bool is_this);
@@ -1004,6 +1057,11 @@
     return &identifier_proxy_;
   }
 
+  virtual bool IsPrimitive() {
+    UNREACHABLE();
+    return false;
+  }
+
  private:
   explicit VariableProxySentinel(bool is_this) : VariableProxy(is_this) { }
   static VariableProxySentinel this_proxy_;
@@ -1047,6 +1105,11 @@
 
   virtual bool IsLeaf() { return true; }
 
+  virtual bool IsPrimitive() {
+    UNREACHABLE();
+    return false;
+  }
+
   bool IsStackAllocated() { return type_ == PARAMETER || type_ == LOCAL; }
 
   // Accessors
@@ -1079,6 +1142,8 @@
 
   virtual bool IsValidLeftHandSide() { return true; }
 
+  virtual bool IsPrimitive();
+
   Expression* obj() const { return obj_; }
   Expression* key() const { return key_; }
   int position() const { return pos_; }
@@ -1109,6 +1174,8 @@
   // Type testing and conversion.
   virtual Call* AsCall() { return this; }
 
+  virtual bool IsPrimitive();
+
   Expression* expression() const { return expression_; }
   ZoneList<Expression*>* arguments() const { return arguments_; }
   int position() { return pos_; }
@@ -1131,6 +1198,8 @@
 
   virtual void Accept(AstVisitor* v);
 
+  virtual bool IsPrimitive();
+
   Expression* expression() const { return expression_; }
   ZoneList<Expression*>* arguments() const { return arguments_; }
   int position() { return pos_; }
@@ -1155,6 +1224,8 @@
 
   virtual void Accept(AstVisitor* v);
 
+  virtual bool IsPrimitive();
+
   Handle<String> name() const { return name_; }
   Runtime::Function* function() const { return function_; }
   ZoneList<Expression*>* arguments() const { return arguments_; }
@@ -1179,6 +1250,8 @@
   // Type testing & conversion
   virtual UnaryOperation* AsUnaryOperation() { return this; }
 
+  virtual bool IsPrimitive();
+
   Token::Value op() const { return op_; }
   Expression* expression() const { return expression_; }
 
@@ -1200,6 +1273,8 @@
   // Type testing & conversion
   virtual BinaryOperation* AsBinaryOperation() { return this; }
 
+  virtual bool IsPrimitive();
+
   // True iff the result can be safely overwritten (to avoid allocation).
   // False for operations that can return one of their operands.
   bool ResultOverwriteAllowed() {
@@ -1246,6 +1321,14 @@
 
   virtual void Accept(AstVisitor* v);
 
+  virtual CountOperation* AsCountOperation() { return this; }
+
+  virtual Variable* AssignedVar() {
+    return expression()->AsVariableProxy()->AsVariable();
+  }
+
+  virtual bool IsPrimitive();
+
   bool is_prefix() const { return is_prefix_; }
   bool is_postfix() const { return !is_prefix_; }
   Token::Value op() const { return op_; }
@@ -1272,6 +1355,8 @@
 
   virtual void Accept(AstVisitor* v);
 
+  virtual bool IsPrimitive();
+
   Token::Value op() const { return op_; }
   Expression* left() const { return left_; }
   Expression* right() const { return right_; }
@@ -1302,6 +1387,8 @@
 
   virtual void Accept(AstVisitor* v);
 
+  virtual bool IsPrimitive();
+
   Expression* condition() const { return condition_; }
   Expression* then_expression() const { return then_expression_; }
   Expression* else_expression() const { return else_expression_; }
@@ -1324,6 +1411,14 @@
   virtual void Accept(AstVisitor* v);
   virtual Assignment* AsAssignment() { return this; }
 
+  virtual bool IsPrimitive();
+
+  Assignment* AsSimpleAssignment() { return !is_compound() ? this : NULL; }
+
+  virtual Variable* AssignedVar() {
+    return target()->AsVariableProxy()->AsVariable();
+  }
+
   Token::Value binary_op() const;
 
   Token::Value op() const { return op_; }
@@ -1358,6 +1453,9 @@
       : exception_(exception), pos_(pos) {}
 
   virtual void Accept(AstVisitor* v);
+
+  virtual bool IsPrimitive();
+
   Expression* exception() const { return exception_; }
   int position() const { return pos_; }
 
@@ -1407,6 +1505,8 @@
 
   virtual bool IsLeaf() { return true; }
 
+  virtual bool IsPrimitive();
+
   Handle<String> name() const  { return name_; }
   Scope* scope() const  { return scope_; }
   ZoneList<Statement*>* body() const  { return body_; }
@@ -1477,6 +1577,8 @@
 
   virtual void Accept(AstVisitor* v);
 
+  virtual bool IsPrimitive();
+
  private:
   Handle<JSFunction> boilerplate_;
 };
@@ -1486,6 +1588,7 @@
  public:
   virtual void Accept(AstVisitor* v);
   virtual bool IsLeaf() { return true; }
+  virtual bool IsPrimitive();
 };
 
 
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 12efbc1..8df37d2 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -55,7 +55,7 @@
   }
 
   void Iterate(ObjectVisitor* v) {
-    v->VisitPointer(bit_cast<Object**, FixedArray**>(&cache_));
+    v->VisitPointer(BitCast<Object**, FixedArray**>(&cache_));
   }
 
 
@@ -245,12 +245,6 @@
       bool make_prototype_enumerable = false);
   void MakeFunctionInstancePrototypeWritable();
 
-  void AddSpecialFunction(Handle<JSObject> prototype,
-                          const char* name,
-                          Handle<Code> code);
-
-  void BuildSpecialFunctionTable();
-
   static bool CompileBuiltin(int index);
   static bool CompileNative(Vector<const char> name, Handle<String> source);
   static bool CompileScriptCached(Vector<const char> name,
@@ -777,8 +771,6 @@
     delegate->shared()->DontAdaptArguments();
   }
 
-  global_context()->set_special_function_table(Heap::empty_fixed_array());
-
   // Initialize the out of memory slot.
   global_context()->set_out_of_memory(Heap::false_value());
 
@@ -1457,65 +1449,6 @@
 }
 
 
-void Genesis::AddSpecialFunction(Handle<JSObject> prototype,
-                                 const char* name,
-                                 Handle<Code> code) {
-  Handle<String> key = Factory::LookupAsciiSymbol(name);
-  Handle<Object> value = Handle<Object>(prototype->GetProperty(*key));
-  if (value->IsJSFunction()) {
-    Handle<JSFunction> optimized = Factory::NewFunction(key,
-                                                        JS_OBJECT_TYPE,
-                                                        JSObject::kHeaderSize,
-                                                        code,
-                                                        false);
-    optimized->shared()->DontAdaptArguments();
-    int len = global_context()->special_function_table()->length();
-    Handle<FixedArray> new_array = Factory::NewFixedArray(len + 3);
-    for (int index = 0; index < len; index++) {
-      new_array->set(index,
-                     global_context()->special_function_table()->get(index));
-    }
-    new_array->set(len+0, *prototype);
-    new_array->set(len+1, *value);
-    new_array->set(len+2, *optimized);
-    global_context()->set_special_function_table(*new_array);
-  }
-}
-
-
-void Genesis::BuildSpecialFunctionTable() {
-  HandleScope scope;
-  Handle<JSObject> global = Handle<JSObject>(global_context()->global());
-  // Add special versions for some Array.prototype functions.
-  Handle<JSFunction> function =
-      Handle<JSFunction>(
-          JSFunction::cast(global->GetProperty(Heap::Array_symbol())));
-  Handle<JSObject> visible_prototype =
-      Handle<JSObject>(JSObject::cast(function->prototype()));
-  // Remember to put those specializations on the hidden prototype if present.
-  Handle<JSObject> special_prototype;
-  Handle<Object> superproto(visible_prototype->GetPrototype());
-  if (superproto->IsJSObject() &&
-      JSObject::cast(*superproto)->map()->is_hidden_prototype()) {
-    special_prototype = Handle<JSObject>::cast(superproto);
-  } else {
-    special_prototype = visible_prototype;
-  }
-  AddSpecialFunction(special_prototype, "pop",
-                     Handle<Code>(Builtins::builtin(Builtins::ArrayPop)));
-  AddSpecialFunction(special_prototype, "push",
-                     Handle<Code>(Builtins::builtin(Builtins::ArrayPush)));
-  AddSpecialFunction(special_prototype, "shift",
-                     Handle<Code>(Builtins::builtin(Builtins::ArrayShift)));
-  AddSpecialFunction(special_prototype, "unshift",
-                     Handle<Code>(Builtins::builtin(Builtins::ArrayUnshift)));
-  AddSpecialFunction(special_prototype, "slice",
-                     Handle<Code>(Builtins::builtin(Builtins::ArraySlice)));
-  AddSpecialFunction(special_prototype, "splice",
-                     Handle<Code>(Builtins::builtin(Builtins::ArraySplice)));
-}
-
-
 Genesis::Genesis(Handle<Object> global_object,
                  v8::Handle<v8::ObjectTemplate> global_template,
                  v8::ExtensionConfiguration* extensions) {
@@ -1539,7 +1472,6 @@
   if (!InstallNatives()) return;
 
   MakeFunctionInstancePrototypeWritable();
-  BuildSpecialFunctionTable();
 
   if (!ConfigureGlobalObjects(global_template)) return;
 
diff --git a/src/builtins.cc b/src/builtins.cc
index a8ba818..e59dbcf 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -319,6 +319,24 @@
 }
 
 
+static bool IsJSArrayWithFastElements(Object* receiver,
+                                      FixedArray** elements) {
+  if (!receiver->IsJSArray()) {
+    return false;
+  }
+
+  JSArray* array = JSArray::cast(receiver);
+
+  HeapObject* elms = HeapObject::cast(array->elements());
+  if (elms->map() != Heap::fixed_array_map()) {
+    return false;
+  }
+
+  *elements = FixedArray::cast(elms);
+  return true;
+}
+
+
 static Object* CallJsBuiltin(const char* name,
                              BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
   HandleScope handleScope;
@@ -331,7 +349,7 @@
   Vector<Object**> argv(Vector<Object**>::New(args.length() - 1));
   int n_args = args.length() - 1;
   for (int i = 0; i < n_args; i++) {
-    argv[i] = &args[i + 1];
+    argv[i] = args.at<Object>(i + 1).location();
   }
   bool pending_exception = false;
   Handle<Object> result = Execution::Call(function,
@@ -346,8 +364,12 @@
 
 
 BUILTIN(ArrayPush) {
-  JSArray* array = JSArray::cast(*args.receiver());
-  ASSERT(array->HasFastElements());
+  Object* receiver = *args.receiver();
+  FixedArray* elms = NULL;
+  if (!IsJSArrayWithFastElements(receiver, &elms)) {
+    return CallJsBuiltin("ArrayPush", args);
+  }
+  JSArray* array = JSArray::cast(receiver);
 
   int len = Smi::cast(array->length())->value();
   int to_add = args.length() - 1;
@@ -359,7 +381,6 @@
   ASSERT(to_add <= (Smi::kMaxValue - len));
 
   int new_length = len + to_add;
-  FixedArray* elms = FixedArray::cast(array->elements());
 
   if (new_length > elms->length()) {
     // New backing storage is needed.
@@ -390,14 +411,17 @@
 
 
 BUILTIN(ArrayPop) {
-  JSArray* array = JSArray::cast(*args.receiver());
-  ASSERT(array->HasFastElements());
+  Object* receiver = *args.receiver();
+  FixedArray* elms = NULL;
+  if (!IsJSArrayWithFastElements(receiver, &elms)) {
+    return CallJsBuiltin("ArrayPop", args);
+  }
+  JSArray* array = JSArray::cast(receiver);
 
   int len = Smi::cast(array->length())->value();
   if (len == 0) return Heap::undefined_value();
 
   // Get top element
-  FixedArray* elms = FixedArray::cast(array->elements());
   Object* top = elms->get(len - 1);
 
   // Set the length.
@@ -420,18 +444,18 @@
 
 
 BUILTIN(ArrayShift) {
-  if (!ArrayPrototypeHasNoElements()) {
+  Object* receiver = *args.receiver();
+  FixedArray* elms = NULL;
+  if (!IsJSArrayWithFastElements(receiver, &elms)
+      || !ArrayPrototypeHasNoElements()) {
     return CallJsBuiltin("ArrayShift", args);
   }
-
-  JSArray* array = JSArray::cast(*args.receiver());
+  JSArray* array = JSArray::cast(receiver);
   ASSERT(array->HasFastElements());
 
   int len = Smi::cast(array->length())->value();
   if (len == 0) return Heap::undefined_value();
 
-  FixedArray* elms = FixedArray::cast(array->elements());
-
   // Get first element
   Object* first = elms->get(0);
   if (first->IsTheHole()) {
@@ -451,26 +475,22 @@
 
 
 BUILTIN(ArrayUnshift) {
-  if (!ArrayPrototypeHasNoElements()) {
+  Object* receiver = *args.receiver();
+  FixedArray* elms = NULL;
+  if (!IsJSArrayWithFastElements(receiver, &elms)
+      || !ArrayPrototypeHasNoElements()) {
     return CallJsBuiltin("ArrayUnshift", args);
   }
-
-  JSArray* array = JSArray::cast(*args.receiver());
+  JSArray* array = JSArray::cast(receiver);
   ASSERT(array->HasFastElements());
 
   int len = Smi::cast(array->length())->value();
   int to_add = args.length() - 1;
-  // Note that we cannot quit early if to_add == 0 as
-  // values should be lifted from prototype into
-  // the array.
-
   int new_length = len + to_add;
   // Currently fixed arrays cannot grow too big, so
   // we should never hit this case.
   ASSERT(to_add <= (Smi::kMaxValue - len));
 
-  FixedArray* elms = FixedArray::cast(array->elements());
-
   if (new_length > elms->length()) {
     // New backing storage is needed.
     int capacity = new_length + (new_length >> 1) + 16;
@@ -503,11 +523,13 @@
 
 
 BUILTIN(ArraySlice) {
-  if (!ArrayPrototypeHasNoElements()) {
+  Object* receiver = *args.receiver();
+  FixedArray* elms = NULL;
+  if (!IsJSArrayWithFastElements(receiver, &elms)
+      || !ArrayPrototypeHasNoElements()) {
     return CallJsBuiltin("ArraySlice", args);
   }
-
-  JSArray* array = JSArray::cast(*args.receiver());
+  JSArray* array = JSArray::cast(receiver);
   ASSERT(array->HasFastElements());
 
   int len = Smi::cast(array->length())->value();
@@ -558,8 +580,6 @@
   if (result->IsFailure()) return result;
   FixedArray* result_elms = FixedArray::cast(result);
 
-  FixedArray* elms = FixedArray::cast(array->elements());
-
   AssertNoAllocation no_gc;
   CopyElements(&no_gc, result_elms, 0, elms, k, result_len);
 
@@ -573,11 +593,13 @@
 
 
 BUILTIN(ArraySplice) {
-  if (!ArrayPrototypeHasNoElements()) {
+  Object* receiver = *args.receiver();
+  FixedArray* elms = NULL;
+  if (!IsJSArrayWithFastElements(receiver, &elms)
+      || !ArrayPrototypeHasNoElements()) {
     return CallJsBuiltin("ArraySplice", args);
   }
-
-  JSArray* array = JSArray::cast(*args.receiver());
+  JSArray* array = JSArray::cast(receiver);
   ASSERT(array->HasFastElements());
 
   int len = Smi::cast(array->length())->value();
@@ -618,8 +640,6 @@
   }
   int actual_delete_count = Min(Max(delete_count, 0), len - actual_start);
 
-  FixedArray* elms = FixedArray::cast(array->elements());
-
   JSArray* result_array = NULL;
   if (actual_delete_count == 0) {
     Object* result = AllocateEmptyJSArray();
@@ -766,20 +786,19 @@
 
   HandleScope scope;
   Handle<JSFunction> function = args.called_function();
+  ASSERT(function->shared()->IsApiFunction());
 
+  FunctionTemplateInfo* fun_data = function->shared()->get_api_func_data();
   if (is_construct) {
-    Handle<FunctionTemplateInfo> desc =
-        Handle<FunctionTemplateInfo>(
-            FunctionTemplateInfo::cast(function->shared()->function_data()));
+    Handle<FunctionTemplateInfo> desc(fun_data);
     bool pending_exception = false;
     Factory::ConfigureInstance(desc, Handle<JSObject>::cast(args.receiver()),
                                &pending_exception);
     ASSERT(Top::has_pending_exception() == pending_exception);
     if (pending_exception) return Failure::Exception();
+    fun_data = *desc;
   }
 
-  FunctionTemplateInfo* fun_data =
-      FunctionTemplateInfo::cast(function->shared()->function_data());
   Object* raw_holder = TypeCheck(args.length(), &args[0], fun_data);
 
   if (raw_holder->IsNull()) {
@@ -850,8 +869,8 @@
 
 static void VerifyTypeCheck(Handle<JSObject> object,
                             Handle<JSFunction> function) {
-  FunctionTemplateInfo* info =
-      FunctionTemplateInfo::cast(function->shared()->function_data());
+  ASSERT(function->shared()->IsApiFunction());
+  FunctionTemplateInfo* info = function->shared()->get_api_func_data();
   if (info->signature()->IsUndefined()) return;
   SignatureInfo* signature = SignatureInfo::cast(info->signature());
   Object* receiver_type = signature->receiver();
@@ -935,9 +954,9 @@
   // used to create the called object.
   ASSERT(obj->map()->has_instance_call_handler());
   JSFunction* constructor = JSFunction::cast(obj->map()->constructor());
-  Object* template_info = constructor->shared()->function_data();
+  ASSERT(constructor->shared()->IsApiFunction());
   Object* handler =
-      FunctionTemplateInfo::cast(template_info)->instance_call_handler();
+      constructor->shared()->get_api_func_data()->instance_call_handler();
   ASSERT(!handler->IsUndefined());
   CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
   Object* callback_obj = call_data->callback();
diff --git a/src/cached_powers.h b/src/cached_powers.h
new file mode 100644
index 0000000..7c3d234
--- /dev/null
+++ b/src/cached_powers.h
@@ -0,0 +1,119 @@
+// 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_CACHED_POWERS_H_
+#define V8_CACHED_POWERS_H_
+
+#include "diy_fp.h"
+
+namespace v8 {
+namespace internal {
+
+struct CachedPower {
+  uint64_t significand;
+  int16_t binary_exponent;
+  int16_t decimal_exponent;
+};
+
+// The following defines implement the interface between this file and the
+// generated 'powers_ten.h'.
+// GRISU_CACHE_NAME(1) contains all possible cached powers.
+// GRISU_CACHE_NAME(i) contains GRISU_CACHE_NAME(1) where only every 'i'th
+// element is kept. More formally GRISU_CACHE_NAME(i) contains the elements j*i
+// with 0 <= j < k with k such that j*k < the size of GRISU_CACHE_NAME(1).
+// The higher 'i' is the fewer elements we use.
+// Given that there are less elements, the exponent-distance between two
+// elements in the cache grows. The variable GRISU_CACHE_MAX_DISTANCE(i) stores
+// the maximum distance between two elements.
+#define GRISU_CACHE_STRUCT CachedPower
+#define GRISU_CACHE_NAME(i) kCachedPowers##i
+#define GRISU_CACHE_MAX_DISTANCE(i) kCachedPowersMaxDistance##i
+#define GRISU_CACHE_OFFSET kCachedPowerOffset
+#define GRISU_UINT64_C V8_2PART_UINT64_C
+// The following include imports the precompiled cached powers.
+#include "powers_ten.h"  // NOLINT
+
+static const double kD_1_LOG2_10 = 0.30102999566398114;  //  1 / lg(10)
+
+// We can't use a function since we reference variables depending on the 'i'.
+// This way the compiler is able to see at compile time that only one
+// cache-array variable is used and thus can remove all the others.
+#define COMPUTE_FOR_CACHE(i) \
+  if (!found && (gamma - alpha + 1 >= GRISU_CACHE_MAX_DISTANCE(i))) {   \
+    int kQ = DiyFp::kSignificandSize;                                   \
+    double k = ceiling((alpha - e + kQ - 1) * kD_1_LOG2_10);            \
+    int index = (GRISU_CACHE_OFFSET + static_cast<int>(k) - 1) / i + 1; \
+    cached_power = GRISU_CACHE_NAME(i)[index];                          \
+    found = true;                                                       \
+  }                                                                     \
+
+static void GetCachedPower(int e, int alpha, int gamma, int* mk, DiyFp* c_mk) {
+  // The following if statement should be optimized by the compiler so that only
+  // one array is referenced and the others are not included in the object file.
+  bool found = false;
+  CachedPower cached_power;
+  COMPUTE_FOR_CACHE(20);
+  COMPUTE_FOR_CACHE(19);
+  COMPUTE_FOR_CACHE(18);
+  COMPUTE_FOR_CACHE(17);
+  COMPUTE_FOR_CACHE(16);
+  COMPUTE_FOR_CACHE(15);
+  COMPUTE_FOR_CACHE(14);
+  COMPUTE_FOR_CACHE(13);
+  COMPUTE_FOR_CACHE(12);
+  COMPUTE_FOR_CACHE(11);
+  COMPUTE_FOR_CACHE(10);
+  COMPUTE_FOR_CACHE(9);
+  COMPUTE_FOR_CACHE(8);
+  COMPUTE_FOR_CACHE(7);
+  COMPUTE_FOR_CACHE(6);
+  COMPUTE_FOR_CACHE(5);
+  COMPUTE_FOR_CACHE(4);
+  COMPUTE_FOR_CACHE(3);
+  COMPUTE_FOR_CACHE(2);
+  COMPUTE_FOR_CACHE(1);
+  if (!found) {
+    UNIMPLEMENTED();
+    // Silence compiler warnings.
+    cached_power.significand = 0;
+    cached_power.binary_exponent = 0;
+    cached_power.decimal_exponent = 0;
+  }
+  *c_mk = DiyFp(cached_power.significand, cached_power.binary_exponent);
+  *mk = cached_power.decimal_exponent;
+  ASSERT((alpha <= c_mk->e() + e) && (c_mk->e() + e <= gamma));
+}
+#undef GRISU_REDUCTION
+#undef GRISU_CACHE_STRUCT
+#undef GRISU_CACHE_NAME
+#undef GRISU_CACHE_MAX_DISTANCE
+#undef GRISU_CACHE_OFFSET
+#undef GRISU_UINT64_C
+
+} }  // namespace v8::internal
+
+#endif  // V8_CACHED_POWERS_H_
diff --git a/src/checks.h b/src/checks.h
index eeb748b..cdcd18a 100644
--- a/src/checks.h
+++ b/src/checks.h
@@ -80,6 +80,7 @@
   }
 }
 
+
 // Helper function used by the CHECK_EQ function when given int64_t
 // arguments.  Should not be called directly.
 static inline void CheckEqualsHelper(const char* file, int line,
@@ -202,6 +203,27 @@
 }
 
 
+static inline void CheckNonEqualsHelper(const char* file,
+                                     int line,
+                                     const char* expected_source,
+                                     double expected,
+                                     const char* value_source,
+                                     double value) {
+  // Force values to 64 bit memory to truncate 80 bit precision on IA32.
+  volatile double* exp = new double[1];
+  *exp = expected;
+  volatile double* val = new double[1];
+  *val = value;
+  if (*exp == *val) {
+    V8_Fatal(file, line,
+             "CHECK_NE(%s, %s) failed\n#   Value: %f",
+             expected_source, value_source, *val);
+  }
+  delete[] exp;
+  delete[] val;
+}
+
+
 namespace v8 {
   class Value;
   template <class T> class Handle;
diff --git a/src/codegen.cc b/src/codegen.cc
index 6841c21..f9913b9 100644
--- a/src/codegen.cc
+++ b/src/codegen.cc
@@ -351,42 +351,18 @@
 }
 
 
+// List of special runtime calls which are generated inline. For some of these
+// functions the code will be generated inline, and for others a call to a code
+// stub will be inlined.
 
-// Special cases: These 'runtime calls' manipulate the current
-// frame and are only used 1 or two places, so we generate them
-// inline instead of generating calls to them.  They are used
-// for implementing Function.prototype.call() and
-// Function.prototype.apply().
+#define INLINE_RUNTIME_ENTRY(Name, argc, ressize)                             \
+    {&CodeGenerator::Generate##Name,  "_" #Name, argc},                       \
+
 CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = {
-  {&CodeGenerator::GenerateIsSmi, "_IsSmi"},
-  {&CodeGenerator::GenerateIsNonNegativeSmi, "_IsNonNegativeSmi"},
-  {&CodeGenerator::GenerateIsArray, "_IsArray"},
-  {&CodeGenerator::GenerateIsRegExp, "_IsRegExp"},
-  {&CodeGenerator::GenerateIsConstructCall, "_IsConstructCall"},
-  {&CodeGenerator::GenerateArgumentsLength, "_ArgumentsLength"},
-  {&CodeGenerator::GenerateArgumentsAccess, "_Arguments"},
-  {&CodeGenerator::GenerateClassOf, "_ClassOf"},
-  {&CodeGenerator::GenerateValueOf, "_ValueOf"},
-  {&CodeGenerator::GenerateSetValueOf, "_SetValueOf"},
-  {&CodeGenerator::GenerateFastCharCodeAt, "_FastCharCodeAt"},
-  {&CodeGenerator::GenerateCharFromCode, "_CharFromCode"},
-  {&CodeGenerator::GenerateObjectEquals, "_ObjectEquals"},
-  {&CodeGenerator::GenerateLog, "_Log"},
-  {&CodeGenerator::GenerateRandomPositiveSmi, "_RandomPositiveSmi"},
-  {&CodeGenerator::GenerateIsObject, "_IsObject"},
-  {&CodeGenerator::GenerateIsFunction, "_IsFunction"},
-  {&CodeGenerator::GenerateIsUndetectableObject, "_IsUndetectableObject"},
-  {&CodeGenerator::GenerateStringAdd, "_StringAdd"},
-  {&CodeGenerator::GenerateSubString, "_SubString"},
-  {&CodeGenerator::GenerateStringCompare, "_StringCompare"},
-  {&CodeGenerator::GenerateRegExpExec, "_RegExpExec"},
-  {&CodeGenerator::GenerateNumberToString, "_NumberToString"},
-  {&CodeGenerator::GenerateMathPow, "_Math_pow"},
-  {&CodeGenerator::GenerateMathSin, "_Math_sin"},
-  {&CodeGenerator::GenerateMathCos, "_Math_cos"},
-  {&CodeGenerator::GenerateMathSqrt, "_Math_sqrt"},
+  INLINE_RUNTIME_FUNCTION_LIST(INLINE_RUNTIME_ENTRY)
 };
 
+#undef INLINE_RUNTIME_ENTRY
 
 CodeGenerator::InlineRuntimeLUT* CodeGenerator::FindInlineRuntimeLUT(
     Handle<String> name) {
@@ -431,6 +407,14 @@
 }
 
 
+int CodeGenerator::InlineRuntimeCallArgumentsCount(Handle<String> name) {
+  CodeGenerator::InlineRuntimeLUT* f =
+      CodeGenerator::FindInlineRuntimeLUT(name);
+  if (f != NULL) return f->nargs;
+  return -1;
+}
+
+
 // Simple condition analysis.  ALWAYS_TRUE and ALWAYS_FALSE represent a
 // known result for the test expression, with no side effects.
 CodeGenerator::ConditionAnalysis CodeGenerator::AnalyzeCondition(
diff --git a/src/codegen.h b/src/codegen.h
index 8dcde84..40ed6ce 100644
--- a/src/codegen.h
+++ b/src/codegen.h
@@ -99,6 +99,36 @@
 namespace internal {
 
 
+#define INLINE_RUNTIME_FUNCTION_LIST(F) \
+  F(IsSmi, 1, 1)                                                             \
+  F(IsNonNegativeSmi, 1, 1)                                                  \
+  F(IsArray, 1, 1)                                                           \
+  F(IsRegExp, 1, 1)                                                          \
+  F(IsConstructCall, 0, 1)                                                   \
+  F(ArgumentsLength, 0, 1)                                                   \
+  F(Arguments, 1, 1)                                                         \
+  F(ClassOf, 1, 1)                                                           \
+  F(ValueOf, 1, 1)                                                           \
+  F(SetValueOf, 2, 1)                                                        \
+  F(FastCharCodeAt, 2, 1)                                                    \
+  F(CharFromCode, 1, 1)                                                      \
+  F(ObjectEquals, 2, 1)                                                      \
+  F(Log, 3, 1)                                                               \
+  F(RandomPositiveSmi, 0, 1)                                                 \
+  F(IsObject, 1, 1)                                                          \
+  F(IsFunction, 1, 1)                                                        \
+  F(IsUndetectableObject, 1, 1)                                              \
+  F(StringAdd, 2, 1)                                                         \
+  F(SubString, 3, 1)                                                         \
+  F(StringCompare, 2, 1)                                                     \
+  F(RegExpExec, 4, 1)                                                        \
+  F(NumberToString, 1, 1)                                                    \
+  F(MathPow, 2, 1)                                                           \
+  F(MathSin, 1, 1)                                                           \
+  F(MathCos, 1, 1)                                                           \
+  F(MathSqrt, 1, 1)
+
+
 // Support for "structured" code comments.
 #ifdef DEBUG
 
diff --git a/src/compilation-cache.cc b/src/compilation-cache.cc
index 9dcbeb5..378a24e 100644
--- a/src/compilation-cache.cc
+++ b/src/compilation-cache.cc
@@ -218,9 +218,7 @@
 
 
 void CompilationSubCache::Clear() {
-  for (int i = 0; i < generations_; i++) {
-    tables_[i] = Heap::undefined_value();
-  }
+  MemsetPointer(tables_, Heap::undefined_value(), generations_);
 }
 
 
diff --git a/src/compiler.cc b/src/compiler.cc
index ebb62f1..dce8816 100755
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -79,12 +79,32 @@
     return Handle<Code>::null();
   }
 
+  if (function->scope()->num_parameters() > 0 ||
+      function->scope()->num_stack_slots()) {
+    AssignedVariablesAnalyzer ava(function);
+    ava.Analyze();
+    if (ava.HasStackOverflow()) {
+      return Handle<Code>::null();
+    }
+  }
+
   if (FLAG_use_flow_graph) {
     FlowGraphBuilder builder;
     builder.Build(function);
 
+    if (!builder.HasStackOverflow()) {
+      int variable_count =
+          function->num_parameters() + function->scope()->num_stack_slots();
+      if (variable_count > 0 && builder.definitions()->length() > 0) {
+        ReachingDefinitions rd(builder.postorder(),
+                               builder.definitions(),
+                               variable_count);
+        rd.Compute();
+      }
+    }
+
 #ifdef DEBUG
-    if (FLAG_print_graph_text) {
+    if (FLAG_print_graph_text && !builder.HasStackOverflow()) {
       builder.graph()->PrintText(builder.postorder());
     }
 #endif
@@ -463,12 +483,32 @@
       return Handle<JSFunction>::null();
     }
 
+    if (literal->scope()->num_parameters() > 0 ||
+        literal->scope()->num_stack_slots()) {
+      AssignedVariablesAnalyzer ava(literal);
+      ava.Analyze();
+      if (ava.HasStackOverflow()) {
+        return Handle<JSFunction>::null();
+      }
+    }
+
     if (FLAG_use_flow_graph) {
       FlowGraphBuilder builder;
       builder.Build(literal);
 
+    if (!builder.HasStackOverflow()) {
+      int variable_count =
+          literal->num_parameters() + literal->scope()->num_stack_slots();
+      if (variable_count > 0 && builder.definitions()->length() > 0) {
+        ReachingDefinitions rd(builder.postorder(),
+                               builder.definitions(),
+                               variable_count);
+        rd.Compute();
+      }
+    }
+
 #ifdef DEBUG
-      if (FLAG_print_graph_text) {
+      if (FLAG_print_graph_text && !builder.HasStackOverflow()) {
         builder.graph()->PrintText(builder.postorder());
       }
 #endif
diff --git a/src/contexts.h b/src/contexts.h
index 98ebc47..4997741 100644
--- a/src/contexts.h
+++ b/src/contexts.h
@@ -50,12 +50,6 @@
 // must always be allocated via Heap::AllocateContext() or
 // Factory::NewContext.
 
-// Comment for special_function_table:
-// Table for providing optimized/specialized functions.
-// The array contains triplets [object, general_function, optimized_function].
-// Primarily added to support built-in optimized variants of
-// Array.prototype.{push,pop}.
-
 #define GLOBAL_CONTEXT_FIELDS(V) \
   V(GLOBAL_PROXY_INDEX, JSObject, global_proxy_object) \
   V(SECURITY_TOKEN_INDEX, Object, security_token) \
@@ -82,7 +76,6 @@
   V(FUNCTION_MAP_INDEX, Map, function_map) \
   V(FUNCTION_INSTANCE_MAP_INDEX, Map, function_instance_map) \
   V(JS_ARRAY_MAP_INDEX, Map, js_array_map)\
-  V(SPECIAL_FUNCTION_TABLE_INDEX, FixedArray, special_function_table) \
   V(ARGUMENTS_BOILERPLATE_INDEX, JSObject, arguments_boilerplate) \
   V(MESSAGE_LISTENERS_INDEX, JSObject, message_listeners) \
   V(MAKE_MESSAGE_FUN_INDEX, JSFunction, make_message_fun) \
@@ -206,7 +199,6 @@
     GLOBAL_EVAL_FUN_INDEX,
     INSTANTIATE_FUN_INDEX,
     CONFIGURE_INSTANCE_FUN_INDEX,
-    SPECIAL_FUNCTION_TABLE_INDEX,
     MESSAGE_LISTENERS_INDEX,
     MAKE_MESSAGE_FUN_INDEX,
     GET_STACK_TRACE_LINE_INDEX,
diff --git a/src/conversions.cc b/src/conversions.cc
index fd6d38d..864b625 100644
--- a/src/conversions.cc
+++ b/src/conversions.cc
@@ -31,6 +31,7 @@
 
 #include "conversions-inl.h"
 #include "factory.h"
+#include "grisu3.h"
 #include "scanner.h"
 
 namespace v8 {
@@ -382,8 +383,17 @@
       int decimal_point;
       int sign;
 
-      char* decimal_rep = dtoa(v, 0, 0, &decimal_point, &sign, NULL);
-      int length = StrLength(decimal_rep);
+      char* decimal_rep;
+      bool used_dtoa = false;
+      char grisu_buffer[kGrisu3MaximalLength + 1];
+      int length;
+      if (grisu3(v, grisu_buffer, &sign, &length, &decimal_point)) {
+        decimal_rep = grisu_buffer;
+      } else {
+        decimal_rep = dtoa(v, 0, 0, &decimal_point, &sign, NULL);
+        used_dtoa = true;
+        length = StrLength(decimal_rep);
+      }
 
       if (sign) builder.AddCharacter('-');
 
@@ -418,7 +428,7 @@
         builder.AddFormatted("%d", exponent);
       }
 
-      freedtoa(decimal_rep);
+      if (used_dtoa) freedtoa(decimal_rep);
     }
   }
   return builder.Finalize();
diff --git a/src/data-flow.cc b/src/data-flow.cc
index 6b45da0..f6ccef1 100644
--- a/src/data-flow.cc
+++ b/src/data-flow.cc
@@ -28,73 +28,76 @@
 #include "v8.h"
 
 #include "data-flow.h"
+#include "scopes.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 (is_empty() || !exit()->IsBlockNode()) {
-    AppendNode(new BlockNode());
-  }
+  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 (is_empty()) {
-    entry_ = exit_ = node;
-  } else {
-    exit()->AddSuccessor(node);
-    node->AddPredecessor(exit());
-    exit_ = node;
+  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) {
-  ASSERT(!graph->is_empty());
-  if (is_empty()) {
-    entry_ = graph->entry();
-    exit_ = graph->exit();
-  } else {
-    exit()->AddSuccessor(graph->entry());
-    graph->entry()->AddPredecessor(exit());
-    exit_ = graph->exit();
+  // 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* merge) {
-  // Graphs are in edge split form.  Add empty blocks if necessary.
-  if (left->is_empty()) left->AppendNode(new BlockNode());
-  if (right->is_empty()) right->AppendNode(new BlockNode());
-
-  // Add the branch, left flowgraph and merge.
+                      JoinNode* join) {
+  // Add the branch node, left flowgraph, join node.
   AppendNode(branch);
   AppendGraph(left);
-  AppendNode(merge);
+  AppendNode(join);
 
   // Splice in the right flowgraph.
-  right->AppendNode(merge);
+  right->AppendNode(join);
   branch->AddSuccessor(right->entry());
   right->entry()->AddPredecessor(branch);
 }
 
 
-void FlowGraph::Loop(JoinNode* merge,
+void FlowGraph::Loop(JoinNode* join,
                      FlowGraph* condition,
                      BranchNode* branch,
                      FlowGraph* body) {
-  // Add the merge, condition and branch.  Add merge's predecessors in
+  // Add the join, condition and branch.  Add join's predecessors in
   // left-to-right order.
-  AppendNode(merge);
-  body->AppendNode(merge);
+  AppendNode(join);
+  body->AppendNode(join);
   AppendGraph(condition);
   AppendNode(branch);
 
@@ -104,19 +107,6 @@
 }
 
 
-void EntryNode::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 ExitNode::Traverse(bool mark,
                         ZoneList<Node*>* preorder,
                         ZoneList<Node*>* postorder) {
@@ -143,14 +133,14 @@
                           ZoneList<Node*>* postorder) {
   ASSERT(successor0_ != NULL && successor1_ != NULL);
   preorder->Add(this);
-  if (!successor0_->IsMarkedWith(mark)) {
-    successor0_->MarkWith(mark);
-    successor0_->Traverse(mark, preorder, postorder);
-  }
   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);
 }
 
@@ -169,16 +159,15 @@
 
 
 void FlowGraphBuilder::Build(FunctionLiteral* lit) {
-  graph_ = FlowGraph::Empty();
-  graph_.AppendNode(new EntryNode());
   global_exit_ = new ExitNode();
   VisitStatements(lit->body());
 
-  if (HasStackOverflow()) {
-    graph_ = FlowGraph::Empty();
-    return;
-  }
+  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
@@ -222,6 +211,7 @@
   graph_ = FlowGraph::Empty();
   Visit(stmt->else_statement());
 
+  if (HasStackOverflow()) return;
   JoinNode* join = new JoinNode();
   original.Split(branch, &left, &graph_, join);
   graph_ = original;
@@ -239,20 +229,17 @@
 
 
 void FlowGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
-  Visit(stmt->expression());
-  graph_.AppendInstruction(stmt);
-  graph_.AppendNode(global_exit());
+  SetStackOverflow();
 }
 
 
 void FlowGraphBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) {
-  Visit(stmt->expression());
-  graph_.AppendInstruction(stmt);
+  SetStackOverflow();
 }
 
 
 void FlowGraphBuilder::VisitWithExitStatement(WithExitStatement* stmt) {
-  graph_.AppendInstruction(stmt);
+  SetStackOverflow();
 }
 
 
@@ -262,44 +249,12 @@
 
 
 void FlowGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
-  JoinNode* join = new JoinNode();
-  FlowGraph original = graph_;
-  graph_ = FlowGraph::Empty();
-  Visit(stmt->body());
-
-  FlowGraph body = graph_;
-  graph_ = FlowGraph::Empty();
-  Visit(stmt->cond());
-
-  BranchNode* branch = new BranchNode();
-
-  // Add body, condition and branch.
-  original.AppendNode(join);
-  original.AppendGraph(&body);
-  original.AppendGraph(&graph_);  // The condition.
-  original.AppendNode(branch);
-
-  // Tie the knot.
-  branch->AddSuccessor(join);
-  join->AddPredecessor(branch);
-
-  graph_ = original;
+  SetStackOverflow();
 }
 
 
 void FlowGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
-  JoinNode* join = new JoinNode();
-  FlowGraph original = graph_;
-  graph_ = FlowGraph::Empty();
-  Visit(stmt->cond());
-
-  BranchNode* branch = new BranchNode();
-  FlowGraph condition = graph_;
-  graph_ = FlowGraph::Empty();
-  Visit(stmt->body());
-
-  original.Loop(join, &condition, branch, &graph_);
-  graph_ = original;
+  SetStackOverflow();
 }
 
 
@@ -318,23 +273,14 @@
 
   if (stmt->next() != NULL) Visit(stmt->next());
 
+  if (HasStackOverflow()) return;
   original.Loop(join, &condition, branch, &graph_);
   graph_ = original;
 }
 
 
 void FlowGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
-  Visit(stmt->enumerable());
-
-  JoinNode* join = new JoinNode();
-  FlowGraph empty;
-  BranchNode* branch = new BranchNode();
-  FlowGraph original = graph_;
-  graph_ = FlowGraph::Empty();
-  Visit(stmt->body());
-
-  original.Loop(join, &empty, branch, &graph_);
-  graph_ = original;
+  SetStackOverflow();
 }
 
 
@@ -349,36 +295,23 @@
 
 
 void FlowGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
-  graph_.AppendInstruction(stmt);
+  SetStackOverflow();
 }
 
 
 void FlowGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
-  graph_.AppendInstruction(expr);
+  SetStackOverflow();
 }
 
 
 void FlowGraphBuilder::VisitFunctionBoilerplateLiteral(
     FunctionBoilerplateLiteral* expr) {
-  graph_.AppendInstruction(expr);
+  SetStackOverflow();
 }
 
 
 void FlowGraphBuilder::VisitConditional(Conditional* expr) {
-  Visit(expr->condition());
-
-  BranchNode* branch = new BranchNode();
-  FlowGraph original = graph_;
-  graph_ = FlowGraph::Empty();
-  Visit(expr->then_expression());
-
-  FlowGraph left = graph_;
-  graph_ = FlowGraph::Empty();
-  Visit(expr->else_expression());
-
-  JoinNode* join = new JoinNode();
-  original.Split(branch, &left, &graph_, join);
-  graph_ = original;
+  SetStackOverflow();
 }
 
 
@@ -398,30 +331,22 @@
 
 
 void FlowGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
-  graph_.AppendInstruction(expr);
+  SetStackOverflow();
 }
 
 
 void FlowGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
-  ZoneList<ObjectLiteral::Property*>* properties = expr->properties();
-  for (int i = 0, len = properties->length(); i < len; i++) {
-    Visit(properties->at(i)->value());
-  }
-  graph_.AppendInstruction(expr);
+  SetStackOverflow();
 }
 
 
 void FlowGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
-  ZoneList<Expression*>* values = expr->values();
-  for (int i = 0, len = values->length(); i < len; i++) {
-    Visit(values->at(i));
-  }
-  graph_.AppendInstruction(expr);
+  SetStackOverflow();
 }
 
 
 void FlowGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) {
-  graph_.AppendInstruction(expr);
+  SetStackOverflow();
 }
 
 
@@ -433,26 +358,32 @@
   ASSERT(var == NULL || prop == NULL);
   if (var != NULL) {
     Visit(expr->value());
-    if (var->IsStackAllocated()) definitions_.Add(expr);
+    if (var->IsStackAllocated()) {
+      expr->set_num(definitions_.length());
+      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) {
-  Visit(expr->exception());
-  graph_.AppendInstruction(expr);
+  SetStackOverflow();
 }
 
 
 void FlowGraphBuilder::VisitProperty(Property* expr) {
   Visit(expr->obj());
   if (!expr->key()->IsPropertyName()) Visit(expr->key());
+
+  if (HasStackOverflow()) return;
   graph_.AppendInstruction(expr);
 }
 
@@ -463,32 +394,42 @@
   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) {
-  Visit(expr->expression());
-  ZoneList<Expression*>* arguments = expr->arguments();
-  for (int i = 0, len = arguments->length(); i < len; i++) {
-    Visit(arguments->at(i));
-  }
-  graph_.AppendInstruction(expr);
+  SetStackOverflow();
 }
 
 
 void FlowGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
-  ZoneList<Expression*>* arguments = expr->arguments();
-  for (int i = 0, len = arguments->length(); i < len; i++) {
-    Visit(arguments->at(i));
-  }
-  graph_.AppendInstruction(expr);
+  SetStackOverflow();
 }
 
 
 void FlowGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
-  Visit(expr->expression());
-  graph_.AppendInstruction(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();
+  }
 }
 
 
@@ -496,56 +437,37 @@
   Visit(expr->expression());
   Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
   if (var != NULL && var->IsStackAllocated()) {
+    expr->set_num(definitions_.length());
     definitions_.Add(expr);
   }
+
+  if (HasStackOverflow()) return;
   graph_.AppendInstruction(expr);
 }
 
 
 void FlowGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
-  Visit(expr->left());
-
   switch (expr->op()) {
     case Token::COMMA:
-      Visit(expr->right());
+    case Token::OR:
+    case Token::AND:
+      SetStackOverflow();
       break;
 
-    case Token::OR: {
-      BranchNode* branch = new BranchNode();
-      FlowGraph original = graph_;
-      graph_ = FlowGraph::Empty();
-      Visit(expr->right());
-      FlowGraph empty;
-      JoinNode* join = new JoinNode();
-      original.Split(branch, &empty, &graph_, join);
-      graph_ = original;
-      break;
-    }
-
-    case Token::AND: {
-      BranchNode* branch = new BranchNode();
-      FlowGraph original = graph_;
-      graph_ = FlowGraph::Empty();
-      Visit(expr->right());
-      FlowGraph empty;
-      JoinNode* join = new JoinNode();
-      original.Split(branch, &graph_, &empty, join);
-      graph_ = original;
-      break;
-    }
-
     case Token::BIT_OR:
     case Token::BIT_XOR:
     case Token::BIT_AND:
     case Token::SHL:
-    case Token::SAR:
     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;
 
@@ -556,14 +478,34 @@
 
 
 void FlowGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
-  Visit(expr->left());
-  Visit(expr->right());
-  graph_.AppendInstruction(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) {
-  graph_.AppendInstruction(expr);
+  SetStackOverflow();
 }
 
 
@@ -1098,6 +1040,451 @@
 }
 
 
+AssignedVariablesAnalyzer::AssignedVariablesAnalyzer(FunctionLiteral* fun)
+    : fun_(fun),
+      av_(fun->scope()->num_parameters() + fun->scope()->num_stack_slots()) {}
+
+
+void AssignedVariablesAnalyzer::Analyze() {
+  ASSERT(av_.length() > 0);
+  VisitStatements(fun_->body());
+}
+
+
+Variable* AssignedVariablesAnalyzer::FindSmiLoopVariable(ForStatement* stmt) {
+  // The loop must have all necessary parts.
+  if (stmt->init() == NULL || stmt->cond() == NULL || stmt->next() == NULL) {
+    return NULL;
+  }
+  // The initialization statement has to be a simple assignment.
+  Assignment* init = stmt->init()->StatementAsSimpleAssignment();
+  if (init == NULL) return NULL;
+
+  // We only deal with local variables.
+  Variable* loop_var = init->target()->AsVariableProxy()->AsVariable();
+  if (loop_var == NULL || !loop_var->IsStackAllocated()) return NULL;
+
+  // The initial value has to be a smi.
+  Literal* init_lit = init->value()->AsLiteral();
+  if (init_lit == NULL || !init_lit->handle()->IsSmi()) return NULL;
+  int init_value = Smi::cast(*init_lit->handle())->value();
+
+  // The condition must be a compare of variable with <, <=, >, or >=.
+  CompareOperation* cond = stmt->cond()->AsCompareOperation();
+  if (cond == NULL) return NULL;
+  if (cond->op() != Token::LT
+      && cond->op() != Token::LTE
+      && cond->op() != Token::GT
+      && cond->op() != Token::GTE) return NULL;
+
+  // The lhs must be the same variable as in the init expression.
+  if (cond->left()->AsVariableProxy()->AsVariable() != loop_var) return NULL;
+
+  // The rhs must be a smi.
+  Literal* term_lit = cond->right()->AsLiteral();
+  if (term_lit == NULL || !term_lit->handle()->IsSmi()) return NULL;
+  int term_value = Smi::cast(*term_lit->handle())->value();
+
+  // The count operation updates the same variable as in the init expression.
+  CountOperation* update = stmt->next()->StatementAsCountOperation();
+  if (update == NULL) return NULL;
+  if (update->expression()->AsVariableProxy()->AsVariable() != loop_var) {
+    return NULL;
+  }
+
+  // The direction of the count operation must agree with the start and the end
+  // value. We currently do not allow the initial value to be the same as the
+  // terminal value. This _would_ be ok as long as the loop body never executes
+  // or executes exactly one time.
+  if (init_value == term_value) return NULL;
+  if (init_value < term_value && update->op() != Token::INC) return NULL;
+  if (init_value > term_value && update->op() != Token::DEC) return NULL;
+
+  // Found a smi loop variable.
+  return loop_var;
+}
+
+int AssignedVariablesAnalyzer::BitIndex(Variable* var) {
+  ASSERT(var != NULL);
+  ASSERT(var->IsStackAllocated());
+  Slot* slot = var->slot();
+  if (slot->type() == Slot::PARAMETER) {
+    return slot->index();
+  } else {
+    return fun_->scope()->num_parameters() + slot->index();
+  }
+}
+
+
+void AssignedVariablesAnalyzer::RecordAssignedVar(Variable* var) {
+  ASSERT(var != NULL);
+  if (var->IsStackAllocated()) {
+    av_.Add(BitIndex(var));
+  }
+}
+
+
+void AssignedVariablesAnalyzer::MarkIfTrivial(Expression* expr) {
+  Variable* var = expr->AsVariableProxy()->AsVariable();
+  if (var != NULL &&
+      var->IsStackAllocated() &&
+      !var->is_arguments() &&
+      var->mode() != Variable::CONST &&
+      (var->is_this() || !av_.Contains(BitIndex(var)))) {
+    expr->AsVariableProxy()->set_is_trivial(true);
+  }
+}
+
+
+void AssignedVariablesAnalyzer::ProcessExpression(Expression* expr) {
+  BitVector saved_av(av_);
+  av_.Clear();
+  Visit(expr);
+  av_.Union(saved_av);
+}
+
+void AssignedVariablesAnalyzer::VisitBlock(Block* stmt) {
+  VisitStatements(stmt->statements());
+}
+
+
+void AssignedVariablesAnalyzer::VisitExpressionStatement(
+    ExpressionStatement* stmt) {
+  ProcessExpression(stmt->expression());
+}
+
+
+void AssignedVariablesAnalyzer::VisitEmptyStatement(EmptyStatement* stmt) {
+  // Do nothing.
+}
+
+
+void AssignedVariablesAnalyzer::VisitIfStatement(IfStatement* stmt) {
+  ProcessExpression(stmt->condition());
+  Visit(stmt->then_statement());
+  Visit(stmt->else_statement());
+}
+
+
+void AssignedVariablesAnalyzer::VisitContinueStatement(
+    ContinueStatement* stmt) {
+  // Nothing to do.
+}
+
+
+void AssignedVariablesAnalyzer::VisitBreakStatement(BreakStatement* stmt) {
+  // Nothing to do.
+}
+
+
+void AssignedVariablesAnalyzer::VisitReturnStatement(ReturnStatement* stmt) {
+  ProcessExpression(stmt->expression());
+}
+
+
+void AssignedVariablesAnalyzer::VisitWithEnterStatement(
+    WithEnterStatement* stmt) {
+  ProcessExpression(stmt->expression());
+}
+
+
+void AssignedVariablesAnalyzer::VisitWithExitStatement(
+    WithExitStatement* stmt) {
+  // Nothing to do.
+}
+
+
+void AssignedVariablesAnalyzer::VisitSwitchStatement(SwitchStatement* stmt) {
+  BitVector result(av_);
+  av_.Clear();
+  Visit(stmt->tag());
+  result.Union(av_);
+  for (int i = 0; i < stmt->cases()->length(); i++) {
+    CaseClause* clause = stmt->cases()->at(i);
+    if (!clause->is_default()) {
+      av_.Clear();
+      Visit(clause->label());
+      result.Union(av_);
+    }
+    VisitStatements(clause->statements());
+  }
+  av_.Union(result);
+}
+
+
+void AssignedVariablesAnalyzer::VisitDoWhileStatement(DoWhileStatement* stmt) {
+  ProcessExpression(stmt->cond());
+  Visit(stmt->body());
+}
+
+
+void AssignedVariablesAnalyzer::VisitWhileStatement(WhileStatement* stmt) {
+  ProcessExpression(stmt->cond());
+  Visit(stmt->body());
+}
+
+
+void AssignedVariablesAnalyzer::VisitForStatement(ForStatement* stmt) {
+  if (stmt->init() != NULL) Visit(stmt->init());
+
+  if (stmt->cond() != NULL) ProcessExpression(stmt->cond());
+
+  if (stmt->next() != NULL) Visit(stmt->next());
+
+  // Process loop body. After visiting the loop body av_ contains
+  // the assigned variables of the loop body.
+  BitVector saved_av(av_);
+  av_.Clear();
+  Visit(stmt->body());
+
+  Variable* var = FindSmiLoopVariable(stmt);
+  if (var != NULL && !av_.Contains(BitIndex(var))) {
+    stmt->set_loop_variable(var);
+  }
+
+  av_.Union(saved_av);
+}
+
+
+void AssignedVariablesAnalyzer::VisitForInStatement(ForInStatement* stmt) {
+  ProcessExpression(stmt->each());
+  ProcessExpression(stmt->enumerable());
+  Visit(stmt->body());
+}
+
+
+void AssignedVariablesAnalyzer::VisitTryCatchStatement(
+    TryCatchStatement* stmt) {
+  Visit(stmt->try_block());
+  Visit(stmt->catch_block());
+}
+
+
+void AssignedVariablesAnalyzer::VisitTryFinallyStatement(
+    TryFinallyStatement* stmt) {
+  Visit(stmt->try_block());
+  Visit(stmt->finally_block());
+}
+
+
+void AssignedVariablesAnalyzer::VisitDebuggerStatement(
+    DebuggerStatement* stmt) {
+  // Nothing to do.
+}
+
+
+void AssignedVariablesAnalyzer::VisitFunctionLiteral(FunctionLiteral* expr) {
+  // Nothing to do.
+  ASSERT(av_.IsEmpty());
+}
+
+
+void AssignedVariablesAnalyzer::VisitFunctionBoilerplateLiteral(
+    FunctionBoilerplateLiteral* expr) {
+  // Nothing to do.
+  ASSERT(av_.IsEmpty());
+}
+
+
+void AssignedVariablesAnalyzer::VisitConditional(Conditional* expr) {
+  ASSERT(av_.IsEmpty());
+
+  Visit(expr->condition());
+
+  BitVector result(av_);
+  av_.Clear();
+  Visit(expr->then_expression());
+  result.Union(av_);
+
+  av_.Clear();
+  Visit(expr->else_expression());
+  av_.Union(result);
+}
+
+
+void AssignedVariablesAnalyzer::VisitSlot(Slot* expr) {
+  UNREACHABLE();
+}
+
+
+void AssignedVariablesAnalyzer::VisitVariableProxy(VariableProxy* expr) {
+  // Nothing to do.
+  ASSERT(av_.IsEmpty());
+}
+
+
+void AssignedVariablesAnalyzer::VisitLiteral(Literal* expr) {
+  // Nothing to do.
+  ASSERT(av_.IsEmpty());
+}
+
+
+void AssignedVariablesAnalyzer::VisitRegExpLiteral(RegExpLiteral* expr) {
+  // Nothing to do.
+  ASSERT(av_.IsEmpty());
+}
+
+
+void AssignedVariablesAnalyzer::VisitObjectLiteral(ObjectLiteral* expr) {
+  ASSERT(av_.IsEmpty());
+  BitVector result(av_.length());
+  for (int i = 0; i < expr->properties()->length(); i++) {
+    Visit(expr->properties()->at(i)->value());
+    result.Union(av_);
+    av_.Clear();
+  }
+  av_.CopyFrom(result);
+}
+
+
+void AssignedVariablesAnalyzer::VisitArrayLiteral(ArrayLiteral* expr) {
+  ASSERT(av_.IsEmpty());
+  BitVector result(av_.length());
+  for (int i = 0; i < expr->values()->length(); i++) {
+    Visit(expr->values()->at(i));
+    result.Union(av_);
+    av_.Clear();
+  }
+  av_.CopyFrom(result);
+}
+
+
+void AssignedVariablesAnalyzer::VisitCatchExtensionObject(
+    CatchExtensionObject* expr) {
+  ASSERT(av_.IsEmpty());
+  Visit(expr->key());
+  ProcessExpression(expr->value());
+}
+
+
+void AssignedVariablesAnalyzer::VisitAssignment(Assignment* expr) {
+  ASSERT(av_.IsEmpty());
+
+  if (expr->target()->AsProperty() != NULL) {
+    // Visit receiver and key of property store and rhs.
+    Visit(expr->target()->AsProperty()->obj());
+    ProcessExpression(expr->target()->AsProperty()->key());
+    ProcessExpression(expr->value());
+
+    // If we have a variable as a receiver in a property store, check if
+    // we can mark it as trivial.
+    MarkIfTrivial(expr->target()->AsProperty()->obj());
+  } else {
+    Visit(expr->target());
+    ProcessExpression(expr->value());
+
+    Variable* var = expr->target()->AsVariableProxy()->AsVariable();
+    if (var != NULL) RecordAssignedVar(var);
+  }
+}
+
+
+void AssignedVariablesAnalyzer::VisitThrow(Throw* expr) {
+  ASSERT(av_.IsEmpty());
+  Visit(expr->exception());
+}
+
+
+void AssignedVariablesAnalyzer::VisitProperty(Property* expr) {
+  ASSERT(av_.IsEmpty());
+  Visit(expr->obj());
+  ProcessExpression(expr->key());
+
+  // In case we have a variable as a receiver, check if we can mark
+  // it as trivial.
+  MarkIfTrivial(expr->obj());
+}
+
+
+void AssignedVariablesAnalyzer::VisitCall(Call* expr) {
+  ASSERT(av_.IsEmpty());
+  Visit(expr->expression());
+  BitVector result(av_);
+  for (int i = 0; i < expr->arguments()->length(); i++) {
+    av_.Clear();
+    Visit(expr->arguments()->at(i));
+    result.Union(av_);
+  }
+  av_.CopyFrom(result);
+}
+
+
+void AssignedVariablesAnalyzer::VisitCallNew(CallNew* expr) {
+  ASSERT(av_.IsEmpty());
+  Visit(expr->expression());
+  BitVector result(av_);
+  for (int i = 0; i < expr->arguments()->length(); i++) {
+    av_.Clear();
+    Visit(expr->arguments()->at(i));
+    result.Union(av_);
+  }
+  av_.CopyFrom(result);
+}
+
+
+void AssignedVariablesAnalyzer::VisitCallRuntime(CallRuntime* expr) {
+  ASSERT(av_.IsEmpty());
+  BitVector result(av_);
+  for (int i = 0; i < expr->arguments()->length(); i++) {
+    av_.Clear();
+    Visit(expr->arguments()->at(i));
+    result.Union(av_);
+  }
+  av_.CopyFrom(result);
+}
+
+
+void AssignedVariablesAnalyzer::VisitUnaryOperation(UnaryOperation* expr) {
+  ASSERT(av_.IsEmpty());
+  Visit(expr->expression());
+}
+
+
+void AssignedVariablesAnalyzer::VisitCountOperation(CountOperation* expr) {
+  ASSERT(av_.IsEmpty());
+
+  Visit(expr->expression());
+
+  Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
+  if (var != NULL) RecordAssignedVar(var);
+}
+
+
+void AssignedVariablesAnalyzer::VisitBinaryOperation(BinaryOperation* expr) {
+  ASSERT(av_.IsEmpty());
+  Visit(expr->left());
+
+  ProcessExpression(expr->right());
+
+  // In case we have a variable on the left side, check if we can mark
+  // it as trivial.
+  MarkIfTrivial(expr->left());
+}
+
+
+void AssignedVariablesAnalyzer::VisitCompareOperation(CompareOperation* expr) {
+  ASSERT(av_.IsEmpty());
+  Visit(expr->left());
+
+  ProcessExpression(expr->right());
+
+  // In case we have a variable on the left side, check if we can mark
+  // it as trivial.
+  MarkIfTrivial(expr->left());
+}
+
+
+void AssignedVariablesAnalyzer::VisitThisFunction(ThisFunction* expr) {
+  // Nothing to do.
+  ASSERT(av_.IsEmpty());
+}
+
+
+void AssignedVariablesAnalyzer::VisitDeclaration(Declaration* decl) {
+  UNREACHABLE();
+}
+
+
 #ifdef DEBUG
 
 // Print a textual representation of an instruction in a flow graph.  Using
@@ -1105,7 +1492,10 @@
 // only used for printing in debug mode.
 class TextInstructionPrinter: public AstVisitor {
  public:
-  TextInstructionPrinter() {}
+  TextInstructionPrinter() : number_(0) {}
+
+  int NextNumber() { return number_; }
+  void AssignNumber(AstNode* node) { node->set_num(number_++); }
 
  private:
   // AST node visit functions.
@@ -1113,6 +1503,8 @@
   AST_NODE_LIST(DECLARE_VISIT)
 #undef DECLARE_VISIT
 
+  int number_;
+
   DISALLOW_COPY_AND_ASSIGN(TextInstructionPrinter);
 };
 
@@ -1233,8 +1625,7 @@
 void TextInstructionPrinter::VisitVariableProxy(VariableProxy* expr) {
   Variable* var = expr->AsVariable();
   if (var != NULL) {
-    SmartPointer<char> name = var->name()->ToCString();
-    PrintF("%s", *name);
+    PrintF("%s", *var->name()->ToCString());
   } else {
     ASSERT(expr->AsProperty() != NULL);
     VisitProperty(expr->AsProperty());
@@ -1273,9 +1664,8 @@
   Property* prop = expr->target()->AsProperty();
 
   if (var != NULL) {
-    SmartPointer<char> name = var->name()->ToCString();
     PrintF("%s %s @%d",
-           *name,
+           *var->name()->ToCString(),
            Token::String(expr->op()),
            expr->value()->num());
   } else if (prop != NULL) {
@@ -1297,6 +1687,10 @@
     // Throw reference error.
     Visit(expr->target());
   }
+
+  if (expr->num() != AstNode::kNoNumber) {
+    PrintF(" ;; D%d", expr->num());
+  }
 }
 
 
@@ -1339,8 +1733,7 @@
 
 
 void TextInstructionPrinter::VisitCallRuntime(CallRuntime* expr) {
-  SmartPointer<char> name = expr->name()->ToCString();
-  PrintF("%s(", *name);
+  PrintF("%s(", *expr->name()->ToCString());
   ZoneList<Expression*>* arguments = expr->arguments();
   for (int i = 0, len = arguments->length(); i < len; i++) {
     if (i != 0) PrintF(", ");
@@ -1361,6 +1754,10 @@
   } else {
     PrintF("@%d%s", expr->expression()->num(), Token::String(expr->op()));
   }
+
+  if (expr->num() != AstNode::kNoNumber) {
+    PrintF(" ;; D%d", expr->num());
+  }
 }
 
 
@@ -1392,36 +1789,66 @@
 static int instruction_count = 0;
 
 
-void Node::AssignNumbers() {
+void Node::AssignNodeNumber() {
   set_number(node_count++);
 }
 
 
-void BlockNode::AssignNumbers() {
-  set_number(node_count++);
-  for (int i = 0, len = instructions_.length(); i < len; i++) {
-    instructions_[i]->set_num(instruction_count++);
+void Node::PrintReachingDefinitions() {
+  if (rd_.rd_in() != NULL) {
+    ASSERT(rd_.kill() != NULL && rd_.gen() != NULL);
+
+    PrintF("RD_in = {");
+    bool first = true;
+    for (int i = 0; i < rd_.rd_in()->length(); i++) {
+      if (rd_.rd_in()->Contains(i)) {
+        if (!first) PrintF(",");
+        PrintF("%d");
+        first = false;
+      }
+    }
+    PrintF("}\n");
+
+    PrintF("RD_kill = {");
+    first = true;
+    for (int i = 0; i < rd_.kill()->length(); i++) {
+      if (rd_.kill()->Contains(i)) {
+        if (!first) PrintF(",");
+        PrintF("%d");
+        first = false;
+      }
+    }
+    PrintF("}\n");
+
+    PrintF("RD_gen = {");
+    first = true;
+    for (int i = 0; i < rd_.gen()->length(); i++) {
+      if (rd_.gen()->Contains(i)) {
+        if (!first) PrintF(",");
+        PrintF("%d");
+        first = false;
+      }
+    }
+    PrintF("}\n");
   }
 }
 
 
-void EntryNode::PrintText() {
-  PrintF("L%d: Entry\n", number());
-  PrintF("goto L%d\n\n", successor_->number());
-}
-
 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++) {
-    PrintF("%d ", instructions_[i]->num());
+    PrintF("%d ", printer.NextNumber());
     printer.Visit(instructions_[i]);
+    printer.AssignNumber(instructions_[i]);
     PrintF("\n");
   }
   PrintF("goto L%d\n\n", successor_->number());
@@ -1429,12 +1856,14 @@
 
 
 void BranchNode::PrintText() {
+  PrintReachingDefinitions();
   PrintF("L%d: Branch\n", number());
   PrintF("goto (L%d, L%d)\n\n", successor0_->number(), successor1_->number());
 }
 
 
 void JoinNode::PrintText() {
+  PrintReachingDefinitions();
   PrintF("L%d: Join(", number());
   for (int i = 0, len = predecessors_.length(); i < len; i++) {
     if (i != 0) PrintF(", ");
@@ -1451,7 +1880,7 @@
   node_count = 0;
   instruction_count = 0;
   for (int i = postorder->length() - 1; i >= 0; i--) {
-    postorder->at(i)->AssignNumbers();
+    postorder->at(i)->AssignNodeNumber();
   }
 
   // Print basic blocks in reverse postorder.
@@ -1464,4 +1893,231 @@
 #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 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 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);
+
+  for (int i = 0; i < instruction_count; i++) {
+    Expression* expr = instructions_[i]->AsExpression();
+    if (expr == NULL) continue;
+    Variable* var = expr->AssignedVar();
+    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);
+
+    // 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 ExitNode::ComputeRDOut(BitVector* result) {
+  // Should not be the predecessor of any node.
+  UNREACHABLE();
+}
+
+
+void BlockNode::ComputeRDOut(BitVector* result) {
+  // All definitions reaching this block ...
+  result->CopyFrom(*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 BranchNode::ComputeRDOut(BitVector* result) {
+  // Branch nodes don't kill or generate definitions.
+  result->CopyFrom(*rd_.rd_in());
+}
+
+
+void JoinNode::ComputeRDOut(BitVector* result) {
+  // Join nodes don't kill or generate definitions.
+  result->CopyFrom(*rd_.rd_in());
+}
+
+
+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 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);
+
+  if (rd_.rd_in()->Equals(new_rd_in)) return;
+
+  // Update RD_in.
+  rd_.rd_in()->CopyFrom(new_rd_in);
+  // Add the successor to the worklist if not already present.
+  if (!successor_->IsMarkedWith(mark)) {
+    successor_->MarkWith(mark);
+    worklist->Insert(successor_);
+  }
+}
+
+
+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;
+
+  // Update RD_in.
+  rd_.rd_in()->CopyFrom(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 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);
+  }
+
+  if (rd_.rd_in()->Equals(new_rd_in)) return;
+
+  // Update RD_in.
+  rd_.rd_in()->CopyFrom(new_rd_in);
+  // Add the successor to the worklist if not already present.
+  if (!successor_->IsMarkedWith(mark)) {
+    successor_->MarkWith(mark);
+    worklist->Insert(successor_);
+  }
+}
+
+
+void ReachingDefinitions::Compute() {
+  ASSERT(!definitions_->is_empty());
+
+  int variable_count = variables_.length();
+  int definition_count = definitions_->length();
+  int node_count = postorder_->length();
+
+  // Step 1: For each variable, identify the set of all its definitions in
+  // the body.
+  for (int i = 0; i < definition_count; i++) {
+    Variable* var = definitions_->at(i)->AssignedVar();
+    variables_[IndexFor(var, variable_count)]->Add(i);
+  }
+
+  if (FLAG_print_graph_text) {
+    for (int i = 0; i < variable_count; i++) {
+      BitVector* def_set = variables_[i];
+      if (!def_set->IsEmpty()) {
+        // At least one definition.
+        bool first = true;
+        for (int j = 0; j < definition_count; j++) {
+          if (def_set->Contains(j)) {
+            if (first) {
+              Variable* var = definitions_->at(j)->AssignedVar();
+              ASSERT(var != NULL);
+              PrintF("Def[%s] = {%d", *var->name()->ToCString(), j);
+              first = false;
+            } else {
+              PrintF(", %d", j);
+            }
+          }
+        }
+        PrintF("}\n");
+      }
+    }
+  }
+
+  // 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);
+  }
+}
+
+
 } }  // namespace v8::internal
diff --git a/src/data-flow.h b/src/data-flow.h
index 2dc2d73..236d0ad 100644
--- a/src/data-flow.h
+++ b/src/data-flow.h
@@ -100,6 +100,13 @@
     }
   }
 
+  void Subtract(const BitVector& other) {
+    ASSERT(other.length() == length());
+    for (int i = 0; i < data_length_; i++) {
+      data_[i] &= ~other.data_[i];
+    }
+  }
+
   void Clear() {
     for (int i = 0; i < data_length_; i++) {
       data_[i] = 0;
@@ -113,6 +120,13 @@
     return true;
   }
 
+  bool Equals(const BitVector& other) {
+    for (int i = 0; i < data_length_; i++) {
+      if (data_[i] != other.data_[i]) return false;
+    }
+    return true;
+  }
+
   int length() const { return length_; }
 
  private:
@@ -122,56 +136,68 @@
 };
 
 
-// Forward declarations of Node types.
-class Node;
-class BranchNode;
-class 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 {
+// Simple fixed-capacity list-based worklist (managed as a queue) of
+// pointers to T.
+template<typename T>
+class WorkList BASE_EMBEDDED {
  public:
-  FlowGraph() : entry_(NULL), exit_(NULL) {}
+  // The worklist cannot grow bigger than size.  We keep one item empty to
+  // distinguish between empty and full.
+  explicit WorkList(int size)
+      : capacity_(size + 1), head_(0), tail_(0), queue_(capacity_) {
+    for (int i = 0; i < capacity_; i++) queue_.Add(NULL);
+  }
 
-  static FlowGraph Empty() { return FlowGraph(); }
+  bool is_empty() { return head_ == tail_; }
 
-  bool is_empty() const { return entry_ == NULL; }
-  Node* entry() const { return entry_; }
-  Node* exit() const { return exit_; }
+  bool is_full() {
+    // The worklist is full if head is at 0 and tail is at capacity - 1:
+    //   head == 0 && tail == capacity-1 ==> tail - head == capacity - 1
+    // or if tail is immediately to the left of head:
+    //   tail+1 == head  ==> tail - head == -1
+    int diff = tail_ - head_;
+    return (diff == -1 || diff == capacity_ - 1);
+  }
 
-  // Add a single instruction to the end of this flowgraph.
-  void AppendInstruction(AstNode* instruction);
+  void Insert(T* item) {
+    ASSERT(!is_full());
+    queue_[tail_++] = item;
+    if (tail_ == capacity_) tail_ = 0;
+  }
 
-  // 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(ZoneList<Node*>* postorder);
-#endif
+  T* Remove() {
+    ASSERT(!is_empty());
+    T* item = queue_[head_++];
+    if (head_ == capacity_) head_ = 0;
+    return item;
+  }
 
  private:
-  Node* entry_;
-  Node* exit_;
+  int capacity_;  // Including one empty slot.
+  int head_;      // Where the first item is.
+  int tail_;      // Where the next inserted item will go.
+  List<T*> queue_;
+};
+
+
+struct ReachingDefinitionsData BASE_EMBEDDED {
+ public:
+  ReachingDefinitionsData() : rd_in_(NULL), kill_(NULL), gen_(NULL) {}
+
+  void Initialize(int definition_count) {
+    rd_in_ = new BitVector(definition_count);
+    kill_ = new BitVector(definition_count);
+    gen_ = new BitVector(definition_count);
+  }
+
+  BitVector* rd_in() { return rd_in_; }
+  BitVector* kill() { return kill_; }
+  BitVector* gen() { return gen_; }
+
+ private:
+  BitVector* rd_in_;
+  BitVector* kill_;
+  BitVector* gen_;
 };
 
 
@@ -182,7 +208,9 @@
 
   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;
@@ -200,11 +228,23 @@
   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;
+
 #ifdef DEBUG
-  virtual void AssignNumbers();
+  void AssignNodeNumber();
+  void PrintReachingDefinitions();
   virtual void PrintText() = 0;
 #endif
 
+ protected:
+  ReachingDefinitionsData rd_;
+
  private:
   int number_;
   bool mark_;
@@ -213,49 +253,27 @@
 };
 
 
-// An entry node has no predecessors and a single successor.
-class EntryNode: public Node {
- public:
-  EntryNode() : successor_(NULL) {}
-
-  void AddPredecessor(Node* predecessor) { UNREACHABLE(); }
-
-  void AddSuccessor(Node* successor) {
-    ASSERT(successor_ == NULL && successor != NULL);
-    successor_ = successor;
-  }
-
-  void Traverse(bool mark,
-                ZoneList<Node*>* preorder,
-                ZoneList<Node*>* postorder);
-
-#ifdef DEBUG
-  void PrintText();
-#endif
-
- private:
-  Node* successor_;
-
-  DISALLOW_COPY_AND_ASSIGN(EntryNode);
-};
-
-
 // An exit node has a arbitrarily many predecessors and no successors.
 class ExitNode: public Node {
  public:
   ExitNode() : predecessors_(4) {}
 
+  bool IsExitNode() { return true; }
+
   void AddPredecessor(Node* predecessor) {
     ASSERT(predecessor != NULL);
     predecessors_.Add(predecessor);
   }
 
-  void AddSuccessor(Node* successor) { /* Do nothing. */ }
+  void AddSuccessor(Node* successor) { UNREACHABLE(); }
 
   void Traverse(bool mark,
                 ZoneList<Node*>* preorder,
                 ZoneList<Node*>* postorder);
 
+  void ComputeRDOut(BitVector* result);
+  void UpdateRDIn(WorkList<Node>* worklist, bool mark);
+
 #ifdef DEBUG
   void PrintText();
 #endif
@@ -280,6 +298,8 @@
 
   bool IsBlockNode() { return true; }
 
+  bool is_empty() { return instructions_.is_empty(); }
+
   void AddPredecessor(Node* predecessor) {
     ASSERT(predecessor_ == NULL && predecessor != NULL);
     predecessor_ = predecessor;
@@ -298,8 +318,14 @@
                 ZoneList<Node*>* preorder,
                 ZoneList<Node*>* postorder);
 
+  void InitializeReachingDefinitions(int definition_count,
+                                     List<BitVector*>* variables,
+                                     WorkList<Node>* worklist,
+                                     bool mark);
+  void ComputeRDOut(BitVector* result);
+  void UpdateRDIn(WorkList<Node>* worklist, bool mark);
+
 #ifdef DEBUG
-  void AssignNumbers();
   void PrintText();
 #endif
 
@@ -317,6 +343,8 @@
  public:
   BranchNode() : predecessor_(NULL), successor0_(NULL), successor1_(NULL) {}
 
+  bool IsBranchNode() { return true; }
+
   void AddPredecessor(Node* predecessor) {
     ASSERT(predecessor_ == NULL && predecessor != NULL);
     predecessor_ = predecessor;
@@ -335,6 +363,9 @@
                 ZoneList<Node*>* preorder,
                 ZoneList<Node*>* postorder);
 
+  void ComputeRDOut(BitVector* result);
+  void UpdateRDIn(WorkList<Node>* worklist, bool mark);
+
 #ifdef DEBUG
   void PrintText();
 #endif
@@ -374,6 +405,9 @@
                 ZoneList<Node*>* preorder,
                 ZoneList<Node*>* postorder);
 
+  void ComputeRDOut(BitVector* result);
+  void UpdateRDIn(WorkList<Node>* worklist, bool mark);
+
 #ifdef DEBUG
   void PrintText();
 #endif
@@ -386,12 +420,68 @@
 };
 
 
+// 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(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:
   FlowGraphBuilder()
-      : global_exit_(NULL),
+      : graph_(FlowGraph::Empty()),
+        global_exit_(NULL),
         preorder_(4),
         postorder_(4),
         definitions_(4) {
@@ -400,8 +490,8 @@
   void Build(FunctionLiteral* lit);
 
   FlowGraph* graph() { return &graph_; }
-
   ZoneList<Node*>* postorder() { return &postorder_; }
+  ZoneList<Expression*>* definitions() { return &definitions_; }
 
  private:
   ExitNode* global_exit() { return global_exit_; }
@@ -418,8 +508,9 @@
 
   // The flow graph builder collects a list of definitions (assignments and
   // count operations) to stack-allocated variables to use for reaching
-  // definitions analysis.
-  ZoneList<AstNode*> definitions_;
+  // definitions analysis.  AST node numbers in the AST are used to refer
+  // into this list.
+  ZoneList<Expression*> definitions_;
 
   DISALLOW_COPY_AND_ASSIGN(FlowGraphBuilder);
 };
@@ -502,6 +593,74 @@
 };
 
 
+// Computes the set of assigned variables and annotates variables proxies
+// that are trivial sub-expressions and for-loops where the loop variable
+// is guaranteed to be a smi.
+class AssignedVariablesAnalyzer : public AstVisitor {
+ public:
+  explicit AssignedVariablesAnalyzer(FunctionLiteral* fun);
+
+  void Analyze();
+
+ private:
+  Variable* FindSmiLoopVariable(ForStatement* stmt);
+
+  int BitIndex(Variable* var);
+
+  void RecordAssignedVar(Variable* var);
+
+  void MarkIfTrivial(Expression* expr);
+
+  // Visits an expression saving the accumulator before, clearing
+  // it before visting and restoring it after visiting.
+  void ProcessExpression(Expression* expr);
+
+  // AST node visit functions.
+#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
+  AST_NODE_LIST(DECLARE_VISIT)
+#undef DECLARE_VISIT
+
+  FunctionLiteral* fun_;
+
+  // Accumulator for assigned variables set.
+  BitVector av_;
+
+  DISALLOW_COPY_AND_ASSIGN(AssignedVariablesAnalyzer);
+};
+
+
+class ReachingDefinitions BASE_EMBEDDED {
+ public:
+  ReachingDefinitions(ZoneList<Node*>* postorder,
+                      ZoneList<Expression*>* definitions,
+                      int variable_count)
+      : postorder_(postorder),
+        definitions_(definitions),
+        variables_(variable_count) {
+    int definition_count = definitions->length();
+    for (int i = 0; i < variable_count; i++) {
+      variables_.Add(new BitVector(definition_count));
+    }
+  }
+
+  static int IndexFor(Variable* var, int variable_count);
+
+  void Compute();
+
+ private:
+  // A (postorder) list of flow-graph nodes in the body.
+  ZoneList<Node*>* postorder_;
+
+  // A list of all the definitions in the body.
+  ZoneList<Expression*>* definitions_;
+
+  // For each variable, the set of all its definitions.
+  List<BitVector*> variables_;
+
+  DISALLOW_COPY_AND_ASSIGN(ReachingDefinitions);
+};
+
+
 } }  // namespace v8::internal
 
 
diff --git a/src/date-delay.js b/src/date-delay.js
index c0180c2..f2ea1ec 100644
--- a/src/date-delay.js
+++ b/src/date-delay.js
@@ -293,55 +293,48 @@
 }
 
 
-// Constructor for creating objects holding year, month, and date.
-// Introduced to ensure the two return points in FromJulianDay match same map.
-function DayTriplet(year, month, date) {
-  this.year = year;
-  this.month = month;
-  this.date = date;
+var ymd_from_time_cache = [$NaN, $NaN, $NaN];
+var ymd_from_time_cached_time = $NaN;
+
+function YearFromTime(t) {
+  if (t !== ymd_from_time_cached_time) {
+    // Limits according to ECMA 262 15.9.1.1
+    if (!$isFinite(t) || t < -8640000000000000 || t > 8640000000000000) {
+      return $NaN;
+    }
+
+    %DateYMDFromTime(t, ymd_from_time_cache);
+    ymd_from_time_cached_time = t
+  }
+
+  return ymd_from_time_cache[0];
 }
 
-var julian_day_cache_triplet;
-var julian_day_cache_day = $NaN;
+function MonthFromTime(t) {
+  if (t !== ymd_from_time_cached_time) {
+    // Limits according to ECMA 262 15.9.1.1
+    if (!$isFinite(t) || t < -8640000000000000 || t > 8640000000000000) {
+      return $NaN;
+    }
+    %DateYMDFromTime(t, ymd_from_time_cache);
+    ymd_from_time_cached_time = t
+  }
 
-// Compute year, month, and day from modified Julian day.
-// The missing days in 1582 are ignored for JavaScript compatibility.
-function FromJulianDay(julian) {
-  if (julian_day_cache_day == julian) {
-    return julian_day_cache_triplet;
+  return ymd_from_time_cache[1];
+}
+
+function DateFromTime(t) {
+  if (t !== ymd_from_time_cached_time) {
+    // Limits according to ECMA 262 15.9.1.1
+    if (!$isFinite(t) || t < -8640000000000000 || t > 8640000000000000) {
+      return $NaN;
+    }
+
+    %DateYMDFromTime(t, ymd_from_time_cache);
+    ymd_from_time_cached_time = t
   }
-  var result;
-  // Avoid floating point and non-Smi maths in common case.  This is also a period of
-  // time where leap years are very regular.  The range is not too large to avoid overflow
-  // when doing the multiply-to-divide trick.
-  if (julian > kDayZeroInJulianDay &&
-      (julian - kDayZeroInJulianDay) < 40177) { // 1970 - 2080
-    var jsimple = (julian - kDayZeroInJulianDay) + 731; // Day 0 is 1st January 1968
-    var y = 1968;
-    // Divide by 1461 by multiplying with 22967 and shifting down by 25!
-    var after_1968 = (jsimple * 22967) >> 25;
-    y += after_1968 << 2;
-    jsimple -= 1461 * after_1968;
-    var four_year_cycle = four_year_cycle_table[jsimple];
-    result = new DayTriplet(y + (four_year_cycle >> kYearShift),
-                            (four_year_cycle & kMonthMask) >> kMonthShift,
-                            four_year_cycle & kDayMask);
-  } else {
-    var jalpha = FLOOR((julian - 1867216.25) / 36524.25);
-    var jb = julian + 1 + jalpha - FLOOR(0.25 * jalpha) + 1524;
-    var jc = FLOOR(6680.0 + ((jb-2439870) - 122.1)/365.25);
-    var jd = FLOOR(365 * jc + (0.25 * jc));
-    var je = FLOOR((jb - jd)/30.6001);
-    var m = je - 1;
-    if (m > 12) m -= 13;
-    var y = jc - 4715;
-    if (m > 2) { --y; --m; }
-    var d = jb - jd - FLOOR(30.6001 * je);
-    result = new DayTriplet(y, m, d);
-  }
-  julian_day_cache_day = julian;
-  julian_day_cache_triplet = result;
-  return result;
+
+  return ymd_from_time_cache[2];
 }
 
 
@@ -577,11 +570,10 @@
 
 
 function DateString(time) {
-  var YMD = FromJulianDay(DAY(time) + kDayZeroInJulianDay);
   return WeekDays[WeekDay(time)] + ' '
-      + Months[YMD.month] + ' '
-      + TwoDigitString(YMD.date) + ' '
-      + YMD.year;
+      + Months[MonthFromTime(time)] + ' '
+      + TwoDigitString(DateFromTime(time)) + ' '
+      + YearFromTime(time);
 }
 
 
@@ -590,11 +582,10 @@
 
 
 function LongDateString(time) {
-  var YMD = FromJulianDay(DAY(time) + kDayZeroInJulianDay);
   return LongWeekDays[WeekDay(time)] + ', '
-      + LongMonths[YMD.month] + ' '
-      + TwoDigitString(YMD.date) + ', '
-      + YMD.year;
+      + LongMonths[MonthFromTime(time)] + ' '
+      + TwoDigitString(DateFromTime(time)) + ', '
+      + YearFromTime(time);
 }
 
 
diff --git a/src/debug.cc b/src/debug.cc
index 959bea1..81752e6 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -803,7 +803,7 @@
 
 
 void Debug::Iterate(ObjectVisitor* v) {
-  v->VisitPointer(bit_cast<Object**, Code**>(&(debug_break_return_)));
+  v->VisitPointer(BitCast<Object**, Code**>(&(debug_break_return_)));
 }
 
 
diff --git a/src/diy_fp.h b/src/diy_fp.h
new file mode 100644
index 0000000..9cd7003
--- /dev/null
+++ b/src/diy_fp.h
@@ -0,0 +1,136 @@
+// 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_DIY_FP_H_
+#define V8_DIY_FP_H_
+
+namespace v8 {
+namespace internal {
+
+// This "Do It Yourself Floating Point" class implements a floating-point number
+// with a uint64 significand and an int exponent. Normalized DiyFp numbers will
+// have the most significant bit of the significand set.
+// Multiplication and Subtraction do not normalize their results.
+// DiyFp are not designed to contain special doubles (NaN and Infinity).
+class DiyFp {
+ public:
+  static const int kSignificandSize = 64;
+
+  DiyFp() : f_(0), e_(0) {}
+  DiyFp(uint64_t f, int e) : f_(f), e_(e) {}
+
+  // this = this - other.
+  // The exponents of both numbers must be the same and the significand of this
+  // must be bigger than the significand of other.
+  // The result will not be normalized.
+  void Subtract(const DiyFp& other) {
+    ASSERT(e_ == other.e_);
+    ASSERT(f_ >= other.f_);
+    f_ -= other.f_;
+  }
+
+  // Returns a - b.
+  // The exponents of both numbers must be the same and this must be bigger
+  // than other. The result will not be normalized.
+  static DiyFp Minus(const DiyFp& a, const DiyFp& b) {
+    DiyFp result = a;
+    result.Subtract(b);
+    return result;
+  }
+
+
+  // this = this * other.
+  void Multiply(const DiyFp& other) {
+    // Simply "emulates" a 128 bit multiplication.
+    // However: the resulting number only contains 64 bits. The least
+    // significant 64 bits are only used for rounding the most significant 64
+    // bits.
+    const uint64_t kM32 = 0xFFFFFFFFu;
+    uint64_t a = f_ >> 32;
+    uint64_t b = f_ & kM32;
+    uint64_t c = other.f_ >> 32;
+    uint64_t d = other.f_ & kM32;
+    uint64_t ac = a * c;
+    uint64_t bc = b * c;
+    uint64_t ad = a * d;
+    uint64_t bd = b * d;
+    uint64_t tmp = (bd >> 32) + (ad & kM32) + (bc & kM32);
+    tmp += 1U << 31;  // round
+    uint64_t result_f = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32);
+    e_ += other.e_ + 64;
+    f_ = result_f;
+  }
+
+  // returns a * b;
+  static DiyFp Times(const DiyFp& a, const DiyFp& b) {
+    DiyFp result = a;
+    result.Multiply(b);
+    return result;
+  }
+
+  void Normalize() {
+    ASSERT(f_ != 0);
+    uint64_t f = f_;
+    int e = e_;
+
+    // This method is mainly called for normalizing boundaries. In general
+    // boundaries need to be shifted by 10 bits. We thus optimize for this case.
+    const uint64_t k10MSBits = V8_2PART_UINT64_C(0xFFC00000, 00000000);
+    while ((f & k10MSBits) == 0) {
+      f <<= 10;
+      e -= 10;
+    }
+    while ((f & kUint64MSB) == 0) {
+      f <<= 1;
+      e--;
+    }
+    f_ = f;
+    e_ = e;
+  }
+
+  static DiyFp Normalize(const DiyFp& a) {
+    DiyFp result = a;
+    result.Normalize();
+    return result;
+  }
+
+  uint64_t f() const { return f_; }
+  int e() const { return e_; }
+
+  void set_f(uint64_t new_value) { f_ = new_value; }
+  void set_e(int new_value) { e_ = new_value; }
+
+ private:
+  static const uint64_t kUint64MSB = V8_2PART_UINT64_C(0x80000000, 00000000);
+
+  uint64_t f_;
+  int e_;
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_DIY_FP_H_
diff --git a/src/double.h b/src/double.h
new file mode 100644
index 0000000..f3d17b9
--- /dev/null
+++ b/src/double.h
@@ -0,0 +1,169 @@
+// 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_DOUBLE_H_
+#define V8_DOUBLE_H_
+
+#include "diy_fp.h"
+
+namespace v8 {
+namespace internal {
+
+// We assume that doubles and uint64_t have the same endianness.
+static uint64_t double_to_uint64(double d) { return BitCast<uint64_t>(d); }
+static double uint64_to_double(uint64_t d64) { return BitCast<double>(d64); }
+
+// Helper functions for doubles.
+class Double {
+ public:
+  static const uint64_t kSignMask = V8_2PART_UINT64_C(0x80000000, 00000000);
+  static const uint64_t kExponentMask = V8_2PART_UINT64_C(0x7FF00000, 00000000);
+  static const uint64_t kSignificandMask =
+      V8_2PART_UINT64_C(0x000FFFFF, FFFFFFFF);
+  static const uint64_t kHiddenBit = V8_2PART_UINT64_C(0x00100000, 00000000);
+
+  Double() : d64_(0) {}
+  explicit Double(double d) : d64_(double_to_uint64(d)) {}
+  explicit Double(uint64_t d64) : d64_(d64) {}
+
+  DiyFp AsDiyFp() const {
+    ASSERT(!IsSpecial());
+    return DiyFp(Significand(), Exponent());
+  }
+
+  // this->Significand() must not be 0.
+  DiyFp AsNormalizedDiyFp() const {
+    uint64_t f = Significand();
+    int e = Exponent();
+
+    ASSERT(f != 0);
+
+    // The current double could be a denormal.
+    while ((f & kHiddenBit) == 0) {
+      f <<= 1;
+      e--;
+    }
+    // Do the final shifts in one go. Don't forget the hidden bit (the '-1').
+    f <<= DiyFp::kSignificandSize - kSignificandSize - 1;
+    e -= DiyFp::kSignificandSize - kSignificandSize - 1;
+    return DiyFp(f, e);
+  }
+
+  // Returns the double's bit as uint64.
+  uint64_t AsUint64() const {
+    return d64_;
+  }
+
+  int Exponent() const {
+    if (IsDenormal()) return kDenormalExponent;
+
+    uint64_t d64 = AsUint64();
+    int biased_e = static_cast<int>((d64 & kExponentMask) >> kSignificandSize);
+    return biased_e - kExponentBias;
+  }
+
+  uint64_t Significand() const {
+    uint64_t d64 = AsUint64();
+    uint64_t significand = d64 & kSignificandMask;
+    if (!IsDenormal()) {
+      return significand + kHiddenBit;
+    } else {
+      return significand;
+    }
+  }
+
+  // Returns true if the double is a denormal.
+  bool IsDenormal() const {
+    uint64_t d64 = AsUint64();
+    return (d64 & kExponentMask) == 0;
+  }
+
+  // We consider denormals not to be special.
+  // Hence only Infinity and NaN are special.
+  bool IsSpecial() const {
+    uint64_t d64 = AsUint64();
+    return (d64 & kExponentMask) == kExponentMask;
+  }
+
+  bool IsNan() const {
+    uint64_t d64 = AsUint64();
+    return ((d64 & kExponentMask) == kExponentMask) &&
+        ((d64 & kSignificandMask) != 0);
+  }
+
+
+  bool IsInfinite() const {
+    uint64_t d64 = AsUint64();
+    return ((d64 & kExponentMask) == kExponentMask) &&
+        ((d64 & kSignificandMask) == 0);
+  }
+
+
+  int Sign() const {
+    uint64_t d64 = AsUint64();
+    return (d64 & kSignMask) == 0? 1: -1;
+  }
+
+
+  // Returns the two boundaries of this.
+  // The bigger boundary (m_plus) is normalized. The lower boundary has the same
+  // exponent as m_plus.
+  void NormalizedBoundaries(DiyFp* out_m_minus, DiyFp* out_m_plus) const {
+    DiyFp v = this->AsDiyFp();
+    bool significand_is_zero = (v.f() == kHiddenBit);
+    DiyFp m_plus = DiyFp::Normalize(DiyFp((v.f() << 1) + 1, v.e() - 1));
+    DiyFp m_minus;
+    if (significand_is_zero && v.e() != kDenormalExponent) {
+      // The boundary is closer. Think of v = 1000e10 and v- = 9999e9.
+      // Then the boundary (== (v - v-)/2) is not just at a distance of 1e9 but
+      // at a distance of 1e8.
+      // The only exception is for the smallest normal: the largest denormal is
+      // at the same distance as its successor.
+      // Note: denormals have the same exponent as the smallest normals.
+      m_minus = DiyFp((v.f() << 2) - 1, v.e() - 2);
+    } else {
+      m_minus = DiyFp((v.f() << 1) - 1, v.e() - 1);
+    }
+    m_minus.set_f(m_minus.f() << (m_minus.e() - m_plus.e()));
+    m_minus.set_e(m_plus.e());
+    *out_m_plus = m_plus;
+    *out_m_minus = m_minus;
+  }
+
+  double value() const { return uint64_to_double(d64_); }
+
+ private:
+  static const int kSignificandSize = 52;  // Excludes the hidden bit.
+  static const int kExponentBias = 0x3FF + kSignificandSize;
+  static const int kDenormalExponent = -kExponentBias + 1;
+
+  uint64_t d64_;
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_DOUBLE_H_
diff --git a/src/factory.cc b/src/factory.cc
index 8d20749..993e2b6 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -866,6 +866,7 @@
     map->set_instance_descriptors(*array);
   }
 
+  ASSERT(result->shared()->IsApiFunction());
   return result;
 }
 
diff --git a/src/factory.h b/src/factory.h
index 36911da..e08bde4 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -317,7 +317,7 @@
 
 #define ROOT_ACCESSOR(type, name, camel_name)                                  \
   static inline Handle<type> name() {                                          \
-    return Handle<type>(bit_cast<type**, Object**>(                            \
+    return Handle<type>(BitCast<type**, Object**>(                             \
         &Heap::roots_[Heap::k##camel_name##RootIndex]));                       \
   }
   ROOT_LIST(ROOT_ACCESSOR)
@@ -325,7 +325,7 @@
 
 #define SYMBOL_ACCESSOR(name, str) \
   static inline Handle<String> name() {                                        \
-    return Handle<String>(bit_cast<String**, Object**>(                        \
+    return Handle<String>(BitCast<String**, Object**>(                         \
         &Heap::roots_[Heap::k##name##RootIndex]));                             \
   }
   SYMBOL_LIST(SYMBOL_ACCESSOR)
diff --git a/src/globals.h b/src/globals.h
index 3840fee..6759a35 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -98,6 +98,11 @@
 #define V8_PTR_PREFIX ""
 #endif  // V8_HOST_ARCH_64_BIT
 
+// The following macro works on both 32 and 64-bit platforms.
+// Usage: instead of writing 0x1234567890123456
+//      write V8_2PART_UINT64_C(0x12345678,90123456);
+#define V8_2PART_UINT64_C(a, b) (((static_cast<uint64_t>(a) << 32) + 0x##b##u))
+
 #define V8PRIxPTR V8_PTR_PREFIX "x"
 #define V8PRIdPTR V8_PTR_PREFIX "d"
 
@@ -569,42 +574,6 @@
 #define INLINE(header) inline header
 #endif
 
-// The type-based aliasing rule allows the compiler to assume that pointers of
-// different types (for some definition of different) never alias each other.
-// Thus the following code does not work:
-//
-// float f = foo();
-// int fbits = *(int*)(&f);
-//
-// The compiler 'knows' that the int pointer can't refer to f since the types
-// don't match, so the compiler may cache f in a register, leaving random data
-// in fbits.  Using C++ style casts makes no difference, however a pointer to
-// char data is assumed to alias any other pointer.  This is the 'memcpy
-// exception'.
-//
-// Bit_cast uses the memcpy exception to move the bits from a variable of one
-// type of a variable of another type.  Of course the end result is likely to
-// be implementation dependent.  Most compilers (gcc-4.2 and MSVC 2005)
-// will completely optimize bit_cast away.
-//
-// There is an additional use for bit_cast.
-// Recent gccs will warn when they see casts that may result in breakage due to
-// the type-based aliasing rule.  If you have checked that there is no breakage
-// you can use bit_cast to cast one pointer type to another.  This confuses gcc
-// enough that it can no longer see that you have cast one pointer type to
-// another thus avoiding the warning.
-template <class Dest, class Source>
-inline Dest bit_cast(const Source& source) {
-  // Compile time assertion: sizeof(Dest) == sizeof(Source)
-  // A compile error here means your Dest and Source have different sizes.
-  typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1];
-
-  Dest dest;
-  memcpy(&dest, &source, sizeof(dest));
-  return dest;
-}
-
-
 // Feature flags bit positions. They are mostly based on the CPUID spec.
 // (We assign CPUID itself to one of the currently reserved bits --
 // feel free to change this if needed.)
diff --git a/src/grisu3.cc b/src/grisu3.cc
new file mode 100644
index 0000000..13c4932
--- /dev/null
+++ b/src/grisu3.cc
@@ -0,0 +1,494 @@
+// 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 "v8.h"
+
+#include "grisu3.h"
+
+#include "cached_powers.h"
+#include "diy_fp.h"
+#include "double.h"
+
+namespace v8 {
+namespace internal {
+
+template <int alpha = -60, int gamma = -32>
+class Grisu3 {
+ public:
+  // Provides a decimal representation of v.
+  // Returns true if it succeeds, otherwise the result can not be trusted.
+  // There will be *length digits inside the buffer (not null-terminated).
+  // If the function returns true then
+  //        v == (double) (buffer * 10^decimal_exponent).
+  // The digits in the buffer are the shortest representation possible: no
+  // 0.099999999999 instead of 0.1.
+  // The last digit will be closest to the actual v. That is, even if several
+  // digits might correctly yield 'v' when read again, the closest will be
+  // computed.
+  static bool grisu3(double v,
+                     char* buffer, int* length, int* decimal_exponent);
+
+ private:
+  // Rounds the buffer according to the rest.
+  // If there is too much imprecision to round then false is returned.
+  // Similarily false is returned when the buffer is not within Delta.
+  static bool RoundWeed(char* buffer, int len, uint64_t wp_W, uint64_t Delta,
+                        uint64_t rest, uint64_t ten_kappa, uint64_t ulp);
+  // Dispatches to the a specialized digit-generation routine. The chosen
+  // routine depends on w.e (which in turn depends on alpha and gamma).
+  // Currently there is only one digit-generation routine, but it would be easy
+  // to add others.
+  static bool DigitGen(DiyFp low, DiyFp w, DiyFp high,
+                       char* buffer, int* len, int* kappa);
+  // Generates w's digits. The result is the shortest in the interval low-high.
+  // All DiyFp are assumed to be imprecise and this function takes this
+  // imprecision into account. If the function cannot compute the best
+  // representation (due to the imprecision) then false is returned.
+  static bool DigitGen_m60_m32(DiyFp low, DiyFp w, DiyFp high,
+                               char* buffer, int* length, int* kappa);
+};
+
+
+template<int alpha, int gamma>
+bool Grisu3<alpha, gamma>::grisu3(double v,
+                                  char* buffer,
+                                  int* length,
+                                  int* decimal_exponent) {
+  DiyFp w = Double(v).AsNormalizedDiyFp();
+  // boundary_minus and boundary_plus are the boundaries between v and its
+  // neighbors. Any number strictly between boundary_minus and boundary_plus
+  // will round to v when read as double.
+  // Grisu3 will never output representations that lie exactly on a boundary.
+  DiyFp boundary_minus, boundary_plus;
+  Double(v).NormalizedBoundaries(&boundary_minus, &boundary_plus);
+  ASSERT(boundary_plus.e() == w.e());
+  DiyFp ten_mk;  // Cached power of ten: 10^-k
+  int mk;        // -k
+  GetCachedPower(w.e() + DiyFp::kSignificandSize, alpha, gamma, &mk, &ten_mk);
+  ASSERT(alpha <= w.e() + ten_mk.e() + DiyFp::kSignificandSize &&
+         gamma >= w.e() + ten_mk.e() + DiyFp::kSignificandSize);
+  // Note that ten_mk is only an approximation of 10^-k. A DiyFp only contains a
+  // 64 bit significand and ten_mk is thus only precise up to 64 bits.
+
+  // The DiyFp::Times procedure rounds its result, and ten_mk is approximated
+  // too. The variable scaled_w (as well as scaled_boundary_minus/plus) are now
+  // off by a small amount.
+  // In fact: scaled_w - w*10^k < 1ulp (unit in the last place) of scaled_w.
+  // In other words: let f = scaled_w.f() and e = scaled_w.e(), then
+  //           (f-1) * 2^e < w*10^k < (f+1) * 2^e
+  DiyFp scaled_w = DiyFp::Times(w, ten_mk);
+  ASSERT(scaled_w.e() ==
+         boundary_plus.e() + ten_mk.e() + DiyFp::kSignificandSize);
+  // In theory it would be possible to avoid some recomputations by computing
+  // the difference between w and boundary_minus/plus (a power of 2) and to
+  // compute scaled_boundary_minus/plus by subtracting/adding from
+  // scaled_w. However the code becomes much less readable and the speed
+  // enhancements are not terriffic.
+  DiyFp scaled_boundary_minus = DiyFp::Times(boundary_minus, ten_mk);
+  DiyFp scaled_boundary_plus  = DiyFp::Times(boundary_plus,  ten_mk);
+
+  // DigitGen will generate the digits of scaled_w. Therefore we have
+  // v == (double) (scaled_w * 10^-mk).
+  // Set decimal_exponent == -mk and pass it to DigitGen. If scaled_w is not an
+  // integer than it will be updated. For instance if scaled_w == 1.23 then
+  // the buffer will be filled with "123" und the decimal_exponent will be
+  // decreased by 2.
+  int kappa;
+  bool result = DigitGen(scaled_boundary_minus, scaled_w, scaled_boundary_plus,
+                         buffer, length, &kappa);
+  *decimal_exponent = -mk + kappa;
+  return result;
+}
+
+// Generates the digits of input number w.
+// w is a floating-point number (DiyFp), consisting of a significand and an
+// exponent. Its exponent is bounded by alpha and gamma. Typically alpha >= -63
+// and gamma <= 3.
+// Returns false if it fails, in which case the generated digits in the buffer
+// should not be used.
+// Preconditions:
+//  * low, w and high are correct up to 1 ulp (unit in the last place). That
+//    is, their error must be less that a unit of their last digits.
+//  * low.e() == w.e() == high.e()
+//  * low < w < high, and taking into account their error: low~ <= high~
+//  * alpha <= w.e() <= gamma
+// Postconditions: returns false if procedure fails.
+//   otherwise:
+//     * buffer is not null-terminated, but len contains the number of digits.
+//     * buffer contains the shortest possible decimal digit-sequence
+//       such that LOW < buffer * 10^kappa < HIGH, where LOW and HIGH are the
+//       correct values of low and high (without their error).
+//     * if more than one decimal representation gives the minimal number of
+//       decimal digits then the one closest to W (where W is the correct value
+//       of w) is chosen.
+// Remark: this procedure takes into account the imprecision of its input
+//   numbers. If the precision is not enough to guarantee all the postconditions
+//   then false is returned. This usually happens rarely (~0.5%).
+template<int alpha, int gamma>
+bool Grisu3<alpha, gamma>::DigitGen(DiyFp low,
+                                    DiyFp w,
+                                    DiyFp high,
+                                    char* buffer,
+                                    int* len,
+                                    int* kappa) {
+  ASSERT(low.e() == w.e() && w.e() == high.e());
+  ASSERT(low.f() + 1 <= high.f() - 1);
+  ASSERT(alpha <= w.e() && w.e() <= gamma);
+  // The following tests use alpha and gamma to avoid unnecessary dynamic tests.
+  if ((alpha >= -60 && gamma <= -32) ||  // -60 <= w.e() <= -32
+      (alpha <= -32 && gamma >= -60 &&   // Alpha/gamma overlaps -60/-32 region.
+       -60 <= w.e() && w.e() <= -32)) {
+    return DigitGen_m60_m32(low, w, high, buffer, len, kappa);
+  } else {
+    // A simple adaption of the special case -60/-32 would allow greater ranges
+    // of alpha/gamma and thus reduce the number of precomputed cached powers of
+    // ten.
+    UNIMPLEMENTED();
+    return false;
+  }
+}
+
+static const uint32_t kTen4 = 10000;
+static const uint32_t kTen5 = 100000;
+static const uint32_t kTen6 = 1000000;
+static const uint32_t kTen7 = 10000000;
+static const uint32_t kTen8 = 100000000;
+static const uint32_t kTen9 = 1000000000;
+
+// Returns the biggest power of ten that is <= than the given number. We
+// furthermore receive the maximum number of bits 'number' has.
+// If number_bits == 0 then 0^-1 is returned
+// The number of bits must be <= 32.
+static void BiggestPowerTen(uint32_t number,
+                            int number_bits,
+                            uint32_t* power,
+                            int* exponent) {
+  switch (number_bits) {
+    case 32:
+    case 31:
+    case 30:
+      if (kTen9 <= number) {
+        *power = kTen9;
+        *exponent = 9;
+        break;
+      }  // else fallthrough
+    case 29:
+    case 28:
+    case 27:
+      if (kTen8 <= number) {
+        *power = kTen8;
+        *exponent = 8;
+        break;
+      }  // else fallthrough
+    case 26:
+    case 25:
+    case 24:
+      if (kTen7 <= number) {
+        *power = kTen7;
+        *exponent = 7;
+        break;
+      }  // else fallthrough
+    case 23:
+    case 22:
+    case 21:
+    case 20:
+      if (kTen6 <= number) {
+        *power = kTen6;
+        *exponent = 6;
+        break;
+      }  // else fallthrough
+    case 19:
+    case 18:
+    case 17:
+      if (kTen5 <= number) {
+        *power = kTen5;
+        *exponent = 5;
+        break;
+      }  // else fallthrough
+    case 16:
+    case 15:
+    case 14:
+      if (kTen4 <= number) {
+        *power = kTen4;
+        *exponent = 4;
+        break;
+      }  // else fallthrough
+    case 13:
+    case 12:
+    case 11:
+    case 10:
+      if (1000 <= number) {
+        *power = 1000;
+        *exponent = 3;
+        break;
+      }  // else fallthrough
+    case 9:
+    case 8:
+    case 7:
+      if (100 <= number) {
+        *power = 100;
+        *exponent = 2;
+        break;
+      }  // else fallthrough
+    case 6:
+    case 5:
+    case 4:
+      if (10 <= number) {
+        *power = 10;
+        *exponent = 1;
+        break;
+      }  // else fallthrough
+    case 3:
+    case 2:
+    case 1:
+      if (1 <= number) {
+        *power = 1;
+        *exponent = 0;
+        break;
+      }  // else fallthrough
+    case 0:
+      *power = 0;
+      *exponent = -1;
+      break;
+    default:
+      // Following assignments are here to silence compiler warnings.
+      *power = 0;
+      *exponent = 0;
+      UNREACHABLE();
+  }
+}
+
+
+// Same comments as for DigitGen but with additional precondition:
+//    -60 <= w.e() <= -32
+//
+// Say, for the sake of example, that
+//   w.e() == -48, and w.f() == 0x1234567890abcdef
+// w's value can be computed by w.f() * 2^w.e()
+// We can obtain w's integral digits by simply shifting w.f() by -w.e().
+//  -> w's integral part is 0x1234
+//  w's fractional part is therefore 0x567890abcdef.
+// Printing w's integral part is easy (simply print 0x1234 in decimal).
+// In order to print its fraction we repeatedly multiply the fraction by 10 and
+// get each digit. Example the first digit after the comma would be computed by
+//   (0x567890abcdef * 10) >> 48. -> 3
+// The whole thing becomes slightly more complicated because we want to stop
+// once we have enough digits. That is, once the digits inside the buffer
+// represent 'w' we can stop. Everything inside the interval low - high
+// represents w. However we have to pay attention to low, high and w's
+// imprecision.
+template<int alpha, int gamma>
+bool Grisu3<alpha, gamma>::DigitGen_m60_m32(DiyFp low,
+                                            DiyFp w,
+                                            DiyFp high,
+                                            char* buffer,
+                                            int* length,
+                                            int* kappa) {
+  // low, w and high are imprecise, but by less than one ulp (unit in the last
+  // place).
+  // If we remove (resp. add) 1 ulp from low (resp. high) we are certain that
+  // the new numbers are outside of the interval we want the final
+  // representation to lie in.
+  // Inversely adding (resp. removing) 1 ulp from low (resp. high) would yield
+  // numbers that are certain to lie in the interval. We will use this fact
+  // later on.
+  // We will now start by generating the digits within the uncertain
+  // interval. Later we will weed out representations that lie outside the safe
+  // interval and thus _might_ lie outside the correct interval.
+  uint64_t unit = 1;
+  DiyFp too_low = DiyFp(low.f() - unit, low.e());
+  DiyFp too_high = DiyFp(high.f() + unit, high.e());
+  // too_low and too_high are guaranteed to lie outside the interval we want the
+  // generated number in.
+  DiyFp unsafe_interval = DiyFp::Minus(too_high, too_low);
+  // We now cut the input number into two parts: the integral digits and the
+  // fractionals. We will not write any decimal separator though, but adapt
+  // kappa instead.
+  // Reminder: we are currently computing the digits (stored inside the buffer)
+  // such that:   too_low < buffer * 10^kappa < too_high
+  // We use too_high for the digit_generation and stop as soon as possible.
+  // If we stop early we effectively round down.
+  DiyFp one = DiyFp(static_cast<uint64_t>(1) << -w.e(), w.e());
+  // Division by one is a shift.
+  uint32_t integrals = static_cast<uint32_t>(too_high.f() >> -one.e());
+  // Modulo by one is an and.
+  uint64_t fractionals = too_high.f() & (one.f() - 1);
+  uint32_t divider;
+  int divider_exponent;
+  BiggestPowerTen(integrals, DiyFp::kSignificandSize - (-one.e()),
+                  &divider, &divider_exponent);
+  *kappa = divider_exponent + 1;
+  *length = 0;
+  // Loop invariant: buffer = too_high / 10^kappa  (integer division)
+  // The invariant holds for the first iteration: kappa has been initialized
+  // with the divider exponent + 1. And the divider is the biggest power of ten
+  // that is smaller than integrals.
+  while (*kappa > 0) {
+    int digit = integrals / divider;
+    buffer[*length] = '0' + digit;
+    (*length)++;
+    integrals %= divider;
+    (*kappa)--;
+    // Note that kappa now equals the exponent of the divider and that the
+    // invariant thus holds again.
+    uint64_t rest =
+        (static_cast<uint64_t>(integrals) << -one.e()) + fractionals;
+    // Invariant: too_high = buffer * 10^kappa + DiyFp(rest, one.e())
+    // Reminder: unsafe_interval.e() == one.e()
+    if (rest < unsafe_interval.f()) {
+      // Rounding down (by not emitting the remaining digits) yields a number
+      // that lies within the unsafe interval.
+      return RoundWeed(buffer, *length, DiyFp::Minus(too_high, w).f(),
+                       unsafe_interval.f(), rest,
+                       static_cast<uint64_t>(divider) << -one.e(), unit);
+    }
+    divider /= 10;
+  }
+
+  // The integrals have been generated. We are at the point of the decimal
+  // separator. In the following loop we simply multiply the remaining digits by
+  // 10 and divide by one. We just need to pay attention to multiply associated
+  // data (like the interval or 'unit'), too.
+  // Instead of multiplying by 10 we multiply by 5 (cheaper operation) and
+  // increase its (imaginary) exponent. At the same time we decrease the
+  // divider's (one's) exponent and shift its significand.
+  // Basically, if fractionals was a DiyFp (with fractionals.e == one.e):
+  //      fractionals.f *= 10;
+  //      fractionals.f >>= 1; fractionals.e++; // value remains unchanged.
+  //      one.f >>= 1; one.e++;                 // value remains unchanged.
+  //      and we have again fractionals.e == one.e which allows us to divide
+  //           fractionals.f() by one.f()
+  // We simply combine the *= 10 and the >>= 1.
+  while (true) {
+    fractionals *= 5;
+    unit *= 5;
+    unsafe_interval.set_f(unsafe_interval.f() * 5);
+    unsafe_interval.set_e(unsafe_interval.e() + 1);  // Will be optimized out.
+    one.set_f(one.f() >> 1);
+    one.set_e(one.e() + 1);
+    // Integer division by one.
+    int digit = static_cast<int>(fractionals >> -one.e());
+    buffer[*length] = '0' + digit;
+    (*length)++;
+    fractionals &= one.f() - 1;  // Modulo by one.
+    (*kappa)--;
+    if (fractionals < unsafe_interval.f()) {
+      return RoundWeed(buffer, *length, DiyFp::Minus(too_high, w).f() * unit,
+                       unsafe_interval.f(), fractionals, one.f(), unit);
+    }
+  }
+}
+
+
+// Rounds the given generated digits in the buffer and weeds out generated
+// digits that are not in the safe interval, or where we cannot find a rounded
+// representation.
+// Input: * buffer containing the digits of too_high / 10^kappa
+//        * the buffer's length
+//        * distance_too_high_w == (too_high - w).f() * unit
+//        * unsafe_interval == (too_high - too_low).f() * unit
+//        * rest = (too_high - buffer * 10^kappa).f() * unit
+//        * ten_kappa = 10^kappa * unit
+//        * unit = the common multiplier
+// Output: returns true on success.
+//    Modifies the generated digits in the buffer to approach (round towards) w.
+template<int alpha, int gamma>
+bool Grisu3<alpha, gamma>::RoundWeed(char* buffer,
+                                     int length,
+                                     uint64_t distance_too_high_w,
+                                     uint64_t unsafe_interval,
+                                     uint64_t rest,
+                                     uint64_t ten_kappa,
+                                     uint64_t unit) {
+  uint64_t small_distance = distance_too_high_w - unit;
+  uint64_t big_distance = distance_too_high_w + unit;
+  // Let w- = too_high - big_distance, and
+  //     w+ = too_high - small_distance.
+  // Note: w- < w < w+
+  //
+  // The real w (* unit) must lie somewhere inside the interval
+  // ]w-; w+[ (often written as "(w-; w+)")
+
+  // Basically the buffer currently contains a number in the unsafe interval
+  // ]too_low; too_high[ with too_low < w < too_high
+  //
+  // By generating the digits of too_high we got the biggest last digit.
+  // In the case that w+ < buffer < too_high we try to decrement the buffer.
+  // This way the buffer approaches (rounds towards) w.
+  // There are 3 conditions that stop the decrementation process:
+  //   1) the buffer is already below w+
+  //   2) decrementing the buffer would make it leave the unsafe interval
+  //   3) decrementing the buffer would yield a number below w+ and farther away
+  //      than the current number. In other words:
+  //                       (buffer{-1} < w+) && w+ - buffer{-1} > buffer - w+
+  // Instead of using the buffer directly we use its distance to too_high.
+  // Conceptually rest ~= too_high - buffer
+  while (rest < small_distance &&  // Negated condition 1
+         unsafe_interval - rest >= ten_kappa &&  // Negated condition 2
+         (rest + ten_kappa < small_distance ||  // buffer{-1} > w+
+          small_distance - rest >= rest + ten_kappa - small_distance)) {
+    buffer[length - 1]--;
+    rest += ten_kappa;
+  }
+
+  // We have approached w+ as much as possible. We now test if approaching w-
+  // would require changing the buffer. If yes, then we have two possible
+  // representations close to w, but we cannot decide which one is closer.
+  if (rest < big_distance &&
+      unsafe_interval - rest >= ten_kappa &&
+      (rest + ten_kappa < big_distance ||
+       big_distance - rest > rest + ten_kappa - big_distance)) {
+    return false;
+  }
+
+  // Weeding test.
+  //   The safe interval is [too_low + 2 ulp; too_high - 2 ulp]
+  //   Since too_low = too_high - unsafe_interval this is equivalent too
+  //      [too_high - unsafe_interval + 4 ulp; too_high - 2 ulp]
+  //   Conceptually we have: rest ~= too_high - buffer
+  return (2 * unit <= rest) && (rest <= unsafe_interval - 4 * unit);
+}
+
+
+bool grisu3(double v, char* buffer, int* sign, int* length, int* point) {
+  ASSERT(v != 0);
+  ASSERT(!Double(v).IsSpecial());
+
+  if (v < 0) {
+    v = -v;
+    *sign = 1;
+  } else {
+    *sign = 0;
+  }
+  int decimal_exponent;
+  bool result = Grisu3<-60, -32>::grisu3(v, buffer, length, &decimal_exponent);
+  *point = *length + decimal_exponent;
+  buffer[*length] = '\0';
+  return result;
+}
+
+} }  // namespace v8::internal
diff --git a/src/grisu3.h b/src/grisu3.h
new file mode 100644
index 0000000..b41ca37
--- /dev/null
+++ b/src/grisu3.h
@@ -0,0 +1,55 @@
+// 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_GRISU3_H_
+#define V8_GRISU3_H_
+
+namespace v8 {
+namespace internal {
+
+// Grisu3 will produce at most kGrisu3MaximalLength digits. This does not
+// include the terminating '\0' character.
+static const int kGrisu3MaximalLength = 17;
+
+// Provides a decimal representation of v.
+//   v must satisfy v != 0 and it must not be Infinity or NaN.
+// Returns true if it succeeds, otherwise the result can not be trusted.
+// There will be *length digits inside the buffer followed by a null terminator.
+// If the function returns true then
+//   v == (double) (buffer * 10^(decimal-point - length)).
+// The digits in the buffer are the shortest representation possible: no
+// 0.099999999999 instead of 0.1.
+// The last digit will be closest to the actual v. That is, even if several
+// digits might correctly yield 'v' when read again, the buffer will contain the
+// one closest to v.
+// The variable 'sign' will be '0' if the given number is positive, and '1'
+//   otherwise.
+bool grisu3(double d, char* buffer, int* sign, int* length, int* decimal_point);
+
+} }  // namespace v8::internal
+
+#endif  // V8_GRISU3_H_
diff --git a/src/heap.cc b/src/heap.cc
index fbe0464..d666875 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -2571,11 +2571,9 @@
               reinterpret_cast<Object**>(source->address()),
               object_size);
     // Update write barrier for all fields that lie beyond the header.
-    for (int offset = JSObject::kHeaderSize;
-         offset < object_size;
-         offset += kPointerSize) {
-      RecordWrite(clone_address, offset);
-    }
+    RecordWrites(clone_address,
+                 JSObject::kHeaderSize,
+                 object_size - JSObject::kHeaderSize);
   } else {
     clone = new_space_.AllocateRaw(object_size);
     if (clone->IsFailure()) return clone;
@@ -2906,12 +2904,9 @@
     reinterpret_cast<Array*>(result)->set_map(fixed_array_map());
     FixedArray* array = FixedArray::cast(result);
     array->set_length(length);
-    Object* value = undefined_value();
     // Initialize body.
-    for (int index = 0; index < length; index++) {
-      ASSERT(!Heap::InNewSpace(value));  // value = undefined
-      array->set(index, value, SKIP_WRITE_BARRIER);
-    }
+    ASSERT(!Heap::InNewSpace(undefined_value()));
+    MemsetPointer(array->data_start(), undefined_value(), length);
   }
   return result;
 }
@@ -2963,11 +2958,8 @@
   reinterpret_cast<Array*>(result)->set_map(fixed_array_map());
   FixedArray* array = FixedArray::cast(result);
   array->set_length(length);
-  Object* value = undefined_value();
-  for (int index = 0; index < length; index++) {
-    ASSERT(!Heap::InNewSpace(value));  // value = undefined
-    array->set(index, value, SKIP_WRITE_BARRIER);
-  }
+  ASSERT(!Heap::InNewSpace(undefined_value()));
+  MemsetPointer(array->data_start(), undefined_value(), length);
   return array;
 }
 
@@ -2994,9 +2986,7 @@
     array->set_length(length);
     // Initialize body.
     ASSERT(!Heap::InNewSpace(the_hole_value()));
-    MemsetPointer(HeapObject::RawField(array, FixedArray::kHeaderSize),
-                  the_hole_value(),
-                  length);
+    MemsetPointer(array->data_start(), the_hole_value(), length);
   }
   return result;
 }
@@ -3409,7 +3399,7 @@
   v->VisitPointers(&roots_[0], &roots_[kStrongRootListLength]);
   v->Synchronize("strong_root_list");
 
-  v->VisitPointer(bit_cast<Object**, String**>(&hidden_symbol_));
+  v->VisitPointer(BitCast<Object**, String**>(&hidden_symbol_));
   v->Synchronize("symbol");
 
   Bootstrapper::Iterate(v);
diff --git a/src/ia32/assembler-ia32.cc b/src/ia32/assembler-ia32.cc
index f13556b..7f0d5d4 100644
--- a/src/ia32/assembler-ia32.cc
+++ b/src/ia32/assembler-ia32.cc
@@ -2148,6 +2148,17 @@
 }
 
 
+void Assembler::movmskpd(Register dst, XMMRegister src) {
+  ASSERT(CpuFeatures::IsEnabled(SSE2));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x66);
+  EMIT(0x0F);
+  EMIT(0x50);
+  emit_sse_operand(dst, src);
+}
+
+
 void Assembler::movdqa(const Operand& dst, XMMRegister src ) {
   ASSERT(CpuFeatures::IsEnabled(SSE2));
   EnsureSpace ensure_space(this);
@@ -2283,6 +2294,11 @@
 }
 
 
+void Assembler::emit_sse_operand(Register dst, XMMRegister src) {
+  EMIT(0xC0 | dst.code() << 3 | src.code());
+}
+
+
 void Assembler::Print() {
   Disassembler::Decode(stdout, buffer_, pc_);
 }
diff --git a/src/ia32/assembler-ia32.h b/src/ia32/assembler-ia32.h
index 4497e2a..d8cd57a 100644
--- a/src/ia32/assembler-ia32.h
+++ b/src/ia32/assembler-ia32.h
@@ -769,6 +769,7 @@
 
   void comisd(XMMRegister dst, XMMRegister src);
   void ucomisd(XMMRegister dst, XMMRegister src);
+  void movmskpd(Register dst, XMMRegister src);
 
   void movdqa(XMMRegister dst, const Operand& src);
   void movdqa(const Operand& dst, XMMRegister src);
@@ -828,7 +829,7 @@
 
   void emit_sse_operand(XMMRegister reg, const Operand& adr);
   void emit_sse_operand(XMMRegister dst, XMMRegister src);
-
+  void emit_sse_operand(Register dst, XMMRegister src);
 
  private:
   byte* addr_at(int pos)  { return buffer_ + pos; }
diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc
index bdd1c4a..703fffe 100644
--- a/src/ia32/codegen-ia32.cc
+++ b/src/ia32/codegen-ia32.cc
@@ -2286,61 +2286,69 @@
       // a jump target and branching to duplicate the virtual frame at
       // the first split.  We manually handle the off-frame references
       // by reconstituting them on the non-fall-through path.
-      JumpTarget is_smi;
-      __ test(left_side.reg(), Immediate(kSmiTagMask));
-      is_smi.Branch(zero, taken);
 
-      bool is_for_loop_compare = (node->AsCompareOperation() != NULL)
-          && node->AsCompareOperation()->is_for_loop_condition();
-      if (!is_for_loop_compare
-          && CpuFeatures::IsSupported(SSE2)
-          && right_val->IsSmi()) {
-        // Right side is a constant smi and left side has been checked
-        // not to be a smi.
-        CpuFeatures::Scope use_sse2(SSE2);
-        JumpTarget not_number;
-        __ cmp(FieldOperand(left_reg, HeapObject::kMapOffset),
-               Immediate(Factory::heap_number_map()));
-        not_number.Branch(not_equal, &left_side);
-        __ movdbl(xmm1,
-                  FieldOperand(left_reg, HeapNumber::kValueOffset));
-        int value = Smi::cast(*right_val)->value();
-        if (value == 0) {
-          __ xorpd(xmm0, xmm0);
-        } else {
-          Result temp = allocator()->Allocate();
-          __ mov(temp.reg(), Immediate(value));
-          __ cvtsi2sd(xmm0, Operand(temp.reg()));
-          temp.Unuse();
+      if (left_side.is_smi()) {
+        if (FLAG_debug_code) {
+          __ AbortIfNotSmi(left_side.reg(), "Argument not a smi");
         }
-        __ comisd(xmm1, xmm0);
-        // Jump to builtin for NaN.
-        not_number.Branch(parity_even, &left_side);
-        left_side.Unuse();
-        Condition double_cc = cc;
-        switch (cc) {
-          case less:          double_cc = below;       break;
-          case equal:         double_cc = equal;       break;
-          case less_equal:    double_cc = below_equal; break;
-          case greater:       double_cc = above;       break;
-          case greater_equal: double_cc = above_equal; break;
-          default: UNREACHABLE();
+      } else {
+        JumpTarget is_smi;
+        __ test(left_side.reg(), Immediate(kSmiTagMask));
+        is_smi.Branch(zero, taken);
+
+        bool is_for_loop_compare = (node->AsCompareOperation() != NULL)
+            && node->AsCompareOperation()->is_for_loop_condition();
+        if (!is_for_loop_compare
+            && CpuFeatures::IsSupported(SSE2)
+            && right_val->IsSmi()) {
+          // Right side is a constant smi and left side has been checked
+          // not to be a smi.
+          CpuFeatures::Scope use_sse2(SSE2);
+          JumpTarget not_number;
+          __ cmp(FieldOperand(left_reg, HeapObject::kMapOffset),
+                 Immediate(Factory::heap_number_map()));
+          not_number.Branch(not_equal, &left_side);
+          __ movdbl(xmm1,
+                    FieldOperand(left_reg, HeapNumber::kValueOffset));
+          int value = Smi::cast(*right_val)->value();
+          if (value == 0) {
+            __ xorpd(xmm0, xmm0);
+          } else {
+            Result temp = allocator()->Allocate();
+            __ mov(temp.reg(), Immediate(value));
+            __ cvtsi2sd(xmm0, Operand(temp.reg()));
+            temp.Unuse();
+          }
+          __ comisd(xmm1, xmm0);
+          // Jump to builtin for NaN.
+          not_number.Branch(parity_even, &left_side);
+          left_side.Unuse();
+          Condition double_cc = cc;
+          switch (cc) {
+            case less:          double_cc = below;       break;
+            case equal:         double_cc = equal;       break;
+            case less_equal:    double_cc = below_equal; break;
+            case greater:       double_cc = above;       break;
+            case greater_equal: double_cc = above_equal; break;
+            default: UNREACHABLE();
+          }
+          dest->true_target()->Branch(double_cc);
+          dest->false_target()->Jump();
+          not_number.Bind(&left_side);
         }
-        dest->true_target()->Branch(double_cc);
+
+        // Setup and call the compare stub.
+        CompareStub stub(cc, strict, kCantBothBeNaN);
+        Result result = frame_->CallStub(&stub, &left_side, &right_side);
+        result.ToRegister();
+        __ cmp(result.reg(), 0);
+        result.Unuse();
+        dest->true_target()->Branch(cc);
         dest->false_target()->Jump();
-        not_number.Bind(&left_side);
+
+        is_smi.Bind();
       }
 
-      // Setup and call the compare stub.
-      CompareStub stub(cc, strict, kCantBothBeNaN);
-      Result result = frame_->CallStub(&stub, &left_side, &right_side);
-      result.ToRegister();
-      __ cmp(result.reg(), 0);
-      result.Unuse();
-      dest->true_target()->Branch(cc);
-      dest->false_target()->Jump();
-
-      is_smi.Bind();
       left_side = Result(left_reg);
       right_side = Result(right_val);
       // Test smi equality and comparison by signed int comparison.
@@ -3579,6 +3587,24 @@
   }
 
   CheckStack();  // TODO(1222600): ignore if body contains calls.
+
+  // If we have (a) a loop with a compile-time constant trip count
+  // and (b) the loop induction variable is not assignend inside the
+  // loop we update the number type of the induction variable to be smi.
+
+  if (node->is_fast_smi_loop()) {
+    // Set number type of the loop variable to smi.
+    Slot* slot = node->loop_variable()->slot();
+    ASSERT(slot->type() == Slot::LOCAL);
+    frame_->SetTypeForLocalAt(slot->index(), NumberInfo::Smi());
+    if (FLAG_debug_code) {
+      frame_->PushLocalAt(slot->index());
+      Result var = frame_->Pop();
+      var.ToRegister();
+      __ AbortIfNotSmi(var.reg(), "Loop variable not a smi.");
+    }
+  }
+
   Visit(node->body());
 
   // If there is an update expression, compile it if necessary.
@@ -4754,11 +4780,13 @@
   frame_->Push(Smi::FromInt(node->literal_index()));
   // Constant properties.
   frame_->Push(node->constant_properties());
+  // Should the object literal have fast elements?
+  frame_->Push(Smi::FromInt(node->fast_elements() ? 1 : 0));
   Result clone;
   if (node->depth() > 1) {
-    clone = frame_->CallRuntime(Runtime::kCreateObjectLiteral, 3);
+    clone = frame_->CallRuntime(Runtime::kCreateObjectLiteral, 4);
   } else {
-    clone = frame_->CallRuntime(Runtime::kCreateObjectLiteralShallow, 3);
+    clone = frame_->CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
   }
   frame_->Push(&clone);
 
@@ -5912,7 +5940,7 @@
 }
 
 
-void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateArguments(ZoneList<Expression*>* args) {
   ASSERT(args->length() == 1);
 
   // ArgumentsAccessStub expects the key in edx and the formal
@@ -6624,15 +6652,6 @@
       __ Set(tmp.reg(), Immediate(0));
     }
 
-    DeferredCode* deferred = NULL;
-    if (is_postfix) {
-      deferred = new DeferredPostfixCountOperation(new_value.reg(),
-                                                   old_value.reg(),
-                                                   is_increment);
-    } else {
-      deferred = new DeferredPrefixCountOperation(new_value.reg(),
-                                                  is_increment);
-    }
 
     if (is_increment) {
       __ add(Operand(new_value.reg()), Immediate(Smi::FromInt(1)));
@@ -6640,24 +6659,41 @@
       __ sub(Operand(new_value.reg()), Immediate(Smi::FromInt(1)));
     }
 
-    // If the count operation didn't overflow and the result is a valid
-    // smi, we're done. Otherwise, we jump to the deferred slow-case
-    // code.
-    if (tmp.is_valid()) {
-      // We combine the overflow and the smi tag check if we could
-      // successfully allocate a temporary byte register.
-      __ setcc(overflow, tmp.reg());
-      __ or_(Operand(tmp.reg()), new_value.reg());
-      __ test(tmp.reg(), Immediate(kSmiTagMask));
-      tmp.Unuse();
-      deferred->Branch(not_zero);
+    if (new_value.is_smi()) {
+      if (FLAG_debug_code) {
+        __ AbortIfNotSmi(new_value.reg(), "Argument not a smi");
+      }
+      if (tmp.is_valid()) tmp.Unuse();
     } else {
-      // Otherwise we test separately for overflow and smi tag.
-      deferred->Branch(overflow);
-      __ test(new_value.reg(), Immediate(kSmiTagMask));
-      deferred->Branch(not_zero);
+      DeferredCode* deferred = NULL;
+      if (is_postfix) {
+        deferred = new DeferredPostfixCountOperation(new_value.reg(),
+                                                     old_value.reg(),
+                                                     is_increment);
+      } else {
+        deferred = new DeferredPrefixCountOperation(new_value.reg(),
+                                                    is_increment);
+      }
+
+      // If the count operation didn't overflow and the result is a valid
+      // smi, we're done. Otherwise, we jump to the deferred slow-case
+      // code.
+      if (tmp.is_valid()) {
+        // We combine the overflow and the smi tag check if we could
+        // successfully allocate a temporary byte register.
+        __ setcc(overflow, tmp.reg());
+        __ or_(Operand(tmp.reg()), new_value.reg());
+        __ test(tmp.reg(), Immediate(kSmiTagMask));
+        tmp.Unuse();
+        deferred->Branch(not_zero);
+      } else {
+        // Otherwise we test separately for overflow and smi tag.
+        deferred->Branch(overflow);
+        __ test(new_value.reg(), Immediate(kSmiTagMask));
+        deferred->Branch(not_zero);
+      }
+      deferred->BindExit();
     }
-    deferred->BindExit();
 
     // Postfix: store the old value in the allocated slot under the
     // reference.
@@ -6823,8 +6859,15 @@
       overwrite_mode = OVERWRITE_RIGHT;
     }
 
-    Load(node->left());
-    Load(node->right());
+    if (node->left()->IsTrivial()) {
+      Load(node->right());
+      Result right = frame_->Pop();
+      frame_->Push(node->left());
+      frame_->Push(&right);
+    } else {
+      Load(node->left());
+      Load(node->right());
+    }
     GenericBinaryOperation(node->op(), node->type(), overwrite_mode);
   }
 }
@@ -7024,8 +7067,20 @@
     default:
       UNREACHABLE();
   }
-  if (!left_already_loaded) Load(left);
-  Load(right);
+
+  if (left->IsTrivial()) {
+    if (!left_already_loaded) {
+      Load(right);
+      Result right_result = frame_->Pop();
+      frame_->Push(left);
+      frame_->Push(&right_result);
+    } else {
+      Load(right);
+    }
+  } else {
+    if (!left_already_loaded) Load(left);
+    Load(right);
+  }
   Comparison(node, cc, strict, destination());
 }
 
@@ -10162,6 +10217,12 @@
 }
 
 
+void RecordWriteStub::Generate(MacroAssembler* masm) {
+  masm->RecordWriteHelper(object_, addr_, scratch_);
+  masm->ret(0);
+}
+
+
 void CompareStub::Generate(MacroAssembler* masm) {
   Label call_builtin, done;
 
diff --git a/src/ia32/codegen-ia32.h b/src/ia32/codegen-ia32.h
index 79cad72..f7ec0b5 100644
--- a/src/ia32/codegen-ia32.h
+++ b/src/ia32/codegen-ia32.h
@@ -339,6 +339,10 @@
   bool in_spilled_code() const { return in_spilled_code_; }
   void set_in_spilled_code(bool flag) { in_spilled_code_ = flag; }
 
+  // If the name is an inline runtime function call return the number of
+  // expected arguments. Otherwise return -1.
+  static int InlineRuntimeCallArgumentsCount(Handle<String> name);
+
  private:
   // Construction/Destruction
   explicit CodeGenerator(MacroAssembler* masm);
@@ -522,6 +526,7 @@
   struct InlineRuntimeLUT {
     void (CodeGenerator::*method)(ZoneList<Expression*>*);
     const char* name;
+    int nargs;
   };
 
   static InlineRuntimeLUT* FindInlineRuntimeLUT(Handle<String> name);
@@ -555,7 +560,7 @@
 
   // Support for arguments.length and arguments[?].
   void GenerateArgumentsLength(ZoneList<Expression*>* args);
-  void GenerateArgumentsAccess(ZoneList<Expression*>* args);
+  void GenerateArguments(ZoneList<Expression*>* args);
 
   // Support for accessing the class and value fields of an object.
   void GenerateClassOf(ZoneList<Expression*>* args);
@@ -593,14 +598,10 @@
   // Fast support for number to string.
   void GenerateNumberToString(ZoneList<Expression*>* args);
 
-  // Fast support for Math.pow().
+  // Fast call to math functions.
   void GenerateMathPow(ZoneList<Expression*>* args);
-
-  // Fast call to transcendental functions.
   void GenerateMathSin(ZoneList<Expression*>* args);
   void GenerateMathCos(ZoneList<Expression*>* args);
-
-  // Fast case for sqrt
   void GenerateMathSqrt(ZoneList<Expression*>* args);
 
   // Simple condition analysis.
@@ -976,6 +977,42 @@
 };
 
 
+class RecordWriteStub : public CodeStub {
+ public:
+  RecordWriteStub(Register object, Register addr, Register scratch)
+      : object_(object), addr_(addr), scratch_(scratch) { }
+
+  void Generate(MacroAssembler* masm);
+
+ private:
+  Register object_;
+  Register addr_;
+  Register scratch_;
+
+#ifdef DEBUG
+  void Print() {
+    PrintF("RecordWriteStub (object reg %d), (addr reg %d), (scratch reg %d)\n",
+           object_.code(), addr_.code(), scratch_.code());
+  }
+#endif
+
+  // Minor key encoding in 12 bits of three registers (object, address and
+  // scratch) OOOOAAAASSSS.
+  class ScratchBits: public BitField<uint32_t, 0, 4> {};
+  class AddressBits: public BitField<uint32_t, 4, 4> {};
+  class ObjectBits: public BitField<uint32_t, 8, 4> {};
+
+  Major MajorKey() { return RecordWrite; }
+
+  int MinorKey() {
+    // Encode the registers.
+    return ObjectBits::encode(object_.code()) |
+           AddressBits::encode(addr_.code()) |
+           ScratchBits::encode(scratch_.code());
+  }
+};
+
+
 } }  // namespace v8::internal
 
 #endif  // V8_IA32_CODEGEN_IA32_H_
diff --git a/src/ia32/disasm-ia32.cc b/src/ia32/disasm-ia32.cc
index 0d85b10..8d342e0 100644
--- a/src/ia32/disasm-ia32.cc
+++ b/src/ia32/disasm-ia32.cc
@@ -1069,12 +1069,26 @@
             } else {
               UnimplementedInstruction();
             }
-          } else if (*data == 0x2F) {
+          } else if (*data == 0x2E || *data == 0x2F) {
+            const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
             data++;
             int mod, regop, rm;
             get_modrm(*data, &mod, &regop, &rm);
-            AppendToBuffer("comisd %s,%s",
-                           NameOfXMMRegister(regop),
+            if (mod == 0x3) {
+              AppendToBuffer("%s %s,%s", mnem,
+                             NameOfXMMRegister(regop),
+                             NameOfXMMRegister(rm));
+              data++;
+            } else {
+              AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
+              data += PrintRightOperand(data);
+            }
+          } else if (*data == 0x50) {
+            data++;
+            int mod, regop, rm;
+            get_modrm(*data, &mod, &regop, &rm);
+            AppendToBuffer("movmskpd %s,%s",
+                           NameOfCPURegister(regop),
                            NameOfXMMRegister(rm));
             data++;
           } else if (*data == 0x57) {
@@ -1198,6 +1212,7 @@
             const char* mnem = "?";
             switch (b2) {
               case 0x2A: mnem = "cvtsi2sd"; break;
+              case 0x2C: mnem = "cvttsd2si"; break;
               case 0x51: mnem = "sqrtsd"; break;
               case 0x58: mnem = "addsd"; break;
               case 0x59: mnem = "mulsd"; break;
@@ -1208,14 +1223,38 @@
             int mod, regop, rm;
             get_modrm(*data, &mod, &regop, &rm);
             if (b2 == 0x2A) {
-              AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
-              data += PrintRightOperand(data);
+              if (mod != 0x3) {
+                AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
+                data += PrintRightOperand(data);
+              } else {
+                AppendToBuffer("%s %s,%s",
+                               mnem,
+                               NameOfXMMRegister(regop),
+                               NameOfCPURegister(rm));
+                data++;
+              }
+            } else if (b2 == 0x2C) {
+              if (mod != 0x3) {
+                AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
+                data += PrintRightOperand(data);
+              } else {
+                AppendToBuffer("%s %s,%s",
+                               mnem,
+                               NameOfCPURegister(regop),
+                               NameOfXMMRegister(rm));
+                data++;
+              }
             } else {
-              AppendToBuffer("%s %s,%s",
-                             mnem,
-                             NameOfXMMRegister(regop),
-                             NameOfXMMRegister(rm));
-              data++;
+              if (mod != 0x3) {
+                AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
+                data += PrintRightOperand(data);
+              } else {
+                AppendToBuffer("%s %s,%s",
+                               mnem,
+                               NameOfXMMRegister(regop),
+                               NameOfXMMRegister(rm));
+                data++;
+              }
             }
           }
         } else {
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index 6e3ae10..cedf9c9 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -901,10 +901,11 @@
   __ push(FieldOperand(edi, JSFunction::kLiteralsOffset));
   __ push(Immediate(Smi::FromInt(expr->literal_index())));
   __ push(Immediate(expr->constant_properties()));
+  __ push(Immediate(Smi::FromInt(expr->fast_elements() ? 1 : 0)));
   if (expr->depth() > 1) {
-    __ CallRuntime(Runtime::kCreateObjectLiteral, 3);
+    __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
   } else {
-    __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 3);
+    __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
   }
 
   // If result_saved is true the result is on top of the stack.  If
diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc
index 555cd1b..3928661 100644
--- a/src/ia32/ic-ia32.cc
+++ b/src/ia32/ic-ia32.cc
@@ -152,6 +152,108 @@
 }
 
 
+static void GenerateNumberDictionaryLoad(MacroAssembler* masm,
+                                         Label* miss,
+                                         Register elements,
+                                         Register key,
+                                         Register r0,
+                                         Register r1,
+                                         Register r2) {
+  // 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. If the load succeeds and we
+  //            fall through, key holds the result on exit.
+  //
+  // Scratch registers:
+  //
+  // r0 - holds the untagged key on entry and holds the hash once computed.
+  //
+  // r1 - used to hold the capacity mask of the dictionary
+  //
+  // r2 - 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);
+  __ mov(r1, r0);
+  __ not_(r0);
+  __ shl(r1, 15);
+  __ add(r0, Operand(r1));
+  // hash = hash ^ (hash >> 12);
+  __ mov(r1, r0);
+  __ shr(r1, 12);
+  __ xor_(r0, Operand(r1));
+  // hash = hash + (hash << 2);
+  __ lea(r0, Operand(r0, r0, times_4, 0));
+  // hash = hash ^ (hash >> 4);
+  __ mov(r1, r0);
+  __ shr(r1, 4);
+  __ xor_(r0, Operand(r1));
+  // hash = hash * 2057;
+  __ imul(r0, r0, 2057);
+  // hash = hash ^ (hash >> 16);
+  __ mov(r1, r0);
+  __ shr(r1, 16);
+  __ xor_(r0, Operand(r1));
+
+  // Compute capacity mask.
+  const int kCapacityOffset =
+      NumberDictionary::kHeaderSize +
+      NumberDictionary::kCapacityIndex * kPointerSize;
+  __ mov(r1, FieldOperand(elements, 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++) {
+    // Use r2 for index calculations and keep the hash intact in r0.
+    __ mov(r2, r0);
+    // Compute the masked index: (hash + i + i * i) & mask.
+    if (i > 0) {
+      __ add(Operand(r2), Immediate(NumberDictionary::GetProbeOffset(i)));
+    }
+    __ and_(r2, Operand(r1));
+
+    // Scale the index by multiplying by the entry size.
+    ASSERT(NumberDictionary::kEntrySize == 3);
+    __ lea(r2, Operand(r2, r2, times_2, 0));  // r2 = r2 * 3
+
+    // Check if the key matches.
+    __ cmp(key, FieldOperand(elements,
+                             r2,
+                             times_pointer_size,
+                             kElementsStartOffset));
+    if (i != (kProbes - 1)) {
+      __ j(equal, &done, taken);
+    } else {
+      __ j(not_equal, miss, not_taken);
+    }
+  }
+
+  __ bind(&done);
+  // Check that the value is a normal propety.
+  const int kDetailsOffset = 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;
+  __ mov(key, FieldOperand(elements, r2, times_pointer_size, kValueOffset));
+}
+
+
 // Helper function used to check that a value is either not an object
 // or is loaded if it is an object.
 static void GenerateCheckNonObjectOrLoaded(MacroAssembler* masm, Label* miss,
@@ -225,6 +327,7 @@
   // -----------------------------------
   Label slow, check_string, index_int, index_string;
   Label check_pixel_array, probe_dictionary;
+  Label check_number_dictionary;
 
   // Check that the object isn't a smi.
   __ test(edx, Immediate(kSmiTagMask));
@@ -273,7 +376,7 @@
   // ebx: untagged index
   // eax: key
   // ecx: elements
-  __ CheckMap(ecx, Factory::pixel_array_map(), &slow, true);
+  __ CheckMap(ecx, Factory::pixel_array_map(), &check_number_dictionary, true);
   __ cmp(ebx, FieldOperand(ecx, PixelArray::kLengthOffset));
   __ j(above_equal, &slow);
   __ mov(eax, FieldOperand(ecx, PixelArray::kExternalPointerOffset));
@@ -281,6 +384,32 @@
   __ SmiTag(eax);
   __ ret(0);
 
+  __ bind(&check_number_dictionary);
+  // Check whether the elements is a number dictionary.
+  // edx: receiver
+  // ebx: untagged index
+  // eax: key
+  // ecx: elements
+  __ CheckMap(ecx, Factory::hash_table_map(), &slow, true);
+  Label slow_pop_receiver;
+  // Push receiver on the stack to free up a register for the dictionary
+  // probing.
+  __ push(edx);
+  GenerateNumberDictionaryLoad(masm,
+                               &slow_pop_receiver,
+                               ecx,
+                               eax,
+                               ebx,
+                               edx,
+                               edi);
+  // Pop receiver before returning.
+  __ pop(edx);
+  __ ret(0);
+
+  __ bind(&slow_pop_receiver);
+  // Pop the receiver from the stack and jump to runtime.
+  __ pop(edx);
+
   __ bind(&slow);
   // Slow case: jump to runtime.
   // edx: receiver
diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc
index 45e24fa..703ca79 100644
--- a/src/ia32/macro-assembler-ia32.cc
+++ b/src/ia32/macro-assembler-ia32.cc
@@ -47,33 +47,32 @@
 }
 
 
-static void RecordWriteHelper(MacroAssembler* masm,
-                              Register object,
-                              Register addr,
-                              Register scratch) {
+void MacroAssembler::RecordWriteHelper(Register object,
+                                       Register addr,
+                                       Register scratch) {
   Label fast;
 
   // Compute the page start address from the heap object pointer, and reuse
   // the 'object' register for it.
-  masm->and_(object, ~Page::kPageAlignmentMask);
+  and_(object, ~Page::kPageAlignmentMask);
   Register page_start = object;
 
   // Compute the bit addr in the remembered set/index of the pointer in the
   // page. Reuse 'addr' as pointer_offset.
-  masm->sub(addr, Operand(page_start));
-  masm->shr(addr, kObjectAlignmentBits);
+  sub(addr, Operand(page_start));
+  shr(addr, kObjectAlignmentBits);
   Register pointer_offset = addr;
 
   // If the bit offset lies beyond the normal remembered set range, it is in
   // the extra remembered set area of a large object.
-  masm->cmp(pointer_offset, Page::kPageSize / kPointerSize);
-  masm->j(less, &fast);
+  cmp(pointer_offset, Page::kPageSize / kPointerSize);
+  j(less, &fast);
 
   // Adjust 'page_start' so that addressing using 'pointer_offset' hits the
   // extra remembered set after the large object.
 
   // Find the length of the large object (FixedArray).
-  masm->mov(scratch, Operand(page_start, Page::kObjectStartOffset
+  mov(scratch, Operand(page_start, Page::kObjectStartOffset
                                          + FixedArray::kLengthOffset));
   Register array_length = scratch;
 
@@ -83,59 +82,40 @@
   // Add the delta between the end of the normal RSet and the start of the
   // extra RSet to 'page_start', so that addressing the bit using
   // 'pointer_offset' hits the extra RSet words.
-  masm->lea(page_start,
-            Operand(page_start, array_length, times_pointer_size,
-                    Page::kObjectStartOffset + FixedArray::kHeaderSize
-                        - Page::kRSetEndOffset));
+  lea(page_start,
+      Operand(page_start, array_length, times_pointer_size,
+              Page::kObjectStartOffset + FixedArray::kHeaderSize
+                  - Page::kRSetEndOffset));
 
   // NOTE: For now, we use the bit-test-and-set (bts) x86 instruction
   // to limit code size. We should probably evaluate this decision by
   // measuring the performance of an equivalent implementation using
   // "simpler" instructions
-  masm->bind(&fast);
-  masm->bts(Operand(page_start, Page::kRSetOffset), pointer_offset);
+  bind(&fast);
+  bts(Operand(page_start, Page::kRSetOffset), pointer_offset);
 }
 
 
-class RecordWriteStub : public CodeStub {
- public:
-  RecordWriteStub(Register object, Register addr, Register scratch)
-      : object_(object), addr_(addr), scratch_(scratch) { }
-
-  void Generate(MacroAssembler* masm);
-
- private:
-  Register object_;
-  Register addr_;
-  Register scratch_;
-
-#ifdef DEBUG
-  void Print() {
-    PrintF("RecordWriteStub (object reg %d), (addr reg %d), (scratch reg %d)\n",
-           object_.code(), addr_.code(), scratch_.code());
+void MacroAssembler::InNewSpace(Register object,
+                                Register scratch,
+                                Condition cc,
+                                Label* branch) {
+  if (Serializer::enabled()) {
+    // Can't do arithmetic on external references if it might get serialized.
+    mov(scratch, Operand(object));
+    // The mask isn't really an address.  We load it as an external reference in
+    // case the size of the new space is different between the snapshot maker
+    // and the running system.
+    and_(Operand(scratch), Immediate(ExternalReference::new_space_mask()));
+    cmp(Operand(scratch), Immediate(ExternalReference::new_space_start()));
+    j(cc, branch);
+  } else {
+    int32_t new_space_start = reinterpret_cast<int32_t>(
+        ExternalReference::new_space_start().address());
+    lea(scratch, Operand(object, -new_space_start));
+    and_(scratch, Heap::NewSpaceMask());
+    j(cc, branch);
   }
-#endif
-
-  // Minor key encoding in 12 bits of three registers (object, address and
-  // scratch) OOOOAAAASSSS.
-  class ScratchBits: public BitField<uint32_t, 0, 4> {};
-  class AddressBits: public BitField<uint32_t, 4, 4> {};
-  class ObjectBits: public BitField<uint32_t, 8, 4> {};
-
-  Major MajorKey() { return RecordWrite; }
-
-  int MinorKey() {
-    // Encode the registers.
-    return ObjectBits::encode(object_.code()) |
-           AddressBits::encode(addr_.code()) |
-           ScratchBits::encode(scratch_.code());
-  }
-};
-
-
-void RecordWriteStub::Generate(MacroAssembler* masm) {
-  RecordWriteHelper(masm, object_, addr_, scratch_);
-  masm->ret(0);
 }
 
 
@@ -161,22 +141,7 @@
   test(value, Immediate(kSmiTagMask));
   j(zero, &done);
 
-  if (Serializer::enabled()) {
-    // Can't do arithmetic on external references if it might get serialized.
-    mov(value, Operand(object));
-    // The mask isn't really an address.  We load it as an external reference in
-    // case the size of the new space is different between the snapshot maker
-    // and the running system.
-    and_(Operand(value), Immediate(ExternalReference::new_space_mask()));
-    cmp(Operand(value), Immediate(ExternalReference::new_space_start()));
-    j(equal, &done);
-  } else {
-    int32_t new_space_start = reinterpret_cast<int32_t>(
-        ExternalReference::new_space_start().address());
-    lea(value, Operand(object, -new_space_start));
-    and_(value, Heap::NewSpaceMask());
-    j(equal, &done);
-  }
+  InNewSpace(object, value, equal, &done);
 
   if ((offset > 0) && (offset < Page::kMaxHeapObjectSize)) {
     // Compute the bit offset in the remembered set, leave it in 'value'.
@@ -209,7 +174,7 @@
     // If we are already generating a shared stub, not inlining the
     // record write code isn't going to save us any memory.
     if (generating_stub()) {
-      RecordWriteHelper(this, object, dst, value);
+      RecordWriteHelper(object, dst, value);
     } else {
       RecordWriteStub stub(object, dst, value);
       CallStub(&stub);
@@ -221,9 +186,9 @@
   // Clobber all input registers when running with the debug-code flag
   // turned on to provoke errors.
   if (FLAG_debug_code) {
-    mov(object, Immediate(bit_cast<int32_t>(kZapValue)));
-    mov(value, Immediate(bit_cast<int32_t>(kZapValue)));
-    mov(scratch, Immediate(bit_cast<int32_t>(kZapValue)));
+    mov(object, Immediate(BitCast<int32_t>(kZapValue)));
+    mov(value, Immediate(BitCast<int32_t>(kZapValue)));
+    mov(scratch, Immediate(BitCast<int32_t>(kZapValue)));
   }
 }
 
@@ -397,6 +362,12 @@
 }
 
 
+void MacroAssembler::AbortIfNotSmi(Register object, const char* msg) {
+  test(object, Immediate(kSmiTagMask));
+  Assert(equal, msg);
+}
+
+
 void MacroAssembler::EnterFrame(StackFrame::Type type) {
   push(ebp);
   mov(ebp, Operand(esp));
diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h
index a284b63..00243d7 100644
--- a/src/ia32/macro-assembler-ia32.h
+++ b/src/ia32/macro-assembler-ia32.h
@@ -48,6 +48,18 @@
   // ---------------------------------------------------------------------------
   // GC Support
 
+
+  void RecordWriteHelper(Register object,
+                         Register addr,
+                         Register scratch);
+
+  // Check if object is in new space.
+  // scratch can be object itself, but it will be clobbered.
+  void InNewSpace(Register object,
+                  Register scratch,
+                  Condition cc,  // equal for new space, not_equal otherwise.
+                  Label* branch);
+
   // Set the remembered set bit for [object+offset].
   // object is the object being stored into, value is the object being stored.
   // If offset is zero, then the scratch register contains the array index into
@@ -179,6 +191,9 @@
   // Abort execution if argument is not a number. Used in debug code.
   void AbortIfNotNumber(Register object, const char* msg);
 
+  // Abort execution if argument is not a smi. Used in debug code.
+  void AbortIfNotSmi(Register object, const char* msg);
+
   // ---------------------------------------------------------------------------
   // Exception handling
 
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index a7e9a69..902a5b8 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -549,9 +549,8 @@
   // fast api call builtin.
   void AnalyzePossibleApiFunction(JSFunction* function) {
     SharedFunctionInfo* sfi = function->shared();
-    if (sfi->function_data()->IsUndefined()) return;
-    FunctionTemplateInfo* info =
-        FunctionTemplateInfo::cast(sfi->function_data());
+    if (!sfi->IsApiFunction()) return;
+    FunctionTemplateInfo* info = sfi->get_api_func_data();
 
     // Require a C++ callback.
     if (info->call_code()->IsUndefined()) return;
@@ -698,8 +697,7 @@
 
     CallOptimization optimization(lookup);
 
-    if (optimization.is_constant_call() &&
-        !Top::CanHaveSpecialFunctions(holder)) {
+    if (optimization.is_constant_call()) {
       CompileCacheable(masm,
                        object,
                        receiver,
@@ -1211,6 +1209,195 @@
 }
 
 
+Object* CallStubCompiler::CompileArrayPushCall(Object* object,
+                                               JSObject* holder,
+                                               JSFunction* function,
+                                               String* name,
+                                               CheckType check) {
+  // ----------- S t a t e -------------
+  //  -- ecx                 : name
+  //  -- esp[0]              : return address
+  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
+  //  -- ...
+  //  -- esp[(argc + 1) * 4] : receiver
+  // -----------------------------------
+  ASSERT(check == RECEIVER_MAP_CHECK);
+
+  Label miss;
+
+  // Get the receiver from the stack.
+  const int argc = arguments().immediate();
+  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
+
+  // Check that the receiver isn't a smi.
+  __ test(edx, Immediate(kSmiTagMask));
+  __ j(zero, &miss);
+
+  CheckPrototypes(JSObject::cast(object), edx,
+                  holder, ebx,
+                  eax, name, &miss);
+
+  if (argc == 0) {
+    // Noop, return the length.
+    __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
+    __ ret((argc + 1) * kPointerSize);
+  } else {
+    // Get the elements array of the object.
+    __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset));
+
+    // Check that the elements are in fast mode (not dictionary).
+    __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
+           Immediate(Factory::fixed_array_map()));
+    __ j(not_equal, &miss);
+
+    if (argc == 1) {  // Otherwise fall through to call builtin.
+      Label call_builtin, exit, with_rset_update;
+
+      // Get the array's length into eax and calculate new length.
+      __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
+      STATIC_ASSERT(kSmiTagSize == 1);
+      STATIC_ASSERT(kSmiTag == 0);
+      __ add(Operand(eax), Immediate(argc << 1));
+
+      // Get the element's length into ecx.
+      __ mov(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
+      __ SmiTag(ecx);
+
+      // Check if we could survive without allocation, go to builtin otherwise.
+      __ cmp(eax, Operand(ecx));
+      __ j(greater, &call_builtin);
+
+      // Save new length.
+      __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
+
+      // Push the element.
+      __ lea(edx, FieldOperand(ebx,
+                               eax, times_half_pointer_size,
+                               FixedArray::kHeaderSize - argc * kPointerSize));
+      __ mov(ecx, Operand(esp, argc * kPointerSize));
+      __ mov(Operand(edx, 0), ecx);
+
+      // Check if value is a smi.
+      __ test(ecx, Immediate(kSmiTagMask));
+      __ j(not_zero, &with_rset_update);
+
+      __ bind(&exit);
+      __ ret((argc + 1) * kPointerSize);
+
+      __ bind(&with_rset_update);
+
+      __ InNewSpace(ebx, ecx, equal, &exit);
+
+      RecordWriteStub stub(ebx, edx, ecx);
+      __ CallStub(&stub);
+      __ ret((argc + 1) * kPointerSize);
+
+      __ bind(&call_builtin);
+    }
+
+    __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush),
+                                 argc + 1,
+                                 1);
+  }
+
+  __ bind(&miss);
+
+  Handle<Code> ic = ComputeCallMiss(arguments().immediate());
+  __ jmp(ic, RelocInfo::CODE_TARGET);
+
+  // Return the generated code.
+  String* function_name = NULL;
+  if (function->shared()->name()->IsString()) {
+    function_name = String::cast(function->shared()->name());
+  }
+  return GetCode(CONSTANT_FUNCTION, function_name);
+}
+
+
+Object* CallStubCompiler::CompileArrayPopCall(Object* object,
+                                              JSObject* holder,
+                                              JSFunction* function,
+                                              String* name,
+                                              CheckType check) {
+  // ----------- S t a t e -------------
+  //  -- ecx                 : name
+  //  -- esp[0]              : return address
+  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
+  //  -- ...
+  //  -- esp[(argc + 1) * 4] : receiver
+  // -----------------------------------
+  ASSERT(check == RECEIVER_MAP_CHECK);
+
+  Label miss, empty_array, call_builtin;
+
+  // Get the receiver from the stack.
+  const int argc = arguments().immediate();
+  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
+
+  // Check that the receiver isn't a smi.
+  __ test(edx, Immediate(kSmiTagMask));
+  __ j(zero, &miss);
+
+  CheckPrototypes(JSObject::cast(object), edx,
+                  holder, ebx,
+                  eax, name, &miss);
+
+  // Get the elements array of the object.
+  __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset));
+
+  // Check that the elements are in fast mode (not dictionary).
+  __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
+         Immediate(Factory::fixed_array_map()));
+  __ j(not_equal, &miss);
+
+  // Get the array's length into ecx and calculate new length.
+  __ mov(ecx, FieldOperand(edx, JSArray::kLengthOffset));
+  __ sub(Operand(ecx), Immediate(Smi::FromInt(1)));
+  __ j(negative, &empty_array);
+
+  // Get the last element.
+  STATIC_ASSERT(kSmiTagSize == 1);
+  STATIC_ASSERT(kSmiTag == 0);
+  __ mov(eax, FieldOperand(ebx,
+                           ecx, times_half_pointer_size,
+                           FixedArray::kHeaderSize));
+  __ cmp(Operand(eax), Immediate(Factory::the_hole_value()));
+  __ j(equal, &call_builtin);
+
+  // Set the array's length.
+  __ mov(FieldOperand(edx, JSArray::kLengthOffset), ecx);
+
+  // Fill with the hole.
+  __ mov(FieldOperand(ebx,
+                      ecx, times_half_pointer_size,
+                      FixedArray::kHeaderSize),
+         Immediate(Factory::the_hole_value()));
+  __ ret((argc + 1) * kPointerSize);
+
+  __ bind(&empty_array);
+  __ mov(eax, Immediate(Factory::undefined_value()));
+  __ ret((argc + 1) * kPointerSize);
+
+  __ bind(&call_builtin);
+
+  __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop),
+                               argc + 1,
+                               1);
+
+  __ bind(&miss);
+
+  Handle<Code> ic = ComputeCallMiss(arguments().immediate());
+  __ jmp(ic, RelocInfo::CODE_TARGET);
+
+  // Return the generated code.
+  String* function_name = NULL;
+  if (function->shared()->name()->IsString()) {
+    function_name = String::cast(function->shared()->name());
+  }
+  return GetCode(CONSTANT_FUNCTION, function_name);
+}
+
+
 Object* CallStubCompiler::CompileCallConstant(Object* object,
                                               JSObject* holder,
                                               JSFunction* function,
@@ -1223,6 +1410,14 @@
   //  -- ...
   //  -- esp[(argc + 1) * 4] : receiver
   // -----------------------------------
+
+  SharedFunctionInfo* function_info = function->shared();
+  if (function_info->HasCustomCallGenerator()) {
+    CustomCallGenerator generator =
+        ToCData<CustomCallGenerator>(function_info->function_data());
+    return generator(this, object, holder, function, name, check);
+  }
+
   Label miss_in_smi_check;
 
   // Get the receiver from the stack.
@@ -1333,18 +1528,6 @@
       break;
     }
 
-    case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
-      CheckPrototypes(JSObject::cast(object), edx, holder,
-                      ebx, eax, name, &miss);
-      // Make sure object->HasFastElements().
-      // Get the elements array of the object.
-      __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
-      // Check that the object is in fast mode (not dictionary).
-      __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
-             Immediate(Factory::fixed_array_map()));
-      __ j(not_equal, &miss, not_taken);
-      break;
-
     default:
       UNREACHABLE();
   }
diff --git a/src/ia32/virtual-frame-ia32.cc b/src/ia32/virtual-frame-ia32.cc
index 7b03a5b..a749c78 100644
--- a/src/ia32/virtual-frame-ia32.cc
+++ b/src/ia32/virtual-frame-ia32.cc
@@ -1171,11 +1171,17 @@
   }
 
   VariableProxy* proxy = expr->AsVariableProxy();
-  if (proxy != NULL && proxy->is_this()) {
-    PushParameterAt(-1);
-    return;
+  if (proxy != NULL) {
+    Slot* slot = proxy->var()->slot();
+    if (slot->type() == Slot::LOCAL) {
+      PushLocalAt(slot->index());
+      return;
+    }
+    if (slot->type() == Slot::PARAMETER) {
+      PushParameterAt(slot->index());
+      return;
+    }
   }
-
   UNREACHABLE();
 }
 
diff --git a/src/ia32/virtual-frame-ia32.h b/src/ia32/virtual-frame-ia32.h
index cd2d18f..042f9b7 100644
--- a/src/ia32/virtual-frame-ia32.h
+++ b/src/ia32/virtual-frame-ia32.h
@@ -422,6 +422,9 @@
   // the frame.  Nip(k) is equivalent to x = Pop(), Drop(k), Push(x).
   inline void Nip(int num_dropped);
 
+  // Update the type information of a local variable frame element directly.
+  inline void SetTypeForLocalAt(int index, NumberInfo info);
+
  private:
   static const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;
   static const int kFunctionOffset = JavaScriptFrameConstants::kFunctionOffset;
diff --git a/src/ic.cc b/src/ic.cc
index 31154b7..2b97a8b 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -458,17 +458,6 @@
   ASSERT(result != Heap::the_hole_value());
 
   if (result->IsJSFunction()) {
-    // Check if there is an optimized (builtin) version of the function.
-    // Ignored this will degrade performance for some Array functions.
-    // Please note we only return the optimized function iff
-    // the JSObject has FastElements.
-    if (object->IsJSObject() && JSObject::cast(*object)->HasFastElements()) {
-      Object* opt = Top::LookupSpecialFunction(JSObject::cast(*object),
-                                               lookup.holder(),
-                                               JSFunction::cast(result));
-      if (opt->IsJSFunction()) return opt;
-    }
-
 #ifdef ENABLE_DEBUGGER_SUPPORT
     // Handle stepping into a function if step into is active.
     if (Debug::StepInActive()) {
diff --git a/src/log-utils.cc b/src/log-utils.cc
index 722e0fc..62f0ca6 100644
--- a/src/log-utils.cc
+++ b/src/log-utils.cc
@@ -196,6 +196,9 @@
   char* end_pos = dest_buf + actual_size - 1;
   while (end_pos >= dest_buf && *end_pos != '\n') --end_pos;
   actual_size = static_cast<int>(end_pos - dest_buf + 1);
+  // If the assertion below is hit, it means that there was no line end
+  // found --- something wrong has happened.
+  ASSERT(actual_size > 0);
   ASSERT(actual_size <= max_size);
   return actual_size;
 }
diff --git a/src/log-utils.h b/src/log-utils.h
index b769e90..8889f1b 100644
--- a/src/log-utils.h
+++ b/src/log-utils.h
@@ -115,7 +115,7 @@
   }
 
   // Size of buffer used for formatting log messages.
-  static const int kMessageBufferSize = 2048;
+  static const int kMessageBufferSize = v8::V8::kMinimumSizeForLogLinesBuffer;
 
  private:
   typedef int (*WritePtr)(const char* msg, int length);
diff --git a/src/log.cc b/src/log.cc
index 588d345..4441875 100644
--- a/src/log.cc
+++ b/src/log.cc
@@ -1346,10 +1346,9 @@
         LOG(CodeCreateEvent(
             Logger::LAZY_COMPILE_TAG, shared->code(), *func_name));
       }
-    } else if (shared->function_data()->IsFunctionTemplateInfo()) {
+    } else if (shared->IsApiFunction()) {
       // API function.
-      FunctionTemplateInfo* fun_data =
-          FunctionTemplateInfo::cast(shared->function_data());
+      FunctionTemplateInfo* fun_data = shared->get_api_func_data();
       Object* raw_call_data = fun_data->call_code();
       if (!raw_call_data->IsUndefined()) {
         CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
diff --git a/src/macros.py b/src/macros.py
index 9da2552..122b057 100644
--- a/src/macros.py
+++ b/src/macros.py
@@ -136,9 +136,9 @@
 # a type error is thrown.
 macro DATE_VALUE(arg) = (%_ClassOf(arg) === 'Date' ? %_ValueOf(arg) : ThrowDateTypeError());
 macro DAY(time) = ($floor(time / 86400000));
-macro MONTH_FROM_TIME(time) = (FromJulianDay(($floor(time / 86400000)) + 2440588).month);
-macro DATE_FROM_TIME(time) = (FromJulianDay(($floor(time / 86400000)) + 2440588).date);
-macro YEAR_FROM_TIME(time) = (FromJulianDay(($floor(time / 86400000)) + 2440588).year);
+macro MONTH_FROM_TIME(time) = (MonthFromTime(time));
+macro DATE_FROM_TIME(time) = (DateFromTime(time));
+macro YEAR_FROM_TIME(time) = (YearFromTime(time));
 macro HOUR_FROM_TIME(time) = (Modulo($floor(time / 3600000), 24));
 macro MIN_FROM_TIME(time) = (Modulo($floor(time / 60000), 60));
 macro SEC_FROM_TIME(time) = (Modulo($floor(time / 1000), 60));
diff --git a/src/math.js b/src/math.js
index 034f32d..0623cb8 100644
--- a/src/math.js
+++ b/src/math.js
@@ -45,7 +45,8 @@
 function MathAbs(x) {
   if (%_IsSmi(x)) return x >= 0 ? x : -x;
   if (!IS_NUMBER(x)) x = ToNumber(x);
-  return %Math_abs(x);
+  if (x === 0) return 0;  // To handle -0.
+  return x > 0 ? x : -x;
 }
 
 // ECMA 262 - 15.8.2.2
@@ -84,7 +85,7 @@
 // ECMA 262 - 15.8.2.7
 function MathCos(x) {
   if (!IS_NUMBER(x)) x = ToNumber(x);
-  return %_Math_cos(x);
+  return %_MathCos(x);
 }
 
 // ECMA 262 - 15.8.2.8
@@ -159,7 +160,7 @@
 function MathPow(x, y) {
   if (!IS_NUMBER(x)) x = ToNumber(x);
   if (!IS_NUMBER(y)) y = ToNumber(y);
-  return %_Math_pow(x, y);
+  return %_MathPow(x, y);
 }
 
 // ECMA 262 - 15.8.2.14
@@ -176,13 +177,13 @@
 // ECMA 262 - 15.8.2.16
 function MathSin(x) {
   if (!IS_NUMBER(x)) x = ToNumber(x);
-  return %_Math_sin(x);
+  return %_MathSin(x);
 }
 
 // ECMA 262 - 15.8.2.17
 function MathSqrt(x) {
   if (!IS_NUMBER(x)) x = ToNumber(x);
-  return %_Math_sqrt(x);
+  return %_MathSqrt(x);
 }
 
 // ECMA 262 - 15.8.2.18
diff --git a/src/messages.js b/src/messages.js
index 5848115..cb392ff 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -182,7 +182,8 @@
       invalid_json:                 "String '%0' is not valid JSON",
       circular_structure:           "Converting circular structure to JSON",
       obj_ctor_property_non_object: "Object.%0 called on non-object",
-      array_indexof_not_defined:    "Array.getIndexOf: Argument undefined"
+      array_indexof_not_defined:    "Array.getIndexOf: Argument undefined",
+      illegal_access:               "illegal access"
     };
   }
   var format = kMessages[message.type];
diff --git a/src/mips/codegen-mips-inl.h b/src/mips/codegen-mips-inl.h
index 2a77715..904dd74 100644
--- a/src/mips/codegen-mips-inl.h
+++ b/src/mips/codegen-mips-inl.h
@@ -38,16 +38,6 @@
 
 void DeferredCode::Jump() { __ b(&entry_label_); }
 
-void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) {
-  UNIMPLEMENTED_MIPS();
-}
-
-
-void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) {
-  UNIMPLEMENTED_MIPS();
-}
-
-
 #undef __
 
 } }  // namespace v8::internal
diff --git a/src/mips/codegen-mips.cc b/src/mips/codegen-mips.cc
index facccc2..7b32180 100644
--- a/src/mips/codegen-mips.cc
+++ b/src/mips/codegen-mips.cc
@@ -31,6 +31,7 @@
 #include "bootstrapper.h"
 #include "codegen-inl.h"
 #include "debug.h"
+#include "ic-inl.h"
 #include "parser.h"
 #include "register-allocator-inl.h"
 #include "runtime.h"
@@ -297,6 +298,16 @@
 }
 
 
+void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) {
+  UNIMPLEMENTED_MIPS();
+}
+
+
+void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) {
+  UNIMPLEMENTED_MIPS();
+}
+
+
 void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) {
   UNIMPLEMENTED_MIPS();
 }
@@ -335,7 +346,7 @@
 }
 
 
-void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateArguments(ZoneList<Expression*>* args) {
   UNIMPLEMENTED_MIPS();
 }
 
@@ -429,6 +440,11 @@
 #define __ ACCESS_MASM(masm)
 
 
+Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) {
+  return Handle<Code>::null();
+}
+
+
 // On entry a0 and a1 are the things to be compared.  On exit v0 is 0,
 // positive or negative to indicate the result of the comparison.
 void CompareStub::Generate(MacroAssembler* masm) {
diff --git a/src/mips/codegen-mips.h b/src/mips/codegen-mips.h
index 987dcca..3f78fcd 100644
--- a/src/mips/codegen-mips.h
+++ b/src/mips/codegen-mips.h
@@ -154,6 +154,10 @@
   // used by the debugger to patch the JS return sequence.
   static const int kJSReturnSequenceLength = 6;
 
+  // If the name is an inline runtime function call return the number of
+  // expected arguments. Otherwise return -1.
+  static int InlineRuntimeCallArgumentsCount(Handle<String> name);
+
  private:
   // Construction/Destruction.
   explicit CodeGenerator(MacroAssembler* masm);
@@ -188,6 +192,7 @@
   struct InlineRuntimeLUT {
     void (CodeGenerator::*method)(ZoneList<Expression*>*);
     const char* name;
+    int nargs;
   };
 
   static InlineRuntimeLUT* FindInlineRuntimeLUT(Handle<String> name);
@@ -216,7 +221,7 @@
 
   // Support for arguments.length and arguments[?].
   void GenerateArgumentsLength(ZoneList<Expression*>* args);
-  void GenerateArgumentsAccess(ZoneList<Expression*>* args);
+  void GenerateArguments(ZoneList<Expression*>* args);
 
   // Support for accessing the class and value fields of an object.
   void GenerateClassOf(ZoneList<Expression*>* args);
@@ -246,15 +251,11 @@
   void GenerateRegExpExec(ZoneList<Expression*>* args);
   void GenerateNumberToString(ZoneList<Expression*>* args);
 
-  // Fast support for Math.pow().
+  // Fast call to math functions.
   void GenerateMathPow(ZoneList<Expression*>* args);
-  // Fast support for Math.sqrt().
-  void GenerateMathPow(ZoneList<Expression*>* args);
-
-
-  // Fast support for Math.sin and Math.cos.
-  inline void GenerateMathSin(ZoneList<Expression*>* args);
-  inline void GenerateMathCos(ZoneList<Expression*>* args);
+  void GenerateMathSin(ZoneList<Expression*>* args);
+  void GenerateMathCos(ZoneList<Expression*>* args);
+  void GenerateMathSqrt(ZoneList<Expression*>* args);
 
   // Simple condition analysis.
   enum ConditionAnalysis {
diff --git a/src/mips/simulator-mips.cc b/src/mips/simulator-mips.cc
index 2e2dc86..e2280d3 100644
--- a/src/mips/simulator-mips.cc
+++ b/src/mips/simulator-mips.cc
@@ -31,7 +31,7 @@
 
 #include "disasm.h"
 #include "assembler.h"
-#include "globals.h"    // Need the bit_cast
+#include "globals.h"    // Need the BitCast
 #include "mips/constants-mips.h"
 #include "mips/simulator-mips.h"
 
@@ -604,7 +604,7 @@
 
 void Simulator::set_fpu_register_double(int fpureg, double value) {
   ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
-  *v8i::bit_cast<double*, int32_t*>(&FPUregisters_[fpureg]) = value;
+  *v8i::BitCast<double*, int32_t*>(&FPUregisters_[fpureg]) = value;
 }
 
 
@@ -625,7 +625,7 @@
 
 double Simulator::get_fpu_register_double(int fpureg) const {
   ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
-  return *v8i::bit_cast<double*, int32_t*>(
+  return *v8i::BitCast<double*, int32_t*>(
       const_cast<int32_t*>(&FPUregisters_[fpureg]));
 }
 
@@ -901,7 +901,7 @@
           break;
         case MFHC1:
           fp_out = get_fpu_register_double(fs_reg);
-          alu_out = *v8i::bit_cast<int32_t*, double*>(&fp_out);
+          alu_out = *v8i::BitCast<int32_t*, double*>(&fp_out);
           break;
         case MTC1:
         case MTHC1:
diff --git a/src/mips/virtual-frame-mips.h b/src/mips/virtual-frame-mips.h
index e5bc93f..77c795c 100644
--- a/src/mips/virtual-frame-mips.h
+++ b/src/mips/virtual-frame-mips.h
@@ -71,7 +71,7 @@
 
   // Create a duplicate of an existing valid frame element.
   FrameElement CopyElementAt(int index,
-                             NumberInfo::Type info = NumberInfo::kUnknown);
+                             NumberInfo info = NumberInfo::Unknown());
 
   // The number of elements on the virtual frame.
   int element_count() { return elements_.length(); }
@@ -367,7 +367,7 @@
   void EmitMultiPushReversed(RegList regs);  // higher first
 
   // Push an element on the virtual frame.
-  inline void Push(Register reg, NumberInfo::Type info = NumberInfo::kUnknown);
+  inline void Push(Register reg, NumberInfo info = NumberInfo::Unknown());
   inline void Push(Handle<Object> value);
   inline void Push(Smi* value);
 
@@ -391,6 +391,8 @@
   // 'a' registers are arguments register a0 to a3.
   void EmitArgumentSlots(RegList reglist);
 
+  inline void SetTypeForLocalAt(int index, NumberInfo info);
+
  private:
   static const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;
   static const int kFunctionOffset = JavaScriptFrameConstants::kFunctionOffset;
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index 492b492..44a3b1a 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -789,7 +789,7 @@
   VerifyObjectField(kNameOffset);
   VerifyObjectField(kCodeOffset);
   VerifyObjectField(kInstanceClassNameOffset);
-  VerifyObjectField(kExternalReferenceDataOffset);
+  VerifyObjectField(kFunctionDataOffset);
   VerifyObjectField(kScriptOffset);
   VerifyObjectField(kDebugInfoOffset);
 }
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 18f45f3..4cc9b9f 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -2361,8 +2361,7 @@
 ACCESSORS(SharedFunctionInfo, name, Object, kNameOffset)
 ACCESSORS(SharedFunctionInfo, instance_class_name, Object,
           kInstanceClassNameOffset)
-ACCESSORS(SharedFunctionInfo, function_data, Object,
-          kExternalReferenceDataOffset)
+ACCESSORS(SharedFunctionInfo, function_data, Object, kFunctionDataOffset)
 ACCESSORS(SharedFunctionInfo, script, Object, kScriptOffset)
 ACCESSORS(SharedFunctionInfo, debug_info, Object, kDebugInfoOffset)
 ACCESSORS(SharedFunctionInfo, inferred_name, String, kInferredNameOffset)
@@ -2453,6 +2452,22 @@
 }
 
 
+bool SharedFunctionInfo::IsApiFunction() {
+  return function_data()->IsFunctionTemplateInfo();
+}
+
+
+FunctionTemplateInfo* SharedFunctionInfo::get_api_func_data() {
+  ASSERT(IsApiFunction());
+  return FunctionTemplateInfo::cast(function_data());
+}
+
+
+bool SharedFunctionInfo::HasCustomCallGenerator() {
+  return function_data()->IsProxy();
+}
+
+
 bool JSFunction::IsBoilerplate() {
   return map() == Heap::boilerplate_function_map();
 }
diff --git a/src/objects.cc b/src/objects.cc
index 5457678..132aa9e 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -480,7 +480,7 @@
   if (!cons_obj->IsJSFunction())
     return true;
   JSFunction* fun = JSFunction::cast(cons_obj);
-  if (!fun->shared()->function_data()->IsFunctionTemplateInfo())
+  if (!fun->shared()->IsApiFunction())
     return true;
   // If the object is fully fast case and has the same map it was
   // created with then no changes can have been made to it.
@@ -6433,9 +6433,9 @@
 InterceptorInfo* JSObject::GetNamedInterceptor() {
   ASSERT(map()->has_named_interceptor());
   JSFunction* constructor = JSFunction::cast(map()->constructor());
-  Object* template_info = constructor->shared()->function_data();
+  ASSERT(constructor->shared()->IsApiFunction());
   Object* result =
-      FunctionTemplateInfo::cast(template_info)->named_property_handler();
+      constructor->shared()->get_api_func_data()->named_property_handler();
   return InterceptorInfo::cast(result);
 }
 
@@ -6443,9 +6443,9 @@
 InterceptorInfo* JSObject::GetIndexedInterceptor() {
   ASSERT(map()->has_indexed_interceptor());
   JSFunction* constructor = JSFunction::cast(map()->constructor());
-  Object* template_info = constructor->shared()->function_data();
+  ASSERT(constructor->shared()->IsApiFunction());
   Object* result =
-      FunctionTemplateInfo::cast(template_info)->indexed_property_handler();
+      constructor->shared()->get_api_func_data()->indexed_property_handler();
   return InterceptorInfo::cast(result);
 }
 
diff --git a/src/objects.h b/src/objects.h
index 2004d50..b3fe448 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -2154,24 +2154,24 @@
 
   // Returns the value at entry.
   Object* ValueAt(int entry) {
-    return get(HashTable<Shape, Key>::EntryToIndex(entry)+1);
+    return this->get(HashTable<Shape, Key>::EntryToIndex(entry)+1);
   }
 
   // Set the value for entry.
   void ValueAtPut(int entry, Object* value) {
-    set(HashTable<Shape, Key>::EntryToIndex(entry)+1, value);
+    this->set(HashTable<Shape, Key>::EntryToIndex(entry)+1, value);
   }
 
   // Returns the property details for the property at entry.
   PropertyDetails DetailsAt(int entry) {
     ASSERT(entry >= 0);  // Not found is -1, which is not caught by get().
     return PropertyDetails(
-        Smi::cast(get(HashTable<Shape, Key>::EntryToIndex(entry) + 2)));
+        Smi::cast(this->get(HashTable<Shape, Key>::EntryToIndex(entry) + 2)));
   }
 
   // Set the details for entry.
   void DetailsAtPut(int entry, PropertyDetails value) {
-    set(HashTable<Shape, Key>::EntryToIndex(entry) + 2, value.AsSmi());
+    this->set(HashTable<Shape, Key>::EntryToIndex(entry) + 2, value.AsSmi());
   }
 
   // Sorting support
@@ -2194,7 +2194,7 @@
 
   // Accessors for next enumeration index.
   void SetNextEnumerationIndex(int index) {
-    fast_set(this, kNextEnumerationIndexIndex, Smi::FromInt(index));
+    this->fast_set(this, kNextEnumerationIndexIndex, Smi::FromInt(index));
   }
 
   int NextEnumerationIndex() {
@@ -3186,12 +3186,18 @@
   // [instance class name]: class name for instances.
   DECL_ACCESSORS(instance_class_name, Object)
 
-  // [function data]: This field has been added for make benefit the API.
+  // [function data]: This field holds some additional data for function.
+  // Currently it either has FunctionTemplateInfo to make benefit the API
+  // or Proxy wrapping CustomCallGenerator.
   // In the long run we don't want all functions to have this field but
   // we can fix that when we have a better model for storing hidden data
   // on objects.
   DECL_ACCESSORS(function_data, Object)
 
+  inline bool IsApiFunction();
+  inline FunctionTemplateInfo* get_api_func_data();
+  inline bool HasCustomCallGenerator();
+
   // [script info]: Script from which the function originates.
   DECL_ACCESSORS(script, Object)
 
@@ -3299,9 +3305,9 @@
   static const int kConstructStubOffset = kCodeOffset + kPointerSize;
   static const int kInstanceClassNameOffset =
       kConstructStubOffset + kPointerSize;
-  static const int kExternalReferenceDataOffset =
+  static const int kFunctionDataOffset =
       kInstanceClassNameOffset + kPointerSize;
-  static const int kScriptOffset = kExternalReferenceDataOffset + kPointerSize;
+  static const int kScriptOffset = kFunctionDataOffset + kPointerSize;
   static const int kDebugInfoOffset = kScriptOffset + kPointerSize;
   static const int kInferredNameOffset = kDebugInfoOffset + kPointerSize;
   static const int kThisPropertyAssignmentsOffset =
diff --git a/src/parser.cc b/src/parser.cc
index dd72669..74f6997 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -30,6 +30,7 @@
 #include "api.h"
 #include "ast.h"
 #include "bootstrapper.h"
+#include "codegen.h"
 #include "compiler.h"
 #include "messages.h"
 #include "platform.h"
@@ -211,6 +212,7 @@
       ZoneList<ObjectLiteral::Property*>* properties,
       Handle<FixedArray> constants,
       bool* is_simple,
+      bool* fast_elements,
       int* depth);
 
   // Populate the literals fixed array for a materialized array literal.
@@ -1962,9 +1964,7 @@
       Factory::NewFunctionBoilerplate(name, literals, code);
   boilerplate->shared()->set_construct_stub(*construct_stub);
 
-  // Copy the function data to the boilerplate. Used by
-  // builtins.cc:HandleApiCall to perform argument type checks and to
-  // find the right native code to call.
+  // Copy the function data to the boilerplate.
   boilerplate->shared()->set_function_data(fun->shared()->function_data());
   int parameters = fun->shared()->formal_parameter_count();
   boilerplate->shared()->set_formal_parameter_count(parameters);
@@ -3445,7 +3445,11 @@
   ObjectLiteral* object_literal = expression->AsObjectLiteral();
   if (object_literal != NULL) {
     ASSERT(object_literal->is_simple());
-    result->set(kTypeSlot, Smi::FromInt(OBJECT_LITERAL));
+    if (object_literal->fast_elements()) {
+      result->set(kTypeSlot, Smi::FromInt(OBJECT_LITERAL_FAST_ELEMENTS));
+    } else {
+      result->set(kTypeSlot, Smi::FromInt(OBJECT_LITERAL_SLOW_ELEMENTS));
+    }
     result->set(kElementsSlot, *object_literal->constant_properties());
   } else {
     ArrayLiteral* array_literal = expression->AsArrayLiteral();
@@ -3483,11 +3487,14 @@
     ZoneList<ObjectLiteral::Property*>* properties,
     Handle<FixedArray> constant_properties,
     bool* is_simple,
+    bool* fast_elements,
     int* depth) {
   int position = 0;
   // Accumulate the value in local variables and store it at the end.
   bool is_simple_acc = true;
   int depth_acc = 1;
+  uint32_t max_element_index = 0;
+  uint32_t elements = 0;
   for (int i = 0; i < properties->length(); i++) {
     ObjectLiteral::Property* property = properties->at(i);
     if (!IsBoilerplateProperty(property)) {
@@ -3506,11 +3513,31 @@
     Handle<Object> value = GetBoilerplateValue(property->value());
     is_simple_acc = is_simple_acc && !value->IsUndefined();
 
+    // Keep track of the number of elements in the object literal and
+    // the largest element index.  If the largest element index is
+    // much larger than the number of elements, creating an object
+    // literal with fast elements will be a waste of space.
+    uint32_t element_index = 0;
+    if (key->IsString()
+        && Handle<String>::cast(key)->AsArrayIndex(&element_index)
+        && element_index > max_element_index) {
+      max_element_index = element_index;
+      elements++;
+    } else if (key->IsSmi()) {
+      int key_value = Smi::cast(*key)->value();
+      if (key_value > 0
+          && static_cast<uint32_t>(key_value) > max_element_index) {
+        max_element_index = key_value;
+      }
+      elements++;
+    }
+
     // Add name, value pair to the fixed array.
     constant_properties->set(position++, *key);
     constant_properties->set(position++, *value);
   }
-
+  *fast_elements =
+      (max_element_index <= 32) || ((2 * elements) >= max_element_index);
   *is_simple = is_simple_acc;
   *depth = depth_acc;
 }
@@ -3608,15 +3635,18 @@
       Factory::NewFixedArray(number_of_boilerplate_properties * 2, TENURED);
 
   bool is_simple = true;
+  bool fast_elements = true;
   int depth = 1;
   BuildObjectLiteralConstantProperties(properties.elements(),
                                        constant_properties,
                                        &is_simple,
+                                       &fast_elements,
                                        &depth);
   return new ObjectLiteral(constant_properties,
                            properties.elements(),
                            literal_index,
                            is_simple,
+                           fast_elements,
                            depth);
 }
 
@@ -3832,7 +3862,27 @@
     }
   }
 
-  // Otherwise we have a runtime call.
+  // Check that the expected number arguments are passed to runtime functions.
+  if (!is_pre_parsing_) {
+    if (function != NULL
+        && function->nargs != -1
+        && function->nargs != args->length()) {
+      ReportMessage("illegal_access", Vector<const char*>::empty());
+      *ok = false;
+      return NULL;
+    } else if (function == NULL && !name.is_null()) {
+      // If this is not a runtime function implemented in C++ it might be an
+      // inlined runtime function.
+      int argc = CodeGenerator::InlineRuntimeCallArgumentsCount(name);
+      if (argc != -1 && argc != args->length()) {
+        ReportMessage("illegal_access", Vector<const char*>::empty());
+        *ok = false;
+        return NULL;
+      }
+    }
+  }
+
+  // Otherwise we have a valid runtime call.
   return NEW(CallRuntime(name, function, args));
 }
 
@@ -4123,15 +4173,18 @@
   Handle<FixedArray> constant_properties =
         Factory::NewFixedArray(boilerplate_properties * 2, TENURED);
   bool is_simple = true;
+  bool fast_elements = true;
   int depth = 1;
   BuildObjectLiteralConstantProperties(properties.elements(),
                                        constant_properties,
                                        &is_simple,
+                                       &fast_elements,
                                        &depth);
   return new ObjectLiteral(constant_properties,
                            properties.elements(),
                            literal_index,
                            is_simple,
+                           fast_elements,
                            depth);
 }
 
diff --git a/src/parser.h b/src/parser.h
index 0f808d7..2e5daf9 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -168,7 +168,8 @@
 class CompileTimeValue: public AllStatic {
  public:
   enum Type {
-    OBJECT_LITERAL,
+    OBJECT_LITERAL_FAST_ELEMENTS,
+    OBJECT_LITERAL_SLOW_ELEMENTS,
     ARRAY_LITERAL
   };
 
diff --git a/src/powers_ten.h b/src/powers_ten.h
new file mode 100644
index 0000000..7e88c51
--- /dev/null
+++ b/src/powers_ten.h
@@ -0,0 +1,2461 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// ------------ GENERATED FILE ----------------
+// command used:
+//  tools/generate-ten-powers --from -308 --to 342 --mantissa-size 64 --round round -o src/powers_ten.h  // NOLINT
+
+// This file is intended to be included inside another .h or .cc files
+// with the following defines set:
+//  GRISU_CACHE_STRUCT: should expand to the name of a struct that will
+//   hold the cached powers of ten. Each entry will hold a 64-bit
+//   significand, a 16-bit signed binary exponent, and a 16-bit
+//   signed decimal exponent. Each entry will be constructed as follows:
+//      { significand, binary_exponent, decimal_exponent }.
+//  GRISU_CACHE_NAME(i): generates the name for the different caches.
+//   The parameter i will be a number in the range 1-20. A cache will
+//   hold every i'th element of a full cache. GRISU_CACHE_NAME(1) will
+//   thus hold all elements. The higher i the fewer elements it has.
+//   Ideally the user should only reference one cache and let the
+//   compiler remove the unused ones.
+//  GRISU_CACHE_MAX_DISTANCE(i): generates the name for the maximum
+//   binary exponent distance between all elements of a given cache.
+//  GRISU_CACHE_OFFSET: is used as variable name for the decimal
+//   exponent offset. It is equal to -cache[0].decimal_exponent.
+//  GRISU_UINT64_C: used to construct 64-bit values in a platform
+//   independent way. In order to encode 0x123456789ABCDEF0 the macro
+//   will be invoked as follows: GRISU_UINT64_C(0x12345678,9ABCDEF0).
+
+
+static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(1)[] = {
+  {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308},
+  {GRISU_UINT64_C(0x8fd0c162, 06306bac), -1083, -307},
+  {GRISU_UINT64_C(0xb3c4f1ba, 87bc8697), -1080, -306},
+  {GRISU_UINT64_C(0xe0b62e29, 29aba83c), -1077, -305},
+  {GRISU_UINT64_C(0x8c71dcd9, ba0b4926), -1073, -304},
+  {GRISU_UINT64_C(0xaf8e5410, 288e1b6f), -1070, -303},
+  {GRISU_UINT64_C(0xdb71e914, 32b1a24b), -1067, -302},
+  {GRISU_UINT64_C(0x892731ac, 9faf056f), -1063, -301},
+  {GRISU_UINT64_C(0xab70fe17, c79ac6ca), -1060, -300},
+  {GRISU_UINT64_C(0xd64d3d9d, b981787d), -1057, -299},
+  {GRISU_UINT64_C(0x85f04682, 93f0eb4e), -1053, -298},
+  {GRISU_UINT64_C(0xa76c5823, 38ed2622), -1050, -297},
+  {GRISU_UINT64_C(0xd1476e2c, 07286faa), -1047, -296},
+  {GRISU_UINT64_C(0x82cca4db, 847945ca), -1043, -295},
+  {GRISU_UINT64_C(0xa37fce12, 6597973d), -1040, -294},
+  {GRISU_UINT64_C(0xcc5fc196, fefd7d0c), -1037, -293},
+  {GRISU_UINT64_C(0xff77b1fc, bebcdc4f), -1034, -292},
+  {GRISU_UINT64_C(0x9faacf3d, f73609b1), -1030, -291},
+  {GRISU_UINT64_C(0xc795830d, 75038c1e), -1027, -290},
+  {GRISU_UINT64_C(0xf97ae3d0, d2446f25), -1024, -289},
+  {GRISU_UINT64_C(0x9becce62, 836ac577), -1020, -288},
+  {GRISU_UINT64_C(0xc2e801fb, 244576d5), -1017, -287},
+  {GRISU_UINT64_C(0xf3a20279, ed56d48a), -1014, -286},
+  {GRISU_UINT64_C(0x9845418c, 345644d7), -1010, -285},
+  {GRISU_UINT64_C(0xbe5691ef, 416bd60c), -1007, -284},
+  {GRISU_UINT64_C(0xedec366b, 11c6cb8f), -1004, -283},
+  {GRISU_UINT64_C(0x94b3a202, eb1c3f39), -1000, -282},
+  {GRISU_UINT64_C(0xb9e08a83, a5e34f08), -997, -281},
+  {GRISU_UINT64_C(0xe858ad24, 8f5c22ca), -994, -280},
+  {GRISU_UINT64_C(0x91376c36, d99995be), -990, -279},
+  {GRISU_UINT64_C(0xb5854744, 8ffffb2e), -987, -278},
+  {GRISU_UINT64_C(0xe2e69915, b3fff9f9), -984, -277},
+  {GRISU_UINT64_C(0x8dd01fad, 907ffc3c), -980, -276},
+  {GRISU_UINT64_C(0xb1442798, f49ffb4b), -977, -275},
+  {GRISU_UINT64_C(0xdd95317f, 31c7fa1d), -974, -274},
+  {GRISU_UINT64_C(0x8a7d3eef, 7f1cfc52), -970, -273},
+  {GRISU_UINT64_C(0xad1c8eab, 5ee43b67), -967, -272},
+  {GRISU_UINT64_C(0xd863b256, 369d4a41), -964, -271},
+  {GRISU_UINT64_C(0x873e4f75, e2224e68), -960, -270},
+  {GRISU_UINT64_C(0xa90de353, 5aaae202), -957, -269},
+  {GRISU_UINT64_C(0xd3515c28, 31559a83), -954, -268},
+  {GRISU_UINT64_C(0x8412d999, 1ed58092), -950, -267},
+  {GRISU_UINT64_C(0xa5178fff, 668ae0b6), -947, -266},
+  {GRISU_UINT64_C(0xce5d73ff, 402d98e4), -944, -265},
+  {GRISU_UINT64_C(0x80fa687f, 881c7f8e), -940, -264},
+  {GRISU_UINT64_C(0xa139029f, 6a239f72), -937, -263},
+  {GRISU_UINT64_C(0xc9874347, 44ac874f), -934, -262},
+  {GRISU_UINT64_C(0xfbe91419, 15d7a922), -931, -261},
+  {GRISU_UINT64_C(0x9d71ac8f, ada6c9b5), -927, -260},
+  {GRISU_UINT64_C(0xc4ce17b3, 99107c23), -924, -259},
+  {GRISU_UINT64_C(0xf6019da0, 7f549b2b), -921, -258},
+  {GRISU_UINT64_C(0x99c10284, 4f94e0fb), -917, -257},
+  {GRISU_UINT64_C(0xc0314325, 637a193a), -914, -256},
+  {GRISU_UINT64_C(0xf03d93ee, bc589f88), -911, -255},
+  {GRISU_UINT64_C(0x96267c75, 35b763b5), -907, -254},
+  {GRISU_UINT64_C(0xbbb01b92, 83253ca3), -904, -253},
+  {GRISU_UINT64_C(0xea9c2277, 23ee8bcb), -901, -252},
+  {GRISU_UINT64_C(0x92a1958a, 7675175f), -897, -251},
+  {GRISU_UINT64_C(0xb749faed, 14125d37), -894, -250},
+  {GRISU_UINT64_C(0xe51c79a8, 5916f485), -891, -249},
+  {GRISU_UINT64_C(0x8f31cc09, 37ae58d3), -887, -248},
+  {GRISU_UINT64_C(0xb2fe3f0b, 8599ef08), -884, -247},
+  {GRISU_UINT64_C(0xdfbdcece, 67006ac9), -881, -246},
+  {GRISU_UINT64_C(0x8bd6a141, 006042be), -877, -245},
+  {GRISU_UINT64_C(0xaecc4991, 4078536d), -874, -244},
+  {GRISU_UINT64_C(0xda7f5bf5, 90966849), -871, -243},
+  {GRISU_UINT64_C(0x888f9979, 7a5e012d), -867, -242},
+  {GRISU_UINT64_C(0xaab37fd7, d8f58179), -864, -241},
+  {GRISU_UINT64_C(0xd5605fcd, cf32e1d7), -861, -240},
+  {GRISU_UINT64_C(0x855c3be0, a17fcd26), -857, -239},
+  {GRISU_UINT64_C(0xa6b34ad8, c9dfc070), -854, -238},
+  {GRISU_UINT64_C(0xd0601d8e, fc57b08c), -851, -237},
+  {GRISU_UINT64_C(0x823c1279, 5db6ce57), -847, -236},
+  {GRISU_UINT64_C(0xa2cb1717, b52481ed), -844, -235},
+  {GRISU_UINT64_C(0xcb7ddcdd, a26da269), -841, -234},
+  {GRISU_UINT64_C(0xfe5d5415, 0b090b03), -838, -233},
+  {GRISU_UINT64_C(0x9efa548d, 26e5a6e2), -834, -232},
+  {GRISU_UINT64_C(0xc6b8e9b0, 709f109a), -831, -231},
+  {GRISU_UINT64_C(0xf867241c, 8cc6d4c1), -828, -230},
+  {GRISU_UINT64_C(0x9b407691, d7fc44f8), -824, -229},
+  {GRISU_UINT64_C(0xc2109436, 4dfb5637), -821, -228},
+  {GRISU_UINT64_C(0xf294b943, e17a2bc4), -818, -227},
+  {GRISU_UINT64_C(0x979cf3ca, 6cec5b5b), -814, -226},
+  {GRISU_UINT64_C(0xbd8430bd, 08277231), -811, -225},
+  {GRISU_UINT64_C(0xece53cec, 4a314ebe), -808, -224},
+  {GRISU_UINT64_C(0x940f4613, ae5ed137), -804, -223},
+  {GRISU_UINT64_C(0xb9131798, 99f68584), -801, -222},
+  {GRISU_UINT64_C(0xe757dd7e, c07426e5), -798, -221},
+  {GRISU_UINT64_C(0x9096ea6f, 3848984f), -794, -220},
+  {GRISU_UINT64_C(0xb4bca50b, 065abe63), -791, -219},
+  {GRISU_UINT64_C(0xe1ebce4d, c7f16dfc), -788, -218},
+  {GRISU_UINT64_C(0x8d3360f0, 9cf6e4bd), -784, -217},
+  {GRISU_UINT64_C(0xb080392c, c4349ded), -781, -216},
+  {GRISU_UINT64_C(0xdca04777, f541c568), -778, -215},
+  {GRISU_UINT64_C(0x89e42caa, f9491b61), -774, -214},
+  {GRISU_UINT64_C(0xac5d37d5, b79b6239), -771, -213},
+  {GRISU_UINT64_C(0xd77485cb, 25823ac7), -768, -212},
+  {GRISU_UINT64_C(0x86a8d39e, f77164bd), -764, -211},
+  {GRISU_UINT64_C(0xa8530886, b54dbdec), -761, -210},
+  {GRISU_UINT64_C(0xd267caa8, 62a12d67), -758, -209},
+  {GRISU_UINT64_C(0x8380dea9, 3da4bc60), -754, -208},
+  {GRISU_UINT64_C(0xa4611653, 8d0deb78), -751, -207},
+  {GRISU_UINT64_C(0xcd795be8, 70516656), -748, -206},
+  {GRISU_UINT64_C(0x806bd971, 4632dff6), -744, -205},
+  {GRISU_UINT64_C(0xa086cfcd, 97bf97f4), -741, -204},
+  {GRISU_UINT64_C(0xc8a883c0, fdaf7df0), -738, -203},
+  {GRISU_UINT64_C(0xfad2a4b1, 3d1b5d6c), -735, -202},
+  {GRISU_UINT64_C(0x9cc3a6ee, c6311a64), -731, -201},
+  {GRISU_UINT64_C(0xc3f490aa, 77bd60fd), -728, -200},
+  {GRISU_UINT64_C(0xf4f1b4d5, 15acb93c), -725, -199},
+  {GRISU_UINT64_C(0x99171105, 2d8bf3c5), -721, -198},
+  {GRISU_UINT64_C(0xbf5cd546, 78eef0b7), -718, -197},
+  {GRISU_UINT64_C(0xef340a98, 172aace5), -715, -196},
+  {GRISU_UINT64_C(0x9580869f, 0e7aac0f), -711, -195},
+  {GRISU_UINT64_C(0xbae0a846, d2195713), -708, -194},
+  {GRISU_UINT64_C(0xe998d258, 869facd7), -705, -193},
+  {GRISU_UINT64_C(0x91ff8377, 5423cc06), -701, -192},
+  {GRISU_UINT64_C(0xb67f6455, 292cbf08), -698, -191},
+  {GRISU_UINT64_C(0xe41f3d6a, 7377eeca), -695, -190},
+  {GRISU_UINT64_C(0x8e938662, 882af53e), -691, -189},
+  {GRISU_UINT64_C(0xb23867fb, 2a35b28e), -688, -188},
+  {GRISU_UINT64_C(0xdec681f9, f4c31f31), -685, -187},
+  {GRISU_UINT64_C(0x8b3c113c, 38f9f37f), -681, -186},
+  {GRISU_UINT64_C(0xae0b158b, 4738705f), -678, -185},
+  {GRISU_UINT64_C(0xd98ddaee, 19068c76), -675, -184},
+  {GRISU_UINT64_C(0x87f8a8d4, cfa417ca), -671, -183},
+  {GRISU_UINT64_C(0xa9f6d30a, 038d1dbc), -668, -182},
+  {GRISU_UINT64_C(0xd47487cc, 8470652b), -665, -181},
+  {GRISU_UINT64_C(0x84c8d4df, d2c63f3b), -661, -180},
+  {GRISU_UINT64_C(0xa5fb0a17, c777cf0a), -658, -179},
+  {GRISU_UINT64_C(0xcf79cc9d, b955c2cc), -655, -178},
+  {GRISU_UINT64_C(0x81ac1fe2, 93d599c0), -651, -177},
+  {GRISU_UINT64_C(0xa21727db, 38cb0030), -648, -176},
+  {GRISU_UINT64_C(0xca9cf1d2, 06fdc03c), -645, -175},
+  {GRISU_UINT64_C(0xfd442e46, 88bd304b), -642, -174},
+  {GRISU_UINT64_C(0x9e4a9cec, 15763e2f), -638, -173},
+  {GRISU_UINT64_C(0xc5dd4427, 1ad3cdba), -635, -172},
+  {GRISU_UINT64_C(0xf7549530, e188c129), -632, -171},
+  {GRISU_UINT64_C(0x9a94dd3e, 8cf578ba), -628, -170},
+  {GRISU_UINT64_C(0xc13a148e, 3032d6e8), -625, -169},
+  {GRISU_UINT64_C(0xf18899b1, bc3f8ca2), -622, -168},
+  {GRISU_UINT64_C(0x96f5600f, 15a7b7e5), -618, -167},
+  {GRISU_UINT64_C(0xbcb2b812, db11a5de), -615, -166},
+  {GRISU_UINT64_C(0xebdf6617, 91d60f56), -612, -165},
+  {GRISU_UINT64_C(0x936b9fce, bb25c996), -608, -164},
+  {GRISU_UINT64_C(0xb84687c2, 69ef3bfb), -605, -163},
+  {GRISU_UINT64_C(0xe65829b3, 046b0afa), -602, -162},
+  {GRISU_UINT64_C(0x8ff71a0f, e2c2e6dc), -598, -161},
+  {GRISU_UINT64_C(0xb3f4e093, db73a093), -595, -160},
+  {GRISU_UINT64_C(0xe0f218b8, d25088b8), -592, -159},
+  {GRISU_UINT64_C(0x8c974f73, 83725573), -588, -158},
+  {GRISU_UINT64_C(0xafbd2350, 644eead0), -585, -157},
+  {GRISU_UINT64_C(0xdbac6c24, 7d62a584), -582, -156},
+  {GRISU_UINT64_C(0x894bc396, ce5da772), -578, -155},
+  {GRISU_UINT64_C(0xab9eb47c, 81f5114f), -575, -154},
+  {GRISU_UINT64_C(0xd686619b, a27255a3), -572, -153},
+  {GRISU_UINT64_C(0x8613fd01, 45877586), -568, -152},
+  {GRISU_UINT64_C(0xa798fc41, 96e952e7), -565, -151},
+  {GRISU_UINT64_C(0xd17f3b51, fca3a7a1), -562, -150},
+  {GRISU_UINT64_C(0x82ef8513, 3de648c5), -558, -149},
+  {GRISU_UINT64_C(0xa3ab6658, 0d5fdaf6), -555, -148},
+  {GRISU_UINT64_C(0xcc963fee, 10b7d1b3), -552, -147},
+  {GRISU_UINT64_C(0xffbbcfe9, 94e5c620), -549, -146},
+  {GRISU_UINT64_C(0x9fd561f1, fd0f9bd4), -545, -145},
+  {GRISU_UINT64_C(0xc7caba6e, 7c5382c9), -542, -144},
+  {GRISU_UINT64_C(0xf9bd690a, 1b68637b), -539, -143},
+  {GRISU_UINT64_C(0x9c1661a6, 51213e2d), -535, -142},
+  {GRISU_UINT64_C(0xc31bfa0f, e5698db8), -532, -141},
+  {GRISU_UINT64_C(0xf3e2f893, dec3f126), -529, -140},
+  {GRISU_UINT64_C(0x986ddb5c, 6b3a76b8), -525, -139},
+  {GRISU_UINT64_C(0xbe895233, 86091466), -522, -138},
+  {GRISU_UINT64_C(0xee2ba6c0, 678b597f), -519, -137},
+  {GRISU_UINT64_C(0x94db4838, 40b717f0), -515, -136},
+  {GRISU_UINT64_C(0xba121a46, 50e4ddec), -512, -135},
+  {GRISU_UINT64_C(0xe896a0d7, e51e1566), -509, -134},
+  {GRISU_UINT64_C(0x915e2486, ef32cd60), -505, -133},
+  {GRISU_UINT64_C(0xb5b5ada8, aaff80b8), -502, -132},
+  {GRISU_UINT64_C(0xe3231912, d5bf60e6), -499, -131},
+  {GRISU_UINT64_C(0x8df5efab, c5979c90), -495, -130},
+  {GRISU_UINT64_C(0xb1736b96, b6fd83b4), -492, -129},
+  {GRISU_UINT64_C(0xddd0467c, 64bce4a1), -489, -128},
+  {GRISU_UINT64_C(0x8aa22c0d, bef60ee4), -485, -127},
+  {GRISU_UINT64_C(0xad4ab711, 2eb3929e), -482, -126},
+  {GRISU_UINT64_C(0xd89d64d5, 7a607745), -479, -125},
+  {GRISU_UINT64_C(0x87625f05, 6c7c4a8b), -475, -124},
+  {GRISU_UINT64_C(0xa93af6c6, c79b5d2e), -472, -123},
+  {GRISU_UINT64_C(0xd389b478, 79823479), -469, -122},
+  {GRISU_UINT64_C(0x843610cb, 4bf160cc), -465, -121},
+  {GRISU_UINT64_C(0xa54394fe, 1eedb8ff), -462, -120},
+  {GRISU_UINT64_C(0xce947a3d, a6a9273e), -459, -119},
+  {GRISU_UINT64_C(0x811ccc66, 8829b887), -455, -118},
+  {GRISU_UINT64_C(0xa163ff80, 2a3426a9), -452, -117},
+  {GRISU_UINT64_C(0xc9bcff60, 34c13053), -449, -116},
+  {GRISU_UINT64_C(0xfc2c3f38, 41f17c68), -446, -115},
+  {GRISU_UINT64_C(0x9d9ba783, 2936edc1), -442, -114},
+  {GRISU_UINT64_C(0xc5029163, f384a931), -439, -113},
+  {GRISU_UINT64_C(0xf64335bc, f065d37d), -436, -112},
+  {GRISU_UINT64_C(0x99ea0196, 163fa42e), -432, -111},
+  {GRISU_UINT64_C(0xc06481fb, 9bcf8d3a), -429, -110},
+  {GRISU_UINT64_C(0xf07da27a, 82c37088), -426, -109},
+  {GRISU_UINT64_C(0x964e858c, 91ba2655), -422, -108},
+  {GRISU_UINT64_C(0xbbe226ef, b628afeb), -419, -107},
+  {GRISU_UINT64_C(0xeadab0ab, a3b2dbe5), -416, -106},
+  {GRISU_UINT64_C(0x92c8ae6b, 464fc96f), -412, -105},
+  {GRISU_UINT64_C(0xb77ada06, 17e3bbcb), -409, -104},
+  {GRISU_UINT64_C(0xe5599087, 9ddcaabe), -406, -103},
+  {GRISU_UINT64_C(0x8f57fa54, c2a9eab7), -402, -102},
+  {GRISU_UINT64_C(0xb32df8e9, f3546564), -399, -101},
+  {GRISU_UINT64_C(0xdff97724, 70297ebd), -396, -100},
+  {GRISU_UINT64_C(0x8bfbea76, c619ef36), -392, -99},
+  {GRISU_UINT64_C(0xaefae514, 77a06b04), -389, -98},
+  {GRISU_UINT64_C(0xdab99e59, 958885c5), -386, -97},
+  {GRISU_UINT64_C(0x88b402f7, fd75539b), -382, -96},
+  {GRISU_UINT64_C(0xaae103b5, fcd2a882), -379, -95},
+  {GRISU_UINT64_C(0xd59944a3, 7c0752a2), -376, -94},
+  {GRISU_UINT64_C(0x857fcae6, 2d8493a5), -372, -93},
+  {GRISU_UINT64_C(0xa6dfbd9f, b8e5b88f), -369, -92},
+  {GRISU_UINT64_C(0xd097ad07, a71f26b2), -366, -91},
+  {GRISU_UINT64_C(0x825ecc24, c8737830), -362, -90},
+  {GRISU_UINT64_C(0xa2f67f2d, fa90563b), -359, -89},
+  {GRISU_UINT64_C(0xcbb41ef9, 79346bca), -356, -88},
+  {GRISU_UINT64_C(0xfea126b7, d78186bd), -353, -87},
+  {GRISU_UINT64_C(0x9f24b832, e6b0f436), -349, -86},
+  {GRISU_UINT64_C(0xc6ede63f, a05d3144), -346, -85},
+  {GRISU_UINT64_C(0xf8a95fcf, 88747d94), -343, -84},
+  {GRISU_UINT64_C(0x9b69dbe1, b548ce7d), -339, -83},
+  {GRISU_UINT64_C(0xc24452da, 229b021c), -336, -82},
+  {GRISU_UINT64_C(0xf2d56790, ab41c2a3), -333, -81},
+  {GRISU_UINT64_C(0x97c560ba, 6b0919a6), -329, -80},
+  {GRISU_UINT64_C(0xbdb6b8e9, 05cb600f), -326, -79},
+  {GRISU_UINT64_C(0xed246723, 473e3813), -323, -78},
+  {GRISU_UINT64_C(0x9436c076, 0c86e30c), -319, -77},
+  {GRISU_UINT64_C(0xb9447093, 8fa89bcf), -316, -76},
+  {GRISU_UINT64_C(0xe7958cb8, 7392c2c3), -313, -75},
+  {GRISU_UINT64_C(0x90bd77f3, 483bb9ba), -309, -74},
+  {GRISU_UINT64_C(0xb4ecd5f0, 1a4aa828), -306, -73},
+  {GRISU_UINT64_C(0xe2280b6c, 20dd5232), -303, -72},
+  {GRISU_UINT64_C(0x8d590723, 948a535f), -299, -71},
+  {GRISU_UINT64_C(0xb0af48ec, 79ace837), -296, -70},
+  {GRISU_UINT64_C(0xdcdb1b27, 98182245), -293, -69},
+  {GRISU_UINT64_C(0x8a08f0f8, bf0f156b), -289, -68},
+  {GRISU_UINT64_C(0xac8b2d36, eed2dac6), -286, -67},
+  {GRISU_UINT64_C(0xd7adf884, aa879177), -283, -66},
+  {GRISU_UINT64_C(0x86ccbb52, ea94baeb), -279, -65},
+  {GRISU_UINT64_C(0xa87fea27, a539e9a5), -276, -64},
+  {GRISU_UINT64_C(0xd29fe4b1, 8e88640f), -273, -63},
+  {GRISU_UINT64_C(0x83a3eeee, f9153e89), -269, -62},
+  {GRISU_UINT64_C(0xa48ceaaa, b75a8e2b), -266, -61},
+  {GRISU_UINT64_C(0xcdb02555, 653131b6), -263, -60},
+  {GRISU_UINT64_C(0x808e1755, 5f3ebf12), -259, -59},
+  {GRISU_UINT64_C(0xa0b19d2a, b70e6ed6), -256, -58},
+  {GRISU_UINT64_C(0xc8de0475, 64d20a8c), -253, -57},
+  {GRISU_UINT64_C(0xfb158592, be068d2f), -250, -56},
+  {GRISU_UINT64_C(0x9ced737b, b6c4183d), -246, -55},
+  {GRISU_UINT64_C(0xc428d05a, a4751e4d), -243, -54},
+  {GRISU_UINT64_C(0xf5330471, 4d9265e0), -240, -53},
+  {GRISU_UINT64_C(0x993fe2c6, d07b7fac), -236, -52},
+  {GRISU_UINT64_C(0xbf8fdb78, 849a5f97), -233, -51},
+  {GRISU_UINT64_C(0xef73d256, a5c0f77d), -230, -50},
+  {GRISU_UINT64_C(0x95a86376, 27989aae), -226, -49},
+  {GRISU_UINT64_C(0xbb127c53, b17ec159), -223, -48},
+  {GRISU_UINT64_C(0xe9d71b68, 9dde71b0), -220, -47},
+  {GRISU_UINT64_C(0x92267121, 62ab070e), -216, -46},
+  {GRISU_UINT64_C(0xb6b00d69, bb55c8d1), -213, -45},
+  {GRISU_UINT64_C(0xe45c10c4, 2a2b3b06), -210, -44},
+  {GRISU_UINT64_C(0x8eb98a7a, 9a5b04e3), -206, -43},
+  {GRISU_UINT64_C(0xb267ed19, 40f1c61c), -203, -42},
+  {GRISU_UINT64_C(0xdf01e85f, 912e37a3), -200, -41},
+  {GRISU_UINT64_C(0x8b61313b, babce2c6), -196, -40},
+  {GRISU_UINT64_C(0xae397d8a, a96c1b78), -193, -39},
+  {GRISU_UINT64_C(0xd9c7dced, 53c72256), -190, -38},
+  {GRISU_UINT64_C(0x881cea14, 545c7575), -186, -37},
+  {GRISU_UINT64_C(0xaa242499, 697392d3), -183, -36},
+  {GRISU_UINT64_C(0xd4ad2dbf, c3d07788), -180, -35},
+  {GRISU_UINT64_C(0x84ec3c97, da624ab5), -176, -34},
+  {GRISU_UINT64_C(0xa6274bbd, d0fadd62), -173, -33},
+  {GRISU_UINT64_C(0xcfb11ead, 453994ba), -170, -32},
+  {GRISU_UINT64_C(0x81ceb32c, 4b43fcf5), -166, -31},
+  {GRISU_UINT64_C(0xa2425ff7, 5e14fc32), -163, -30},
+  {GRISU_UINT64_C(0xcad2f7f5, 359a3b3e), -160, -29},
+  {GRISU_UINT64_C(0xfd87b5f2, 8300ca0e), -157, -28},
+  {GRISU_UINT64_C(0x9e74d1b7, 91e07e48), -153, -27},
+  {GRISU_UINT64_C(0xc6120625, 76589ddb), -150, -26},
+  {GRISU_UINT64_C(0xf79687ae, d3eec551), -147, -25},
+  {GRISU_UINT64_C(0x9abe14cd, 44753b53), -143, -24},
+  {GRISU_UINT64_C(0xc16d9a00, 95928a27), -140, -23},
+  {GRISU_UINT64_C(0xf1c90080, baf72cb1), -137, -22},
+  {GRISU_UINT64_C(0x971da050, 74da7bef), -133, -21},
+  {GRISU_UINT64_C(0xbce50864, 92111aeb), -130, -20},
+  {GRISU_UINT64_C(0xec1e4a7d, b69561a5), -127, -19},
+  {GRISU_UINT64_C(0x9392ee8e, 921d5d07), -123, -18},
+  {GRISU_UINT64_C(0xb877aa32, 36a4b449), -120, -17},
+  {GRISU_UINT64_C(0xe69594be, c44de15b), -117, -16},
+  {GRISU_UINT64_C(0x901d7cf7, 3ab0acd9), -113, -15},
+  {GRISU_UINT64_C(0xb424dc35, 095cd80f), -110, -14},
+  {GRISU_UINT64_C(0xe12e1342, 4bb40e13), -107, -13},
+  {GRISU_UINT64_C(0x8cbccc09, 6f5088cc), -103, -12},
+  {GRISU_UINT64_C(0xafebff0b, cb24aaff), -100, -11},
+  {GRISU_UINT64_C(0xdbe6fece, bdedd5bf), -97, -10},
+  {GRISU_UINT64_C(0x89705f41, 36b4a597), -93, -9},
+  {GRISU_UINT64_C(0xabcc7711, 8461cefd), -90, -8},
+  {GRISU_UINT64_C(0xd6bf94d5, e57a42bc), -87, -7},
+  {GRISU_UINT64_C(0x8637bd05, af6c69b6), -83, -6},
+  {GRISU_UINT64_C(0xa7c5ac47, 1b478423), -80, -5},
+  {GRISU_UINT64_C(0xd1b71758, e219652c), -77, -4},
+  {GRISU_UINT64_C(0x83126e97, 8d4fdf3b), -73, -3},
+  {GRISU_UINT64_C(0xa3d70a3d, 70a3d70a), -70, -2},
+  {GRISU_UINT64_C(0xcccccccc, cccccccd), -67, -1},
+  {GRISU_UINT64_C(0x80000000, 00000000), -63, 0},
+  {GRISU_UINT64_C(0xa0000000, 00000000), -60, 1},
+  {GRISU_UINT64_C(0xc8000000, 00000000), -57, 2},
+  {GRISU_UINT64_C(0xfa000000, 00000000), -54, 3},
+  {GRISU_UINT64_C(0x9c400000, 00000000), -50, 4},
+  {GRISU_UINT64_C(0xc3500000, 00000000), -47, 5},
+  {GRISU_UINT64_C(0xf4240000, 00000000), -44, 6},
+  {GRISU_UINT64_C(0x98968000, 00000000), -40, 7},
+  {GRISU_UINT64_C(0xbebc2000, 00000000), -37, 8},
+  {GRISU_UINT64_C(0xee6b2800, 00000000), -34, 9},
+  {GRISU_UINT64_C(0x9502f900, 00000000), -30, 10},
+  {GRISU_UINT64_C(0xba43b740, 00000000), -27, 11},
+  {GRISU_UINT64_C(0xe8d4a510, 00000000), -24, 12},
+  {GRISU_UINT64_C(0x9184e72a, 00000000), -20, 13},
+  {GRISU_UINT64_C(0xb5e620f4, 80000000), -17, 14},
+  {GRISU_UINT64_C(0xe35fa931, a0000000), -14, 15},
+  {GRISU_UINT64_C(0x8e1bc9bf, 04000000), -10, 16},
+  {GRISU_UINT64_C(0xb1a2bc2e, c5000000), -7, 17},
+  {GRISU_UINT64_C(0xde0b6b3a, 76400000), -4, 18},
+  {GRISU_UINT64_C(0x8ac72304, 89e80000), 0, 19},
+  {GRISU_UINT64_C(0xad78ebc5, ac620000), 3, 20},
+  {GRISU_UINT64_C(0xd8d726b7, 177a8000), 6, 21},
+  {GRISU_UINT64_C(0x87867832, 6eac9000), 10, 22},
+  {GRISU_UINT64_C(0xa968163f, 0a57b400), 13, 23},
+  {GRISU_UINT64_C(0xd3c21bce, cceda100), 16, 24},
+  {GRISU_UINT64_C(0x84595161, 401484a0), 20, 25},
+  {GRISU_UINT64_C(0xa56fa5b9, 9019a5c8), 23, 26},
+  {GRISU_UINT64_C(0xcecb8f27, f4200f3a), 26, 27},
+  {GRISU_UINT64_C(0x813f3978, f8940984), 30, 28},
+  {GRISU_UINT64_C(0xa18f07d7, 36b90be5), 33, 29},
+  {GRISU_UINT64_C(0xc9f2c9cd, 04674edf), 36, 30},
+  {GRISU_UINT64_C(0xfc6f7c40, 45812296), 39, 31},
+  {GRISU_UINT64_C(0x9dc5ada8, 2b70b59e), 43, 32},
+  {GRISU_UINT64_C(0xc5371912, 364ce305), 46, 33},
+  {GRISU_UINT64_C(0xf684df56, c3e01bc7), 49, 34},
+  {GRISU_UINT64_C(0x9a130b96, 3a6c115c), 53, 35},
+  {GRISU_UINT64_C(0xc097ce7b, c90715b3), 56, 36},
+  {GRISU_UINT64_C(0xf0bdc21a, bb48db20), 59, 37},
+  {GRISU_UINT64_C(0x96769950, b50d88f4), 63, 38},
+  {GRISU_UINT64_C(0xbc143fa4, e250eb31), 66, 39},
+  {GRISU_UINT64_C(0xeb194f8e, 1ae525fd), 69, 40},
+  {GRISU_UINT64_C(0x92efd1b8, d0cf37be), 73, 41},
+  {GRISU_UINT64_C(0xb7abc627, 050305ae), 76, 42},
+  {GRISU_UINT64_C(0xe596b7b0, c643c719), 79, 43},
+  {GRISU_UINT64_C(0x8f7e32ce, 7bea5c70), 83, 44},
+  {GRISU_UINT64_C(0xb35dbf82, 1ae4f38c), 86, 45},
+  {GRISU_UINT64_C(0xe0352f62, a19e306f), 89, 46},
+  {GRISU_UINT64_C(0x8c213d9d, a502de45), 93, 47},
+  {GRISU_UINT64_C(0xaf298d05, 0e4395d7), 96, 48},
+  {GRISU_UINT64_C(0xdaf3f046, 51d47b4c), 99, 49},
+  {GRISU_UINT64_C(0x88d8762b, f324cd10), 103, 50},
+  {GRISU_UINT64_C(0xab0e93b6, efee0054), 106, 51},
+  {GRISU_UINT64_C(0xd5d238a4, abe98068), 109, 52},
+  {GRISU_UINT64_C(0x85a36366, eb71f041), 113, 53},
+  {GRISU_UINT64_C(0xa70c3c40, a64e6c52), 116, 54},
+  {GRISU_UINT64_C(0xd0cf4b50, cfe20766), 119, 55},
+  {GRISU_UINT64_C(0x82818f12, 81ed44a0), 123, 56},
+  {GRISU_UINT64_C(0xa321f2d7, 226895c8), 126, 57},
+  {GRISU_UINT64_C(0xcbea6f8c, eb02bb3a), 129, 58},
+  {GRISU_UINT64_C(0xfee50b70, 25c36a08), 132, 59},
+  {GRISU_UINT64_C(0x9f4f2726, 179a2245), 136, 60},
+  {GRISU_UINT64_C(0xc722f0ef, 9d80aad6), 139, 61},
+  {GRISU_UINT64_C(0xf8ebad2b, 84e0d58c), 142, 62},
+  {GRISU_UINT64_C(0x9b934c3b, 330c8577), 146, 63},
+  {GRISU_UINT64_C(0xc2781f49, ffcfa6d5), 149, 64},
+  {GRISU_UINT64_C(0xf316271c, 7fc3908b), 152, 65},
+  {GRISU_UINT64_C(0x97edd871, cfda3a57), 156, 66},
+  {GRISU_UINT64_C(0xbde94e8e, 43d0c8ec), 159, 67},
+  {GRISU_UINT64_C(0xed63a231, d4c4fb27), 162, 68},
+  {GRISU_UINT64_C(0x945e455f, 24fb1cf9), 166, 69},
+  {GRISU_UINT64_C(0xb975d6b6, ee39e437), 169, 70},
+  {GRISU_UINT64_C(0xe7d34c64, a9c85d44), 172, 71},
+  {GRISU_UINT64_C(0x90e40fbe, ea1d3a4b), 176, 72},
+  {GRISU_UINT64_C(0xb51d13ae, a4a488dd), 179, 73},
+  {GRISU_UINT64_C(0xe264589a, 4dcdab15), 182, 74},
+  {GRISU_UINT64_C(0x8d7eb760, 70a08aed), 186, 75},
+  {GRISU_UINT64_C(0xb0de6538, 8cc8ada8), 189, 76},
+  {GRISU_UINT64_C(0xdd15fe86, affad912), 192, 77},
+  {GRISU_UINT64_C(0x8a2dbf14, 2dfcc7ab), 196, 78},
+  {GRISU_UINT64_C(0xacb92ed9, 397bf996), 199, 79},
+  {GRISU_UINT64_C(0xd7e77a8f, 87daf7fc), 202, 80},
+  {GRISU_UINT64_C(0x86f0ac99, b4e8dafd), 206, 81},
+  {GRISU_UINT64_C(0xa8acd7c0, 222311bd), 209, 82},
+  {GRISU_UINT64_C(0xd2d80db0, 2aabd62c), 212, 83},
+  {GRISU_UINT64_C(0x83c7088e, 1aab65db), 216, 84},
+  {GRISU_UINT64_C(0xa4b8cab1, a1563f52), 219, 85},
+  {GRISU_UINT64_C(0xcde6fd5e, 09abcf27), 222, 86},
+  {GRISU_UINT64_C(0x80b05e5a, c60b6178), 226, 87},
+  {GRISU_UINT64_C(0xa0dc75f1, 778e39d6), 229, 88},
+  {GRISU_UINT64_C(0xc913936d, d571c84c), 232, 89},
+  {GRISU_UINT64_C(0xfb587849, 4ace3a5f), 235, 90},
+  {GRISU_UINT64_C(0x9d174b2d, cec0e47b), 239, 91},
+  {GRISU_UINT64_C(0xc45d1df9, 42711d9a), 242, 92},
+  {GRISU_UINT64_C(0xf5746577, 930d6501), 245, 93},
+  {GRISU_UINT64_C(0x9968bf6a, bbe85f20), 249, 94},
+  {GRISU_UINT64_C(0xbfc2ef45, 6ae276e9), 252, 95},
+  {GRISU_UINT64_C(0xefb3ab16, c59b14a3), 255, 96},
+  {GRISU_UINT64_C(0x95d04aee, 3b80ece6), 259, 97},
+  {GRISU_UINT64_C(0xbb445da9, ca61281f), 262, 98},
+  {GRISU_UINT64_C(0xea157514, 3cf97227), 265, 99},
+  {GRISU_UINT64_C(0x924d692c, a61be758), 269, 100},
+  {GRISU_UINT64_C(0xb6e0c377, cfa2e12e), 272, 101},
+  {GRISU_UINT64_C(0xe498f455, c38b997a), 275, 102},
+  {GRISU_UINT64_C(0x8edf98b5, 9a373fec), 279, 103},
+  {GRISU_UINT64_C(0xb2977ee3, 00c50fe7), 282, 104},
+  {GRISU_UINT64_C(0xdf3d5e9b, c0f653e1), 285, 105},
+  {GRISU_UINT64_C(0x8b865b21, 5899f46d), 289, 106},
+  {GRISU_UINT64_C(0xae67f1e9, aec07188), 292, 107},
+  {GRISU_UINT64_C(0xda01ee64, 1a708dea), 295, 108},
+  {GRISU_UINT64_C(0x884134fe, 908658b2), 299, 109},
+  {GRISU_UINT64_C(0xaa51823e, 34a7eedf), 302, 110},
+  {GRISU_UINT64_C(0xd4e5e2cd, c1d1ea96), 305, 111},
+  {GRISU_UINT64_C(0x850fadc0, 9923329e), 309, 112},
+  {GRISU_UINT64_C(0xa6539930, bf6bff46), 312, 113},
+  {GRISU_UINT64_C(0xcfe87f7c, ef46ff17), 315, 114},
+  {GRISU_UINT64_C(0x81f14fae, 158c5f6e), 319, 115},
+  {GRISU_UINT64_C(0xa26da399, 9aef774a), 322, 116},
+  {GRISU_UINT64_C(0xcb090c80, 01ab551c), 325, 117},
+  {GRISU_UINT64_C(0xfdcb4fa0, 02162a63), 328, 118},
+  {GRISU_UINT64_C(0x9e9f11c4, 014dda7e), 332, 119},
+  {GRISU_UINT64_C(0xc646d635, 01a1511e), 335, 120},
+  {GRISU_UINT64_C(0xf7d88bc2, 4209a565), 338, 121},
+  {GRISU_UINT64_C(0x9ae75759, 6946075f), 342, 122},
+  {GRISU_UINT64_C(0xc1a12d2f, c3978937), 345, 123},
+  {GRISU_UINT64_C(0xf209787b, b47d6b85), 348, 124},
+  {GRISU_UINT64_C(0x9745eb4d, 50ce6333), 352, 125},
+  {GRISU_UINT64_C(0xbd176620, a501fc00), 355, 126},
+  {GRISU_UINT64_C(0xec5d3fa8, ce427b00), 358, 127},
+  {GRISU_UINT64_C(0x93ba47c9, 80e98ce0), 362, 128},
+  {GRISU_UINT64_C(0xb8a8d9bb, e123f018), 365, 129},
+  {GRISU_UINT64_C(0xe6d3102a, d96cec1e), 368, 130},
+  {GRISU_UINT64_C(0x9043ea1a, c7e41393), 372, 131},
+  {GRISU_UINT64_C(0xb454e4a1, 79dd1877), 375, 132},
+  {GRISU_UINT64_C(0xe16a1dc9, d8545e95), 378, 133},
+  {GRISU_UINT64_C(0x8ce2529e, 2734bb1d), 382, 134},
+  {GRISU_UINT64_C(0xb01ae745, b101e9e4), 385, 135},
+  {GRISU_UINT64_C(0xdc21a117, 1d42645d), 388, 136},
+  {GRISU_UINT64_C(0x899504ae, 72497eba), 392, 137},
+  {GRISU_UINT64_C(0xabfa45da, 0edbde69), 395, 138},
+  {GRISU_UINT64_C(0xd6f8d750, 9292d603), 398, 139},
+  {GRISU_UINT64_C(0x865b8692, 5b9bc5c2), 402, 140},
+  {GRISU_UINT64_C(0xa7f26836, f282b733), 405, 141},
+  {GRISU_UINT64_C(0xd1ef0244, af2364ff), 408, 142},
+  {GRISU_UINT64_C(0x8335616a, ed761f1f), 412, 143},
+  {GRISU_UINT64_C(0xa402b9c5, a8d3a6e7), 415, 144},
+  {GRISU_UINT64_C(0xcd036837, 130890a1), 418, 145},
+  {GRISU_UINT64_C(0x80222122, 6be55a65), 422, 146},
+  {GRISU_UINT64_C(0xa02aa96b, 06deb0fe), 425, 147},
+  {GRISU_UINT64_C(0xc83553c5, c8965d3d), 428, 148},
+  {GRISU_UINT64_C(0xfa42a8b7, 3abbf48d), 431, 149},
+  {GRISU_UINT64_C(0x9c69a972, 84b578d8), 435, 150},
+  {GRISU_UINT64_C(0xc38413cf, 25e2d70e), 438, 151},
+  {GRISU_UINT64_C(0xf46518c2, ef5b8cd1), 441, 152},
+  {GRISU_UINT64_C(0x98bf2f79, d5993803), 445, 153},
+  {GRISU_UINT64_C(0xbeeefb58, 4aff8604), 448, 154},
+  {GRISU_UINT64_C(0xeeaaba2e, 5dbf6785), 451, 155},
+  {GRISU_UINT64_C(0x952ab45c, fa97a0b3), 455, 156},
+  {GRISU_UINT64_C(0xba756174, 393d88e0), 458, 157},
+  {GRISU_UINT64_C(0xe912b9d1, 478ceb17), 461, 158},
+  {GRISU_UINT64_C(0x91abb422, ccb812ef), 465, 159},
+  {GRISU_UINT64_C(0xb616a12b, 7fe617aa), 468, 160},
+  {GRISU_UINT64_C(0xe39c4976, 5fdf9d95), 471, 161},
+  {GRISU_UINT64_C(0x8e41ade9, fbebc27d), 475, 162},
+  {GRISU_UINT64_C(0xb1d21964, 7ae6b31c), 478, 163},
+  {GRISU_UINT64_C(0xde469fbd, 99a05fe3), 481, 164},
+  {GRISU_UINT64_C(0x8aec23d6, 80043bee), 485, 165},
+  {GRISU_UINT64_C(0xada72ccc, 20054aea), 488, 166},
+  {GRISU_UINT64_C(0xd910f7ff, 28069da4), 491, 167},
+  {GRISU_UINT64_C(0x87aa9aff, 79042287), 495, 168},
+  {GRISU_UINT64_C(0xa99541bf, 57452b28), 498, 169},
+  {GRISU_UINT64_C(0xd3fa922f, 2d1675f2), 501, 170},
+  {GRISU_UINT64_C(0x847c9b5d, 7c2e09b7), 505, 171},
+  {GRISU_UINT64_C(0xa59bc234, db398c25), 508, 172},
+  {GRISU_UINT64_C(0xcf02b2c2, 1207ef2f), 511, 173},
+  {GRISU_UINT64_C(0x8161afb9, 4b44f57d), 515, 174},
+  {GRISU_UINT64_C(0xa1ba1ba7, 9e1632dc), 518, 175},
+  {GRISU_UINT64_C(0xca28a291, 859bbf93), 521, 176},
+  {GRISU_UINT64_C(0xfcb2cb35, e702af78), 524, 177},
+  {GRISU_UINT64_C(0x9defbf01, b061adab), 528, 178},
+  {GRISU_UINT64_C(0xc56baec2, 1c7a1916), 531, 179},
+  {GRISU_UINT64_C(0xf6c69a72, a3989f5c), 534, 180},
+  {GRISU_UINT64_C(0x9a3c2087, a63f6399), 538, 181},
+  {GRISU_UINT64_C(0xc0cb28a9, 8fcf3c80), 541, 182},
+  {GRISU_UINT64_C(0xf0fdf2d3, f3c30b9f), 544, 183},
+  {GRISU_UINT64_C(0x969eb7c4, 7859e744), 548, 184},
+  {GRISU_UINT64_C(0xbc4665b5, 96706115), 551, 185},
+  {GRISU_UINT64_C(0xeb57ff22, fc0c795a), 554, 186},
+  {GRISU_UINT64_C(0x9316ff75, dd87cbd8), 558, 187},
+  {GRISU_UINT64_C(0xb7dcbf53, 54e9bece), 561, 188},
+  {GRISU_UINT64_C(0xe5d3ef28, 2a242e82), 564, 189},
+  {GRISU_UINT64_C(0x8fa47579, 1a569d11), 568, 190},
+  {GRISU_UINT64_C(0xb38d92d7, 60ec4455), 571, 191},
+  {GRISU_UINT64_C(0xe070f78d, 3927556b), 574, 192},
+  {GRISU_UINT64_C(0x8c469ab8, 43b89563), 578, 193},
+  {GRISU_UINT64_C(0xaf584166, 54a6babb), 581, 194},
+  {GRISU_UINT64_C(0xdb2e51bf, e9d0696a), 584, 195},
+  {GRISU_UINT64_C(0x88fcf317, f22241e2), 588, 196},
+  {GRISU_UINT64_C(0xab3c2fdd, eeaad25b), 591, 197},
+  {GRISU_UINT64_C(0xd60b3bd5, 6a5586f2), 594, 198},
+  {GRISU_UINT64_C(0x85c70565, 62757457), 598, 199},
+  {GRISU_UINT64_C(0xa738c6be, bb12d16d), 601, 200},
+  {GRISU_UINT64_C(0xd106f86e, 69d785c8), 604, 201},
+  {GRISU_UINT64_C(0x82a45b45, 0226b39d), 608, 202},
+  {GRISU_UINT64_C(0xa34d7216, 42b06084), 611, 203},
+  {GRISU_UINT64_C(0xcc20ce9b, d35c78a5), 614, 204},
+  {GRISU_UINT64_C(0xff290242, c83396ce), 617, 205},
+  {GRISU_UINT64_C(0x9f79a169, bd203e41), 621, 206},
+  {GRISU_UINT64_C(0xc75809c4, 2c684dd1), 624, 207},
+  {GRISU_UINT64_C(0xf92e0c35, 37826146), 627, 208},
+  {GRISU_UINT64_C(0x9bbcc7a1, 42b17ccc), 631, 209},
+  {GRISU_UINT64_C(0xc2abf989, 935ddbfe), 634, 210},
+  {GRISU_UINT64_C(0xf356f7eb, f83552fe), 637, 211},
+  {GRISU_UINT64_C(0x98165af3, 7b2153df), 641, 212},
+  {GRISU_UINT64_C(0xbe1bf1b0, 59e9a8d6), 644, 213},
+  {GRISU_UINT64_C(0xeda2ee1c, 7064130c), 647, 214},
+  {GRISU_UINT64_C(0x9485d4d1, c63e8be8), 651, 215},
+  {GRISU_UINT64_C(0xb9a74a06, 37ce2ee1), 654, 216},
+  {GRISU_UINT64_C(0xe8111c87, c5c1ba9a), 657, 217},
+  {GRISU_UINT64_C(0x910ab1d4, db9914a0), 661, 218},
+  {GRISU_UINT64_C(0xb54d5e4a, 127f59c8), 664, 219},
+  {GRISU_UINT64_C(0xe2a0b5dc, 971f303a), 667, 220},
+  {GRISU_UINT64_C(0x8da471a9, de737e24), 671, 221},
+  {GRISU_UINT64_C(0xb10d8e14, 56105dad), 674, 222},
+  {GRISU_UINT64_C(0xdd50f199, 6b947519), 677, 223},
+  {GRISU_UINT64_C(0x8a5296ff, e33cc930), 681, 224},
+  {GRISU_UINT64_C(0xace73cbf, dc0bfb7b), 684, 225},
+  {GRISU_UINT64_C(0xd8210bef, d30efa5a), 687, 226},
+  {GRISU_UINT64_C(0x8714a775, e3e95c78), 691, 227},
+  {GRISU_UINT64_C(0xa8d9d153, 5ce3b396), 694, 228},
+  {GRISU_UINT64_C(0xd31045a8, 341ca07c), 697, 229},
+  {GRISU_UINT64_C(0x83ea2b89, 2091e44e), 701, 230},
+  {GRISU_UINT64_C(0xa4e4b66b, 68b65d61), 704, 231},
+  {GRISU_UINT64_C(0xce1de406, 42e3f4b9), 707, 232},
+  {GRISU_UINT64_C(0x80d2ae83, e9ce78f4), 711, 233},
+  {GRISU_UINT64_C(0xa1075a24, e4421731), 714, 234},
+  {GRISU_UINT64_C(0xc94930ae, 1d529cfd), 717, 235},
+  {GRISU_UINT64_C(0xfb9b7cd9, a4a7443c), 720, 236},
+  {GRISU_UINT64_C(0x9d412e08, 06e88aa6), 724, 237},
+  {GRISU_UINT64_C(0xc491798a, 08a2ad4f), 727, 238},
+  {GRISU_UINT64_C(0xf5b5d7ec, 8acb58a3), 730, 239},
+  {GRISU_UINT64_C(0x9991a6f3, d6bf1766), 734, 240},
+  {GRISU_UINT64_C(0xbff610b0, cc6edd3f), 737, 241},
+  {GRISU_UINT64_C(0xeff394dc, ff8a948f), 740, 242},
+  {GRISU_UINT64_C(0x95f83d0a, 1fb69cd9), 744, 243},
+  {GRISU_UINT64_C(0xbb764c4c, a7a44410), 747, 244},
+  {GRISU_UINT64_C(0xea53df5f, d18d5514), 750, 245},
+  {GRISU_UINT64_C(0x92746b9b, e2f8552c), 754, 246},
+  {GRISU_UINT64_C(0xb7118682, dbb66a77), 757, 247},
+  {GRISU_UINT64_C(0xe4d5e823, 92a40515), 760, 248},
+  {GRISU_UINT64_C(0x8f05b116, 3ba6832d), 764, 249},
+  {GRISU_UINT64_C(0xb2c71d5b, ca9023f8), 767, 250},
+  {GRISU_UINT64_C(0xdf78e4b2, bd342cf7), 770, 251},
+  {GRISU_UINT64_C(0x8bab8eef, b6409c1a), 774, 252},
+  {GRISU_UINT64_C(0xae9672ab, a3d0c321), 777, 253},
+  {GRISU_UINT64_C(0xda3c0f56, 8cc4f3e9), 780, 254},
+  {GRISU_UINT64_C(0x88658996, 17fb1871), 784, 255},
+  {GRISU_UINT64_C(0xaa7eebfb, 9df9de8e), 787, 256},
+  {GRISU_UINT64_C(0xd51ea6fa, 85785631), 790, 257},
+  {GRISU_UINT64_C(0x8533285c, 936b35df), 794, 258},
+  {GRISU_UINT64_C(0xa67ff273, b8460357), 797, 259},
+  {GRISU_UINT64_C(0xd01fef10, a657842c), 800, 260},
+  {GRISU_UINT64_C(0x8213f56a, 67f6b29c), 804, 261},
+  {GRISU_UINT64_C(0xa298f2c5, 01f45f43), 807, 262},
+  {GRISU_UINT64_C(0xcb3f2f76, 42717713), 810, 263},
+  {GRISU_UINT64_C(0xfe0efb53, d30dd4d8), 813, 264},
+  {GRISU_UINT64_C(0x9ec95d14, 63e8a507), 817, 265},
+  {GRISU_UINT64_C(0xc67bb459, 7ce2ce49), 820, 266},
+  {GRISU_UINT64_C(0xf81aa16f, dc1b81db), 823, 267},
+  {GRISU_UINT64_C(0x9b10a4e5, e9913129), 827, 268},
+  {GRISU_UINT64_C(0xc1d4ce1f, 63f57d73), 830, 269},
+  {GRISU_UINT64_C(0xf24a01a7, 3cf2dcd0), 833, 270},
+  {GRISU_UINT64_C(0x976e4108, 8617ca02), 837, 271},
+  {GRISU_UINT64_C(0xbd49d14a, a79dbc82), 840, 272},
+  {GRISU_UINT64_C(0xec9c459d, 51852ba3), 843, 273},
+  {GRISU_UINT64_C(0x93e1ab82, 52f33b46), 847, 274},
+  {GRISU_UINT64_C(0xb8da1662, e7b00a17), 850, 275},
+  {GRISU_UINT64_C(0xe7109bfb, a19c0c9d), 853, 276},
+  {GRISU_UINT64_C(0x906a617d, 450187e2), 857, 277},
+  {GRISU_UINT64_C(0xb484f9dc, 9641e9db), 860, 278},
+  {GRISU_UINT64_C(0xe1a63853, bbd26451), 863, 279},
+  {GRISU_UINT64_C(0x8d07e334, 55637eb3), 867, 280},
+  {GRISU_UINT64_C(0xb049dc01, 6abc5e60), 870, 281},
+  {GRISU_UINT64_C(0xdc5c5301, c56b75f7), 873, 282},
+  {GRISU_UINT64_C(0x89b9b3e1, 1b6329bb), 877, 283},
+  {GRISU_UINT64_C(0xac2820d9, 623bf429), 880, 284},
+  {GRISU_UINT64_C(0xd732290f, bacaf134), 883, 285},
+  {GRISU_UINT64_C(0x867f59a9, d4bed6c0), 887, 286},
+  {GRISU_UINT64_C(0xa81f3014, 49ee8c70), 890, 287},
+  {GRISU_UINT64_C(0xd226fc19, 5c6a2f8c), 893, 288},
+  {GRISU_UINT64_C(0x83585d8f, d9c25db8), 897, 289},
+  {GRISU_UINT64_C(0xa42e74f3, d032f526), 900, 290},
+  {GRISU_UINT64_C(0xcd3a1230, c43fb26f), 903, 291},
+  {GRISU_UINT64_C(0x80444b5e, 7aa7cf85), 907, 292},
+  {GRISU_UINT64_C(0xa0555e36, 1951c367), 910, 293},
+  {GRISU_UINT64_C(0xc86ab5c3, 9fa63441), 913, 294},
+  {GRISU_UINT64_C(0xfa856334, 878fc151), 916, 295},
+  {GRISU_UINT64_C(0x9c935e00, d4b9d8d2), 920, 296},
+  {GRISU_UINT64_C(0xc3b83581, 09e84f07), 923, 297},
+  {GRISU_UINT64_C(0xf4a642e1, 4c6262c9), 926, 298},
+  {GRISU_UINT64_C(0x98e7e9cc, cfbd7dbe), 930, 299},
+  {GRISU_UINT64_C(0xbf21e440, 03acdd2d), 933, 300},
+  {GRISU_UINT64_C(0xeeea5d50, 04981478), 936, 301},
+  {GRISU_UINT64_C(0x95527a52, 02df0ccb), 940, 302},
+  {GRISU_UINT64_C(0xbaa718e6, 8396cffe), 943, 303},
+  {GRISU_UINT64_C(0xe950df20, 247c83fd), 946, 304},
+  {GRISU_UINT64_C(0x91d28b74, 16cdd27e), 950, 305},
+  {GRISU_UINT64_C(0xb6472e51, 1c81471e), 953, 306},
+  {GRISU_UINT64_C(0xe3d8f9e5, 63a198e5), 956, 307},
+  {GRISU_UINT64_C(0x8e679c2f, 5e44ff8f), 960, 308},
+  {GRISU_UINT64_C(0xb201833b, 35d63f73), 963, 309},
+  {GRISU_UINT64_C(0xde81e40a, 034bcf50), 966, 310},
+  {GRISU_UINT64_C(0x8b112e86, 420f6192), 970, 311},
+  {GRISU_UINT64_C(0xadd57a27, d29339f6), 973, 312},
+  {GRISU_UINT64_C(0xd94ad8b1, c7380874), 976, 313},
+  {GRISU_UINT64_C(0x87cec76f, 1c830549), 980, 314},
+  {GRISU_UINT64_C(0xa9c2794a, e3a3c69b), 983, 315},
+  {GRISU_UINT64_C(0xd433179d, 9c8cb841), 986, 316},
+  {GRISU_UINT64_C(0x849feec2, 81d7f329), 990, 317},
+  {GRISU_UINT64_C(0xa5c7ea73, 224deff3), 993, 318},
+  {GRISU_UINT64_C(0xcf39e50f, eae16bf0), 996, 319},
+  {GRISU_UINT64_C(0x81842f29, f2cce376), 1000, 320},
+  {GRISU_UINT64_C(0xa1e53af4, 6f801c53), 1003, 321},
+  {GRISU_UINT64_C(0xca5e89b1, 8b602368), 1006, 322},
+  {GRISU_UINT64_C(0xfcf62c1d, ee382c42), 1009, 323},
+  {GRISU_UINT64_C(0x9e19db92, b4e31ba9), 1013, 324},
+  {GRISU_UINT64_C(0xc5a05277, 621be294), 1016, 325},
+  {GRISU_UINT64_C(0xf7086715, 3aa2db39), 1019, 326},
+  {GRISU_UINT64_C(0x9a65406d, 44a5c903), 1023, 327},
+  {GRISU_UINT64_C(0xc0fe9088, 95cf3b44), 1026, 328},
+  {GRISU_UINT64_C(0xf13e34aa, bb430a15), 1029, 329},
+  {GRISU_UINT64_C(0x96c6e0ea, b509e64d), 1033, 330},
+  {GRISU_UINT64_C(0xbc789925, 624c5fe1), 1036, 331},
+  {GRISU_UINT64_C(0xeb96bf6e, badf77d9), 1039, 332},
+  {GRISU_UINT64_C(0x933e37a5, 34cbaae8), 1043, 333},
+  {GRISU_UINT64_C(0xb80dc58e, 81fe95a1), 1046, 334},
+  {GRISU_UINT64_C(0xe61136f2, 227e3b0a), 1049, 335},
+  {GRISU_UINT64_C(0x8fcac257, 558ee4e6), 1053, 336},
+  {GRISU_UINT64_C(0xb3bd72ed, 2af29e20), 1056, 337},
+  {GRISU_UINT64_C(0xe0accfa8, 75af45a8), 1059, 338},
+  {GRISU_UINT64_C(0x8c6c01c9, 498d8b89), 1063, 339},
+  {GRISU_UINT64_C(0xaf87023b, 9bf0ee6b), 1066, 340},
+  {GRISU_UINT64_C(0xdb68c2ca, 82ed2a06), 1069, 341},
+  {GRISU_UINT64_C(0x892179be, 91d43a44), 1073, 342},
+  };
+static const int GRISU_CACHE_MAX_DISTANCE(1) = 4;
+// nb elements (1): 651
+static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(2)[] = {
+  {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308},
+  {GRISU_UINT64_C(0xb3c4f1ba, 87bc8697), -1080, -306},
+  {GRISU_UINT64_C(0x8c71dcd9, ba0b4926), -1073, -304},
+  {GRISU_UINT64_C(0xdb71e914, 32b1a24b), -1067, -302},
+  {GRISU_UINT64_C(0xab70fe17, c79ac6ca), -1060, -300},
+  {GRISU_UINT64_C(0x85f04682, 93f0eb4e), -1053, -298},
+  {GRISU_UINT64_C(0xd1476e2c, 07286faa), -1047, -296},
+  {GRISU_UINT64_C(0xa37fce12, 6597973d), -1040, -294},
+  {GRISU_UINT64_C(0xff77b1fc, bebcdc4f), -1034, -292},
+  {GRISU_UINT64_C(0xc795830d, 75038c1e), -1027, -290},
+  {GRISU_UINT64_C(0x9becce62, 836ac577), -1020, -288},
+  {GRISU_UINT64_C(0xf3a20279, ed56d48a), -1014, -286},
+  {GRISU_UINT64_C(0xbe5691ef, 416bd60c), -1007, -284},
+  {GRISU_UINT64_C(0x94b3a202, eb1c3f39), -1000, -282},
+  {GRISU_UINT64_C(0xe858ad24, 8f5c22ca), -994, -280},
+  {GRISU_UINT64_C(0xb5854744, 8ffffb2e), -987, -278},
+  {GRISU_UINT64_C(0x8dd01fad, 907ffc3c), -980, -276},
+  {GRISU_UINT64_C(0xdd95317f, 31c7fa1d), -974, -274},
+  {GRISU_UINT64_C(0xad1c8eab, 5ee43b67), -967, -272},
+  {GRISU_UINT64_C(0x873e4f75, e2224e68), -960, -270},
+  {GRISU_UINT64_C(0xd3515c28, 31559a83), -954, -268},
+  {GRISU_UINT64_C(0xa5178fff, 668ae0b6), -947, -266},
+  {GRISU_UINT64_C(0x80fa687f, 881c7f8e), -940, -264},
+  {GRISU_UINT64_C(0xc9874347, 44ac874f), -934, -262},
+  {GRISU_UINT64_C(0x9d71ac8f, ada6c9b5), -927, -260},
+  {GRISU_UINT64_C(0xf6019da0, 7f549b2b), -921, -258},
+  {GRISU_UINT64_C(0xc0314325, 637a193a), -914, -256},
+  {GRISU_UINT64_C(0x96267c75, 35b763b5), -907, -254},
+  {GRISU_UINT64_C(0xea9c2277, 23ee8bcb), -901, -252},
+  {GRISU_UINT64_C(0xb749faed, 14125d37), -894, -250},
+  {GRISU_UINT64_C(0x8f31cc09, 37ae58d3), -887, -248},
+  {GRISU_UINT64_C(0xdfbdcece, 67006ac9), -881, -246},
+  {GRISU_UINT64_C(0xaecc4991, 4078536d), -874, -244},
+  {GRISU_UINT64_C(0x888f9979, 7a5e012d), -867, -242},
+  {GRISU_UINT64_C(0xd5605fcd, cf32e1d7), -861, -240},
+  {GRISU_UINT64_C(0xa6b34ad8, c9dfc070), -854, -238},
+  {GRISU_UINT64_C(0x823c1279, 5db6ce57), -847, -236},
+  {GRISU_UINT64_C(0xcb7ddcdd, a26da269), -841, -234},
+  {GRISU_UINT64_C(0x9efa548d, 26e5a6e2), -834, -232},
+  {GRISU_UINT64_C(0xf867241c, 8cc6d4c1), -828, -230},
+  {GRISU_UINT64_C(0xc2109436, 4dfb5637), -821, -228},
+  {GRISU_UINT64_C(0x979cf3ca, 6cec5b5b), -814, -226},
+  {GRISU_UINT64_C(0xece53cec, 4a314ebe), -808, -224},
+  {GRISU_UINT64_C(0xb9131798, 99f68584), -801, -222},
+  {GRISU_UINT64_C(0x9096ea6f, 3848984f), -794, -220},
+  {GRISU_UINT64_C(0xe1ebce4d, c7f16dfc), -788, -218},
+  {GRISU_UINT64_C(0xb080392c, c4349ded), -781, -216},
+  {GRISU_UINT64_C(0x89e42caa, f9491b61), -774, -214},
+  {GRISU_UINT64_C(0xd77485cb, 25823ac7), -768, -212},
+  {GRISU_UINT64_C(0xa8530886, b54dbdec), -761, -210},
+  {GRISU_UINT64_C(0x8380dea9, 3da4bc60), -754, -208},
+  {GRISU_UINT64_C(0xcd795be8, 70516656), -748, -206},
+  {GRISU_UINT64_C(0xa086cfcd, 97bf97f4), -741, -204},
+  {GRISU_UINT64_C(0xfad2a4b1, 3d1b5d6c), -735, -202},
+  {GRISU_UINT64_C(0xc3f490aa, 77bd60fd), -728, -200},
+  {GRISU_UINT64_C(0x99171105, 2d8bf3c5), -721, -198},
+  {GRISU_UINT64_C(0xef340a98, 172aace5), -715, -196},
+  {GRISU_UINT64_C(0xbae0a846, d2195713), -708, -194},
+  {GRISU_UINT64_C(0x91ff8377, 5423cc06), -701, -192},
+  {GRISU_UINT64_C(0xe41f3d6a, 7377eeca), -695, -190},
+  {GRISU_UINT64_C(0xb23867fb, 2a35b28e), -688, -188},
+  {GRISU_UINT64_C(0x8b3c113c, 38f9f37f), -681, -186},
+  {GRISU_UINT64_C(0xd98ddaee, 19068c76), -675, -184},
+  {GRISU_UINT64_C(0xa9f6d30a, 038d1dbc), -668, -182},
+  {GRISU_UINT64_C(0x84c8d4df, d2c63f3b), -661, -180},
+  {GRISU_UINT64_C(0xcf79cc9d, b955c2cc), -655, -178},
+  {GRISU_UINT64_C(0xa21727db, 38cb0030), -648, -176},
+  {GRISU_UINT64_C(0xfd442e46, 88bd304b), -642, -174},
+  {GRISU_UINT64_C(0xc5dd4427, 1ad3cdba), -635, -172},
+  {GRISU_UINT64_C(0x9a94dd3e, 8cf578ba), -628, -170},
+  {GRISU_UINT64_C(0xf18899b1, bc3f8ca2), -622, -168},
+  {GRISU_UINT64_C(0xbcb2b812, db11a5de), -615, -166},
+  {GRISU_UINT64_C(0x936b9fce, bb25c996), -608, -164},
+  {GRISU_UINT64_C(0xe65829b3, 046b0afa), -602, -162},
+  {GRISU_UINT64_C(0xb3f4e093, db73a093), -595, -160},
+  {GRISU_UINT64_C(0x8c974f73, 83725573), -588, -158},
+  {GRISU_UINT64_C(0xdbac6c24, 7d62a584), -582, -156},
+  {GRISU_UINT64_C(0xab9eb47c, 81f5114f), -575, -154},
+  {GRISU_UINT64_C(0x8613fd01, 45877586), -568, -152},
+  {GRISU_UINT64_C(0xd17f3b51, fca3a7a1), -562, -150},
+  {GRISU_UINT64_C(0xa3ab6658, 0d5fdaf6), -555, -148},
+  {GRISU_UINT64_C(0xffbbcfe9, 94e5c620), -549, -146},
+  {GRISU_UINT64_C(0xc7caba6e, 7c5382c9), -542, -144},
+  {GRISU_UINT64_C(0x9c1661a6, 51213e2d), -535, -142},
+  {GRISU_UINT64_C(0xf3e2f893, dec3f126), -529, -140},
+  {GRISU_UINT64_C(0xbe895233, 86091466), -522, -138},
+  {GRISU_UINT64_C(0x94db4838, 40b717f0), -515, -136},
+  {GRISU_UINT64_C(0xe896a0d7, e51e1566), -509, -134},
+  {GRISU_UINT64_C(0xb5b5ada8, aaff80b8), -502, -132},
+  {GRISU_UINT64_C(0x8df5efab, c5979c90), -495, -130},
+  {GRISU_UINT64_C(0xddd0467c, 64bce4a1), -489, -128},
+  {GRISU_UINT64_C(0xad4ab711, 2eb3929e), -482, -126},
+  {GRISU_UINT64_C(0x87625f05, 6c7c4a8b), -475, -124},
+  {GRISU_UINT64_C(0xd389b478, 79823479), -469, -122},
+  {GRISU_UINT64_C(0xa54394fe, 1eedb8ff), -462, -120},
+  {GRISU_UINT64_C(0x811ccc66, 8829b887), -455, -118},
+  {GRISU_UINT64_C(0xc9bcff60, 34c13053), -449, -116},
+  {GRISU_UINT64_C(0x9d9ba783, 2936edc1), -442, -114},
+  {GRISU_UINT64_C(0xf64335bc, f065d37d), -436, -112},
+  {GRISU_UINT64_C(0xc06481fb, 9bcf8d3a), -429, -110},
+  {GRISU_UINT64_C(0x964e858c, 91ba2655), -422, -108},
+  {GRISU_UINT64_C(0xeadab0ab, a3b2dbe5), -416, -106},
+  {GRISU_UINT64_C(0xb77ada06, 17e3bbcb), -409, -104},
+  {GRISU_UINT64_C(0x8f57fa54, c2a9eab7), -402, -102},
+  {GRISU_UINT64_C(0xdff97724, 70297ebd), -396, -100},
+  {GRISU_UINT64_C(0xaefae514, 77a06b04), -389, -98},
+  {GRISU_UINT64_C(0x88b402f7, fd75539b), -382, -96},
+  {GRISU_UINT64_C(0xd59944a3, 7c0752a2), -376, -94},
+  {GRISU_UINT64_C(0xa6dfbd9f, b8e5b88f), -369, -92},
+  {GRISU_UINT64_C(0x825ecc24, c8737830), -362, -90},
+  {GRISU_UINT64_C(0xcbb41ef9, 79346bca), -356, -88},
+  {GRISU_UINT64_C(0x9f24b832, e6b0f436), -349, -86},
+  {GRISU_UINT64_C(0xf8a95fcf, 88747d94), -343, -84},
+  {GRISU_UINT64_C(0xc24452da, 229b021c), -336, -82},
+  {GRISU_UINT64_C(0x97c560ba, 6b0919a6), -329, -80},
+  {GRISU_UINT64_C(0xed246723, 473e3813), -323, -78},
+  {GRISU_UINT64_C(0xb9447093, 8fa89bcf), -316, -76},
+  {GRISU_UINT64_C(0x90bd77f3, 483bb9ba), -309, -74},
+  {GRISU_UINT64_C(0xe2280b6c, 20dd5232), -303, -72},
+  {GRISU_UINT64_C(0xb0af48ec, 79ace837), -296, -70},
+  {GRISU_UINT64_C(0x8a08f0f8, bf0f156b), -289, -68},
+  {GRISU_UINT64_C(0xd7adf884, aa879177), -283, -66},
+  {GRISU_UINT64_C(0xa87fea27, a539e9a5), -276, -64},
+  {GRISU_UINT64_C(0x83a3eeee, f9153e89), -269, -62},
+  {GRISU_UINT64_C(0xcdb02555, 653131b6), -263, -60},
+  {GRISU_UINT64_C(0xa0b19d2a, b70e6ed6), -256, -58},
+  {GRISU_UINT64_C(0xfb158592, be068d2f), -250, -56},
+  {GRISU_UINT64_C(0xc428d05a, a4751e4d), -243, -54},
+  {GRISU_UINT64_C(0x993fe2c6, d07b7fac), -236, -52},
+  {GRISU_UINT64_C(0xef73d256, a5c0f77d), -230, -50},
+  {GRISU_UINT64_C(0xbb127c53, b17ec159), -223, -48},
+  {GRISU_UINT64_C(0x92267121, 62ab070e), -216, -46},
+  {GRISU_UINT64_C(0xe45c10c4, 2a2b3b06), -210, -44},
+  {GRISU_UINT64_C(0xb267ed19, 40f1c61c), -203, -42},
+  {GRISU_UINT64_C(0x8b61313b, babce2c6), -196, -40},
+  {GRISU_UINT64_C(0xd9c7dced, 53c72256), -190, -38},
+  {GRISU_UINT64_C(0xaa242499, 697392d3), -183, -36},
+  {GRISU_UINT64_C(0x84ec3c97, da624ab5), -176, -34},
+  {GRISU_UINT64_C(0xcfb11ead, 453994ba), -170, -32},
+  {GRISU_UINT64_C(0xa2425ff7, 5e14fc32), -163, -30},
+  {GRISU_UINT64_C(0xfd87b5f2, 8300ca0e), -157, -28},
+  {GRISU_UINT64_C(0xc6120625, 76589ddb), -150, -26},
+  {GRISU_UINT64_C(0x9abe14cd, 44753b53), -143, -24},
+  {GRISU_UINT64_C(0xf1c90080, baf72cb1), -137, -22},
+  {GRISU_UINT64_C(0xbce50864, 92111aeb), -130, -20},
+  {GRISU_UINT64_C(0x9392ee8e, 921d5d07), -123, -18},
+  {GRISU_UINT64_C(0xe69594be, c44de15b), -117, -16},
+  {GRISU_UINT64_C(0xb424dc35, 095cd80f), -110, -14},
+  {GRISU_UINT64_C(0x8cbccc09, 6f5088cc), -103, -12},
+  {GRISU_UINT64_C(0xdbe6fece, bdedd5bf), -97, -10},
+  {GRISU_UINT64_C(0xabcc7711, 8461cefd), -90, -8},
+  {GRISU_UINT64_C(0x8637bd05, af6c69b6), -83, -6},
+  {GRISU_UINT64_C(0xd1b71758, e219652c), -77, -4},
+  {GRISU_UINT64_C(0xa3d70a3d, 70a3d70a), -70, -2},
+  {GRISU_UINT64_C(0x80000000, 00000000), -63, 0},
+  {GRISU_UINT64_C(0xc8000000, 00000000), -57, 2},
+  {GRISU_UINT64_C(0x9c400000, 00000000), -50, 4},
+  {GRISU_UINT64_C(0xf4240000, 00000000), -44, 6},
+  {GRISU_UINT64_C(0xbebc2000, 00000000), -37, 8},
+  {GRISU_UINT64_C(0x9502f900, 00000000), -30, 10},
+  {GRISU_UINT64_C(0xe8d4a510, 00000000), -24, 12},
+  {GRISU_UINT64_C(0xb5e620f4, 80000000), -17, 14},
+  {GRISU_UINT64_C(0x8e1bc9bf, 04000000), -10, 16},
+  {GRISU_UINT64_C(0xde0b6b3a, 76400000), -4, 18},
+  {GRISU_UINT64_C(0xad78ebc5, ac620000), 3, 20},
+  {GRISU_UINT64_C(0x87867832, 6eac9000), 10, 22},
+  {GRISU_UINT64_C(0xd3c21bce, cceda100), 16, 24},
+  {GRISU_UINT64_C(0xa56fa5b9, 9019a5c8), 23, 26},
+  {GRISU_UINT64_C(0x813f3978, f8940984), 30, 28},
+  {GRISU_UINT64_C(0xc9f2c9cd, 04674edf), 36, 30},
+  {GRISU_UINT64_C(0x9dc5ada8, 2b70b59e), 43, 32},
+  {GRISU_UINT64_C(0xf684df56, c3e01bc7), 49, 34},
+  {GRISU_UINT64_C(0xc097ce7b, c90715b3), 56, 36},
+  {GRISU_UINT64_C(0x96769950, b50d88f4), 63, 38},
+  {GRISU_UINT64_C(0xeb194f8e, 1ae525fd), 69, 40},
+  {GRISU_UINT64_C(0xb7abc627, 050305ae), 76, 42},
+  {GRISU_UINT64_C(0x8f7e32ce, 7bea5c70), 83, 44},
+  {GRISU_UINT64_C(0xe0352f62, a19e306f), 89, 46},
+  {GRISU_UINT64_C(0xaf298d05, 0e4395d7), 96, 48},
+  {GRISU_UINT64_C(0x88d8762b, f324cd10), 103, 50},
+  {GRISU_UINT64_C(0xd5d238a4, abe98068), 109, 52},
+  {GRISU_UINT64_C(0xa70c3c40, a64e6c52), 116, 54},
+  {GRISU_UINT64_C(0x82818f12, 81ed44a0), 123, 56},
+  {GRISU_UINT64_C(0xcbea6f8c, eb02bb3a), 129, 58},
+  {GRISU_UINT64_C(0x9f4f2726, 179a2245), 136, 60},
+  {GRISU_UINT64_C(0xf8ebad2b, 84e0d58c), 142, 62},
+  {GRISU_UINT64_C(0xc2781f49, ffcfa6d5), 149, 64},
+  {GRISU_UINT64_C(0x97edd871, cfda3a57), 156, 66},
+  {GRISU_UINT64_C(0xed63a231, d4c4fb27), 162, 68},
+  {GRISU_UINT64_C(0xb975d6b6, ee39e437), 169, 70},
+  {GRISU_UINT64_C(0x90e40fbe, ea1d3a4b), 176, 72},
+  {GRISU_UINT64_C(0xe264589a, 4dcdab15), 182, 74},
+  {GRISU_UINT64_C(0xb0de6538, 8cc8ada8), 189, 76},
+  {GRISU_UINT64_C(0x8a2dbf14, 2dfcc7ab), 196, 78},
+  {GRISU_UINT64_C(0xd7e77a8f, 87daf7fc), 202, 80},
+  {GRISU_UINT64_C(0xa8acd7c0, 222311bd), 209, 82},
+  {GRISU_UINT64_C(0x83c7088e, 1aab65db), 216, 84},
+  {GRISU_UINT64_C(0xcde6fd5e, 09abcf27), 222, 86},
+  {GRISU_UINT64_C(0xa0dc75f1, 778e39d6), 229, 88},
+  {GRISU_UINT64_C(0xfb587849, 4ace3a5f), 235, 90},
+  {GRISU_UINT64_C(0xc45d1df9, 42711d9a), 242, 92},
+  {GRISU_UINT64_C(0x9968bf6a, bbe85f20), 249, 94},
+  {GRISU_UINT64_C(0xefb3ab16, c59b14a3), 255, 96},
+  {GRISU_UINT64_C(0xbb445da9, ca61281f), 262, 98},
+  {GRISU_UINT64_C(0x924d692c, a61be758), 269, 100},
+  {GRISU_UINT64_C(0xe498f455, c38b997a), 275, 102},
+  {GRISU_UINT64_C(0xb2977ee3, 00c50fe7), 282, 104},
+  {GRISU_UINT64_C(0x8b865b21, 5899f46d), 289, 106},
+  {GRISU_UINT64_C(0xda01ee64, 1a708dea), 295, 108},
+  {GRISU_UINT64_C(0xaa51823e, 34a7eedf), 302, 110},
+  {GRISU_UINT64_C(0x850fadc0, 9923329e), 309, 112},
+  {GRISU_UINT64_C(0xcfe87f7c, ef46ff17), 315, 114},
+  {GRISU_UINT64_C(0xa26da399, 9aef774a), 322, 116},
+  {GRISU_UINT64_C(0xfdcb4fa0, 02162a63), 328, 118},
+  {GRISU_UINT64_C(0xc646d635, 01a1511e), 335, 120},
+  {GRISU_UINT64_C(0x9ae75759, 6946075f), 342, 122},
+  {GRISU_UINT64_C(0xf209787b, b47d6b85), 348, 124},
+  {GRISU_UINT64_C(0xbd176620, a501fc00), 355, 126},
+  {GRISU_UINT64_C(0x93ba47c9, 80e98ce0), 362, 128},
+  {GRISU_UINT64_C(0xe6d3102a, d96cec1e), 368, 130},
+  {GRISU_UINT64_C(0xb454e4a1, 79dd1877), 375, 132},
+  {GRISU_UINT64_C(0x8ce2529e, 2734bb1d), 382, 134},
+  {GRISU_UINT64_C(0xdc21a117, 1d42645d), 388, 136},
+  {GRISU_UINT64_C(0xabfa45da, 0edbde69), 395, 138},
+  {GRISU_UINT64_C(0x865b8692, 5b9bc5c2), 402, 140},
+  {GRISU_UINT64_C(0xd1ef0244, af2364ff), 408, 142},
+  {GRISU_UINT64_C(0xa402b9c5, a8d3a6e7), 415, 144},
+  {GRISU_UINT64_C(0x80222122, 6be55a65), 422, 146},
+  {GRISU_UINT64_C(0xc83553c5, c8965d3d), 428, 148},
+  {GRISU_UINT64_C(0x9c69a972, 84b578d8), 435, 150},
+  {GRISU_UINT64_C(0xf46518c2, ef5b8cd1), 441, 152},
+  {GRISU_UINT64_C(0xbeeefb58, 4aff8604), 448, 154},
+  {GRISU_UINT64_C(0x952ab45c, fa97a0b3), 455, 156},
+  {GRISU_UINT64_C(0xe912b9d1, 478ceb17), 461, 158},
+  {GRISU_UINT64_C(0xb616a12b, 7fe617aa), 468, 160},
+  {GRISU_UINT64_C(0x8e41ade9, fbebc27d), 475, 162},
+  {GRISU_UINT64_C(0xde469fbd, 99a05fe3), 481, 164},
+  {GRISU_UINT64_C(0xada72ccc, 20054aea), 488, 166},
+  {GRISU_UINT64_C(0x87aa9aff, 79042287), 495, 168},
+  {GRISU_UINT64_C(0xd3fa922f, 2d1675f2), 501, 170},
+  {GRISU_UINT64_C(0xa59bc234, db398c25), 508, 172},
+  {GRISU_UINT64_C(0x8161afb9, 4b44f57d), 515, 174},
+  {GRISU_UINT64_C(0xca28a291, 859bbf93), 521, 176},
+  {GRISU_UINT64_C(0x9defbf01, b061adab), 528, 178},
+  {GRISU_UINT64_C(0xf6c69a72, a3989f5c), 534, 180},
+  {GRISU_UINT64_C(0xc0cb28a9, 8fcf3c80), 541, 182},
+  {GRISU_UINT64_C(0x969eb7c4, 7859e744), 548, 184},
+  {GRISU_UINT64_C(0xeb57ff22, fc0c795a), 554, 186},
+  {GRISU_UINT64_C(0xb7dcbf53, 54e9bece), 561, 188},
+  {GRISU_UINT64_C(0x8fa47579, 1a569d11), 568, 190},
+  {GRISU_UINT64_C(0xe070f78d, 3927556b), 574, 192},
+  {GRISU_UINT64_C(0xaf584166, 54a6babb), 581, 194},
+  {GRISU_UINT64_C(0x88fcf317, f22241e2), 588, 196},
+  {GRISU_UINT64_C(0xd60b3bd5, 6a5586f2), 594, 198},
+  {GRISU_UINT64_C(0xa738c6be, bb12d16d), 601, 200},
+  {GRISU_UINT64_C(0x82a45b45, 0226b39d), 608, 202},
+  {GRISU_UINT64_C(0xcc20ce9b, d35c78a5), 614, 204},
+  {GRISU_UINT64_C(0x9f79a169, bd203e41), 621, 206},
+  {GRISU_UINT64_C(0xf92e0c35, 37826146), 627, 208},
+  {GRISU_UINT64_C(0xc2abf989, 935ddbfe), 634, 210},
+  {GRISU_UINT64_C(0x98165af3, 7b2153df), 641, 212},
+  {GRISU_UINT64_C(0xeda2ee1c, 7064130c), 647, 214},
+  {GRISU_UINT64_C(0xb9a74a06, 37ce2ee1), 654, 216},
+  {GRISU_UINT64_C(0x910ab1d4, db9914a0), 661, 218},
+  {GRISU_UINT64_C(0xe2a0b5dc, 971f303a), 667, 220},
+  {GRISU_UINT64_C(0xb10d8e14, 56105dad), 674, 222},
+  {GRISU_UINT64_C(0x8a5296ff, e33cc930), 681, 224},
+  {GRISU_UINT64_C(0xd8210bef, d30efa5a), 687, 226},
+  {GRISU_UINT64_C(0xa8d9d153, 5ce3b396), 694, 228},
+  {GRISU_UINT64_C(0x83ea2b89, 2091e44e), 701, 230},
+  {GRISU_UINT64_C(0xce1de406, 42e3f4b9), 707, 232},
+  {GRISU_UINT64_C(0xa1075a24, e4421731), 714, 234},
+  {GRISU_UINT64_C(0xfb9b7cd9, a4a7443c), 720, 236},
+  {GRISU_UINT64_C(0xc491798a, 08a2ad4f), 727, 238},
+  {GRISU_UINT64_C(0x9991a6f3, d6bf1766), 734, 240},
+  {GRISU_UINT64_C(0xeff394dc, ff8a948f), 740, 242},
+  {GRISU_UINT64_C(0xbb764c4c, a7a44410), 747, 244},
+  {GRISU_UINT64_C(0x92746b9b, e2f8552c), 754, 246},
+  {GRISU_UINT64_C(0xe4d5e823, 92a40515), 760, 248},
+  {GRISU_UINT64_C(0xb2c71d5b, ca9023f8), 767, 250},
+  {GRISU_UINT64_C(0x8bab8eef, b6409c1a), 774, 252},
+  {GRISU_UINT64_C(0xda3c0f56, 8cc4f3e9), 780, 254},
+  {GRISU_UINT64_C(0xaa7eebfb, 9df9de8e), 787, 256},
+  {GRISU_UINT64_C(0x8533285c, 936b35df), 794, 258},
+  {GRISU_UINT64_C(0xd01fef10, a657842c), 800, 260},
+  {GRISU_UINT64_C(0xa298f2c5, 01f45f43), 807, 262},
+  {GRISU_UINT64_C(0xfe0efb53, d30dd4d8), 813, 264},
+  {GRISU_UINT64_C(0xc67bb459, 7ce2ce49), 820, 266},
+  {GRISU_UINT64_C(0x9b10a4e5, e9913129), 827, 268},
+  {GRISU_UINT64_C(0xf24a01a7, 3cf2dcd0), 833, 270},
+  {GRISU_UINT64_C(0xbd49d14a, a79dbc82), 840, 272},
+  {GRISU_UINT64_C(0x93e1ab82, 52f33b46), 847, 274},
+  {GRISU_UINT64_C(0xe7109bfb, a19c0c9d), 853, 276},
+  {GRISU_UINT64_C(0xb484f9dc, 9641e9db), 860, 278},
+  {GRISU_UINT64_C(0x8d07e334, 55637eb3), 867, 280},
+  {GRISU_UINT64_C(0xdc5c5301, c56b75f7), 873, 282},
+  {GRISU_UINT64_C(0xac2820d9, 623bf429), 880, 284},
+  {GRISU_UINT64_C(0x867f59a9, d4bed6c0), 887, 286},
+  {GRISU_UINT64_C(0xd226fc19, 5c6a2f8c), 893, 288},
+  {GRISU_UINT64_C(0xa42e74f3, d032f526), 900, 290},
+  {GRISU_UINT64_C(0x80444b5e, 7aa7cf85), 907, 292},
+  {GRISU_UINT64_C(0xc86ab5c3, 9fa63441), 913, 294},
+  {GRISU_UINT64_C(0x9c935e00, d4b9d8d2), 920, 296},
+  {GRISU_UINT64_C(0xf4a642e1, 4c6262c9), 926, 298},
+  {GRISU_UINT64_C(0xbf21e440, 03acdd2d), 933, 300},
+  {GRISU_UINT64_C(0x95527a52, 02df0ccb), 940, 302},
+  {GRISU_UINT64_C(0xe950df20, 247c83fd), 946, 304},
+  {GRISU_UINT64_C(0xb6472e51, 1c81471e), 953, 306},
+  {GRISU_UINT64_C(0x8e679c2f, 5e44ff8f), 960, 308},
+  {GRISU_UINT64_C(0xde81e40a, 034bcf50), 966, 310},
+  {GRISU_UINT64_C(0xadd57a27, d29339f6), 973, 312},
+  {GRISU_UINT64_C(0x87cec76f, 1c830549), 980, 314},
+  {GRISU_UINT64_C(0xd433179d, 9c8cb841), 986, 316},
+  {GRISU_UINT64_C(0xa5c7ea73, 224deff3), 993, 318},
+  {GRISU_UINT64_C(0x81842f29, f2cce376), 1000, 320},
+  {GRISU_UINT64_C(0xca5e89b1, 8b602368), 1006, 322},
+  {GRISU_UINT64_C(0x9e19db92, b4e31ba9), 1013, 324},
+  {GRISU_UINT64_C(0xf7086715, 3aa2db39), 1019, 326},
+  {GRISU_UINT64_C(0xc0fe9088, 95cf3b44), 1026, 328},
+  {GRISU_UINT64_C(0x96c6e0ea, b509e64d), 1033, 330},
+  {GRISU_UINT64_C(0xeb96bf6e, badf77d9), 1039, 332},
+  {GRISU_UINT64_C(0xb80dc58e, 81fe95a1), 1046, 334},
+  {GRISU_UINT64_C(0x8fcac257, 558ee4e6), 1053, 336},
+  {GRISU_UINT64_C(0xe0accfa8, 75af45a8), 1059, 338},
+  {GRISU_UINT64_C(0xaf87023b, 9bf0ee6b), 1066, 340},
+  {GRISU_UINT64_C(0x892179be, 91d43a44), 1073, 342},
+  };
+static const int GRISU_CACHE_MAX_DISTANCE(2) = 7;
+// nb elements (2): 326
+static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(3)[] = {
+  {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308},
+  {GRISU_UINT64_C(0xe0b62e29, 29aba83c), -1077, -305},
+  {GRISU_UINT64_C(0xdb71e914, 32b1a24b), -1067, -302},
+  {GRISU_UINT64_C(0xd64d3d9d, b981787d), -1057, -299},
+  {GRISU_UINT64_C(0xd1476e2c, 07286faa), -1047, -296},
+  {GRISU_UINT64_C(0xcc5fc196, fefd7d0c), -1037, -293},
+  {GRISU_UINT64_C(0xc795830d, 75038c1e), -1027, -290},
+  {GRISU_UINT64_C(0xc2e801fb, 244576d5), -1017, -287},
+  {GRISU_UINT64_C(0xbe5691ef, 416bd60c), -1007, -284},
+  {GRISU_UINT64_C(0xb9e08a83, a5e34f08), -997, -281},
+  {GRISU_UINT64_C(0xb5854744, 8ffffb2e), -987, -278},
+  {GRISU_UINT64_C(0xb1442798, f49ffb4b), -977, -275},
+  {GRISU_UINT64_C(0xad1c8eab, 5ee43b67), -967, -272},
+  {GRISU_UINT64_C(0xa90de353, 5aaae202), -957, -269},
+  {GRISU_UINT64_C(0xa5178fff, 668ae0b6), -947, -266},
+  {GRISU_UINT64_C(0xa139029f, 6a239f72), -937, -263},
+  {GRISU_UINT64_C(0x9d71ac8f, ada6c9b5), -927, -260},
+  {GRISU_UINT64_C(0x99c10284, 4f94e0fb), -917, -257},
+  {GRISU_UINT64_C(0x96267c75, 35b763b5), -907, -254},
+  {GRISU_UINT64_C(0x92a1958a, 7675175f), -897, -251},
+  {GRISU_UINT64_C(0x8f31cc09, 37ae58d3), -887, -248},
+  {GRISU_UINT64_C(0x8bd6a141, 006042be), -877, -245},
+  {GRISU_UINT64_C(0x888f9979, 7a5e012d), -867, -242},
+  {GRISU_UINT64_C(0x855c3be0, a17fcd26), -857, -239},
+  {GRISU_UINT64_C(0x823c1279, 5db6ce57), -847, -236},
+  {GRISU_UINT64_C(0xfe5d5415, 0b090b03), -838, -233},
+  {GRISU_UINT64_C(0xf867241c, 8cc6d4c1), -828, -230},
+  {GRISU_UINT64_C(0xf294b943, e17a2bc4), -818, -227},
+  {GRISU_UINT64_C(0xece53cec, 4a314ebe), -808, -224},
+  {GRISU_UINT64_C(0xe757dd7e, c07426e5), -798, -221},
+  {GRISU_UINT64_C(0xe1ebce4d, c7f16dfc), -788, -218},
+  {GRISU_UINT64_C(0xdca04777, f541c568), -778, -215},
+  {GRISU_UINT64_C(0xd77485cb, 25823ac7), -768, -212},
+  {GRISU_UINT64_C(0xd267caa8, 62a12d67), -758, -209},
+  {GRISU_UINT64_C(0xcd795be8, 70516656), -748, -206},
+  {GRISU_UINT64_C(0xc8a883c0, fdaf7df0), -738, -203},
+  {GRISU_UINT64_C(0xc3f490aa, 77bd60fd), -728, -200},
+  {GRISU_UINT64_C(0xbf5cd546, 78eef0b7), -718, -197},
+  {GRISU_UINT64_C(0xbae0a846, d2195713), -708, -194},
+  {GRISU_UINT64_C(0xb67f6455, 292cbf08), -698, -191},
+  {GRISU_UINT64_C(0xb23867fb, 2a35b28e), -688, -188},
+  {GRISU_UINT64_C(0xae0b158b, 4738705f), -678, -185},
+  {GRISU_UINT64_C(0xa9f6d30a, 038d1dbc), -668, -182},
+  {GRISU_UINT64_C(0xa5fb0a17, c777cf0a), -658, -179},
+  {GRISU_UINT64_C(0xa21727db, 38cb0030), -648, -176},
+  {GRISU_UINT64_C(0x9e4a9cec, 15763e2f), -638, -173},
+  {GRISU_UINT64_C(0x9a94dd3e, 8cf578ba), -628, -170},
+  {GRISU_UINT64_C(0x96f5600f, 15a7b7e5), -618, -167},
+  {GRISU_UINT64_C(0x936b9fce, bb25c996), -608, -164},
+  {GRISU_UINT64_C(0x8ff71a0f, e2c2e6dc), -598, -161},
+  {GRISU_UINT64_C(0x8c974f73, 83725573), -588, -158},
+  {GRISU_UINT64_C(0x894bc396, ce5da772), -578, -155},
+  {GRISU_UINT64_C(0x8613fd01, 45877586), -568, -152},
+  {GRISU_UINT64_C(0x82ef8513, 3de648c5), -558, -149},
+  {GRISU_UINT64_C(0xffbbcfe9, 94e5c620), -549, -146},
+  {GRISU_UINT64_C(0xf9bd690a, 1b68637b), -539, -143},
+  {GRISU_UINT64_C(0xf3e2f893, dec3f126), -529, -140},
+  {GRISU_UINT64_C(0xee2ba6c0, 678b597f), -519, -137},
+  {GRISU_UINT64_C(0xe896a0d7, e51e1566), -509, -134},
+  {GRISU_UINT64_C(0xe3231912, d5bf60e6), -499, -131},
+  {GRISU_UINT64_C(0xddd0467c, 64bce4a1), -489, -128},
+  {GRISU_UINT64_C(0xd89d64d5, 7a607745), -479, -125},
+  {GRISU_UINT64_C(0xd389b478, 79823479), -469, -122},
+  {GRISU_UINT64_C(0xce947a3d, a6a9273e), -459, -119},
+  {GRISU_UINT64_C(0xc9bcff60, 34c13053), -449, -116},
+  {GRISU_UINT64_C(0xc5029163, f384a931), -439, -113},
+  {GRISU_UINT64_C(0xc06481fb, 9bcf8d3a), -429, -110},
+  {GRISU_UINT64_C(0xbbe226ef, b628afeb), -419, -107},
+  {GRISU_UINT64_C(0xb77ada06, 17e3bbcb), -409, -104},
+  {GRISU_UINT64_C(0xb32df8e9, f3546564), -399, -101},
+  {GRISU_UINT64_C(0xaefae514, 77a06b04), -389, -98},
+  {GRISU_UINT64_C(0xaae103b5, fcd2a882), -379, -95},
+  {GRISU_UINT64_C(0xa6dfbd9f, b8e5b88f), -369, -92},
+  {GRISU_UINT64_C(0xa2f67f2d, fa90563b), -359, -89},
+  {GRISU_UINT64_C(0x9f24b832, e6b0f436), -349, -86},
+  {GRISU_UINT64_C(0x9b69dbe1, b548ce7d), -339, -83},
+  {GRISU_UINT64_C(0x97c560ba, 6b0919a6), -329, -80},
+  {GRISU_UINT64_C(0x9436c076, 0c86e30c), -319, -77},
+  {GRISU_UINT64_C(0x90bd77f3, 483bb9ba), -309, -74},
+  {GRISU_UINT64_C(0x8d590723, 948a535f), -299, -71},
+  {GRISU_UINT64_C(0x8a08f0f8, bf0f156b), -289, -68},
+  {GRISU_UINT64_C(0x86ccbb52, ea94baeb), -279, -65},
+  {GRISU_UINT64_C(0x83a3eeee, f9153e89), -269, -62},
+  {GRISU_UINT64_C(0x808e1755, 5f3ebf12), -259, -59},
+  {GRISU_UINT64_C(0xfb158592, be068d2f), -250, -56},
+  {GRISU_UINT64_C(0xf5330471, 4d9265e0), -240, -53},
+  {GRISU_UINT64_C(0xef73d256, a5c0f77d), -230, -50},
+  {GRISU_UINT64_C(0xe9d71b68, 9dde71b0), -220, -47},
+  {GRISU_UINT64_C(0xe45c10c4, 2a2b3b06), -210, -44},
+  {GRISU_UINT64_C(0xdf01e85f, 912e37a3), -200, -41},
+  {GRISU_UINT64_C(0xd9c7dced, 53c72256), -190, -38},
+  {GRISU_UINT64_C(0xd4ad2dbf, c3d07788), -180, -35},
+  {GRISU_UINT64_C(0xcfb11ead, 453994ba), -170, -32},
+  {GRISU_UINT64_C(0xcad2f7f5, 359a3b3e), -160, -29},
+  {GRISU_UINT64_C(0xc6120625, 76589ddb), -150, -26},
+  {GRISU_UINT64_C(0xc16d9a00, 95928a27), -140, -23},
+  {GRISU_UINT64_C(0xbce50864, 92111aeb), -130, -20},
+  {GRISU_UINT64_C(0xb877aa32, 36a4b449), -120, -17},
+  {GRISU_UINT64_C(0xb424dc35, 095cd80f), -110, -14},
+  {GRISU_UINT64_C(0xafebff0b, cb24aaff), -100, -11},
+  {GRISU_UINT64_C(0xabcc7711, 8461cefd), -90, -8},
+  {GRISU_UINT64_C(0xa7c5ac47, 1b478423), -80, -5},
+  {GRISU_UINT64_C(0xa3d70a3d, 70a3d70a), -70, -2},
+  {GRISU_UINT64_C(0xa0000000, 00000000), -60, 1},
+  {GRISU_UINT64_C(0x9c400000, 00000000), -50, 4},
+  {GRISU_UINT64_C(0x98968000, 00000000), -40, 7},
+  {GRISU_UINT64_C(0x9502f900, 00000000), -30, 10},
+  {GRISU_UINT64_C(0x9184e72a, 00000000), -20, 13},
+  {GRISU_UINT64_C(0x8e1bc9bf, 04000000), -10, 16},
+  {GRISU_UINT64_C(0x8ac72304, 89e80000), 0, 19},
+  {GRISU_UINT64_C(0x87867832, 6eac9000), 10, 22},
+  {GRISU_UINT64_C(0x84595161, 401484a0), 20, 25},
+  {GRISU_UINT64_C(0x813f3978, f8940984), 30, 28},
+  {GRISU_UINT64_C(0xfc6f7c40, 45812296), 39, 31},
+  {GRISU_UINT64_C(0xf684df56, c3e01bc7), 49, 34},
+  {GRISU_UINT64_C(0xf0bdc21a, bb48db20), 59, 37},
+  {GRISU_UINT64_C(0xeb194f8e, 1ae525fd), 69, 40},
+  {GRISU_UINT64_C(0xe596b7b0, c643c719), 79, 43},
+  {GRISU_UINT64_C(0xe0352f62, a19e306f), 89, 46},
+  {GRISU_UINT64_C(0xdaf3f046, 51d47b4c), 99, 49},
+  {GRISU_UINT64_C(0xd5d238a4, abe98068), 109, 52},
+  {GRISU_UINT64_C(0xd0cf4b50, cfe20766), 119, 55},
+  {GRISU_UINT64_C(0xcbea6f8c, eb02bb3a), 129, 58},
+  {GRISU_UINT64_C(0xc722f0ef, 9d80aad6), 139, 61},
+  {GRISU_UINT64_C(0xc2781f49, ffcfa6d5), 149, 64},
+  {GRISU_UINT64_C(0xbde94e8e, 43d0c8ec), 159, 67},
+  {GRISU_UINT64_C(0xb975d6b6, ee39e437), 169, 70},
+  {GRISU_UINT64_C(0xb51d13ae, a4a488dd), 179, 73},
+  {GRISU_UINT64_C(0xb0de6538, 8cc8ada8), 189, 76},
+  {GRISU_UINT64_C(0xacb92ed9, 397bf996), 199, 79},
+  {GRISU_UINT64_C(0xa8acd7c0, 222311bd), 209, 82},
+  {GRISU_UINT64_C(0xa4b8cab1, a1563f52), 219, 85},
+  {GRISU_UINT64_C(0xa0dc75f1, 778e39d6), 229, 88},
+  {GRISU_UINT64_C(0x9d174b2d, cec0e47b), 239, 91},
+  {GRISU_UINT64_C(0x9968bf6a, bbe85f20), 249, 94},
+  {GRISU_UINT64_C(0x95d04aee, 3b80ece6), 259, 97},
+  {GRISU_UINT64_C(0x924d692c, a61be758), 269, 100},
+  {GRISU_UINT64_C(0x8edf98b5, 9a373fec), 279, 103},
+  {GRISU_UINT64_C(0x8b865b21, 5899f46d), 289, 106},
+  {GRISU_UINT64_C(0x884134fe, 908658b2), 299, 109},
+  {GRISU_UINT64_C(0x850fadc0, 9923329e), 309, 112},
+  {GRISU_UINT64_C(0x81f14fae, 158c5f6e), 319, 115},
+  {GRISU_UINT64_C(0xfdcb4fa0, 02162a63), 328, 118},
+  {GRISU_UINT64_C(0xf7d88bc2, 4209a565), 338, 121},
+  {GRISU_UINT64_C(0xf209787b, b47d6b85), 348, 124},
+  {GRISU_UINT64_C(0xec5d3fa8, ce427b00), 358, 127},
+  {GRISU_UINT64_C(0xe6d3102a, d96cec1e), 368, 130},
+  {GRISU_UINT64_C(0xe16a1dc9, d8545e95), 378, 133},
+  {GRISU_UINT64_C(0xdc21a117, 1d42645d), 388, 136},
+  {GRISU_UINT64_C(0xd6f8d750, 9292d603), 398, 139},
+  {GRISU_UINT64_C(0xd1ef0244, af2364ff), 408, 142},
+  {GRISU_UINT64_C(0xcd036837, 130890a1), 418, 145},
+  {GRISU_UINT64_C(0xc83553c5, c8965d3d), 428, 148},
+  {GRISU_UINT64_C(0xc38413cf, 25e2d70e), 438, 151},
+  {GRISU_UINT64_C(0xbeeefb58, 4aff8604), 448, 154},
+  {GRISU_UINT64_C(0xba756174, 393d88e0), 458, 157},
+  {GRISU_UINT64_C(0xb616a12b, 7fe617aa), 468, 160},
+  {GRISU_UINT64_C(0xb1d21964, 7ae6b31c), 478, 163},
+  {GRISU_UINT64_C(0xada72ccc, 20054aea), 488, 166},
+  {GRISU_UINT64_C(0xa99541bf, 57452b28), 498, 169},
+  {GRISU_UINT64_C(0xa59bc234, db398c25), 508, 172},
+  {GRISU_UINT64_C(0xa1ba1ba7, 9e1632dc), 518, 175},
+  {GRISU_UINT64_C(0x9defbf01, b061adab), 528, 178},
+  {GRISU_UINT64_C(0x9a3c2087, a63f6399), 538, 181},
+  {GRISU_UINT64_C(0x969eb7c4, 7859e744), 548, 184},
+  {GRISU_UINT64_C(0x9316ff75, dd87cbd8), 558, 187},
+  {GRISU_UINT64_C(0x8fa47579, 1a569d11), 568, 190},
+  {GRISU_UINT64_C(0x8c469ab8, 43b89563), 578, 193},
+  {GRISU_UINT64_C(0x88fcf317, f22241e2), 588, 196},
+  {GRISU_UINT64_C(0x85c70565, 62757457), 598, 199},
+  {GRISU_UINT64_C(0x82a45b45, 0226b39d), 608, 202},
+  {GRISU_UINT64_C(0xff290242, c83396ce), 617, 205},
+  {GRISU_UINT64_C(0xf92e0c35, 37826146), 627, 208},
+  {GRISU_UINT64_C(0xf356f7eb, f83552fe), 637, 211},
+  {GRISU_UINT64_C(0xeda2ee1c, 7064130c), 647, 214},
+  {GRISU_UINT64_C(0xe8111c87, c5c1ba9a), 657, 217},
+  {GRISU_UINT64_C(0xe2a0b5dc, 971f303a), 667, 220},
+  {GRISU_UINT64_C(0xdd50f199, 6b947519), 677, 223},
+  {GRISU_UINT64_C(0xd8210bef, d30efa5a), 687, 226},
+  {GRISU_UINT64_C(0xd31045a8, 341ca07c), 697, 229},
+  {GRISU_UINT64_C(0xce1de406, 42e3f4b9), 707, 232},
+  {GRISU_UINT64_C(0xc94930ae, 1d529cfd), 717, 235},
+  {GRISU_UINT64_C(0xc491798a, 08a2ad4f), 727, 238},
+  {GRISU_UINT64_C(0xbff610b0, cc6edd3f), 737, 241},
+  {GRISU_UINT64_C(0xbb764c4c, a7a44410), 747, 244},
+  {GRISU_UINT64_C(0xb7118682, dbb66a77), 757, 247},
+  {GRISU_UINT64_C(0xb2c71d5b, ca9023f8), 767, 250},
+  {GRISU_UINT64_C(0xae9672ab, a3d0c321), 777, 253},
+  {GRISU_UINT64_C(0xaa7eebfb, 9df9de8e), 787, 256},
+  {GRISU_UINT64_C(0xa67ff273, b8460357), 797, 259},
+  {GRISU_UINT64_C(0xa298f2c5, 01f45f43), 807, 262},
+  {GRISU_UINT64_C(0x9ec95d14, 63e8a507), 817, 265},
+  {GRISU_UINT64_C(0x9b10a4e5, e9913129), 827, 268},
+  {GRISU_UINT64_C(0x976e4108, 8617ca02), 837, 271},
+  {GRISU_UINT64_C(0x93e1ab82, 52f33b46), 847, 274},
+  {GRISU_UINT64_C(0x906a617d, 450187e2), 857, 277},
+  {GRISU_UINT64_C(0x8d07e334, 55637eb3), 867, 280},
+  {GRISU_UINT64_C(0x89b9b3e1, 1b6329bb), 877, 283},
+  {GRISU_UINT64_C(0x867f59a9, d4bed6c0), 887, 286},
+  {GRISU_UINT64_C(0x83585d8f, d9c25db8), 897, 289},
+  {GRISU_UINT64_C(0x80444b5e, 7aa7cf85), 907, 292},
+  {GRISU_UINT64_C(0xfa856334, 878fc151), 916, 295},
+  {GRISU_UINT64_C(0xf4a642e1, 4c6262c9), 926, 298},
+  {GRISU_UINT64_C(0xeeea5d50, 04981478), 936, 301},
+  {GRISU_UINT64_C(0xe950df20, 247c83fd), 946, 304},
+  {GRISU_UINT64_C(0xe3d8f9e5, 63a198e5), 956, 307},
+  {GRISU_UINT64_C(0xde81e40a, 034bcf50), 966, 310},
+  {GRISU_UINT64_C(0xd94ad8b1, c7380874), 976, 313},
+  {GRISU_UINT64_C(0xd433179d, 9c8cb841), 986, 316},
+  {GRISU_UINT64_C(0xcf39e50f, eae16bf0), 996, 319},
+  {GRISU_UINT64_C(0xca5e89b1, 8b602368), 1006, 322},
+  {GRISU_UINT64_C(0xc5a05277, 621be294), 1016, 325},
+  {GRISU_UINT64_C(0xc0fe9088, 95cf3b44), 1026, 328},
+  {GRISU_UINT64_C(0xbc789925, 624c5fe1), 1036, 331},
+  {GRISU_UINT64_C(0xb80dc58e, 81fe95a1), 1046, 334},
+  {GRISU_UINT64_C(0xb3bd72ed, 2af29e20), 1056, 337},
+  {GRISU_UINT64_C(0xaf87023b, 9bf0ee6b), 1066, 340},
+  };
+static const int GRISU_CACHE_MAX_DISTANCE(3) = 10;
+// nb elements (3): 217
+static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(4)[] = {
+  {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308},
+  {GRISU_UINT64_C(0x8c71dcd9, ba0b4926), -1073, -304},
+  {GRISU_UINT64_C(0xab70fe17, c79ac6ca), -1060, -300},
+  {GRISU_UINT64_C(0xd1476e2c, 07286faa), -1047, -296},
+  {GRISU_UINT64_C(0xff77b1fc, bebcdc4f), -1034, -292},
+  {GRISU_UINT64_C(0x9becce62, 836ac577), -1020, -288},
+  {GRISU_UINT64_C(0xbe5691ef, 416bd60c), -1007, -284},
+  {GRISU_UINT64_C(0xe858ad24, 8f5c22ca), -994, -280},
+  {GRISU_UINT64_C(0x8dd01fad, 907ffc3c), -980, -276},
+  {GRISU_UINT64_C(0xad1c8eab, 5ee43b67), -967, -272},
+  {GRISU_UINT64_C(0xd3515c28, 31559a83), -954, -268},
+  {GRISU_UINT64_C(0x80fa687f, 881c7f8e), -940, -264},
+  {GRISU_UINT64_C(0x9d71ac8f, ada6c9b5), -927, -260},
+  {GRISU_UINT64_C(0xc0314325, 637a193a), -914, -256},
+  {GRISU_UINT64_C(0xea9c2277, 23ee8bcb), -901, -252},
+  {GRISU_UINT64_C(0x8f31cc09, 37ae58d3), -887, -248},
+  {GRISU_UINT64_C(0xaecc4991, 4078536d), -874, -244},
+  {GRISU_UINT64_C(0xd5605fcd, cf32e1d7), -861, -240},
+  {GRISU_UINT64_C(0x823c1279, 5db6ce57), -847, -236},
+  {GRISU_UINT64_C(0x9efa548d, 26e5a6e2), -834, -232},
+  {GRISU_UINT64_C(0xc2109436, 4dfb5637), -821, -228},
+  {GRISU_UINT64_C(0xece53cec, 4a314ebe), -808, -224},
+  {GRISU_UINT64_C(0x9096ea6f, 3848984f), -794, -220},
+  {GRISU_UINT64_C(0xb080392c, c4349ded), -781, -216},
+  {GRISU_UINT64_C(0xd77485cb, 25823ac7), -768, -212},
+  {GRISU_UINT64_C(0x8380dea9, 3da4bc60), -754, -208},
+  {GRISU_UINT64_C(0xa086cfcd, 97bf97f4), -741, -204},
+  {GRISU_UINT64_C(0xc3f490aa, 77bd60fd), -728, -200},
+  {GRISU_UINT64_C(0xef340a98, 172aace5), -715, -196},
+  {GRISU_UINT64_C(0x91ff8377, 5423cc06), -701, -192},
+  {GRISU_UINT64_C(0xb23867fb, 2a35b28e), -688, -188},
+  {GRISU_UINT64_C(0xd98ddaee, 19068c76), -675, -184},
+  {GRISU_UINT64_C(0x84c8d4df, d2c63f3b), -661, -180},
+  {GRISU_UINT64_C(0xa21727db, 38cb0030), -648, -176},
+  {GRISU_UINT64_C(0xc5dd4427, 1ad3cdba), -635, -172},
+  {GRISU_UINT64_C(0xf18899b1, bc3f8ca2), -622, -168},
+  {GRISU_UINT64_C(0x936b9fce, bb25c996), -608, -164},
+  {GRISU_UINT64_C(0xb3f4e093, db73a093), -595, -160},
+  {GRISU_UINT64_C(0xdbac6c24, 7d62a584), -582, -156},
+  {GRISU_UINT64_C(0x8613fd01, 45877586), -568, -152},
+  {GRISU_UINT64_C(0xa3ab6658, 0d5fdaf6), -555, -148},
+  {GRISU_UINT64_C(0xc7caba6e, 7c5382c9), -542, -144},
+  {GRISU_UINT64_C(0xf3e2f893, dec3f126), -529, -140},
+  {GRISU_UINT64_C(0x94db4838, 40b717f0), -515, -136},
+  {GRISU_UINT64_C(0xb5b5ada8, aaff80b8), -502, -132},
+  {GRISU_UINT64_C(0xddd0467c, 64bce4a1), -489, -128},
+  {GRISU_UINT64_C(0x87625f05, 6c7c4a8b), -475, -124},
+  {GRISU_UINT64_C(0xa54394fe, 1eedb8ff), -462, -120},
+  {GRISU_UINT64_C(0xc9bcff60, 34c13053), -449, -116},
+  {GRISU_UINT64_C(0xf64335bc, f065d37d), -436, -112},
+  {GRISU_UINT64_C(0x964e858c, 91ba2655), -422, -108},
+  {GRISU_UINT64_C(0xb77ada06, 17e3bbcb), -409, -104},
+  {GRISU_UINT64_C(0xdff97724, 70297ebd), -396, -100},
+  {GRISU_UINT64_C(0x88b402f7, fd75539b), -382, -96},
+  {GRISU_UINT64_C(0xa6dfbd9f, b8e5b88f), -369, -92},
+  {GRISU_UINT64_C(0xcbb41ef9, 79346bca), -356, -88},
+  {GRISU_UINT64_C(0xf8a95fcf, 88747d94), -343, -84},
+  {GRISU_UINT64_C(0x97c560ba, 6b0919a6), -329, -80},
+  {GRISU_UINT64_C(0xb9447093, 8fa89bcf), -316, -76},
+  {GRISU_UINT64_C(0xe2280b6c, 20dd5232), -303, -72},
+  {GRISU_UINT64_C(0x8a08f0f8, bf0f156b), -289, -68},
+  {GRISU_UINT64_C(0xa87fea27, a539e9a5), -276, -64},
+  {GRISU_UINT64_C(0xcdb02555, 653131b6), -263, -60},
+  {GRISU_UINT64_C(0xfb158592, be068d2f), -250, -56},
+  {GRISU_UINT64_C(0x993fe2c6, d07b7fac), -236, -52},
+  {GRISU_UINT64_C(0xbb127c53, b17ec159), -223, -48},
+  {GRISU_UINT64_C(0xe45c10c4, 2a2b3b06), -210, -44},
+  {GRISU_UINT64_C(0x8b61313b, babce2c6), -196, -40},
+  {GRISU_UINT64_C(0xaa242499, 697392d3), -183, -36},
+  {GRISU_UINT64_C(0xcfb11ead, 453994ba), -170, -32},
+  {GRISU_UINT64_C(0xfd87b5f2, 8300ca0e), -157, -28},
+  {GRISU_UINT64_C(0x9abe14cd, 44753b53), -143, -24},
+  {GRISU_UINT64_C(0xbce50864, 92111aeb), -130, -20},
+  {GRISU_UINT64_C(0xe69594be, c44de15b), -117, -16},
+  {GRISU_UINT64_C(0x8cbccc09, 6f5088cc), -103, -12},
+  {GRISU_UINT64_C(0xabcc7711, 8461cefd), -90, -8},
+  {GRISU_UINT64_C(0xd1b71758, e219652c), -77, -4},
+  {GRISU_UINT64_C(0x80000000, 00000000), -63, 0},
+  {GRISU_UINT64_C(0x9c400000, 00000000), -50, 4},
+  {GRISU_UINT64_C(0xbebc2000, 00000000), -37, 8},
+  {GRISU_UINT64_C(0xe8d4a510, 00000000), -24, 12},
+  {GRISU_UINT64_C(0x8e1bc9bf, 04000000), -10, 16},
+  {GRISU_UINT64_C(0xad78ebc5, ac620000), 3, 20},
+  {GRISU_UINT64_C(0xd3c21bce, cceda100), 16, 24},
+  {GRISU_UINT64_C(0x813f3978, f8940984), 30, 28},
+  {GRISU_UINT64_C(0x9dc5ada8, 2b70b59e), 43, 32},
+  {GRISU_UINT64_C(0xc097ce7b, c90715b3), 56, 36},
+  {GRISU_UINT64_C(0xeb194f8e, 1ae525fd), 69, 40},
+  {GRISU_UINT64_C(0x8f7e32ce, 7bea5c70), 83, 44},
+  {GRISU_UINT64_C(0xaf298d05, 0e4395d7), 96, 48},
+  {GRISU_UINT64_C(0xd5d238a4, abe98068), 109, 52},
+  {GRISU_UINT64_C(0x82818f12, 81ed44a0), 123, 56},
+  {GRISU_UINT64_C(0x9f4f2726, 179a2245), 136, 60},
+  {GRISU_UINT64_C(0xc2781f49, ffcfa6d5), 149, 64},
+  {GRISU_UINT64_C(0xed63a231, d4c4fb27), 162, 68},
+  {GRISU_UINT64_C(0x90e40fbe, ea1d3a4b), 176, 72},
+  {GRISU_UINT64_C(0xb0de6538, 8cc8ada8), 189, 76},
+  {GRISU_UINT64_C(0xd7e77a8f, 87daf7fc), 202, 80},
+  {GRISU_UINT64_C(0x83c7088e, 1aab65db), 216, 84},
+  {GRISU_UINT64_C(0xa0dc75f1, 778e39d6), 229, 88},
+  {GRISU_UINT64_C(0xc45d1df9, 42711d9a), 242, 92},
+  {GRISU_UINT64_C(0xefb3ab16, c59b14a3), 255, 96},
+  {GRISU_UINT64_C(0x924d692c, a61be758), 269, 100},
+  {GRISU_UINT64_C(0xb2977ee3, 00c50fe7), 282, 104},
+  {GRISU_UINT64_C(0xda01ee64, 1a708dea), 295, 108},
+  {GRISU_UINT64_C(0x850fadc0, 9923329e), 309, 112},
+  {GRISU_UINT64_C(0xa26da399, 9aef774a), 322, 116},
+  {GRISU_UINT64_C(0xc646d635, 01a1511e), 335, 120},
+  {GRISU_UINT64_C(0xf209787b, b47d6b85), 348, 124},
+  {GRISU_UINT64_C(0x93ba47c9, 80e98ce0), 362, 128},
+  {GRISU_UINT64_C(0xb454e4a1, 79dd1877), 375, 132},
+  {GRISU_UINT64_C(0xdc21a117, 1d42645d), 388, 136},
+  {GRISU_UINT64_C(0x865b8692, 5b9bc5c2), 402, 140},
+  {GRISU_UINT64_C(0xa402b9c5, a8d3a6e7), 415, 144},
+  {GRISU_UINT64_C(0xc83553c5, c8965d3d), 428, 148},
+  {GRISU_UINT64_C(0xf46518c2, ef5b8cd1), 441, 152},
+  {GRISU_UINT64_C(0x952ab45c, fa97a0b3), 455, 156},
+  {GRISU_UINT64_C(0xb616a12b, 7fe617aa), 468, 160},
+  {GRISU_UINT64_C(0xde469fbd, 99a05fe3), 481, 164},
+  {GRISU_UINT64_C(0x87aa9aff, 79042287), 495, 168},
+  {GRISU_UINT64_C(0xa59bc234, db398c25), 508, 172},
+  {GRISU_UINT64_C(0xca28a291, 859bbf93), 521, 176},
+  {GRISU_UINT64_C(0xf6c69a72, a3989f5c), 534, 180},
+  {GRISU_UINT64_C(0x969eb7c4, 7859e744), 548, 184},
+  {GRISU_UINT64_C(0xb7dcbf53, 54e9bece), 561, 188},
+  {GRISU_UINT64_C(0xe070f78d, 3927556b), 574, 192},
+  {GRISU_UINT64_C(0x88fcf317, f22241e2), 588, 196},
+  {GRISU_UINT64_C(0xa738c6be, bb12d16d), 601, 200},
+  {GRISU_UINT64_C(0xcc20ce9b, d35c78a5), 614, 204},
+  {GRISU_UINT64_C(0xf92e0c35, 37826146), 627, 208},
+  {GRISU_UINT64_C(0x98165af3, 7b2153df), 641, 212},
+  {GRISU_UINT64_C(0xb9a74a06, 37ce2ee1), 654, 216},
+  {GRISU_UINT64_C(0xe2a0b5dc, 971f303a), 667, 220},
+  {GRISU_UINT64_C(0x8a5296ff, e33cc930), 681, 224},
+  {GRISU_UINT64_C(0xa8d9d153, 5ce3b396), 694, 228},
+  {GRISU_UINT64_C(0xce1de406, 42e3f4b9), 707, 232},
+  {GRISU_UINT64_C(0xfb9b7cd9, a4a7443c), 720, 236},
+  {GRISU_UINT64_C(0x9991a6f3, d6bf1766), 734, 240},
+  {GRISU_UINT64_C(0xbb764c4c, a7a44410), 747, 244},
+  {GRISU_UINT64_C(0xe4d5e823, 92a40515), 760, 248},
+  {GRISU_UINT64_C(0x8bab8eef, b6409c1a), 774, 252},
+  {GRISU_UINT64_C(0xaa7eebfb, 9df9de8e), 787, 256},
+  {GRISU_UINT64_C(0xd01fef10, a657842c), 800, 260},
+  {GRISU_UINT64_C(0xfe0efb53, d30dd4d8), 813, 264},
+  {GRISU_UINT64_C(0x9b10a4e5, e9913129), 827, 268},
+  {GRISU_UINT64_C(0xbd49d14a, a79dbc82), 840, 272},
+  {GRISU_UINT64_C(0xe7109bfb, a19c0c9d), 853, 276},
+  {GRISU_UINT64_C(0x8d07e334, 55637eb3), 867, 280},
+  {GRISU_UINT64_C(0xac2820d9, 623bf429), 880, 284},
+  {GRISU_UINT64_C(0xd226fc19, 5c6a2f8c), 893, 288},
+  {GRISU_UINT64_C(0x80444b5e, 7aa7cf85), 907, 292},
+  {GRISU_UINT64_C(0x9c935e00, d4b9d8d2), 920, 296},
+  {GRISU_UINT64_C(0xbf21e440, 03acdd2d), 933, 300},
+  {GRISU_UINT64_C(0xe950df20, 247c83fd), 946, 304},
+  {GRISU_UINT64_C(0x8e679c2f, 5e44ff8f), 960, 308},
+  {GRISU_UINT64_C(0xadd57a27, d29339f6), 973, 312},
+  {GRISU_UINT64_C(0xd433179d, 9c8cb841), 986, 316},
+  {GRISU_UINT64_C(0x81842f29, f2cce376), 1000, 320},
+  {GRISU_UINT64_C(0x9e19db92, b4e31ba9), 1013, 324},
+  {GRISU_UINT64_C(0xc0fe9088, 95cf3b44), 1026, 328},
+  {GRISU_UINT64_C(0xeb96bf6e, badf77d9), 1039, 332},
+  {GRISU_UINT64_C(0x8fcac257, 558ee4e6), 1053, 336},
+  {GRISU_UINT64_C(0xaf87023b, 9bf0ee6b), 1066, 340},
+  };
+static const int GRISU_CACHE_MAX_DISTANCE(4) = 14;
+// nb elements (4): 163
+static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(5)[] = {
+  {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308},
+  {GRISU_UINT64_C(0xaf8e5410, 288e1b6f), -1070, -303},
+  {GRISU_UINT64_C(0x85f04682, 93f0eb4e), -1053, -298},
+  {GRISU_UINT64_C(0xcc5fc196, fefd7d0c), -1037, -293},
+  {GRISU_UINT64_C(0x9becce62, 836ac577), -1020, -288},
+  {GRISU_UINT64_C(0xedec366b, 11c6cb8f), -1004, -283},
+  {GRISU_UINT64_C(0xb5854744, 8ffffb2e), -987, -278},
+  {GRISU_UINT64_C(0x8a7d3eef, 7f1cfc52), -970, -273},
+  {GRISU_UINT64_C(0xd3515c28, 31559a83), -954, -268},
+  {GRISU_UINT64_C(0xa139029f, 6a239f72), -937, -263},
+  {GRISU_UINT64_C(0xf6019da0, 7f549b2b), -921, -258},
+  {GRISU_UINT64_C(0xbbb01b92, 83253ca3), -904, -253},
+  {GRISU_UINT64_C(0x8f31cc09, 37ae58d3), -887, -248},
+  {GRISU_UINT64_C(0xda7f5bf5, 90966849), -871, -243},
+  {GRISU_UINT64_C(0xa6b34ad8, c9dfc070), -854, -238},
+  {GRISU_UINT64_C(0xfe5d5415, 0b090b03), -838, -233},
+  {GRISU_UINT64_C(0xc2109436, 4dfb5637), -821, -228},
+  {GRISU_UINT64_C(0x940f4613, ae5ed137), -804, -223},
+  {GRISU_UINT64_C(0xe1ebce4d, c7f16dfc), -788, -218},
+  {GRISU_UINT64_C(0xac5d37d5, b79b6239), -771, -213},
+  {GRISU_UINT64_C(0x8380dea9, 3da4bc60), -754, -208},
+  {GRISU_UINT64_C(0xc8a883c0, fdaf7df0), -738, -203},
+  {GRISU_UINT64_C(0x99171105, 2d8bf3c5), -721, -198},
+  {GRISU_UINT64_C(0xe998d258, 869facd7), -705, -193},
+  {GRISU_UINT64_C(0xb23867fb, 2a35b28e), -688, -188},
+  {GRISU_UINT64_C(0x87f8a8d4, cfa417ca), -671, -183},
+  {GRISU_UINT64_C(0xcf79cc9d, b955c2cc), -655, -178},
+  {GRISU_UINT64_C(0x9e4a9cec, 15763e2f), -638, -173},
+  {GRISU_UINT64_C(0xf18899b1, bc3f8ca2), -622, -168},
+  {GRISU_UINT64_C(0xb84687c2, 69ef3bfb), -605, -163},
+  {GRISU_UINT64_C(0x8c974f73, 83725573), -588, -158},
+  {GRISU_UINT64_C(0xd686619b, a27255a3), -572, -153},
+  {GRISU_UINT64_C(0xa3ab6658, 0d5fdaf6), -555, -148},
+  {GRISU_UINT64_C(0xf9bd690a, 1b68637b), -539, -143},
+  {GRISU_UINT64_C(0xbe895233, 86091466), -522, -138},
+  {GRISU_UINT64_C(0x915e2486, ef32cd60), -505, -133},
+  {GRISU_UINT64_C(0xddd0467c, 64bce4a1), -489, -128},
+  {GRISU_UINT64_C(0xa93af6c6, c79b5d2e), -472, -123},
+  {GRISU_UINT64_C(0x811ccc66, 8829b887), -455, -118},
+  {GRISU_UINT64_C(0xc5029163, f384a931), -439, -113},
+  {GRISU_UINT64_C(0x964e858c, 91ba2655), -422, -108},
+  {GRISU_UINT64_C(0xe5599087, 9ddcaabe), -406, -103},
+  {GRISU_UINT64_C(0xaefae514, 77a06b04), -389, -98},
+  {GRISU_UINT64_C(0x857fcae6, 2d8493a5), -372, -93},
+  {GRISU_UINT64_C(0xcbb41ef9, 79346bca), -356, -88},
+  {GRISU_UINT64_C(0x9b69dbe1, b548ce7d), -339, -83},
+  {GRISU_UINT64_C(0xed246723, 473e3813), -323, -78},
+  {GRISU_UINT64_C(0xb4ecd5f0, 1a4aa828), -306, -73},
+  {GRISU_UINT64_C(0x8a08f0f8, bf0f156b), -289, -68},
+  {GRISU_UINT64_C(0xd29fe4b1, 8e88640f), -273, -63},
+  {GRISU_UINT64_C(0xa0b19d2a, b70e6ed6), -256, -58},
+  {GRISU_UINT64_C(0xf5330471, 4d9265e0), -240, -53},
+  {GRISU_UINT64_C(0xbb127c53, b17ec159), -223, -48},
+  {GRISU_UINT64_C(0x8eb98a7a, 9a5b04e3), -206, -43},
+  {GRISU_UINT64_C(0xd9c7dced, 53c72256), -190, -38},
+  {GRISU_UINT64_C(0xa6274bbd, d0fadd62), -173, -33},
+  {GRISU_UINT64_C(0xfd87b5f2, 8300ca0e), -157, -28},
+  {GRISU_UINT64_C(0xc16d9a00, 95928a27), -140, -23},
+  {GRISU_UINT64_C(0x9392ee8e, 921d5d07), -123, -18},
+  {GRISU_UINT64_C(0xe12e1342, 4bb40e13), -107, -13},
+  {GRISU_UINT64_C(0xabcc7711, 8461cefd), -90, -8},
+  {GRISU_UINT64_C(0x83126e97, 8d4fdf3b), -73, -3},
+  {GRISU_UINT64_C(0xc8000000, 00000000), -57, 2},
+  {GRISU_UINT64_C(0x98968000, 00000000), -40, 7},
+  {GRISU_UINT64_C(0xe8d4a510, 00000000), -24, 12},
+  {GRISU_UINT64_C(0xb1a2bc2e, c5000000), -7, 17},
+  {GRISU_UINT64_C(0x87867832, 6eac9000), 10, 22},
+  {GRISU_UINT64_C(0xcecb8f27, f4200f3a), 26, 27},
+  {GRISU_UINT64_C(0x9dc5ada8, 2b70b59e), 43, 32},
+  {GRISU_UINT64_C(0xf0bdc21a, bb48db20), 59, 37},
+  {GRISU_UINT64_C(0xb7abc627, 050305ae), 76, 42},
+  {GRISU_UINT64_C(0x8c213d9d, a502de45), 93, 47},
+  {GRISU_UINT64_C(0xd5d238a4, abe98068), 109, 52},
+  {GRISU_UINT64_C(0xa321f2d7, 226895c8), 126, 57},
+  {GRISU_UINT64_C(0xf8ebad2b, 84e0d58c), 142, 62},
+  {GRISU_UINT64_C(0xbde94e8e, 43d0c8ec), 159, 67},
+  {GRISU_UINT64_C(0x90e40fbe, ea1d3a4b), 176, 72},
+  {GRISU_UINT64_C(0xdd15fe86, affad912), 192, 77},
+  {GRISU_UINT64_C(0xa8acd7c0, 222311bd), 209, 82},
+  {GRISU_UINT64_C(0x80b05e5a, c60b6178), 226, 87},
+  {GRISU_UINT64_C(0xc45d1df9, 42711d9a), 242, 92},
+  {GRISU_UINT64_C(0x95d04aee, 3b80ece6), 259, 97},
+  {GRISU_UINT64_C(0xe498f455, c38b997a), 275, 102},
+  {GRISU_UINT64_C(0xae67f1e9, aec07188), 292, 107},
+  {GRISU_UINT64_C(0x850fadc0, 9923329e), 309, 112},
+  {GRISU_UINT64_C(0xcb090c80, 01ab551c), 325, 117},
+  {GRISU_UINT64_C(0x9ae75759, 6946075f), 342, 122},
+  {GRISU_UINT64_C(0xec5d3fa8, ce427b00), 358, 127},
+  {GRISU_UINT64_C(0xb454e4a1, 79dd1877), 375, 132},
+  {GRISU_UINT64_C(0x899504ae, 72497eba), 392, 137},
+  {GRISU_UINT64_C(0xd1ef0244, af2364ff), 408, 142},
+  {GRISU_UINT64_C(0xa02aa96b, 06deb0fe), 425, 147},
+  {GRISU_UINT64_C(0xf46518c2, ef5b8cd1), 441, 152},
+  {GRISU_UINT64_C(0xba756174, 393d88e0), 458, 157},
+  {GRISU_UINT64_C(0x8e41ade9, fbebc27d), 475, 162},
+  {GRISU_UINT64_C(0xd910f7ff, 28069da4), 491, 167},
+  {GRISU_UINT64_C(0xa59bc234, db398c25), 508, 172},
+  {GRISU_UINT64_C(0xfcb2cb35, e702af78), 524, 177},
+  {GRISU_UINT64_C(0xc0cb28a9, 8fcf3c80), 541, 182},
+  {GRISU_UINT64_C(0x9316ff75, dd87cbd8), 558, 187},
+  {GRISU_UINT64_C(0xe070f78d, 3927556b), 574, 192},
+  {GRISU_UINT64_C(0xab3c2fdd, eeaad25b), 591, 197},
+  {GRISU_UINT64_C(0x82a45b45, 0226b39d), 608, 202},
+  {GRISU_UINT64_C(0xc75809c4, 2c684dd1), 624, 207},
+  {GRISU_UINT64_C(0x98165af3, 7b2153df), 641, 212},
+  {GRISU_UINT64_C(0xe8111c87, c5c1ba9a), 657, 217},
+  {GRISU_UINT64_C(0xb10d8e14, 56105dad), 674, 222},
+  {GRISU_UINT64_C(0x8714a775, e3e95c78), 691, 227},
+  {GRISU_UINT64_C(0xce1de406, 42e3f4b9), 707, 232},
+  {GRISU_UINT64_C(0x9d412e08, 06e88aa6), 724, 237},
+  {GRISU_UINT64_C(0xeff394dc, ff8a948f), 740, 242},
+  {GRISU_UINT64_C(0xb7118682, dbb66a77), 757, 247},
+  {GRISU_UINT64_C(0x8bab8eef, b6409c1a), 774, 252},
+  {GRISU_UINT64_C(0xd51ea6fa, 85785631), 790, 257},
+  {GRISU_UINT64_C(0xa298f2c5, 01f45f43), 807, 262},
+  {GRISU_UINT64_C(0xf81aa16f, dc1b81db), 823, 267},
+  {GRISU_UINT64_C(0xbd49d14a, a79dbc82), 840, 272},
+  {GRISU_UINT64_C(0x906a617d, 450187e2), 857, 277},
+  {GRISU_UINT64_C(0xdc5c5301, c56b75f7), 873, 282},
+  {GRISU_UINT64_C(0xa81f3014, 49ee8c70), 890, 287},
+  {GRISU_UINT64_C(0x80444b5e, 7aa7cf85), 907, 292},
+  {GRISU_UINT64_C(0xc3b83581, 09e84f07), 923, 297},
+  {GRISU_UINT64_C(0x95527a52, 02df0ccb), 940, 302},
+  {GRISU_UINT64_C(0xe3d8f9e5, 63a198e5), 956, 307},
+  {GRISU_UINT64_C(0xadd57a27, d29339f6), 973, 312},
+  {GRISU_UINT64_C(0x849feec2, 81d7f329), 990, 317},
+  {GRISU_UINT64_C(0xca5e89b1, 8b602368), 1006, 322},
+  {GRISU_UINT64_C(0x9a65406d, 44a5c903), 1023, 327},
+  {GRISU_UINT64_C(0xeb96bf6e, badf77d9), 1039, 332},
+  {GRISU_UINT64_C(0xb3bd72ed, 2af29e20), 1056, 337},
+  {GRISU_UINT64_C(0x892179be, 91d43a44), 1073, 342},
+  };
+static const int GRISU_CACHE_MAX_DISTANCE(5) = 17;
+// nb elements (5): 131
+static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(6)[] = {
+  {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308},
+  {GRISU_UINT64_C(0xdb71e914, 32b1a24b), -1067, -302},
+  {GRISU_UINT64_C(0xd1476e2c, 07286faa), -1047, -296},
+  {GRISU_UINT64_C(0xc795830d, 75038c1e), -1027, -290},
+  {GRISU_UINT64_C(0xbe5691ef, 416bd60c), -1007, -284},
+  {GRISU_UINT64_C(0xb5854744, 8ffffb2e), -987, -278},
+  {GRISU_UINT64_C(0xad1c8eab, 5ee43b67), -967, -272},
+  {GRISU_UINT64_C(0xa5178fff, 668ae0b6), -947, -266},
+  {GRISU_UINT64_C(0x9d71ac8f, ada6c9b5), -927, -260},
+  {GRISU_UINT64_C(0x96267c75, 35b763b5), -907, -254},
+  {GRISU_UINT64_C(0x8f31cc09, 37ae58d3), -887, -248},
+  {GRISU_UINT64_C(0x888f9979, 7a5e012d), -867, -242},
+  {GRISU_UINT64_C(0x823c1279, 5db6ce57), -847, -236},
+  {GRISU_UINT64_C(0xf867241c, 8cc6d4c1), -828, -230},
+  {GRISU_UINT64_C(0xece53cec, 4a314ebe), -808, -224},
+  {GRISU_UINT64_C(0xe1ebce4d, c7f16dfc), -788, -218},
+  {GRISU_UINT64_C(0xd77485cb, 25823ac7), -768, -212},
+  {GRISU_UINT64_C(0xcd795be8, 70516656), -748, -206},
+  {GRISU_UINT64_C(0xc3f490aa, 77bd60fd), -728, -200},
+  {GRISU_UINT64_C(0xbae0a846, d2195713), -708, -194},
+  {GRISU_UINT64_C(0xb23867fb, 2a35b28e), -688, -188},
+  {GRISU_UINT64_C(0xa9f6d30a, 038d1dbc), -668, -182},
+  {GRISU_UINT64_C(0xa21727db, 38cb0030), -648, -176},
+  {GRISU_UINT64_C(0x9a94dd3e, 8cf578ba), -628, -170},
+  {GRISU_UINT64_C(0x936b9fce, bb25c996), -608, -164},
+  {GRISU_UINT64_C(0x8c974f73, 83725573), -588, -158},
+  {GRISU_UINT64_C(0x8613fd01, 45877586), -568, -152},
+  {GRISU_UINT64_C(0xffbbcfe9, 94e5c620), -549, -146},
+  {GRISU_UINT64_C(0xf3e2f893, dec3f126), -529, -140},
+  {GRISU_UINT64_C(0xe896a0d7, e51e1566), -509, -134},
+  {GRISU_UINT64_C(0xddd0467c, 64bce4a1), -489, -128},
+  {GRISU_UINT64_C(0xd389b478, 79823479), -469, -122},
+  {GRISU_UINT64_C(0xc9bcff60, 34c13053), -449, -116},
+  {GRISU_UINT64_C(0xc06481fb, 9bcf8d3a), -429, -110},
+  {GRISU_UINT64_C(0xb77ada06, 17e3bbcb), -409, -104},
+  {GRISU_UINT64_C(0xaefae514, 77a06b04), -389, -98},
+  {GRISU_UINT64_C(0xa6dfbd9f, b8e5b88f), -369, -92},
+  {GRISU_UINT64_C(0x9f24b832, e6b0f436), -349, -86},
+  {GRISU_UINT64_C(0x97c560ba, 6b0919a6), -329, -80},
+  {GRISU_UINT64_C(0x90bd77f3, 483bb9ba), -309, -74},
+  {GRISU_UINT64_C(0x8a08f0f8, bf0f156b), -289, -68},
+  {GRISU_UINT64_C(0x83a3eeee, f9153e89), -269, -62},
+  {GRISU_UINT64_C(0xfb158592, be068d2f), -250, -56},
+  {GRISU_UINT64_C(0xef73d256, a5c0f77d), -230, -50},
+  {GRISU_UINT64_C(0xe45c10c4, 2a2b3b06), -210, -44},
+  {GRISU_UINT64_C(0xd9c7dced, 53c72256), -190, -38},
+  {GRISU_UINT64_C(0xcfb11ead, 453994ba), -170, -32},
+  {GRISU_UINT64_C(0xc6120625, 76589ddb), -150, -26},
+  {GRISU_UINT64_C(0xbce50864, 92111aeb), -130, -20},
+  {GRISU_UINT64_C(0xb424dc35, 095cd80f), -110, -14},
+  {GRISU_UINT64_C(0xabcc7711, 8461cefd), -90, -8},
+  {GRISU_UINT64_C(0xa3d70a3d, 70a3d70a), -70, -2},
+  {GRISU_UINT64_C(0x9c400000, 00000000), -50, 4},
+  {GRISU_UINT64_C(0x9502f900, 00000000), -30, 10},
+  {GRISU_UINT64_C(0x8e1bc9bf, 04000000), -10, 16},
+  {GRISU_UINT64_C(0x87867832, 6eac9000), 10, 22},
+  {GRISU_UINT64_C(0x813f3978, f8940984), 30, 28},
+  {GRISU_UINT64_C(0xf684df56, c3e01bc7), 49, 34},
+  {GRISU_UINT64_C(0xeb194f8e, 1ae525fd), 69, 40},
+  {GRISU_UINT64_C(0xe0352f62, a19e306f), 89, 46},
+  {GRISU_UINT64_C(0xd5d238a4, abe98068), 109, 52},
+  {GRISU_UINT64_C(0xcbea6f8c, eb02bb3a), 129, 58},
+  {GRISU_UINT64_C(0xc2781f49, ffcfa6d5), 149, 64},
+  {GRISU_UINT64_C(0xb975d6b6, ee39e437), 169, 70},
+  {GRISU_UINT64_C(0xb0de6538, 8cc8ada8), 189, 76},
+  {GRISU_UINT64_C(0xa8acd7c0, 222311bd), 209, 82},
+  {GRISU_UINT64_C(0xa0dc75f1, 778e39d6), 229, 88},
+  {GRISU_UINT64_C(0x9968bf6a, bbe85f20), 249, 94},
+  {GRISU_UINT64_C(0x924d692c, a61be758), 269, 100},
+  {GRISU_UINT64_C(0x8b865b21, 5899f46d), 289, 106},
+  {GRISU_UINT64_C(0x850fadc0, 9923329e), 309, 112},
+  {GRISU_UINT64_C(0xfdcb4fa0, 02162a63), 328, 118},
+  {GRISU_UINT64_C(0xf209787b, b47d6b85), 348, 124},
+  {GRISU_UINT64_C(0xe6d3102a, d96cec1e), 368, 130},
+  {GRISU_UINT64_C(0xdc21a117, 1d42645d), 388, 136},
+  {GRISU_UINT64_C(0xd1ef0244, af2364ff), 408, 142},
+  {GRISU_UINT64_C(0xc83553c5, c8965d3d), 428, 148},
+  {GRISU_UINT64_C(0xbeeefb58, 4aff8604), 448, 154},
+  {GRISU_UINT64_C(0xb616a12b, 7fe617aa), 468, 160},
+  {GRISU_UINT64_C(0xada72ccc, 20054aea), 488, 166},
+  {GRISU_UINT64_C(0xa59bc234, db398c25), 508, 172},
+  {GRISU_UINT64_C(0x9defbf01, b061adab), 528, 178},
+  {GRISU_UINT64_C(0x969eb7c4, 7859e744), 548, 184},
+  {GRISU_UINT64_C(0x8fa47579, 1a569d11), 568, 190},
+  {GRISU_UINT64_C(0x88fcf317, f22241e2), 588, 196},
+  {GRISU_UINT64_C(0x82a45b45, 0226b39d), 608, 202},
+  {GRISU_UINT64_C(0xf92e0c35, 37826146), 627, 208},
+  {GRISU_UINT64_C(0xeda2ee1c, 7064130c), 647, 214},
+  {GRISU_UINT64_C(0xe2a0b5dc, 971f303a), 667, 220},
+  {GRISU_UINT64_C(0xd8210bef, d30efa5a), 687, 226},
+  {GRISU_UINT64_C(0xce1de406, 42e3f4b9), 707, 232},
+  {GRISU_UINT64_C(0xc491798a, 08a2ad4f), 727, 238},
+  {GRISU_UINT64_C(0xbb764c4c, a7a44410), 747, 244},
+  {GRISU_UINT64_C(0xb2c71d5b, ca9023f8), 767, 250},
+  {GRISU_UINT64_C(0xaa7eebfb, 9df9de8e), 787, 256},
+  {GRISU_UINT64_C(0xa298f2c5, 01f45f43), 807, 262},
+  {GRISU_UINT64_C(0x9b10a4e5, e9913129), 827, 268},
+  {GRISU_UINT64_C(0x93e1ab82, 52f33b46), 847, 274},
+  {GRISU_UINT64_C(0x8d07e334, 55637eb3), 867, 280},
+  {GRISU_UINT64_C(0x867f59a9, d4bed6c0), 887, 286},
+  {GRISU_UINT64_C(0x80444b5e, 7aa7cf85), 907, 292},
+  {GRISU_UINT64_C(0xf4a642e1, 4c6262c9), 926, 298},
+  {GRISU_UINT64_C(0xe950df20, 247c83fd), 946, 304},
+  {GRISU_UINT64_C(0xde81e40a, 034bcf50), 966, 310},
+  {GRISU_UINT64_C(0xd433179d, 9c8cb841), 986, 316},
+  {GRISU_UINT64_C(0xca5e89b1, 8b602368), 1006, 322},
+  {GRISU_UINT64_C(0xc0fe9088, 95cf3b44), 1026, 328},
+  {GRISU_UINT64_C(0xb80dc58e, 81fe95a1), 1046, 334},
+  {GRISU_UINT64_C(0xaf87023b, 9bf0ee6b), 1066, 340},
+  };
+static const int GRISU_CACHE_MAX_DISTANCE(6) = 20;
+// nb elements (6): 109
+static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(7)[] = {
+  {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308},
+  {GRISU_UINT64_C(0x892731ac, 9faf056f), -1063, -301},
+  {GRISU_UINT64_C(0xa37fce12, 6597973d), -1040, -294},
+  {GRISU_UINT64_C(0xc2e801fb, 244576d5), -1017, -287},
+  {GRISU_UINT64_C(0xe858ad24, 8f5c22ca), -994, -280},
+  {GRISU_UINT64_C(0x8a7d3eef, 7f1cfc52), -970, -273},
+  {GRISU_UINT64_C(0xa5178fff, 668ae0b6), -947, -266},
+  {GRISU_UINT64_C(0xc4ce17b3, 99107c23), -924, -259},
+  {GRISU_UINT64_C(0xea9c2277, 23ee8bcb), -901, -252},
+  {GRISU_UINT64_C(0x8bd6a141, 006042be), -877, -245},
+  {GRISU_UINT64_C(0xa6b34ad8, c9dfc070), -854, -238},
+  {GRISU_UINT64_C(0xc6b8e9b0, 709f109a), -831, -231},
+  {GRISU_UINT64_C(0xece53cec, 4a314ebe), -808, -224},
+  {GRISU_UINT64_C(0x8d3360f0, 9cf6e4bd), -784, -217},
+  {GRISU_UINT64_C(0xa8530886, b54dbdec), -761, -210},
+  {GRISU_UINT64_C(0xc8a883c0, fdaf7df0), -738, -203},
+  {GRISU_UINT64_C(0xef340a98, 172aace5), -715, -196},
+  {GRISU_UINT64_C(0x8e938662, 882af53e), -691, -189},
+  {GRISU_UINT64_C(0xa9f6d30a, 038d1dbc), -668, -182},
+  {GRISU_UINT64_C(0xca9cf1d2, 06fdc03c), -645, -175},
+  {GRISU_UINT64_C(0xf18899b1, bc3f8ca2), -622, -168},
+  {GRISU_UINT64_C(0x8ff71a0f, e2c2e6dc), -598, -161},
+  {GRISU_UINT64_C(0xab9eb47c, 81f5114f), -575, -154},
+  {GRISU_UINT64_C(0xcc963fee, 10b7d1b3), -552, -147},
+  {GRISU_UINT64_C(0xf3e2f893, dec3f126), -529, -140},
+  {GRISU_UINT64_C(0x915e2486, ef32cd60), -505, -133},
+  {GRISU_UINT64_C(0xad4ab711, 2eb3929e), -482, -126},
+  {GRISU_UINT64_C(0xce947a3d, a6a9273e), -459, -119},
+  {GRISU_UINT64_C(0xf64335bc, f065d37d), -436, -112},
+  {GRISU_UINT64_C(0x92c8ae6b, 464fc96f), -412, -105},
+  {GRISU_UINT64_C(0xaefae514, 77a06b04), -389, -98},
+  {GRISU_UINT64_C(0xd097ad07, a71f26b2), -366, -91},
+  {GRISU_UINT64_C(0xf8a95fcf, 88747d94), -343, -84},
+  {GRISU_UINT64_C(0x9436c076, 0c86e30c), -319, -77},
+  {GRISU_UINT64_C(0xb0af48ec, 79ace837), -296, -70},
+  {GRISU_UINT64_C(0xd29fe4b1, 8e88640f), -273, -63},
+  {GRISU_UINT64_C(0xfb158592, be068d2f), -250, -56},
+  {GRISU_UINT64_C(0x95a86376, 27989aae), -226, -49},
+  {GRISU_UINT64_C(0xb267ed19, 40f1c61c), -203, -42},
+  {GRISU_UINT64_C(0xd4ad2dbf, c3d07788), -180, -35},
+  {GRISU_UINT64_C(0xfd87b5f2, 8300ca0e), -157, -28},
+  {GRISU_UINT64_C(0x971da050, 74da7bef), -133, -21},
+  {GRISU_UINT64_C(0xb424dc35, 095cd80f), -110, -14},
+  {GRISU_UINT64_C(0xd6bf94d5, e57a42bc), -87, -7},
+  {GRISU_UINT64_C(0x80000000, 00000000), -63, 0},
+  {GRISU_UINT64_C(0x98968000, 00000000), -40, 7},
+  {GRISU_UINT64_C(0xb5e620f4, 80000000), -17, 14},
+  {GRISU_UINT64_C(0xd8d726b7, 177a8000), 6, 21},
+  {GRISU_UINT64_C(0x813f3978, f8940984), 30, 28},
+  {GRISU_UINT64_C(0x9a130b96, 3a6c115c), 53, 35},
+  {GRISU_UINT64_C(0xb7abc627, 050305ae), 76, 42},
+  {GRISU_UINT64_C(0xdaf3f046, 51d47b4c), 99, 49},
+  {GRISU_UINT64_C(0x82818f12, 81ed44a0), 123, 56},
+  {GRISU_UINT64_C(0x9b934c3b, 330c8577), 146, 63},
+  {GRISU_UINT64_C(0xb975d6b6, ee39e437), 169, 70},
+  {GRISU_UINT64_C(0xdd15fe86, affad912), 192, 77},
+  {GRISU_UINT64_C(0x83c7088e, 1aab65db), 216, 84},
+  {GRISU_UINT64_C(0x9d174b2d, cec0e47b), 239, 91},
+  {GRISU_UINT64_C(0xbb445da9, ca61281f), 262, 98},
+  {GRISU_UINT64_C(0xdf3d5e9b, c0f653e1), 285, 105},
+  {GRISU_UINT64_C(0x850fadc0, 9923329e), 309, 112},
+  {GRISU_UINT64_C(0x9e9f11c4, 014dda7e), 332, 119},
+  {GRISU_UINT64_C(0xbd176620, a501fc00), 355, 126},
+  {GRISU_UINT64_C(0xe16a1dc9, d8545e95), 378, 133},
+  {GRISU_UINT64_C(0x865b8692, 5b9bc5c2), 402, 140},
+  {GRISU_UINT64_C(0xa02aa96b, 06deb0fe), 425, 147},
+  {GRISU_UINT64_C(0xbeeefb58, 4aff8604), 448, 154},
+  {GRISU_UINT64_C(0xe39c4976, 5fdf9d95), 471, 161},
+  {GRISU_UINT64_C(0x87aa9aff, 79042287), 495, 168},
+  {GRISU_UINT64_C(0xa1ba1ba7, 9e1632dc), 518, 175},
+  {GRISU_UINT64_C(0xc0cb28a9, 8fcf3c80), 541, 182},
+  {GRISU_UINT64_C(0xe5d3ef28, 2a242e82), 564, 189},
+  {GRISU_UINT64_C(0x88fcf317, f22241e2), 588, 196},
+  {GRISU_UINT64_C(0xa34d7216, 42b06084), 611, 203},
+  {GRISU_UINT64_C(0xc2abf989, 935ddbfe), 634, 210},
+  {GRISU_UINT64_C(0xe8111c87, c5c1ba9a), 657, 217},
+  {GRISU_UINT64_C(0x8a5296ff, e33cc930), 681, 224},
+  {GRISU_UINT64_C(0xa4e4b66b, 68b65d61), 704, 231},
+  {GRISU_UINT64_C(0xc491798a, 08a2ad4f), 727, 238},
+  {GRISU_UINT64_C(0xea53df5f, d18d5514), 750, 245},
+  {GRISU_UINT64_C(0x8bab8eef, b6409c1a), 774, 252},
+  {GRISU_UINT64_C(0xa67ff273, b8460357), 797, 259},
+  {GRISU_UINT64_C(0xc67bb459, 7ce2ce49), 820, 266},
+  {GRISU_UINT64_C(0xec9c459d, 51852ba3), 843, 273},
+  {GRISU_UINT64_C(0x8d07e334, 55637eb3), 867, 280},
+  {GRISU_UINT64_C(0xa81f3014, 49ee8c70), 890, 287},
+  {GRISU_UINT64_C(0xc86ab5c3, 9fa63441), 913, 294},
+  {GRISU_UINT64_C(0xeeea5d50, 04981478), 936, 301},
+  {GRISU_UINT64_C(0x8e679c2f, 5e44ff8f), 960, 308},
+  {GRISU_UINT64_C(0xa9c2794a, e3a3c69b), 983, 315},
+  {GRISU_UINT64_C(0xca5e89b1, 8b602368), 1006, 322},
+  {GRISU_UINT64_C(0xf13e34aa, bb430a15), 1029, 329},
+  {GRISU_UINT64_C(0x8fcac257, 558ee4e6), 1053, 336},
+  };
+static const int GRISU_CACHE_MAX_DISTANCE(7) = 24;
+// nb elements (7): 93
+static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(8)[] = {
+  {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308},
+  {GRISU_UINT64_C(0xab70fe17, c79ac6ca), -1060, -300},
+  {GRISU_UINT64_C(0xff77b1fc, bebcdc4f), -1034, -292},
+  {GRISU_UINT64_C(0xbe5691ef, 416bd60c), -1007, -284},
+  {GRISU_UINT64_C(0x8dd01fad, 907ffc3c), -980, -276},
+  {GRISU_UINT64_C(0xd3515c28, 31559a83), -954, -268},
+  {GRISU_UINT64_C(0x9d71ac8f, ada6c9b5), -927, -260},
+  {GRISU_UINT64_C(0xea9c2277, 23ee8bcb), -901, -252},
+  {GRISU_UINT64_C(0xaecc4991, 4078536d), -874, -244},
+  {GRISU_UINT64_C(0x823c1279, 5db6ce57), -847, -236},
+  {GRISU_UINT64_C(0xc2109436, 4dfb5637), -821, -228},
+  {GRISU_UINT64_C(0x9096ea6f, 3848984f), -794, -220},
+  {GRISU_UINT64_C(0xd77485cb, 25823ac7), -768, -212},
+  {GRISU_UINT64_C(0xa086cfcd, 97bf97f4), -741, -204},
+  {GRISU_UINT64_C(0xef340a98, 172aace5), -715, -196},
+  {GRISU_UINT64_C(0xb23867fb, 2a35b28e), -688, -188},
+  {GRISU_UINT64_C(0x84c8d4df, d2c63f3b), -661, -180},
+  {GRISU_UINT64_C(0xc5dd4427, 1ad3cdba), -635, -172},
+  {GRISU_UINT64_C(0x936b9fce, bb25c996), -608, -164},
+  {GRISU_UINT64_C(0xdbac6c24, 7d62a584), -582, -156},
+  {GRISU_UINT64_C(0xa3ab6658, 0d5fdaf6), -555, -148},
+  {GRISU_UINT64_C(0xf3e2f893, dec3f126), -529, -140},
+  {GRISU_UINT64_C(0xb5b5ada8, aaff80b8), -502, -132},
+  {GRISU_UINT64_C(0x87625f05, 6c7c4a8b), -475, -124},
+  {GRISU_UINT64_C(0xc9bcff60, 34c13053), -449, -116},
+  {GRISU_UINT64_C(0x964e858c, 91ba2655), -422, -108},
+  {GRISU_UINT64_C(0xdff97724, 70297ebd), -396, -100},
+  {GRISU_UINT64_C(0xa6dfbd9f, b8e5b88f), -369, -92},
+  {GRISU_UINT64_C(0xf8a95fcf, 88747d94), -343, -84},
+  {GRISU_UINT64_C(0xb9447093, 8fa89bcf), -316, -76},
+  {GRISU_UINT64_C(0x8a08f0f8, bf0f156b), -289, -68},
+  {GRISU_UINT64_C(0xcdb02555, 653131b6), -263, -60},
+  {GRISU_UINT64_C(0x993fe2c6, d07b7fac), -236, -52},
+  {GRISU_UINT64_C(0xe45c10c4, 2a2b3b06), -210, -44},
+  {GRISU_UINT64_C(0xaa242499, 697392d3), -183, -36},
+  {GRISU_UINT64_C(0xfd87b5f2, 8300ca0e), -157, -28},
+  {GRISU_UINT64_C(0xbce50864, 92111aeb), -130, -20},
+  {GRISU_UINT64_C(0x8cbccc09, 6f5088cc), -103, -12},
+  {GRISU_UINT64_C(0xd1b71758, e219652c), -77, -4},
+  {GRISU_UINT64_C(0x9c400000, 00000000), -50, 4},
+  {GRISU_UINT64_C(0xe8d4a510, 00000000), -24, 12},
+  {GRISU_UINT64_C(0xad78ebc5, ac620000), 3, 20},
+  {GRISU_UINT64_C(0x813f3978, f8940984), 30, 28},
+  {GRISU_UINT64_C(0xc097ce7b, c90715b3), 56, 36},
+  {GRISU_UINT64_C(0x8f7e32ce, 7bea5c70), 83, 44},
+  {GRISU_UINT64_C(0xd5d238a4, abe98068), 109, 52},
+  {GRISU_UINT64_C(0x9f4f2726, 179a2245), 136, 60},
+  {GRISU_UINT64_C(0xed63a231, d4c4fb27), 162, 68},
+  {GRISU_UINT64_C(0xb0de6538, 8cc8ada8), 189, 76},
+  {GRISU_UINT64_C(0x83c7088e, 1aab65db), 216, 84},
+  {GRISU_UINT64_C(0xc45d1df9, 42711d9a), 242, 92},
+  {GRISU_UINT64_C(0x924d692c, a61be758), 269, 100},
+  {GRISU_UINT64_C(0xda01ee64, 1a708dea), 295, 108},
+  {GRISU_UINT64_C(0xa26da399, 9aef774a), 322, 116},
+  {GRISU_UINT64_C(0xf209787b, b47d6b85), 348, 124},
+  {GRISU_UINT64_C(0xb454e4a1, 79dd1877), 375, 132},
+  {GRISU_UINT64_C(0x865b8692, 5b9bc5c2), 402, 140},
+  {GRISU_UINT64_C(0xc83553c5, c8965d3d), 428, 148},
+  {GRISU_UINT64_C(0x952ab45c, fa97a0b3), 455, 156},
+  {GRISU_UINT64_C(0xde469fbd, 99a05fe3), 481, 164},
+  {GRISU_UINT64_C(0xa59bc234, db398c25), 508, 172},
+  {GRISU_UINT64_C(0xf6c69a72, a3989f5c), 534, 180},
+  {GRISU_UINT64_C(0xb7dcbf53, 54e9bece), 561, 188},
+  {GRISU_UINT64_C(0x88fcf317, f22241e2), 588, 196},
+  {GRISU_UINT64_C(0xcc20ce9b, d35c78a5), 614, 204},
+  {GRISU_UINT64_C(0x98165af3, 7b2153df), 641, 212},
+  {GRISU_UINT64_C(0xe2a0b5dc, 971f303a), 667, 220},
+  {GRISU_UINT64_C(0xa8d9d153, 5ce3b396), 694, 228},
+  {GRISU_UINT64_C(0xfb9b7cd9, a4a7443c), 720, 236},
+  {GRISU_UINT64_C(0xbb764c4c, a7a44410), 747, 244},
+  {GRISU_UINT64_C(0x8bab8eef, b6409c1a), 774, 252},
+  {GRISU_UINT64_C(0xd01fef10, a657842c), 800, 260},
+  {GRISU_UINT64_C(0x9b10a4e5, e9913129), 827, 268},
+  {GRISU_UINT64_C(0xe7109bfb, a19c0c9d), 853, 276},
+  {GRISU_UINT64_C(0xac2820d9, 623bf429), 880, 284},
+  {GRISU_UINT64_C(0x80444b5e, 7aa7cf85), 907, 292},
+  {GRISU_UINT64_C(0xbf21e440, 03acdd2d), 933, 300},
+  {GRISU_UINT64_C(0x8e679c2f, 5e44ff8f), 960, 308},
+  {GRISU_UINT64_C(0xd433179d, 9c8cb841), 986, 316},
+  {GRISU_UINT64_C(0x9e19db92, b4e31ba9), 1013, 324},
+  {GRISU_UINT64_C(0xeb96bf6e, badf77d9), 1039, 332},
+  {GRISU_UINT64_C(0xaf87023b, 9bf0ee6b), 1066, 340},
+  };
+static const int GRISU_CACHE_MAX_DISTANCE(8) = 27;
+// nb elements (8): 82
+static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(9)[] = {
+  {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308},
+  {GRISU_UINT64_C(0xd64d3d9d, b981787d), -1057, -299},
+  {GRISU_UINT64_C(0xc795830d, 75038c1e), -1027, -290},
+  {GRISU_UINT64_C(0xb9e08a83, a5e34f08), -997, -281},
+  {GRISU_UINT64_C(0xad1c8eab, 5ee43b67), -967, -272},
+  {GRISU_UINT64_C(0xa139029f, 6a239f72), -937, -263},
+  {GRISU_UINT64_C(0x96267c75, 35b763b5), -907, -254},
+  {GRISU_UINT64_C(0x8bd6a141, 006042be), -877, -245},
+  {GRISU_UINT64_C(0x823c1279, 5db6ce57), -847, -236},
+  {GRISU_UINT64_C(0xf294b943, e17a2bc4), -818, -227},
+  {GRISU_UINT64_C(0xe1ebce4d, c7f16dfc), -788, -218},
+  {GRISU_UINT64_C(0xd267caa8, 62a12d67), -758, -209},
+  {GRISU_UINT64_C(0xc3f490aa, 77bd60fd), -728, -200},
+  {GRISU_UINT64_C(0xb67f6455, 292cbf08), -698, -191},
+  {GRISU_UINT64_C(0xa9f6d30a, 038d1dbc), -668, -182},
+  {GRISU_UINT64_C(0x9e4a9cec, 15763e2f), -638, -173},
+  {GRISU_UINT64_C(0x936b9fce, bb25c996), -608, -164},
+  {GRISU_UINT64_C(0x894bc396, ce5da772), -578, -155},
+  {GRISU_UINT64_C(0xffbbcfe9, 94e5c620), -549, -146},
+  {GRISU_UINT64_C(0xee2ba6c0, 678b597f), -519, -137},
+  {GRISU_UINT64_C(0xddd0467c, 64bce4a1), -489, -128},
+  {GRISU_UINT64_C(0xce947a3d, a6a9273e), -459, -119},
+  {GRISU_UINT64_C(0xc06481fb, 9bcf8d3a), -429, -110},
+  {GRISU_UINT64_C(0xb32df8e9, f3546564), -399, -101},
+  {GRISU_UINT64_C(0xa6dfbd9f, b8e5b88f), -369, -92},
+  {GRISU_UINT64_C(0x9b69dbe1, b548ce7d), -339, -83},
+  {GRISU_UINT64_C(0x90bd77f3, 483bb9ba), -309, -74},
+  {GRISU_UINT64_C(0x86ccbb52, ea94baeb), -279, -65},
+  {GRISU_UINT64_C(0xfb158592, be068d2f), -250, -56},
+  {GRISU_UINT64_C(0xe9d71b68, 9dde71b0), -220, -47},
+  {GRISU_UINT64_C(0xd9c7dced, 53c72256), -190, -38},
+  {GRISU_UINT64_C(0xcad2f7f5, 359a3b3e), -160, -29},
+  {GRISU_UINT64_C(0xbce50864, 92111aeb), -130, -20},
+  {GRISU_UINT64_C(0xafebff0b, cb24aaff), -100, -11},
+  {GRISU_UINT64_C(0xa3d70a3d, 70a3d70a), -70, -2},
+  {GRISU_UINT64_C(0x98968000, 00000000), -40, 7},
+  {GRISU_UINT64_C(0x8e1bc9bf, 04000000), -10, 16},
+  {GRISU_UINT64_C(0x84595161, 401484a0), 20, 25},
+  {GRISU_UINT64_C(0xf684df56, c3e01bc7), 49, 34},
+  {GRISU_UINT64_C(0xe596b7b0, c643c719), 79, 43},
+  {GRISU_UINT64_C(0xd5d238a4, abe98068), 109, 52},
+  {GRISU_UINT64_C(0xc722f0ef, 9d80aad6), 139, 61},
+  {GRISU_UINT64_C(0xb975d6b6, ee39e437), 169, 70},
+  {GRISU_UINT64_C(0xacb92ed9, 397bf996), 199, 79},
+  {GRISU_UINT64_C(0xa0dc75f1, 778e39d6), 229, 88},
+  {GRISU_UINT64_C(0x95d04aee, 3b80ece6), 259, 97},
+  {GRISU_UINT64_C(0x8b865b21, 5899f46d), 289, 106},
+  {GRISU_UINT64_C(0x81f14fae, 158c5f6e), 319, 115},
+  {GRISU_UINT64_C(0xf209787b, b47d6b85), 348, 124},
+  {GRISU_UINT64_C(0xe16a1dc9, d8545e95), 378, 133},
+  {GRISU_UINT64_C(0xd1ef0244, af2364ff), 408, 142},
+  {GRISU_UINT64_C(0xc38413cf, 25e2d70e), 438, 151},
+  {GRISU_UINT64_C(0xb616a12b, 7fe617aa), 468, 160},
+  {GRISU_UINT64_C(0xa99541bf, 57452b28), 498, 169},
+  {GRISU_UINT64_C(0x9defbf01, b061adab), 528, 178},
+  {GRISU_UINT64_C(0x9316ff75, dd87cbd8), 558, 187},
+  {GRISU_UINT64_C(0x88fcf317, f22241e2), 588, 196},
+  {GRISU_UINT64_C(0xff290242, c83396ce), 617, 205},
+  {GRISU_UINT64_C(0xeda2ee1c, 7064130c), 647, 214},
+  {GRISU_UINT64_C(0xdd50f199, 6b947519), 677, 223},
+  {GRISU_UINT64_C(0xce1de406, 42e3f4b9), 707, 232},
+  {GRISU_UINT64_C(0xbff610b0, cc6edd3f), 737, 241},
+  {GRISU_UINT64_C(0xb2c71d5b, ca9023f8), 767, 250},
+  {GRISU_UINT64_C(0xa67ff273, b8460357), 797, 259},
+  {GRISU_UINT64_C(0x9b10a4e5, e9913129), 827, 268},
+  {GRISU_UINT64_C(0x906a617d, 450187e2), 857, 277},
+  {GRISU_UINT64_C(0x867f59a9, d4bed6c0), 887, 286},
+  {GRISU_UINT64_C(0xfa856334, 878fc151), 916, 295},
+  {GRISU_UINT64_C(0xe950df20, 247c83fd), 946, 304},
+  {GRISU_UINT64_C(0xd94ad8b1, c7380874), 976, 313},
+  {GRISU_UINT64_C(0xca5e89b1, 8b602368), 1006, 322},
+  {GRISU_UINT64_C(0xbc789925, 624c5fe1), 1036, 331},
+  {GRISU_UINT64_C(0xaf87023b, 9bf0ee6b), 1066, 340},
+  };
+static const int GRISU_CACHE_MAX_DISTANCE(9) = 30;
+// nb elements (9): 73
+static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(10)[] = {
+  {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308},
+  {GRISU_UINT64_C(0x85f04682, 93f0eb4e), -1053, -298},
+  {GRISU_UINT64_C(0x9becce62, 836ac577), -1020, -288},
+  {GRISU_UINT64_C(0xb5854744, 8ffffb2e), -987, -278},
+  {GRISU_UINT64_C(0xd3515c28, 31559a83), -954, -268},
+  {GRISU_UINT64_C(0xf6019da0, 7f549b2b), -921, -258},
+  {GRISU_UINT64_C(0x8f31cc09, 37ae58d3), -887, -248},
+  {GRISU_UINT64_C(0xa6b34ad8, c9dfc070), -854, -238},
+  {GRISU_UINT64_C(0xc2109436, 4dfb5637), -821, -228},
+  {GRISU_UINT64_C(0xe1ebce4d, c7f16dfc), -788, -218},
+  {GRISU_UINT64_C(0x8380dea9, 3da4bc60), -754, -208},
+  {GRISU_UINT64_C(0x99171105, 2d8bf3c5), -721, -198},
+  {GRISU_UINT64_C(0xb23867fb, 2a35b28e), -688, -188},
+  {GRISU_UINT64_C(0xcf79cc9d, b955c2cc), -655, -178},
+  {GRISU_UINT64_C(0xf18899b1, bc3f8ca2), -622, -168},
+  {GRISU_UINT64_C(0x8c974f73, 83725573), -588, -158},
+  {GRISU_UINT64_C(0xa3ab6658, 0d5fdaf6), -555, -148},
+  {GRISU_UINT64_C(0xbe895233, 86091466), -522, -138},
+  {GRISU_UINT64_C(0xddd0467c, 64bce4a1), -489, -128},
+  {GRISU_UINT64_C(0x811ccc66, 8829b887), -455, -118},
+  {GRISU_UINT64_C(0x964e858c, 91ba2655), -422, -108},
+  {GRISU_UINT64_C(0xaefae514, 77a06b04), -389, -98},
+  {GRISU_UINT64_C(0xcbb41ef9, 79346bca), -356, -88},
+  {GRISU_UINT64_C(0xed246723, 473e3813), -323, -78},
+  {GRISU_UINT64_C(0x8a08f0f8, bf0f156b), -289, -68},
+  {GRISU_UINT64_C(0xa0b19d2a, b70e6ed6), -256, -58},
+  {GRISU_UINT64_C(0xbb127c53, b17ec159), -223, -48},
+  {GRISU_UINT64_C(0xd9c7dced, 53c72256), -190, -38},
+  {GRISU_UINT64_C(0xfd87b5f2, 8300ca0e), -157, -28},
+  {GRISU_UINT64_C(0x9392ee8e, 921d5d07), -123, -18},
+  {GRISU_UINT64_C(0xabcc7711, 8461cefd), -90, -8},
+  {GRISU_UINT64_C(0xc8000000, 00000000), -57, 2},
+  {GRISU_UINT64_C(0xe8d4a510, 00000000), -24, 12},
+  {GRISU_UINT64_C(0x87867832, 6eac9000), 10, 22},
+  {GRISU_UINT64_C(0x9dc5ada8, 2b70b59e), 43, 32},
+  {GRISU_UINT64_C(0xb7abc627, 050305ae), 76, 42},
+  {GRISU_UINT64_C(0xd5d238a4, abe98068), 109, 52},
+  {GRISU_UINT64_C(0xf8ebad2b, 84e0d58c), 142, 62},
+  {GRISU_UINT64_C(0x90e40fbe, ea1d3a4b), 176, 72},
+  {GRISU_UINT64_C(0xa8acd7c0, 222311bd), 209, 82},
+  {GRISU_UINT64_C(0xc45d1df9, 42711d9a), 242, 92},
+  {GRISU_UINT64_C(0xe498f455, c38b997a), 275, 102},
+  {GRISU_UINT64_C(0x850fadc0, 9923329e), 309, 112},
+  {GRISU_UINT64_C(0x9ae75759, 6946075f), 342, 122},
+  {GRISU_UINT64_C(0xb454e4a1, 79dd1877), 375, 132},
+  {GRISU_UINT64_C(0xd1ef0244, af2364ff), 408, 142},
+  {GRISU_UINT64_C(0xf46518c2, ef5b8cd1), 441, 152},
+  {GRISU_UINT64_C(0x8e41ade9, fbebc27d), 475, 162},
+  {GRISU_UINT64_C(0xa59bc234, db398c25), 508, 172},
+  {GRISU_UINT64_C(0xc0cb28a9, 8fcf3c80), 541, 182},
+  {GRISU_UINT64_C(0xe070f78d, 3927556b), 574, 192},
+  {GRISU_UINT64_C(0x82a45b45, 0226b39d), 608, 202},
+  {GRISU_UINT64_C(0x98165af3, 7b2153df), 641, 212},
+  {GRISU_UINT64_C(0xb10d8e14, 56105dad), 674, 222},
+  {GRISU_UINT64_C(0xce1de406, 42e3f4b9), 707, 232},
+  {GRISU_UINT64_C(0xeff394dc, ff8a948f), 740, 242},
+  {GRISU_UINT64_C(0x8bab8eef, b6409c1a), 774, 252},
+  {GRISU_UINT64_C(0xa298f2c5, 01f45f43), 807, 262},
+  {GRISU_UINT64_C(0xbd49d14a, a79dbc82), 840, 272},
+  {GRISU_UINT64_C(0xdc5c5301, c56b75f7), 873, 282},
+  {GRISU_UINT64_C(0x80444b5e, 7aa7cf85), 907, 292},
+  {GRISU_UINT64_C(0x95527a52, 02df0ccb), 940, 302},
+  {GRISU_UINT64_C(0xadd57a27, d29339f6), 973, 312},
+  {GRISU_UINT64_C(0xca5e89b1, 8b602368), 1006, 322},
+  {GRISU_UINT64_C(0xeb96bf6e, badf77d9), 1039, 332},
+  {GRISU_UINT64_C(0x892179be, 91d43a44), 1073, 342},
+  };
+static const int GRISU_CACHE_MAX_DISTANCE(10) = 34;
+// nb elements (10): 66
+static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(11)[] = {
+  {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308},
+  {GRISU_UINT64_C(0xa76c5823, 38ed2622), -1050, -297},
+  {GRISU_UINT64_C(0xf3a20279, ed56d48a), -1014, -286},
+  {GRISU_UINT64_C(0xb1442798, f49ffb4b), -977, -275},
+  {GRISU_UINT64_C(0x80fa687f, 881c7f8e), -940, -264},
+  {GRISU_UINT64_C(0xbbb01b92, 83253ca3), -904, -253},
+  {GRISU_UINT64_C(0x888f9979, 7a5e012d), -867, -242},
+  {GRISU_UINT64_C(0xc6b8e9b0, 709f109a), -831, -231},
+  {GRISU_UINT64_C(0x9096ea6f, 3848984f), -794, -220},
+  {GRISU_UINT64_C(0xd267caa8, 62a12d67), -758, -209},
+  {GRISU_UINT64_C(0x99171105, 2d8bf3c5), -721, -198},
+  {GRISU_UINT64_C(0xdec681f9, f4c31f31), -685, -187},
+  {GRISU_UINT64_C(0xa21727db, 38cb0030), -648, -176},
+  {GRISU_UINT64_C(0xebdf6617, 91d60f56), -612, -165},
+  {GRISU_UINT64_C(0xab9eb47c, 81f5114f), -575, -154},
+  {GRISU_UINT64_C(0xf9bd690a, 1b68637b), -539, -143},
+  {GRISU_UINT64_C(0xb5b5ada8, aaff80b8), -502, -132},
+  {GRISU_UINT64_C(0x843610cb, 4bf160cc), -465, -121},
+  {GRISU_UINT64_C(0xc06481fb, 9bcf8d3a), -429, -110},
+  {GRISU_UINT64_C(0x8bfbea76, c619ef36), -392, -99},
+  {GRISU_UINT64_C(0xcbb41ef9, 79346bca), -356, -88},
+  {GRISU_UINT64_C(0x9436c076, 0c86e30c), -319, -77},
+  {GRISU_UINT64_C(0xd7adf884, aa879177), -283, -66},
+  {GRISU_UINT64_C(0x9ced737b, b6c4183d), -246, -55},
+  {GRISU_UINT64_C(0xe45c10c4, 2a2b3b06), -210, -44},
+  {GRISU_UINT64_C(0xa6274bbd, d0fadd62), -173, -33},
+  {GRISU_UINT64_C(0xf1c90080, baf72cb1), -137, -22},
+  {GRISU_UINT64_C(0xafebff0b, cb24aaff), -100, -11},
+  {GRISU_UINT64_C(0x80000000, 00000000), -63, 0},
+  {GRISU_UINT64_C(0xba43b740, 00000000), -27, 11},
+  {GRISU_UINT64_C(0x87867832, 6eac9000), 10, 22},
+  {GRISU_UINT64_C(0xc5371912, 364ce305), 46, 33},
+  {GRISU_UINT64_C(0x8f7e32ce, 7bea5c70), 83, 44},
+  {GRISU_UINT64_C(0xd0cf4b50, cfe20766), 119, 55},
+  {GRISU_UINT64_C(0x97edd871, cfda3a57), 156, 66},
+  {GRISU_UINT64_C(0xdd15fe86, affad912), 192, 77},
+  {GRISU_UINT64_C(0xa0dc75f1, 778e39d6), 229, 88},
+  {GRISU_UINT64_C(0xea157514, 3cf97227), 265, 99},
+  {GRISU_UINT64_C(0xaa51823e, 34a7eedf), 302, 110},
+  {GRISU_UINT64_C(0xf7d88bc2, 4209a565), 338, 121},
+  {GRISU_UINT64_C(0xb454e4a1, 79dd1877), 375, 132},
+  {GRISU_UINT64_C(0x8335616a, ed761f1f), 412, 143},
+  {GRISU_UINT64_C(0xbeeefb58, 4aff8604), 448, 154},
+  {GRISU_UINT64_C(0x8aec23d6, 80043bee), 485, 165},
+  {GRISU_UINT64_C(0xca28a291, 859bbf93), 521, 176},
+  {GRISU_UINT64_C(0x9316ff75, dd87cbd8), 558, 187},
+  {GRISU_UINT64_C(0xd60b3bd5, 6a5586f2), 594, 198},
+  {GRISU_UINT64_C(0x9bbcc7a1, 42b17ccc), 631, 209},
+  {GRISU_UINT64_C(0xe2a0b5dc, 971f303a), 667, 220},
+  {GRISU_UINT64_C(0xa4e4b66b, 68b65d61), 704, 231},
+  {GRISU_UINT64_C(0xeff394dc, ff8a948f), 740, 242},
+  {GRISU_UINT64_C(0xae9672ab, a3d0c321), 777, 253},
+  {GRISU_UINT64_C(0xfe0efb53, d30dd4d8), 813, 264},
+  {GRISU_UINT64_C(0xb8da1662, e7b00a17), 850, 275},
+  {GRISU_UINT64_C(0x867f59a9, d4bed6c0), 887, 286},
+  {GRISU_UINT64_C(0xc3b83581, 09e84f07), 923, 297},
+  {GRISU_UINT64_C(0x8e679c2f, 5e44ff8f), 960, 308},
+  {GRISU_UINT64_C(0xcf39e50f, eae16bf0), 996, 319},
+  {GRISU_UINT64_C(0x96c6e0ea, b509e64d), 1033, 330},
+  {GRISU_UINT64_C(0xdb68c2ca, 82ed2a06), 1069, 341},
+  };
+static const int GRISU_CACHE_MAX_DISTANCE(11) = 37;
+// nb elements (11): 60
+static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(12)[] = {
+  {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308},
+  {GRISU_UINT64_C(0xd1476e2c, 07286faa), -1047, -296},
+  {GRISU_UINT64_C(0xbe5691ef, 416bd60c), -1007, -284},
+  {GRISU_UINT64_C(0xad1c8eab, 5ee43b67), -967, -272},
+  {GRISU_UINT64_C(0x9d71ac8f, ada6c9b5), -927, -260},
+  {GRISU_UINT64_C(0x8f31cc09, 37ae58d3), -887, -248},
+  {GRISU_UINT64_C(0x823c1279, 5db6ce57), -847, -236},
+  {GRISU_UINT64_C(0xece53cec, 4a314ebe), -808, -224},
+  {GRISU_UINT64_C(0xd77485cb, 25823ac7), -768, -212},
+  {GRISU_UINT64_C(0xc3f490aa, 77bd60fd), -728, -200},
+  {GRISU_UINT64_C(0xb23867fb, 2a35b28e), -688, -188},
+  {GRISU_UINT64_C(0xa21727db, 38cb0030), -648, -176},
+  {GRISU_UINT64_C(0x936b9fce, bb25c996), -608, -164},
+  {GRISU_UINT64_C(0x8613fd01, 45877586), -568, -152},
+  {GRISU_UINT64_C(0xf3e2f893, dec3f126), -529, -140},
+  {GRISU_UINT64_C(0xddd0467c, 64bce4a1), -489, -128},
+  {GRISU_UINT64_C(0xc9bcff60, 34c13053), -449, -116},
+  {GRISU_UINT64_C(0xb77ada06, 17e3bbcb), -409, -104},
+  {GRISU_UINT64_C(0xa6dfbd9f, b8e5b88f), -369, -92},
+  {GRISU_UINT64_C(0x97c560ba, 6b0919a6), -329, -80},
+  {GRISU_UINT64_C(0x8a08f0f8, bf0f156b), -289, -68},
+  {GRISU_UINT64_C(0xfb158592, be068d2f), -250, -56},
+  {GRISU_UINT64_C(0xe45c10c4, 2a2b3b06), -210, -44},
+  {GRISU_UINT64_C(0xcfb11ead, 453994ba), -170, -32},
+  {GRISU_UINT64_C(0xbce50864, 92111aeb), -130, -20},
+  {GRISU_UINT64_C(0xabcc7711, 8461cefd), -90, -8},
+  {GRISU_UINT64_C(0x9c400000, 00000000), -50, 4},
+  {GRISU_UINT64_C(0x8e1bc9bf, 04000000), -10, 16},
+  {GRISU_UINT64_C(0x813f3978, f8940984), 30, 28},
+  {GRISU_UINT64_C(0xeb194f8e, 1ae525fd), 69, 40},
+  {GRISU_UINT64_C(0xd5d238a4, abe98068), 109, 52},
+  {GRISU_UINT64_C(0xc2781f49, ffcfa6d5), 149, 64},
+  {GRISU_UINT64_C(0xb0de6538, 8cc8ada8), 189, 76},
+  {GRISU_UINT64_C(0xa0dc75f1, 778e39d6), 229, 88},
+  {GRISU_UINT64_C(0x924d692c, a61be758), 269, 100},
+  {GRISU_UINT64_C(0x850fadc0, 9923329e), 309, 112},
+  {GRISU_UINT64_C(0xf209787b, b47d6b85), 348, 124},
+  {GRISU_UINT64_C(0xdc21a117, 1d42645d), 388, 136},
+  {GRISU_UINT64_C(0xc83553c5, c8965d3d), 428, 148},
+  {GRISU_UINT64_C(0xb616a12b, 7fe617aa), 468, 160},
+  {GRISU_UINT64_C(0xa59bc234, db398c25), 508, 172},
+  {GRISU_UINT64_C(0x969eb7c4, 7859e744), 548, 184},
+  {GRISU_UINT64_C(0x88fcf317, f22241e2), 588, 196},
+  {GRISU_UINT64_C(0xf92e0c35, 37826146), 627, 208},
+  {GRISU_UINT64_C(0xe2a0b5dc, 971f303a), 667, 220},
+  {GRISU_UINT64_C(0xce1de406, 42e3f4b9), 707, 232},
+  {GRISU_UINT64_C(0xbb764c4c, a7a44410), 747, 244},
+  {GRISU_UINT64_C(0xaa7eebfb, 9df9de8e), 787, 256},
+  {GRISU_UINT64_C(0x9b10a4e5, e9913129), 827, 268},
+  {GRISU_UINT64_C(0x8d07e334, 55637eb3), 867, 280},
+  {GRISU_UINT64_C(0x80444b5e, 7aa7cf85), 907, 292},
+  {GRISU_UINT64_C(0xe950df20, 247c83fd), 946, 304},
+  {GRISU_UINT64_C(0xd433179d, 9c8cb841), 986, 316},
+  {GRISU_UINT64_C(0xc0fe9088, 95cf3b44), 1026, 328},
+  {GRISU_UINT64_C(0xaf87023b, 9bf0ee6b), 1066, 340},
+  };
+static const int GRISU_CACHE_MAX_DISTANCE(12) = 40;
+// nb elements (12): 55
+static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(13)[] = {
+  {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308},
+  {GRISU_UINT64_C(0x82cca4db, 847945ca), -1043, -295},
+  {GRISU_UINT64_C(0x94b3a202, eb1c3f39), -1000, -282},
+  {GRISU_UINT64_C(0xa90de353, 5aaae202), -957, -269},
+  {GRISU_UINT64_C(0xc0314325, 637a193a), -914, -256},
+  {GRISU_UINT64_C(0xda7f5bf5, 90966849), -871, -243},
+  {GRISU_UINT64_C(0xf867241c, 8cc6d4c1), -828, -230},
+  {GRISU_UINT64_C(0x8d3360f0, 9cf6e4bd), -784, -217},
+  {GRISU_UINT64_C(0xa086cfcd, 97bf97f4), -741, -204},
+  {GRISU_UINT64_C(0xb67f6455, 292cbf08), -698, -191},
+  {GRISU_UINT64_C(0xcf79cc9d, b955c2cc), -655, -178},
+  {GRISU_UINT64_C(0xebdf6617, 91d60f56), -612, -165},
+  {GRISU_UINT64_C(0x8613fd01, 45877586), -568, -152},
+  {GRISU_UINT64_C(0x986ddb5c, 6b3a76b8), -525, -139},
+  {GRISU_UINT64_C(0xad4ab711, 2eb3929e), -482, -126},
+  {GRISU_UINT64_C(0xc5029163, f384a931), -439, -113},
+  {GRISU_UINT64_C(0xdff97724, 70297ebd), -396, -100},
+  {GRISU_UINT64_C(0xfea126b7, d78186bd), -353, -87},
+  {GRISU_UINT64_C(0x90bd77f3, 483bb9ba), -309, -74},
+  {GRISU_UINT64_C(0xa48ceaaa, b75a8e2b), -266, -61},
+  {GRISU_UINT64_C(0xbb127c53, b17ec159), -223, -48},
+  {GRISU_UINT64_C(0xd4ad2dbf, c3d07788), -180, -35},
+  {GRISU_UINT64_C(0xf1c90080, baf72cb1), -137, -22},
+  {GRISU_UINT64_C(0x89705f41, 36b4a597), -93, -9},
+  {GRISU_UINT64_C(0x9c400000, 00000000), -50, 4},
+  {GRISU_UINT64_C(0xb1a2bc2e, c5000000), -7, 17},
+  {GRISU_UINT64_C(0xc9f2c9cd, 04674edf), 36, 30},
+  {GRISU_UINT64_C(0xe596b7b0, c643c719), 79, 43},
+  {GRISU_UINT64_C(0x82818f12, 81ed44a0), 123, 56},
+  {GRISU_UINT64_C(0x945e455f, 24fb1cf9), 166, 69},
+  {GRISU_UINT64_C(0xa8acd7c0, 222311bd), 209, 82},
+  {GRISU_UINT64_C(0xbfc2ef45, 6ae276e9), 252, 95},
+  {GRISU_UINT64_C(0xda01ee64, 1a708dea), 295, 108},
+  {GRISU_UINT64_C(0xf7d88bc2, 4209a565), 338, 121},
+  {GRISU_UINT64_C(0x8ce2529e, 2734bb1d), 382, 134},
+  {GRISU_UINT64_C(0xa02aa96b, 06deb0fe), 425, 147},
+  {GRISU_UINT64_C(0xb616a12b, 7fe617aa), 468, 160},
+  {GRISU_UINT64_C(0xcf02b2c2, 1207ef2f), 511, 173},
+  {GRISU_UINT64_C(0xeb57ff22, fc0c795a), 554, 186},
+  {GRISU_UINT64_C(0x85c70565, 62757457), 598, 199},
+  {GRISU_UINT64_C(0x98165af3, 7b2153df), 641, 212},
+  {GRISU_UINT64_C(0xace73cbf, dc0bfb7b), 684, 225},
+  {GRISU_UINT64_C(0xc491798a, 08a2ad4f), 727, 238},
+  {GRISU_UINT64_C(0xdf78e4b2, bd342cf7), 770, 251},
+  {GRISU_UINT64_C(0xfe0efb53, d30dd4d8), 813, 264},
+  {GRISU_UINT64_C(0x906a617d, 450187e2), 857, 277},
+  {GRISU_UINT64_C(0xa42e74f3, d032f526), 900, 290},
+  {GRISU_UINT64_C(0xbaa718e6, 8396cffe), 943, 303},
+  {GRISU_UINT64_C(0xd433179d, 9c8cb841), 986, 316},
+  {GRISU_UINT64_C(0xf13e34aa, bb430a15), 1029, 329},
+  {GRISU_UINT64_C(0x892179be, 91d43a44), 1073, 342},
+  };
+static const int GRISU_CACHE_MAX_DISTANCE(13) = 44;
+// nb elements (13): 51
+static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(14)[] = {
+  {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308},
+  {GRISU_UINT64_C(0xa37fce12, 6597973d), -1040, -294},
+  {GRISU_UINT64_C(0xe858ad24, 8f5c22ca), -994, -280},
+  {GRISU_UINT64_C(0xa5178fff, 668ae0b6), -947, -266},
+  {GRISU_UINT64_C(0xea9c2277, 23ee8bcb), -901, -252},
+  {GRISU_UINT64_C(0xa6b34ad8, c9dfc070), -854, -238},
+  {GRISU_UINT64_C(0xece53cec, 4a314ebe), -808, -224},
+  {GRISU_UINT64_C(0xa8530886, b54dbdec), -761, -210},
+  {GRISU_UINT64_C(0xef340a98, 172aace5), -715, -196},
+  {GRISU_UINT64_C(0xa9f6d30a, 038d1dbc), -668, -182},
+  {GRISU_UINT64_C(0xf18899b1, bc3f8ca2), -622, -168},
+  {GRISU_UINT64_C(0xab9eb47c, 81f5114f), -575, -154},
+  {GRISU_UINT64_C(0xf3e2f893, dec3f126), -529, -140},
+  {GRISU_UINT64_C(0xad4ab711, 2eb3929e), -482, -126},
+  {GRISU_UINT64_C(0xf64335bc, f065d37d), -436, -112},
+  {GRISU_UINT64_C(0xaefae514, 77a06b04), -389, -98},
+  {GRISU_UINT64_C(0xf8a95fcf, 88747d94), -343, -84},
+  {GRISU_UINT64_C(0xb0af48ec, 79ace837), -296, -70},
+  {GRISU_UINT64_C(0xfb158592, be068d2f), -250, -56},
+  {GRISU_UINT64_C(0xb267ed19, 40f1c61c), -203, -42},
+  {GRISU_UINT64_C(0xfd87b5f2, 8300ca0e), -157, -28},
+  {GRISU_UINT64_C(0xb424dc35, 095cd80f), -110, -14},
+  {GRISU_UINT64_C(0x80000000, 00000000), -63, 0},
+  {GRISU_UINT64_C(0xb5e620f4, 80000000), -17, 14},
+  {GRISU_UINT64_C(0x813f3978, f8940984), 30, 28},
+  {GRISU_UINT64_C(0xb7abc627, 050305ae), 76, 42},
+  {GRISU_UINT64_C(0x82818f12, 81ed44a0), 123, 56},
+  {GRISU_UINT64_C(0xb975d6b6, ee39e437), 169, 70},
+  {GRISU_UINT64_C(0x83c7088e, 1aab65db), 216, 84},
+  {GRISU_UINT64_C(0xbb445da9, ca61281f), 262, 98},
+  {GRISU_UINT64_C(0x850fadc0, 9923329e), 309, 112},
+  {GRISU_UINT64_C(0xbd176620, a501fc00), 355, 126},
+  {GRISU_UINT64_C(0x865b8692, 5b9bc5c2), 402, 140},
+  {GRISU_UINT64_C(0xbeeefb58, 4aff8604), 448, 154},
+  {GRISU_UINT64_C(0x87aa9aff, 79042287), 495, 168},
+  {GRISU_UINT64_C(0xc0cb28a9, 8fcf3c80), 541, 182},
+  {GRISU_UINT64_C(0x88fcf317, f22241e2), 588, 196},
+  {GRISU_UINT64_C(0xc2abf989, 935ddbfe), 634, 210},
+  {GRISU_UINT64_C(0x8a5296ff, e33cc930), 681, 224},
+  {GRISU_UINT64_C(0xc491798a, 08a2ad4f), 727, 238},
+  {GRISU_UINT64_C(0x8bab8eef, b6409c1a), 774, 252},
+  {GRISU_UINT64_C(0xc67bb459, 7ce2ce49), 820, 266},
+  {GRISU_UINT64_C(0x8d07e334, 55637eb3), 867, 280},
+  {GRISU_UINT64_C(0xc86ab5c3, 9fa63441), 913, 294},
+  {GRISU_UINT64_C(0x8e679c2f, 5e44ff8f), 960, 308},
+  {GRISU_UINT64_C(0xca5e89b1, 8b602368), 1006, 322},
+  {GRISU_UINT64_C(0x8fcac257, 558ee4e6), 1053, 336},
+  };
+static const int GRISU_CACHE_MAX_DISTANCE(14) = 47;
+// nb elements (14): 47
+static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(15)[] = {
+  {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308},
+  {GRISU_UINT64_C(0xcc5fc196, fefd7d0c), -1037, -293},
+  {GRISU_UINT64_C(0xb5854744, 8ffffb2e), -987, -278},
+  {GRISU_UINT64_C(0xa139029f, 6a239f72), -937, -263},
+  {GRISU_UINT64_C(0x8f31cc09, 37ae58d3), -887, -248},
+  {GRISU_UINT64_C(0xfe5d5415, 0b090b03), -838, -233},
+  {GRISU_UINT64_C(0xe1ebce4d, c7f16dfc), -788, -218},
+  {GRISU_UINT64_C(0xc8a883c0, fdaf7df0), -738, -203},
+  {GRISU_UINT64_C(0xb23867fb, 2a35b28e), -688, -188},
+  {GRISU_UINT64_C(0x9e4a9cec, 15763e2f), -638, -173},
+  {GRISU_UINT64_C(0x8c974f73, 83725573), -588, -158},
+  {GRISU_UINT64_C(0xf9bd690a, 1b68637b), -539, -143},
+  {GRISU_UINT64_C(0xddd0467c, 64bce4a1), -489, -128},
+  {GRISU_UINT64_C(0xc5029163, f384a931), -439, -113},
+  {GRISU_UINT64_C(0xaefae514, 77a06b04), -389, -98},
+  {GRISU_UINT64_C(0x9b69dbe1, b548ce7d), -339, -83},
+  {GRISU_UINT64_C(0x8a08f0f8, bf0f156b), -289, -68},
+  {GRISU_UINT64_C(0xf5330471, 4d9265e0), -240, -53},
+  {GRISU_UINT64_C(0xd9c7dced, 53c72256), -190, -38},
+  {GRISU_UINT64_C(0xc16d9a00, 95928a27), -140, -23},
+  {GRISU_UINT64_C(0xabcc7711, 8461cefd), -90, -8},
+  {GRISU_UINT64_C(0x98968000, 00000000), -40, 7},
+  {GRISU_UINT64_C(0x87867832, 6eac9000), 10, 22},
+  {GRISU_UINT64_C(0xf0bdc21a, bb48db20), 59, 37},
+  {GRISU_UINT64_C(0xd5d238a4, abe98068), 109, 52},
+  {GRISU_UINT64_C(0xbde94e8e, 43d0c8ec), 159, 67},
+  {GRISU_UINT64_C(0xa8acd7c0, 222311bd), 209, 82},
+  {GRISU_UINT64_C(0x95d04aee, 3b80ece6), 259, 97},
+  {GRISU_UINT64_C(0x850fadc0, 9923329e), 309, 112},
+  {GRISU_UINT64_C(0xec5d3fa8, ce427b00), 358, 127},
+  {GRISU_UINT64_C(0xd1ef0244, af2364ff), 408, 142},
+  {GRISU_UINT64_C(0xba756174, 393d88e0), 458, 157},
+  {GRISU_UINT64_C(0xa59bc234, db398c25), 508, 172},
+  {GRISU_UINT64_C(0x9316ff75, dd87cbd8), 558, 187},
+  {GRISU_UINT64_C(0x82a45b45, 0226b39d), 608, 202},
+  {GRISU_UINT64_C(0xe8111c87, c5c1ba9a), 657, 217},
+  {GRISU_UINT64_C(0xce1de406, 42e3f4b9), 707, 232},
+  {GRISU_UINT64_C(0xb7118682, dbb66a77), 757, 247},
+  {GRISU_UINT64_C(0xa298f2c5, 01f45f43), 807, 262},
+  {GRISU_UINT64_C(0x906a617d, 450187e2), 857, 277},
+  {GRISU_UINT64_C(0x80444b5e, 7aa7cf85), 907, 292},
+  {GRISU_UINT64_C(0xe3d8f9e5, 63a198e5), 956, 307},
+  {GRISU_UINT64_C(0xca5e89b1, 8b602368), 1006, 322},
+  {GRISU_UINT64_C(0xb3bd72ed, 2af29e20), 1056, 337},
+  };
+static const int GRISU_CACHE_MAX_DISTANCE(15) = 50;
+// nb elements (15): 44
+static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(16)[] = {
+  {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308},
+  {GRISU_UINT64_C(0xff77b1fc, bebcdc4f), -1034, -292},
+  {GRISU_UINT64_C(0x8dd01fad, 907ffc3c), -980, -276},
+  {GRISU_UINT64_C(0x9d71ac8f, ada6c9b5), -927, -260},
+  {GRISU_UINT64_C(0xaecc4991, 4078536d), -874, -244},
+  {GRISU_UINT64_C(0xc2109436, 4dfb5637), -821, -228},
+  {GRISU_UINT64_C(0xd77485cb, 25823ac7), -768, -212},
+  {GRISU_UINT64_C(0xef340a98, 172aace5), -715, -196},
+  {GRISU_UINT64_C(0x84c8d4df, d2c63f3b), -661, -180},
+  {GRISU_UINT64_C(0x936b9fce, bb25c996), -608, -164},
+  {GRISU_UINT64_C(0xa3ab6658, 0d5fdaf6), -555, -148},
+  {GRISU_UINT64_C(0xb5b5ada8, aaff80b8), -502, -132},
+  {GRISU_UINT64_C(0xc9bcff60, 34c13053), -449, -116},
+  {GRISU_UINT64_C(0xdff97724, 70297ebd), -396, -100},
+  {GRISU_UINT64_C(0xf8a95fcf, 88747d94), -343, -84},
+  {GRISU_UINT64_C(0x8a08f0f8, bf0f156b), -289, -68},
+  {GRISU_UINT64_C(0x993fe2c6, d07b7fac), -236, -52},
+  {GRISU_UINT64_C(0xaa242499, 697392d3), -183, -36},
+  {GRISU_UINT64_C(0xbce50864, 92111aeb), -130, -20},
+  {GRISU_UINT64_C(0xd1b71758, e219652c), -77, -4},
+  {GRISU_UINT64_C(0xe8d4a510, 00000000), -24, 12},
+  {GRISU_UINT64_C(0x813f3978, f8940984), 30, 28},
+  {GRISU_UINT64_C(0x8f7e32ce, 7bea5c70), 83, 44},
+  {GRISU_UINT64_C(0x9f4f2726, 179a2245), 136, 60},
+  {GRISU_UINT64_C(0xb0de6538, 8cc8ada8), 189, 76},
+  {GRISU_UINT64_C(0xc45d1df9, 42711d9a), 242, 92},
+  {GRISU_UINT64_C(0xda01ee64, 1a708dea), 295, 108},
+  {GRISU_UINT64_C(0xf209787b, b47d6b85), 348, 124},
+  {GRISU_UINT64_C(0x865b8692, 5b9bc5c2), 402, 140},
+  {GRISU_UINT64_C(0x952ab45c, fa97a0b3), 455, 156},
+  {GRISU_UINT64_C(0xa59bc234, db398c25), 508, 172},
+  {GRISU_UINT64_C(0xb7dcbf53, 54e9bece), 561, 188},
+  {GRISU_UINT64_C(0xcc20ce9b, d35c78a5), 614, 204},
+  {GRISU_UINT64_C(0xe2a0b5dc, 971f303a), 667, 220},
+  {GRISU_UINT64_C(0xfb9b7cd9, a4a7443c), 720, 236},
+  {GRISU_UINT64_C(0x8bab8eef, b6409c1a), 774, 252},
+  {GRISU_UINT64_C(0x9b10a4e5, e9913129), 827, 268},
+  {GRISU_UINT64_C(0xac2820d9, 623bf429), 880, 284},
+  {GRISU_UINT64_C(0xbf21e440, 03acdd2d), 933, 300},
+  {GRISU_UINT64_C(0xd433179d, 9c8cb841), 986, 316},
+  {GRISU_UINT64_C(0xeb96bf6e, badf77d9), 1039, 332},
+  };
+static const int GRISU_CACHE_MAX_DISTANCE(16) = 54;
+// nb elements (16): 41
+static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(17)[] = {
+  {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308},
+  {GRISU_UINT64_C(0x9faacf3d, f73609b1), -1030, -291},
+  {GRISU_UINT64_C(0xdd95317f, 31c7fa1d), -974, -274},
+  {GRISU_UINT64_C(0x99c10284, 4f94e0fb), -917, -257},
+  {GRISU_UINT64_C(0xd5605fcd, cf32e1d7), -861, -240},
+  {GRISU_UINT64_C(0x940f4613, ae5ed137), -804, -223},
+  {GRISU_UINT64_C(0xcd795be8, 70516656), -748, -206},
+  {GRISU_UINT64_C(0x8e938662, 882af53e), -691, -189},
+  {GRISU_UINT64_C(0xc5dd4427, 1ad3cdba), -635, -172},
+  {GRISU_UINT64_C(0x894bc396, ce5da772), -578, -155},
+  {GRISU_UINT64_C(0xbe895233, 86091466), -522, -138},
+  {GRISU_UINT64_C(0x843610cb, 4bf160cc), -465, -121},
+  {GRISU_UINT64_C(0xb77ada06, 17e3bbcb), -409, -104},
+  {GRISU_UINT64_C(0xfea126b7, d78186bd), -353, -87},
+  {GRISU_UINT64_C(0xb0af48ec, 79ace837), -296, -70},
+  {GRISU_UINT64_C(0xf5330471, 4d9265e0), -240, -53},
+  {GRISU_UINT64_C(0xaa242499, 697392d3), -183, -36},
+  {GRISU_UINT64_C(0xec1e4a7d, b69561a5), -127, -19},
+  {GRISU_UINT64_C(0xa3d70a3d, 70a3d70a), -70, -2},
+  {GRISU_UINT64_C(0xe35fa931, a0000000), -14, 15},
+  {GRISU_UINT64_C(0x9dc5ada8, 2b70b59e), 43, 32},
+  {GRISU_UINT64_C(0xdaf3f046, 51d47b4c), 99, 49},
+  {GRISU_UINT64_C(0x97edd871, cfda3a57), 156, 66},
+  {GRISU_UINT64_C(0xd2d80db0, 2aabd62c), 212, 83},
+  {GRISU_UINT64_C(0x924d692c, a61be758), 269, 100},
+  {GRISU_UINT64_C(0xcb090c80, 01ab551c), 325, 117},
+  {GRISU_UINT64_C(0x8ce2529e, 2734bb1d), 382, 134},
+  {GRISU_UINT64_C(0xc38413cf, 25e2d70e), 438, 151},
+  {GRISU_UINT64_C(0x87aa9aff, 79042287), 495, 168},
+  {GRISU_UINT64_C(0xbc4665b5, 96706115), 551, 185},
+  {GRISU_UINT64_C(0x82a45b45, 0226b39d), 608, 202},
+  {GRISU_UINT64_C(0xb54d5e4a, 127f59c8), 664, 219},
+  {GRISU_UINT64_C(0xfb9b7cd9, a4a7443c), 720, 236},
+  {GRISU_UINT64_C(0xae9672ab, a3d0c321), 777, 253},
+  {GRISU_UINT64_C(0xf24a01a7, 3cf2dcd0), 833, 270},
+  {GRISU_UINT64_C(0xa81f3014, 49ee8c70), 890, 287},
+  {GRISU_UINT64_C(0xe950df20, 247c83fd), 946, 304},
+  {GRISU_UINT64_C(0xa1e53af4, 6f801c53), 1003, 321},
+  {GRISU_UINT64_C(0xe0accfa8, 75af45a8), 1059, 338},
+  };
+static const int GRISU_CACHE_MAX_DISTANCE(17) = 57;
+// nb elements (17): 39
+static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(18)[] = {
+  {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308},
+  {GRISU_UINT64_C(0xc795830d, 75038c1e), -1027, -290},
+  {GRISU_UINT64_C(0xad1c8eab, 5ee43b67), -967, -272},
+  {GRISU_UINT64_C(0x96267c75, 35b763b5), -907, -254},
+  {GRISU_UINT64_C(0x823c1279, 5db6ce57), -847, -236},
+  {GRISU_UINT64_C(0xe1ebce4d, c7f16dfc), -788, -218},
+  {GRISU_UINT64_C(0xc3f490aa, 77bd60fd), -728, -200},
+  {GRISU_UINT64_C(0xa9f6d30a, 038d1dbc), -668, -182},
+  {GRISU_UINT64_C(0x936b9fce, bb25c996), -608, -164},
+  {GRISU_UINT64_C(0xffbbcfe9, 94e5c620), -549, -146},
+  {GRISU_UINT64_C(0xddd0467c, 64bce4a1), -489, -128},
+  {GRISU_UINT64_C(0xc06481fb, 9bcf8d3a), -429, -110},
+  {GRISU_UINT64_C(0xa6dfbd9f, b8e5b88f), -369, -92},
+  {GRISU_UINT64_C(0x90bd77f3, 483bb9ba), -309, -74},
+  {GRISU_UINT64_C(0xfb158592, be068d2f), -250, -56},
+  {GRISU_UINT64_C(0xd9c7dced, 53c72256), -190, -38},
+  {GRISU_UINT64_C(0xbce50864, 92111aeb), -130, -20},
+  {GRISU_UINT64_C(0xa3d70a3d, 70a3d70a), -70, -2},
+  {GRISU_UINT64_C(0x8e1bc9bf, 04000000), -10, 16},
+  {GRISU_UINT64_C(0xf684df56, c3e01bc7), 49, 34},
+  {GRISU_UINT64_C(0xd5d238a4, abe98068), 109, 52},
+  {GRISU_UINT64_C(0xb975d6b6, ee39e437), 169, 70},
+  {GRISU_UINT64_C(0xa0dc75f1, 778e39d6), 229, 88},
+  {GRISU_UINT64_C(0x8b865b21, 5899f46d), 289, 106},
+  {GRISU_UINT64_C(0xf209787b, b47d6b85), 348, 124},
+  {GRISU_UINT64_C(0xd1ef0244, af2364ff), 408, 142},
+  {GRISU_UINT64_C(0xb616a12b, 7fe617aa), 468, 160},
+  {GRISU_UINT64_C(0x9defbf01, b061adab), 528, 178},
+  {GRISU_UINT64_C(0x88fcf317, f22241e2), 588, 196},
+  {GRISU_UINT64_C(0xeda2ee1c, 7064130c), 647, 214},
+  {GRISU_UINT64_C(0xce1de406, 42e3f4b9), 707, 232},
+  {GRISU_UINT64_C(0xb2c71d5b, ca9023f8), 767, 250},
+  {GRISU_UINT64_C(0x9b10a4e5, e9913129), 827, 268},
+  {GRISU_UINT64_C(0x867f59a9, d4bed6c0), 887, 286},
+  {GRISU_UINT64_C(0xe950df20, 247c83fd), 946, 304},
+  {GRISU_UINT64_C(0xca5e89b1, 8b602368), 1006, 322},
+  {GRISU_UINT64_C(0xaf87023b, 9bf0ee6b), 1066, 340},
+  };
+static const int GRISU_CACHE_MAX_DISTANCE(18) = 60;
+// nb elements (18): 37
+static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(19)[] = {
+  {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308},
+  {GRISU_UINT64_C(0xf97ae3d0, d2446f25), -1024, -289},
+  {GRISU_UINT64_C(0x873e4f75, e2224e68), -960, -270},
+  {GRISU_UINT64_C(0x92a1958a, 7675175f), -897, -251},
+  {GRISU_UINT64_C(0x9efa548d, 26e5a6e2), -834, -232},
+  {GRISU_UINT64_C(0xac5d37d5, b79b6239), -771, -213},
+  {GRISU_UINT64_C(0xbae0a846, d2195713), -708, -194},
+  {GRISU_UINT64_C(0xca9cf1d2, 06fdc03c), -645, -175},
+  {GRISU_UINT64_C(0xdbac6c24, 7d62a584), -582, -156},
+  {GRISU_UINT64_C(0xee2ba6c0, 678b597f), -519, -137},
+  {GRISU_UINT64_C(0x811ccc66, 8829b887), -455, -118},
+  {GRISU_UINT64_C(0x8bfbea76, c619ef36), -392, -99},
+  {GRISU_UINT64_C(0x97c560ba, 6b0919a6), -329, -80},
+  {GRISU_UINT64_C(0xa48ceaaa, b75a8e2b), -266, -61},
+  {GRISU_UINT64_C(0xb267ed19, 40f1c61c), -203, -42},
+  {GRISU_UINT64_C(0xc16d9a00, 95928a27), -140, -23},
+  {GRISU_UINT64_C(0xd1b71758, e219652c), -77, -4},
+  {GRISU_UINT64_C(0xe35fa931, a0000000), -14, 15},
+  {GRISU_UINT64_C(0xf684df56, c3e01bc7), 49, 34},
+  {GRISU_UINT64_C(0x85a36366, eb71f041), 113, 53},
+  {GRISU_UINT64_C(0x90e40fbe, ea1d3a4b), 176, 72},
+  {GRISU_UINT64_C(0x9d174b2d, cec0e47b), 239, 91},
+  {GRISU_UINT64_C(0xaa51823e, 34a7eedf), 302, 110},
+  {GRISU_UINT64_C(0xb8a8d9bb, e123f018), 365, 129},
+  {GRISU_UINT64_C(0xc83553c5, c8965d3d), 428, 148},
+  {GRISU_UINT64_C(0xd910f7ff, 28069da4), 491, 167},
+  {GRISU_UINT64_C(0xeb57ff22, fc0c795a), 554, 186},
+  {GRISU_UINT64_C(0xff290242, c83396ce), 617, 205},
+  {GRISU_UINT64_C(0x8a5296ff, e33cc930), 681, 224},
+  {GRISU_UINT64_C(0x95f83d0a, 1fb69cd9), 744, 243},
+  {GRISU_UINT64_C(0xa298f2c5, 01f45f43), 807, 262},
+  {GRISU_UINT64_C(0xb049dc01, 6abc5e60), 870, 281},
+  {GRISU_UINT64_C(0xbf21e440, 03acdd2d), 933, 300},
+  {GRISU_UINT64_C(0xcf39e50f, eae16bf0), 996, 319},
+  {GRISU_UINT64_C(0xe0accfa8, 75af45a8), 1059, 338},
+  };
+static const int GRISU_CACHE_MAX_DISTANCE(19) = 64;
+// nb elements (19): 35
+static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(20)[] = {
+  {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308},
+  {GRISU_UINT64_C(0x9becce62, 836ac577), -1020, -288},
+  {GRISU_UINT64_C(0xd3515c28, 31559a83), -954, -268},
+  {GRISU_UINT64_C(0x8f31cc09, 37ae58d3), -887, -248},
+  {GRISU_UINT64_C(0xc2109436, 4dfb5637), -821, -228},
+  {GRISU_UINT64_C(0x8380dea9, 3da4bc60), -754, -208},
+  {GRISU_UINT64_C(0xb23867fb, 2a35b28e), -688, -188},
+  {GRISU_UINT64_C(0xf18899b1, bc3f8ca2), -622, -168},
+  {GRISU_UINT64_C(0xa3ab6658, 0d5fdaf6), -555, -148},
+  {GRISU_UINT64_C(0xddd0467c, 64bce4a1), -489, -128},
+  {GRISU_UINT64_C(0x964e858c, 91ba2655), -422, -108},
+  {GRISU_UINT64_C(0xcbb41ef9, 79346bca), -356, -88},
+  {GRISU_UINT64_C(0x8a08f0f8, bf0f156b), -289, -68},
+  {GRISU_UINT64_C(0xbb127c53, b17ec159), -223, -48},
+  {GRISU_UINT64_C(0xfd87b5f2, 8300ca0e), -157, -28},
+  {GRISU_UINT64_C(0xabcc7711, 8461cefd), -90, -8},
+  {GRISU_UINT64_C(0xe8d4a510, 00000000), -24, 12},
+  {GRISU_UINT64_C(0x9dc5ada8, 2b70b59e), 43, 32},
+  {GRISU_UINT64_C(0xd5d238a4, abe98068), 109, 52},
+  {GRISU_UINT64_C(0x90e40fbe, ea1d3a4b), 176, 72},
+  {GRISU_UINT64_C(0xc45d1df9, 42711d9a), 242, 92},
+  {GRISU_UINT64_C(0x850fadc0, 9923329e), 309, 112},
+  {GRISU_UINT64_C(0xb454e4a1, 79dd1877), 375, 132},
+  {GRISU_UINT64_C(0xf46518c2, ef5b8cd1), 441, 152},
+  {GRISU_UINT64_C(0xa59bc234, db398c25), 508, 172},
+  {GRISU_UINT64_C(0xe070f78d, 3927556b), 574, 192},
+  {GRISU_UINT64_C(0x98165af3, 7b2153df), 641, 212},
+  {GRISU_UINT64_C(0xce1de406, 42e3f4b9), 707, 232},
+  {GRISU_UINT64_C(0x8bab8eef, b6409c1a), 774, 252},
+  {GRISU_UINT64_C(0xbd49d14a, a79dbc82), 840, 272},
+  {GRISU_UINT64_C(0x80444b5e, 7aa7cf85), 907, 292},
+  {GRISU_UINT64_C(0xadd57a27, d29339f6), 973, 312},
+  {GRISU_UINT64_C(0xeb96bf6e, badf77d9), 1039, 332},
+  };
+static const int GRISU_CACHE_MAX_DISTANCE(20) = 67;
+// nb elements (20): 33
+static const int GRISU_CACHE_OFFSET = 308;
diff --git a/src/regexp-delay.js b/src/regexp-delay.js
index 843d0aa..3031799 100644
--- a/src/regexp-delay.js
+++ b/src/regexp-delay.js
@@ -95,6 +95,16 @@
     %IgnoreAttributesAndSetProperty(object, 'ignoreCase', ignoreCase);
     %IgnoreAttributesAndSetProperty(object, 'multiline', multiline);
     %IgnoreAttributesAndSetProperty(object, 'lastIndex', 0);
+    // Clear the regexp result cache.
+    cachedRegexp = 0;
+    cachedSubject = 0;
+    cachedLastIndex = 0;
+    cachedAnswer = 0;
+    // These are from string.js.
+    cachedReplaceSubject = 0;
+    cachedReplaceRegexp = 0;
+    cachedReplaceReplacement = 0;
+    cachedReplaceAnswer = 0;
   }
 
   // Call internal function to compile the pattern.
@@ -140,7 +150,36 @@
 }
 
 
+var cachedRegexp;
+var cachedSubject;
+var cachedLastIndex;
+var cachedAnswer;
+
+
+function CloneRegexpAnswer(array) {
+  var len = array.length;
+  var answer = new $Array(len);
+  for (var i = 0; i < len; i++) {
+    answer[i] = array[i];
+  }
+  answer.index = array.index;
+  answer.input = array.input;
+  return answer;
+}
+
+
 function RegExpExec(string) {
+  if (%_ObjectEquals(cachedLastIndex, this.lastIndex) &&
+      %_ObjectEquals(cachedRegexp, this) &&
+      %_ObjectEquals(cachedSubject, string)) {
+    var last = cachedAnswer;
+    if (last == null) {
+      return last;
+    } else {
+      return CloneRegexpAnswer(last);
+    }
+  }
+
   if (!IS_REGEXP(this)) {
     throw MakeTypeError('incompatible_method_receiver',
                         ['RegExp.prototype.exec', this]);
@@ -159,6 +198,7 @@
     s = ToString(string);
   }
   var lastIndex = this.lastIndex;
+
   var i = this.global ? TO_INTEGER(lastIndex) : 0;
 
   if (i < 0 || i > s.length) {
@@ -172,7 +212,11 @@
 
   if (matchIndices == null) {
     if (this.global) this.lastIndex = 0;
-    return matchIndices; // no match
+    cachedLastIndex = lastIndex;
+    cachedRegexp = this;
+    cachedSubject = s;
+    cachedAnswer = matchIndices;  // Null.
+    return matchIndices;        // No match.
   }
 
   var numResults = NUMBER_OF_CAPTURES(lastMatchInfo) >> 1;
@@ -196,11 +240,18 @@
     }
   }
 
-  if (this.global)
-    this.lastIndex = lastMatchInfo[CAPTURE1];
   result.index = lastMatchInfo[CAPTURE0];
   result.input = s;
-  return result;
+  if (this.global) {
+    this.lastIndex = lastMatchInfo[CAPTURE1];
+    return result;
+  } else {
+    cachedRegexp = this;
+    cachedSubject = s;
+    cachedLastIndex = lastIndex;
+    cachedAnswer = result;
+    return CloneRegexpAnswer(result);
+  }
 }
 
 
diff --git a/src/runtime.cc b/src/runtime.cc
index 6d3a158..61534d3 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -32,6 +32,7 @@
 #include "accessors.h"
 #include "api.h"
 #include "arguments.h"
+#include "codegen.h"
 #include "compiler.h"
 #include "cpu.h"
 #include "dateparser-inl.h"
@@ -247,7 +248,8 @@
 
 static Handle<Object> CreateObjectLiteralBoilerplate(
     Handle<FixedArray> literals,
-    Handle<FixedArray> constant_properties) {
+    Handle<FixedArray> constant_properties,
+    bool should_have_fast_elements) {
   // Get the global context from the literals array.  This is the
   // context in which the function was created and we use the object
   // function from this context to create the object literal.  We do
@@ -263,6 +265,10 @@
                                             &is_result_from_cache);
 
   Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
+
+  // Normalize the elements of the boilerplate to save space if needed.
+  if (!should_have_fast_elements) NormalizeElements(boilerplate);
+
   {  // Add the constant properties to the boilerplate.
     int length = constant_properties->length();
     OptimizedObjectForAddingMultipleProperties opt(boilerplate,
@@ -344,8 +350,10 @@
     Handle<FixedArray> array) {
   Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
   switch (CompileTimeValue::GetType(array)) {
-    case CompileTimeValue::OBJECT_LITERAL:
-      return CreateObjectLiteralBoilerplate(literals, elements);
+    case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
+      return CreateObjectLiteralBoilerplate(literals, elements, true);
+    case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
+      return CreateObjectLiteralBoilerplate(literals, elements, false);
     case CompileTimeValue::ARRAY_LITERAL:
       return CreateArrayLiteralBoilerplate(literals, elements);
     default:
@@ -355,26 +363,6 @@
 }
 
 
-static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) {
-  HandleScope scope;
-  ASSERT(args.length() == 3);
-  // Copy the arguments.
-  CONVERT_ARG_CHECKED(FixedArray, literals, 0);
-  CONVERT_SMI_CHECKED(literals_index, args[1]);
-  CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
-
-  Handle<Object> result =
-    CreateObjectLiteralBoilerplate(literals, constant_properties);
-
-  if (result.is_null()) return Failure::Exception();
-
-  // Update the functions literal and return the boilerplate.
-  literals->set(literals_index, *result);
-
-  return *result;
-}
-
-
 static Object* Runtime_CreateArrayLiteralBoilerplate(Arguments args) {
   // Takes a FixedArray of elements containing the literal elements of
   // the array literal and produces JSArray with those elements.
@@ -398,15 +386,19 @@
 
 static Object* Runtime_CreateObjectLiteral(Arguments args) {
   HandleScope scope;
-  ASSERT(args.length() == 3);
+  ASSERT(args.length() == 4);
   CONVERT_ARG_CHECKED(FixedArray, literals, 0);
   CONVERT_SMI_CHECKED(literals_index, args[1]);
   CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
+  CONVERT_SMI_CHECKED(fast_elements, args[3]);
+  bool should_have_fast_elements = fast_elements == 1;
 
   // Check if boilerplate exists. If not, create it first.
   Handle<Object> boilerplate(literals->get(literals_index));
   if (*boilerplate == Heap::undefined_value()) {
-    boilerplate = CreateObjectLiteralBoilerplate(literals, constant_properties);
+    boilerplate = CreateObjectLiteralBoilerplate(literals,
+                                                 constant_properties,
+                                                 should_have_fast_elements);
     if (boilerplate.is_null()) return Failure::Exception();
     // Update the functions literal and return the boilerplate.
     literals->set(literals_index, *boilerplate);
@@ -417,15 +409,19 @@
 
 static Object* Runtime_CreateObjectLiteralShallow(Arguments args) {
   HandleScope scope;
-  ASSERT(args.length() == 3);
+  ASSERT(args.length() == 4);
   CONVERT_ARG_CHECKED(FixedArray, literals, 0);
   CONVERT_SMI_CHECKED(literals_index, args[1]);
   CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
+  CONVERT_SMI_CHECKED(fast_elements, args[3]);
+  bool should_have_fast_elements = fast_elements == 1;
 
   // Check if boilerplate exists. If not, create it first.
   Handle<Object> boilerplate(literals->get(literals_index));
   if (*boilerplate == Heap::undefined_value()) {
-    boilerplate = CreateObjectLiteralBoilerplate(literals, constant_properties);
+    boilerplate = CreateObjectLiteralBoilerplate(literals,
+                                                 constant_properties,
+                                                 should_have_fast_elements);
     if (boilerplate.is_null()) return Failure::Exception();
     // Update the functions literal and return the boilerplate.
     literals->set(literals_index, *boilerplate);
@@ -1242,6 +1238,70 @@
 }
 
 
+static void SetCustomCallGenerator(Handle<JSFunction> function,
+                                   CustomCallGenerator generator) {
+  if (function->shared()->function_data()->IsUndefined()) {
+    function->shared()->set_function_data(*FromCData(generator));
+  }
+}
+
+
+static Handle<JSFunction> InstallBuiltin(Handle<JSObject> holder,
+                                         const char* name,
+                                         Builtins::Name builtin_name,
+                                         CustomCallGenerator generator = NULL) {
+  Handle<String> key = Factory::LookupAsciiSymbol(name);
+  Handle<Code> code(Builtins::builtin(builtin_name));
+  Handle<JSFunction> optimized = Factory::NewFunction(key,
+                                                      JS_OBJECT_TYPE,
+                                                      JSObject::kHeaderSize,
+                                                      code,
+                                                      false);
+  optimized->shared()->DontAdaptArguments();
+  if (generator != NULL) {
+    SetCustomCallGenerator(optimized, generator);
+  }
+  SetProperty(holder, key, optimized, NONE);
+  return optimized;
+}
+
+
+static Object* CompileArrayPushCall(CallStubCompiler* compiler,
+                                    Object* object,
+                                    JSObject* holder,
+                                    JSFunction* function,
+                                    String* name,
+                                    StubCompiler::CheckType check) {
+  return compiler->CompileArrayPushCall(object, holder, function, name, check);
+}
+
+
+static Object* CompileArrayPopCall(CallStubCompiler* compiler,
+                                   Object* object,
+                                   JSObject* holder,
+                                   JSFunction* function,
+                                   String* name,
+                                   StubCompiler::CheckType check) {
+  return compiler->CompileArrayPopCall(object, holder, function, name, check);
+}
+
+
+static Object* Runtime_SpecialArrayFunctions(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 1);
+  CONVERT_ARG_CHECKED(JSObject, holder, 0);
+
+  InstallBuiltin(holder, "pop", Builtins::ArrayPop, CompileArrayPopCall);
+  InstallBuiltin(holder, "push", Builtins::ArrayPush, CompileArrayPushCall);
+  InstallBuiltin(holder, "shift", Builtins::ArrayShift);
+  InstallBuiltin(holder, "unshift", Builtins::ArrayUnshift);
+  InstallBuiltin(holder, "slice", Builtins::ArraySlice);
+  InstallBuiltin(holder, "splice", Builtins::ArraySplice);
+
+  return *holder;
+}
+
+
 static Object* Runtime_MaterializeRegExpLiteral(Arguments args) {
   HandleScope scope;
   ASSERT(args.length() == 4);
@@ -1376,10 +1436,8 @@
   ASSERT(args.length() == 1);
 
   CONVERT_CHECKED(JSFunction, f, args[0]);
-  // The function_data field of the shared function info is used exclusively by
-  // the API.
-  return !f->shared()->function_data()->IsUndefined() ? Heap::true_value()
-                                                      : Heap::false_value();
+  return f->shared()->IsApiFunction() ? Heap::true_value()
+                                      : Heap::false_value();
 }
 
 static Object* Runtime_FunctionIsBuiltin(Arguments args) {
@@ -4847,16 +4905,6 @@
 }
 
 
-static Object* Runtime_Math_abs(Arguments args) {
-  NoHandleAllocation ha;
-  ASSERT(args.length() == 1);
-  Counters::math_abs.Increment();
-
-  CONVERT_DOUBLE_CHECKED(x, args[0]);
-  return Heap::AllocateHeapNumber(fabs(x));
-}
-
-
 static Object* Runtime_Math_acos(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 1);
@@ -5090,14 +5138,7 @@
 }
 
 
-static Object* Runtime_DateMakeDay(Arguments args) {
-  NoHandleAllocation ha;
-  ASSERT(args.length() == 3);
-
-  CONVERT_SMI_CHECKED(year, args[0]);
-  CONVERT_SMI_CHECKED(month, args[1]);
-  CONVERT_SMI_CHECKED(date, args[2]);
-
+static int MakeDay(int year, int month, int day) {
   static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
                                        181, 212, 243, 273, 304, 334};
   static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
@@ -5119,7 +5160,7 @@
   //    ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
   //    Jan 1 1970. This is required so that we don't run into integer
   //    division of negative numbers.
-  // c) there shouldn't be overflow for 32-bit integers in the following
+  // c) there shouldn't be an overflow for 32-bit integers in the following
   //    operations.
   static const int year_delta = 399999;
   static const int base_day = 365 * (1970 + year_delta) +
@@ -5135,10 +5176,327 @@
                       base_day;
 
   if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
-    return Smi::FromInt(day_from_year + day_from_month[month] + date - 1);
+    return day_from_year + day_from_month[month] + day - 1;
   }
 
-  return Smi::FromInt(day_from_year + day_from_month_leap[month] + date - 1);
+  return day_from_year + day_from_month_leap[month] + day - 1;
+}
+
+
+static Object* Runtime_DateMakeDay(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 3);
+
+  CONVERT_SMI_CHECKED(year, args[0]);
+  CONVERT_SMI_CHECKED(month, args[1]);
+  CONVERT_SMI_CHECKED(date, args[2]);
+
+  return Smi::FromInt(MakeDay(year, month, date));
+}
+
+
+static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
+static const int kDaysIn4Years = 4 * 365 + 1;
+static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
+static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
+static const int kDays1970to2000 = 30 * 365 + 7;
+static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
+                               kDays1970to2000;
+static const int kYearsOffset = 400000;
+
+static const char kDayInYear[] = {
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30,
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+      22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
+
+static const char kMonthInYear[] = {
+      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      0, 0, 0, 0, 0, 0,
+      1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+      1, 1, 1,
+      2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+      2, 2, 2, 2, 2, 2,
+      3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+      3, 3, 3, 3, 3,
+      4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+      4, 4, 4, 4, 4, 4,
+      5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+      5, 5, 5, 5, 5,
+      6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+      6, 6, 6, 6, 6, 6,
+      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+      7, 7, 7, 7, 7, 7,
+      8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+      8, 8, 8, 8, 8,
+      9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+      9, 9, 9, 9, 9, 9,
+      10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+      10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+      11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+      11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+
+      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      0, 0, 0, 0, 0, 0,
+      1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+      1, 1, 1,
+      2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+      2, 2, 2, 2, 2, 2,
+      3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+      3, 3, 3, 3, 3,
+      4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+      4, 4, 4, 4, 4, 4,
+      5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+      5, 5, 5, 5, 5,
+      6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+      6, 6, 6, 6, 6, 6,
+      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+      7, 7, 7, 7, 7, 7,
+      8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+      8, 8, 8, 8, 8,
+      9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+      9, 9, 9, 9, 9, 9,
+      10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+      10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+      11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+      11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+
+      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      0, 0, 0, 0, 0, 0,
+      1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+      1, 1, 1, 1,
+      2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+      2, 2, 2, 2, 2, 2,
+      3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+      3, 3, 3, 3, 3,
+      4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+      4, 4, 4, 4, 4, 4,
+      5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+      5, 5, 5, 5, 5,
+      6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+      6, 6, 6, 6, 6, 6,
+      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+      7, 7, 7, 7, 7, 7,
+      8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+      8, 8, 8, 8, 8,
+      9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+      9, 9, 9, 9, 9, 9,
+      10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+      10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+      11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+      11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+
+      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      0, 0, 0, 0, 0, 0,
+      1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+      1, 1, 1,
+      2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+      2, 2, 2, 2, 2, 2,
+      3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+      3, 3, 3, 3, 3,
+      4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+      4, 4, 4, 4, 4, 4,
+      5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+      5, 5, 5, 5, 5,
+      6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+      6, 6, 6, 6, 6, 6,
+      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+      7, 7, 7, 7, 7, 7,
+      8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+      8, 8, 8, 8, 8,
+      9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+      9, 9, 9, 9, 9, 9,
+      10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+      10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+      11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+      11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
+
+
+// This function works for dates from 1970 to 2099.
+static inline void DateYMDFromTimeAfter1970(int date,
+                                            int &year, int &month, int &day) {
+#ifdef DEBUG
+  int save_date = date;  // Need this for ASSERT in the end.
+#endif
+
+  year = 1970 + (4 * date + 2) / kDaysIn4Years;
+  date %= kDaysIn4Years;
+
+  month = kMonthInYear[date];
+  day = kDayInYear[date];
+
+  ASSERT(MakeDay(year, month, day) == save_date);
+}
+
+
+static inline void DateYMDFromTimeSlow(int date,
+                                       int &year, int &month, int &day) {
+#ifdef DEBUG
+  int save_date = date;  // Need this for ASSERT in the end.
+#endif
+
+  date += kDaysOffset;
+  year = 400 * (date / kDaysIn400Years) - kYearsOffset;
+  date %= kDaysIn400Years;
+
+  ASSERT(MakeDay(year, 0, 1) + date == save_date);
+
+  date--;
+  int yd1 = date / kDaysIn100Years;
+  date %= kDaysIn100Years;
+  year += 100 * yd1;
+
+  date++;
+  int yd2 = date / kDaysIn4Years;
+  date %= kDaysIn4Years;
+  year += 4 * yd2;
+
+  date--;
+  int yd3 = date / 365;
+  date %= 365;
+  year += yd3;
+
+  bool is_leap = (!yd1 || yd2) && !yd3;
+
+  ASSERT(date >= -1);
+  ASSERT(is_leap || date >= 0);
+  ASSERT(date < 365 || is_leap && date < 366);
+  ASSERT(is_leap == (year % 4 == 0 && (year % 100 || (year % 400 == 0))));
+  ASSERT(is_leap || MakeDay(year, 0, 1) + date == save_date);
+  ASSERT(!is_leap || MakeDay(year, 0, 1) + date + 1 == save_date);
+
+  if (is_leap) {
+    day = kDayInYear[2*365 + 1 + date];
+    month = kMonthInYear[2*365 + 1 + date];
+  } else {
+    day = kDayInYear[date];
+    month = kMonthInYear[date];
+  }
+
+  ASSERT(MakeDay(year, month, day) == save_date);
+}
+
+
+static inline void DateYMDFromTime(int date,
+                                   int &year, int &month, int &day) {
+  if (date >= 0 && date < 32 * kDaysIn4Years) {
+    DateYMDFromTimeAfter1970(date, year, month, day);
+  } else {
+    DateYMDFromTimeSlow(date, year, month, day);
+  }
+}
+
+
+static Object* Runtime_DateYMDFromTime(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_DOUBLE_CHECKED(t, args[0]);
+  CONVERT_CHECKED(JSArray, res_array, args[1]);
+
+  int year, month, day;
+  DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
+
+  res_array->SetElement(0, Smi::FromInt(year));
+  res_array->SetElement(1, Smi::FromInt(month));
+  res_array->SetElement(2, Smi::FromInt(day));
+
+  return Heap::undefined_value();
 }
 
 
@@ -8675,18 +9033,28 @@
   HandleScope scope;
   Handle<JSArray> result = Factory::NewJSArray(0);
   int index = 0;
+  bool inline_runtime_functions = false;
 #define ADD_ENTRY(Name, argc, ressize)                                       \
   {                                                                          \
     HandleScope inner;                                                       \
-    Handle<String> name =                                                    \
-      Factory::NewStringFromAscii(                                           \
-          Vector<const char>(#Name, StrLength(#Name)));       \
+    Handle<String> name;                                                     \
+    /* Inline runtime functions have an underscore in front of the name. */  \
+    if (inline_runtime_functions) {                                          \
+      name = Factory::NewStringFromAscii(                                    \
+          Vector<const char>("_" #Name, StrLength("_" #Name)));              \
+    } else {                                                                 \
+      name = Factory::NewStringFromAscii(                                    \
+          Vector<const char>(#Name, StrLength(#Name)));                      \
+    }                                                                        \
     Handle<JSArray> pair = Factory::NewJSArray(0);                           \
     SetElement(pair, 0, name);                                               \
     SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc)));                    \
     SetElement(result, index++, pair);                                       \
   }
+  inline_runtime_functions = false;
   RUNTIME_FUNCTION_LIST(ADD_ENTRY)
+  inline_runtime_functions = true;
+  INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
 #undef ADD_ENTRY
   return *result;
 }
diff --git a/src/runtime.h b/src/runtime.h
index 8c2f86d..143f636 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -61,6 +61,7 @@
   F(ToFastProperties, 1, 1) \
   F(ToSlowProperties, 1, 1) \
   F(FinishArrayPrototypeSetup, 1, 1) \
+  F(SpecialArrayFunctions, 1, 1) \
   \
   F(IsInPrototypeChain, 2, 1) \
   F(SetHiddenPrototype, 2, 1) \
@@ -132,7 +133,6 @@
   F(StringCompare, 2, 1) \
   \
   /* Math */ \
-  F(Math_abs, 1, 1) \
   F(Math_acos, 1, 1) \
   F(Math_asin, 1, 1) \
   F(Math_atan, 1, 1) \
@@ -204,6 +204,7 @@
   F(DateLocalTimeOffset, 0, 1) \
   F(DateDaylightSavingsOffset, 1, 1) \
   F(DateMakeDay, 3, 1) \
+  F(DateYMDFromTime, 2, 1) \
   \
   /* Numbers */ \
   F(NumberIsFinite, 1, 1) \
@@ -234,11 +235,10 @@
   /* Literals */ \
   F(MaterializeRegExpLiteral, 4, 1)\
   F(CreateArrayLiteralBoilerplate, 3, 1) \
-  F(CreateObjectLiteralBoilerplate, 3, 1) \
   F(CloneLiteralBoilerplate, 1, 1) \
   F(CloneShallowLiteralBoilerplate, 1, 1) \
-  F(CreateObjectLiteral, 3, 1) \
-  F(CreateObjectLiteralShallow, 3, 1) \
+  F(CreateObjectLiteral, 4, 1) \
+  F(CreateObjectLiteralShallow, 4, 1) \
   F(CreateArrayLiteral, 3, 1) \
   F(CreateArrayLiteralShallow, 3, 1) \
   \
diff --git a/src/scopes.h b/src/scopes.h
index 9b506d9..c2354b2 100644
--- a/src/scopes.h
+++ b/src/scopes.h
@@ -277,7 +277,6 @@
   // The number of contexts between this and scope; zero if this == scope.
   int ContextChainLength(Scope* scope);
 
-
   // ---------------------------------------------------------------------------
   // Debugging.
 
diff --git a/src/string.js b/src/string.js
index 067578c..e22c93b 100644
--- a/src/string.js
+++ b/src/string.js
@@ -239,14 +239,29 @@
 }
 
 
+var cachedReplaceSubject;
+var cachedReplaceRegexp;
+var cachedReplaceReplacement;
+var cachedReplaceAnswer;
+
 // Helper function for regular expressions in String.prototype.replace.
 function StringReplaceRegExp(subject, regexp, replace) {
+  if (%_ObjectEquals(replace, cachedReplaceReplacement) &&
+      %_ObjectEquals(subject, cachedReplaceSubject) &&
+      %_ObjectEquals(regexp, cachedReplaceRegexp)) {
+    return cachedReplaceAnswer;
+  }
   replace = TO_STRING_INLINE(replace);
-  return %StringReplaceRegExpWithString(subject,
-                                        regexp,
-                                        replace,
-                                        lastMatchInfo);
-};
+  var answer = %StringReplaceRegExpWithString(subject,
+                                              regexp,
+                                              replace,
+                                              lastMatchInfo);
+  cachedReplaceSubject = subject;
+  cachedReplaceRegexp = regexp;
+  cachedReplaceReplacement = replace;
+  cachedReplaceAnswer = answer;
+  return answer;
+}
 
 
 // Expand the $-expressions in the string and return a new string with
@@ -387,43 +402,68 @@
   // Unfortunately, that means this code is nearly duplicated, here and in
   // jsregexp.cc.
   if (regexp.global) {
-    var numberOfCaptures = NUMBER_OF_CAPTURES(matchInfo) >> 1;
     var previous = 0;
-    do {
-      var startOfMatch = matchInfo[CAPTURE0];
-      result.addSpecialSlice(previous, startOfMatch);
-      previous = matchInfo[CAPTURE1];
-      if (numberOfCaptures == 1) {
+    var startOfMatch;
+    if (NUMBER_OF_CAPTURES(matchInfo) == 2) {
+      // Both branches contain essentially the same loop except for the call
+      // to the replace function. The branch is put outside of the loop for
+      // speed
+      do {
+        startOfMatch = matchInfo[CAPTURE0];
+        result.addSpecialSlice(previous, startOfMatch);
+        previous = matchInfo[CAPTURE1];
         var match = SubString(subject, startOfMatch, previous);
         // Don't call directly to avoid exposing the built-in global object.
         result.add(replace.call(null, match, startOfMatch, subject));
-      } else {
-        result.add(ApplyReplacementFunction(replace, matchInfo, subject));
-      }
-      // Can't use matchInfo any more from here, since the function could
-      // overwrite it.
-      // Continue with the next match.
-      // Increment previous if we matched an empty string, as per ECMA-262
-      // 15.5.4.10.
-      if (previous == startOfMatch) {
-        // Add the skipped character to the output, if any.
-        if (previous < subject.length) {
-          result.addSpecialSlice(previous, previous + 1);
+        // Can't use matchInfo any more from here, since the function could
+        // overwrite it.
+        // Continue with the next match.
+        // Increment previous if we matched an empty string, as per ECMA-262
+        // 15.5.4.10.
+        if (previous == startOfMatch) {
+          // Add the skipped character to the output, if any.
+          if (previous < subject.length) {
+            result.addSpecialSlice(previous, previous + 1);
+          }
+          previous++;
+          // Per ECMA-262 15.10.6.2, if the previous index is greater than the
+          // string length, there is no match
+          if (previous > subject.length) {
+            return result.generate();
+          }
         }
-        previous++;
-      }
-
-      // Per ECMA-262 15.10.6.2, if the previous index is greater than the
-      // string length, there is no match
-      matchInfo = (previous > subject.length)
-          ? null
-          : DoRegExpExec(regexp, subject, previous);
-    } while (!IS_NULL(matchInfo));
-
-    // Tack on the final right substring after the last match, if necessary.
-    if (previous < subject.length) {
-      result.addSpecialSlice(previous, subject.length);
+        matchInfo = DoRegExpExec(regexp, subject, previous);
+      } while (!IS_NULL(matchInfo));
+    } else {
+      do {
+        startOfMatch = matchInfo[CAPTURE0];
+        result.addSpecialSlice(previous, startOfMatch);
+        previous = matchInfo[CAPTURE1];
+        result.add(ApplyReplacementFunction(replace, matchInfo, subject));
+        // Can't use matchInfo any more from here, since the function could
+        // overwrite it.
+        // Continue with the next match.
+        // Increment previous if we matched an empty string, as per ECMA-262
+        // 15.5.4.10.
+        if (previous == startOfMatch) {
+          // Add the skipped character to the output, if any.
+          if (previous < subject.length) {
+            result.addSpecialSlice(previous, previous + 1);
+          }
+          previous++;
+          // Per ECMA-262 15.10.6.2, if the previous index is greater than the
+          // string length, there is no match
+          if (previous > subject.length) {
+            return result.generate();
+          }
+        }
+        matchInfo = DoRegExpExec(regexp, subject, previous);
+      } while (!IS_NULL(matchInfo));
     }
+
+    // Tack on the final right substring after the last match.
+    result.addSpecialSlice(previous, subject.length);
+
   } else { // Not a global regexp, no need to loop.
     result.addSpecialSlice(0, matchInfo[CAPTURE0]);
     var endOfMatch = matchInfo[CAPTURE1];
@@ -719,16 +759,26 @@
   return %StringTrim(TO_STRING_INLINE(this), false, true);
 }
 
+var static_charcode_array = new $Array(4);
+
 // ECMA-262, section 15.5.3.2
 function StringFromCharCode(code) {
   var n = %_ArgumentsLength();
-  if (n == 1) return %_CharFromCode(ToNumber(code) & 0xffff)
+  if (n == 1) {
+    if (!%_IsSmi(code)) code = ToNumber(code);
+    return %_CharFromCode(code & 0xffff);
+  }
 
   // NOTE: This is not super-efficient, but it is necessary because we
   // want to avoid converting to numbers from within the virtual
   // machine. Maybe we can find another way of doing this?
-  var codes = new $Array(n);
-  for (var i = 0; i < n; i++) codes[i] = ToNumber(%_Arguments(i));
+  var codes = static_charcode_array;
+  for (var i = 0; i < n; i++) {
+    var code = %_Arguments(i);
+    if (!%_IsSmi(code)) code = ToNumber(code);
+    codes[i] = code;
+  }
+  codes.length = n;
   return %StringFromCharCodeArray(codes);
 }
 
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index 577c2d7..c942d9d 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -435,14 +435,6 @@
                                     argc);
   Object* code = map->FindInCodeCache(name, flags);
   if (code->IsUndefined()) {
-    if (object->IsJSObject()) {
-      Object* opt =
-          Top::LookupSpecialFunction(JSObject::cast(object), holder, function);
-      if (opt->IsJSFunction()) {
-        check = StubCompiler::JSARRAY_HAS_FAST_ELEMENTS_CHECK;
-        function = JSFunction::cast(opt);
-      }
-    }
     // If the function hasn't been compiled yet, we cannot do it now
     // because it may cause GC. To avoid this issue, we return an
     // internal error which will make sure we do not update any
diff --git a/src/stub-cache.h b/src/stub-cache.h
index 43354db..0e986dd 100644
--- a/src/stub-cache.h
+++ b/src/stub-cache.h
@@ -326,8 +326,7 @@
     RECEIVER_MAP_CHECK,
     STRING_CHECK,
     NUMBER_CHECK,
-    BOOLEAN_CHECK,
-    JSARRAY_HAS_FAST_ELEMENTS_CHECK
+    BOOLEAN_CHECK
   };
 
   StubCompiler() : scope_(), masm_(NULL, 256), failure_(NULL) { }
@@ -549,7 +548,7 @@
 
 class CallStubCompiler: public StubCompiler {
  public:
-  explicit CallStubCompiler(int argc, InLoopFlag in_loop)
+  CallStubCompiler(int argc, InLoopFlag in_loop)
       : arguments_(argc), in_loop_(in_loop) { }
 
   Object* CompileCallField(JSObject* object,
@@ -570,6 +569,18 @@
                             JSFunction* function,
                             String* name);
 
+  Object* CompileArrayPushCall(Object* object,
+                               JSObject* holder,
+                               JSFunction* function,
+                               String* name,
+                               CheckType check);
+
+  Object* CompileArrayPopCall(Object* object,
+                              JSObject* holder,
+                              JSFunction* function,
+                              String* name,
+                              CheckType check);
+
  private:
   const ParameterCount arguments_;
   const InLoopFlag in_loop_;
@@ -591,6 +602,14 @@
 };
 
 
+typedef Object* (*CustomCallGenerator)(CallStubCompiler* compiler,
+                                       Object* object,
+                                       JSObject* holder,
+                                       JSFunction* function,
+                                       String* name,
+                                       StubCompiler::CheckType check);
+
+
 } }  // namespace v8::internal
 
 #endif  // V8_STUB_CACHE_H_
diff --git a/src/top.cc b/src/top.cc
index 7c8a1c9..3efd1fc 100644
--- a/src/top.cc
+++ b/src/top.cc
@@ -92,15 +92,15 @@
   v->VisitPointer(&(thread->pending_exception_));
   v->VisitPointer(&(thread->pending_message_obj_));
   v->VisitPointer(
-      bit_cast<Object**, Script**>(&(thread->pending_message_script_)));
-  v->VisitPointer(bit_cast<Object**, Context**>(&(thread->context_)));
+      BitCast<Object**, Script**>(&(thread->pending_message_script_)));
+  v->VisitPointer(BitCast<Object**, Context**>(&(thread->context_)));
   v->VisitPointer(&(thread->scheduled_exception_));
 
   for (v8::TryCatch* block = thread->TryCatchHandler();
        block != NULL;
        block = TRY_CATCH_FROM_ADDRESS(block->next_)) {
-    v->VisitPointer(bit_cast<Object**, void**>(&(block->exception_)));
-    v->VisitPointer(bit_cast<Object**, void**>(&(block->message_)));
+    v->VisitPointer(BitCast<Object**, void**>(&(block->exception_)));
+    v->VisitPointer(BitCast<Object**, void**>(&(block->message_)));
   }
 
   // Iterate over pointers on native execution stack.
@@ -439,10 +439,9 @@
 
   // Get the data object from access check info.
   JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
-  Object* info = constructor->shared()->function_data();
-  if (info == Heap::undefined_value()) return;
-
-  Object* data_obj = FunctionTemplateInfo::cast(info)->access_check_info();
+  if (!constructor->shared()->IsApiFunction()) return;
+  Object* data_obj =
+      constructor->shared()->get_api_func_data()->access_check_info();
   if (data_obj == Heap::undefined_value()) return;
 
   HandleScope scope;
@@ -502,10 +501,10 @@
 
   // Get named access check callback
   JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
-  Object* info = constructor->shared()->function_data();
-  if (info == Heap::undefined_value()) return false;
+  if (!constructor->shared()->IsApiFunction()) return false;
 
-  Object* data_obj = FunctionTemplateInfo::cast(info)->access_check_info();
+  Object* data_obj =
+     constructor->shared()->get_api_func_data()->access_check_info();
   if (data_obj == Heap::undefined_value()) return false;
 
   Object* fun_obj = AccessCheckInfo::cast(data_obj)->named_callback();
@@ -547,10 +546,10 @@
 
   // Get indexed access check callback
   JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
-  Object* info = constructor->shared()->function_data();
-  if (info == Heap::undefined_value()) return false;
+  if (!constructor->shared()->IsApiFunction()) return false;
 
-  Object* data_obj = FunctionTemplateInfo::cast(info)->access_check_info();
+  Object* data_obj =
+      constructor->shared()->get_api_func_data()->access_check_info();
   if (data_obj == Heap::undefined_value()) return false;
 
   Object* fun_obj = AccessCheckInfo::cast(data_obj)->indexed_callback();
@@ -950,27 +949,6 @@
 }
 
 
-bool Top::CanHaveSpecialFunctions(JSObject* object) {
-  return object->IsJSArray();
-}
-
-
-Object* Top::LookupSpecialFunction(JSObject* receiver,
-                                   JSObject* prototype,
-                                   JSFunction* function) {
-  if (CanHaveSpecialFunctions(receiver)) {
-    FixedArray* table = context()->global_context()->special_function_table();
-    for (int index = 0; index < table->length(); index +=3) {
-      if ((prototype == table->get(index)) &&
-          (function == table->get(index+1))) {
-        return table->get(index+2);
-      }
-    }
-  }
-  return Heap::undefined_value();
-}
-
-
 char* Top::ArchiveThread(char* to) {
   memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(thread_local_));
   InitializeThreadLocal();
diff --git a/src/top.h b/src/top.h
index ddc73ba..e20a2a0 100644
--- a/src/top.h
+++ b/src/top.h
@@ -342,11 +342,6 @@
     return Handle<JSBuiltinsObject>(thread_local_.context_->builtins());
   }
 
-  static bool CanHaveSpecialFunctions(JSObject* object);
-  static Object* LookupSpecialFunction(JSObject* receiver,
-                                       JSObject* prototype,
-                                       JSFunction* value);
-
   static void RegisterTryCatchHandler(v8::TryCatch* that);
   static void UnregisterTryCatchHandler(v8::TryCatch* that);
 
diff --git a/src/utils.h b/src/utils.h
index deab09f..3c8d873 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -29,6 +29,7 @@
 #define V8_UTILS_H_
 
 #include <stdlib.h>
+#include <string.h>
 
 namespace v8 {
 namespace internal {
@@ -396,7 +397,7 @@
     if (this == &rhs) return *this;
     Vector<T>::operator=(rhs);
     memcpy(buffer_, rhs.buffer_, sizeof(T) * kSize);
-    set_start(buffer_);
+    this->set_start(buffer_);
     return *this;
   }
 
@@ -599,6 +600,43 @@
 // Calculate 10^exponent.
 int TenToThe(int exponent);
 
+
+// The type-based aliasing rule allows the compiler to assume that pointers of
+// different types (for some definition of different) never alias each other.
+// Thus the following code does not work:
+//
+// float f = foo();
+// int fbits = *(int*)(&f);
+//
+// The compiler 'knows' that the int pointer can't refer to f since the types
+// don't match, so the compiler may cache f in a register, leaving random data
+// in fbits.  Using C++ style casts makes no difference, however a pointer to
+// char data is assumed to alias any other pointer.  This is the 'memcpy
+// exception'.
+//
+// Bit_cast uses the memcpy exception to move the bits from a variable of one
+// type of a variable of another type.  Of course the end result is likely to
+// be implementation dependent.  Most compilers (gcc-4.2 and MSVC 2005)
+// will completely optimize BitCast away.
+//
+// There is an additional use for BitCast.
+// Recent gccs will warn when they see casts that may result in breakage due to
+// the type-based aliasing rule.  If you have checked that there is no breakage
+// you can use BitCast to cast one pointer type to another.  This confuses gcc
+// enough that it can no longer see that you have cast one pointer type to
+// another thus avoiding the warning.
+template <class Dest, class Source>
+inline Dest BitCast(const Source& source) {
+  // Compile time assertion: sizeof(Dest) == sizeof(Source)
+  // A compile error here means your Dest and Source have different sizes.
+  typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1];
+
+  Dest dest;
+  memcpy(&dest, &source, sizeof(dest));
+  return dest;
+}
+
+
 } }  // namespace v8::internal
 
 #endif  // V8_UTILS_H_
diff --git a/src/v8-counters.h b/src/v8-counters.h
index 2b493fb..b595cd4 100644
--- a/src/v8-counters.h
+++ b/src/v8-counters.h
@@ -170,7 +170,6 @@
   SC(regexp_entry_native, V8.RegExpEntryNative)                       \
   SC(number_to_string_native, V8.NumberToStringNative)                \
   SC(number_to_string_runtime, V8.NumberToStringRuntime)              \
-  SC(math_abs, V8.MathAbs)                                            \
   SC(math_acos, V8.MathAcos)                                          \
   SC(math_asin, V8.MathAsin)                                          \
   SC(math_atan, V8.MathAtan)                                          \
diff --git a/src/version.cc b/src/version.cc
index 3562e1d..83382de 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,8 +34,8 @@
 // cannot be changed without changing the SCons build script.
 #define MAJOR_VERSION     2
 #define MINOR_VERSION     1
-#define BUILD_NUMBER      3
-#define PATCH_LEVEL       1
+#define BUILD_NUMBER      4
+#define PATCH_LEVEL       0
 #define CANDIDATE_VERSION false
 
 // Define SONAME to have the SCons build the put a specific SONAME into the
diff --git a/src/virtual-frame-inl.h b/src/virtual-frame-inl.h
index 9aa88fe..ff599d0 100644
--- a/src/virtual-frame-inl.h
+++ b/src/virtual-frame-inl.h
@@ -119,6 +119,12 @@
   return true;
 }
 
+
+void VirtualFrame::SetTypeForLocalAt(int index, NumberInfo info) {
+  elements_[local0_index() + index].set_number_info(info);
+}
+
+
 } }  // namespace v8::internal
 
 #endif  // V8_VIRTUAL_FRAME_INL_H_
diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
index b10c3f9..f5a8d3c 100644
--- a/src/x64/codegen-x64.cc
+++ b/src/x64/codegen-x64.cc
@@ -2424,11 +2424,13 @@
   frame_->Push(Smi::FromInt(node->literal_index()));
   // Constant properties.
   frame_->Push(node->constant_properties());
+  // Should the object literal have fast elements?
+  frame_->Push(Smi::FromInt(node->fast_elements() ? 1 : 0));
   Result clone;
   if (node->depth() > 1) {
-    clone = frame_->CallRuntime(Runtime::kCreateObjectLiteral, 3);
+    clone = frame_->CallRuntime(Runtime::kCreateObjectLiteral, 4);
   } else {
-    clone = frame_->CallRuntime(Runtime::kCreateObjectLiteralShallow, 3);
+    clone = frame_->CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
   }
   frame_->Push(&clone);
 
@@ -3600,7 +3602,7 @@
 }
 
 
-void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateArguments(ZoneList<Expression*>* args) {
   ASSERT(args->length() == 1);
 
   // ArgumentsAccessStub expects the key in rdx and the formal
diff --git a/src/x64/codegen-x64.h b/src/x64/codegen-x64.h
index 8f5fdc1..3256cb2 100644
--- a/src/x64/codegen-x64.h
+++ b/src/x64/codegen-x64.h
@@ -337,6 +337,10 @@
   bool in_spilled_code() const { return in_spilled_code_; }
   void set_in_spilled_code(bool flag) { in_spilled_code_ = flag; }
 
+  // If the name is an inline runtime function call return the number of
+  // expected arguments. Otherwise return -1.
+  static int InlineRuntimeCallArgumentsCount(Handle<String> name);
+
  private:
   // Construction/Destruction
   explicit CodeGenerator(MacroAssembler* masm);
@@ -506,6 +510,7 @@
   struct InlineRuntimeLUT {
     void (CodeGenerator::*method)(ZoneList<Expression*>*);
     const char* name;
+    int nargs;
   };
   static InlineRuntimeLUT* FindInlineRuntimeLUT(Handle<String> name);
   bool CheckForInlineRuntimeCall(CallRuntime* node);
@@ -537,7 +542,7 @@
 
   // Support for arguments.length and arguments[?].
   void GenerateArgumentsLength(ZoneList<Expression*>* args);
-  void GenerateArgumentsAccess(ZoneList<Expression*>* args);
+  void GenerateArguments(ZoneList<Expression*>* args);
 
   // Support for accessing the class and value fields of an object.
   void GenerateClassOf(ZoneList<Expression*>* args);
@@ -575,14 +580,10 @@
   // Fast support for number to string.
   void GenerateNumberToString(ZoneList<Expression*>* args);
 
-  // Fast support for Math.pow().
-  void GenerateMathPow(ZoneList<Expression*>* args);
-
   // Fast call to math functions.
+  void GenerateMathPow(ZoneList<Expression*>* args);
   void GenerateMathSin(ZoneList<Expression*>* args);
   void GenerateMathCos(ZoneList<Expression*>* args);
-
-  // Fast case for sqrt
   void GenerateMathSqrt(ZoneList<Expression*>* args);
 
 // Simple condition analysis.
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index bfa1a44..65f99a3 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -903,10 +903,11 @@
   __ push(FieldOperand(rdi, JSFunction::kLiteralsOffset));
   __ Push(Smi::FromInt(expr->literal_index()));
   __ Push(expr->constant_properties());
+  __ Push(Smi::FromInt(expr->fast_elements() ? 1 : 0));
   if (expr->depth() > 1) {
-    __ CallRuntime(Runtime::kCreateObjectLiteral, 3);
+    __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
   } else {
-    __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 3);
+    __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
   }
 
   // If result_saved is true the result is on top of the stack.  If
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index dca2780..a8e2fdf 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -197,9 +197,9 @@
   // avoid having the fast case for smis leave the registers
   // unchanged.
   if (FLAG_debug_code) {
-    movq(object, bit_cast<int64_t>(kZapValue), RelocInfo::NONE);
-    movq(value, bit_cast<int64_t>(kZapValue), RelocInfo::NONE);
-    movq(smi_index, bit_cast<int64_t>(kZapValue), RelocInfo::NONE);
+    movq(object, BitCast<int64_t>(kZapValue), RelocInfo::NONE);
+    movq(value, BitCast<int64_t>(kZapValue), RelocInfo::NONE);
+    movq(smi_index, BitCast<int64_t>(kZapValue), RelocInfo::NONE);
   }
 }
 
@@ -270,9 +270,9 @@
   // Clobber all input registers when running with the debug-code flag
   // turned on to provoke errors.
   if (FLAG_debug_code) {
-    movq(object, bit_cast<int64_t>(kZapValue), RelocInfo::NONE);
-    movq(scratch, bit_cast<int64_t>(kZapValue), RelocInfo::NONE);
-    movq(smi_index, bit_cast<int64_t>(kZapValue), RelocInfo::NONE);
+    movq(object, BitCast<int64_t>(kZapValue), RelocInfo::NONE);
+    movq(scratch, BitCast<int64_t>(kZapValue), RelocInfo::NONE);
+    movq(smi_index, BitCast<int64_t>(kZapValue), RelocInfo::NONE);
   }
 }
 
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index 5d73b5f..aa620fc 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -655,6 +655,118 @@
 #define __ ACCESS_MASM((masm()))
 
 
+Object* CallStubCompiler::CompileArrayPushCall(Object* object,
+                                               JSObject* holder,
+                                               JSFunction* function,
+                                               String* name,
+                                               CheckType check) {
+  // ----------- S t a t e -------------
+  // rcx                 : function name
+  // rsp[0]              : return address
+  // rsp[8]              : argument argc
+  // rsp[16]             : argument argc - 1
+  // ...
+  // rsp[argc * 8]       : argument 1
+  // rsp[(argc + 1) * 8] : argument 0 = receiver
+  // -----------------------------------
+
+  // TODO(639): faster implementation.
+  ASSERT(check == RECEIVER_MAP_CHECK);
+
+  Label miss;
+
+  // Get the receiver from the stack.
+  const int argc = arguments().immediate();
+  __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
+
+  // Check that the receiver isn't a smi.
+  __ JumpIfSmi(rdx, &miss);
+
+  // Check that the maps haven't changed.
+  CheckPrototypes(JSObject::cast(object), rdx, holder,
+                  rbx, rax, name, &miss);
+
+  // Patch the receiver on the stack with the global proxy if
+  // necessary.
+  if (object->IsGlobalObject()) {
+    __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
+    __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
+  }
+
+  __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush),
+                               argc + 1,
+                               1);
+
+  // Handle call cache miss.
+  __ bind(&miss);
+  Handle<Code> ic = ComputeCallMiss(arguments().immediate());
+  __ Jump(ic, RelocInfo::CODE_TARGET);
+
+  // Return the generated code.
+  String* function_name = NULL;
+  if (function->shared()->name()->IsString()) {
+    function_name = String::cast(function->shared()->name());
+  }
+  return GetCode(CONSTANT_FUNCTION, function_name);
+}
+
+
+Object* CallStubCompiler::CompileArrayPopCall(Object* object,
+                                              JSObject* holder,
+                                              JSFunction* function,
+                                              String* name,
+                                              CheckType check) {
+  // ----------- S t a t e -------------
+  // rcx                 : function name
+  // rsp[0]              : return address
+  // rsp[8]              : argument argc
+  // rsp[16]             : argument argc - 1
+  // ...
+  // rsp[argc * 8]       : argument 1
+  // rsp[(argc + 1) * 8] : argument 0 = receiver
+  // -----------------------------------
+
+  // TODO(642): faster implementation.
+  ASSERT(check == RECEIVER_MAP_CHECK);
+
+  Label miss;
+
+  // Get the receiver from the stack.
+  const int argc = arguments().immediate();
+  __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
+
+  // Check that the receiver isn't a smi.
+  __ JumpIfSmi(rdx, &miss);
+
+  // Check that the maps haven't changed.
+  CheckPrototypes(JSObject::cast(object), rdx, holder,
+                  rbx, rax, name, &miss);
+
+  // Patch the receiver on the stack with the global proxy if
+  // necessary.
+  if (object->IsGlobalObject()) {
+    __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
+    __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
+  }
+
+  __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop),
+                               argc + 1,
+                               1);
+
+  // Handle call cache miss.
+  __ bind(&miss);
+  Handle<Code> ic = ComputeCallMiss(arguments().immediate());
+  __ Jump(ic, RelocInfo::CODE_TARGET);
+
+  // Return the generated code.
+  String* function_name = NULL;
+  if (function->shared()->name()->IsString()) {
+    function_name = String::cast(function->shared()->name());
+  }
+  return GetCode(CONSTANT_FUNCTION, function_name);
+}
+
+
 Object* CallStubCompiler::CompileCallConstant(Object* object,
                                               JSObject* holder,
                                               JSFunction* function,
@@ -670,6 +782,13 @@
   // rsp[(argc + 1) * 8] : argument 0 = receiver
   // -----------------------------------
 
+  SharedFunctionInfo* function_info = function->shared();
+  if (function_info->HasCustomCallGenerator()) {
+    CustomCallGenerator generator =
+        ToCData<CustomCallGenerator>(function_info->function_data());
+    return generator(this, object, holder, function, name, check);
+  }
+
   Label miss;
 
   // Get the receiver from the stack.
@@ -759,18 +878,6 @@
       break;
     }
 
-    case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
-      CheckPrototypes(JSObject::cast(object), rdx, holder,
-                      rbx, rax, name, &miss);
-      // Make sure object->HasFastElements().
-      // Get the elements array of the object.
-      __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
-      // Check that the object is in fast mode (not dictionary).
-      __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset),
-             Factory::fixed_array_map());
-      __ j(not_equal, &miss);
-      break;
-
     default:
       UNREACHABLE();
   }
diff --git a/src/x64/virtual-frame-x64.h b/src/x64/virtual-frame-x64.h
index ddd606b..e93140e 100644
--- a/src/x64/virtual-frame-x64.h
+++ b/src/x64/virtual-frame-x64.h
@@ -416,6 +416,8 @@
   // the frame.  Nip(k) is equivalent to x = Pop(), Drop(k), Push(x).
   inline void Nip(int num_dropped);
 
+  inline void SetTypeForLocalAt(int index, NumberInfo info);
+
  private:
   static const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;
   static const int kFunctionOffset = JavaScriptFrameConstants::kFunctionOffset;