Version 3.21.12
Fixed bitwise negation on x64. (Chromium issue 285355)
Dropped GetCurrentThreadId() and TerminateExecution(int) from the external API.
Fixed polymorphic INTERCEPTOR StoreICs on ARM/MIPS. (Chromium issue 284998)
Added check if timeout has expired after processing each sample. (issue 2814,v8:2871)
Removed obsolete global V8::has_been_fooed flags. (issue 2744)
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@16593 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index d39b110..7a498ba 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2013-09-09: Version 3.21.12
+
+ Fixed bitwise negation on x64.
+ (Chromium issue 285355)
+
+ Dropped GetCurrentThreadId() and TerminateExecution(int) from
+ the external API.
+
+ Fixed polymorphic INTERCEPTOR StoreICs on ARM/MIPS.
+ (Chromium issue 284998)
+
+ Added check if timeout has expired after processing each sample.
+ (issue 2814,v8:2871)
+
+ Removed obsolete global V8::has_been_fooed flags.
+ (issue 2744)
+
+ Performance and stability improvements on all platforms.
+
+
2013-09-05: Version 3.21.11
Performance and stability improvements on all platforms.
diff --git a/include/v8.h b/include/v8.h
index ba4d19b..55a8ea6 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -120,7 +120,10 @@
template <class T> class Handle;
template <class T> class Local;
template <class T> class Eternal;
-template <class T> class Persistent;
+template<class T> class NonCopyablePersistentTraits;
+template<class T,
+ class M = NonCopyablePersistentTraits<T> > class Persistent;
+template<class T, class P> class WeakCallbackObject;
class FunctionTemplate;
class ObjectTemplate;
class Data;
@@ -142,6 +145,7 @@
template<typename T> class CustomArguments;
class PropertyCallbackArguments;
class FunctionCallbackArguments;
+class GlobalHandles;
}
@@ -169,27 +173,6 @@
intptr_t data_;
};
-
-// --- Weak Handles ---
-
-
-/**
- * A weak reference callback function.
- *
- * This callback should either explicitly invoke Dispose on |object| if
- * V8 wrapper is not needed anymore, or 'revive' it by invocation of MakeWeak.
- *
- * \param object the weak global object to be reclaimed by the garbage collector
- * \param parameter the value passed in when making the weak global object
- */
-template<typename T, typename P>
-class WeakReferenceCallbacks {
- public:
- typedef void (*Revivable)(Isolate* isolate,
- Persistent<T>* object,
- P* parameter);
-};
-
// --- Handles ---
#define TYPE_CHECK(T, S) \
@@ -230,13 +213,6 @@
*/
V8_INLINE(Handle()) : val_(0) {}
-#ifdef V8_USE_UNSAFE_HANDLES
- /**
- * Creates a new handle for the specified value.
- */
- V8_INLINE(explicit Handle(T* val)) : val_(val) {}
-#endif
-
/**
* Creates a handle for the contents of the specified handle. This
* constructor allows you to pass handles as arguments by value and
@@ -285,7 +261,6 @@
return *a == *b;
}
-#ifndef V8_USE_UNSAFE_HANDLES
template <class S> V8_INLINE(
bool operator==(const Persistent<S>& that) const) {
internal::Object** a = reinterpret_cast<internal::Object**>(**this);
@@ -294,7 +269,6 @@
if (b == 0) return false;
return *a == *b;
}
-#endif
/**
* Checks whether two handles are different.
@@ -306,12 +280,10 @@
return !operator==(that);
}
-#ifndef V8_USE_UNSAFE_HANDLES
template <class S> V8_INLINE(
bool operator!=(const Persistent<S>& that) const) {
return !operator==(that);
}
-#endif
template <class S> V8_INLINE(static Handle<T> Cast(Handle<S> that)) {
#ifdef V8_ENABLE_CHECKS
@@ -326,11 +298,9 @@
return Handle<S>::Cast(*this);
}
-#ifndef V8_USE_UNSAFE_HANDLES
V8_INLINE(static Handle<T> New(Isolate* isolate, Handle<T> that)) {
return New(isolate, that.val_);
}
- // TODO(dcarney): remove before cutover
V8_INLINE(static Handle<T> New(Isolate* isolate, const Persistent<T>& that)) {
return New(isolate, that.val_);
}
@@ -343,11 +313,10 @@
* Creates a new handle for the specified value.
*/
V8_INLINE(explicit Handle(T* val)) : val_(val) {}
-#endif
private:
friend class Utils;
- template<class F> friend class Persistent;
+ template<class F, class M> friend class Persistent;
template<class F> friend class Local;
template<class F> friend class FunctionCallbackInfo;
template<class F> friend class PropertyCallbackInfo;
@@ -359,9 +328,7 @@
friend class Context;
friend class HandleScope;
-#ifndef V8_USE_UNSAFE_HANDLES
V8_INLINE(static Handle<T> New(Isolate* isolate, T* that));
-#endif
T* val_;
};
@@ -374,7 +341,6 @@
* handle scope are destroyed when the handle scope is destroyed. Hence it
* is not necessary to explicitly deallocate local handles.
*/
-// TODO(dcarney): deprecate entire class
template <class T> class Local : public Handle<T> {
public:
V8_INLINE(Local());
@@ -389,10 +355,6 @@
}
-#ifdef V8_USE_UNSAFE_HANDLES
- template <class S> V8_INLINE(Local(S* that) : Handle<T>(that)) { }
-#endif
-
template <class S> V8_INLINE(static Local<T> Cast(Local<S> that)) {
#ifdef V8_ENABLE_CHECKS
// If we're going to perform the type check then we have to check
@@ -401,12 +363,10 @@
#endif
return Local<T>(T::Cast(*that));
}
-#ifndef V8_USE_UNSAFE_HANDLES
template <class S> V8_INLINE(Local(Handle<S> that))
: Handle<T>(reinterpret_cast<T*>(*that)) {
TYPE_CHECK(T, S);
}
-#endif
template <class S> V8_INLINE(Local<S> As()) {
return Local<S>::Cast(*this);
@@ -419,21 +379,20 @@
*/
V8_INLINE(static Local<T> New(Handle<T> that));
V8_INLINE(static Local<T> New(Isolate* isolate, Handle<T> that));
-#ifndef V8_USE_UNSAFE_HANDLES
- // TODO(dcarney): remove before cutover
- V8_INLINE(static Local<T> New(Isolate* isolate, const Persistent<T>& that));
+ template<class M>
+ V8_INLINE(static Local<T> New(Isolate* isolate,
+ const Persistent<T, M>& that));
#ifndef V8_ALLOW_ACCESS_TO_RAW_HANDLE_CONSTRUCTOR
private:
#endif
template <class S> V8_INLINE(Local(S* that) : Handle<T>(that)) { }
-#endif
private:
friend class Utils;
template<class F> friend class Eternal;
- template<class F> friend class Persistent;
+ template<class F, class M> friend class Persistent;
template<class F> friend class Handle;
template<class F> friend class FunctionCallbackInfo;
template<class F> friend class PropertyCallbackInfo;
@@ -468,6 +427,61 @@
};
+template<class T, class P>
+class WeakCallbackData {
+ public:
+ typedef void (*Callback)(const WeakCallbackData<T, P>& data);
+
+ V8_INLINE(Isolate* GetIsolate()) const { return isolate_; }
+ V8_INLINE(Local<T> GetValue()) const { return handle_; }
+ V8_INLINE(P* GetParameter()) const { return parameter_; }
+
+ private:
+ friend class internal::GlobalHandles;
+ WeakCallbackData(Isolate* isolate, Local<T> handle, P* parameter)
+ : isolate_(isolate), handle_(handle), parameter_(parameter) { }
+ Isolate* isolate_;
+ Local<T> handle_;
+ P* parameter_;
+};
+
+
+// TODO(dcarney): Remove this class.
+template<typename T,
+ typename P,
+ typename M = NonCopyablePersistentTraits<T> >
+class WeakReferenceCallbacks {
+ public:
+ typedef void (*Revivable)(Isolate* isolate,
+ Persistent<T, M>* object,
+ P* parameter);
+};
+
+
+/**
+ * Default traits for Persistent. This class does not allow
+ * use of the copy constructor or assignment operator.
+ * At present kResetInDestructor is not set, but that will change in a future
+ * version.
+ */
+template<class T>
+class NonCopyablePersistentTraits {
+ public:
+ typedef Persistent<T, NonCopyablePersistentTraits<T> > NonCopyablePersistent;
+ static const bool kResetInDestructor = false;
+ template<class S, class M>
+ V8_INLINE(static void Copy(const Persistent<S, M>& source,
+ NonCopyablePersistent* dest)) {
+ Uncompilable<Object>();
+ }
+ // TODO(dcarney): come up with a good compile error here.
+ template<class O>
+ V8_INLINE(static void Uncompilable()) {
+ TYPE_CHECK(O, Primitive);
+ }
+};
+
+
/**
* An object reference that is independent of any handle scope. Where
* a Local handle only lives as long as the HandleScope in which it was
@@ -477,106 +491,84 @@
* A persistent handle contains a reference to a storage cell within
* the v8 engine which holds an object value and which is updated by
* the garbage collector whenever the object is moved. A new storage
- * cell can be created using Persistent::New and existing handles can
- * be disposed using Persistent::Dispose. Since persistent handles
- * are passed by value you may have many persistent handle objects
- * that point to the same storage cell. For instance, if you pass a
- * persistent handle as an argument to a function you will not get two
- * different storage cells but rather two references to the same
- * storage cell.
+ * cell can be created using the constructor or Persistent::Reset and
+ * existing handles can be disposed using Persistent::Reset.
+ *
+ * Copy, assignment and destructor bevavior is controlled by the traits
+ * class M.
*/
-template <class T> class Persistent // NOLINT
-#ifdef V8_USE_UNSAFE_HANDLES
- : public Handle<T> {
-#else
- { // NOLINT
-#endif
+template <class T, class M> class Persistent {
public:
-#ifndef V8_USE_UNSAFE_HANDLES
- V8_INLINE(Persistent()) : val_(0) { }
- // TODO(dcarney): add this back before cutover.
-// V8_INLINE(~Persistent()) {
-// Dispose();
-// }
- V8_INLINE(bool IsEmpty() const) { return val_ == 0; }
- // TODO(dcarney): remove somehow before cutover
- // The handle should either be 0, or a pointer to a live cell.
- V8_INLINE(void Clear()) { val_ = 0; }
-
/**
- * A constructor that creates a new global cell pointing to that. In contrast
- * to the copy constructor, this creates a new persistent handle which needs
- * to be separately disposed.
+ * A Persistent with no storage cell.
+ */
+ V8_INLINE(Persistent()) : val_(0) { }
+ /**
+ * Construct a Persistent from a Handle.
+ * When the Handle is non-empty, a new storage cell is created
+ * pointing to the same object, and no flags are set.
*/
template <class S> V8_INLINE(Persistent(Isolate* isolate, Handle<S> that))
- : val_(New(isolate, *that)) { }
-
- template <class S> V8_INLINE(Persistent(Isolate* isolate,
- const Persistent<S>& that)) // NOLINT
- : val_(New(isolate, *that)) { }
-
-#else
- /**
- * Creates an empty persistent handle that doesn't point to any
- * storage cell.
- */
- V8_INLINE(Persistent()) : Handle<T>() { }
-
- /**
- * Creates a persistent handle for the same storage cell as the
- * specified handle. This constructor allows you to pass persistent
- * handles as arguments by value and to assign between persistent
- * handles. However, attempting to assign between incompatible
- * persistent handles, for instance from a Persistent<String> to a
- * Persistent<Number> will cause a compile-time error. Assigning
- * between compatible persistent handles, for instance assigning a
- * Persistent<String> to a variable declared as Persistent<Value>,
- * is allowed as String is a subclass of Value.
- */
- template <class S> V8_INLINE(Persistent(Persistent<S> that))
- : Handle<T>(reinterpret_cast<T*>(*that)) {
- /**
- * This check fails when trying to convert between incompatible
- * handles. For example, converting from a Handle<String> to a
- * Handle<Number>.
- */
+ : val_(New(isolate, *that)) {
TYPE_CHECK(T, S);
}
-
- template <class S> V8_INLINE(Persistent(S* that)) : Handle<T>(that) { }
-
/**
- * A constructor that creates a new global cell pointing to that. In contrast
- * to the copy constructor, this creates a new persistent handle which needs
- * to be separately disposed.
+ * Construct a Persistent from a Persistent.
+ * When the Persistent is non-empty, a new storage cell is created
+ * pointing to the same object, and no flags are set.
*/
- template <class S> V8_INLINE(Persistent(Isolate* isolate, Handle<S> that))
- : Handle<T>(New(isolate, that)) { }
-
+ template <class S, class M2>
+ V8_INLINE(Persistent(Isolate* isolate, const Persistent<S, M2>& that))
+ : val_(New(isolate, *that)) {
+ TYPE_CHECK(T, S);
+ }
/**
- * "Casts" a plain handle which is known to be a persistent handle
- * to a persistent handle.
+ * The copy constructors and assignment operator create a Persistent
+ * exactly as the Persistent constructor, but the Copy function from the
+ * traits class is called, allowing the setting of flags based on the
+ * copied Persistent.
*/
- template <class S> explicit V8_INLINE(Persistent(Handle<S> that))
- : Handle<T>(*that) { }
-
-#endif
-
-#ifdef V8_USE_UNSAFE_HANDLES
- template <class S> V8_INLINE(static Persistent<T> Cast(Persistent<S> that)) {
-#ifdef V8_ENABLE_CHECKS
- // If we're going to perform the type check then we have to check
- // that the handle isn't empty before doing the checked cast.
- if (that.IsEmpty()) return Persistent<T>();
-#endif
- return Persistent<T>(T::Cast(*that));
+ V8_INLINE(Persistent(const Persistent& that)) : val_(0) {
+ Copy(that);
+ }
+ template <class S, class M2>
+ V8_INLINE(Persistent(const Persistent<S, M2>& that)) : val_(0) {
+ Copy(that);
+ }
+ V8_INLINE(Persistent& operator=(const Persistent& that)) { // NOLINT
+ Copy(that);
+ return *this;
+ }
+ template <class S, class M2>
+ V8_INLINE(Persistent& operator=(const Persistent<S, M2>& that)) { // NOLINT
+ Copy(that);
+ return *this;
}
- template <class S> V8_INLINE(Persistent<S> As()) {
- return Persistent<S>::Cast(*this);
- }
+ /**
+ * If non-empty, destroy the underlying storage cell
+ * IsEmpty() will return true after this call.
+ */
+ V8_INLINE(void Reset());
+ template <class S>
+ /**
+ * If non-empty, destroy the underlying storage cell
+ * and create a new one with the contents of other if other is non empty
+ */
+ V8_INLINE(void Reset(Isolate* isolate, const Handle<S>& other));
+ /**
+ * If non-empty, destroy the underlying storage cell
+ * and create a new one with the contents of other if other is non empty
+ */
+ template <class S, class M2>
+ V8_INLINE(void Reset(Isolate* isolate, const Persistent<S, M2>& other));
+ // TODO(dcarney): deprecate
+ V8_INLINE(void Dispose()) { Reset(); }
+ V8_DEPRECATED(V8_INLINE(void Dispose(Isolate* isolate))) { Reset(); }
-#else
+ V8_INLINE(bool IsEmpty() const) { return val_ == 0; }
+
+ // TODO(dcarney): this is pretty useless, fix or remove
template <class S>
V8_INLINE(static Persistent<T>& Cast(Persistent<S>& that)) { // NOLINT
#ifdef V8_ENABLE_CHECKS
@@ -587,20 +579,13 @@
return reinterpret_cast<Persistent<T>&>(that);
}
+ // TODO(dcarney): this is pretty useless, fix or remove
template <class S> V8_INLINE(Persistent<S>& As()) { // NOLINT
return Persistent<S>::Cast(*this);
}
-#endif
-#ifdef V8_USE_UNSAFE_HANDLES
- V8_DEPRECATED(static Persistent<T> New(Handle<T> that));
- V8_INLINE(static Persistent<T> New(Isolate* isolate, Handle<T> that));
- V8_INLINE(static Persistent<T> New(Isolate* isolate, Persistent<T> that));
-#endif
-
-#ifndef V8_USE_UNSAFE_HANDLES
- template <class S> V8_INLINE(
- bool operator==(const Persistent<S>& that) const) {
+ template <class S, class M2> V8_INLINE(
+ bool operator==(const Persistent<S, M2>& that) const) {
internal::Object** a = reinterpret_cast<internal::Object**>(**this);
internal::Object** b = reinterpret_cast<internal::Object**>(*that);
if (a == 0) return b == 0;
@@ -616,52 +601,35 @@
return *a == *b;
}
- template <class S> V8_INLINE(
- bool operator!=(const Persistent<S>& that) const) {
+ template <class S, class M2> V8_INLINE(
+ bool operator!=(const Persistent<S, M2>& that) const) {
return !operator==(that);
}
template <class S> V8_INLINE(bool operator!=(const Handle<S>& that) const) {
return !operator==(that);
}
-#endif
-
- V8_INLINE(void Dispose());
-
- /**
- * Releases the storage cell referenced by this persistent handle.
- * Does not remove the reference to the cell from any handles.
- * This handle's reference, and any other references to the storage
- * cell remain and IsEmpty will still return false.
- */
- V8_DEPRECATED(V8_INLINE(void Dispose(Isolate* isolate))) { Dispose(); }
-
- /**
- * Make the reference to this object weak. When only weak handles
- * refer to the object, the garbage collector will perform a
- * callback to the given V8::NearDeathCallback function, passing
- * it the object reference and the given parameters.
- */
- template<typename S, typename P>
- V8_INLINE(void MakeWeak(
- P* parameters,
- typename WeakReferenceCallbacks<S, P>::Revivable callback));
template<typename P>
- V8_INLINE(void MakeWeak(
- P* parameters,
- typename WeakReferenceCallbacks<T, P>::Revivable callback));
+ V8_INLINE(void SetWeak(
+ P* parameter,
+ typename WeakCallbackData<T, P>::Callback callback));
template<typename S, typename P>
- V8_DEPRECATED(void MakeWeak(
- Isolate* isolate,
- P* parameters,
+ V8_INLINE(void SetWeak(
+ P* parameter,
+ typename WeakCallbackData<S, P>::Callback callback));
+
+ // TODO(dcarney): deprecate
+ template<typename S, typename P>
+ V8_INLINE(void MakeWeak(
+ P* parameter,
typename WeakReferenceCallbacks<S, P>::Revivable callback));
+ // TODO(dcarney): deprecate
template<typename P>
- V8_DEPRECATED(void MakeWeak(
- Isolate* isolate,
- P* parameters,
+ V8_INLINE(void MakeWeak(
+ P* parameter,
typename WeakReferenceCallbacks<T, P>::Revivable callback));
V8_INLINE(void ClearWeak());
@@ -735,68 +703,35 @@
return WrapperClassId();
}
- /**
- * Disposes the current contents of the handle and replaces it.
- */
- V8_INLINE(void Reset(Isolate* isolate, const Handle<T>& other));
-
-#ifndef V8_USE_UNSAFE_HANDLES
- V8_INLINE(void Reset(Isolate* isolate, const Persistent<T>& other));
-#endif
-
- /**
- * Returns the underlying raw pointer and clears the handle. The caller is
- * responsible of eventually destroying the underlying object (by creating a
- * Persistent handle which points to it and Disposing it). In the future,
- * destructing a Persistent will also Dispose it. With this function, the
- * embedder can let the Persistent go out of scope without it getting
- * disposed.
- */
+ // TODO(dcarney): remove
V8_INLINE(T* ClearAndLeak());
-#ifndef V8_USE_UNSAFE_HANDLES
+ // TODO(dcarney): remove
+ V8_INLINE(void Clear()) { val_ = 0; }
- private:
- // TODO(dcarney): make unlinkable before cutover
- V8_INLINE(Persistent(const Persistent& that)) : val_(that.val_) {}
- // TODO(dcarney): make unlinkable before cutover
- V8_INLINE(Persistent& operator=(const Persistent& that)) { // NOLINT
- this->val_ = that.val_;
- return *this;
- }
-
- public:
+ // TODO(dcarney): remove
#ifndef V8_ALLOW_ACCESS_TO_RAW_HANDLE_CONSTRUCTOR
private:
#endif
- // TODO(dcarney): remove before cutover
template <class S> V8_INLINE(Persistent(S* that)) : val_(that) { }
- // TODO(dcarney): remove before cutover
V8_INLINE(T* operator*() const) { return val_; }
private:
- // TODO(dcarney): remove before cutover
- V8_INLINE(T* operator->() const) { return val_; }
- public:
-#endif
-
- private:
friend class Utils;
template<class F> friend class Handle;
template<class F> friend class Local;
- template<class F> friend class Persistent;
+ template<class F1, class F2> friend class Persistent;
template<class F> friend class ReturnValue;
V8_INLINE(static T* New(Isolate* isolate, T* that));
+ template<class S, class M2>
+ V8_INLINE(void Copy(const Persistent<S, M2>& that));
-#ifndef V8_USE_UNSAFE_HANDLES
T* val_;
-#endif
};
-
/**
* A stack-allocated class that governs a number of local handles.
* After a handle scope has been created, all local handles will be
@@ -2361,11 +2296,129 @@
};
+template<typename T>
+class ReturnValue {
+ public:
+ template <class S> V8_INLINE(ReturnValue(const ReturnValue<S>& that))
+ : value_(that.value_) {
+ TYPE_CHECK(T, S);
+ }
+ // Handle setters
+ template <typename S> V8_INLINE(void Set(const Persistent<S>& handle));
+ template <typename S> V8_INLINE(void Set(const Handle<S> handle));
+ // Fast primitive setters
+ V8_INLINE(void Set(bool value));
+ V8_INLINE(void Set(double i));
+ V8_INLINE(void Set(int32_t i));
+ V8_INLINE(void Set(uint32_t i));
+ // Fast JS primitive setters
+ V8_INLINE(void SetNull());
+ V8_INLINE(void SetUndefined());
+ V8_INLINE(void SetEmptyString());
+ // Convenience getter for Isolate
+ V8_INLINE(Isolate* GetIsolate());
+
+ private:
+ template<class F> friend class ReturnValue;
+ template<class F> friend class FunctionCallbackInfo;
+ template<class F> friend class PropertyCallbackInfo;
+ V8_INLINE(internal::Object* GetDefaultValue());
+ V8_INLINE(explicit ReturnValue(internal::Object** slot));
+ internal::Object** value_;
+};
+
+
+/**
+ * The argument information given to function call callbacks. This
+ * class provides access to information about the context of the call,
+ * including the receiver, the number and values of arguments, and
+ * the holder of the function.
+ */
+template<typename T>
+class FunctionCallbackInfo {
+ public:
+ V8_INLINE(int Length() const);
+ V8_INLINE(Local<Value> operator[](int i) const);
+ V8_INLINE(Local<Function> Callee() const);
+ V8_INLINE(Local<Object> This() const);
+ V8_INLINE(Local<Object> Holder() const);
+ V8_INLINE(bool IsConstructCall() const);
+ V8_INLINE(Local<Value> Data() const);
+ V8_INLINE(Isolate* GetIsolate() const);
+ V8_INLINE(ReturnValue<T> GetReturnValue() const);
+ // This shouldn't be public, but the arm compiler needs it.
+ static const int kArgsLength = 6;
+
+ protected:
+ friend class internal::FunctionCallbackArguments;
+ friend class internal::CustomArguments<FunctionCallbackInfo>;
+ static const int kReturnValueIndex = 0;
+ static const int kReturnValueDefaultValueIndex = -1;
+ static const int kIsolateIndex = -2;
+ static const int kDataIndex = -3;
+ static const int kCalleeIndex = -4;
+ static const int kHolderIndex = -5;
+
+ V8_INLINE(FunctionCallbackInfo(internal::Object** implicit_args,
+ internal::Object** values,
+ int length,
+ bool is_construct_call));
+ internal::Object** implicit_args_;
+ internal::Object** values_;
+ int length_;
+ bool is_construct_call_;
+};
+
+
+/**
+ * The information passed to a property callback about the context
+ * of the property access.
+ */
+template<typename T>
+class PropertyCallbackInfo {
+ public:
+ V8_INLINE(Isolate* GetIsolate() const);
+ V8_INLINE(Local<Value> Data() const);
+ V8_INLINE(Local<Object> This() const);
+ V8_INLINE(Local<Object> Holder() const);
+ V8_INLINE(ReturnValue<T> GetReturnValue() const);
+ // This shouldn't be public, but the arm compiler needs it.
+ static const int kArgsLength = 6;
+
+ protected:
+ friend class MacroAssembler;
+ friend class internal::PropertyCallbackArguments;
+ friend class internal::CustomArguments<PropertyCallbackInfo>;
+ static const int kThisIndex = 0;
+ static const int kHolderIndex = -1;
+ static const int kDataIndex = -2;
+ static const int kReturnValueIndex = -3;
+ static const int kReturnValueDefaultValueIndex = -4;
+ static const int kIsolateIndex = -5;
+
+ V8_INLINE(PropertyCallbackInfo(internal::Object** args))
+ : args_(args) { }
+ internal::Object** args_;
+};
+
+
+typedef void (*FunctionCallback)(const FunctionCallbackInfo<Value>& info);
+
+
/**
* A JavaScript function object (ECMA-262, 15.3).
*/
class V8_EXPORT Function : public Object {
public:
+ /**
+ * Create a function in the current execution context
+ * for a given FunctionCallback.
+ */
+ static Local<Function> New(Isolate* isolate,
+ FunctionCallback callback,
+ Local<Value> data = Local<Value>(),
+ int length = 0);
+
Local<Object> NewInstance() const;
Local<Object> NewInstance(int argc, Handle<Value> argv[]) const;
Local<Value> Call(Handle<Object> recv, int argc, Handle<Value> argv[]);
@@ -3034,114 +3087,6 @@
};
-template<typename T>
-class ReturnValue {
- public:
- template <class S> V8_INLINE(ReturnValue(const ReturnValue<S>& that))
- : value_(that.value_) {
- TYPE_CHECK(T, S);
- }
- // Handle setters
- template <typename S> V8_INLINE(void Set(const Persistent<S>& handle));
- template <typename S> V8_INLINE(void Set(const Handle<S> handle));
- // Fast primitive setters
- V8_INLINE(void Set(bool value));
- V8_INLINE(void Set(double i));
- V8_INLINE(void Set(int32_t i));
- V8_INLINE(void Set(uint32_t i));
- // Fast JS primitive setters
- V8_INLINE(void SetNull());
- V8_INLINE(void SetUndefined());
- V8_INLINE(void SetEmptyString());
- // Convenience getter for Isolate
- V8_INLINE(Isolate* GetIsolate());
-
- private:
- template<class F> friend class ReturnValue;
- template<class F> friend class FunctionCallbackInfo;
- template<class F> friend class PropertyCallbackInfo;
- V8_INLINE(internal::Object* GetDefaultValue());
- V8_INLINE(explicit ReturnValue(internal::Object** slot));
- internal::Object** value_;
-};
-
-
-/**
- * The argument information given to function call callbacks. This
- * class provides access to information about the context of the call,
- * including the receiver, the number and values of arguments, and
- * the holder of the function.
- */
-template<typename T>
-class FunctionCallbackInfo {
- public:
- V8_INLINE(int Length() const);
- V8_INLINE(Local<Value> operator[](int i) const);
- V8_INLINE(Local<Function> Callee() const);
- V8_INLINE(Local<Object> This() const);
- V8_INLINE(Local<Object> Holder() const);
- V8_INLINE(bool IsConstructCall() const);
- V8_INLINE(Local<Value> Data() const);
- V8_INLINE(Isolate* GetIsolate() const);
- V8_INLINE(ReturnValue<T> GetReturnValue() const);
- // This shouldn't be public, but the arm compiler needs it.
- static const int kArgsLength = 6;
-
- protected:
- friend class internal::FunctionCallbackArguments;
- friend class internal::CustomArguments<FunctionCallbackInfo>;
- static const int kReturnValueIndex = 0;
- static const int kReturnValueDefaultValueIndex = -1;
- static const int kIsolateIndex = -2;
- static const int kDataIndex = -3;
- static const int kCalleeIndex = -4;
- static const int kHolderIndex = -5;
-
- V8_INLINE(FunctionCallbackInfo(internal::Object** implicit_args,
- internal::Object** values,
- int length,
- bool is_construct_call));
- internal::Object** implicit_args_;
- internal::Object** values_;
- int length_;
- bool is_construct_call_;
-};
-
-
-/**
- * The information passed to a property callback about the context
- * of the property access.
- */
-template<typename T>
-class PropertyCallbackInfo {
- public:
- V8_INLINE(Isolate* GetIsolate() const);
- V8_INLINE(Local<Value> Data() const);
- V8_INLINE(Local<Object> This() const);
- V8_INLINE(Local<Object> Holder() const);
- V8_INLINE(ReturnValue<T> GetReturnValue() const);
- // This shouldn't be public, but the arm compiler needs it.
- static const int kArgsLength = 6;
-
- protected:
- friend class MacroAssembler;
- friend class internal::PropertyCallbackArguments;
- friend class internal::CustomArguments<PropertyCallbackInfo>;
- static const int kThisIndex = 0;
- static const int kHolderIndex = -1;
- static const int kDataIndex = -2;
- static const int kReturnValueIndex = -3;
- static const int kReturnValueDefaultValueIndex = -4;
- static const int kIsolateIndex = -5;
-
- V8_INLINE(PropertyCallbackInfo(internal::Object** args))
- : args_(args) { }
- internal::Object** args_;
-};
-
-
-typedef void (*FunctionCallback)(const FunctionCallbackInfo<Value>& info);
-
/**
* NamedProperty[Getter|Setter] are used as interceptors on object.
* See ObjectTemplate::SetNamedPropertyHandler.
@@ -4592,40 +4537,6 @@
intptr_t change_in_bytes);
/**
- * Retrieve the V8 thread id of the calling thread.
- *
- * The thread id for a thread should only be retrieved after the V8
- * lock has been acquired with a Locker object with that thread.
- */
- static int GetCurrentThreadId();
-
- /**
- * Forcefully terminate execution of a JavaScript thread. This can
- * be used to terminate long-running scripts.
- *
- * TerminateExecution should only be called when then V8 lock has
- * been acquired with a Locker object. Therefore, in order to be
- * able to terminate long-running threads, preemption must be
- * enabled to allow the user of TerminateExecution to acquire the
- * lock.
- *
- * The termination is achieved by throwing an exception that is
- * uncatchable by JavaScript exception handlers. Termination
- * exceptions act as if they were caught by a C++ TryCatch exception
- * handler. If forceful termination is used, any C++ TryCatch
- * exception handler that catches an exception should check if that
- * exception is a termination exception and immediately return if
- * that is the case. Returning immediately in that case will
- * continue the propagation of the termination exception if needed.
- *
- * The thread id passed to TerminateExecution must have been
- * obtained by calling GetCurrentThreadId on the thread in question.
- *
- * \param thread_id The thread id of the thread to terminate.
- */
- static void TerminateExecution(int thread_id);
-
- /**
* Forcefully terminate the current thread of JavaScript execution
* in the given isolate. If no isolate is provided, the default
* isolate is used.
@@ -4743,10 +4654,13 @@
static internal::Object** GlobalizeReference(internal::Isolate* isolate,
internal::Object** handle);
+ static internal::Object** CopyPersistent(internal::Object** handle);
static void DisposeGlobal(internal::Object** global_handle);
typedef WeakReferenceCallbacks<Value, void>::Revivable RevivableCallback;
+ typedef WeakCallbackData<Value, void>::Callback WeakCallback;
static void MakeWeak(internal::Object** global_handle,
void* data,
+ WeakCallback weak_callback,
RevivableCallback weak_reference_callback);
static void ClearWeak(internal::Object** global_handle);
static void Eternalize(Isolate* isolate,
@@ -4757,7 +4671,7 @@
template <class T> friend class Handle;
template <class T> friend class Local;
template <class T> friend class Eternal;
- template <class T> friend class Persistent;
+ template <class T, class M> friend class Persistent;
friend class Context;
};
@@ -5098,11 +5012,7 @@
}
// TODO(dcarney): deprecate
V8_INLINE(Scope(Isolate* isolate, Persistent<Context>& context)) // NOLINT
-#ifndef V8_USE_UNSAFE_HANDLES
: context_(Handle<Context>::New(isolate, context)) {
-#else
- : context_(Local<Context>::New(isolate, context)) {
-#endif
context_->Enter();
}
V8_INLINE(~Scope()) { context_->Exit(); }
@@ -5592,9 +5502,9 @@
return New(isolate, that.val_);
}
-#ifndef V8_USE_UNSAFE_HANDLES
template <class T>
-Local<T> Local<T>::New(Isolate* isolate, const Persistent<T>& that) {
+template <class M>
+Local<T> Local<T>::New(Isolate* isolate, const Persistent<T, M>& that) {
return New(isolate, that.val_);
}
@@ -5606,7 +5516,6 @@
return Handle<T>(reinterpret_cast<T*>(HandleScope::CreateHandle(
reinterpret_cast<internal::Isolate*>(isolate), *p)));
}
-#endif
template <class T>
@@ -5633,27 +5542,8 @@
}
-#ifdef V8_USE_UNSAFE_HANDLES
-template <class T>
-Persistent<T> Persistent<T>::New(Handle<T> that) {
- return New(Isolate::GetCurrent(), that.val_);
-}
-
-
-template <class T>
-Persistent<T> Persistent<T>::New(Isolate* isolate, Handle<T> that) {
- return New(Isolate::GetCurrent(), that.val_);
-}
-
-template <class T>
-Persistent<T> Persistent<T>::New(Isolate* isolate, Persistent<T> that) {
- return New(Isolate::GetCurrent(), that.val_);
-}
-#endif
-
-
-template <class T>
-T* Persistent<T>::New(Isolate* isolate, T* that) {
+template <class T, class M>
+T* Persistent<T, M>::New(Isolate* isolate, T* that) {
if (that == NULL) return NULL;
internal::Object** p = reinterpret_cast<internal::Object**>(that);
return reinterpret_cast<T*>(
@@ -5662,8 +5552,20 @@
}
-template <class T>
-bool Persistent<T>::IsIndependent() const {
+template <class T, class M>
+template <class S, class M2>
+void Persistent<T, M>::Copy(const Persistent<S, M2>& that) {
+ TYPE_CHECK(T, S);
+ Reset();
+ if (that.IsEmpty()) return;
+ internal::Object** p = reinterpret_cast<internal::Object**>(that.val_);
+ this->val_ = reinterpret_cast<T*>(V8::CopyPersistent(p));
+ M::Copy(that, this);
+}
+
+
+template <class T, class M>
+bool Persistent<T, M>::IsIndependent() const {
typedef internal::Internals I;
if (this->IsEmpty()) return false;
return I::GetNodeFlag(reinterpret_cast<internal::Object**>(this->val_),
@@ -5671,8 +5573,8 @@
}
-template <class T>
-bool Persistent<T>::IsNearDeath() const {
+template <class T, class M>
+bool Persistent<T, M>::IsNearDeath() const {
typedef internal::Internals I;
if (this->IsEmpty()) return false;
uint8_t node_state =
@@ -5682,8 +5584,8 @@
}
-template <class T>
-bool Persistent<T>::IsWeak() const {
+template <class T, class M>
+bool Persistent<T, M>::IsWeak() const {
typedef internal::Internals I;
if (this->IsEmpty()) return false;
return I::GetNodeState(reinterpret_cast<internal::Object**>(this->val_)) ==
@@ -5691,66 +5593,89 @@
}
-template <class T>
-void Persistent<T>::Dispose() {
+template <class T, class M>
+void Persistent<T, M>::Reset() {
if (this->IsEmpty()) return;
V8::DisposeGlobal(reinterpret_cast<internal::Object**>(this->val_));
-#ifndef V8_USE_UNSAFE_HANDLES
val_ = 0;
-#endif
}
-template <class T>
+template <class T, class M>
+template <class S>
+void Persistent<T, M>::Reset(Isolate* isolate, const Handle<S>& other) {
+ TYPE_CHECK(T, S);
+ Reset();
+ if (other.IsEmpty()) return;
+ this->val_ = New(isolate, other.val_);
+}
+
+
+template <class T, class M>
+template <class S, class M2>
+void Persistent<T, M>::Reset(Isolate* isolate,
+ const Persistent<S, M2>& other) {
+ TYPE_CHECK(T, S);
+ Reset();
+ if (other.IsEmpty()) return;
+ this->val_ = New(isolate, other.val_);
+}
+
+
+template <class T, class M>
template <typename S, typename P>
-void Persistent<T>::MakeWeak(
+void Persistent<T, M>::SetWeak(
+ P* parameter,
+ typename WeakCallbackData<S, P>::Callback callback) {
+ TYPE_CHECK(S, T);
+ typedef typename WeakCallbackData<Value, void>::Callback Callback;
+ V8::MakeWeak(reinterpret_cast<internal::Object**>(this->val_),
+ parameter,
+ reinterpret_cast<Callback>(callback),
+ NULL);
+}
+
+
+template <class T, class M>
+template <typename P>
+void Persistent<T, M>::SetWeak(
+ P* parameter,
+ typename WeakCallbackData<T, P>::Callback callback) {
+ SetWeak<T, P>(parameter, callback);
+}
+
+
+template <class T, class M>
+template <typename S, typename P>
+void Persistent<T, M>::MakeWeak(
P* parameters,
typename WeakReferenceCallbacks<S, P>::Revivable callback) {
TYPE_CHECK(S, T);
typedef typename WeakReferenceCallbacks<Value, void>::Revivable Revivable;
V8::MakeWeak(reinterpret_cast<internal::Object**>(this->val_),
parameters,
+ NULL,
reinterpret_cast<Revivable>(callback));
}
-template <class T>
+template <class T, class M>
template <typename P>
-void Persistent<T>::MakeWeak(
+void Persistent<T, M>::MakeWeak(
P* parameters,
typename WeakReferenceCallbacks<T, P>::Revivable callback) {
MakeWeak<T, P>(parameters, callback);
}
-template <class T>
-template <typename S, typename P>
-void Persistent<T>::MakeWeak(
- Isolate* isolate,
- P* parameters,
- typename WeakReferenceCallbacks<S, P>::Revivable callback) {
- MakeWeak<S, P>(parameters, callback);
-}
-
-
-template <class T>
-template<typename P>
-void Persistent<T>::MakeWeak(
- Isolate* isolate,
- P* parameters,
- typename WeakReferenceCallbacks<T, P>::Revivable callback) {
- MakeWeak<P>(parameters, callback);
-}
-
-
-template <class T>
-void Persistent<T>::ClearWeak() {
+template <class T, class M>
+void Persistent<T, M>::ClearWeak() {
V8::ClearWeak(reinterpret_cast<internal::Object**>(this->val_));
}
-template <class T>
-void Persistent<T>::MarkIndependent() {
+template <class T, class M>
+void Persistent<T, M>::MarkIndependent() {
typedef internal::Internals I;
if (this->IsEmpty()) return;
I::UpdateNodeFlag(reinterpret_cast<internal::Object**>(this->val_),
@@ -5759,8 +5684,8 @@
}
-template <class T>
-void Persistent<T>::MarkPartiallyDependent() {
+template <class T, class M>
+void Persistent<T, M>::MarkPartiallyDependent() {
typedef internal::Internals I;
if (this->IsEmpty()) return;
I::UpdateNodeFlag(reinterpret_cast<internal::Object**>(this->val_),
@@ -5769,54 +5694,17 @@
}
-template <class T>
-void Persistent<T>::Reset(Isolate* isolate, const Handle<T>& other) {
- Dispose();
-#ifdef V8_USE_UNSAFE_HANDLES
- *this = *New(isolate, other);
-#else
- if (other.IsEmpty()) {
- this->val_ = NULL;
- return;
- }
- internal::Object** p = reinterpret_cast<internal::Object**>(other.val_);
- this->val_ = reinterpret_cast<T*>(
- V8::GlobalizeReference(reinterpret_cast<internal::Isolate*>(isolate), p));
-#endif
-}
-
-
-#ifndef V8_USE_UNSAFE_HANDLES
-template <class T>
-void Persistent<T>::Reset(Isolate* isolate, const Persistent<T>& other) {
- Dispose();
- if (other.IsEmpty()) {
- this->val_ = NULL;
- return;
- }
- internal::Object** p = reinterpret_cast<internal::Object**>(other.val_);
- this->val_ = reinterpret_cast<T*>(
- V8::GlobalizeReference(reinterpret_cast<internal::Isolate*>(isolate), p));
-}
-#endif
-
-
-template <class T>
-T* Persistent<T>::ClearAndLeak() {
+template <class T, class M>
+T* Persistent<T, M>::ClearAndLeak() {
T* old;
-#ifdef V8_USE_UNSAFE_HANDLES
- old = **this;
- *this = Persistent<T>();
-#else
old = val_;
val_ = NULL;
-#endif
return old;
}
-template <class T>
-void Persistent<T>::SetWrapperClassId(uint16_t class_id) {
+template <class T, class M>
+void Persistent<T, M>::SetWrapperClassId(uint16_t class_id) {
typedef internal::Internals I;
if (this->IsEmpty()) return;
internal::Object** obj = reinterpret_cast<internal::Object**>(this->val_);
@@ -5825,8 +5713,8 @@
}
-template <class T>
-uint16_t Persistent<T>::WrapperClassId() const {
+template <class T, class M>
+uint16_t Persistent<T, M>::WrapperClassId() const {
typedef internal::Internals I;
if (this->IsEmpty()) return 0;
internal::Object** obj = reinterpret_cast<internal::Object**>(this->val_);
diff --git a/src/api.cc b/src/api.cc
index ad75715..1bc80d2 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -660,11 +660,22 @@
}
+i::Object** V8::CopyPersistent(i::Object** obj) {
+ i::Handle<i::Object> result = i::GlobalHandles::CopyGlobal(obj);
+#ifdef DEBUG
+ (*obj)->Verify();
+#endif // DEBUG
+ return result.location();
+}
+
+
void V8::MakeWeak(i::Object** object,
void* parameters,
+ WeakCallback weak_callback,
RevivableCallback weak_reference_callback) {
i::GlobalHandles::MakeWeak(object,
parameters,
+ weak_callback,
weak_reference_callback);
}
@@ -1052,6 +1063,37 @@
}
+static Local<FunctionTemplate> FunctionTemplateNew(
+ i::Isolate* isolate,
+ FunctionCallback callback,
+ v8::Handle<Value> data,
+ v8::Handle<Signature> signature,
+ int length,
+ bool do_not_cache) {
+ i::Handle<i::Struct> struct_obj =
+ isolate->factory()->NewStruct(i::FUNCTION_TEMPLATE_INFO_TYPE);
+ i::Handle<i::FunctionTemplateInfo> obj =
+ i::Handle<i::FunctionTemplateInfo>::cast(struct_obj);
+ InitializeFunctionTemplate(obj);
+ obj->set_do_not_cache(do_not_cache);
+ int next_serial_number = 0;
+ if (!do_not_cache) {
+ next_serial_number = isolate->next_serial_number() + 1;
+ isolate->set_next_serial_number(next_serial_number);
+ }
+ obj->set_serial_number(i::Smi::FromInt(next_serial_number));
+ if (callback != 0) {
+ if (data.IsEmpty()) data = v8::Undefined();
+ Utils::ToLocal(obj)->SetCallHandler(callback, data);
+ }
+ obj->set_length(length);
+ obj->set_undetectable(false);
+ obj->set_needs_access_check(false);
+ if (!signature.IsEmpty())
+ obj->set_signature(*Utils::OpenHandle(*signature));
+ return Utils::ToLocal(obj);
+}
+
Local<FunctionTemplate> FunctionTemplate::New(
FunctionCallback callback,
v8::Handle<Value> data,
@@ -1061,25 +1103,8 @@
EnsureInitializedForIsolate(isolate, "v8::FunctionTemplate::New()");
LOG_API(isolate, "FunctionTemplate::New");
ENTER_V8(isolate);
- i::Handle<i::Struct> struct_obj =
- isolate->factory()->NewStruct(i::FUNCTION_TEMPLATE_INFO_TYPE);
- i::Handle<i::FunctionTemplateInfo> obj =
- i::Handle<i::FunctionTemplateInfo>::cast(struct_obj);
- InitializeFunctionTemplate(obj);
- int next_serial_number = isolate->next_serial_number();
- isolate->set_next_serial_number(next_serial_number + 1);
- obj->set_serial_number(i::Smi::FromInt(next_serial_number));
- if (callback != 0) {
- if (data.IsEmpty()) data = v8::Undefined();
- Utils::ToLocal(obj)->SetCallHandler(callback, data);
- }
- obj->set_length(length);
- obj->set_undetectable(false);
- obj->set_needs_access_check(false);
-
- if (!signature.IsEmpty())
- obj->set_signature(*Utils::OpenHandle(*signature));
- return Utils::ToLocal(obj);
+ return FunctionTemplateNew(
+ isolate, callback, data, signature, length, false);
}
@@ -4189,6 +4214,19 @@
}
+Local<Function> Function::New(Isolate* v8_isolate,
+ FunctionCallback callback,
+ Local<Value> data,
+ int length) {
+ i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
+ LOG_API(isolate, "Function::New");
+ ENTER_V8(isolate);
+ return FunctionTemplateNew(
+ isolate, callback, data, Local<Signature>(), length, true)->
+ GetFunction();
+}
+
+
Local<v8::Object> Function::NewInstance() const {
return NewInstance(0, NULL);
}
@@ -5408,26 +5446,6 @@
return env;
}
-#ifdef V8_USE_UNSAFE_HANDLES
-Persistent<Context> v8::Context::New(
- v8::ExtensionConfiguration* extensions,
- v8::Handle<ObjectTemplate> global_template,
- v8::Handle<Value> global_object) {
- i::Isolate::EnsureDefaultIsolate();
- i::Isolate* isolate = i::Isolate::Current();
- Isolate* external_isolate = reinterpret_cast<Isolate*>(isolate);
- EnsureInitializedForIsolate(isolate, "v8::Context::New()");
- LOG_API(isolate, "Context::New");
- ON_BAILOUT(isolate, "v8::Context::New()", return Persistent<Context>());
- i::HandleScope scope(isolate);
- i::Handle<i::Context> env =
- CreateEnvironment(isolate, extensions, global_template, global_object);
- if (env.is_null()) return Persistent<Context>();
- return Persistent<Context>::New(external_isolate, Utils::ToLocal(env));
-}
-#endif
-
-
Local<Context> v8::Context::New(
v8::Isolate* external_isolate,
v8::ExtensionConfiguration* extensions,
@@ -6772,29 +6790,6 @@
}
-int V8::GetCurrentThreadId() {
- i::Isolate* isolate = i::Isolate::Current();
- EnsureInitializedForIsolate(isolate, "V8::GetCurrentThreadId()");
- return isolate->thread_id().ToInteger();
-}
-
-
-void V8::TerminateExecution(int thread_id) {
- i::Isolate* isolate = i::Isolate::Current();
- if (!isolate->IsInitialized()) return;
- API_ENTRY_CHECK(isolate, "V8::TerminateExecution()");
- // If the thread_id identifies the current thread just terminate
- // execution right away. Otherwise, ask the thread manager to
- // terminate the thread with the given id if any.
- i::ThreadId internal_tid = i::ThreadId::FromInteger(thread_id);
- if (isolate->thread_id().Equals(internal_tid)) {
- isolate->stack_guard()->TerminateExecution();
- } else {
- isolate->thread_manager()->TerminateExecution(internal_tid);
- }
-}
-
-
void V8::TerminateExecution(Isolate* isolate) {
// If no isolate is supplied, use the default isolate.
if (isolate != NULL) {
@@ -7888,7 +7883,7 @@
getter));
VMState<EXTERNAL> state(isolate);
ExternalCallbackScope call_scope(isolate, getter_address);
- return getter(property, info);
+ getter(property, info);
}
@@ -7899,7 +7894,7 @@
reinterpret_cast<Address>(reinterpret_cast<intptr_t>(callback));
VMState<EXTERNAL> state(isolate);
ExternalCallbackScope call_scope(isolate, callback_address);
- return callback(info);
+ callback(info);
}
diff --git a/src/apinatives.js b/src/apinatives.js
index 7adeb7e..5fb36c0 100644
--- a/src/apinatives.js
+++ b/src/apinatives.js
@@ -74,8 +74,9 @@
cache[serialNumber] = null;
var fun = %CreateApiFunction(data);
if (name) %FunctionSetName(fun, name);
- cache[serialNumber] = fun;
var flags = %GetTemplateField(data, kApiFlagOffset);
+ var doNotCache = flags & (1 << kDoNotCacheBit);
+ if (!doNotCache) cache[serialNumber] = fun;
if (flags & (1 << kRemovePrototypeBit)) {
%FunctionRemovePrototype(fun);
} else {
@@ -97,6 +98,7 @@
}
}
ConfigureTemplateInstance(fun, data);
+ if (doNotCache) return fun;
} catch (e) {
cache[serialNumber] = kUninitialized;
throw e;
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index f9e21f7..132e1a6 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -1511,20 +1511,39 @@
if (instr->representation().IsSmiOrInteger32()) {
ASSERT(instr->left()->representation().Equals(instr->representation()));
ASSERT(instr->right()->representation().Equals(instr->representation()));
- LOperand* left;
- LOperand* right = UseOrConstant(instr->BetterRightOperand());
- LOperand* temp = NULL;
- if (instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
- (instr->CheckFlag(HValue::kCanOverflow) ||
- !right->IsConstantOperand())) {
- left = UseRegister(instr->BetterLeftOperand());
- temp = TempRegister();
+ HValue* left = instr->BetterLeftOperand();
+ HValue* right = instr->BetterRightOperand();
+ LOperand* left_op;
+ LOperand* right_op;
+ bool can_overflow = instr->CheckFlag(HValue::kCanOverflow);
+ bool bailout_on_minus_zero = instr->CheckFlag(HValue::kBailoutOnMinusZero);
+
+ if (right->IsConstant()) {
+ HConstant* constant = HConstant::cast(right);
+ int32_t constant_value = constant->Integer32Value();
+ // Constants -1, 0 and 1 can be optimized if the result can overflow.
+ // For other constants, it can be optimized only without overflow.
+ if (!can_overflow || ((constant_value >= -1) && (constant_value <= 1))) {
+ left_op = UseRegisterAtStart(left);
+ right_op = UseConstant(right);
+ } else {
+ if (bailout_on_minus_zero) {
+ left_op = UseRegister(left);
+ } else {
+ left_op = UseRegisterAtStart(left);
+ }
+ right_op = UseRegister(right);
+ }
} else {
- left = UseRegisterAtStart(instr->BetterLeftOperand());
+ if (bailout_on_minus_zero) {
+ left_op = UseRegister(left);
+ } else {
+ left_op = UseRegisterAtStart(left);
+ }
+ right_op = UseRegister(right);
}
- LMulI* mul = new(zone()) LMulI(left, right, temp);
- if (instr->CheckFlag(HValue::kCanOverflow) ||
- instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ LMulI* mul = new(zone()) LMulI(left_op, right_op);
+ if (can_overflow || bailout_on_minus_zero) {
AssignEnvironment(mul);
}
return DefineAsRegister(mul);
diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
index 781dcf4..f90f3c4 100644
--- a/src/arm/lithium-arm.h
+++ b/src/arm/lithium-arm.h
@@ -677,17 +677,15 @@
};
-class LMulI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
+class LMulI V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
- LMulI(LOperand* left, LOperand* right, LOperand* temp) {
+ LMulI(LOperand* left, LOperand* right) {
inputs_[0] = left;
inputs_[1] = right;
- temps_[0] = temp;
}
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
- LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(MulI, "mul-i")
DECLARE_HYDROGEN_ACCESSOR(Mul)
@@ -1286,7 +1284,9 @@
DECLARE_CONCRETE_INSTRUCTION(ConstantT, "constant-t")
DECLARE_HYDROGEN_ACCESSOR(Constant)
- Handle<Object> value() const { return hydrogen()->handle(); }
+ Handle<Object> value(Isolate* isolate) const {
+ return hydrogen()->handle(isolate);
+ }
};
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index ae24210..d880286 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -423,7 +423,7 @@
} else if (op->IsConstantOperand()) {
LConstantOperand* const_op = LConstantOperand::cast(op);
HConstant* constant = chunk_->LookupConstant(const_op);
- Handle<Object> literal = constant->handle();
+ Handle<Object> literal = constant->handle(isolate());
Representation r = chunk_->LookupLiteralRepresentation(const_op);
if (r.IsInteger32()) {
ASSERT(literal->IsNumber());
@@ -458,7 +458,7 @@
} else if (op->IsConstantOperand()) {
LConstantOperand* const_op = LConstantOperand::cast(op);
HConstant* constant = chunk_->LookupConstant(const_op);
- Handle<Object> literal = constant->handle();
+ Handle<Object> literal = constant->handle(isolate());
Representation r = chunk_->LookupLiteralRepresentation(const_op);
if (r.IsInteger32()) {
ASSERT(literal->IsNumber());
@@ -486,7 +486,7 @@
Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
HConstant* constant = chunk_->LookupConstant(op);
ASSERT(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged());
- return constant->handle();
+ return constant->handle(isolate());
}
@@ -543,7 +543,7 @@
Abort(kToOperandUnsupportedDoubleImmediate);
}
ASSERT(r.IsTagged());
- return Operand(constant->handle());
+ return Operand(constant->handle(isolate()));
} else if (op->IsRegister()) {
return Operand(ToRegister(op));
} else if (op->IsDoubleRegister()) {
@@ -690,7 +690,7 @@
translation->StoreDoubleRegister(reg);
} else if (op->IsConstantOperand()) {
HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op));
- int src_index = DefineDeoptimizationLiteral(constant->handle());
+ int src_index = DefineDeoptimizationLiteral(constant->handle(isolate()));
translation->StoreLiteral(src_index);
} else {
UNREACHABLE();
@@ -1573,17 +1573,16 @@
void LCodeGen::DoMulI(LMulI* instr) {
- Register scratch = scratch0();
Register result = ToRegister(instr->result());
// Note that result may alias left.
Register left = ToRegister(instr->left());
LOperand* right_op = instr->right();
- bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
bool bailout_on_minus_zero =
instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
+ bool overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
- if (right_op->IsConstantOperand() && !can_overflow) {
+ if (right_op->IsConstantOperand()) {
int32_t constant = ToInteger32(LConstantOperand::cast(right_op));
if (bailout_on_minus_zero && (constant < 0)) {
@@ -1595,7 +1594,12 @@
switch (constant) {
case -1:
- __ rsb(result, left, Operand::Zero());
+ if (overflow) {
+ __ rsb(result, left, Operand::Zero(), SetCC);
+ DeoptimizeIf(vs, instr->environment());
+ } else {
+ __ rsb(result, left, Operand::Zero());
+ }
break;
case 0:
if (bailout_on_minus_zero) {
@@ -1616,23 +1620,21 @@
int32_t mask = constant >> 31;
uint32_t constant_abs = (constant + mask) ^ mask;
- if (IsPowerOf2(constant_abs) ||
- IsPowerOf2(constant_abs - 1) ||
- IsPowerOf2(constant_abs + 1)) {
- if (IsPowerOf2(constant_abs)) {
- int32_t shift = WhichPowerOf2(constant_abs);
- __ mov(result, Operand(left, LSL, shift));
- } else if (IsPowerOf2(constant_abs - 1)) {
- int32_t shift = WhichPowerOf2(constant_abs - 1);
- __ add(result, left, Operand(left, LSL, shift));
- } else if (IsPowerOf2(constant_abs + 1)) {
- int32_t shift = WhichPowerOf2(constant_abs + 1);
- __ rsb(result, left, Operand(left, LSL, shift));
- }
-
+ if (IsPowerOf2(constant_abs)) {
+ int32_t shift = WhichPowerOf2(constant_abs);
+ __ mov(result, Operand(left, LSL, shift));
// Correct the sign of the result is the constant is negative.
if (constant < 0) __ rsb(result, result, Operand::Zero());
-
+ } else if (IsPowerOf2(constant_abs - 1)) {
+ int32_t shift = WhichPowerOf2(constant_abs - 1);
+ __ add(result, left, Operand(left, LSL, shift));
+ // Correct the sign of the result is the constant is negative.
+ if (constant < 0) __ rsb(result, result, Operand::Zero());
+ } else if (IsPowerOf2(constant_abs + 1)) {
+ int32_t shift = WhichPowerOf2(constant_abs + 1);
+ __ rsb(result, left, Operand(left, LSL, shift));
+ // Correct the sign of the result is the constant is negative.
+ if (constant < 0) __ rsb(result, result, Operand::Zero());
} else {
// Generate standard code.
__ mov(ip, Operand(constant));
@@ -1641,12 +1643,11 @@
}
} else {
- Register right = EmitLoadRegister(right_op, scratch);
- if (bailout_on_minus_zero) {
- __ orr(ToRegister(instr->temp()), left, right);
- }
+ ASSERT(right_op->IsRegister());
+ Register right = ToRegister(right_op);
- if (can_overflow) {
+ if (overflow) {
+ Register scratch = scratch0();
// scratch:result = left * right.
if (instr->hydrogen()->representation().IsSmi()) {
__ SmiUntag(result, left);
@@ -1666,12 +1667,12 @@
}
if (bailout_on_minus_zero) {
- // Bail out if the result is supposed to be negative zero.
Label done;
+ __ teq(left, Operand(right));
+ __ b(pl, &done);
+ // Bail out if the result is minus zero.
__ cmp(result, Operand::Zero());
- __ b(ne, &done);
- __ cmp(ToRegister(instr->temp()), Operand::Zero());
- DeoptimizeIf(mi, instr->environment());
+ DeoptimizeIf(eq, instr->environment());
__ bind(&done);
}
}
@@ -1868,7 +1869,7 @@
void LCodeGen::DoConstantT(LConstantT* instr) {
- Handle<Object> value = instr->value();
+ Handle<Object> value = instr->value(isolate());
AllowDeferredHandleDereference smi_check;
__ LoadObject(ToRegister(instr->result()), value);
}
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index cb02931..c1c87d9 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -924,6 +924,35 @@
}
+// Generate call to api function.
+static void GenerateFastApiCall(MacroAssembler* masm,
+ const CallOptimization& optimization,
+ Register receiver,
+ Register scratch,
+ int argc,
+ Register* values) {
+ ASSERT(optimization.is_simple_api_call());
+ ASSERT(!receiver.is(scratch));
+
+ const int stack_space = kFastApiCallArguments + argc + 1;
+ // Assign stack space for the call arguments.
+ __ sub(sp, sp, Operand(stack_space * kPointerSize));
+ // Write holder to stack frame.
+ __ str(receiver, MemOperand(sp, 0));
+ // Write receiver to stack frame.
+ int index = stack_space - 1;
+ __ str(receiver, MemOperand(sp, index * kPointerSize));
+ // Write the arguments to stack frame.
+ for (int i = 0; i < argc; i++) {
+ ASSERT(!receiver.is(values[i]));
+ ASSERT(!scratch.is(values[i]));
+ __ str(receiver, MemOperand(sp, index-- * kPointerSize));
+ }
+
+ GenerateFastApiDirectCall(masm, optimization, argc);
+}
+
+
class CallInterceptorCompiler BASE_EMBEDDED {
public:
CallInterceptorCompiler(StubCompiler* stub_compiler,
@@ -1381,19 +1410,8 @@
void BaseLoadStubCompiler::GenerateLoadCallback(
const CallOptimization& call_optimization) {
- ASSERT(call_optimization.is_simple_api_call());
-
- // Assign stack space for the call arguments.
- __ sub(sp, sp, Operand((kFastApiCallArguments + 1) * kPointerSize));
-
- int argc = 0;
- int api_call_argc = argc + kFastApiCallArguments;
- // Write holder to stack frame.
- __ str(receiver(), MemOperand(sp, 0));
- // Write receiver to stack frame.
- __ str(receiver(), MemOperand(sp, api_call_argc * kPointerSize));
-
- GenerateFastApiDirectCall(masm(), call_optimization, argc);
+ GenerateFastApiCall(
+ masm(), call_optimization, receiver(), scratch3(), 0, NULL);
}
@@ -2793,6 +2811,24 @@
}
+Handle<Code> StoreStubCompiler::CompileStoreCallback(
+ Handle<JSObject> object,
+ Handle<JSObject> holder,
+ Handle<Name> name,
+ const CallOptimization& call_optimization) {
+ Label success;
+ HandlerFrontend(object, receiver(), holder, name, &success);
+ __ bind(&success);
+
+ Register values[] = { value() };
+ GenerateFastApiCall(
+ masm(), call_optimization, receiver(), scratch3(), 1, values);
+
+ // Return the generated code.
+ return GetCode(kind(), Code::CALLBACKS, name);
+}
+
+
#undef __
#define __ ACCESS_MASM(masm)
diff --git a/src/ast.cc b/src/ast.cc
index cbadb75..6d1dc12 100644
--- a/src/ast.cc
+++ b/src/ast.cc
@@ -646,8 +646,15 @@
Literal* key = property->key()->AsLiteral();
ASSERT(key != NULL && key->value()->IsString());
Handle<String> name = Handle<String>::cast(key->value());
+ check_type_ = oracle->GetCallCheckType(this);
receiver_types_.Clear();
- oracle->CallReceiverTypes(this, name, call_kind, &receiver_types_);
+ if (check_type_ == RECEIVER_MAP_CHECK) {
+ oracle->CallReceiverTypes(this, name, call_kind, &receiver_types_);
+ is_monomorphic_ = is_monomorphic_ && receiver_types_.length() > 0;
+ } else {
+ holder_ = GetPrototypeForPrimitiveCheck(check_type_, oracle->isolate());
+ receiver_types_.Add(handle(holder_->map()), oracle->zone());
+ }
#ifdef DEBUG
if (FLAG_enable_slow_asserts) {
int length = receiver_types_.length();
@@ -657,17 +664,8 @@
}
}
#endif
- check_type_ = oracle->GetCallCheckType(this);
if (is_monomorphic_) {
- Handle<Map> map;
- if (receiver_types_.length() > 0) {
- ASSERT(check_type_ == RECEIVER_MAP_CHECK);
- map = receiver_types_.at(0);
- } else {
- ASSERT(check_type_ != RECEIVER_MAP_CHECK);
- holder_ = GetPrototypeForPrimitiveCheck(check_type_, oracle->isolate());
- map = Handle<Map>(holder_->map());
- }
+ Handle<Map> map = receiver_types_.first();
is_monomorphic_ = ComputeTarget(map, name);
}
}
diff --git a/src/ast.h b/src/ast.h
index d0454fb..c630906 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -288,6 +288,14 @@
Add(map, zone);
}
+ void FilterForPossibleTransitions(Map* root_map) {
+ for (int i = list_.length() - 1; i >= 0; i--) {
+ if (at(i)->FindRootMap() != root_map) {
+ list_.RemoveElement(list_.at(i));
+ }
+ }
+ }
+
void Add(Handle<Map> handle, Zone* zone) {
list_.Add(handle.location(), zone);
}
@@ -366,12 +374,6 @@
UNREACHABLE();
return NULL;
}
- Handle<Map> GetMonomorphicReceiverType() {
- ASSERT(IsMonomorphic());
- SmallMapList* types = GetReceiverTypes();
- ASSERT(types != NULL && types->length() == 1);
- return types->at(0);
- }
virtual KeyedAccessStoreMode GetStoreMode() {
UNREACHABLE();
return STANDARD_STORE;
diff --git a/src/cpu-profiler.cc b/src/cpu-profiler.cc
index 6e93b64..74e0d82 100644
--- a/src/cpu-profiler.cc
+++ b/src/cpu-profiler.cc
@@ -103,50 +103,54 @@
return false;
}
-
-bool ProfilerEventsProcessor::ProcessTicks() {
- while (true) {
- while (!ticks_from_vm_buffer_.IsEmpty()
- && ticks_from_vm_buffer_.Peek()->order ==
- last_processed_code_event_id_) {
- TickSampleEventRecord record;
- ticks_from_vm_buffer_.Dequeue(&record);
- generator_->RecordTickSample(record.sample);
- }
-
- const TickSampleEventRecord* record = ticks_buffer_.Peek();
- if (record == NULL) return !ticks_from_vm_buffer_.IsEmpty();
- if (record->order != last_processed_code_event_id_) return true;
- generator_->RecordTickSample(record->sample);
- ticks_buffer_.Remove();
+ProfilerEventsProcessor::SampleProcessingResult
+ ProfilerEventsProcessor::ProcessOneSample() {
+ if (!ticks_from_vm_buffer_.IsEmpty()
+ && ticks_from_vm_buffer_.Peek()->order ==
+ last_processed_code_event_id_) {
+ TickSampleEventRecord record;
+ ticks_from_vm_buffer_.Dequeue(&record);
+ generator_->RecordTickSample(record.sample);
+ return OneSampleProcessed;
}
-}
-
-void ProfilerEventsProcessor::ProcessEventsAndDoSample() {
- ElapsedTimer timer;
- timer.Start();
- // Keep processing existing events until we need to do next sample.
- while (!timer.HasExpired(period_)) {
- if (ProcessTicks()) {
- // All ticks of the current dequeue_order are processed,
- // proceed to the next code event.
- ProcessCodeEvent();
- }
+ const TickSampleEventRecord* record = ticks_buffer_.Peek();
+ if (record == NULL) {
+ if (ticks_from_vm_buffer_.IsEmpty()) return NoSamplesInQueue;
+ return FoundSampleForNextCodeEvent;
}
- // Schedule next sample. sampler_ is NULL in tests.
- if (sampler_) sampler_->DoSample();
+ if (record->order != last_processed_code_event_id_) {
+ return FoundSampleForNextCodeEvent;
+ }
+ generator_->RecordTickSample(record->sample);
+ ticks_buffer_.Remove();
+ return OneSampleProcessed;
}
void ProfilerEventsProcessor::Run() {
while (running_) {
- ProcessEventsAndDoSample();
+ ElapsedTimer timer;
+ timer.Start();
+ // Keep processing existing events until we need to do next sample.
+ do {
+ if (FoundSampleForNextCodeEvent == ProcessOneSample()) {
+ // All ticks of the current last_processed_code_event_id_ are
+ // processed, proceed to the next code event.
+ ProcessCodeEvent();
+ }
+ } while (!timer.HasExpired(period_));
+
+ // Schedule next sample. sampler_ is NULL in tests.
+ if (sampler_) sampler_->DoSample();
}
// Process remaining tick events.
do {
- ProcessTicks();
+ SampleProcessingResult result;
+ do {
+ result = ProcessOneSample();
+ } while (result == OneSampleProcessed);
} while (ProcessCodeEvent());
}
diff --git a/src/cpu-profiler.h b/src/cpu-profiler.h
index e36c301..8aba542 100644
--- a/src/cpu-profiler.h
+++ b/src/cpu-profiler.h
@@ -161,9 +161,13 @@
private:
// Called from events processing thread (Run() method.)
bool ProcessCodeEvent();
- bool ProcessTicks();
- void ProcessEventsAndDoSample();
+ enum SampleProcessingResult {
+ OneSampleProcessed,
+ FoundSampleForNextCodeEvent,
+ NoSamplesInQueue
+ };
+ SampleProcessingResult ProcessOneSample();
ProfileGenerator* generator_;
Sampler* sampler_;
diff --git a/src/debug-debugger.js b/src/debug-debugger.js
index a588b4c..19209d4 100644
--- a/src/debug-debugger.js
+++ b/src/debug-debugger.js
@@ -957,12 +957,17 @@
this.selected_frame = 0;
}
-ExecutionState.prototype.prepareStep = function(opt_action, opt_count) {
+ExecutionState.prototype.prepareStep = function(opt_action, opt_count,
+ opt_callframe) {
var action = Debug.StepAction.StepIn;
if (!IS_UNDEFINED(opt_action)) action = %ToNumber(opt_action);
var count = opt_count ? %ToNumber(opt_count) : 1;
+ var callFrameId = 0;
+ if (!IS_UNDEFINED(opt_callframe)) {
+ callFrameId = opt_callframe.details_.frameId();
+ }
- return %PrepareStep(this.break_id, action, count);
+ return %PrepareStep(this.break_id, action, count, callFrameId);
};
ExecutionState.prototype.evaluateGlobal = function(source, disable_break,
diff --git a/src/debug.cc b/src/debug.cc
index c82a2aa..7624f26 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -1017,7 +1017,7 @@
// Clear queue
thread_local_.queued_step_count_ = 0;
- PrepareStep(StepNext, step_count);
+ PrepareStep(StepNext, step_count, StackFrame::NO_ID);
} else {
// Notify the debug event listeners.
isolate_->debugger()->OnDebugBreak(break_points_hit, false);
@@ -1055,7 +1055,7 @@
ClearStepping();
// Set up for the remaining steps.
- PrepareStep(step_action, step_count);
+ PrepareStep(step_action, step_count, StackFrame::NO_ID);
}
if (thread_local_.frame_drop_mode_ == FRAMES_UNTOUCHED) {
@@ -1376,7 +1376,9 @@
}
-void Debug::PrepareStep(StepAction step_action, int step_count) {
+void Debug::PrepareStep(StepAction step_action,
+ int step_count,
+ StackFrame::Id frame_id) {
HandleScope scope(isolate_);
PrepareForBreakPoints();
@@ -1402,6 +1404,9 @@
// If there is no JavaScript stack don't do anything.
return;
}
+ if (frame_id != StackFrame::NO_ID) {
+ id = frame_id;
+ }
JavaScriptFrameIterator frames_it(isolate_, id);
JavaScriptFrame* frame = frames_it.frame();
diff --git a/src/debug.h b/src/debug.h
index 85f7583..03ee40e 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -261,7 +261,9 @@
void FloodHandlerWithOneShot();
void ChangeBreakOnException(ExceptionBreakType type, bool enable);
bool IsBreakOnException(ExceptionBreakType type);
- void PrepareStep(StepAction step_action, int step_count);
+ void PrepareStep(StepAction step_action,
+ int step_count,
+ StackFrame::Id frame_id);
void ClearStepping();
void ClearStepOut();
bool IsStepping() { return thread_local_.step_count_ > 0; }
diff --git a/src/execution.cc b/src/execution.cc
index 91d340e..c59a737 100644
--- a/src/execution.cc
+++ b/src/execution.cc
@@ -705,12 +705,14 @@
Handle<FunctionTemplateInfo> data,
bool* exc) {
Isolate* isolate = data->GetIsolate();
- // Fast case: see if the function has already been instantiated
- int serial_number = Smi::cast(data->serial_number())->value();
- Object* elm =
- isolate->native_context()->function_cache()->
- GetElementNoExceptionThrown(isolate, serial_number);
- if (elm->IsJSFunction()) return Handle<JSFunction>(JSFunction::cast(elm));
+ if (!data->do_not_cache()) {
+ // Fast case: see if the function has already been instantiated
+ int serial_number = Smi::cast(data->serial_number())->value();
+ Object* elm =
+ isolate->native_context()->function_cache()->
+ GetElementNoExceptionThrown(isolate, serial_number);
+ if (elm->IsJSFunction()) return Handle<JSFunction>(JSFunction::cast(elm));
+ }
// The function has not yet been instantiated in this context; do it.
Handle<Object> args[] = { data };
Handle<Object> result = Call(isolate,
diff --git a/src/global-handles.cc b/src/global-handles.cc
index 4a2aad3..1a98e49 100644
--- a/src/global-handles.cc
+++ b/src/global-handles.cc
@@ -90,7 +90,7 @@
set_partially_dependent(false);
set_in_new_space_list(false);
parameter_or_next_free_.next_free = NULL;
- weak_reference_callback_ = NULL;
+ weak_callback_ = NULL;
}
#endif
@@ -111,7 +111,7 @@
set_partially_dependent(false);
set_state(NORMAL);
parameter_or_next_free_.parameter = NULL;
- weak_reference_callback_ = NULL;
+ weak_callback_ = NULL;
IncreaseBlockUses();
}
@@ -123,7 +123,7 @@
class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
set_independent(false);
set_partially_dependent(false);
- weak_reference_callback_ = NULL;
+ weak_callback_ = NULL;
DecreaseBlockUses();
}
@@ -169,6 +169,13 @@
flags_ = IsInNewSpaceList::update(flags_, v);
}
+ bool is_revivable_callback() {
+ return IsRevivableCallback::decode(flags_);
+ }
+ void set_revivable_callback(bool v) {
+ flags_ = IsRevivableCallback::update(flags_, v);
+ }
+
bool IsNearDeath() const {
// Check for PENDING to ensure correct answer when processing callbacks.
return state() == PENDING || state() == NEAR_DEATH;
@@ -228,11 +235,20 @@
}
void MakeWeak(void* parameter,
- RevivableCallback weak_reference_callback) {
+ WeakCallback weak_callback,
+ RevivableCallback revivable_callback) {
+ ASSERT((weak_callback == NULL) != (revivable_callback == NULL));
ASSERT(state() != FREE);
set_state(WEAK);
set_parameter(parameter);
- weak_reference_callback_ = weak_reference_callback;
+ if (weak_callback != NULL) {
+ weak_callback_ = weak_callback;
+ set_revivable_callback(false);
+ } else {
+ weak_callback_ =
+ reinterpret_cast<WeakCallback>(revivable_callback);
+ set_revivable_callback(true);
+ }
}
void ClearWeakness() {
@@ -243,7 +259,7 @@
bool PostGarbageCollectionProcessing(Isolate* isolate) {
if (state() != Node::PENDING) return false;
- if (weak_reference_callback_ == NULL) {
+ if (weak_callback_ == NULL) {
Release();
return false;
}
@@ -262,9 +278,20 @@
// Leaving V8.
VMState<EXTERNAL> state(isolate);
HandleScope handle_scope(isolate);
- weak_reference_callback_(reinterpret_cast<v8::Isolate*>(isolate),
- reinterpret_cast<Persistent<Value>*>(&object),
- par);
+ if (is_revivable_callback()) {
+ RevivableCallback revivable =
+ reinterpret_cast<RevivableCallback>(weak_callback_);
+ revivable(reinterpret_cast<v8::Isolate*>(isolate),
+ reinterpret_cast<Persistent<Value>*>(&object),
+ par);
+ } else {
+ Handle<Object> handle(*object, isolate);
+ v8::WeakCallbackData<v8::Value, void> data(
+ reinterpret_cast<v8::Isolate*>(isolate),
+ v8::Utils::ToLocal(handle),
+ par);
+ weak_callback_(data);
+ }
}
// Absence of explicit cleanup or revival of weak handle
// in most of the cases would lead to memory leak.
@@ -272,9 +299,10 @@
return true;
}
+ inline GlobalHandles* GetGlobalHandles();
+
private:
inline NodeBlock* FindBlock();
- inline GlobalHandles* GetGlobalHandles();
inline void IncreaseBlockUses();
inline void DecreaseBlockUses();
@@ -297,11 +325,12 @@
class IsIndependent: public BitField<bool, 4, 1> {};
class IsPartiallyDependent: public BitField<bool, 5, 1> {};
class IsInNewSpaceList: public BitField<bool, 6, 1> {};
+ class IsRevivableCallback: public BitField<bool, 7, 1> {};
uint8_t flags_;
// Handle specific callback - might be a weak reference in disguise.
- RevivableCallback weak_reference_callback_;
+ WeakCallback weak_callback_;
// Provided data for callback. In FREE state, this is used for
// the free list link.
@@ -480,6 +509,12 @@
}
+Handle<Object> GlobalHandles::CopyGlobal(Object** location) {
+ ASSERT(location != NULL);
+ return Node::FromLocation(location)->GetGlobalHandles()->Create(*location);
+}
+
+
void GlobalHandles::Destroy(Object** location) {
if (location != NULL) Node::FromLocation(location)->Release();
}
@@ -487,9 +522,10 @@
void GlobalHandles::MakeWeak(Object** location,
void* parameter,
- RevivableCallback weak_reference_callback) {
- ASSERT(weak_reference_callback != NULL);
- Node::FromLocation(location)->MakeWeak(parameter, weak_reference_callback);
+ WeakCallback weak_callback,
+ RevivableCallback revivable_callback) {
+ Node::FromLocation(location)->MakeWeak(
+ parameter, weak_callback, revivable_callback);
}
diff --git a/src/global-handles.h b/src/global-handles.h
index 57cf70e..4b46aac 100644
--- a/src/global-handles.h
+++ b/src/global-handles.h
@@ -128,9 +128,13 @@
// Creates a new global handle that is alive until Destroy is called.
Handle<Object> Create(Object* value);
+ // Copy a global handle
+ static Handle<Object> CopyGlobal(Object** location);
+
// Destroy a global handle.
static void Destroy(Object** location);
+ typedef WeakCallbackData<v8::Value, void>::Callback WeakCallback;
typedef WeakReferenceCallbacks<v8::Value, void>::Revivable RevivableCallback;
// Make the global handle weak and set the callback parameter for the
@@ -141,7 +145,14 @@
// reason is that Smi::FromInt(0) does not change during garage collection.
static void MakeWeak(Object** location,
void* parameter,
- RevivableCallback weak_reference_callback);
+ WeakCallback weak_callback,
+ RevivableCallback revivable_callback);
+
+ static inline void MakeWeak(Object** location,
+ void* parameter,
+ RevivableCallback revivable_callback) {
+ MakeWeak(location, parameter, NULL, revivable_callback);
+ }
void RecordStats(HeapStats* stats);
diff --git a/src/hydrogen-escape-analysis.cc b/src/hydrogen-escape-analysis.cc
index 00cfe27..997e4f9 100644
--- a/src/hydrogen-escape-analysis.cc
+++ b/src/hydrogen-escape-analysis.cc
@@ -31,7 +31,7 @@
namespace internal {
-bool HEscapeAnalysisPhase::HasNoEscapingUses(HValue* value) {
+bool HEscapeAnalysisPhase::HasNoEscapingUses(HValue* value, int size) {
for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) {
HValue* use = it.value();
if (use->HasEscapingOperandAt(it.index())) {
@@ -41,7 +41,15 @@
}
return false;
}
- if (use->RedefinedOperandIndex() == it.index() && !HasNoEscapingUses(use)) {
+ if (use->HasOutOfBoundsAccess(size)) {
+ if (FLAG_trace_escape_analysis) {
+ PrintF("#%d (%s) out of bounds at #%d (%s) @%d\n", value->id(),
+ value->Mnemonic(), use->id(), use->Mnemonic(), it.index());
+ }
+ return false;
+ }
+ int redefined_index = use->RedefinedOperandIndex();
+ if (redefined_index == it.index() && !HasNoEscapingUses(use, size)) {
if (FLAG_trace_escape_analysis) {
PrintF("#%d (%s) escapes redefinition #%d (%s) @%d\n", value->id(),
value->Mnemonic(), use->id(), use->Mnemonic(), it.index());
@@ -59,7 +67,11 @@
HBasicBlock* block = graph()->blocks()->at(i);
for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
HInstruction* instr = it.Current();
- if (instr->IsAllocate() && HasNoEscapingUses(instr)) {
+ if (!instr->IsAllocate()) continue;
+ HAllocate* allocate = HAllocate::cast(instr);
+ if (!allocate->size()->IsInteger32Constant()) continue;
+ int size_in_bytes = allocate->size()->GetInteger32Constant();
+ if (HasNoEscapingUses(instr, size_in_bytes)) {
if (FLAG_trace_escape_analysis) {
PrintF("#%d (%s) is being captured\n", instr->id(),
instr->Mnemonic());
@@ -290,7 +302,6 @@
HAllocate* allocate = HAllocate::cast(captured_.at(i));
// Compute number of scalar values and start with clean slate.
- if (!allocate->size()->IsInteger32Constant()) continue;
int size_in_bytes = allocate->size()->GetInteger32Constant();
number_of_values_ = size_in_bytes / kPointerSize;
number_of_objects_++;
diff --git a/src/hydrogen-escape-analysis.h b/src/hydrogen-escape-analysis.h
index 311a653..3e27cc1 100644
--- a/src/hydrogen-escape-analysis.h
+++ b/src/hydrogen-escape-analysis.h
@@ -49,7 +49,7 @@
private:
void CollectCapturedValues();
- bool HasNoEscapingUses(HValue* value);
+ bool HasNoEscapingUses(HValue* value, int size);
void PerformScalarReplacement();
void AnalyzeDataFlow(HInstruction* instr);
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index cd8755a..2855e8a 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -2575,12 +2575,13 @@
Maybe<HConstant*> HConstant::CopyToTruncatedNumber(Zone* zone) {
HConstant* res = NULL;
- if (handle()->IsBoolean()) {
- res = handle()->BooleanValue() ?
+ Handle<Object> handle = this->handle(zone->isolate());
+ if (handle->IsBoolean()) {
+ res = handle->BooleanValue() ?
new(zone) HConstant(1) : new(zone) HConstant(0);
- } else if (handle()->IsUndefined()) {
+ } else if (handle->IsUndefined()) {
res = new(zone) HConstant(OS::nan_value());
- } else if (handle()->IsNull()) {
+ } else if (handle->IsNull()) {
res = new(zone) HConstant(0);
}
return Maybe<HConstant*>(res != NULL, res);
@@ -2596,7 +2597,7 @@
stream->Add("%p ", reinterpret_cast<void*>(
external_reference_value_.address()));
} else {
- handle()->ShortPrint(stream);
+ handle(Isolate::Current())->ShortPrint(stream);
}
}
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index a6d8915..2bfb284 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -867,6 +867,7 @@
// Escape analysis helpers.
virtual bool HasEscapingOperandAt(int index) { return true; }
+ virtual bool HasOutOfBoundsAccess(int size) { return false; }
// Representation helpers.
virtual Representation observed_input_representation(int index) {
@@ -3285,9 +3286,9 @@
return new_constant;
}
- Handle<Object> handle() {
+ Handle<Object> handle(Isolate* isolate) {
if (handle_.is_null()) {
- Factory* factory = Isolate::Current()->factory();
+ Factory* factory = isolate->factory();
// Default arguments to is_not_in_new_space depend on this heap number
// to be tenured so that it's guaranteed not be be located in new space.
handle_ = factory->NewNumber(double_value_, TENURED);
@@ -3298,7 +3299,7 @@
}
bool HasMap(Handle<Map> map) {
- Handle<Object> constant_object = handle();
+ Handle<Object> constant_object = handle(map->GetIsolate());
return constant_object->IsHeapObject() &&
Handle<HeapObject>::cast(constant_object)->map() == *map;
}
@@ -3358,7 +3359,6 @@
virtual bool EmitAtUses() V8_OVERRIDE;
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
- bool IsInteger() { return handle()->IsSmi(); }
HConstant* CopyToRepresentation(Representation r, Zone* zone) const;
Maybe<HConstant*> CopyToTruncatedInt32(Zone* zone);
Maybe<HConstant*> CopyToTruncatedNumber(Zone* zone);
@@ -5756,6 +5756,9 @@
}
virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; }
+ virtual bool HasOutOfBoundsAccess(int size) V8_OVERRIDE {
+ return !access().IsInobject() || access().offset() >= size;
+ }
virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
if (index == 0 && access().IsExternalMemory()) {
// object must be external in case of external memory access
@@ -6071,6 +6074,9 @@
virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE {
return index == 1;
}
+ virtual bool HasOutOfBoundsAccess(int size) V8_OVERRIDE {
+ return !access().IsInobject() || access().offset() >= size;
+ }
virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
if (index == 0 && access().IsExternalMemory()) {
// object must be external in case of external memory access
@@ -6105,7 +6111,8 @@
Handle<Map> transition_map() const {
if (has_transition()) {
- return Handle<Map>::cast(HConstant::cast(transition())->handle());
+ return Handle<Map>::cast(
+ HConstant::cast(transition())->handle(Isolate::Current()));
} else {
return Handle<Map>();
}
@@ -6113,7 +6120,7 @@
void SetTransition(HConstant* map_constant, CompilationInfo* info) {
ASSERT(!has_transition()); // Only set once.
- Handle<Map> map = Handle<Map>::cast(map_constant->handle());
+ Handle<Map> map = Handle<Map>::cast(map_constant->handle(info->isolate()));
if (map->CanBeDeprecated()) {
map->AddDependentCompilationInfo(DependentCode::kTransitionGroup, info);
}
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index d6b8d64..437d29b 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -4896,40 +4896,111 @@
}
-void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
- Property* prop = expr->target()->AsProperty();
- ASSERT(prop != NULL);
- CHECK_ALIVE(VisitForValue(prop->obj()));
+static bool ComputeReceiverTypes(Expression* expr,
+ HValue* receiver,
+ SmallMapList** t) {
+ SmallMapList* types = expr->GetReceiverTypes();
+ *t = types;
+ bool monomorphic = expr->IsMonomorphic();
+ if (types != NULL && receiver->HasMonomorphicJSObjectType()) {
+ Map* root_map = receiver->GetMonomorphicJSObjectMap()->FindRootMap();
+ types->FilterForPossibleTransitions(root_map);
+ monomorphic = types->length() == 1;
+ }
+ return monomorphic && CanInlinePropertyAccess(*types->first());
+}
- if (prop->key()->IsPropertyName()) {
- // Named store.
- CHECK_ALIVE(VisitForValue(expr->value()));
- HValue* value = environment()->ExpressionStackAt(0);
- HValue* object = environment()->ExpressionStackAt(1);
- if (expr->IsUninitialized()) {
- Add<HDeoptimize>("Insufficient type feedback for property assignment",
- Deoptimizer::SOFT);
- }
- return BuildStoreNamed(
- expr, expr->id(), expr->AssignmentId(), prop, object, value);
- } else {
+void HOptimizedGraphBuilder::BuildStore(Expression* expr,
+ Property* prop,
+ BailoutId ast_id,
+ BailoutId return_id,
+ bool is_uninitialized) {
+ HValue* value = environment()->ExpressionStackAt(0);
+
+ if (!prop->key()->IsPropertyName()) {
// Keyed store.
- CHECK_ALIVE(VisitForValue(prop->key()));
- CHECK_ALIVE(VisitForValue(expr->value()));
- HValue* value = environment()->ExpressionStackAt(0);
HValue* key = environment()->ExpressionStackAt(1);
HValue* object = environment()->ExpressionStackAt(2);
bool has_side_effects = false;
- HandleKeyedElementAccess(object, key, value, expr, expr->AssignmentId(),
+ HandleKeyedElementAccess(object, key, value, expr, return_id,
expr->position(),
true, // is_store
&has_side_effects);
Drop(3);
Push(value);
- Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE);
+ Add<HSimulate>(return_id, REMOVABLE_SIMULATE);
return ast_context()->ReturnValue(Pop());
}
+
+ // Named store.
+ HValue* object = environment()->ExpressionStackAt(1);
+
+ if (is_uninitialized) {
+ Add<HDeoptimize>("Insufficient type feedback for property assignment",
+ Deoptimizer::SOFT);
+ }
+
+ Literal* key = prop->key()->AsLiteral();
+ Handle<String> name = Handle<String>::cast(key->value());
+ ASSERT(!name.is_null());
+
+ HInstruction* instr = NULL;
+
+ SmallMapList* types;
+ bool monomorphic = ComputeReceiverTypes(expr, object, &types);
+
+ if (monomorphic) {
+ Handle<Map> map = types->first();
+ Handle<JSFunction> setter;
+ Handle<JSObject> holder;
+ if (LookupSetter(map, name, &setter, &holder)) {
+ AddCheckConstantFunction(holder, object, map);
+ if (FLAG_inline_accessors &&
+ TryInlineSetter(setter, ast_id, return_id, value)) {
+ return;
+ }
+ Drop(2);
+ Add<HPushArgument>(object);
+ Add<HPushArgument>(value);
+ instr = new(zone()) HCallConstantFunction(setter, 2);
+ } else {
+ Drop(2);
+ CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object,
+ name,
+ value,
+ map));
+ }
+ } else if (types != NULL && types->length() > 1) {
+ Drop(2);
+ return HandlePolymorphicStoreNamedField(
+ expr->position(), ast_id, object, value, types, name);
+ } else {
+ Drop(2);
+ instr = BuildStoreNamedGeneric(object, name, value);
+ }
+
+ if (!ast_context()->IsEffect()) Push(value);
+ instr->set_position(expr->position());
+ AddInstruction(instr);
+ if (instr->HasObservableSideEffects()) {
+ Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
+ }
+ if (!ast_context()->IsEffect()) Drop(1);
+ return ast_context()->ReturnValue(value);
+}
+
+
+void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
+ Property* prop = expr->target()->AsProperty();
+ ASSERT(prop != NULL);
+ CHECK_ALIVE(VisitForValue(prop->obj()));
+ if (!prop->key()->IsPropertyName()) {
+ CHECK_ALIVE(VisitForValue(prop->key()));
+ }
+ CHECK_ALIVE(VisitForValue(expr->value()));
+ BuildStore(expr, prop, expr->id(),
+ expr->AssignmentId(), expr->IsUninitialized());
}
@@ -4978,64 +5049,6 @@
}
-void HOptimizedGraphBuilder::BuildStoreNamed(Expression* expr,
- BailoutId id,
- BailoutId assignment_id,
- Property* prop,
- HValue* object,
- HValue* value) {
- Literal* key = prop->key()->AsLiteral();
- Handle<String> name = Handle<String>::cast(key->value());
- ASSERT(!name.is_null());
-
- HInstruction* instr = NULL;
- SmallMapList* types = expr->GetReceiverTypes();
- bool monomorphic = expr->IsMonomorphic();
- Handle<Map> map;
- if (monomorphic) {
- map = types->first();
- monomorphic = CanInlinePropertyAccess(*map);
- }
- if (monomorphic) {
- Handle<JSFunction> setter;
- Handle<JSObject> holder;
- if (LookupSetter(map, name, &setter, &holder)) {
- AddCheckConstantFunction(holder, object, map);
- if (FLAG_inline_accessors &&
- TryInlineSetter(setter, id, assignment_id, value)) {
- return;
- }
- Drop(2);
- Add<HPushArgument>(object);
- Add<HPushArgument>(value);
- instr = new(zone()) HCallConstantFunction(setter, 2);
- } else {
- Drop(2);
- CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object,
- name,
- value,
- map));
- }
- } else if (types != NULL && types->length() > 1) {
- Drop(2);
- return HandlePolymorphicStoreNamedField(
- expr->position(), id, object, value, types, name);
- } else {
- Drop(2);
- instr = BuildStoreNamedGeneric(object, name, value);
- }
-
- if (!ast_context()->IsEffect()) Push(value);
- instr->set_position(expr->position());
- AddInstruction(instr);
- if (instr->HasObservableSideEffects()) {
- Add<HSimulate>(id, REMOVABLE_SIMULATE);
- }
- if (!ast_context()->IsEffect()) Drop(1);
- return ast_context()->ReturnValue(value);
-}
-
-
void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
Expression* target = expr->target();
VariableProxy* proxy = target->AsVariableProxy();
@@ -5117,62 +5130,30 @@
return ast_context()->ReturnValue(Pop());
} else if (prop != NULL) {
- if (prop->key()->IsPropertyName()) {
- // Named property.
- CHECK_ALIVE(VisitForValue(prop->obj()));
- HValue* object = Top();
- CHECK_ALIVE(PushLoad(prop, object, expr->position()));
-
- CHECK_ALIVE(VisitForValue(expr->value()));
- HValue* right = Pop();
- HValue* left = Pop();
-
- HInstruction* instr = BuildBinaryOperation(operation, left, right);
- PushAndAdd(instr);
- if (instr->HasObservableSideEffects()) {
- Add<HSimulate>(operation->id(), REMOVABLE_SIMULATE);
- }
-
- return BuildStoreNamed(
- expr, expr->id(), expr->AssignmentId(), prop, object, instr);
- } else {
- // Keyed property.
- CHECK_ALIVE(VisitForValue(prop->obj()));
+ CHECK_ALIVE(VisitForValue(prop->obj()));
+ HValue* object = Top();
+ HValue* key = NULL;
+ if ((!prop->IsStringLength() &&
+ !prop->IsFunctionPrototype() &&
+ !prop->key()->IsPropertyName()) ||
+ prop->IsStringAccess()) {
CHECK_ALIVE(VisitForValue(prop->key()));
- HValue* obj = environment()->ExpressionStackAt(1);
- HValue* key = environment()->ExpressionStackAt(0);
-
- bool has_side_effects = false;
- HValue* load = HandleKeyedElementAccess(
- obj, key, NULL, prop, prop->LoadId(), RelocInfo::kNoPosition,
- false, // is_store
- &has_side_effects);
- Push(load);
- if (has_side_effects) Add<HSimulate>(prop->LoadId(), REMOVABLE_SIMULATE);
-
- CHECK_ALIVE(VisitForValue(expr->value()));
- HValue* right = Pop();
- HValue* left = Pop();
-
- HInstruction* instr = BuildBinaryOperation(operation, left, right);
- PushAndAdd(instr);
- if (instr->HasObservableSideEffects()) {
- Add<HSimulate>(operation->id(), REMOVABLE_SIMULATE);
- }
-
- HandleKeyedElementAccess(obj, key, instr, expr, expr->AssignmentId(),
- RelocInfo::kNoPosition,
- true, // is_store
- &has_side_effects);
-
- // Drop the simulated receiver, key, and value. Return the value.
- Drop(3);
- Push(instr);
- ASSERT(has_side_effects); // Stores always have side effects.
- Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE);
- return ast_context()->ReturnValue(Pop());
+ key = Top();
}
+ CHECK_ALIVE(PushLoad(prop, object, key, expr->position()));
+
+ CHECK_ALIVE(VisitForValue(expr->value()));
+ HValue* right = Pop();
+ HValue* left = Pop();
+
+ HInstruction* instr = BuildBinaryOperation(operation, left, right);
+ PushAndAdd(instr);
+ if (instr->HasObservableSideEffects()) {
+ Add<HSimulate>(operation->id(), REMOVABLE_SIMULATE);
+ }
+ BuildStore(expr, prop, expr->id(),
+ expr->AssignmentId(), expr->IsUninitialized());
} else {
return Bailout(kInvalidLhsInCompoundAssignment);
}
@@ -5692,8 +5673,12 @@
bool* has_side_effects) {
ASSERT(!expr->IsPropertyName());
HInstruction* instr = NULL;
- if (expr->IsMonomorphic()) {
- Handle<Map> map = expr->GetMonomorphicReceiverType();
+
+ SmallMapList* types;
+ bool monomorphic = ComputeReceiverTypes(expr, obj, &types);
+
+ if (monomorphic) {
+ Handle<Map> map = types->first();
if (map->has_slow_elements_kind()) {
instr = is_store ? BuildStoreKeyedGeneric(obj, key, val)
: BuildLoadKeyedGeneric(obj, key);
@@ -5796,8 +5781,7 @@
}
} else {
Push(graph()->GetArgumentsObject());
- VisitForValue(expr->key());
- if (HasStackOverflow() || current_block() == NULL) return true;
+ CHECK_ALIVE_OR_RETURN(VisitForValue(expr->key()), true);
HValue* key = Pop();
Drop(1); // Arguments object.
if (function_state()->outer() == NULL) {
@@ -5824,9 +5808,11 @@
void HOptimizedGraphBuilder::PushLoad(Property* expr,
HValue* object,
+ HValue* key,
int position) {
ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED);
Push(object);
+ if (key != NULL) Push(key);
BuildLoad(expr, position, expr->LoadId());
}
@@ -5842,7 +5828,6 @@
AddInstruction(HCheckInstanceType::NewIsString(string, zone()));
instr = BuildLoadStringLength(string, checkstring);
} else if (expr->IsStringAccess()) {
- CHECK_ALIVE(VisitForValue(expr->key()));
HValue* index = Pop();
HValue* string = Pop();
HValue* context = environment()->context();
@@ -5858,19 +5843,13 @@
} else if (expr->key()->IsPropertyName()) {
Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
- SmallMapList* types = expr->GetReceiverTypes();
HValue* object = Top();
- Handle<Map> map;
- bool monomorphic = false;
- if (expr->IsMonomorphic()) {
- map = types->first();
- monomorphic = CanInlinePropertyAccess(*map);
- } else if (object->HasMonomorphicJSObjectType()) {
- map = object->GetMonomorphicJSObjectMap();
- monomorphic = CanInlinePropertyAccess(*map);
- }
+ SmallMapList* types;
+ bool monomorphic = ComputeReceiverTypes(expr, object, &types);
+
if (monomorphic) {
+ Handle<Map> map = types->first();
Handle<JSFunction> getter;
Handle<JSObject> holder;
if (LookupGetter(map, name, &getter, &holder)) {
@@ -5892,8 +5871,6 @@
}
} else {
- CHECK_ALIVE(VisitForValue(expr->key()));
-
HValue* key = Pop();
HValue* obj = Pop();
@@ -5926,6 +5903,13 @@
if (TryArgumentsAccess(expr)) return;
CHECK_ALIVE(VisitForValue(expr->obj()));
+ if ((!expr->IsStringLength() &&
+ !expr->IsFunctionPrototype() &&
+ !expr->key()->IsPropertyName()) ||
+ expr->IsStringAccess()) {
+ CHECK_ALIVE(VisitForValue(expr->key()));
+ }
+
BuildLoad(expr, expr->position(), expr->id());
}
@@ -6865,14 +6849,12 @@
if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
// Found pattern f.apply(receiver, arguments).
- VisitForValue(prop->obj());
- if (HasStackOverflow() || current_block() == NULL) return true;
+ CHECK_ALIVE_OR_RETURN(VisitForValue(prop->obj()), true);
HValue* function = Top();
AddCheckConstantFunction(expr->holder(), function, function_map);
Drop(1);
- VisitForValue(args->at(0));
- if (HasStackOverflow() || current_block() == NULL) return true;
+ CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(0)), true);
HValue* receiver = Pop();
if (function_state()->outer() == NULL) {
@@ -6903,7 +6885,8 @@
Handle<JSFunction> known_function;
if (function->IsConstant()) {
HConstant* constant_function = HConstant::cast(function);
- known_function = Handle<JSFunction>::cast(constant_function->handle());
+ known_function = Handle<JSFunction>::cast(
+ constant_function->handle(isolate()));
int args_count = arguments_count - 1; // Excluding receiver.
if (TryInlineApply(known_function, expr, args_count)) return true;
}
@@ -6965,23 +6948,19 @@
CHECK_ALIVE(VisitExpressions(expr->arguments()));
Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
- SmallMapList* types = expr->GetReceiverTypes();
-
- bool monomorphic = expr->IsMonomorphic();
- Handle<Map> receiver_map;
- if (monomorphic) {
- receiver_map = (types == NULL || types->is_empty())
- ? Handle<Map>::null()
- : types->first();
- }
-
HValue* receiver =
environment()->ExpressionStackAt(expr->arguments()->length());
+
+ SmallMapList* types;
+ bool was_monomorphic = expr->IsMonomorphic();
+ bool monomorphic = ComputeReceiverTypes(expr, receiver, &types);
+ if (!was_monomorphic && monomorphic) {
+ monomorphic = expr->ComputeTarget(types->first(), name);
+ }
+
if (monomorphic) {
- if (TryInlineBuiltinMethodCall(expr,
- receiver,
- receiver_map,
- expr->check_type())) {
+ Handle<Map> map = types->first();
+ if (TryInlineBuiltinMethodCall(expr, receiver, map, expr->check_type())) {
if (FLAG_trace_inlining) {
PrintF("Inlining builtin ");
expr->target()->ShortPrint();
@@ -6999,7 +6978,7 @@
call = PreProcessCall(
new(zone()) HCallNamed(context, name, argument_count));
} else {
- AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
+ AddCheckConstantFunction(expr->holder(), receiver, map);
if (TryInlineCall(expr)) return;
call = PreProcessCall(
@@ -7474,16 +7453,18 @@
}
-void HOptimizedGraphBuilder::BuildStoreInEffect(Expression* expr,
- Property* prop,
- BailoutId ast_id,
- BailoutId return_id,
- HValue* object,
- HValue* value) {
+void HOptimizedGraphBuilder::BuildStoreForEffect(Expression* expr,
+ Property* prop,
+ BailoutId ast_id,
+ BailoutId return_id,
+ HValue* object,
+ HValue* key,
+ HValue* value) {
EffectContext for_effect(this);
Push(object);
+ if (key != NULL) Push(key);
Push(value);
- BuildStoreNamed(expr, ast_id, return_id, prop, object, value);
+ BuildStore(expr, prop, ast_id, return_id);
}
@@ -7563,69 +7544,42 @@
return Bailout(kLookupVariableInCountOperation);
}
- } else {
- // Argument of the count operation is a property.
- ASSERT(prop != NULL);
-
- if (prop->key()->IsPropertyName()) {
- // Named property.
- if (returns_original_input) Push(graph()->GetConstantUndefined());
-
- CHECK_ALIVE(VisitForValue(prop->obj()));
- HValue* object = Top();
- CHECK_ALIVE(PushLoad(prop, object, expr->position()));
-
- after = BuildIncrement(returns_original_input, expr);
-
- if (returns_original_input) {
- HValue* result = Pop();
- HValue* object = Pop();
- environment()->SetExpressionStackAt(0, result);
- CHECK_ALIVE(BuildStoreInEffect(
- expr, prop, expr->id(), expr->AssignmentId(), object, after));
- return ast_context()->ReturnValue(Pop());
- }
-
- return BuildStoreNamed(
- expr, expr->id(), expr->AssignmentId(), prop, object, after);
- } else {
- // Keyed property.
- if (returns_original_input) Push(graph()->GetConstantUndefined());
-
- CHECK_ALIVE(VisitForValue(prop->obj()));
- CHECK_ALIVE(VisitForValue(prop->key()));
- HValue* obj = environment()->ExpressionStackAt(1);
- HValue* key = environment()->ExpressionStackAt(0);
-
- bool has_side_effects = false;
- HValue* load = HandleKeyedElementAccess(
- obj, key, NULL, prop, prop->LoadId(), RelocInfo::kNoPosition,
- false, // is_store
- &has_side_effects);
- Push(load);
- if (has_side_effects) Add<HSimulate>(prop->LoadId(), REMOVABLE_SIMULATE);
-
- after = BuildIncrement(returns_original_input, expr);
- input = environment()->ExpressionStackAt(0);
-
- HandleKeyedElementAccess(obj, key, after, expr, expr->AssignmentId(),
- RelocInfo::kNoPosition,
- true, // is_store
- &has_side_effects);
-
- // Drop the key and the original value from the bailout environment.
- // Overwrite the receiver with the result of the operation, and the
- // placeholder with the original value if necessary.
- Drop(2);
- environment()->SetExpressionStackAt(0, after);
- if (returns_original_input) environment()->SetExpressionStackAt(1, input);
- ASSERT(has_side_effects); // Stores always have side effects.
- Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE);
- }
+ Drop(returns_original_input ? 2 : 1);
+ return ast_context()->ReturnValue(expr->is_postfix() ? input : after);
}
- Drop(returns_original_input ? 2 : 1);
- return ast_context()->ReturnValue(expr->is_postfix() ? input : after);
+ // Argument of the count operation is a property.
+ ASSERT(prop != NULL);
+ if (returns_original_input) Push(graph()->GetConstantUndefined());
+
+ CHECK_ALIVE(VisitForValue(prop->obj()));
+ HValue* object = Top();
+
+ HValue* key = NULL;
+ if ((!prop->IsStringLength() &&
+ !prop->IsFunctionPrototype() &&
+ !prop->key()->IsPropertyName()) ||
+ prop->IsStringAccess()) {
+ CHECK_ALIVE(VisitForValue(prop->key()));
+ key = Top();
+ }
+
+ CHECK_ALIVE(PushLoad(prop, object, key, expr->position()));
+
+ after = BuildIncrement(returns_original_input, expr);
+
+ if (returns_original_input) {
+ input = Pop();
+ // Drop object and key to push it again in the effect context below.
+ Drop(key == NULL ? 1 : 2);
+ environment()->SetExpressionStackAt(0, input);
+ CHECK_ALIVE(BuildStoreForEffect(
+ expr, prop, expr->id(), expr->AssignmentId(), object, key, after));
+ return ast_context()->ReturnValue(Pop());
+ }
+
+ environment()->SetExpressionStackAt(0, after);
+ return BuildStore(expr, prop, expr->id(), expr->AssignmentId());
}
@@ -7987,12 +7941,15 @@
}
-static bool IsLiteralCompareBool(HValue* left,
+static bool IsLiteralCompareBool(Isolate* isolate,
+ HValue* left,
Token::Value op,
HValue* right) {
return op == Token::EQ_STRICT &&
- ((left->IsConstant() && HConstant::cast(left)->handle()->IsBoolean()) ||
- (right->IsConstant() && HConstant::cast(right)->handle()->IsBoolean()));
+ ((left->IsConstant() &&
+ HConstant::cast(left)->handle(isolate)->IsBoolean()) ||
+ (right->IsConstant() &&
+ HConstant::cast(right)->handle(isolate)->IsBoolean()));
}
@@ -8044,7 +8001,7 @@
HValue* left = Pop();
Token::Value op = expr->op();
- if (IsLiteralCompareBool(left, op, right)) {
+ if (IsLiteralCompareBool(isolate(), left, op, right)) {
HCompareObjectEqAndBranch* result =
New<HCompareObjectEqAndBranch>(left, right);
result->set_position(expr->position());
diff --git a/src/hydrogen.h b/src/hydrogen.h
index a12773f..395d1cd 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -2038,21 +2038,22 @@
BailoutId ast_id);
void PushLoad(Property* property,
HValue* object,
+ HValue* key,
int position);
- void BuildStoreInEffect(Expression* expression,
- Property* prop,
- BailoutId ast_id,
- BailoutId return_id,
- HValue* object,
- HValue* value);
+ void BuildStoreForEffect(Expression* expression,
+ Property* prop,
+ BailoutId ast_id,
+ BailoutId return_id,
+ HValue* object,
+ HValue* key,
+ HValue* value);
- void BuildStoreNamed(Expression* expression,
- BailoutId id,
- BailoutId assignment_id,
- Property* prop,
- HValue* object,
- HValue* value);
+ void BuildStore(Expression* expression,
+ Property* prop,
+ BailoutId ast_id,
+ BailoutId return_id,
+ bool is_uninitialized = false);
HInstruction* BuildStoreNamedField(HValue* object,
Handle<String> name,
diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc
index 28b0f4a..84a4d23 100644
--- a/src/ia32/codegen-ia32.cc
+++ b/src/ia32/codegen-ia32.cc
@@ -177,11 +177,6 @@
#undef __
#define __ ACCESS_MASM(masm)
-// Keep around global pointers to these objects so that Valgrind won't complain.
-static size_t* medium_handlers = NULL;
-static size_t* small_handlers = NULL;
-
-
enum Direction { FORWARD, BACKWARD };
enum Alignment { MOVE_ALIGNED, MOVE_UNALIGNED };
@@ -253,12 +248,24 @@
#define __ masm.
+class LabelConverter {
+ public:
+ explicit LabelConverter(byte* buffer) : buffer_(buffer) {}
+ int32_t address(Label* l) const {
+ return reinterpret_cast<int32_t>(buffer_) + l->pos();
+ }
+ private:
+ byte* buffer_;
+};
+
+
OS::MemMoveFunction CreateMemMoveFunction() {
size_t actual_size;
// Allocate buffer in executable space.
byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size, true));
if (buffer == NULL) return NULL;
MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
+ LabelConverter conv(buffer);
// Generated code is put into a fixed, unmovable buffer, and not into
// the V8 heap. We can't, and don't, refer to any relocatable addresses
@@ -452,7 +459,7 @@
// Special handlers for 9 <= copy_size < 64. No assumptions about
// alignment or move distance, so all reads must be unaligned and
// must happen before any writes.
- Label f9_16, f17_32, f33_48, f49_63;
+ Label medium_handlers, f9_16, f17_32, f33_48, f49_63;
__ bind(&f9_16);
__ movdbl(xmm0, Operand(src, 0));
@@ -488,11 +495,11 @@
__ movdqu(Operand(dst, count, times_1, -0x10), xmm3);
MemMoveEmitPopAndReturn(&masm);
- medium_handlers = new size_t[4];
- medium_handlers[0] = reinterpret_cast<intptr_t>(buffer) + f9_16.pos();
- medium_handlers[1] = reinterpret_cast<intptr_t>(buffer) + f17_32.pos();
- medium_handlers[2] = reinterpret_cast<intptr_t>(buffer) + f33_48.pos();
- medium_handlers[3] = reinterpret_cast<intptr_t>(buffer) + f49_63.pos();
+ __ bind(&medium_handlers);
+ __ dd(conv.address(&f9_16));
+ __ dd(conv.address(&f17_32));
+ __ dd(conv.address(&f33_48));
+ __ dd(conv.address(&f49_63));
__ bind(&medium_size); // Entry point into this block.
__ mov(eax, count);
@@ -505,13 +512,12 @@
__ int3();
__ bind(&ok);
}
- __ mov(eax, Operand(eax, times_4,
- reinterpret_cast<intptr_t>(medium_handlers)));
+ __ mov(eax, Operand(eax, times_4, conv.address(&medium_handlers)));
__ jmp(eax);
}
{
// Specialized copiers for copy_size <= 8 bytes.
- Label f0, f1, f2, f3, f4, f5_8;
+ Label small_handlers, f0, f1, f2, f3, f4, f5_8;
__ bind(&f0);
MemMoveEmitPopAndReturn(&masm);
@@ -544,16 +550,16 @@
__ mov(Operand(dst, count, times_1, -4), edx);
MemMoveEmitPopAndReturn(&masm);
- small_handlers = new size_t[9];
- small_handlers[0] = reinterpret_cast<intptr_t>(buffer) + f0.pos();
- small_handlers[1] = reinterpret_cast<intptr_t>(buffer) + f1.pos();
- small_handlers[2] = reinterpret_cast<intptr_t>(buffer) + f2.pos();
- small_handlers[3] = reinterpret_cast<intptr_t>(buffer) + f3.pos();
- small_handlers[4] = reinterpret_cast<intptr_t>(buffer) + f4.pos();
- small_handlers[5] = reinterpret_cast<intptr_t>(buffer) + f5_8.pos();
- small_handlers[6] = reinterpret_cast<intptr_t>(buffer) + f5_8.pos();
- small_handlers[7] = reinterpret_cast<intptr_t>(buffer) + f5_8.pos();
- small_handlers[8] = reinterpret_cast<intptr_t>(buffer) + f5_8.pos();
+ __ bind(&small_handlers);
+ __ dd(conv.address(&f0));
+ __ dd(conv.address(&f1));
+ __ dd(conv.address(&f2));
+ __ dd(conv.address(&f3));
+ __ dd(conv.address(&f4));
+ __ dd(conv.address(&f5_8));
+ __ dd(conv.address(&f5_8));
+ __ dd(conv.address(&f5_8));
+ __ dd(conv.address(&f5_8));
__ bind(&small_size); // Entry point into this block.
if (FLAG_debug_code) {
@@ -563,8 +569,7 @@
__ int3();
__ bind(&ok);
}
- __ mov(eax, Operand(count, times_4,
- reinterpret_cast<intptr_t>(small_handlers)));
+ __ mov(eax, Operand(count, times_4, conv.address(&small_handlers)));
__ jmp(eax);
}
} else {
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 75525ed..32c9f00 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -713,7 +713,7 @@
Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
HConstant* constant = chunk_->LookupConstant(op);
ASSERT(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged());
- return constant->handle();
+ return constant->handle(isolate());
}
@@ -876,7 +876,7 @@
translation->StoreDoubleRegister(reg);
} else if (op->IsConstantOperand()) {
HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op));
- int src_index = DefineDeoptimizationLiteral(constant->handle());
+ int src_index = DefineDeoptimizationLiteral(constant->handle(isolate()));
translation->StoreLiteral(src_index);
} else {
UNREACHABLE();
@@ -936,7 +936,7 @@
} else if (context->IsConstantOperand()) {
HConstant* constant =
chunk_->LookupConstant(LConstantOperand::cast(context));
- __ LoadObject(esi, Handle<Object>::cast(constant->handle()));
+ __ LoadObject(esi, Handle<Object>::cast(constant->handle(isolate())));
} else {
UNREACHABLE();
}
@@ -1943,7 +1943,7 @@
void LCodeGen::DoConstantT(LConstantT* instr) {
Register reg = ToRegister(instr->result());
- Handle<Object> handle = instr->value();
+ Handle<Object> handle = instr->value(isolate());
AllowDeferredHandleDereference smi_check;
__ LoadObject(reg, handle);
}
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index 8b311b7..ab964af 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -1261,7 +1261,9 @@
DECLARE_CONCRETE_INSTRUCTION(ConstantT, "constant-t")
DECLARE_HYDROGEN_ACCESSOR(Constant)
- Handle<Object> value() const { return hydrogen()->handle(); }
+ Handle<Object> value(Isolate* isolate) const {
+ return hydrogen()->handle(isolate);
+ }
};
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index e90810e..bcf64ce 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -542,6 +542,39 @@
}
+// Generate call to api function.
+static void GenerateFastApiCall(MacroAssembler* masm,
+ const CallOptimization& optimization,
+ Register receiver,
+ Register scratch,
+ int argc,
+ Register* values) {
+ ASSERT(optimization.is_simple_api_call());
+ ASSERT(!receiver.is(scratch));
+
+ const int stack_space = kFastApiCallArguments + argc + 1;
+ // Copy return value.
+ __ mov(scratch, Operand(esp, 0));
+ // Assign stack space for the call arguments.
+ __ sub(esp, Immediate(stack_space * kPointerSize));
+ // Move the return address on top of the stack.
+ __ mov(Operand(esp, 0), scratch);
+ // Write holder to stack frame.
+ __ mov(Operand(esp, 1 * kPointerSize), receiver);
+ // Write receiver to stack frame.
+ int index = stack_space;
+ __ mov(Operand(esp, index-- * kPointerSize), receiver);
+ // Write the arguments to stack frame.
+ for (int i = 0; i < argc; i++) {
+ ASSERT(!receiver.is(values[i]));
+ ASSERT(!scratch.is(values[i]));
+ __ mov(Operand(esp, index-- * kPointerSize), values[i]);
+ }
+
+ GenerateFastApiCall(masm, optimization, argc);
+}
+
+
class CallInterceptorCompiler BASE_EMBEDDED {
public:
CallInterceptorCompiler(StubCompiler* stub_compiler,
@@ -1356,23 +1389,8 @@
void BaseLoadStubCompiler::GenerateLoadCallback(
const CallOptimization& call_optimization) {
- ASSERT(call_optimization.is_simple_api_call());
-
- // Copy return value.
- __ mov(scratch3(), Operand(esp, 0));
- // Assign stack space for the call arguments.
- __ sub(esp, Immediate((kFastApiCallArguments + 1) * kPointerSize));
- // Move the return address on top of the stack.
- __ mov(Operand(esp, 0), scratch3());
-
- int argc = 0;
- int api_call_argc = argc + kFastApiCallArguments;
- // Write holder to stack frame.
- __ mov(Operand(esp, 1 * kPointerSize), receiver());
- // Write receiver to stack frame.
- __ mov(Operand(esp, (api_call_argc + 1) * kPointerSize), receiver());
-
- GenerateFastApiCall(masm(), call_optimization, argc);
+ GenerateFastApiCall(
+ masm(), call_optimization, receiver(), scratch3(), 0, NULL);
}
@@ -2901,6 +2919,24 @@
}
+Handle<Code> StoreStubCompiler::CompileStoreCallback(
+ Handle<JSObject> object,
+ Handle<JSObject> holder,
+ Handle<Name> name,
+ const CallOptimization& call_optimization) {
+ Label success;
+ HandlerFrontend(object, receiver(), holder, name, &success);
+ __ bind(&success);
+
+ Register values[] = { value() };
+ GenerateFastApiCall(
+ masm(), call_optimization, receiver(), scratch1(), 1, values);
+
+ // Return the generated code.
+ return GetCode(kind(), Code::CALLBACKS, name);
+}
+
+
#undef __
#define __ ACCESS_MASM(masm)
diff --git a/src/ic.cc b/src/ic.cc
index d88ab4a..9724c44 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -1831,6 +1831,13 @@
if (!setter->IsJSFunction()) break;
if (holder->IsGlobalObject()) break;
if (!holder->HasFastProperties()) break;
+ Handle<JSFunction> function = Handle<JSFunction>::cast(setter);
+ CallOptimization call_optimization(function);
+ if (call_optimization.is_simple_api_call() &&
+ call_optimization.IsCompatibleReceiver(*receiver)) {
+ return isolate()->stub_cache()->ComputeStoreCallback(
+ name, receiver, holder, call_optimization, strict_mode);
+ }
return isolate()->stub_cache()->ComputeStoreViaSetter(
name, receiver, holder, Handle<JSFunction>::cast(setter),
strict_mode);
diff --git a/src/isolate.cc b/src/isolate.cc
index 17762b2..74a77c6 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -343,35 +343,23 @@
#ifdef DEBUG
Thread::LocalStorageKey PerThreadAssertScopeBase::thread_local_key;
#endif // DEBUG
-RecursiveMutex Isolate::process_wide_mutex_;
+Mutex Isolate::process_wide_mutex_;
Isolate::ThreadDataTable* Isolate::thread_data_table_ = NULL;
Atomic32 Isolate::isolate_counter_ = 0;
-Isolate::PerIsolateThreadData* Isolate::AllocatePerIsolateThreadData(
- ThreadId thread_id) {
- ASSERT(!thread_id.Equals(ThreadId::Invalid()));
- PerIsolateThreadData* per_thread = new PerIsolateThreadData(this, thread_id);
- {
- LockGuard<RecursiveMutex> lock_guard(&process_wide_mutex_);
- ASSERT(thread_data_table_->Lookup(this, thread_id) == NULL);
- thread_data_table_->Insert(per_thread);
- ASSERT(thread_data_table_->Lookup(this, thread_id) == per_thread);
- }
- return per_thread;
-}
-
-
Isolate::PerIsolateThreadData*
Isolate::FindOrAllocatePerThreadDataForThisThread() {
ThreadId thread_id = ThreadId::Current();
PerIsolateThreadData* per_thread = NULL;
{
- LockGuard<RecursiveMutex> lock_guard(&process_wide_mutex_);
+ LockGuard<Mutex> lock_guard(&process_wide_mutex_);
per_thread = thread_data_table_->Lookup(this, thread_id);
if (per_thread == NULL) {
- per_thread = AllocatePerIsolateThreadData(thread_id);
+ per_thread = new PerIsolateThreadData(this, thread_id);
+ thread_data_table_->Insert(per_thread);
}
}
+ ASSERT(thread_data_table_->Lookup(this, thread_id) == per_thread);
return per_thread;
}
@@ -386,7 +374,7 @@
ThreadId thread_id) {
PerIsolateThreadData* per_thread = NULL;
{
- LockGuard<RecursiveMutex> lock_guard(&process_wide_mutex_);
+ LockGuard<Mutex> lock_guard(&process_wide_mutex_);
per_thread = thread_data_table_->Lookup(this, thread_id);
}
return per_thread;
@@ -394,7 +382,7 @@
void Isolate::EnsureDefaultIsolate() {
- LockGuard<RecursiveMutex> lock_guard(&process_wide_mutex_);
+ LockGuard<Mutex> lock_guard(&process_wide_mutex_);
if (default_isolate_ == NULL) {
isolate_key_ = Thread::CreateThreadLocalKey();
thread_id_key_ = Thread::CreateThreadLocalKey();
@@ -1717,15 +1705,6 @@
}
-void Isolate::ThreadDataTable::Remove(Isolate* isolate,
- ThreadId thread_id) {
- PerIsolateThreadData* data = Lookup(isolate, thread_id);
- if (data != NULL) {
- Remove(data);
- }
-}
-
-
void Isolate::ThreadDataTable::RemoveAllThreads(Isolate* isolate) {
PerIsolateThreadData* data = list_;
while (data != NULL) {
@@ -1864,7 +1843,7 @@
Deinit();
- { LockGuard<RecursiveMutex> lock_guard(&process_wide_mutex_);
+ { LockGuard<Mutex> lock_guard(&process_wide_mutex_);
thread_data_table_->RemoveAllThreads(this);
}
diff --git a/src/isolate.h b/src/isolate.h
index 741c4c0..f0854e5 100644
--- a/src/isolate.h
+++ b/src/isolate.h
@@ -1155,7 +1155,6 @@
PerIsolateThreadData* Lookup(Isolate* isolate, ThreadId thread_id);
void Insert(PerIsolateThreadData* data);
- void Remove(Isolate* isolate, ThreadId thread_id);
void Remove(PerIsolateThreadData* data);
void RemoveAllThreads(Isolate* isolate);
@@ -1190,7 +1189,7 @@
// This mutex protects highest_thread_id_, thread_data_table_ and
// default_isolate_.
- static RecursiveMutex process_wide_mutex_;
+ static Mutex process_wide_mutex_;
static Thread::LocalStorageKey per_isolate_thread_data_key_;
static Thread::LocalStorageKey isolate_key_;
@@ -1206,10 +1205,6 @@
static void SetIsolateThreadLocals(Isolate* isolate,
PerIsolateThreadData* data);
- // Allocate and insert PerIsolateThreadData into the ThreadDataTable
- // (regardless of whether such data already exists).
- PerIsolateThreadData* AllocatePerIsolateThreadData(ThreadId thread_id);
-
// Find the PerThread for this particular (isolate, thread) combination.
// If one does not yet exist, allocate a new one.
PerIsolateThreadData* FindOrAllocatePerThreadDataForThisThread();
diff --git a/src/macros.py b/src/macros.py
index 38b9a08..d699c14 100644
--- a/src/macros.py
+++ b/src/macros.py
@@ -69,6 +69,7 @@
const kUninitialized = -1;
const kReadOnlyPrototypeBit = 3;
const kRemovePrototypeBit = 4; # For FunctionTemplateInfo, matches objects.h
+const kDoNotCacheBit = 5; # For FunctionTemplateInfo, matches objects.h
# Note: kDayZeroInJulianDay = ToJulianDay(1970, 0, 1).
const kInvalidDate = 'Invalid Date';
diff --git a/src/mips/stub-cache-mips.cc b/src/mips/stub-cache-mips.cc
index 4342a06..cc75a61 100644
--- a/src/mips/stub-cache-mips.cc
+++ b/src/mips/stub-cache-mips.cc
@@ -917,6 +917,36 @@
kFastApiCallArguments + 1);
}
+
+// Generate call to api function.
+static void GenerateFastApiCall(MacroAssembler* masm,
+ const CallOptimization& optimization,
+ Register receiver,
+ Register scratch,
+ int argc,
+ Register* values) {
+ ASSERT(optimization.is_simple_api_call());
+ ASSERT(!receiver.is(scratch));
+
+ const int stack_space = kFastApiCallArguments + argc + 1;
+ // Assign stack space for the call arguments.
+ __ Subu(sp, sp, Operand(stack_space * kPointerSize));
+ // Write holder to stack frame.
+ __ sw(receiver, MemOperand(sp, 0));
+ // Write receiver to stack frame.
+ int index = stack_space - 1;
+ __ sw(receiver, MemOperand(sp, index * kPointerSize));
+ // Write the arguments to stack frame.
+ for (int i = 0; i < argc; i++) {
+ ASSERT(!receiver.is(values[i]));
+ ASSERT(!scratch.is(values[i]));
+ __ sw(receiver, MemOperand(sp, index-- * kPointerSize));
+ }
+
+ GenerateFastApiDirectCall(masm, optimization, argc);
+}
+
+
class CallInterceptorCompiler BASE_EMBEDDED {
public:
CallInterceptorCompiler(StubCompiler* stub_compiler,
@@ -1375,19 +1405,8 @@
void BaseLoadStubCompiler::GenerateLoadCallback(
const CallOptimization& call_optimization) {
- ASSERT(call_optimization.is_simple_api_call());
-
- // Assign stack space for the call arguments.
- __ Subu(sp, sp, Operand((kFastApiCallArguments + 1) * kPointerSize));
-
- int argc = 0;
- int api_call_argc = argc + kFastApiCallArguments;
- // Write holder to stack frame.
- __ sw(receiver(), MemOperand(sp, 0));
- // Write receiver to stack frame.
- __ sw(receiver(), MemOperand(sp, api_call_argc * kPointerSize));
-
- GenerateFastApiDirectCall(masm(), call_optimization, argc);
+ GenerateFastApiCall(
+ masm(), call_optimization, receiver(), scratch3(), 0, NULL);
}
@@ -2814,6 +2833,24 @@
}
+Handle<Code> StoreStubCompiler::CompileStoreCallback(
+ Handle<JSObject> object,
+ Handle<JSObject> holder,
+ Handle<Name> name,
+ const CallOptimization& call_optimization) {
+ Label success;
+ HandlerFrontend(object, receiver(), holder, name, &success);
+ __ bind(&success);
+
+ Register values[] = { value() };
+ GenerateFastApiCall(
+ masm(), call_optimization, receiver(), scratch3(), 1, values);
+
+ // Return the generated code.
+ return GetCode(kind(), Code::CALLBACKS, name);
+}
+
+
#undef __
#define __ ACCESS_MASM(masm)
diff --git a/src/objects-inl.h b/src/objects-inl.h
index cd8426f..8a3cbec 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -4569,6 +4569,8 @@
kReadOnlyPrototypeBit)
BOOL_ACCESSORS(FunctionTemplateInfo, flag, remove_prototype,
kRemovePrototypeBit)
+BOOL_ACCESSORS(FunctionTemplateInfo, flag, do_not_cache,
+ kDoNotCacheBit)
BOOL_ACCESSORS(SharedFunctionInfo, start_position_and_type, is_expression,
kIsExpressionBit)
BOOL_ACCESSORS(SharedFunctionInfo, start_position_and_type, is_toplevel,
diff --git a/src/objects.h b/src/objects.h
index 30b1b85..97d1e5d 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -9878,6 +9878,7 @@
DECL_BOOLEAN_ACCESSORS(needs_access_check)
DECL_BOOLEAN_ACCESSORS(read_only_prototype)
DECL_BOOLEAN_ACCESSORS(remove_prototype)
+ DECL_BOOLEAN_ACCESSORS(do_not_cache)
static inline FunctionTemplateInfo* cast(Object* obj);
@@ -9913,6 +9914,7 @@
static const int kNeedsAccessCheckBit = 2;
static const int kReadOnlyPrototypeBit = 3;
static const int kRemovePrototypeBit = 4;
+ static const int kDoNotCacheBit = 5;
DISALLOW_IMPLICIT_CONSTRUCTORS(FunctionTemplateInfo);
};
diff --git a/src/platform/elapsed-timer.h b/src/platform/elapsed-timer.h
index e5bcf23..773abbc 100644
--- a/src/platform/elapsed-timer.h
+++ b/src/platform/elapsed-timer.h
@@ -87,7 +87,7 @@
// Returns the time elapsed since the previous start. This method may only
// be called on a previously started timer.
- MUST_USE_RESULT TimeDelta Elapsed() const {
+ TimeDelta Elapsed() const V8_WARN_UNUSED_RESULT {
ASSERT(IsStarted());
TimeDelta elapsed = Now() - start_ticks_;
ASSERT(elapsed.InMicroseconds() >= 0);
@@ -97,13 +97,13 @@
// Returns |true| if the specified |time_delta| has elapsed since the
// previous start, or |false| if not. This method may only be called on
// a previously started timer.
- MUST_USE_RESULT bool HasExpired(TimeDelta time_delta) const {
+ bool HasExpired(TimeDelta time_delta) const V8_WARN_UNUSED_RESULT {
ASSERT(IsStarted());
return Elapsed() >= time_delta;
}
private:
- MUST_USE_RESULT V8_INLINE(static TimeTicks Now()) {
+ V8_INLINE(static TimeTicks Now()) V8_WARN_UNUSED_RESULT {
TimeTicks now = TimeTicks::HighResNow();
ASSERT(!now.IsNull());
return now;
diff --git a/src/runtime.cc b/src/runtime.cc
index 9e44b58..56558e0 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -12484,7 +12484,7 @@
// of frames to step down.
RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
HandleScope scope(isolate);
- ASSERT(args.length() == 3);
+ ASSERT(args.length() == 4);
// Check arguments.
Object* check;
{ MaybeObject* maybe_check = Runtime_CheckExecutionState(
@@ -12495,6 +12495,15 @@
return isolate->Throw(isolate->heap()->illegal_argument_string());
}
+ CONVERT_NUMBER_CHECKED(int, wrapped_frame_id, Int32, args[3]);
+
+ StackFrame::Id frame_id;
+ if (wrapped_frame_id == 0) {
+ frame_id = StackFrame::NO_ID;
+ } else {
+ frame_id = UnwrapFrameId(wrapped_frame_id);
+ }
+
// Get the step action and check validity.
StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
if (step_action != StepIn &&
@@ -12505,6 +12514,11 @@
return isolate->Throw(isolate->heap()->illegal_argument_string());
}
+ if (frame_id != StackFrame::NO_ID && step_action != StepNext &&
+ step_action != StepMin && step_action != StepOut) {
+ return isolate->ThrowIllegalOperation();
+ }
+
// Get the number of steps.
int step_count = NumberToInt32(args[2]);
if (step_count < 1) {
@@ -12516,7 +12530,8 @@
// Prepare step.
isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
- step_count);
+ step_count,
+ frame_id);
return isolate->heap()->undefined_value();
}
diff --git a/src/runtime.h b/src/runtime.h
index 9054fc7..4c76098 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -504,7 +504,7 @@
F(ClearBreakPoint, 1, 1) \
F(ChangeBreakOnException, 2, 1) \
F(IsBreakOnException, 1, 1) \
- F(PrepareStep, 3, 1) \
+ F(PrepareStep, 4, 1) \
F(ClearStepping, 0, 1) \
F(DebugEvaluate, 6, 1) \
F(DebugEvaluateGlobal, 4, 1) \
diff --git a/src/store-buffer.cc b/src/store-buffer.cc
index 9705b60..30b7f25 100644
--- a/src/store-buffer.cc
+++ b/src/store-buffer.cc
@@ -170,7 +170,10 @@
PointerChunkIterator it(heap_);
MemoryChunk* chunk;
while ((chunk = it.next()) != NULL) {
- if (chunk->scan_on_scavenge()) page_has_scan_on_scavenge_flag = true;
+ if (chunk->scan_on_scavenge()) {
+ page_has_scan_on_scavenge_flag = true;
+ break;
+ }
}
if (page_has_scan_on_scavenge_flag) {
@@ -279,7 +282,10 @@
MemoryChunk* chunk;
bool page_has_scan_on_scavenge_flag = false;
while ((chunk = it.next()) != NULL) {
- if (chunk->scan_on_scavenge()) page_has_scan_on_scavenge_flag = true;
+ if (chunk->scan_on_scavenge()) {
+ page_has_scan_on_scavenge_flag = true;
+ break;
+ }
}
if (page_has_scan_on_scavenge_flag) {
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index b312b1e..f83a7d2 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -631,6 +631,24 @@
}
+Handle<Code> StubCache::ComputeStoreCallback(
+ Handle<Name> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder,
+ const CallOptimization& call_optimization,
+ StrictModeFlag strict_mode) {
+ Handle<Code> stub = FindStoreHandler(
+ name, receiver, Code::STORE_IC, Code::CALLBACKS, strict_mode);
+ if (!stub.is_null()) return stub;
+
+ StoreStubCompiler compiler(isolate_, strict_mode);
+ Handle<Code> handler = compiler.CompileStoreCallback(
+ receiver, holder, name, call_optimization);
+ JSObject::UpdateMapCodeCache(receiver, name, handler);
+ return handler;
+}
+
+
Handle<Code> StubCache::ComputeStoreViaSetter(Handle<Name> name,
Handle<JSObject> receiver,
Handle<JSObject> holder,
diff --git a/src/stub-cache.h b/src/stub-cache.h
index a267100..12afdd3 100644
--- a/src/stub-cache.h
+++ b/src/stub-cache.h
@@ -222,6 +222,12 @@
Handle<ExecutableAccessorInfo> callback,
StrictModeFlag strict_mode);
+ Handle<Code> ComputeStoreCallback(Handle<Name> name,
+ Handle<JSObject> object,
+ Handle<JSObject> holder,
+ const CallOptimization& call_optimation,
+ StrictModeFlag strict_mode);
+
Handle<Code> ComputeStoreViaSetter(Handle<Name> name,
Handle<JSObject> object,
Handle<JSObject> holder,
@@ -960,6 +966,11 @@
Handle<Name> name,
Handle<ExecutableAccessorInfo> callback);
+ Handle<Code> CompileStoreCallback(Handle<JSObject> object,
+ Handle<JSObject> holder,
+ Handle<Name> name,
+ const CallOptimization& call_optimization);
+
static void GenerateStoreViaSetter(MacroAssembler* masm,
Handle<JSFunction> setter);
diff --git a/src/v8.cc b/src/v8.cc
index 9dea902..d9ce840 100644
--- a/src/v8.cc
+++ b/src/v8.cc
@@ -50,8 +50,6 @@
V8_DECLARE_ONCE(init_once);
-bool V8::has_been_set_up_ = false;
-bool V8::has_been_disposed_ = false;
List<CallCompletedCallback>* V8::call_completed_callbacks_ = NULL;
v8::ArrayBuffer::Allocator* V8::array_buffer_allocator_ = NULL;
@@ -81,9 +79,6 @@
if (isolate->IsDead()) return false;
if (isolate->IsInitialized()) return true;
- has_been_set_up_ = true;
- has_been_disposed_ = false;
-
return isolate->Init(des);
}
@@ -91,8 +86,7 @@
void V8::TearDown() {
Isolate* isolate = Isolate::Current();
ASSERT(isolate->IsDefaultIsolate());
-
- if (!has_been_set_up_ || has_been_disposed_) return;
+ if (!isolate->IsInitialized()) return;
// The isolate has to be torn down before clearing the LOperand
// caches so that the optimizing compiler thread (if running)
@@ -106,8 +100,6 @@
RegisteredExtension::UnregisterAll();
Isolate::GlobalTearDown();
- has_been_disposed_ = true;
-
delete call_completed_callbacks_;
call_completed_callbacks_ = NULL;
diff --git a/src/v8.h b/src/v8.h
index 69f4df9..23277b3 100644
--- a/src/v8.h
+++ b/src/v8.h
@@ -122,11 +122,6 @@
static void InitializeOncePerProcessImpl();
static void InitializeOncePerProcess();
- // True if V8 has ever been run
- static bool has_been_set_up_;
- // True if engine has been shut down
- // (reset if engine is restarted)
- static bool has_been_disposed_;
// List of callbacks when a Call completes.
static List<CallCompletedCallback>* call_completed_callbacks_;
// Allocator for external array buffers.
diff --git a/src/version.cc b/src/version.cc
index ec28896..9b59e2a 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,8 +34,8 @@
// system so their names cannot be changed without changing the scripts.
#define MAJOR_VERSION 3
#define MINOR_VERSION 21
-#define BUILD_NUMBER 11
-#define PATCH_LEVEL 1
+#define BUILD_NUMBER 12
+#define PATCH_LEVEL 0
// 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 fd9bf18..f1430d7 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -450,7 +450,7 @@
Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
HConstant* constant = chunk_->LookupConstant(op);
ASSERT(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged());
- return constant->handle();
+ return constant->handle(isolate());
}
@@ -582,7 +582,7 @@
translation->StoreDoubleRegister(reg);
} else if (op->IsConstantOperand()) {
HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op));
- int src_index = DefineDeoptimizationLiteral(constant->handle());
+ int src_index = DefineDeoptimizationLiteral(constant->handle(isolate()));
translation->StoreLiteral(src_index);
} else {
UNREACHABLE();
@@ -1425,7 +1425,7 @@
break;
case Token::BIT_XOR:
if (right_operand == int32_t(~0)) {
- __ not_(ToRegister(left));
+ __ notl(ToRegister(left));
} else {
__ xorl(ToRegister(left), Immediate(right_operand));
}
@@ -1598,7 +1598,7 @@
void LCodeGen::DoConstantT(LConstantT* instr) {
- Handle<Object> value = instr->value();
+ Handle<Object> value = instr->value(isolate());
AllowDeferredHandleDereference smi_check;
__ LoadObject(ToRegister(instr->result()), value);
}
diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h
index e95713d..ff0c61b 100644
--- a/src/x64/lithium-x64.h
+++ b/src/x64/lithium-x64.h
@@ -1221,7 +1221,9 @@
DECLARE_CONCRETE_INSTRUCTION(ConstantT, "constant-t")
DECLARE_HYDROGEN_ACCESSOR(Constant)
- Handle<Object> value() const { return hydrogen()->handle(); }
+ Handle<Object> value(Isolate* isolate) const {
+ return hydrogen()->handle(isolate);
+ }
};
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index f6cc449..31f60be 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -528,6 +528,39 @@
}
+// Generate call to api function.
+static void GenerateFastApiCall(MacroAssembler* masm,
+ const CallOptimization& optimization,
+ Register receiver,
+ Register scratch,
+ int argc,
+ Register* values) {
+ ASSERT(optimization.is_simple_api_call());
+ ASSERT(!receiver.is(scratch));
+
+ const int stack_space = kFastApiCallArguments + argc + 1;
+ // Copy return value.
+ __ movq(scratch, Operand(rsp, 0));
+ // Assign stack space for the call arguments.
+ __ subq(rsp, Immediate(stack_space * kPointerSize));
+ // Move the return address on top of the stack.
+ __ movq(Operand(rsp, 0), scratch);
+ // Write holder to stack frame.
+ __ movq(Operand(rsp, 1 * kPointerSize), receiver);
+ // Write receiver to stack frame.
+ int index = stack_space;
+ __ movq(Operand(rsp, index-- * kPointerSize), receiver);
+ // Write the arguments to stack frame.
+ for (int i = 0; i < argc; i++) {
+ ASSERT(!receiver.is(values[i]));
+ ASSERT(!scratch.is(values[i]));
+ __ movq(Operand(rsp, index-- * kPointerSize), values[i]);
+ }
+
+ GenerateFastApiCall(masm, optimization, argc);
+}
+
+
class CallInterceptorCompiler BASE_EMBEDDED {
public:
CallInterceptorCompiler(StubCompiler* stub_compiler,
@@ -1277,24 +1310,8 @@
void BaseLoadStubCompiler::GenerateLoadCallback(
const CallOptimization& call_optimization) {
- ASSERT(call_optimization.is_simple_api_call());
-
- // Copy return value.
- __ movq(scratch3(), Operand(rsp, 0));
- // Assign stack space for the call arguments.
- __ subq(rsp, Immediate((kFastApiCallArguments + 1) * kPointerSize));
- // Move the return address on top of the stack.
- __ movq(Operand(rsp, 0), scratch3());
-
- int argc = 0;
- int api_call_argc = argc + kFastApiCallArguments;
- StackArgumentsAccessor args(rsp, api_call_argc);
- // Write holder to stack frame.
- __ movq(args.GetArgumentOperand(api_call_argc), receiver());
- // Write receiver to stack frame.
- __ movq(args.GetArgumentOperand(api_call_argc - 6), receiver());
-
- GenerateFastApiCall(masm(), call_optimization, argc);
+ GenerateFastApiCall(
+ masm(), call_optimization, receiver(), scratch3(), 0, NULL);
}
@@ -2795,6 +2812,24 @@
}
+Handle<Code> StoreStubCompiler::CompileStoreCallback(
+ Handle<JSObject> object,
+ Handle<JSObject> holder,
+ Handle<Name> name,
+ const CallOptimization& call_optimization) {
+ Label success;
+ HandlerFrontend(object, receiver(), holder, name, &success);
+ __ bind(&success);
+
+ Register values[] = { value() };
+ GenerateFastApiCall(
+ masm(), call_optimization, receiver(), scratch3(), 1, values);
+
+ // Return the generated code.
+ return GetCode(kind(), Code::CALLBACKS, name);
+}
+
+
#undef __
#define __ ACCESS_MASM(masm)
diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status
index e09de7d..a8dde16 100644
--- a/test/cctest/cctest.status
+++ b/test/cctest/cctest.status
@@ -34,6 +34,10 @@
# BUG(382): Weird test. Can't guarantee that it never times out.
test-api/ApplyInterruption: PASS || TIMEOUT
+# TODO(mstarzinger): Fail gracefully on multiple V8::Dispose calls.
+test-api/InitializeAndDisposeOnce: SKIP
+test-api/InitializeAndDisposeMultiple: SKIP
+
# These tests always fail. They are here to test test.py. If
# they don't fail then test.py has failed.
test-serialize/TestThatAlwaysFails: FAIL
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index e190b71..aaac486 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -166,6 +166,24 @@
}
+// Tests that call v8::V8::Dispose() cannot be threaded.
+TEST(InitializeAndDisposeOnce) {
+ CHECK(v8::V8::Initialize());
+ CHECK(v8::V8::Dispose());
+}
+
+
+// Tests that call v8::V8::Dispose() cannot be threaded.
+TEST(InitializeAndDisposeMultiple) {
+ for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
+ for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
+ for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
+ // TODO(mstarzinger): This should fail gracefully instead of asserting.
+ // for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
+ for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
+}
+
+
THREADED_TEST(Handles) {
v8::HandleScope scope(v8::Isolate::GetCurrent());
Local<Context> local_env;
@@ -206,78 +224,98 @@
}
+static void TestSignature(const char* loop_js, Local<Value> receiver) {
+ i::ScopedVector<char> source(200);
+ i::OS::SNPrintF(source,
+ "for (var i = 0; i < 10; i++) {"
+ " %s"
+ "}",
+ loop_js);
+ signature_callback_count = 0;
+ signature_expected_receiver = receiver;
+ bool expected_to_throw = receiver.IsEmpty();
+ v8::TryCatch try_catch;
+ CompileRun(source.start());
+ CHECK_EQ(expected_to_throw, try_catch.HasCaught());
+ if (!expected_to_throw) {
+ CHECK_EQ(10, signature_callback_count);
+ } else {
+ CHECK_EQ(v8_str("TypeError: Illegal invocation"),
+ try_catch.Exception()->ToString());
+ }
+}
+
+
THREADED_TEST(ReceiverSignature) {
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
+ // Setup templates.
v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
- fun->PrototypeTemplate()->Set(
- v8_str("m"),
- v8::FunctionTemplate::New(IncrementingSignatureCallback,
- v8::Handle<Value>(),
- sig));
- fun->PrototypeTemplate()->SetAccessorProperty(
- v8_str("n"),
- v8::FunctionTemplate::New(IncrementingSignatureCallback,
- v8::Handle<Value>(),
- sig));
- env->Global()->Set(v8_str("Fun"), fun->GetFunction());
- Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
- env->Global()->Set(v8_str("fun_instance"), fun_instance);
- signature_callback_count = 0;
- int expected_count = 0;
- signature_expected_receiver = fun_instance;
- CompileRun(
- "var o = fun_instance;"
- "var key_n = 'n';"
- "for (var i = 0; i < 10; i++) o.m();"
- "for (var i = 0; i < 10; i++) o.n;"
- "for (var i = 0; i < 10; i++) o[key_n];");
- expected_count += 30;
- CHECK_EQ(expected_count, signature_callback_count);
+ v8::Handle<v8::FunctionTemplate> callback_sig =
+ v8::FunctionTemplate::New(
+ IncrementingSignatureCallback, Local<Value>(), sig);
+ v8::Handle<v8::FunctionTemplate> callback =
+ v8::FunctionTemplate::New(IncrementingSignatureCallback);
v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
sub_fun->Inherit(fun);
- fun_instance = sub_fun->InstanceTemplate()->NewInstance();
- env->Global()->Set(v8_str("fun_instance"), fun_instance);
- signature_expected_receiver = fun_instance;
- CompileRun(
- "var o = fun_instance;"
- "var key_n = 'n';"
- "for (var i = 0; i < 10; i++) o.m();"
- "for (var i = 0; i < 10; i++) o.n;"
- "for (var i = 0; i < 10; i++) o[key_n];");
- expected_count += 30;
- CHECK_EQ(expected_count, signature_callback_count);
- v8::TryCatch try_catch;
- CompileRun(
- "var o = { };"
- "o.m = Fun.prototype.m;"
- "o.m();");
- CHECK_EQ(expected_count, signature_callback_count);
- CHECK(try_catch.HasCaught());
- CompileRun(
- "var o = { };"
- "o.n = Fun.prototype.n;"
- "o.n;");
- CHECK_EQ(expected_count, signature_callback_count);
- CHECK(try_catch.HasCaught());
- try_catch.Reset();
v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
- sub_fun->Inherit(fun);
+ // Install properties.
+ v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
+ fun_proto->Set(v8_str("prop_sig"), callback_sig);
+ fun_proto->Set(v8_str("prop"), callback);
+ fun_proto->SetAccessorProperty(
+ v8_str("accessor_sig"), callback_sig, callback_sig);
+ fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
+ // Instantiate templates.
+ Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
+ Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
+ // Setup global variables.
+ env->Global()->Set(v8_str("Fun"), fun->GetFunction());
env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
+ env->Global()->Set(v8_str("fun_instance"), fun_instance);
+ env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
CompileRun(
- "var o = new UnrelFun();"
- "o.m = Fun.prototype.m;"
- "o.m();");
- CHECK_EQ(expected_count, signature_callback_count);
- CHECK(try_catch.HasCaught());
- try_catch.Reset();
- CompileRun(
- "var o = new UnrelFun();"
- "o.n = Fun.prototype.n;"
- "o.n;");
- CHECK_EQ(expected_count, signature_callback_count);
- CHECK(try_catch.HasCaught());
+ "var accessor_sig_key = 'accessor_sig';"
+ "var accessor_key = 'accessor';"
+ "var prop_sig_key = 'prop_sig';"
+ "var prop_key = 'prop';"
+ ""
+ "function copy_props(obj) {"
+ " var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
+ " var source = Fun.prototype;"
+ " for (var i in keys) {"
+ " var key = keys[i];"
+ " var desc = Object.getOwnPropertyDescriptor(source, key);"
+ " Object.defineProperty(obj, key, desc);"
+ " }"
+ "}"
+ ""
+ "var obj = {};"
+ "copy_props(obj);"
+ "var unrel = new UnrelFun();"
+ "copy_props(unrel);");
+ // Test with and without ICs
+ const char* test_objects[] = {
+ "fun_instance", "sub_fun_instance", "obj", "unrel" };
+ unsigned bad_signature_start_offset = 2;
+ for (unsigned i = 0; i < ARRAY_SIZE(test_objects); i++) {
+ i::ScopedVector<char> source(200);
+ i::OS::SNPrintF(
+ source, "var test_object = %s; test_object", test_objects[i]);
+ Local<Value> test_object = CompileRun(source.start());
+ TestSignature("test_object.prop();", test_object);
+ TestSignature("test_object.accessor;", test_object);
+ TestSignature("test_object[accessor_key];", test_object);
+ TestSignature("test_object.accessor = 1;", test_object);
+ TestSignature("test_object[accessor_key] = 1;", test_object);
+ if (i >= bad_signature_start_offset) test_object = Local<Value>();
+ TestSignature("test_object.prop_sig();", test_object);
+ TestSignature("test_object.accessor_sig;", test_object);
+ TestSignature("test_object[accessor_sig_key];", test_object);
+ TestSignature("test_object.accessor_sig = 1;", test_object);
+ TestSignature("test_object[accessor_sig_key] = 1;", test_object);
+ }
}
@@ -3208,13 +3246,8 @@
v8::HandleScope scope(isolate);
v8::Local<String> local = v8::Local<String>::New(v8_str("str"));
v8::Persistent<String> global_string(isolate, local);
-#ifdef V8_USE_UNSAFE_HANDLES
- v8::Persistent<Value> global_value =
- v8::Persistent<Value>::Cast(global_string);
-#else
v8::Persistent<Value>& global_value =
v8::Persistent<Value>::Cast(global_string);
-#endif
CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
CHECK(global_string == v8::Persistent<String>::Cast(global_value));
global_string.Dispose();
@@ -12632,6 +12665,75 @@
}
}
+template<class T>
+struct CopyablePersistentTraits {
+ typedef Persistent<T, CopyablePersistentTraits<T> > CopyablePersistent;
+ static const bool kResetInDestructor = true;
+ template<class S, class M>
+ V8_INLINE(static void Copy(const Persistent<S, M>& source,
+ CopyablePersistent* dest)) {
+ // do nothing, just allow copy
+ }
+};
+
+
+TEST(CopyablePersistent) {
+ LocalContext context;
+ v8::Isolate* isolate = context->GetIsolate();
+ i::GlobalHandles* globals =
+ reinterpret_cast<i::Isolate*>(isolate)->global_handles();
+ int initial_handles = globals->global_handles_count();
+ {
+ v8::Persistent<v8::Object, CopyablePersistentTraits<v8::Object> > handle1;
+ {
+ v8::HandleScope scope(isolate);
+ handle1.Reset(isolate, v8::Object::New());
+ }
+ CHECK_EQ(initial_handles + 1, globals->global_handles_count());
+ v8::Persistent<v8::Object, CopyablePersistentTraits<v8::Object> > handle2;
+ handle2 = handle1;
+ CHECK(handle1 == handle2);
+ CHECK_EQ(initial_handles + 2, globals->global_handles_count());
+ v8::Persistent<v8::Object, CopyablePersistentTraits<v8::Object> >
+ handle3(handle2);
+ CHECK(handle1 == handle3);
+ CHECK_EQ(initial_handles + 3, globals->global_handles_count());
+ }
+ // Verify autodispose
+// CHECK_EQ(initial_handles, globals->global_handles_count());
+}
+
+
+static void WeakApiCallback(
+ const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
+ Local<Value> value = data.GetValue()->Get(v8_str("key"));
+ CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
+ data.GetParameter()->Reset();
+ delete data.GetParameter();
+}
+
+
+TEST(WeakCallbackApi) {
+ LocalContext context;
+ v8::Isolate* isolate = context->GetIsolate();
+ i::GlobalHandles* globals =
+ reinterpret_cast<i::Isolate*>(isolate)->global_handles();
+ int initial_handles = globals->global_handles_count();
+ {
+ v8::HandleScope scope(isolate);
+ v8::Local<v8::Object> obj = v8::Object::New();
+ obj->Set(v8_str("key"), v8::Integer::New(231, isolate));
+ v8::Persistent<v8::Object>* handle =
+ new v8::Persistent<v8::Object>(isolate, obj);
+ handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
+ WeakApiCallback);
+ }
+ reinterpret_cast<i::Isolate*>(isolate)->heap()->
+ CollectAllGarbage(i::Heap::kNoGCFlags);
+ // Verify disposed.
+ CHECK_EQ(initial_handles, globals->global_handles_count());
+}
+
v8::Persistent<v8::Object> some_object;
v8::Persistent<v8::Object> bad_handle;
@@ -20453,4 +20555,34 @@
ExpectInt32("obj.interceptor_age", 103);
}
+
#endif // V8_OS_POSIX
+
+
+static Local<Value> function_new_expected_env;
+static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
+ CHECK_EQ(function_new_expected_env, info.Data());
+ info.GetReturnValue().Set(17);
+}
+
+
+THREADED_TEST(FunctionNew) {
+ LocalContext env;
+ v8::Isolate* isolate = env->GetIsolate();
+ v8::HandleScope scope(isolate);
+ Local<Object> data = v8::Object::New();
+ function_new_expected_env = data;
+ Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
+ env->Global()->Set(v8_str("func"), func);
+ Local<Value> result = CompileRun("func();");
+ CHECK_EQ(v8::Integer::New(17, isolate), result);
+ // Verify function not cached
+ int serial_number =
+ i::Smi::cast(v8::Utils::OpenHandle(*func)
+ ->shared()->get_api_func_data()->serial_number())->value();
+ i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
+ i::Object* elm = i_isolate->native_context()->function_cache()
+ ->GetElementNoExceptionThrown(i_isolate, serial_number);
+ CHECK(elm->IsNull());
+}
+
diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc
index 6bd6fee..2540a3d 100644
--- a/test/cctest/test-debug.cc
+++ b/test/cctest/test-debug.cc
@@ -37,6 +37,7 @@
#include "compilation-cache.h"
#include "debug.h"
#include "deoptimizer.h"
+#include "frames.h"
#include "platform.h"
#include "platform/condition-variable.h"
#include "platform/socket.h"
@@ -60,6 +61,7 @@
using ::v8::internal::Debugger;
using ::v8::internal::CommandMessage;
using ::v8::internal::CommandMessageQueue;
+using ::v8::internal::StackFrame;
using ::v8::internal::StepAction;
using ::v8::internal::StepIn; // From StepAction enum
using ::v8::internal::StepNext; // From StepAction enum
@@ -390,7 +392,7 @@
// Prepare to step to next break location.
static void PrepareStep(StepAction step_action) {
v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
- debug->PrepareStep(step_action, 1);
+ debug->PrepareStep(step_action, 1, StackFrame::NO_ID);
}
diff --git a/test/cctest/test-thread-termination.cc b/test/cctest/test-thread-termination.cc
index 4c08539..619bce7 100644
--- a/test/cctest/test-thread-termination.cc
+++ b/test/cctest/test-thread-termination.cc
@@ -192,73 +192,6 @@
}
-class LoopingThread : public v8::internal::Thread {
- public:
- LoopingThread() : Thread("LoopingThread") { }
- void Run() {
- v8::Locker locker(CcTest::default_isolate());
- v8::HandleScope scope(CcTest::default_isolate());
- v8_thread_id_ = v8::V8::GetCurrentThreadId();
- v8::Handle<v8::ObjectTemplate> global =
- CreateGlobalTemplate(Signal, DoLoop);
- v8::Handle<v8::Context> context =
- v8::Context::New(v8::Isolate::GetCurrent(), NULL, global);
- v8::Context::Scope context_scope(context);
- CHECK(!v8::V8::IsExecutionTerminating());
- // Run a loop that will be infinite if thread termination does not work.
- v8::Handle<v8::String> source =
- v8::String::New("try { loop(); fail(); } catch(e) { fail(); }");
- v8::Script::Compile(source)->Run();
- }
-
- int GetV8ThreadId() { return v8_thread_id_; }
-
- private:
- int v8_thread_id_;
-};
-
-
-// Test that multiple threads using default isolate can be terminated
-// from another thread when using Lockers and preemption.
-TEST(TerminateMultipleV8ThreadsDefaultIsolate) {
- {
- v8::Locker locker(CcTest::default_isolate());
- v8::V8::Initialize();
- v8::Locker::StartPreemption(1);
- semaphore = new v8::internal::Semaphore(0);
- }
- const int kThreads = 2;
- i::List<LoopingThread*> threads(kThreads);
- for (int i = 0; i < kThreads; i++) {
- threads.Add(new LoopingThread());
- }
- for (int i = 0; i < kThreads; i++) {
- threads[i]->Start();
- }
- // Wait until all threads have signaled the semaphore.
- for (int i = 0; i < kThreads; i++) {
- semaphore->Wait();
- }
- {
- v8::Locker locker(CcTest::default_isolate());
- for (int i = 0; i < kThreads; i++) {
- v8::V8::TerminateExecution(threads[i]->GetV8ThreadId());
- }
- }
- for (int i = 0; i < kThreads; i++) {
- threads[i]->Join();
- delete threads[i];
- }
- {
- v8::Locker locker(CcTest::default_isolate());
- v8::Locker::StopPreemption();
- }
-
- delete semaphore;
- semaphore = NULL;
-}
-
-
int call_count = 0;
diff --git a/test/mjsunit/compiler/escape-analysis.js b/test/mjsunit/compiler/escape-analysis.js
index 7452e3b..74e638a 100644
--- a/test/mjsunit/compiler/escape-analysis.js
+++ b/test/mjsunit/compiler/escape-analysis.js
@@ -25,7 +25,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Flags: --allow-natives-syntax --use-escape-analysis
+// Flags: --allow-natives-syntax --use-escape-analysis --expose-gc
// Test stores on a join path.
@@ -241,3 +241,33 @@
test(osr2);
test(osr3);
})();
+
+
+// Test out-of-bounds access on captured objects.
+(function testOOB() {
+ function cons1() {
+ this.x = 1;
+ this.y = 2;
+ this.z = 3;
+ }
+ function cons2() {
+ this.a = 7;
+ }
+ function oob(constructor, branch) {
+ var o = new constructor();
+ if (branch) {
+ return o.a;
+ } else {
+ return o.z;
+ }
+ }
+ assertEquals(3, oob(cons1, false));
+ assertEquals(3, oob(cons1, false));
+ assertEquals(7, oob(cons2, true));
+ assertEquals(7, oob(cons2, true));
+ gc(); // Clears type feedback of constructor call.
+ assertEquals(7, oob(cons2, true));
+ assertEquals(7, oob(cons2, true));
+ %OptimizeFunctionOnNextCall(oob);
+ assertEquals(7, oob(cons2, true));
+})();
diff --git a/test/mjsunit/debug-step-4-in-frame.js b/test/mjsunit/debug-step-4-in-frame.js
new file mode 100644
index 0000000..65ac490
--- /dev/null
+++ b/test/mjsunit/debug-step-4-in-frame.js
@@ -0,0 +1,132 @@
+// Copyright 2008 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.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+// Tests how debugger can step over not necessarily in the top frame.
+
+// Simple 3 functions, that protocol their execution state in global
+// variable state.
+var state;
+
+function f() {
+ var a = 1978;
+ for (state[2] = 0; state[2] < 5; state[2]++) {
+ void String(a);
+ }
+}
+function g() {
+ for (state[1] = 0; state[1] < 5; state[1]++) {
+ f();
+ }
+}
+function h() {
+ state = [-1, -1, -1];
+ for (state[0] = 0; state[0] < 5; state[0]++) {
+ g();
+ }
+}
+
+function TestCase(frame_index, step_count, expected_final_state) {
+ print("Test case, parameters " + frame_index + "/" + step_count);
+
+ var listener_exception = null;
+ var state_snapshot;
+ var listener_state;
+ var bp;
+
+ function listener(event, exec_state, event_data, data) {
+ print("Here ("+event+"/"+listener_state+"): " +
+ exec_state.frame(0).sourceLineText());
+ try {
+ if (event == Debug.DebugEvent.Break) {
+ if (listener_state == 0) {
+ Debug.clearBreakPoint(bp);
+ var context_frame;
+ if (frame_index !== undefined) {
+ context_frame = exec_state.frame(frame_index);
+ }
+ exec_state.prepareStep(Debug.StepAction.StepNext,
+ step_count, context_frame);
+ listener_state = 1;
+ } else if (listener_state == 1) {
+ state_snapshot = String(state);
+ print("State: " + state_snapshot);
+ Debug.setListener(null);
+ listener_state = 2;
+ }
+ }
+ } catch (e) {
+ listener_exception = e;
+ }
+ }
+
+
+ // Add the debug event listener.
+ listener_state = 0;
+ Debug.setListener(listener);
+ bp = Debug.setBreakPoint(f, 1);
+
+ h();
+ Debug.setListener(null);
+ if (listener_exception !== null) {
+ print("Exception caught: " + listener_exception);
+ assertUnreachable();
+ }
+
+ assertEquals(expected_final_state, state_snapshot);
+}
+
+
+// Warm-up -- make sure all is compiled and ready for breakpoint.
+h();
+
+
+// Stepping in the default (top) frame.
+TestCase(undefined, 0, "0,0,-1");
+TestCase(undefined, 1, "0,0,-1");
+TestCase(undefined, 2, "0,0,0");
+TestCase(undefined, 5, "0,0,1");
+TestCase(undefined, 8, "0,0,3");
+
+// Stepping in the frame #0 (should be exactly the same as above).
+TestCase(0, 0, "0,0,-1");
+TestCase(0, 1, "0,0,-1");
+TestCase(0, 2, "0,0,0");
+TestCase(0, 5, "0,0,1");
+TestCase(0, 8, "0,0,3");
+
+// Stepping in the frame #1.
+TestCase(1, 0, "0,0,5");
+TestCase(1, 3, "0,1,5");
+TestCase(1, 8, "0,4,5");
+
+// Stepping in the frame #2.
+TestCase(2, 3, "1,5,5");
+TestCase(2, 8, "4,5,5");
diff --git a/test/mjsunit/lithium/MulI.js b/test/mjsunit/lithium/MulI.js
new file mode 100644
index 0000000..68588bd
--- /dev/null
+++ b/test/mjsunit/lithium/MulI.js
@@ -0,0 +1,70 @@
+// Copyright 2013 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.
+
+// Flags: --allow-natives-syntax --no-use-osr
+
+function foo_smi(a, b) {
+ var result = a * b;
+ result += a * 35;
+ result += a * -1;
+ result += a * 1;
+ result += a * 0;
+ return result * a;
+}
+
+function foo_int(a, b) {
+ var result = a * b;
+ result += a * 35;
+ result += a * -1;
+ result += a * 1;
+ result += a * 0;
+ return result * a;
+}
+
+foo_smi(10, 5);
+var r1 = foo_smi(10, 5);
+%OptimizeFunctionOnNextCall(foo_smi);
+var r2 = foo_smi(10, 5);
+
+assertEquals(r1, r2);
+
+foo_int(10, 21474800);
+var r3 = foo_int(10, 21474800);
+%OptimizeFunctionOnNextCall(foo_int);
+var r4 = foo_int(10, 21474800);
+
+assertEquals(r3, r4);
+
+// Check overflow with -1 constant.
+function foo2(value) {
+ return value * -1;
+}
+
+foo2(-2147483600);
+foo2(-2147483600);
+%OptimizeFunctionOnNextCall(foo2);
+assertEquals(2147483648, foo2(-2147483648));
diff --git a/test/mjsunit/regress/regress-crbug-285355.js b/test/mjsunit/regress/regress-crbug-285355.js
new file mode 100644
index 0000000..ebd480a
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-285355.js
@@ -0,0 +1,43 @@
+// Copyright 2013 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.
+
+// Flags: --allow-natives-syntax
+
+function inverted_index() {
+ return ~1;
+}
+
+%NeverOptimizeFunction(inverted_index);
+
+function crash(array) {
+ return array[~inverted_index()] = 2;
+}
+
+assertEquals(2, crash(new Array(1)));
+assertEquals(2, crash(new Array(1)));
+%OptimizeFunctionOnNextCall(crash)
+assertEquals(2, crash(new Array(1)));
diff --git a/tools/run-tests.py b/tools/run-tests.py
index 48682d4..4f212d6 100755
--- a/tools/run-tests.py
+++ b/tools/run-tests.py
@@ -293,7 +293,7 @@
if timeout == -1:
# Simulators are slow, therefore allow a longer default timeout.
if arch in SLOW_ARCHS:
- timeout = 2 * TIMEOUT_DEFAULT;
+ timeout = 3 * TIMEOUT_DEFAULT;
else:
timeout = TIMEOUT_DEFAULT;