Merged r12434, r12435, r12440, r12441, r12443, r12444, r12445, r12446 into trunk branch.

Support register as right operand in min/max support.

Fixed test expectation.

Add build system infrastructure for ENABLE_EXTRA_CHECKS flag (not used yet)

Fix missing colon in common.gypi

Push stacktrace and die if the receiver is of unknown type.

Disable accessor inlining (due to broken deopts)

Add empty-handle checks to API functions (#ifdef ENABLE_EXTRA_CHECKS)

Check the return value of API calls on ia32 and x64.

R=yangguo@chromium.org

Review URL: https://chromiumcodereview.appspot.com/10910093

git-svn-id: http://v8.googlecode.com/svn/trunk@12448 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/Makefile b/Makefile
index 07549a3..7ebfc04 100644
--- a/Makefile
+++ b/Makefile
@@ -61,6 +61,13 @@
 ifeq ($(snapshot), off)
   GYPFLAGS += -Dv8_use_snapshot='false'
 endif
+# extrachecks=on/off
+ifeq ($(extrachecks), on)
+  GYPFLAGS += -Dv8_enable_extra_checks=1
+endif
+ifeq ($(extrachecks), off)
+  GYPFLAGS += -Dv8_enable_extra_checks=0
+endif
 # gdbjit=on
 ifeq ($(gdbjit), on)
   GYPFLAGS += -Dv8_enable_gdbjit=1
diff --git a/build/common.gypi b/build/common.gypi
index b8cd110..fdf4d9c 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -70,6 +70,9 @@
 
     'v8_enable_disassembler%': 0,
 
+    # Enable extra checks in API functions and other strategic places.
+    'v8_enable_extra_checks%': 1,
+
     'v8_object_print%': 0,
 
     'v8_enable_gdbjit%': 0,
@@ -109,6 +112,9 @@
       ['v8_enable_disassembler==1', {
         'defines': ['ENABLE_DISASSEMBLER',],
       }],
+      ['v8_enable_extra_checks==1', {
+        'defines': ['ENABLE_EXTRA_CHECKS',],
+      }],
       ['v8_object_print==1', {
         'defines': ['OBJECT_PRINT',],
       }],
diff --git a/src/api.cc b/src/api.cc
index 65b544c..73eb61d 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -1540,7 +1540,7 @@
                            isolate->global_context(),
                            NULL,
                            pre_data_impl,
-                           Utils::OpenHandle(*script_data),
+                           Utils::OpenHandle(*script_data, true),
                            i::NOT_NATIVES_CODE);
     has_pending_exception = result.is_null();
     EXCEPTION_BAILOUT_CHECK(isolate, Local<Script>());
@@ -4404,7 +4404,7 @@
     // Create the environment.
     env = isolate->bootstrapper()->CreateEnvironment(
         isolate,
-        Utils::OpenHandle(*global_object),
+        Utils::OpenHandle(*global_object, true),
         proxy_template,
         extensions);
 
@@ -5642,7 +5642,8 @@
     foreign =
         isolate->factory()->NewForeign(FUNCTION_ADDR(EventCallbackWrapper));
   }
-  isolate->debugger()->SetEventListener(foreign, Utils::OpenHandle(*data));
+  isolate->debugger()->SetEventListener(foreign,
+                                        Utils::OpenHandle(*data, true));
   return true;
 }
 
@@ -5657,7 +5658,8 @@
   if (that != NULL) {
     foreign = isolate->factory()->NewForeign(FUNCTION_ADDR(that));
   }
-  isolate->debugger()->SetEventListener(foreign, Utils::OpenHandle(*data));
+  isolate->debugger()->SetEventListener(foreign,
+                                        Utils::OpenHandle(*data, true));
   return true;
 }
 
@@ -5668,7 +5670,7 @@
   ON_BAILOUT(isolate, "v8::Debug::SetDebugEventListener()", return false);
   ENTER_V8(isolate);
   isolate->debugger()->SetEventListener(Utils::OpenHandle(*that),
-                                                      Utils::OpenHandle(*data));
+                                        Utils::OpenHandle(*data, true));
   return true;
 }
 
diff --git a/src/api.h b/src/api.h
index ea70dca..7197b6c 100644
--- a/src/api.h
+++ b/src/api.h
@@ -159,6 +159,27 @@
 };
 
 
+#define OPEN_HANDLE_LIST(V)                    \
+  V(Template, TemplateInfo)                    \
+  V(FunctionTemplate, FunctionTemplateInfo)    \
+  V(ObjectTemplate, ObjectTemplateInfo)        \
+  V(Signature, SignatureInfo)                  \
+  V(AccessorSignature, FunctionTemplateInfo)   \
+  V(TypeSwitch, TypeSwitchInfo)                \
+  V(Data, Object)                              \
+  V(RegExp, JSRegExp)                          \
+  V(Object, JSObject)                          \
+  V(Array, JSArray)                            \
+  V(String, String)                            \
+  V(Script, Object)                            \
+  V(Function, JSFunction)                      \
+  V(Message, JSObject)                         \
+  V(Context, Context)                          \
+  V(External, Foreign)                         \
+  V(StackTrace, JSArray)                       \
+  V(StackFrame, JSObject)
+
+
 class Utils {
  public:
   static bool ReportApiFailure(const char* location, const char* message);
@@ -205,42 +226,13 @@
   static inline Local<TypeSwitch> ToLocal(
       v8::internal::Handle<v8::internal::TypeSwitchInfo> obj);
 
-  static inline v8::internal::Handle<v8::internal::TemplateInfo>
-      OpenHandle(const Template* that);
-  static inline v8::internal::Handle<v8::internal::FunctionTemplateInfo>
-      OpenHandle(const FunctionTemplate* that);
-  static inline v8::internal::Handle<v8::internal::ObjectTemplateInfo>
-      OpenHandle(const ObjectTemplate* that);
-  static inline v8::internal::Handle<v8::internal::Object>
-      OpenHandle(const Data* data);
-  static inline v8::internal::Handle<v8::internal::JSRegExp>
-      OpenHandle(const RegExp* data);
-  static inline v8::internal::Handle<v8::internal::JSObject>
-      OpenHandle(const v8::Object* data);
-  static inline v8::internal::Handle<v8::internal::JSArray>
-      OpenHandle(const v8::Array* data);
-  static inline v8::internal::Handle<v8::internal::String>
-      OpenHandle(const String* data);
-  static inline v8::internal::Handle<v8::internal::Object>
-      OpenHandle(const Script* data);
-  static inline v8::internal::Handle<v8::internal::JSFunction>
-      OpenHandle(const Function* data);
-  static inline v8::internal::Handle<v8::internal::JSObject>
-      OpenHandle(const Message* message);
-  static inline v8::internal::Handle<v8::internal::JSArray>
-      OpenHandle(const StackTrace* stack_trace);
-  static inline v8::internal::Handle<v8::internal::JSObject>
-      OpenHandle(const StackFrame* stack_frame);
-  static inline v8::internal::Handle<v8::internal::Context>
-      OpenHandle(const v8::Context* context);
-  static inline v8::internal::Handle<v8::internal::SignatureInfo>
-      OpenHandle(const v8::Signature* sig);
-  static inline v8::internal::Handle<v8::internal::FunctionTemplateInfo>
-      OpenHandle(const v8::AccessorSignature* sig);
-  static inline v8::internal::Handle<v8::internal::TypeSwitchInfo>
-      OpenHandle(const v8::TypeSwitch* that);
-  static inline v8::internal::Handle<v8::internal::Foreign>
-      OpenHandle(const v8::External* that);
+#define DECLARE_OPEN_HANDLE(From, To) \
+  static inline v8::internal::Handle<v8::internal::To> \
+      OpenHandle(const From* that, bool allow_empty_handle = false);
+
+OPEN_HANDLE_LIST(DECLARE_OPEN_HANDLE)
+
+#undef DECLARE_OPEN_HANDLE
 };
 
 
@@ -257,7 +249,7 @@
   if (!is_null()) {
     handle = *this;
   }
-  return Utils::OpenHandle(*scope->Close(Utils::ToLocal(handle)));
+  return Utils::OpenHandle(*scope->Close(Utils::ToLocal(handle)), true);
 }
 
 
@@ -294,33 +286,18 @@
 
 // Implementations of OpenHandle
 
-#define MAKE_OPEN_HANDLE(From, To) \
-  v8::internal::Handle<v8::internal::To> Utils::OpenHandle(\
-    const v8::From* that) { \
-    return v8::internal::Handle<v8::internal::To>( \
+#define MAKE_OPEN_HANDLE(From, To)                                          \
+  v8::internal::Handle<v8::internal::To> Utils::OpenHandle(                 \
+    const v8::From* that, bool allow_empty_handle) {                        \
+    EXTRA_CHECK(allow_empty_handle || that != NULL);                        \
+    return v8::internal::Handle<v8::internal::To>(                          \
         reinterpret_cast<v8::internal::To**>(const_cast<v8::From*>(that))); \
   }
 
-MAKE_OPEN_HANDLE(Template, TemplateInfo)
-MAKE_OPEN_HANDLE(FunctionTemplate, FunctionTemplateInfo)
-MAKE_OPEN_HANDLE(ObjectTemplate, ObjectTemplateInfo)
-MAKE_OPEN_HANDLE(Signature, SignatureInfo)
-MAKE_OPEN_HANDLE(AccessorSignature, FunctionTemplateInfo)
-MAKE_OPEN_HANDLE(TypeSwitch, TypeSwitchInfo)
-MAKE_OPEN_HANDLE(Data, Object)
-MAKE_OPEN_HANDLE(RegExp, JSRegExp)
-MAKE_OPEN_HANDLE(Object, JSObject)
-MAKE_OPEN_HANDLE(Array, JSArray)
-MAKE_OPEN_HANDLE(String, String)
-MAKE_OPEN_HANDLE(Script, Object)
-MAKE_OPEN_HANDLE(Function, JSFunction)
-MAKE_OPEN_HANDLE(Message, JSObject)
-MAKE_OPEN_HANDLE(Context, Context)
-MAKE_OPEN_HANDLE(External, Foreign)
-MAKE_OPEN_HANDLE(StackTrace, JSArray)
-MAKE_OPEN_HANDLE(StackFrame, JSObject)
+OPEN_HANDLE_LIST(MAKE_OPEN_HANDLE)
 
 #undef MAKE_OPEN_HANDLE
+#undef OPEN_HANDLE_LIST
 
 
 namespace internal {
diff --git a/src/checks.h b/src/checks.h
index 608aa14..d0a0c2b 100644
--- a/src/checks.h
+++ b/src/checks.h
@@ -284,4 +284,12 @@
 
 #define ASSERT_NOT_NULL(p)  ASSERT_NE(NULL, p)
 
+// "Extra checks" are lightweight checks that are enabled in some release
+// builds.
+#ifdef ENABLE_EXTRA_CHECKS
+#define EXTRA_CHECK(condition) CHECK(condition)
+#else
+#define EXTRA_CHECK(condition) ((void) 0)
+#endif
+
 #endif  // V8_CHECKS_H_
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 6300fa1..cd81028 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -213,7 +213,7 @@
             "cache optimized code for closures")
 DEFINE_bool(inline_construct, true, "inline constructor calls")
 DEFINE_bool(inline_arguments, true, "inline functions with arguments object")
-DEFINE_bool(inline_accessors, true, "inline JavaScript accessors")
+DEFINE_bool(inline_accessors, false, "inline JavaScript accessors")
 DEFINE_int(loop_weight, 1, "loop weight for representation inference")
 
 DEFINE_bool(optimize_for_in, true,
diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc
index 7069f98..9c5f31e 100644
--- a/src/ia32/macro-assembler-ia32.cc
+++ b/src/ia32/macro-assembler-ia32.cc
@@ -1939,6 +1939,42 @@
   cmp(Operand::StaticVariable(scheduled_exception_address),
       Immediate(isolate()->factory()->the_hole_value()));
   j(not_equal, &promote_scheduled_exception);
+
+#if ENABLE_EXTRA_CHECKS
+  // Check if the function returned a valid JavaScript value.
+  Label ok;
+  Register return_value = eax;
+  Register map = ecx;
+
+  JumpIfSmi(return_value, &ok, Label::kNear);
+  mov(map, FieldOperand(return_value, HeapObject::kMapOffset));
+
+  CmpInstanceType(map, FIRST_NONSTRING_TYPE);
+  j(below, &ok, Label::kNear);
+
+  CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
+  j(above_equal, &ok, Label::kNear);
+
+  cmp(map, isolate()->factory()->heap_number_map());
+  j(equal, &ok, Label::kNear);
+
+  cmp(return_value, isolate()->factory()->undefined_value());
+  j(equal, &ok, Label::kNear);
+
+  cmp(return_value, isolate()->factory()->true_value());
+  j(equal, &ok, Label::kNear);
+
+  cmp(return_value, isolate()->factory()->false_value());
+  j(equal, &ok, Label::kNear);
+
+  cmp(return_value, isolate()->factory()->null_value());
+  j(equal, &ok, Label::kNear);
+
+  Abort("API call returned invalid object");
+
+  bind(&ok);
+#endif
+
   LeaveApiExitFrame();
   ret(stack_space * kPointerSize);
 
diff --git a/src/isolate.cc b/src/isolate.cc
index 7d31029a..75e15a4 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -535,6 +535,24 @@
 }
 
 
+void Isolate::PushStackTraceAndDie(unsigned int magic,
+                                   Object* object,
+                                   Map* map,
+                                   unsigned int magic2) {
+  const int kMaxStackTraceSize = 8192;
+  Handle<String> trace = StackTraceString();
+  char buffer[kMaxStackTraceSize];
+  int length = Min(kMaxStackTraceSize - 1, trace->length());
+  String::WriteToFlat(*trace, buffer, 0, length);
+  buffer[length] = '\0';
+  OS::PrintError("Stacktrace (%x-%x) %p %p: %s\n",
+                 magic, magic2,
+                 static_cast<void*>(object), static_cast<void*>(map),
+                 buffer);
+  OS::Abort();
+}
+
+
 void Isolate::CaptureAndSetCurrentStackTraceFor(Handle<JSObject> error_object) {
   if (capture_stack_trace_for_uncaught_exceptions_) {
     // Capture stack trace for a detailed exception message.
diff --git a/src/isolate.h b/src/isolate.h
index 93b9fb3..1d7bc6f 100644
--- a/src/isolate.h
+++ b/src/isolate.h
@@ -707,6 +707,10 @@
   void PrintStack(StringStream* accumulator);
   void PrintStack();
   Handle<String> StackTraceString();
+  NO_INLINE(void PushStackTraceAndDie(unsigned int magic,
+                                      Object* object,
+                                      Map* map,
+                                      unsigned int magic2));
   Handle<JSArray> CaptureCurrentStackTrace(
       int frame_limit,
       StackTrace::StackTraceOptions options);
diff --git a/src/objects.cc b/src/objects.cc
index 5bd423e..ea836c7 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -141,6 +141,9 @@
       holder = native_context->string_function()->instance_prototype();
     } else if (IsBoolean()) {
       holder = native_context->boolean_function()->instance_prototype();
+    } else {
+      Isolate::Current()->PushStackTraceAndDie(
+          0xDEAD0000, this, JSReceiver::cast(this)->map(), 0xDEAD0001);
     }
   }
   ASSERT(holder != NULL);  // Cannot handle null or undefined.
@@ -207,7 +210,20 @@
     if (result.IsEmpty()) {
       return isolate->heap()->undefined_value();
     }
-    return *v8::Utils::OpenHandle(*result);
+    Object* return_value = *v8::Utils::OpenHandle(*result);
+#if ENABLE_EXTRA_CHECKS
+    if (!(return_value->IsSmi() ||
+          return_value->IsString() ||
+          return_value->IsSpecObject() ||
+          return_value->IsHeapNumber() ||
+          return_value->IsUndefined() ||
+          return_value->IsTrue() ||
+          return_value->IsFalse() ||
+          return_value->IsNull())) {
+      FATAL("API call returned invalid object");
+    }
+#endif
+    return return_value;
   }
 
   // __defineGetter__ callback
diff --git a/src/version.cc b/src/version.cc
index d807dbe..172bf52 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -35,7 +35,7 @@
 #define MAJOR_VERSION     3
 #define MINOR_VERSION     13
 #define BUILD_NUMBER      5
-#define PATCH_LEVEL       1
+#define PATCH_LEVEL       2
 // Use 1 for candidates and 0 otherwise.
 // (Boolean macro values are not supported by all preprocessors.)
 #define IS_CANDIDATE_VERSION 0
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index 27bfe15..60f1644 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -1421,6 +1421,11 @@
       __ cmpq(left_reg, right_imm);
       __ j(condition, &return_left, Label::kNear);
       __ movq(left_reg, right_imm);
+    } else if (right->IsRegister()) {
+      Register right_reg = ToRegister(right);
+      __ cmpq(left_reg, right_reg);
+      __ j(condition, &return_left, Label::kNear);
+      __ movq(left_reg, right_reg);
     } else {
       Operand right_op = ToOperand(right);
       __ cmpq(left_reg, right_op);
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index 32a92a6..1b0f2fa 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -751,6 +751,41 @@
   Cmp(Operand(rsi, 0), factory->the_hole_value());
   j(not_equal, &promote_scheduled_exception);
 
+#if ENABLE_EXTRA_CHECKS
+  // Check if the function returned a valid JavaScript value.
+  Label ok;
+  Register return_value = rax;
+  Register map = rcx;
+
+  JumpIfSmi(return_value, &ok, Label::kNear);
+  movq(map, FieldOperand(return_value, HeapObject::kMapOffset));
+
+  CmpInstanceType(map, FIRST_NONSTRING_TYPE);
+  j(below, &ok, Label::kNear);
+
+  CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
+  j(above_equal, &ok, Label::kNear);
+
+  CompareRoot(map, Heap::kHeapNumberMapRootIndex);
+  j(equal, &ok, Label::kNear);
+
+  CompareRoot(return_value, Heap::kUndefinedValueRootIndex);
+  j(equal, &ok, Label::kNear);
+
+  CompareRoot(return_value, Heap::kTrueValueRootIndex);
+  j(equal, &ok, Label::kNear);
+
+  CompareRoot(return_value, Heap::kFalseValueRootIndex);
+  j(equal, &ok, Label::kNear);
+
+  CompareRoot(return_value, Heap::kNullValueRootIndex);
+  j(equal, &ok, Label::kNear);
+
+  Abort("API call returned invalid object");
+
+  bind(&ok);
+#endif
+
   LeaveApiExitFrame();
   ret(stack_space * kPointerSize);
 
diff --git a/test/mjsunit/regress/regress-crbug-145961.js b/test/mjsunit/regress/regress-crbug-145961.js
new file mode 100644
index 0000000..eb88945
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-145961.js
@@ -0,0 +1,39 @@
+// Copyright 2012 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.
+
+// This test causes the operands to be passed in as Integer32 registers.
+// Flags: --allow-natives-syntax
+function test() {
+  var a = new Int32Array(2);
+  var x = a[0];
+  return Math.min(x, x);
+}
+
+assertEquals(0, test());
+assertEquals(0, test());
+%OptimizeFunctionOnNextCall(test);
+assertEquals(0, test());