Version 3.19.7
Added support for //# sourceURL similar to deprecated //@ sourceURL one. (issue 2702)
Made sure IfBuilder::Return clears the current block. (Chromium issue 243868)
Fixed two CPU profiler tests on ARM and MIPS simulators (issue 2628)
Fixed idle incremental GC for large objects. (Chromium issue 241815)
Disabled --optimize-constructed-arrays due to crashes (Chromium issue 244461)
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@14900 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index ee72eb7..7516c2b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2013-05-31: Version 3.19.7
+
+ Added support for //# sourceURL similar to deprecated //@ sourceURL one.
+ (issue 2702)
+
+ Made sure IfBuilder::Return clears the current block.
+ (Chromium issue 243868)
+
+ Fixed two CPU profiler tests on ARM and MIPS simulators
+ (issue 2628)
+
+ Fixed idle incremental GC for large objects.
+ (Chromium issue 241815)
+
+ Disabled --optimize-constructed-arrays due to crashes
+ (Chromium issue 244461)
+
+ Performance and stability improvements on all platforms.
+
+
2013-05-28: Version 3.19.6
Fixed IfBuilder::Deopt to clear the current block
diff --git a/include/v8.h b/include/v8.h
index 51040fe..3fef9cd 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -228,6 +228,7 @@
#define V8_USE_UNSAFE_HANDLES
+#define V8_USE_OLD_STYLE_PERSISTENT_HANDLE_VISITORS
/**
* An object reference managed by the v8 garbage collector.
@@ -370,11 +371,11 @@
#endif
private:
- template<class F>
- friend class Persistent;
- template<class F>
- friend class Local;
+ template<class F> friend class Persistent;
+ template<class F> friend class Local;
friend class Arguments;
+ template<class F> friend class FunctionCallbackInfo;
+ template<class F> friend class PropertyCallbackInfo;
friend class String;
friend class Object;
friend class AccessorInfo;
@@ -385,6 +386,7 @@
friend class Context;
friend class InternalHandleHelper;
friend class LocalContext;
+ friend class HandleScope;
#ifndef V8_USE_UNSAFE_HANDLES
V8_INLINE(static Handle<T> New(Isolate* isolate, T* that));
@@ -458,17 +460,18 @@
#endif
private:
- template<class F>
- friend class Persistent;
- template<class F>
- friend class Handle;
+ template<class F> friend class Persistent;
+ template<class F> friend class Handle;
friend class Arguments;
+ template<class F> friend class FunctionCallbackInfo;
+ template<class F> friend class PropertyCallbackInfo;
friend class String;
friend class Object;
friend class AccessorInfo;
friend class Context;
friend class InternalHandleHelper;
friend class LocalContext;
+ friend class HandleScope;
V8_INLINE(static Local<T> New(Isolate* isolate, T* that));
};
@@ -516,6 +519,10 @@
template <class S> V8_INLINE(Persistent(Isolate* isolate, Handle<S> that))
: val_(*New(isolate, that)) { }
+ template <class S> V8_INLINE(Persistent(Isolate* isolate,
+ Persistent<S>& that)) // NOLINT
+ : val_(*New(isolate, that)) { }
+
#else
/**
* Creates an empty persistent handle that doesn't point to any
@@ -632,20 +639,8 @@
* This handle's reference, and any other references to the storage
* cell remain and IsEmpty will still return false.
*/
- // TODO(dcarney): remove before cutover
- V8_INLINE(void Dispose(Isolate* isolate));
-
- template<typename S, typename P>
- V8_INLINE(void MakeWeak(
- Isolate* isolate,
- P* parameters,
- typename WeakReferenceCallbacks<S, P>::Revivable callback));
-
- template<typename P>
- V8_INLINE(void MakeWeak(
- Isolate* isolate,
- P* parameters,
- typename WeakReferenceCallbacks<T, P>::Revivable callback));
+ // TODO(dcarney): deprecate
+ V8_INLINE(void Dispose(Isolate* isolate)) { Dispose(); }
/**
* Make the reference to this object weak. When only weak handles
@@ -653,6 +648,34 @@
* 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));
+
+ // TODO(dcarney): deprecate
+ template<typename S, typename P>
+ V8_INLINE(void MakeWeak(
+ Isolate* isolate,
+ P* parameters,
+ typename WeakReferenceCallbacks<S, P>::Revivable callback)) {
+ MakeWeak<S, P>(parameters, callback);
+ }
+
+ // TODO(dcarney): deprecate
+ template<typename P>
+ V8_INLINE(void MakeWeak(
+ Isolate* isolate,
+ P* parameters,
+ typename WeakReferenceCallbacks<T, P>::Revivable callback)) {
+ MakeWeak<P>(parameters, callback);
+ }
+
// TODO(dcarney): remove before cutover
V8_INLINE(void MakeWeak(Isolate* isolate,
void* parameters,
@@ -660,10 +683,8 @@
V8_INLINE(void ClearWeak());
- // TODO(dcarney): remove before cutover
- V8_INLINE(void ClearWeak(Isolate* isolate));
-
- V8_INLINE(void MarkIndependent());
+ // TODO(dcarney): deprecate
+ V8_INLINE(void ClearWeak(Isolate* isolate)) { ClearWeak(); }
/**
* Marks the reference to this object independent. Garbage collector is free
@@ -671,10 +692,10 @@
* independent handle should not assume that it will be preceded by a global
* GC prologue callback or followed by a global GC epilogue callback.
*/
- // TODO(dcarney): remove before cutover
- V8_INLINE(void MarkIndependent(Isolate* isolate));
+ V8_INLINE(void MarkIndependent());
- V8_INLINE(void MarkPartiallyDependent());
+ // TODO(dcarney): deprecate
+ V8_INLINE(void MarkIndependent(Isolate* isolate)) { MarkIndependent(); }
/**
* Marks the reference to this object partially dependent. Partially dependent
@@ -684,49 +705,63 @@
* external dependencies. This mark is automatically cleared after each
* garbage collection.
*/
- // TODO(dcarney): remove before cutover
- V8_INLINE(void MarkPartiallyDependent(Isolate* isolate));
+ V8_INLINE(void MarkPartiallyDependent());
+
+ // TODO(dcarney): deprecate
+ V8_INLINE(void MarkPartiallyDependent(Isolate* isolate)) {
+ MarkPartiallyDependent();
+ }
V8_INLINE(bool IsIndependent() const);
- // TODO(dcarney): remove before cutover
- V8_INLINE(bool IsIndependent(Isolate* isolate) const);
-
- V8_INLINE(bool IsNearDeath() const);
+ // TODO(dcarney): deprecate
+ V8_INLINE(bool IsIndependent(Isolate* isolate) const) {
+ return IsIndependent();
+ }
/** Checks if the handle holds the only reference to an object. */
- // TODO(dcarney): remove before cutover
- V8_INLINE(bool IsNearDeath(Isolate* isolate) const);
+ V8_INLINE(bool IsNearDeath() const);
- V8_INLINE(bool IsWeak() const);
+ // TODO(dcarney): deprecate
+ V8_INLINE(bool IsNearDeath(Isolate* isolate) const) { return IsNearDeath(); }
/** Returns true if the handle's reference is weak. */
- // TODO(dcarney): remove before cutover
- V8_INLINE(bool IsWeak(Isolate* isolate) const);
+ V8_INLINE(bool IsWeak() const);
- V8_INLINE(void SetWrapperClassId(uint16_t class_id));
+ // TODO(dcarney): deprecate
+ V8_INLINE(bool IsWeak(Isolate* isolate) const) { return IsWeak(); }
/**
* Assigns a wrapper class ID to the handle. See RetainedObjectInfo interface
* description in v8-profiler.h for details.
*/
- // TODO(dcarney): remove before cutover
- V8_INLINE(void SetWrapperClassId(Isolate* isolate, uint16_t class_id));
+ V8_INLINE(void SetWrapperClassId(uint16_t class_id));
- V8_INLINE(uint16_t WrapperClassId() const);
+ // TODO(dcarney): deprecate
+ V8_INLINE(void SetWrapperClassId(Isolate* isolate, uint16_t class_id)) {
+ SetWrapperClassId(class_id);
+ }
/**
* Returns the class ID previously assigned to this handle or 0 if no class ID
* was previously assigned.
*/
- // TODO(dcarney): remove before cutover
- V8_INLINE(uint16_t WrapperClassId(Isolate* isolate) const);
+ V8_INLINE(uint16_t WrapperClassId() const);
+
+ // TODO(dcarney): deprecate
+ V8_INLINE(uint16_t WrapperClassId(Isolate* isolate) const) {
+ 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
@@ -776,10 +811,8 @@
#endif
private:
- template<class F>
- friend class Handle;
- template<class F>
- friend class Local;
+ template<class F> friend class Handle;
+ template<class F> friend class Local;
friend class ImplementationUtilities;
friend class ObjectTemplate;
friend class Context;
@@ -1219,7 +1252,8 @@
/**
* Returns the name of the resource that contains the script for the
* function for this StackFrame or sourceURL value if the script name
- * is undefined and its source ends with //@ sourceURL=... string.
+ * is undefined and its source ends with //# sourceURL=... string or
+ * deprecated //@ sourceURL=... string.
*/
Local<String> GetScriptNameOrSourceURL() const;
@@ -4107,8 +4141,13 @@
class V8EXPORT PersistentHandleVisitor { // NOLINT
public:
virtual ~PersistentHandleVisitor() {}
+#ifdef V8_USE_OLD_STYLE_PERSISTENT_HANDLE_VISITORS
virtual void VisitPersistentHandle(Persistent<Value> value,
uint16_t class_id) {}
+#else
+ virtual void VisitPersistentHandle(Persistent<Value>* value,
+ uint16_t class_id) {}
+#endif
};
@@ -4334,41 +4373,6 @@
static void RemoveCallCompletedCallback(CallCompletedCallback callback);
/**
- * Allows the host application to group objects together. If one
- * object in the group is alive, all objects in the group are alive.
- * After each garbage collection, object groups are removed. It is
- * intended to be used in the before-garbage-collection callback
- * function, for instance to simulate DOM tree connections among JS
- * wrapper objects. Object groups for all dependent handles need to
- * be provided for kGCTypeMarkSweepCompact collections, for all other
- * garbage collection types it is sufficient to provide object groups
- * for partially dependent handles only.
- * See v8-profiler.h for RetainedObjectInfo interface description.
- */
- // TODO(marja): deprecate AddObjectGroup. Use Isolate::SetObjectGroupId and
- // HeapProfiler::SetRetainedObjectInfo instead.
- static void AddObjectGroup(Persistent<Value>* objects,
- size_t length,
- RetainedObjectInfo* info = NULL);
- static void AddObjectGroup(Isolate* isolate,
- Persistent<Value>* objects,
- size_t length,
- RetainedObjectInfo* info = NULL);
-
- /**
- * Allows the host application to declare implicit references between
- * the objects: if |parent| is alive, all |children| are alive too.
- * After each garbage collection, all implicit references
- * are removed. It is intended to be used in the before-garbage-collection
- * callback function.
- */
- // TODO(marja): Deprecate AddImplicitReferences. Use
- // Isolate::SetReferenceFromGroup instead.
- static void AddImplicitReferences(Persistent<Object> parent,
- Persistent<Value>* children,
- size_t length);
-
- /**
* Initializes from snapshot if possible. Otherwise, attempts to
* initialize from scratch. This function is called implicitly if
* you use the API without calling it first.
@@ -4600,13 +4604,11 @@
internal::Object** handle);
static void DisposeGlobal(internal::Object** global_handle);
typedef WeakReferenceCallbacks<Value, void>::Revivable RevivableCallback;
- static void MakeWeak(internal::Isolate* isolate,
- internal::Object** global_handle,
+ static void MakeWeak(internal::Object** global_handle,
void* data,
RevivableCallback weak_reference_callback,
NearDeathCallback near_death_callback);
- static void ClearWeak(internal::Isolate* isolate,
- internal::Object** global_handle);
+ static void ClearWeak(internal::Object** global_handle);
template <class T> friend class Handle;
template <class T> friend class Local;
@@ -5495,15 +5497,8 @@
template <class T>
bool Persistent<T>::IsIndependent() const {
- return IsIndependent(Isolate::GetCurrent());
-}
-
-
-template <class T>
-bool Persistent<T>::IsIndependent(Isolate* isolate) const {
typedef internal::Internals I;
if (this->IsEmpty()) return false;
- if (!I::IsInitialized(isolate)) return false;
return I::GetNodeFlag(reinterpret_cast<internal::Object**>(this->val_),
I::kNodeIsIndependentShift);
}
@@ -5511,15 +5506,8 @@
template <class T>
bool Persistent<T>::IsNearDeath() const {
- return IsNearDeath(Isolate::GetCurrent());
-}
-
-
-template <class T>
-bool Persistent<T>::IsNearDeath(Isolate* isolate) const {
typedef internal::Internals I;
if (this->IsEmpty()) return false;
- if (!I::IsInitialized(isolate)) return false;
return I::GetNodeState(reinterpret_cast<internal::Object**>(this->val_)) ==
I::kNodeStateIsNearDeathValue;
}
@@ -5527,15 +5515,8 @@
template <class T>
bool Persistent<T>::IsWeak() const {
- return IsWeak(Isolate::GetCurrent());
-}
-
-
-template <class T>
-bool Persistent<T>::IsWeak(Isolate* isolate) const {
typedef internal::Internals I;
if (this->IsEmpty()) return false;
- if (!I::IsInitialized(isolate)) return false;
return I::GetNodeState(reinterpret_cast<internal::Object**>(this->val_)) ==
I::kNodeStateIsWeakValue;
}
@@ -5552,21 +5533,13 @@
template <class T>
-void Persistent<T>::Dispose(Isolate* isolate) {
- Dispose();
-}
-
-
-template <class T>
template <typename S, typename P>
void Persistent<T>::MakeWeak(
- Isolate* isolate,
P* parameters,
typename WeakReferenceCallbacks<S, P>::Revivable callback) {
TYPE_CHECK(S, T);
typedef typename WeakReferenceCallbacks<Value, void>::Revivable Revivable;
- V8::MakeWeak(reinterpret_cast<internal::Isolate*>(isolate),
- reinterpret_cast<internal::Object**>(this->val_),
+ V8::MakeWeak(reinterpret_cast<internal::Object**>(this->val_),
parameters,
reinterpret_cast<Revivable>(callback),
NULL);
@@ -5576,10 +5549,9 @@
template <class T>
template <typename P>
void Persistent<T>::MakeWeak(
- Isolate* isolate,
P* parameters,
typename WeakReferenceCallbacks<T, P>::Revivable callback) {
- MakeWeak<T, P>(isolate, parameters, callback);
+ MakeWeak<T, P>(parameters, callback);
}
@@ -5587,59 +5559,38 @@
void Persistent<T>::MakeWeak(Isolate* isolate,
void* parameters,
NearDeathCallback callback) {
- V8::MakeWeak(reinterpret_cast<internal::Isolate*>(isolate),
- reinterpret_cast<internal::Object**>(this->val_),
+ V8::MakeWeak(reinterpret_cast<internal::Object**>(this->val_),
parameters,
NULL,
callback);
}
-template <class T>
-void Persistent<T>::ClearWeak() {
- ClearWeak(Isolate::GetCurrent());
-}
template <class T>
-void Persistent<T>::ClearWeak(Isolate* isolate) {
- V8::ClearWeak(reinterpret_cast<internal::Isolate*>(isolate),
- reinterpret_cast<internal::Object**>(this->val_));
+void Persistent<T>::ClearWeak() {
+ V8::ClearWeak(reinterpret_cast<internal::Object**>(this->val_));
}
+
template <class T>
void Persistent<T>::MarkIndependent() {
- MarkIndependent(Isolate::GetCurrent());
-}
-
-template <class T>
-void Persistent<T>::MarkIndependent(Isolate* isolate) {
typedef internal::Internals I;
if (this->IsEmpty()) return;
- if (!I::IsInitialized(isolate)) return;
I::UpdateNodeFlag(reinterpret_cast<internal::Object**>(this->val_),
true,
I::kNodeIsIndependentShift);
}
-template <class T>
-void Persistent<T>::MarkPartiallyDependent() {
- MarkPartiallyDependent(Isolate::GetCurrent());
-}
template <class T>
-void Persistent<T>::MarkPartiallyDependent(Isolate* isolate) {
+void Persistent<T>::MarkPartiallyDependent() {
typedef internal::Internals I;
if (this->IsEmpty()) return;
- if (!I::IsInitialized(isolate)) return;
I::UpdateNodeFlag(reinterpret_cast<internal::Object**>(this->val_),
true,
I::kNodeIsPartiallyDependentShift);
}
-template <class T>
-void Persistent<T>::SetWrapperClassId(uint16_t class_id) {
- SetWrapperClassId(Isolate::GetCurrent(), class_id);
-}
-
template <class T>
void Persistent<T>::Reset(Isolate* isolate, const Handle<T>& other) {
@@ -5658,6 +5609,21 @@
}
+#ifndef V8_USE_UNSAFE_HANDLES
+template <class T>
+void Persistent<T>::Reset(Isolate* isolate, const Persistent<T>& other) {
+ Dispose(isolate);
+ 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() {
T* old;
@@ -5673,25 +5639,19 @@
template <class T>
-void Persistent<T>::SetWrapperClassId(Isolate* isolate, uint16_t class_id) {
+void Persistent<T>::SetWrapperClassId(uint16_t class_id) {
typedef internal::Internals I;
if (this->IsEmpty()) return;
- if (!I::IsInitialized(isolate)) return;
internal::Object** obj = reinterpret_cast<internal::Object**>(this->val_);
uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + I::kNodeClassIdOffset;
*reinterpret_cast<uint16_t*>(addr) = class_id;
}
-template <class T>
-uint16_t Persistent<T>::WrapperClassId() const {
- return WrapperClassId(Isolate::GetCurrent());
-}
template <class T>
-uint16_t Persistent<T>::WrapperClassId(Isolate* isolate) const {
+uint16_t Persistent<T>::WrapperClassId() const {
typedef internal::Internals I;
if (this->IsEmpty()) return 0;
- if (!I::IsInitialized(isolate)) return 0;
internal::Object** obj = reinterpret_cast<internal::Object**>(this->val_);
uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + I::kNodeClassIdOffset;
return *reinterpret_cast<uint16_t*>(addr);
@@ -5705,14 +5665,22 @@
template<typename S>
void ReturnValue<T>::Set(const Persistent<S>& handle) {
TYPE_CHECK(T, S);
- *value_ = *reinterpret_cast<internal::Object**>(*handle);
+ if (V8_UNLIKELY(handle.IsEmpty())) {
+ SetUndefined();
+ } else {
+ *value_ = *reinterpret_cast<internal::Object**>(*handle);
+ }
}
template<typename T>
template<typename S>
void ReturnValue<T>::Set(const Handle<S> handle) {
TYPE_CHECK(T, S);
- *value_ = *reinterpret_cast<internal::Object**>(*handle);
+ if (V8_UNLIKELY(handle.IsEmpty())) {
+ SetUndefined();
+ } else {
+ *value_ = *reinterpret_cast<internal::Object**>(*handle);
+ }
}
template<typename T>
diff --git a/samples/lineprocessor.cc b/samples/lineprocessor.cc
index 45e5dc3..635691e 100644
--- a/samples/lineprocessor.cc
+++ b/samples/lineprocessor.cc
@@ -25,10 +25,6 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// TODO(dcarney): remove
-#define V8_ALLOW_ACCESS_TO_RAW_HANDLE_CONSTRUCTOR
-#define V8_ALLOW_ACCESS_TO_PERSISTENT_IMPLICIT
-
#include <v8.h>
#ifdef ENABLE_DEBUGGER_SUPPORT
@@ -222,8 +218,7 @@
v8::Context::Scope context_scope(context);
#ifdef ENABLE_DEBUGGER_SUPPORT
- debug_message_context =
- v8::Persistent<v8::Context>::New(isolate, context);
+ debug_message_context.Reset(isolate, context);
v8::Locker locker(isolate);
@@ -439,7 +434,7 @@
}
if (res == NULL) {
v8::Handle<v8::Primitive> t = v8::Undefined();
- return v8::Handle<v8::String>(v8::String::Cast(*t));
+ return v8::Handle<v8::String>::Cast(t);
}
// Remove newline char
for (char* pos = buffer; *pos != '\0'; pos++) {
diff --git a/samples/process.cc b/samples/process.cc
index 8a41fae..1c1e7be 100644
--- a/samples/process.cc
+++ b/samples/process.cc
@@ -25,11 +25,6 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// TODO(dcarney): remove this
-#define V8_ALLOW_ACCESS_TO_RAW_HANDLE_CONSTRUCTOR
-#define V8_ALLOW_ACCESS_TO_PERSISTENT_IMPLICIT
-#define V8_ALLOW_ACCESS_TO_PERSISTENT_ARROW
-
#include <v8.h>
#include <string>
@@ -186,7 +181,7 @@
// The script compiled and ran correctly. Now we fetch out the
// Process function from the global object.
Handle<String> process_name = String::New("Process");
- Handle<Value> process_val = context_->Global()->Get(process_name);
+ Handle<Value> process_val = context->Global()->Get(process_name);
// If there is no Process function, or if it is not a function,
// bail out
@@ -197,7 +192,7 @@
// Store the function in a Persistent handle, since we also want
// that to remain after this call returns
- process_ = Persistent<Function>::New(GetIsolate(), process_fun);
+ process_.Reset(GetIsolate(), process_fun);
// All done; all went well
return true;
@@ -240,11 +235,14 @@
// Wrap the map object in a JavaScript wrapper
Handle<Object> opts_obj = WrapMap(opts);
+ v8::Local<v8::Context> context =
+ v8::Local<v8::Context>::New(GetIsolate(), context_);
+
// Set the options object as a property on the global object.
- context_->Global()->Set(String::New("options"), opts_obj);
+ context->Global()->Set(String::New("options"), opts_obj);
Handle<Object> output_obj = WrapMap(output);
- context_->Global()->Set(String::New("output"), output_obj);
+ context->Global()->Set(String::New("output"), output_obj);
return true;
}
@@ -271,7 +269,9 @@
// and one argument, the request.
const int argc = 1;
Handle<Value> argv[argc] = { request_obj };
- Handle<Value> result = process_->Call(context_->Global(), argc, argv);
+ v8::Local<v8::Function> process =
+ v8::Local<v8::Function>::New(GetIsolate(), process_);
+ Handle<Value> result = process->Call(context->Global(), argc, argv);
if (result.IsEmpty()) {
String::Utf8Value error(try_catch.Exception());
Log(*error);
@@ -310,7 +310,7 @@
// It only has to be created once, which we do on demand.
if (map_template_.IsEmpty()) {
Handle<ObjectTemplate> raw_template = MakeMapTemplate(GetIsolate());
- map_template_ = Persistent<ObjectTemplate>::New(GetIsolate(), raw_template);
+ map_template_.Reset(GetIsolate(), raw_template);
}
Handle<ObjectTemplate> templ =
Local<ObjectTemplate>::New(GetIsolate(), map_template_);
@@ -417,8 +417,7 @@
// It only has to be created once, which we do on demand.
if (request_template_.IsEmpty()) {
Handle<ObjectTemplate> raw_template = MakeRequestTemplate(GetIsolate());
- request_template_ =
- Persistent<ObjectTemplate>::New(GetIsolate(), raw_template);
+ request_template_.Reset(GetIsolate(), raw_template);
}
Handle<ObjectTemplate> templ =
Local<ObjectTemplate>::New(GetIsolate(), request_template_);
diff --git a/samples/shell.cc b/samples/shell.cc
index da18cc7..430dd96 100644
--- a/samples/shell.cc
+++ b/samples/shell.cc
@@ -25,11 +25,6 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// TODO(dcarney): remove this
-#define V8_ALLOW_ACCESS_TO_RAW_HANDLE_CONSTRUCTOR
-#define V8_ALLOW_ACCESS_TO_PERSISTENT_IMPLICIT
-#define V8_ALLOW_ACCESS_TO_PERSISTENT_ARROW
-
#include <v8.h>
#include <assert.h>
#include <fcntl.h>
diff --git a/src/api.cc b/src/api.cc
index a5ef054..c2c7930 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -625,23 +625,19 @@
}
-void V8::MakeWeak(i::Isolate* isolate,
- i::Object** object,
+void V8::MakeWeak(i::Object** object,
void* parameters,
RevivableCallback weak_reference_callback,
NearDeathCallback near_death_callback) {
- ASSERT(isolate == i::Isolate::Current());
- LOG_API(isolate, "MakeWeak");
- isolate->global_handles()->MakeWeak(object,
- parameters,
- weak_reference_callback,
- near_death_callback);
+ i::GlobalHandles::MakeWeak(object,
+ parameters,
+ weak_reference_callback,
+ near_death_callback);
}
-void V8::ClearWeak(i::Isolate* isolate, i::Object** obj) {
- LOG_API(isolate, "ClearWeak");
- isolate->global_handles()->ClearWeakness(obj);
+void V8::ClearWeak(i::Object** obj) {
+ i::GlobalHandles::ClearWeakness(obj);
}
@@ -683,19 +679,7 @@
void HandleScope::Leave() {
- v8::ImplementationUtilities::HandleScopeData* current =
- isolate_->handle_scope_data();
- current->level--;
- ASSERT(current->level >= 0);
- current->next = prev_next_;
- if (current->limit != prev_limit_) {
- current->limit = prev_limit_;
- i::HandleScope::DeleteExtensions(isolate_);
- }
-
-#ifdef ENABLE_EXTRA_CHECKS
- i::HandleScope::ZapRange(prev_next_, prev_limit_);
-#endif
+ return i::HandleScope::CloseScope(isolate_, prev_next_, prev_limit_);
}
@@ -5104,8 +5088,14 @@
UNREACHABLE();
}
virtual void VisitEmbedderReference(i::Object** p, uint16_t class_id) {
+#ifdef V8_USE_OLD_STYLE_PERSISTENT_HANDLE_VISITORS
visitor_->VisitPersistentHandle(ToApi<Value>(i::Handle<i::Object>(p)),
class_id);
+#else
+ Value* value = ToApi<Value>(i::Handle<i::Object>(p));
+ visitor_->VisitPersistentHandle(
+ reinterpret_cast<Persistent<Value>*>(&value), class_id);
+#endif
}
private:
PersistentHandleVisitor* visitor_;
@@ -6374,42 +6364,6 @@
}
-void V8::AddObjectGroup(Persistent<Value>* objects,
- size_t length,
- RetainedObjectInfo* info) {
- i::Isolate* isolate = i::Isolate::Current();
- if (IsDeadCheck(isolate, "v8::V8::AddObjectGroup()")) return;
- STATIC_ASSERT(sizeof(Persistent<Value>) == sizeof(i::Object**));
- isolate->global_handles()->AddObjectGroup(
- reinterpret_cast<i::Object***>(objects), length, info);
-}
-
-
-void V8::AddObjectGroup(Isolate* exported_isolate,
- Persistent<Value>* objects,
- size_t length,
- RetainedObjectInfo* info) {
- i::Isolate* isolate = reinterpret_cast<i::Isolate*>(exported_isolate);
- ASSERT(isolate == i::Isolate::Current());
- if (IsDeadCheck(isolate, "v8::V8::AddObjectGroup()")) return;
- STATIC_ASSERT(sizeof(Persistent<Value>) == sizeof(i::Object**));
- isolate->global_handles()->AddObjectGroup(
- reinterpret_cast<i::Object***>(objects), length, info);
-}
-
-
-void V8::AddImplicitReferences(Persistent<Object> parent,
- Persistent<Value>* children,
- size_t length) {
- i::Isolate* isolate = i::Isolate::Current();
- if (IsDeadCheck(isolate, "v8::V8::AddImplicitReferences()")) return;
- STATIC_ASSERT(sizeof(Persistent<Value>) == sizeof(i::Object**));
- isolate->global_handles()->AddImplicitReferences(
- i::Handle<i::HeapObject>::cast(Utils::OpenHandle(*parent)).location(),
- reinterpret_cast<i::Object***>(children), length);
-}
-
-
intptr_t Isolate::AdjustAmountOfExternalAllocatedMemory(
intptr_t change_in_bytes) {
i::Heap* heap = reinterpret_cast<i::Isolate*>(this)->heap();
diff --git a/src/api.h b/src/api.h
index 12d6e3d..62380ce 100644
--- a/src/api.h
+++ b/src/api.h
@@ -637,7 +637,12 @@
internal::Object** block_limit = block_start + kHandleBlockSize;
#ifdef DEBUG
// NoHandleAllocation may make the prev_limit to point inside the block.
- if (block_start <= prev_limit && prev_limit <= block_limit) break;
+ if (block_start <= prev_limit && prev_limit <= block_limit) {
+#ifdef ENABLE_EXTRA_CHECKS
+ internal::HandleScope::ZapRange(prev_limit, block_limit);
+#endif
+ break;
+ }
#else
if (prev_limit == block_limit) break;
#endif
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index 201ecb2..20d4da5 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -45,7 +45,6 @@
static Register registers[] = { r3, r2, r1 };
descriptor->register_param_count_ = 3;
descriptor->register_params_ = registers;
- descriptor->stack_parameter_count_ = NULL;
descriptor->deoptimization_handler_ =
Runtime::FunctionForId(Runtime::kCreateArrayLiteralShallow)->entry;
}
@@ -57,7 +56,6 @@
static Register registers[] = { r3, r2, r1, r0 };
descriptor->register_param_count_ = 4;
descriptor->register_params_ = registers;
- descriptor->stack_parameter_count_ = NULL;
descriptor->deoptimization_handler_ =
Runtime::FunctionForId(Runtime::kCreateObjectLiteralShallow)->entry;
}
@@ -80,7 +78,6 @@
static Register registers[] = { r0 };
descriptor->register_param_count_ = 1;
descriptor->register_params_ = registers;
- descriptor->stack_parameter_count_ = NULL;
descriptor->deoptimization_handler_ = NULL;
}
@@ -91,7 +88,6 @@
static Register registers[] = { r1 };
descriptor->register_param_count_ = 1;
descriptor->register_params_ = registers;
- descriptor->stack_parameter_count_ = NULL;
descriptor->deoptimization_handler_ = NULL;
}
@@ -175,6 +171,19 @@
}
+void ToBooleanStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ static Register registers[] = { r0 };
+ descriptor->register_param_count_ = 1;
+ descriptor->register_params_ = registers;
+ descriptor->deoptimization_handler_ =
+ FUNCTION_ADDR(ToBooleanIC_Miss);
+ descriptor->SetMissHandler(
+ ExternalReference(IC_Utility(IC::kToBooleanIC_Miss), isolate));
+}
+
+
#define __ ACCESS_MASM(masm)
static void EmitIdenticalObjectComparison(MacroAssembler* masm,
@@ -1207,116 +1216,6 @@
}
-// The stub expects its argument in the tos_ register and returns its result in
-// it, too: zero for false, and a non-zero value for true.
-void ToBooleanStub::Generate(MacroAssembler* masm) {
- // This stub overrides SometimesSetsUpAFrame() to return false. That means
- // we cannot call anything that could cause a GC from this stub.
- Label patch;
- const Register map = r9.is(tos_) ? r7 : r9;
-
- // undefined -> false.
- CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false);
-
- // Boolean -> its value.
- CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false);
- CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true);
-
- // 'null' -> false.
- CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false);
-
- if (types_.Contains(SMI)) {
- // Smis: 0 -> false, all other -> true
- __ SmiTst(tos_);
- // tos_ contains the correct return value already
- __ Ret(eq);
- } else if (types_.NeedsMap()) {
- // If we need a map later and have a Smi -> patch.
- __ JumpIfSmi(tos_, &patch);
- }
-
- if (types_.NeedsMap()) {
- __ ldr(map, FieldMemOperand(tos_, HeapObject::kMapOffset));
-
- if (types_.CanBeUndetectable()) {
- __ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset));
- __ tst(ip, Operand(1 << Map::kIsUndetectable));
- // Undetectable -> false.
- __ mov(tos_, Operand::Zero(), LeaveCC, ne);
- __ Ret(ne);
- }
- }
-
- if (types_.Contains(SPEC_OBJECT)) {
- // Spec object -> true.
- __ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE);
- // tos_ contains the correct non-zero return value already.
- __ Ret(ge);
- }
-
- if (types_.Contains(STRING)) {
- // String value -> false iff empty.
- __ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
- __ ldr(tos_, FieldMemOperand(tos_, String::kLengthOffset), lt);
- __ Ret(lt); // the string length is OK as the return value
- }
-
- if (types_.Contains(HEAP_NUMBER)) {
- // Heap number -> false iff +0, -0, or NaN.
- Label not_heap_number;
- __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
- __ b(ne, ¬_heap_number);
-
- __ vldr(d1, FieldMemOperand(tos_, HeapNumber::kValueOffset));
- __ VFPCompareAndSetFlags(d1, 0.0);
- // "tos_" is a register, and contains a non zero value by default.
- // Hence we only need to overwrite "tos_" with zero to return false for
- // FP_ZERO or FP_NAN cases. Otherwise, by default it returns true.
- __ mov(tos_, Operand::Zero(), LeaveCC, eq); // for FP_ZERO
- __ mov(tos_, Operand::Zero(), LeaveCC, vs); // for FP_NAN
- __ Ret();
- __ bind(¬_heap_number);
- }
-
- __ bind(&patch);
- GenerateTypeTransition(masm);
-}
-
-
-void ToBooleanStub::CheckOddball(MacroAssembler* masm,
- Type type,
- Heap::RootListIndex value,
- bool result) {
- if (types_.Contains(type)) {
- // If we see an expected oddball, return its ToBoolean value tos_.
- __ LoadRoot(ip, value);
- __ cmp(tos_, ip);
- // The value of a root is never NULL, so we can avoid loading a non-null
- // value into tos_ when we want to return 'true'.
- if (!result) {
- __ mov(tos_, Operand::Zero(), LeaveCC, eq);
- }
- __ Ret(eq);
- }
-}
-
-
-void ToBooleanStub::GenerateTypeTransition(MacroAssembler* masm) {
- if (!tos_.is(r3)) {
- __ mov(r3, Operand(tos_));
- }
- __ mov(r2, Operand(Smi::FromInt(tos_.code())));
- __ mov(r1, Operand(Smi::FromInt(types_.ToByte())));
- __ Push(r3, r2, r1);
- // Patch the caller to an appropriate specialized stub and return the
- // operation result to the caller of the stub.
- __ TailCallExternalReference(
- ExternalReference(IC_Utility(IC::kToBoolean_Patch), masm->isolate()),
- 3,
- 1);
-}
-
-
void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
// We don't allow a GC during a store buffer overflow so there is no need to
// store the registers in any particular way, but we do have to store and
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index 967a4d4..2b04914 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -678,8 +678,8 @@
Label* if_true,
Label* if_false,
Label* fall_through) {
- ToBooleanStub stub(result_register());
- __ CallStub(&stub, condition->test_id());
+ Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate());
+ CallIC(ic, RelocInfo::CODE_TARGET, condition->test_id());
__ tst(result_register(), result_register());
Split(ne, if_true, if_false, fall_through);
}
@@ -2050,8 +2050,8 @@
Handle<Code> done_ic = isolate()->builtins()->LoadIC_Initialize();
CallIC(done_ic); // result.done in r0
__ add(sp, sp, Operand(kPointerSize)); // drop LoadIC state
- ToBooleanStub stub(r0);
- __ CallStub(&stub);
+ Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate());
+ CallIC(bool_ic);
__ cmp(r0, Operand(0));
__ b(eq, &l_try);
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index 2ad6eb4..c1f24c9 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -2035,7 +2035,7 @@
} else if (input_rep.IsInteger32()) {
return DefineAsRegister(new(zone()) LClampIToUint8(reg));
} else {
- ASSERT(input_rep.IsTagged());
+ ASSERT(input_rep.IsSmiOrTagged());
// Register allocator doesn't (yet) support allocation of double
// temps. Reserve d1 explicitly.
LClampTToUint8* result = new(zone()) LClampTToUint8(reg, FixedTemp(d11));
@@ -2053,11 +2053,13 @@
LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
Representation r = instr->representation();
- if (r.IsInteger32()) {
+ if (r.IsSmi()) {
+ return DefineAsRegister(new(zone()) LConstantS);
+ } else if (r.IsInteger32()) {
return DefineAsRegister(new(zone()) LConstantI);
} else if (r.IsDouble()) {
return DefineAsRegister(new(zone()) LConstantD);
- } else if (r.IsSmiOrTagged()) {
+ } else if (r.IsTagged()) {
return DefineAsRegister(new(zone()) LConstantT);
} else {
UNREACHABLE();
@@ -2483,7 +2485,7 @@
index = UseOrConstant(instr->index());
} else {
length = UseTempRegister(instr->length());
- index = Use(instr->index());
+ index = UseRegisterAtStart(instr->index());
}
return DefineAsRegister(new(zone()) LAccessArgumentsAt(args, length, index));
}
diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
index e4016c4..6ae65e8 100644
--- a/src/arm/lithium-arm.h
+++ b/src/arm/lithium-arm.h
@@ -87,6 +87,7 @@
V(CmpT) \
V(ConstantD) \
V(ConstantI) \
+ V(ConstantS) \
V(ConstantT) \
V(Context) \
V(DebugBreak) \
@@ -1206,6 +1207,15 @@
};
+class LConstantS: public LTemplateInstruction<1, 0, 0> {
+ public:
+ DECLARE_CONCRETE_INSTRUCTION(ConstantS, "constant-s")
+ DECLARE_HYDROGEN_ACCESSOR(Constant)
+
+ Smi* value() const { return Smi::FromInt(hydrogen()->Integer32Value()); }
+};
+
+
class LConstantD: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ConstantD, "constant-d")
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index c1f6695..06a6506 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -181,6 +181,7 @@
__ add(fp, sp, Operand(2 * kPointerSize));
}
frame_is_built_ = true;
+ info_->AddNoFrameRange(0, masm_->pc_offset());
}
// Reserve space for the stack slots needed by the code.
@@ -1900,7 +1901,11 @@
void LCodeGen::DoConstantI(LConstantI* instr) {
- ASSERT(instr->result()->IsRegister());
+ __ mov(ToRegister(instr->result()), Operand(instr->value()));
+}
+
+
+void LCodeGen::DoConstantS(LConstantS* instr) {
__ mov(ToRegister(instr->result()), Operand(instr->value()));
}
@@ -2242,10 +2247,12 @@
Representation r = instr->hydrogen()->value()->representation();
if (r.IsInteger32() || r.IsSmi()) {
+ ASSERT(!info()->IsStub());
Register reg = ToRegister(instr->value());
__ cmp(reg, Operand::Zero());
EmitBranch(true_block, false_block, ne);
} else if (r.IsDouble()) {
+ ASSERT(!info()->IsStub());
DwVfpRegister reg = ToDoubleRegister(instr->value());
// Test the double value. Zero and NaN are false.
__ VFPCompareAndSetFlags(reg, 0.0);
@@ -2256,9 +2263,11 @@
Register reg = ToRegister(instr->value());
HType type = instr->hydrogen()->value()->type();
if (type.IsBoolean()) {
+ ASSERT(!info()->IsStub());
__ CompareRoot(reg, Heap::kTrueValueRootIndex);
EmitBranch(true_block, false_block, eq);
} else if (type.IsSmi()) {
+ ASSERT(!info()->IsStub());
__ cmp(reg, Operand::Zero());
EmitBranch(true_block, false_block, ne);
} else {
@@ -2947,8 +2956,8 @@
int no_frame_start = -1;
if (NeedsEagerFrame()) {
__ mov(sp, fp);
- __ ldm(ia_w, sp, fp.bit() | lr.bit());
no_frame_start = masm_->pc_offset();
+ __ ldm(ia_w, sp, fp.bit() | lr.bit());
}
if (instr->has_constant_parameter_count()) {
int parameter_count = ToInteger32(instr->constant_parameter_count());
@@ -4967,7 +4976,7 @@
void LCodeGen::EmitNumberUntagD(Register input_reg,
DwVfpRegister result_reg,
- bool deoptimize_on_undefined,
+ bool allow_undefined_as_nan,
bool deoptimize_on_minus_zero,
LEnvironment* env,
NumberUntagDMode mode) {
@@ -4987,7 +4996,7 @@
__ ldr(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset));
__ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
__ cmp(scratch, Operand(ip));
- if (deoptimize_on_undefined) {
+ if (!allow_undefined_as_nan) {
DeoptimizeIf(ne, env);
} else {
Label heap_number, convert;
@@ -5157,7 +5166,7 @@
}
EmitNumberUntagD(input_reg, result_reg,
- instr->hydrogen()->deoptimize_on_undefined(),
+ instr->hydrogen()->allow_undefined_as_nan(),
instr->hydrogen()->deoptimize_on_minus_zero(),
instr->environment(),
mode);
diff --git a/src/arm/lithium-codegen-arm.h b/src/arm/lithium-codegen-arm.h
index 58aa93d..f282847 100644
--- a/src/arm/lithium-codegen-arm.h
+++ b/src/arm/lithium-codegen-arm.h
@@ -335,7 +335,7 @@
void EmitBranch(int left_block, int right_block, Condition cc);
void EmitNumberUntagD(Register input,
DwVfpRegister result,
- bool deoptimize_on_undefined,
+ bool allow_undefined_as_nan,
bool deoptimize_on_minus_zero,
LEnvironment* env,
NumberUntagDMode mode);
diff --git a/src/array.js b/src/array.js
index a3674e8..dcfcde5 100644
--- a/src/array.js
+++ b/src/array.js
@@ -395,6 +395,23 @@
}
+function ObservedArrayPop(n) {
+ n--;
+ var value = this[n];
+
+ EnqueueSpliceRecord(this, n, [value], 1, 0);
+
+ try {
+ BeginPerformSplice(this);
+ delete this[n];
+ this.length = n;
+ } finally {
+ EndPerformSplice(this);
+ }
+
+ return value;
+}
+
// Removes the last element from the array and returns it. See
// ECMA-262, section 15.4.4.6.
function ArrayPop() {
@@ -408,6 +425,10 @@
this.length = n;
return;
}
+
+ if (%IsObserved(this))
+ return ObservedArrayPop.call(this, n);
+
n--;
var value = this[n];
delete this[n];
@@ -424,7 +445,6 @@
try {
BeginPerformSplice(this);
-
for (var i = 0; i < m; i++) {
this[i+n] = %_Arguments(i);
}
@@ -558,6 +578,22 @@
}
+function ObservedArrayShift(len) {
+ var first = this[0];
+
+ EnqueueSpliceRecord(this, 0, [first], 1, 0);
+
+ try {
+ BeginPerformSplice(this);
+ SimpleMove(this, 0, 1, len, 0);
+ this.length = len - 1;
+ } finally {
+ EndPerformSplice(this);
+ }
+
+ return first;
+}
+
function ArrayShift() {
if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
throw MakeTypeError("called_on_null_or_undefined",
@@ -571,9 +607,12 @@
return;
}
+ if (%IsObserved(this))
+ return ObservedArrayShift.call(this, len);
+
var first = this[0];
- if (IS_ARRAY(this) && !%IsObserved(this)) {
+ if (IS_ARRAY(this)) {
SmartMove(this, 0, 1, len, 0);
} else {
SimpleMove(this, 0, 1, len, 0);
@@ -584,6 +623,25 @@
return first;
}
+function ObservedArrayUnshift() {
+ var len = TO_UINT32(this.length);
+ var num_arguments = %_ArgumentsLength();
+
+ EnqueueSpliceRecord(this, 0, [], 0, num_arguments);
+
+ try {
+ BeginPerformSplice(this);
+ SimpleMove(this, 0, 0, len, num_arguments);
+ for (var i = 0; i < num_arguments; i++) {
+ this[i] = %_Arguments(i);
+ }
+ this.length = len + num_arguments;
+ } finally {
+ EndPerformSplice(this);
+ }
+
+ return len + num_arguments;
+}
function ArrayUnshift(arg1) { // length == 1
if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
@@ -591,10 +649,13 @@
["Array.prototype.unshift"]);
}
+ if (%IsObserved(this))
+ return ObservedArrayUnshift.apply(this, arguments);
+
var len = TO_UINT32(this.length);
var num_arguments = %_ArgumentsLength();
- if (IS_ARRAY(this) && !%IsObserved(this)) {
+ if (IS_ARRAY(this)) {
SmartMove(this, 0, 0, len, num_arguments);
} else {
SimpleMove(this, 0, 0, len, num_arguments);
@@ -655,52 +716,100 @@
}
-function ArraySplice(start, delete_count) {
- if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
- throw MakeTypeError("called_on_null_or_undefined",
- ["Array.prototype.splice"]);
- }
-
- var num_arguments = %_ArgumentsLength();
-
- var len = TO_UINT32(this.length);
- var start_i = TO_INTEGER(start);
-
+function ComputeSpliceStartIndex(start_i, len) {
if (start_i < 0) {
start_i += len;
- if (start_i < 0) start_i = 0;
- } else {
- if (start_i > len) start_i = len;
+ return start_i < 0 ? 0 : start_i;
}
+ return start_i > len ? len : start_i;
+}
+
+
+function ComputeSpliceDeleteCount(delete_count, num_arguments, len, start_i) {
// SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
// given as a request to delete all the elements from the start.
// And it differs from the case of undefined delete count.
// This does not follow ECMA-262, but we do the same for
// compatibility.
var del_count = 0;
- if (num_arguments == 1) {
- del_count = len - start_i;
- } else {
- del_count = TO_INTEGER(delete_count);
- if (del_count < 0) del_count = 0;
- if (del_count > len - start_i) del_count = len - start_i;
- }
+ if (num_arguments == 1)
+ return len - start_i;
+ del_count = TO_INTEGER(delete_count);
+ if (del_count < 0)
+ return 0;
+
+ if (del_count > len - start_i)
+ return len - start_i;
+
+ return del_count;
+}
+
+
+function ObservedArraySplice(start, delete_count) {
+ var num_arguments = %_ArgumentsLength();
+ var len = TO_UINT32(this.length);
+ var start_i = ComputeSpliceStartIndex(TO_INTEGER(start), len);
+ var del_count = ComputeSpliceDeleteCount(delete_count, num_arguments, len,
+ start_i);
var deleted_elements = [];
deleted_elements.length = del_count;
+ var num_elements_to_add = num_arguments > 2 ? num_arguments - 2 : 0;
- // Number of elements to add.
- var num_additional_args = 0;
- if (num_arguments > 2) {
- num_additional_args = num_arguments - 2;
+ try {
+ BeginPerformSplice(this);
+
+ SimpleSlice(this, start_i, del_count, len, deleted_elements);
+ SimpleMove(this, start_i, del_count, len, num_elements_to_add);
+
+ // Insert the arguments into the resulting array in
+ // place of the deleted elements.
+ var i = start_i;
+ var arguments_index = 2;
+ var arguments_length = %_ArgumentsLength();
+ while (arguments_index < arguments_length) {
+ this[i++] = %_Arguments(arguments_index++);
+ }
+ this.length = len - del_count + num_elements_to_add;
+
+ } finally {
+ EndPerformSplice(this);
+ if (deleted_elements.length || num_elements_to_add) {
+ EnqueueSpliceRecord(this,
+ start_i,
+ deleted_elements.slice(),
+ deleted_elements.length,
+ num_elements_to_add);
+ }
}
- var use_simple_splice = true;
+ // Return the deleted elements.
+ return deleted_elements;
+}
+
+function ArraySplice(start, delete_count) {
+ if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+ throw MakeTypeError("called_on_null_or_undefined",
+ ["Array.prototype.splice"]);
+ }
+
+ if (%IsObserved(this))
+ return ObservedArraySplice.apply(this, arguments);
+
+ var num_arguments = %_ArgumentsLength();
+ var len = TO_UINT32(this.length);
+ var start_i = ComputeSpliceStartIndex(TO_INTEGER(start), len);
+ var del_count = ComputeSpliceDeleteCount(delete_count, num_arguments, len,
+ start_i);
+ var deleted_elements = [];
+ deleted_elements.length = del_count;
+ var num_elements_to_add = num_arguments > 2 ? num_arguments - 2 : 0;
+
+ var use_simple_splice = true;
if (IS_ARRAY(this) &&
- !%IsObserved(this) &&
- num_additional_args !== del_count) {
+ num_elements_to_add !== del_count) {
// If we are only deleting/moving a few things near the end of the
// array then the simple version is going to be faster, because it
// doesn't touch most of the array.
@@ -712,10 +821,10 @@
if (use_simple_splice) {
SimpleSlice(this, start_i, del_count, len, deleted_elements);
- SimpleMove(this, start_i, del_count, len, num_additional_args);
+ SimpleMove(this, start_i, del_count, len, num_elements_to_add);
} else {
SmartSlice(this, start_i, del_count, len, deleted_elements);
- SmartMove(this, start_i, del_count, len, num_additional_args);
+ SmartMove(this, start_i, del_count, len, num_elements_to_add);
}
// Insert the arguments into the resulting array in
@@ -726,7 +835,7 @@
while (arguments_index < arguments_length) {
this[i++] = %_Arguments(arguments_index++);
}
- this.length = len - del_count + num_additional_args;
+ this.length = len - del_count + num_elements_to_add;
// Return the deleted elements.
return deleted_elements;
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index d7b74f8..9277719 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -1611,14 +1611,12 @@
array_function->shared()->DontAdaptArguments();
- MaybeObject* maybe_map = array_function->initial_map()->Copy();
- Map* new_map;
- if (!maybe_map->To(&new_map)) return Handle<JSFunction>::null();
- new_map->set_elements_kind(elements_kind);
- array_function->set_initial_map(new_map);
+ Handle<Map> original_map(array_function->initial_map());
+ Handle<Map> initial_map = factory()->CopyMap(original_map);
+ initial_map->set_elements_kind(elements_kind);
+ array_function->set_initial_map(*initial_map);
// Make "length" magic on instances.
- Handle<Map> initial_map(array_function->initial_map());
Handle<DescriptorArray> array_descriptors(
factory()->NewDescriptorArray(0, 1));
DescriptorArray::WhitenessWitness witness(*array_descriptors);
@@ -1872,14 +1870,11 @@
{
Handle<JSFunction> array_function =
InstallInternalArray(builtins, "InternalArray", FAST_HOLEY_ELEMENTS);
- if (array_function.is_null()) return false;
native_context()->set_internal_array_function(*array_function);
}
{
- Handle<JSFunction> array_function =
- InstallInternalArray(builtins, "InternalPackedArray", FAST_ELEMENTS);
- if (array_function.is_null()) return false;
+ InstallInternalArray(builtins, "InternalPackedArray", FAST_ELEMENTS);
}
if (FLAG_disable_native_files) {
diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc
index 86bf075..9a9f0d5 100644
--- a/src/code-stubs-hydrogen.cc
+++ b/src/code-stubs-hydrogen.cc
@@ -186,11 +186,12 @@
}
}
- if (!current_block()->IsFinished()) {
+ if (current_block() != NULL) {
HReturn* hreturn_instruction = new(zone) HReturn(return_value,
context_,
stack_pop_count);
current_block()->Finish(hreturn_instruction);
+ set_current_block(NULL);
}
return true;
}
@@ -564,16 +565,13 @@
new(zone()) HAccessArgumentsAt(elements, constant_one, constant_zero));
HConstant* max_alloc_length =
- new(zone()) HConstant(JSObject::kInitialMaxFastElementArray,
- Representation::Tagged());
+ new(zone()) HConstant(JSObject::kInitialMaxFastElementArray);
AddInstruction(max_alloc_length);
const int initial_capacity = JSArray::kPreallocatedArrayElements;
- HConstant* initial_capacity_node =
- new(zone()) HConstant(initial_capacity, Representation::Tagged());
+ HConstant* initial_capacity_node = new(zone()) HConstant(initial_capacity);
AddInstruction(initial_capacity_node);
- HBoundsCheck* checked_arg = AddBoundsCheck(
- argument, max_alloc_length, ALLOW_SMI_KEY);
+ HBoundsCheck* checked_arg = AddBoundsCheck(argument, max_alloc_length);
IfBuilder if_builder(this);
if_builder.IfCompare(checked_arg, constant_zero, Token::EQ);
if_builder.Then();
@@ -676,4 +674,24 @@
return DoGenerateCode(this);
}
+
+template <>
+HValue* CodeStubGraphBuilder<ToBooleanStub>::BuildCodeInitializedStub() {
+ ToBooleanStub* stub = casted_stub();
+
+ IfBuilder if_true(this);
+ if_true.If<HBranch>(GetParameter(0), stub->GetTypes());
+ if_true.Then();
+ if_true.Return(graph()->GetConstant1());
+ if_true.Else();
+ if_true.End();
+ return graph()->GetConstant0();
+}
+
+
+Handle<Code> ToBooleanStub::GenerateCode() {
+ return DoGenerateCode(this);
+}
+
+
} } // namespace v8::internal
diff --git a/src/code-stubs.cc b/src/code-stubs.cc
index 2b96dbf..882d743 100644
--- a/src/code-stubs.cc
+++ b/src/code-stubs.cc
@@ -572,6 +572,14 @@
}
+bool ToBooleanStub::Record(Handle<Object> object) {
+ Types old_types(types_);
+ bool to_boolean_value = types_.Record(object);
+ old_types.TraceTransition(types_);
+ return to_boolean_value;
+}
+
+
void ToBooleanStub::PrintName(StringStream* stream) {
stream->Add("ToBooleanStub_");
types_.Print(stream);
diff --git a/src/code-stubs.h b/src/code-stubs.h
index 901751f..513ad9a 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -1816,7 +1816,7 @@
};
-class ToBooleanStub: public PlatformCodeStub {
+class ToBooleanStub: public HydrogenCodeStub {
public:
enum Type {
UNDEFINED,
@@ -1850,31 +1850,47 @@
static Types no_types() { return Types(); }
static Types all_types() { return Types((1 << NUMBER_OF_TYPES) - 1); }
- explicit ToBooleanStub(Register tos, Types types = Types())
- : tos_(tos), types_(types) { }
+ explicit ToBooleanStub(Types types = Types())
+ : types_(types) { }
+ explicit ToBooleanStub(Code::ExtraICState state)
+ : types_(static_cast<byte>(state)) { }
- void Generate(MacroAssembler* masm);
+ bool Record(Handle<Object> object);
+ Types GetTypes() { return types_; }
+
+ virtual Handle<Code> GenerateCode();
+ virtual void InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor);
+
virtual Code::Kind GetCodeKind() const { return Code::TO_BOOLEAN_IC; }
virtual void PrintName(StringStream* stream);
virtual bool SometimesSetsUpAFrame() { return false; }
- private:
- Major MajorKey() { return ToBoolean; }
- int MinorKey() { return (tos_.code() << NUMBER_OF_TYPES) |
- types_.ToByte(); }
-
- virtual void FinishCode(Handle<Code> code) {
- code->set_to_boolean_state(types_.ToByte());
+ static void InitializeForIsolate(Isolate* isolate) {
+ ToBooleanStub stub;
+ stub.InitializeInterfaceDescriptor(
+ isolate,
+ isolate->code_stub_interface_descriptor(CodeStub::ToBoolean));
}
- void CheckOddball(MacroAssembler* masm,
- Type type,
- Heap::RootListIndex value,
- bool result);
- void GenerateTypeTransition(MacroAssembler* masm);
+ static Handle<Code> GetUninitialized(Isolate* isolate) {
+ return ToBooleanStub(UNINITIALIZED).GetCode(isolate);
+ }
- Register tos_;
+ virtual Code::ExtraICState GetExtraICState() {
+ return types_.ToIntegral();
+ }
+
+
+ private:
+ Major MajorKey() { return ToBoolean; }
+ int NotMissMinorKey() { return GetExtraICState(); }
+
+ explicit ToBooleanStub(InitializationState init_state) :
+ HydrogenCodeStub(init_state) {}
+
Types types_;
};
diff --git a/src/d8.cc b/src/d8.cc
index 149a65f..79244d7 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -40,11 +40,6 @@
#include <string.h>
#include <sys/stat.h>
-// TODO(dcarney): remove
-#define V8_ALLOW_ACCESS_TO_PERSISTENT_ARROW
-#define V8_ALLOW_ACCESS_TO_RAW_HANDLE_CONSTRUCTOR
-#define V8_ALLOW_ACCESS_TO_PERSISTENT_IMPLICIT
-
#ifdef V8_SHARED
#include <assert.h>
#endif // V8_SHARED
@@ -246,7 +241,7 @@
v8::Local<v8::Context> context =
v8::Local<v8::Context>::New(isolate, utility_context_);
v8::Context::Scope context_scope(context);
- Handle<Object> global = utility_context_->Global();
+ Handle<Object> global = context->Global();
Handle<Value> fun = global->Get(String::New("Stringify"));
Handle<Value> argv[1] = { result };
Handle<Value> s = Handle<Function>::Cast(fun)->Call(global, 1, argv);
@@ -268,8 +263,7 @@
data_->realm_current_ = 0;
data_->realm_switch_ = 0;
data_->realms_ = new Persistent<Context>[1];
- data_->realms_[0] =
- Persistent<Context>::New(data_->isolate_, Context::GetEntered());
+ data_->realms_[0].Reset(data_->isolate_, Context::GetEntered());
data_->realm_shared_.Clear();
}
@@ -326,7 +320,8 @@
if (index >= data->realm_count_ || data->realms_[index].IsEmpty()) {
return Throw("Invalid realm index");
}
- return data->realms_[index]->Global();
+ return
+ Local<Context>::New(args.GetIsolate(), data->realms_[index])->Global();
}
@@ -337,10 +332,12 @@
Persistent<Context>* old_realms = data->realms_;
int index = data->realm_count_;
data->realms_ = new Persistent<Context>[++data->realm_count_];
- for (int i = 0; i < index; ++i) data->realms_[i] = old_realms[i];
+ for (int i = 0; i < index; ++i) {
+ data->realms_[i].Reset(isolate, old_realms[i]);
+ }
delete[] old_realms;
Handle<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
- data->realms_[index] = Persistent<Context>::New(
+ data->realms_[index].Reset(
isolate, Context::New(isolate, NULL, global_template));
return Number::New(index);
}
@@ -417,7 +414,7 @@
Isolate* isolate = info.GetIsolate();
PerIsolateData* data = PerIsolateData::Get(isolate);
if (!data->realm_shared_.IsEmpty()) data->realm_shared_.Dispose(isolate);
- data->realm_shared_ = Persistent<Value>::New(isolate, value);
+ data->realm_shared_.Reset(isolate, value);
}
@@ -546,8 +543,12 @@
void Shell::ReportException(Isolate* isolate, v8::TryCatch* try_catch) {
HandleScope handle_scope(isolate);
#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
+ Handle<Context> utility_context;
bool enter_context = !Context::InContext();
- if (enter_context) utility_context_->Enter();
+ if (enter_context) {
+ utility_context = Local<Context>::New(isolate, utility_context_);
+ utility_context->Enter();
+ }
#endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT
v8::String::Utf8Value exception(try_catch->Exception());
const char* exception_string = ToCString(exception);
@@ -584,7 +585,7 @@
}
printf("\n");
#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
- if (enter_context) utility_context_->Exit();
+ if (enter_context) utility_context->Exit();
#endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT
}
@@ -594,13 +595,15 @@
Handle<String> text,
Handle<String> full) {
HandleScope handle_scope(isolate);
- v8::Local<v8::Context> context =
+ v8::Local<v8::Context> utility_context =
v8::Local<v8::Context>::New(isolate, utility_context_);
- v8::Context::Scope context_scope(context);
- Handle<Object> global = utility_context_->Global();
+ v8::Context::Scope context_scope(utility_context);
+ Handle<Object> global = utility_context->Global();
Handle<Value> fun = global->Get(String::New("GetCompletions"));
static const int kArgc = 3;
- Handle<Value> argv[kArgc] = { evaluation_context_->Global(), text, full };
+ v8::Local<v8::Context> evaluation_context =
+ v8::Local<v8::Context>::New(isolate, evaluation_context_);
+ Handle<Value> argv[kArgc] = { evaluation_context->Global(), text, full };
Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
return handle_scope.Close(Handle<Array>::Cast(val));
}
@@ -613,7 +616,7 @@
v8::Local<v8::Context> context =
v8::Local<v8::Context>::New(isolate, utility_context_);
v8::Context::Scope context_scope(context);
- Handle<Object> global = utility_context_->Global();
+ Handle<Object> global = context->Global();
Handle<Value> fun = global->Get(String::New("DebugMessageDetails"));
static const int kArgc = 1;
Handle<Value> argv[kArgc] = { message };
@@ -628,7 +631,7 @@
v8::Local<v8::Context> context =
v8::Local<v8::Context>::New(isolate, utility_context_);
v8::Context::Scope context_scope(context);
- Handle<Object> global = utility_context_->Global();
+ Handle<Object> global = context->Global();
Handle<Value> fun = global->Get(String::New("DebugCommandToJSONRequest"));
static const int kArgc = 1;
Handle<Value> argv[kArgc] = { command };
@@ -753,11 +756,13 @@
HandleScope scope(isolate);
// If we use the utility context, we have to set the security tokens so that
// utility, evaluation and debug context can all access each other.
- utility_context_->SetSecurityToken(Undefined(isolate));
- evaluation_context_->SetSecurityToken(Undefined(isolate));
- v8::Local<v8::Context> context =
+ v8::Local<v8::Context> utility_context =
v8::Local<v8::Context>::New(isolate, utility_context_);
- v8::Context::Scope context_scope(context);
+ v8::Local<v8::Context> evaluation_context =
+ v8::Local<v8::Context>::New(isolate, evaluation_context_);
+ utility_context->SetSecurityToken(Undefined(isolate));
+ evaluation_context->SetSecurityToken(Undefined(isolate));
+ v8::Context::Scope context_scope(utility_context);
#ifdef ENABLE_DEBUGGER_SUPPORT
if (i::FLAG_debugger) printf("JavaScript debugger enabled\n");
@@ -766,7 +771,7 @@
debug->Load();
i::Handle<i::JSObject> js_debug
= i::Handle<i::JSObject>(debug->debug_context()->global_object());
- utility_context_->Global()->Set(String::New("$debug"),
+ utility_context->Global()->Set(String::New("$debug"),
Utils::ToLocal(js_debug));
debug->debug_context()->set_security_token(HEAP->undefined_value());
#endif // ENABLE_DEBUGGER_SUPPORT
@@ -1086,8 +1091,7 @@
return Throw("Error reading file");
}
Handle<v8::ArrayBuffer> buffer = ArrayBuffer::New(data, length);
- v8::Persistent<v8::Value> weak_handle =
- v8::Persistent<v8::Value>::New(isolate, buffer);
+ v8::Persistent<v8::Value> weak_handle(isolate, buffer);
weak_handle.MakeWeak(isolate, data, ReadBufferWeakCallback);
weak_handle.MarkIndependent();
isolate->AdjustAmountOfExternalAllocatedMemory(length);
diff --git a/src/global-handles.cc b/src/global-handles.cc
index bfd8357..8ed6fc9 100644
--- a/src/global-handles.cc
+++ b/src/global-handles.cc
@@ -199,9 +199,9 @@
set_independent(true);
}
- void MarkPartiallyDependent(GlobalHandles* global_handles) {
+ void MarkPartiallyDependent() {
ASSERT(state() != FREE);
- if (global_handles->isolate()->heap()->InNewSpace(object_)) {
+ if (GetGlobalHandles()->isolate()->heap()->InNewSpace(object_)) {
set_partially_dependent(true);
}
}
@@ -231,8 +231,7 @@
parameter_or_next_free_.next_free = value;
}
- void MakeWeak(GlobalHandles* global_handles,
- void* parameter,
+ void MakeWeak(void* parameter,
RevivableCallback weak_reference_callback,
NearDeathCallback near_death_callback) {
ASSERT(state() != FREE);
@@ -248,7 +247,7 @@
}
}
- void ClearWeakness(GlobalHandles* global_handles) {
+ void ClearWeakness() {
ASSERT(state() != FREE);
set_state(NORMAL);
set_parameter(NULL);
@@ -296,6 +295,7 @@
private:
inline NodeBlock* FindBlock();
+ inline GlobalHandles* GetGlobalHandles();
inline void IncreaseBlockUses();
inline void DecreaseBlockUses();
@@ -400,6 +400,11 @@
};
+GlobalHandles* GlobalHandles::Node::GetGlobalHandles() {
+ return FindBlock()->global_handles();
+}
+
+
GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() {
intptr_t ptr = reinterpret_cast<intptr_t>(this);
ptr = ptr - index_ * sizeof(Node);
@@ -507,15 +512,14 @@
RevivableCallback weak_reference_callback,
NearDeathCallback near_death_callback) {
ASSERT((weak_reference_callback == NULL) != (near_death_callback == NULL));
- Node::FromLocation(location)->MakeWeak(this,
- parameter,
+ Node::FromLocation(location)->MakeWeak(parameter,
weak_reference_callback,
near_death_callback);
}
void GlobalHandles::ClearWeakness(Object** location) {
- Node::FromLocation(location)->ClearWeakness(this);
+ Node::FromLocation(location)->ClearWeakness();
}
@@ -525,7 +529,7 @@
void GlobalHandles::MarkPartiallyDependent(Object** location) {
- Node::FromLocation(location)->MarkPartiallyDependent(this);
+ Node::FromLocation(location)->MarkPartiallyDependent();
}
diff --git a/src/global-handles.h b/src/global-handles.h
index 3cca384..cce4328 100644
--- a/src/global-handles.h
+++ b/src/global-handles.h
@@ -138,10 +138,10 @@
// function is invoked (for each handle) with the handle and corresponding
// parameter as arguments. Note: cleared means set to Smi::FromInt(0). The
// reason is that Smi::FromInt(0) does not change during garage collection.
- void MakeWeak(Object** location,
- void* parameter,
- RevivableCallback weak_reference_callback,
- NearDeathCallback near_death_callback);
+ static void MakeWeak(Object** location,
+ void* parameter,
+ RevivableCallback weak_reference_callback,
+ NearDeathCallback near_death_callback);
void RecordStats(HeapStats* stats);
@@ -158,13 +158,13 @@
}
// Clear the weakness of a global handle.
- void ClearWeakness(Object** location);
+ static void ClearWeakness(Object** location);
// Clear the weakness of a global handle.
- void MarkIndependent(Object** location);
+ static void MarkIndependent(Object** location);
// Mark the reference to this object externaly unreachable.
- void MarkPartiallyDependent(Object** location);
+ static void MarkPartiallyDependent(Object** location);
static bool IsIndependent(Object** location);
diff --git a/src/handles-inl.h b/src/handles-inl.h
index 4f5e9fe..14687e3 100644
--- a/src/handles-inl.h
+++ b/src/handles-inl.h
@@ -122,31 +122,37 @@
HandleScope::~HandleScope() {
- CloseScope();
+ CloseScope(isolate_, prev_next_, prev_limit_);
}
-void HandleScope::CloseScope() {
+
+void HandleScope::CloseScope(Isolate* isolate,
+ Object** prev_next,
+ Object** prev_limit) {
v8::ImplementationUtilities::HandleScopeData* current =
- isolate_->handle_scope_data();
- current->next = prev_next_;
+ isolate->handle_scope_data();
+
+ current->next = prev_next;
current->level--;
- if (current->limit != prev_limit_) {
- current->limit = prev_limit_;
- DeleteExtensions(isolate_);
+ if (current->limit != prev_limit) {
+ current->limit = prev_limit;
+ DeleteExtensions(isolate);
}
+
#ifdef ENABLE_EXTRA_CHECKS
- ZapRange(prev_next_, prev_limit_);
+ ZapRange(prev_next, prev_limit);
#endif
}
template <typename T>
Handle<T> HandleScope::CloseAndEscape(Handle<T> handle_value) {
- T* value = *handle_value;
- // Throw away all handles in the current scope.
- CloseScope();
v8::ImplementationUtilities::HandleScopeData* current =
isolate_->handle_scope_data();
+
+ T* value = *handle_value;
+ // Throw away all handles in the current scope.
+ CloseScope(isolate_, prev_next_, prev_limit_);
// Allocate one handle in the parent scope.
ASSERT(current->level > 0);
Handle<T> result(CreateHandle<T>(isolate_, value));
@@ -180,15 +186,14 @@
#ifdef DEBUG
inline NoHandleAllocation::NoHandleAllocation(Isolate* isolate)
: isolate_(isolate) {
- v8::ImplementationUtilities::HandleScopeData* current =
- isolate_->handle_scope_data();
-
active_ = !isolate->optimizing_compiler_thread()->IsOptimizerThread();
if (active_) {
// Shrink the current handle scope to make it impossible to do
// handle allocations without an explicit handle scope.
+ v8::ImplementationUtilities::HandleScopeData* current =
+ isolate_->handle_scope_data();
+ limit_ = current->limit;
current->limit = current->next;
-
level_ = current->level;
current->level = 0;
}
@@ -199,10 +204,12 @@
if (active_) {
// Restore state in current handle scope to re-enable handle
// allocations.
- v8::ImplementationUtilities::HandleScopeData* data =
+ v8::ImplementationUtilities::HandleScopeData* current =
isolate_->handle_scope_data();
- ASSERT_EQ(0, data->level);
- data->level = level_;
+ ASSERT_EQ(0, current->level);
+ current->level = level_;
+ ASSERT_EQ(current->next, current->limit);
+ current->limit = limit_;
}
}
diff --git a/src/handles.h b/src/handles.h
index 938d43b..29ece28 100644
--- a/src/handles.h
+++ b/src/handles.h
@@ -155,18 +155,21 @@
void* operator new(size_t size);
void operator delete(void* size_t);
- inline void CloseScope();
-
Isolate* isolate_;
Object** prev_next_;
Object** prev_limit_;
+ // Close the handle scope resetting limits to a previous state.
+ static inline void CloseScope(Isolate* isolate,
+ Object** prev_next,
+ Object** prev_limit);
+
// Extend the handle scope making room for more handles.
static internal::Object** Extend(Isolate* isolate);
#ifdef ENABLE_EXTRA_CHECKS
// Zaps the handles in the half-open interval [start, end).
- static void ZapRange(internal::Object** start, internal::Object** end);
+ static void ZapRange(Object** start, Object** end);
#endif
friend class v8::HandleScope;
@@ -337,6 +340,7 @@
inline ~NoHandleAllocation();
private:
Isolate* isolate_;
+ Object** limit_;
int level_;
bool active_;
#endif
diff --git a/src/heap.cc b/src/heap.cc
index 587e2f1..50b5a34 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -152,7 +152,6 @@
last_idle_notification_gc_count_(0),
last_idle_notification_gc_count_init_(false),
mark_sweeps_since_idle_round_started_(0),
- ms_count_at_last_idle_notification_(0),
gc_count_at_last_idle_gc_(0),
scavenges_since_last_idle_round_(kIdleScavengeThreshold),
gcs_since_last_deopt_(0),
@@ -5770,6 +5769,7 @@
uncommit = true;
}
CollectAllGarbage(kNoGCFlags, "idle notification: finalize incremental");
+ mark_sweeps_since_idle_round_started_++;
gc_count_at_last_idle_gc_ = gc_count_;
if (uncommit) {
new_space_.Shrink();
@@ -5845,18 +5845,9 @@
}
}
- int new_mark_sweeps = ms_count_ - ms_count_at_last_idle_notification_;
- mark_sweeps_since_idle_round_started_ += new_mark_sweeps;
- ms_count_at_last_idle_notification_ = ms_count_;
-
int remaining_mark_sweeps = kMaxMarkSweepsInIdleRound -
mark_sweeps_since_idle_round_started_;
- if (remaining_mark_sweeps <= 0) {
- FinishIdleRound();
- return true;
- }
-
if (incremental_marking()->IsStopped()) {
// If there are no more than two GCs left in this idle round and we are
// allowed to do a full GC, then make those GCs full in order to compact
@@ -5866,6 +5857,7 @@
if (remaining_mark_sweeps <= 2 && hint >= kMinHintForFullGC) {
CollectAllGarbage(kReduceMemoryFootprintMask,
"idle notification: finalize idle round");
+ mark_sweeps_since_idle_round_started_++;
} else {
incremental_marking()->Start();
}
@@ -5873,6 +5865,12 @@
if (!incremental_marking()->IsStopped()) {
AdvanceIdleIncrementalMarking(step_size);
}
+
+ if (mark_sweeps_since_idle_round_started_ >= kMaxMarkSweepsInIdleRound) {
+ FinishIdleRound();
+ return true;
+ }
+
return false;
}
diff --git a/src/heap.h b/src/heap.h
index 3387d94..556e1db 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -2266,7 +2266,6 @@
void StartIdleRound() {
mark_sweeps_since_idle_round_started_ = 0;
- ms_count_at_last_idle_notification_ = ms_count_;
}
void FinishIdleRound() {
@@ -2343,7 +2342,6 @@
bool last_idle_notification_gc_count_init_;
int mark_sweeps_since_idle_round_started_;
- int ms_count_at_last_idle_notification_;
unsigned int gc_count_at_last_idle_gc_;
int scavenges_since_last_idle_round_;
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index 069b3f2..d4938e5 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -1142,17 +1142,16 @@
void HBoundsCheck::InferRepresentation(HInferRepresentation* h_infer) {
ASSERT(CheckFlag(kFlexibleRepresentation));
Representation r;
- HValue* actual_length = length()->ActualValue();
HValue* actual_index = index()->ActualValue();
- if (key_mode_ == DONT_ALLOW_SMI_KEY ||
- !actual_length->representation().IsSmiOrTagged()) {
+ HValue* actual_length = length()->ActualValue();
+ Representation index_rep = actual_index->representation();
+ if (!actual_length->representation().IsSmiOrTagged()) {
r = Representation::Integer32();
- } else if (actual_index->representation().IsSmiOrTagged() ||
- (actual_index->IsConstant() &&
- HConstant::cast(actual_index)->HasSmiValue())) {
- // If the index is smi, or a constant that holds a Smi, allow the length to
- // be smi, since it is usually already smi from loading it out of the length
- // field of a JSArray. This allows for direct comparison without untagging.
+ } else if ((index_rep.IsTagged() && actual_index->type().IsSmi()) ||
+ index_rep.IsSmi()) {
+ // If the index is smi, allow the length to be smi, since it is usually
+ // already smi from loading it out of the length field of a JSArray. This
+ // allows for direct comparison without untagging.
r = Representation::Smi();
} else {
r = Representation::Integer32();
@@ -1486,7 +1485,7 @@
if (CanTruncateToInt32()) stream->Add(" truncating-int32");
if (CheckFlag(kBailoutOnMinusZero)) stream->Add(" -0?");
- if (CheckFlag(kDeoptimizeOnUndefined)) stream->Add(" deopt-on-undefined");
+ if (CheckFlag(kAllowUndefinedAsNaN)) stream->Add(" allow-undefined-as-nan");
}
@@ -1812,8 +1811,18 @@
if (representation().IsInteger32()) {
Range* a = left()->range();
Range* b = right()->range();
- Range* result = new(zone) Range();
- if (a->CanBeMinusZero() || a->CanBeNegative()) {
+
+ // The magnitude of the modulus is bounded by the right operand. Note that
+ // apart for the cases involving kMinInt, the calculation below is the same
+ // as Max(Abs(b->lower()), Abs(b->upper())) - 1.
+ int32_t positive_bound = -(Min(NegAbs(b->lower()), NegAbs(b->upper())) + 1);
+
+ // The result of the modulo operation has the sign of its left operand.
+ bool left_can_be_negative = a->CanBeMinusZero() || a->CanBeNegative();
+ Range* result = new(zone) Range(left_can_be_negative ? -positive_bound : 0,
+ a->CanBePositive() ? positive_bound : 0);
+
+ if (left_can_be_negative) {
result->set_can_be_minus_zero(true);
}
@@ -2481,8 +2490,8 @@
// (false). Therefore, any comparisons other than ordered relational
// comparisons must cause a deopt when one of their arguments is undefined.
// See also v8:1434
- if (!Token::IsOrderedRelationalCompareOp(token_)) {
- SetFlag(kDeoptimizeOnUndefined);
+ if (Token::IsOrderedRelationalCompareOp(token_)) {
+ SetFlag(kAllowUndefinedAsNaN);
}
}
ChangeRepresentation(rep);
@@ -2745,7 +2754,7 @@
for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
HValue* use = it.value();
- if (use->CheckFlag(HValue::kDeoptimizeOnUndefined)) {
+ if (!use->CheckFlag(HValue::kAllowUndefinedAsNaN)) {
return false;
}
}
@@ -3250,7 +3259,7 @@
if (FLAG_fold_constants && string->IsConstant()) {
HConstant* c_string = HConstant::cast(string);
if (c_string->HasStringValue()) {
- return H_CONSTANT_INT32(c_string->StringValue()->length());
+ return new(zone) HConstant(c_string->StringValue()->length());
}
}
return new(zone) HStringLength(string);
@@ -3740,7 +3749,6 @@
// track dominating allocations in order to eliminate write barriers
instr->SetGVNFlag(kDependsOnNewSpacePromotion);
instr->SetFlag(HValue::kTrackSideEffectDominators);
- instr->SetFlag(HValue::kDeoptimizeOnUndefined);
} else {
// try to GVN loads, but don't hoist above map changes
instr->SetFlag(HValue::kUseGVN);
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index 6fbfd15..9f52569 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -263,6 +263,7 @@
bool CanBeMinusZero() const { return CanBeZero() && can_be_minus_zero_; }
bool CanBeZero() const { return upper_ >= 0 && lower_ <= 0; }
bool CanBeNegative() const { return lower_ < 0; }
+ bool CanBePositive() const { return upper_ > 0; }
bool Includes(int value) const { return lower_ <= value && upper_ >= value; }
bool IsMostGeneric() const {
return lower_ == kMinInt && upper_ == kMaxInt && CanBeMinusZero();
@@ -789,7 +790,7 @@
kCanOverflow,
kBailoutOnMinusZero,
kCanBeDivByZero,
- kDeoptimizeOnUndefined,
+ kAllowUndefinedAsNaN,
kIsArguments,
kTruncatingToInt32,
// Set after an instruction is killed.
@@ -1561,6 +1562,9 @@
}
explicit HBranch(HValue* value)
: HUnaryControlInstruction(value, NULL, NULL) { }
+ HBranch(HValue* value, ToBooleanStub::Types expected_input_types)
+ : HUnaryControlInstruction(value, NULL, NULL),
+ expected_input_types_(expected_input_types) { }
virtual Representation RequiredInputRepresentation(int index) {
@@ -1711,14 +1715,14 @@
HChange(HValue* value,
Representation to,
bool is_truncating,
- bool deoptimize_on_undefined)
+ bool allow_undefined_as_nan)
: HUnaryOperation(value) {
ASSERT(!value->representation().IsNone());
ASSERT(!to.IsNone());
ASSERT(!value->representation().Equals(to));
set_representation(to);
SetFlag(kUseGVN);
- if (deoptimize_on_undefined) SetFlag(kDeoptimizeOnUndefined);
+ if (allow_undefined_as_nan) SetFlag(kAllowUndefinedAsNaN);
if (is_truncating) SetFlag(kTruncatingToInt32);
if (value->representation().IsSmi() || value->type().IsSmi()) {
set_type(HType::Smi());
@@ -1734,8 +1738,8 @@
Representation from() const { return value()->representation(); }
Representation to() const { return representation(); }
- bool deoptimize_on_undefined() const {
- return CheckFlag(kDeoptimizeOnUndefined);
+ bool allow_undefined_as_nan() const {
+ return CheckFlag(kAllowUndefinedAsNaN);
}
bool deoptimize_on_minus_zero() const {
return CheckFlag(kBailoutOnMinusZero);
@@ -1765,6 +1769,7 @@
explicit HClampToUint8(HValue* value)
: HUnaryOperation(value) {
set_representation(Representation::Integer32());
+ SetFlag(kAllowUndefinedAsNaN);
SetFlag(kUseGVN);
}
@@ -2491,6 +2496,7 @@
set_representation(Representation::Integer32());
SetFlag(kUseGVN);
SetFlag(kTruncatingToInt32);
+ SetFlag(kAllowUndefinedAsNaN);
}
virtual Representation RequiredInputRepresentation(int index) {
@@ -2600,6 +2606,7 @@
UNREACHABLE();
}
SetFlag(kUseGVN);
+ SetFlag(kAllowUndefinedAsNaN);
}
virtual bool IsDeletable() const { return true; }
@@ -2941,6 +2948,7 @@
}
ASSERT(merged_index >= 0);
SetFlag(kFlexibleRepresentation);
+ SetFlag(kAllowUndefinedAsNaN);
}
virtual Representation RepresentationFromInputs();
@@ -3124,11 +3132,11 @@
public:
HConstant(Handle<Object> handle, Representation r);
HConstant(int32_t value,
- Representation r,
+ Representation r = Representation::None(),
bool is_not_in_new_space = true,
Handle<Object> optional_handle = Handle<Object>::null());
HConstant(double value,
- Representation r,
+ Representation r = Representation::None(),
bool is_not_in_new_space = true,
Handle<Object> optional_handle = Handle<Object>::null());
HConstant(Handle<Object> handle,
@@ -3527,12 +3535,6 @@
};
-enum BoundsCheckKeyMode {
- DONT_ALLOW_SMI_KEY,
- ALLOW_SMI_KEY
-};
-
-
class HBoundsCheckBaseIndexInformation;
@@ -3542,10 +3544,8 @@
// HGraphBuilder::AddBoundsCheck() helper.
// However when building stubs, where we know that the arguments are Int32,
// it makes sense to invoke this constructor directly.
- HBoundsCheck(HValue* index,
- HValue* length,
- BoundsCheckKeyMode key_mode = DONT_ALLOW_SMI_KEY)
- : key_mode_(key_mode), skip_check_(false),
+ HBoundsCheck(HValue* index, HValue* length)
+ : skip_check_(false),
base_(NULL), offset_(0), scale_(0),
responsibility_direction_(DIRECTION_NONE) {
SetOperandAt(0, index);
@@ -3618,7 +3618,6 @@
virtual bool DataEquals(HValue* other) { return true; }
virtual void TryGuaranteeRangeChanging(RangeEvaluationContext* context);
- BoundsCheckKeyMode key_mode_;
bool skip_check_;
HValue* base_;
int offset_;
@@ -3673,6 +3672,7 @@
: HBinaryOperation(context, left, right) {
SetFlag(kFlexibleRepresentation);
SetFlag(kTruncatingToInt32);
+ SetFlag(kAllowUndefinedAsNaN);
SetAllSideEffects();
}
@@ -3727,6 +3727,7 @@
if (!right->IsConstant()) {
SetFlag(kCanBeDivByZero);
}
+ SetFlag(kAllowUndefinedAsNaN);
}
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
@@ -3751,6 +3752,7 @@
: HBinaryOperation(context, left, right) {
SetAllSideEffects();
SetFlag(kFlexibleRepresentation);
+ SetFlag(kAllowUndefinedAsNaN);
}
virtual void RepresentationChanged(Representation to) {
@@ -5736,12 +5738,11 @@
}
if (is_external()) {
SetGVNFlag(kChangesSpecializedArrayElements);
+ SetFlag(kAllowUndefinedAsNaN);
} else if (IsFastDoubleElementsKind(elements_kind)) {
SetGVNFlag(kChangesDoubleArrayElements);
- SetFlag(kDeoptimizeOnUndefined);
} else if (IsFastSmiElementsKind(elements_kind)) {
SetGVNFlag(kChangesArrayElements);
- SetFlag(kDeoptimizeOnUndefined);
} else {
SetGVNFlag(kChangesArrayElements);
}
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 60ba595..54a5225 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -593,11 +593,10 @@
#endif
-HConstant* HGraph::GetConstantInt32(SetOncePointer<HConstant>* pointer,
- int32_t value) {
+HConstant* HGraph::GetConstant(SetOncePointer<HConstant>* pointer,
+ int32_t value) {
if (!pointer->is_set()) {
- HConstant* constant =
- new(zone()) HConstant(value, Representation::Integer32());
+ HConstant* constant = new(zone()) HConstant(value);
constant->InsertAfter(GetConstantUndefined());
pointer->set(constant);
}
@@ -606,17 +605,17 @@
HConstant* HGraph::GetConstant0() {
- return GetConstantInt32(&constant_0_, 0);
+ return GetConstant(&constant_0_, 0);
}
HConstant* HGraph::GetConstant1() {
- return GetConstantInt32(&constant_1_, 1);
+ return GetConstant(&constant_1_, 1);
}
HConstant* HGraph::GetConstantMinus1() {
- return GetConstantInt32(&constant_minus1_, -1);
+ return GetConstant(&constant_minus1_, -1);
}
@@ -648,7 +647,7 @@
HConstant* HGraph::GetInvalidContext() {
- return GetConstantInt32(&constant_invalid_context_, 0xFFFFC0C7);
+ return GetConstant(&constant_invalid_context_, 0xFFFFC0C7);
}
@@ -823,9 +822,10 @@
void HGraphBuilder::IfBuilder::Return(HValue* value) {
HBasicBlock* block = builder_->current_block();
- block->Finish(new(zone()) HReturn(value,
- builder_->environment()->LookupContext(),
- builder_->graph()->GetConstantMinus1()));
+ HValue* context = builder_->environment()->LookupContext();
+ HValue* parameter_count = builder_->graph()->GetConstantMinus1();
+ block->FinishExit(new(zone()) HReturn(value, context, parameter_count));
+ builder_->set_current_block(NULL);
if (did_else_) {
first_false_block_ = NULL;
} else {
@@ -979,11 +979,8 @@
}
-HBoundsCheck* HGraphBuilder::AddBoundsCheck(HValue* index,
- HValue* length,
- BoundsCheckKeyMode key_mode) {
- HBoundsCheck* result = new(graph()->zone()) HBoundsCheck(
- index, length, key_mode);
+HBoundsCheck* HGraphBuilder::AddBoundsCheck(HValue* index, HValue* length) {
+ HBoundsCheck* result = new(graph()->zone()) HBoundsCheck(index, length);
AddInstruction(result);
return result;
}
@@ -1129,7 +1126,7 @@
Zone* zone = this->zone();
IfBuilder length_checker(this);
- length_checker.IfCompare(length, key, Token::EQ, Representation::Smi());
+ length_checker.IfCompare(length, key, Token::EQ);
length_checker.Then();
HValue* current_capacity =
@@ -1137,8 +1134,7 @@
IfBuilder capacity_checker(this);
- capacity_checker.IfCompare(
- length, current_capacity, Token::EQ, Representation::Smi());
+ capacity_checker.IfCompare(length, current_capacity, Token::EQ);
capacity_checker.Then();
HValue* context = environment()->LookupContext();
@@ -1170,7 +1166,7 @@
length_checker.Else();
- AddBoundsCheck(key, length, ALLOW_SMI_KEY);
+ AddBoundsCheck(key, length);
environment()->Push(elements);
length_checker.End();
@@ -1260,11 +1256,11 @@
new(zone) HLoadExternalArrayPointer(elements);
AddInstruction(external_elements);
IfBuilder length_checker(this);
- length_checker.IfCompare(key, length, Token::LT, Representation::Smi());
+ length_checker.IfCompare(key, length, Token::LT);
length_checker.Then();
IfBuilder negative_checker(this);
HValue* bounds_check = negative_checker.IfCompare(
- key, graph()->GetConstant0(), Token::GTE, Representation::Smi());
+ key, graph()->GetConstant0(), Token::GTE);
negative_checker.Then();
HInstruction* result = BuildExternalArrayElementAccess(
external_elements, key, val, bounds_check,
@@ -1275,7 +1271,7 @@
return result;
} else {
ASSERT(store_mode == STANDARD_STORE);
- checked_key = AddBoundsCheck(key, length, ALLOW_SMI_KEY);
+ checked_key = AddBoundsCheck(key, length);
HLoadExternalArrayPointer* external_elements =
new(zone) HLoadExternalArrayPointer(elements);
AddInstruction(external_elements);
@@ -1303,7 +1299,7 @@
length, key, is_js_array);
checked_key = key;
} else {
- checked_key = AddBoundsCheck(key, length, ALLOW_SMI_KEY);
+ checked_key = AddBoundsCheck(key, length);
if (is_store && (fast_elements || fast_smi_only_elements)) {
if (store_mode == STORE_NO_TRANSITION_HANDLE_COW) {
@@ -1471,13 +1467,11 @@
: kPointerSize;
int max_size = heap->MaxRegularSpaceAllocationSize() / element_size;
max_size -= JSArray::kSize / element_size;
- HConstant* max_size_constant =
- new(zone) HConstant(max_size, Representation::Integer32());
+ HConstant* max_size_constant = new(zone) HConstant(max_size);
AddInstruction(max_size_constant);
// Since we're forcing Integer32 representation for this HBoundsCheck,
// there's no need to Smi-check the index.
- AddInstruction(new(zone) HBoundsCheck(
- length, max_size_constant, DONT_ALLOW_SMI_KEY));
+ AddInstruction(new(zone) HBoundsCheck(length, max_size_constant));
}
@@ -1545,8 +1539,7 @@
if (unfold_loop) {
for (int i = 0; i < initial_capacity; i++) {
- HInstruction* key = AddInstruction(new(zone)
- HConstant(i, Representation::Integer32()));
+ HInstruction* key = AddInstruction(new(zone) HConstant(i));
AddInstruction(new(zone) HStoreKeyed(elements, key, hole, elements_kind));
}
} else {
@@ -1593,7 +1586,10 @@
? FAST_HOLEY_ELEMENTS : to_elements_kind;
HInstruction* holey_store = AddInstruction(
new(zone()) HStoreKeyed(to_elements, key, element, holey_kind));
- holey_store->ClearFlag(HValue::kDeoptimizeOnUndefined);
+ // Allow NaN hole values to converted to their tagged counterparts.
+ if (IsFastHoleyElementsKind(to_elements_kind)) {
+ holey_store->SetFlag(HValue::kAllowUndefinedAsNaN);
+ }
builder.EndBody();
@@ -1669,8 +1665,7 @@
// copying loops with constant length up to a given boundary and use this
// helper here instead.
for (int i = 0; i < length; i++) {
- HValue* key_constant =
- AddInstruction(new(zone) HConstant(i, Representation::Integer32()));
+ HValue* key_constant = AddInstruction(new(zone) HConstant(i));
HInstruction* value =
AddInstruction(new(zone) HLoadKeyed(boilerplate_elements,
key_constant,
@@ -3108,8 +3103,8 @@
// change instructions for them.
HInstruction* new_value = NULL;
bool is_truncating = use_value->CheckFlag(HValue::kTruncatingToInt32);
- bool deoptimize_on_undefined =
- use_value->CheckFlag(HValue::kDeoptimizeOnUndefined);
+ bool allow_undefined_as_nan =
+ use_value->CheckFlag(HValue::kAllowUndefinedAsNaN);
if (value->IsConstant()) {
HConstant* constant = HConstant::cast(value);
// Try to create a new copy of the constant with the new representation.
@@ -3120,7 +3115,7 @@
if (new_value == NULL) {
new_value = new(zone()) HChange(value, to,
- is_truncating, deoptimize_on_undefined);
+ is_truncating, allow_undefined_as_nan);
}
new_value->InsertBefore(next);
@@ -3227,8 +3222,8 @@
void HGraph::RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi* phi) {
- if (phi->CheckFlag(HValue::kDeoptimizeOnUndefined)) return;
- phi->SetFlag(HValue::kDeoptimizeOnUndefined);
+ if (!phi->CheckFlag(HValue::kAllowUndefinedAsNaN)) return;
+ phi->ClearFlag(HValue::kAllowUndefinedAsNaN);
for (int i = 0; i < phi->OperandCount(); ++i) {
HValue* input = phi->OperandAt(i);
if (input->IsPhi()) {
@@ -3248,16 +3243,11 @@
// if one of its uses has this flag set.
for (int i = 0; i < phi_list()->length(); i++) {
HPhi* phi = phi_list()->at(i);
- if (phi->representation().IsDouble()) {
- for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) {
- int use_index = it.index();
- HValue* use_value = it.value();
- Representation req = use_value->RequiredInputRepresentation(use_index);
- if (!req.IsDouble() ||
- use_value->CheckFlag(HValue::kDeoptimizeOnUndefined)) {
- RecursivelyMarkPhiDeoptimizeOnUndefined(phi);
- break;
- }
+ for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) {
+ HValue* use_value = it.value();
+ if (!use_value->CheckFlag(HValue::kAllowUndefinedAsNaN)) {
+ RecursivelyMarkPhiDeoptimizeOnUndefined(phi);
+ break;
}
}
}
@@ -5348,8 +5338,7 @@
HInstruction* enum_length = AddInstruction(new(zone()) HMapEnumLength(map));
- HInstruction* start_index = AddInstruction(new(zone()) HConstant(
- Handle<Object>(Smi::FromInt(0), isolate()), Representation::Integer32()));
+ HInstruction* start_index = AddInstruction(new(zone()) HConstant(0));
Push(map);
Push(array);
@@ -6086,9 +6075,7 @@
elements = AddLoadElements(literal);
- HValue* key = AddInstruction(
- new(zone()) HConstant(Handle<Object>(Smi::FromInt(i), isolate()),
- Representation::Integer32()));
+ HValue* key = AddInstruction(new(zone()) HConstant(i));
switch (boilerplate_elements_kind) {
case FAST_SMI_ELEMENTS:
@@ -7283,7 +7270,7 @@
typecheck, Representation::Smi());
length->set_type(HType::Smi());
- checked_key = AddBoundsCheck(key, length, ALLOW_SMI_KEY);
+ checked_key = AddBoundsCheck(key, length);
access = AddInstruction(BuildFastElementAccess(
elements, checked_key, val, elements_kind_branch,
elements_kind, is_store, NEVER_RETURN_HOLE, STANDARD_STORE));
@@ -7301,7 +7288,7 @@
set_current_block(if_fastobject);
length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
- checked_key = AddBoundsCheck(key, length, ALLOW_SMI_KEY);
+ checked_key = AddBoundsCheck(key, length);
access = AddInstruction(BuildFastElementAccess(
elements, checked_key, val, elements_kind_branch,
elements_kind, is_store, NEVER_RETURN_HOLE, STANDARD_STORE));
@@ -7439,9 +7426,7 @@
// Number of arguments without receiver.
int argument_count = environment()->
arguments_environment()->parameter_count() - 1;
- result = new(zone()) HConstant(
- Handle<Object>(Smi::FromInt(argument_count), isolate()),
- Representation::Integer32());
+ result = new(zone()) HConstant(argument_count);
}
} else {
Push(graph()->GetArgumentsObject());
@@ -7464,8 +7449,7 @@
int argument_count = environment()->
arguments_environment()->parameter_count() - 1;
HInstruction* length = AddInstruction(new(zone()) HConstant(
- Handle<Object>(Smi::FromInt(argument_count), isolate()),
- Representation::Integer32()));
+ argument_count));
HInstruction* checked_key = AddBoundsCheck(key, length);
result = new(zone()) HAccessArgumentsAt(elements, length, checked_key);
}
@@ -8335,10 +8319,8 @@
result =
HUnaryMathOperation::New(zone(), context, left, kMathPowHalf);
} else if (exponent == -0.5) {
- HConstant* double_one =
- new(zone()) HConstant(Handle<Object>(Smi::FromInt(1),
- isolate()),
- Representation::Double());
+ HConstant* double_one = new(zone()) HConstant(
+ 1, Representation::Double());
AddInstruction(double_one);
HInstruction* sqrt =
HUnaryMathOperation::New(zone(), context, left, kMathPowHalf);
@@ -9292,7 +9274,7 @@
if (i < 0 || i >= s->length()) {
return new(zone()) HConstant(OS::nan_value(), Representation::Double());
}
- return new(zone()) HConstant(s->Get(i), Representation::Integer32());
+ return new(zone()) HConstant(s->Get(i));
}
}
BuildCheckNonSmi(string);
@@ -10094,8 +10076,7 @@
int elements_length = elements->length();
HValue* object_elements_length =
- AddInstruction(new(zone) HConstant(
- elements_length, Representation::Integer32()));
+ AddInstruction(new(zone) HConstant(elements_length));
BuildInitializeElementsHeader(object_elements, kind, object_elements_length);
@@ -10120,14 +10101,13 @@
elements, Representation::Tagged()));
int elements_length = elements->length();
for (int i = 0; i < elements_length; i++) {
- HValue* key_constant =
- AddInstruction(new(zone) HConstant(i, Representation::Integer32()));
+ HValue* key_constant = AddInstruction(new(zone) HConstant(i));
HInstruction* value_instruction =
AddInstruction(new(zone) HLoadKeyed(
boilerplate_elements, key_constant, NULL, kind, ALLOW_RETURN_HOLE));
HInstruction* store = AddInstruction(new(zone) HStoreKeyed(
object_elements, key_constant, value_instruction, kind));
- store->ClearFlag(HValue::kDeoptimizeOnUndefined);
+ store->SetFlag(HValue::kAllowUndefinedAsNaN);
}
}
@@ -10148,8 +10128,7 @@
Handle<FixedArray>::cast(original_elements);
for (int i = 0; i < elements_length; i++) {
Handle<Object> value(fast_elements->get(i), isolate());
- HValue* key_constant =
- AddInstruction(new(zone) HConstant(i, Representation::Integer32()));
+ HValue* key_constant = AddInstruction(new(zone) HConstant(i));
if (value->IsJSObject()) {
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
Handle<JSObject> original_value_object = Handle<JSObject>::cast(
diff --git a/src/hydrogen.h b/src/hydrogen.h
index 3037e57..7a57448 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -400,8 +400,8 @@
}
private:
- HConstant* GetConstantInt32(SetOncePointer<HConstant>* pointer,
- int32_t integer_value);
+ HConstant* GetConstant(SetOncePointer<HConstant>* pointer,
+ int32_t integer_value);
void MarkLive(HValue* ref, HValue* instr, ZoneList<HValue*>* worklist);
void MarkLiveInstructions();
@@ -952,10 +952,7 @@
HInstruction* AddInstruction(HInstruction* instr);
void AddSimulate(BailoutId id,
RemovableSimulate removable = FIXED_SIMULATE);
- HBoundsCheck* AddBoundsCheck(
- HValue* index,
- HValue* length,
- BoundsCheckKeyMode key_mode = DONT_ALLOW_SMI_KEY);
+ HBoundsCheck* AddBoundsCheck(HValue* index, HValue* length);
HReturn* AddReturn(HValue* value);
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index 598bf17..325e9b7 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -50,7 +50,6 @@
static Register registers[] = { eax, ebx, ecx };
descriptor->register_param_count_ = 3;
descriptor->register_params_ = registers;
- descriptor->stack_parameter_count_ = NULL;
descriptor->deoptimization_handler_ =
Runtime::FunctionForId(Runtime::kCreateArrayLiteralShallow)->entry;
}
@@ -62,7 +61,6 @@
static Register registers[] = { eax, ebx, ecx, edx };
descriptor->register_param_count_ = 4;
descriptor->register_params_ = registers;
- descriptor->stack_parameter_count_ = NULL;
descriptor->deoptimization_handler_ =
Runtime::FunctionForId(Runtime::kCreateObjectLiteralShallow)->entry;
}
@@ -74,7 +72,6 @@
static Register registers[] = { edx, ecx };
descriptor->register_param_count_ = 2;
descriptor->register_params_ = registers;
- descriptor->stack_parameter_count_ = NULL;
descriptor->deoptimization_handler_ =
FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure);
}
@@ -86,7 +83,6 @@
static Register registers[] = { edx };
descriptor->register_param_count_ = 1;
descriptor->register_params_ = registers;
- descriptor->stack_parameter_count_ = NULL;
descriptor->deoptimization_handler_ = NULL;
}
@@ -97,7 +93,6 @@
static Register registers[] = { edx };
descriptor->register_param_count_ = 1;
descriptor->register_params_ = registers;
- descriptor->stack_parameter_count_ = NULL;
descriptor->deoptimization_handler_ = NULL;
}
@@ -180,6 +175,18 @@
ExternalReference(IC_Utility(IC::kCompareNilIC_Miss), isolate));
}
+void ToBooleanStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ static Register registers[] = { eax };
+ descriptor->register_param_count_ = 1;
+ descriptor->register_params_ = registers;
+ descriptor->deoptimization_handler_ =
+ FUNCTION_ADDR(ToBooleanIC_Miss);
+ descriptor->SetMissHandler(
+ ExternalReference(IC_Utility(IC::kToBooleanIC_Miss), isolate));
+}
+
#define __ ACCESS_MASM(masm)
@@ -469,116 +476,6 @@
}
-// The stub expects its argument on the stack and returns its result in tos_:
-// zero for false, and a non-zero value for true.
-void ToBooleanStub::Generate(MacroAssembler* masm) {
- // This stub overrides SometimesSetsUpAFrame() to return false. That means
- // we cannot call anything that could cause a GC from this stub.
- Label patch;
- Factory* factory = masm->isolate()->factory();
- const Register argument = eax;
- const Register map = edx;
-
- if (!types_.IsEmpty()) {
- __ mov(argument, Operand(esp, 1 * kPointerSize));
- }
-
- // undefined -> false
- CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false);
-
- // Boolean -> its value
- CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false);
- CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true);
-
- // 'null' -> false.
- CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false);
-
- if (types_.Contains(SMI)) {
- // Smis: 0 -> false, all other -> true
- Label not_smi;
- __ JumpIfNotSmi(argument, ¬_smi, Label::kNear);
- // argument contains the correct return value already.
- if (!tos_.is(argument)) {
- __ mov(tos_, argument);
- }
- __ ret(1 * kPointerSize);
- __ bind(¬_smi);
- } else if (types_.NeedsMap()) {
- // If we need a map later and have a Smi -> patch.
- __ JumpIfSmi(argument, &patch, Label::kNear);
- }
-
- if (types_.NeedsMap()) {
- __ mov(map, FieldOperand(argument, HeapObject::kMapOffset));
-
- if (types_.CanBeUndetectable()) {
- __ test_b(FieldOperand(map, Map::kBitFieldOffset),
- 1 << Map::kIsUndetectable);
- // Undetectable -> false.
- Label not_undetectable;
- __ j(zero, ¬_undetectable, Label::kNear);
- __ Set(tos_, Immediate(0));
- __ ret(1 * kPointerSize);
- __ bind(¬_undetectable);
- }
- }
-
- if (types_.Contains(SPEC_OBJECT)) {
- // spec object -> true.
- Label not_js_object;
- __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
- __ j(below, ¬_js_object, Label::kNear);
- // argument contains the correct return value already.
- if (!tos_.is(argument)) {
- __ Set(tos_, Immediate(1));
- }
- __ ret(1 * kPointerSize);
- __ bind(¬_js_object);
- }
-
- if (types_.Contains(STRING)) {
- // String value -> false iff empty.
- Label not_string;
- __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
- __ j(above_equal, ¬_string, Label::kNear);
- __ mov(tos_, FieldOperand(argument, String::kLengthOffset));
- __ ret(1 * kPointerSize); // the string length is OK as the return value
- __ bind(¬_string);
- }
-
- if (types_.Contains(SYMBOL)) {
- // Symbol value -> true.
- Label not_symbol;
- __ CmpInstanceType(map, SYMBOL_TYPE);
- __ j(not_equal, ¬_symbol, Label::kNear);
- __ bind(¬_symbol);
- }
-
- if (types_.Contains(HEAP_NUMBER)) {
- // heap number -> false iff +0, -0, or NaN.
- Label not_heap_number, false_result;
- __ cmp(map, factory->heap_number_map());
- __ j(not_equal, ¬_heap_number, Label::kNear);
- __ fldz();
- __ fld_d(FieldOperand(argument, HeapNumber::kValueOffset));
- __ FCmp();
- __ j(zero, &false_result, Label::kNear);
- // argument contains the correct return value already.
- if (!tos_.is(argument)) {
- __ Set(tos_, Immediate(1));
- }
- __ ret(1 * kPointerSize);
- __ bind(&false_result);
- __ Set(tos_, Immediate(0));
- __ ret(1 * kPointerSize);
- __ bind(¬_heap_number);
- }
-
- __ bind(&patch);
- GenerateTypeTransition(masm);
-}
-
-
void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
// We don't allow a GC during a store buffer overflow so there is no need to
// store the registers in any particular way, but we do have to store and
@@ -614,44 +511,6 @@
}
-void ToBooleanStub::CheckOddball(MacroAssembler* masm,
- Type type,
- Heap::RootListIndex value,
- bool result) {
- const Register argument = eax;
- if (types_.Contains(type)) {
- // If we see an expected oddball, return its ToBoolean value tos_.
- Label different_value;
- __ CompareRoot(argument, value);
- __ j(not_equal, &different_value, Label::kNear);
- if (!result) {
- // If we have to return zero, there is no way around clearing tos_.
- __ Set(tos_, Immediate(0));
- } else if (!tos_.is(argument)) {
- // If we have to return non-zero, we can re-use the argument if it is the
- // same register as the result, because we never see Smi-zero here.
- __ Set(tos_, Immediate(1));
- }
- __ ret(1 * kPointerSize);
- __ bind(&different_value);
- }
-}
-
-
-void ToBooleanStub::GenerateTypeTransition(MacroAssembler* masm) {
- __ pop(ecx); // Get return address, operand is now on top of stack.
- __ push(Immediate(Smi::FromInt(tos_.code())));
- __ push(Immediate(Smi::FromInt(types_.ToByte())));
- __ push(ecx); // Push return address.
- // Patch the caller to an appropriate specialized stub and return the
- // operation result to the caller of the stub.
- __ TailCallExternalReference(
- ExternalReference(IC_Utility(IC::kToBoolean_Patch), masm->isolate()),
- 3,
- 1);
-}
-
-
class FloatingPointHelper : public AllStatic {
public:
enum ArgLocation {
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index bf5e02b..9c08ef3 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -641,9 +641,8 @@
Label* if_true,
Label* if_false,
Label* fall_through) {
- ToBooleanStub stub(result_register());
- __ push(result_register());
- __ CallStub(&stub, condition->test_id());
+ Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate());
+ CallIC(ic, RelocInfo::CODE_TARGET, condition->test_id());
__ test(result_register(), result_register());
// The stub returns nonzero for true.
Split(not_zero, if_true, if_false, fall_through);
@@ -2003,9 +2002,8 @@
__ mov(ecx, isolate()->factory()->done_string()); // "done"
Handle<Code> done_ic = isolate()->builtins()->LoadIC_Initialize();
CallIC(done_ic); // result.done in eax
- ToBooleanStub stub(eax);
- __ push(eax);
- __ CallStub(&stub);
+ Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate());
+ CallIC(bool_ic);
__ test(eax, eax);
__ j(zero, &l_try);
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 46dcec0..fb566d1 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -1751,7 +1751,11 @@
void LCodeGen::DoConstantI(LConstantI* instr) {
- ASSERT(instr->result()->IsRegister());
+ __ Set(ToRegister(instr->result()), Immediate(instr->value()));
+}
+
+
+void LCodeGen::DoConstantS(LConstantS* instr) {
__ Set(ToRegister(instr->result()), Immediate(instr->value()));
}
@@ -2124,14 +2128,16 @@
void LCodeGen::DoBranch(LBranch* instr) {
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
- CpuFeatureScope scope(masm(), SSE2);
Representation r = instr->hydrogen()->value()->representation();
if (r.IsSmiOrInteger32()) {
+ ASSERT(!info()->IsStub());
Register reg = ToRegister(instr->value());
__ test(reg, Operand(reg));
EmitBranch(true_block, false_block, not_zero);
} else if (r.IsDouble()) {
+ ASSERT(!info()->IsStub());
+ CpuFeatureScope scope(masm(), SSE2);
XMMRegister reg = ToDoubleRegister(instr->value());
__ xorps(xmm0, xmm0);
__ ucomisd(reg, xmm0);
@@ -2141,9 +2147,11 @@
Register reg = ToRegister(instr->value());
HType type = instr->hydrogen()->value()->type();
if (type.IsBoolean()) {
+ ASSERT(!info()->IsStub());
__ cmp(reg, factory()->true_value());
EmitBranch(true_block, false_block, equal);
} else if (type.IsSmi()) {
+ ASSERT(!info()->IsStub());
__ test(reg, Operand(reg));
EmitBranch(true_block, false_block, not_equal);
} else {
@@ -2227,8 +2235,15 @@
__ cmp(FieldOperand(reg, HeapObject::kMapOffset),
factory()->heap_number_map());
__ j(not_equal, ¬_heap_number, Label::kNear);
- __ xorps(xmm0, xmm0);
- __ ucomisd(xmm0, FieldOperand(reg, HeapNumber::kValueOffset));
+ if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
+ CpuFeatureScope scope(masm(), SSE2);
+ __ xorps(xmm0, xmm0);
+ __ ucomisd(xmm0, FieldOperand(reg, HeapNumber::kValueOffset));
+ } else {
+ __ fldz();
+ __ fld_d(FieldOperand(reg, HeapNumber::kValueOffset));
+ __ FCmp();
+ }
__ j(zero, false_label);
__ jmp(true_label);
__ bind(¬_heap_number);
@@ -5080,7 +5095,7 @@
void LCodeGen::EmitNumberUntagDNoSSE2(Register input_reg,
Register temp_reg,
- bool deoptimize_on_undefined,
+ bool allow_undefined_as_nan,
bool deoptimize_on_minus_zero,
LEnvironment* env,
NumberUntagDMode mode) {
@@ -5095,7 +5110,7 @@
// Heap number map check.
__ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
factory()->heap_number_map());
- if (deoptimize_on_undefined) {
+ if (!allow_undefined_as_nan) {
DeoptimizeIf(not_equal, env);
} else {
Label heap_number, convert;
@@ -5152,7 +5167,7 @@
void LCodeGen::EmitNumberUntagD(Register input_reg,
Register temp_reg,
XMMRegister result_reg,
- bool deoptimize_on_undefined,
+ bool allow_undefined_as_nan,
bool deoptimize_on_minus_zero,
LEnvironment* env,
NumberUntagDMode mode) {
@@ -5167,7 +5182,7 @@
// Heap number map check.
__ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
factory()->heap_number_map());
- if (deoptimize_on_undefined) {
+ if (!allow_undefined_as_nan) {
DeoptimizeIf(not_equal, env);
} else {
Label heap_number, convert;
@@ -5337,15 +5352,20 @@
// Heap number map check.
__ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
factory()->heap_number_map());
- __ j(equal, &heap_number, Label::kNear);
- // Check for undefined. Undefined is converted to zero for truncating
- // conversions.
- __ cmp(input_reg, factory()->undefined_value());
- __ RecordComment("Deferred TaggedToI: cannot truncate");
- DeoptimizeIf(not_equal, instr->environment());
- __ xor_(result_reg, result_reg);
- __ jmp(&done, Label::kFar);
- __ bind(&heap_number);
+ if (instr->truncating()) {
+ __ j(equal, &heap_number, Label::kNear);
+ // Check for undefined. Undefined is converted to zero for truncating
+ // conversions.
+ __ cmp(input_reg, factory()->undefined_value());
+ __ RecordComment("Deferred TaggedToI: cannot truncate");
+ DeoptimizeIf(not_equal, instr->environment());
+ __ xor_(result_reg, result_reg);
+ __ jmp(&done, Label::kFar);
+ __ bind(&heap_number);
+ } else {
+ // Deoptimize if we don't have a heap number.
+ DeoptimizeIf(not_equal, instr->environment());
+ }
// Surprisingly, all of this crazy bit manipulation is considerably
// faster than using the built-in x86 CPU conversion functions (about 6x).
@@ -5515,14 +5535,14 @@
EmitNumberUntagD(input_reg,
temp_reg,
result_reg,
- instr->hydrogen()->deoptimize_on_undefined(),
+ instr->hydrogen()->allow_undefined_as_nan(),
deoptimize_on_minus_zero,
instr->environment(),
mode);
} else {
EmitNumberUntagDNoSSE2(input_reg,
temp_reg,
- instr->hydrogen()->deoptimize_on_undefined(),
+ instr->hydrogen()->allow_undefined_as_nan(),
deoptimize_on_minus_zero,
instr->environment(),
mode);
diff --git a/src/ia32/lithium-codegen-ia32.h b/src/ia32/lithium-codegen-ia32.h
index dce225c..dec768b 100644
--- a/src/ia32/lithium-codegen-ia32.h
+++ b/src/ia32/lithium-codegen-ia32.h
@@ -331,7 +331,7 @@
Register input,
Register temp,
XMMRegister result,
- bool deoptimize_on_undefined,
+ bool allow_undefined_as_nan,
bool deoptimize_on_minus_zero,
LEnvironment* env,
NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED);
@@ -339,7 +339,7 @@
void EmitNumberUntagDNoSSE2(
Register input,
Register temp,
- bool deoptimize_on_undefined,
+ bool allow_undefined_as_nan,
bool deoptimize_on_minus_zero,
LEnvironment* env,
NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED);
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index 1fd0f49..28c4d2c 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -2108,7 +2108,9 @@
LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
Representation r = instr->representation();
- if (r.IsInteger32()) {
+ if (r.IsSmi()) {
+ return DefineAsRegister(new(zone()) LConstantS);
+ } else if (r.IsInteger32()) {
return DefineAsRegister(new(zone()) LConstantI);
} else if (r.IsDouble()) {
double value = instr->DoubleValue();
@@ -2119,7 +2121,7 @@
} else {
return DefineX87TOS(new(zone()) LConstantD(NULL));
}
- } else if (r.IsSmiOrTagged()) {
+ } else if (r.IsTagged()) {
return DefineAsRegister(new(zone()) LConstantT);
} else {
UNREACHABLE();
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index 2ed4cd6..568ef87 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -82,6 +82,7 @@
V(CmpConstantEqAndBranch) \
V(ConstantD) \
V(ConstantI) \
+ V(ConstantS) \
V(ConstantT) \
V(Context) \
V(DebugBreak) \
@@ -1152,6 +1153,15 @@
};
+class LConstantS: public LTemplateInstruction<1, 0, 0> {
+ public:
+ DECLARE_CONCRETE_INSTRUCTION(ConstantS, "constant-s")
+ DECLARE_HYDROGEN_ACCESSOR(Constant)
+
+ Smi* value() const { return Smi::FromInt(hydrogen()->Integer32Value()); }
+};
+
+
class LConstantD: public LTemplateInstruction<1, 0, 1> {
public:
explicit LConstantD(LOperand* temp) {
diff --git a/src/ic.cc b/src/ic.cc
index e81ea10..7061f4d 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -2945,18 +2945,11 @@
} else {
code = stub.GetCode(isolate());
}
-
- patch(*code);
-
+ set_target(*code);
return DoCompareNilSlow(kind, nil, object);
}
-void CompareNilIC::patch(Code* code) {
- set_target(code);
-}
-
-
RUNTIME_FUNCTION(MaybeObject*, CompareNilIC_Miss) {
HandleScope scope(isolate);
Handle<Object> object = args.at<Object>(0);
@@ -2972,28 +2965,23 @@
}
-RUNTIME_FUNCTION(MaybeObject*, ToBoolean_Patch) {
- ASSERT(args.length() == 3);
-
- HandleScope scope(isolate);
- Handle<Object> object = args.at<Object>(0);
- Register tos = Register::from_code(args.smi_at(1));
- ToBooleanStub::Types old_types(args.smi_at(2));
-
- ToBooleanStub::Types new_types(old_types);
- bool to_boolean_value = new_types.Record(object);
- old_types.TraceTransition(new_types);
-
- ToBooleanStub stub(tos, new_types);
- Handle<Code> code = stub.GetCode(isolate);
- ToBooleanIC ic(isolate);
- ic.patch(*code);
+MaybeObject* ToBooleanIC::ToBoolean(Handle<Object> object,
+ Code::ExtraICState extra_ic_state) {
+ ToBooleanStub stub(extra_ic_state);
+ bool to_boolean_value = stub.Record(object);
+ Handle<Code> code = stub.GetCode(isolate());
+ set_target(*code);
return Smi::FromInt(to_boolean_value ? 1 : 0);
}
-void ToBooleanIC::patch(Code* code) {
- set_target(code);
+RUNTIME_FUNCTION(MaybeObject*, ToBooleanIC_Miss) {
+ ASSERT(args.length() == 1);
+ HandleScope scope(isolate);
+ Handle<Object> object = args.at<Object>(0);
+ ToBooleanIC ic(isolate);
+ Code::ExtraICState ic_state = ic.target()->extended_extra_ic_state();
+ return ic.ToBoolean(object, ic_state);
}
diff --git a/src/ic.h b/src/ic.h
index 8fd96a6..4715f0e 100644
--- a/src/ic.h
+++ b/src/ic.h
@@ -62,7 +62,7 @@
ICU(CompareIC_Miss) \
ICU(CompareNilIC_Miss) \
ICU(Unreachable) \
- ICU(ToBoolean_Patch)
+ ICU(ToBooleanIC_Miss)
//
// IC is the base class for LoadIC, StoreIC, CallIC, KeyedLoadIC,
// and KeyedStoreIC.
@@ -789,8 +789,6 @@
static void Clear(Address address, Code* target);
- void patch(Code* code);
-
static MUST_USE_RESULT MaybeObject* DoCompareNilSlow(EqualityKind kind,
NilValue nil,
Handle<Object> object);
@@ -799,9 +797,9 @@
class ToBooleanIC: public IC {
public:
- explicit ToBooleanIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { }
+ explicit ToBooleanIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) { }
- void patch(Code* code);
+ MaybeObject* ToBoolean(Handle<Object> object, Code::ExtraICState state);
};
@@ -811,8 +809,8 @@
DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissFromStubFailure);
DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissFromStubFailure);
-DECLARE_RUNTIME_FUNCTION(MaybeObject*, CompareNilIC_MissLight);
DECLARE_RUNTIME_FUNCTION(MaybeObject*, CompareNilIC_Miss);
+DECLARE_RUNTIME_FUNCTION(MaybeObject*, ToBooleanIC_Miss);
} } // namespace v8::internal
diff --git a/src/incremental-marking.cc b/src/incremental-marking.cc
index bacbb93..e19d6e2 100644
--- a/src/incremental-marking.cc
+++ b/src/incremental-marking.cc
@@ -54,7 +54,8 @@
should_hurry_(false),
marking_speed_(0),
allocated_(0),
- no_marking_scope_depth_(0) {
+ no_marking_scope_depth_(0),
+ unscanned_bytes_of_large_object_(0) {
}
@@ -241,6 +242,7 @@
chunk->progress_bar());
int end_offset = Min(object_size,
start_offset + kProgressBarScanningChunk);
+ int already_scanned_offset = start_offset;
bool scan_until_end = false;
do {
VisitPointersWithAnchor(heap,
@@ -254,6 +256,8 @@
chunk->set_progress_bar(start_offset);
if (start_offset < object_size) {
heap->incremental_marking()->marking_deque()->UnshiftGrey(object);
+ heap->incremental_marking()->NotifyIncompleteScanOfObject(
+ object_size - (start_offset - already_scanned_offset));
}
} else {
FixedArrayVisitor::Visit(map, object);
@@ -739,8 +743,9 @@
if (map == filler_map) continue;
int size = obj->SizeFromMap(map);
- bytes_to_process -= size;
+ unscanned_bytes_of_large_object_ = 0;
VisitObject(map, obj, size);
+ bytes_to_process -= (size - unscanned_bytes_of_large_object_);
}
}
diff --git a/src/incremental-marking.h b/src/incremental-marking.h
index 47d5a51..d47c300 100644
--- a/src/incremental-marking.h
+++ b/src/incremental-marking.h
@@ -220,6 +220,10 @@
void UncommitMarkingDeque();
+ void NotifyIncompleteScanOfObject(int unscanned_bytes) {
+ unscanned_bytes_of_large_object_ = unscanned_bytes;
+ }
+
private:
int64_t SpaceLeftInOldSpace();
@@ -274,6 +278,8 @@
int no_marking_scope_depth_;
+ int unscanned_bytes_of_large_object_;
+
DISALLOW_IMPLICIT_CONSTRUCTORS(IncrementalMarking);
};
diff --git a/src/isolate.cc b/src/isolate.cc
index 8ae0c74..4daeddc 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -2245,6 +2245,7 @@
stub.InitializeInterfaceDescriptor(
this, code_stub_interface_descriptor(CodeStub::FastCloneShallowArray));
CompareNilICStub::InitializeForIsolate(this);
+ ToBooleanStub::InitializeForIsolate(this);
ArrayConstructorStubBase::InstallDescriptors(this);
}
diff --git a/src/messages.js b/src/messages.js
index 2ad68cb..ce075ce 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -543,11 +543,11 @@
* If sourceURL comment is available and script starts at zero returns sourceURL
* comment contents. Otherwise, script name is returned. See
* http://fbug.googlecode.com/svn/branches/firebug1.1/docs/ReleaseNotes_1.1.txt
- * for details on using //@ sourceURL comment to identify scritps that don't
- * have name.
+ * and Source Map Revision 3 proposal for details on using //# sourceURL and
+ * deprecated //@ sourceURL comment to identify scripts that don't have name.
*
- * @return {?string} script name if present, value for //@ sourceURL comment
- * otherwise.
+ * @return {?string} script name if present, value for //# sourceURL or
+ * deprecated //@ sourceURL comment otherwise.
*/
function ScriptNameOrSourceURL() {
if (this.line_offset > 0 || this.column_offset > 0) {
@@ -572,7 +572,7 @@
this.cachedNameOrSourceURL = this.name;
if (sourceUrlPos > 4) {
var sourceUrlPattern =
- /\/\/@[\040\t]sourceURL=[\040\t]*([^\s\'\"]*)[\040\t]*$/gm;
+ /\/\/[#@][\040\t]sourceURL=[\040\t]*([^\s\'\"]*)[\040\t]*$/gm;
// Don't reuse lastMatchInfo here, so we create a new array with room
// for four captures (array with length one longer than the index
// of the fourth capture, where the numbering is zero-based).
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index 9b4170e..bd89d44 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -46,7 +46,6 @@
static Register registers[] = { a3, a2, a1 };
descriptor->register_param_count_ = 3;
descriptor->register_params_ = registers;
- descriptor->stack_parameter_count_ = NULL;
descriptor->deoptimization_handler_ =
Runtime::FunctionForId(Runtime::kCreateArrayLiteralShallow)->entry;
}
@@ -58,7 +57,6 @@
static Register registers[] = { a3, a2, a1, a0 };
descriptor->register_param_count_ = 4;
descriptor->register_params_ = registers;
- descriptor->stack_parameter_count_ = NULL;
descriptor->deoptimization_handler_ =
Runtime::FunctionForId(Runtime::kCreateObjectLiteralShallow)->entry;
}
@@ -81,7 +79,6 @@
static Register registers[] = { a0 };
descriptor->register_param_count_ = 1;
descriptor->register_params_ = registers;
- descriptor->stack_parameter_count_ = NULL;
descriptor->deoptimization_handler_ = NULL;
}
@@ -92,7 +89,6 @@
static Register registers[] = { a1 };
descriptor->register_param_count_ = 1;
descriptor->register_params_ = registers;
- descriptor->stack_parameter_count_ = NULL;
descriptor->deoptimization_handler_ = NULL;
}
@@ -176,6 +172,19 @@
}
+void ToBooleanStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ static Register registers[] = { a0 };
+ descriptor->register_param_count_ = 1;
+ descriptor->register_params_ = registers;
+ descriptor->deoptimization_handler_ =
+ FUNCTION_ADDR(ToBooleanIC_Miss);
+ descriptor->SetMissHandler(
+ ExternalReference(IC_Utility(IC::kToBooleanIC_Miss), isolate));
+}
+
+
#define __ ACCESS_MASM(masm)
static void EmitIdenticalObjectComparison(MacroAssembler* masm,
@@ -1500,116 +1509,6 @@
}
-// The stub expects its argument in the tos_ register and returns its result in
-// it, too: zero for false, and a non-zero value for true.
-void ToBooleanStub::Generate(MacroAssembler* masm) {
- Label patch;
- const Register map = t5.is(tos_) ? t3 : t5;
-
- // undefined -> false.
- CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false);
-
- // Boolean -> its value.
- CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false);
- CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true);
-
- // 'null' -> false.
- CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false);
-
- if (types_.Contains(SMI)) {
- // Smis: 0 -> false, all other -> true
- __ And(at, tos_, kSmiTagMask);
- // tos_ contains the correct return value already
- __ Ret(eq, at, Operand(zero_reg));
- } else if (types_.NeedsMap()) {
- // If we need a map later and have a Smi -> patch.
- __ JumpIfSmi(tos_, &patch);
- }
-
- if (types_.NeedsMap()) {
- __ lw(map, FieldMemOperand(tos_, HeapObject::kMapOffset));
-
- if (types_.CanBeUndetectable()) {
- __ lbu(at, FieldMemOperand(map, Map::kBitFieldOffset));
- __ And(at, at, Operand(1 << Map::kIsUndetectable));
- // Undetectable -> false.
- __ Movn(tos_, zero_reg, at);
- __ Ret(ne, at, Operand(zero_reg));
- }
- }
-
- if (types_.Contains(SPEC_OBJECT)) {
- // Spec object -> true.
- __ lbu(at, FieldMemOperand(map, Map::kInstanceTypeOffset));
- // tos_ contains the correct non-zero return value already.
- __ Ret(ge, at, Operand(FIRST_SPEC_OBJECT_TYPE));
- }
-
- if (types_.Contains(STRING)) {
- // String value -> false iff empty.
- __ lbu(at, FieldMemOperand(map, Map::kInstanceTypeOffset));
- Label skip;
- __ Branch(&skip, ge, at, Operand(FIRST_NONSTRING_TYPE));
- __ Ret(USE_DELAY_SLOT); // the string length is OK as the return value
- __ lw(tos_, FieldMemOperand(tos_, String::kLengthOffset));
- __ bind(&skip);
- }
-
- if (types_.Contains(HEAP_NUMBER)) {
- // Heap number -> false iff +0, -0, or NaN.
- Label not_heap_number;
- __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
- __ Branch(¬_heap_number, ne, map, Operand(at));
- Label zero_or_nan, number;
- __ ldc1(f2, FieldMemOperand(tos_, HeapNumber::kValueOffset));
- __ BranchF(&number, &zero_or_nan, ne, f2, kDoubleRegZero);
- // "tos_" is a register, and contains a non zero value by default.
- // Hence we only need to overwrite "tos_" with zero to return false for
- // FP_ZERO or FP_NAN cases. Otherwise, by default it returns true.
- __ bind(&zero_or_nan);
- __ mov(tos_, zero_reg);
- __ bind(&number);
- __ Ret();
- __ bind(¬_heap_number);
- }
-
- __ bind(&patch);
- GenerateTypeTransition(masm);
-}
-
-
-void ToBooleanStub::CheckOddball(MacroAssembler* masm,
- Type type,
- Heap::RootListIndex value,
- bool result) {
- if (types_.Contains(type)) {
- // If we see an expected oddball, return its ToBoolean value tos_.
- __ LoadRoot(at, value);
- __ Subu(at, at, tos_); // This is a check for equality for the movz below.
- // The value of a root is never NULL, so we can avoid loading a non-null
- // value into tos_ when we want to return 'true'.
- if (!result) {
- __ Movz(tos_, zero_reg, at);
- }
- __ Ret(eq, at, Operand(zero_reg));
- }
-}
-
-
-void ToBooleanStub::GenerateTypeTransition(MacroAssembler* masm) {
- __ Move(a3, tos_);
- __ li(a2, Operand(Smi::FromInt(tos_.code())));
- __ li(a1, Operand(Smi::FromInt(types_.ToByte())));
- __ Push(a3, a2, a1);
- // Patch the caller to an appropriate specialized stub and return the
- // operation result to the caller of the stub.
- __ TailCallExternalReference(
- ExternalReference(IC_Utility(IC::kToBoolean_Patch), masm->isolate()),
- 3,
- 1);
-}
-
-
void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
// We don't allow a GC during a store buffer overflow so there is no need to
// store the registers in any particular way, but we do have to store and
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index 6a3b72d..78f44ab 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -677,8 +677,9 @@
Label* if_true,
Label* if_false,
Label* fall_through) {
- ToBooleanStub stub(result_register());
- __ CallStub(&stub, condition->test_id());
+ __ mov(a0, result_register());
+ Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate());
+ CallIC(ic, RelocInfo::CODE_TARGET, condition->test_id());
__ mov(at, zero_reg);
Split(ne, v0, Operand(at), if_true, if_false, fall_through);
}
@@ -2061,8 +2062,9 @@
Handle<Code> done_ic = isolate()->builtins()->LoadIC_Initialize();
CallIC(done_ic); // result.done in v0
__ Addu(sp, sp, Operand(kPointerSize)); // drop LoadIC state
- ToBooleanStub stub(v0);
- __ CallStub(&stub);
+ __ mov(a0, v0);
+ Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate());
+ CallIC(bool_ic);
__ Branch(&l_try, eq, v0, Operand(zero_reg));
// result.value
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index 05fa792..25ba162 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -521,6 +521,12 @@
}
+Smi* LCodeGen::ToSmi(LConstantOperand* op) const {
+ HConstant* constant = chunk_->LookupConstant(op);
+ return Smi::FromInt(constant->Integer32Value());
+}
+
+
double LCodeGen::ToDouble(LConstantOperand* op) const {
HConstant* constant = chunk_->LookupConstant(op);
ASSERT(constant->HasDoubleValue());
@@ -1494,7 +1500,11 @@
void LCodeGen::DoConstantI(LConstantI* instr) {
- ASSERT(instr->result()->IsRegister());
+ __ li(ToRegister(instr->result()), Operand(instr->value()));
+}
+
+
+void LCodeGen::DoConstantS(LConstantS* instr) {
__ li(ToRegister(instr->result()), Operand(instr->value()));
}
@@ -1867,9 +1877,11 @@
Representation r = instr->hydrogen()->value()->representation();
if (r.IsInteger32() || r.IsSmi()) {
+ ASSERT(!info()->IsStub());
Register reg = ToRegister(instr->value());
EmitBranch(true_block, false_block, ne, reg, Operand(zero_reg));
} else if (r.IsDouble()) {
+ ASSERT(!info()->IsStub());
DoubleRegister reg = ToDoubleRegister(instr->value());
// Test the double value. Zero and NaN are false.
EmitBranchF(true_block, false_block, nue, reg, kDoubleRegZero);
@@ -1878,9 +1890,11 @@
Register reg = ToRegister(instr->value());
HType type = instr->hydrogen()->value()->type();
if (type.IsBoolean()) {
+ ASSERT(!info()->IsStub());
__ LoadRoot(at, Heap::kTrueValueRootIndex);
EmitBranch(true_block, false_block, eq, reg, Operand(at));
} else if (type.IsSmi()) {
+ ASSERT(!info()->IsStub());
EmitBranch(true_block, false_block, ne, reg, Operand(zero_reg));
} else {
Label* true_label = chunk_->GetAssemblyLabel(true_block);
@@ -2047,11 +2061,23 @@
Operand cmp_right = Operand(0);
if (right->IsConstantOperand()) {
- cmp_left = ToRegister(left);
- cmp_right = Operand(ToInteger32(LConstantOperand::cast(right)));
+ int32_t value = ToInteger32(LConstantOperand::cast(right));
+ if (instr->hydrogen_value()->representation().IsSmi()) {
+ cmp_left = ToRegister(left);
+ cmp_right = Operand(Smi::FromInt(value));
+ } else {
+ cmp_left = ToRegister(left);
+ cmp_right = Operand(value);
+ }
} else if (left->IsConstantOperand()) {
- cmp_left = ToRegister(right);
- cmp_right = Operand(ToInteger32(LConstantOperand::cast(left)));
+ int32_t value = ToInteger32(LConstantOperand::cast(left));
+ if (instr->hydrogen_value()->representation().IsSmi()) {
+ cmp_left = ToRegister(right);
+ cmp_right = Operand(Smi::FromInt(value));
+ } else {
+ cmp_left = ToRegister(right);
+ cmp_right = Operand(value);
+ }
// We transposed the operands. Reverse the condition.
cond = ReverseCondition(cond);
} else {
@@ -2566,8 +2592,8 @@
int no_frame_start = -1;
if (NeedsEagerFrame()) {
__ mov(sp, fp);
- __ Pop(ra, fp);
no_frame_start = masm_->pc_offset();
+ __ Pop(ra, fp);
}
if (instr->has_constant_parameter_count()) {
int parameter_count = ToInteger32(instr->constant_parameter_count());
@@ -4659,7 +4685,7 @@
void LCodeGen::EmitNumberUntagD(Register input_reg,
DoubleRegister result_reg,
- bool deoptimize_on_undefined,
+ bool allow_undefined_as_nan,
bool deoptimize_on_minus_zero,
LEnvironment* env,
NumberUntagDMode mode) {
@@ -4676,7 +4702,7 @@
// Heap number map check.
__ lw(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset));
__ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
- if (deoptimize_on_undefined) {
+ if (!allow_undefined_as_nan) {
DeoptimizeIf(ne, env, scratch, Operand(at));
} else {
Label heap_number, convert;
@@ -4849,7 +4875,7 @@
}
EmitNumberUntagD(input_reg, result_reg,
- instr->hydrogen()->deoptimize_on_undefined(),
+ instr->hydrogen()->allow_undefined_as_nan(),
instr->hydrogen()->deoptimize_on_minus_zero(),
instr->environment(),
mode);
@@ -5211,7 +5237,10 @@
flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
}
if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
+ ASSERT(!instr->hydrogen()->CanAllocateInOldDataSpace());
flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
+ } else if (instr->hydrogen()->CanAllocateInOldDataSpace()) {
+ flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_DATA_SPACE);
}
if (instr->size()->IsConstantOperand()) {
int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
@@ -5250,11 +5279,12 @@
}
if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
- CallRuntimeFromDeferred(
- Runtime::kAllocateInOldPointerSpace, 1, instr);
+ ASSERT(!instr->hydrogen()->CanAllocateInOldDataSpace());
+ CallRuntimeFromDeferred(Runtime::kAllocateInOldPointerSpace, 1, instr);
+ } else if (instr->hydrogen()->CanAllocateInOldDataSpace()) {
+ CallRuntimeFromDeferred(Runtime::kAllocateInOldDataSpace, 1, instr);
} else {
- CallRuntimeFromDeferred(
- Runtime::kAllocateInNewSpace, 1, instr);
+ CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr);
}
__ StoreToSafepointRegisterSlot(v0, result);
}
diff --git a/src/mips/lithium-codegen-mips.h b/src/mips/lithium-codegen-mips.h
index a575f5d..2f4e140 100644
--- a/src/mips/lithium-codegen-mips.h
+++ b/src/mips/lithium-codegen-mips.h
@@ -118,6 +118,7 @@
FloatRegister flt_scratch,
DoubleRegister dbl_scratch);
int ToInteger32(LConstantOperand* op) const;
+ Smi* ToSmi(LConstantOperand* op) const;
double ToDouble(LConstantOperand* op) const;
Operand ToOperand(LOperand* op);
MemOperand ToMemOperand(LOperand* op) const;
@@ -342,7 +343,7 @@
void EmitCmpI(LOperand* left, LOperand* right);
void EmitNumberUntagD(Register input,
DoubleRegister result,
- bool deoptimize_on_undefined,
+ bool allow_undefined_as_nan,
bool deoptimize_on_minus_zero,
LEnvironment* env,
NumberUntagDMode mode);
diff --git a/src/mips/lithium-gap-resolver-mips.cc b/src/mips/lithium-gap-resolver-mips.cc
index 87efae5..23a8f32 100644
--- a/src/mips/lithium-gap-resolver-mips.cc
+++ b/src/mips/lithium-gap-resolver-mips.cc
@@ -252,7 +252,9 @@
LConstantOperand* constant_source = LConstantOperand::cast(source);
if (destination->IsRegister()) {
Register dst = cgen_->ToRegister(destination);
- if (cgen_->IsInteger32(constant_source)) {
+ if (cgen_->IsSmi(constant_source)) {
+ __ li(dst, Operand(cgen_->ToSmi(constant_source)));
+ } else if (cgen_->IsInteger32(constant_source)) {
__ li(dst, Operand(cgen_->ToInteger32(constant_source)));
} else {
__ LoadObject(dst, cgen_->ToHandle(constant_source));
@@ -260,7 +262,9 @@
} else {
ASSERT(destination->IsStackSlot());
ASSERT(!in_cycle_); // Constant moves happen after all cycles are gone.
- if (cgen_->IsInteger32(constant_source)) {
+ if (cgen_->IsSmi(constant_source)) {
+ __ li(kLithiumScratchReg, Operand(cgen_->ToSmi(constant_source)));
+ } else if (cgen_->IsInteger32(constant_source)) {
__ li(kLithiumScratchReg,
Operand(cgen_->ToInteger32(constant_source)));
} else {
diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc
index 22adc2a..2325064 100644
--- a/src/mips/lithium-mips.cc
+++ b/src/mips/lithium-mips.cc
@@ -1554,9 +1554,10 @@
LInstruction* LChunkBuilder::DoCompareIDAndBranch(
HCompareIDAndBranch* instr) {
Representation r = instr->representation();
- if (r.IsInteger32()) {
- ASSERT(instr->left()->representation().IsInteger32());
- ASSERT(instr->right()->representation().IsInteger32());
+ if (r.IsSmiOrInteger32()) {
+ ASSERT(instr->left()->representation().IsSmiOrInteger32());
+ ASSERT(instr->left()->representation().Equals(
+ instr->right()->representation()));
LOperand* left = UseRegisterOrConstantAtStart(instr->left());
LOperand* right = UseRegisterOrConstantAtStart(instr->right());
return new(zone()) LCmpIDAndBranch(left, right);
@@ -1908,7 +1909,7 @@
} else if (input_rep.IsInteger32()) {
return DefineAsRegister(new(zone()) LClampIToUint8(reg));
} else {
- ASSERT(input_rep.IsTagged());
+ ASSERT(input_rep.IsSmiOrTagged());
// Register allocator doesn't (yet) support allocation of double
// temps. Reserve f22 explicitly.
LClampTToUint8* result = new(zone()) LClampTToUint8(reg, FixedTemp(f22));
@@ -1926,11 +1927,13 @@
LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
Representation r = instr->representation();
- if (r.IsInteger32()) {
+ if (r.IsSmi()) {
+ return DefineAsRegister(new(zone()) LConstantS);
+ } else if (r.IsInteger32()) {
return DefineAsRegister(new(zone()) LConstantI);
} else if (r.IsDouble()) {
return DefineAsRegister(new(zone()) LConstantD);
- } else if (r.IsSmiOrTagged()) {
+ } else if (r.IsTagged()) {
return DefineAsRegister(new(zone()) LConstantT);
} else {
UNREACHABLE();
@@ -2357,7 +2360,7 @@
index = UseOrConstant(instr->index());
} else {
length = UseTempRegister(instr->length());
- index = Use(instr->index());
+ index = UseRegisterAtStart(instr->index());
}
return DefineAsRegister(new(zone()) LAccessArgumentsAt(args, length, index));
}
diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h
index e3ada26..01dd6c2 100644
--- a/src/mips/lithium-mips.h
+++ b/src/mips/lithium-mips.h
@@ -87,6 +87,7 @@
V(CmpT) \
V(ConstantD) \
V(ConstantI) \
+ V(ConstantS) \
V(ConstantT) \
V(Context) \
V(DebugBreak) \
@@ -1153,6 +1154,15 @@
};
+class LConstantS: public LTemplateInstruction<1, 0, 0> {
+ public:
+ DECLARE_CONCRETE_INSTRUCTION(ConstantS, "constant-s")
+ DECLARE_HYDROGEN_ACCESSOR(Constant)
+
+ Smi* value() const { return Smi::FromInt(hydrogen()->Integer32Value()); }
+};
+
+
class LConstantD: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ConstantD, "constant-d")
diff --git a/src/mksnapshot.cc b/src/mksnapshot.cc
index 7592a89..978ea21 100644
--- a/src/mksnapshot.cc
+++ b/src/mksnapshot.cc
@@ -32,10 +32,6 @@
#endif
#include <signal.h>
-// TODO(dcarney): remove
-#define V8_ALLOW_ACCESS_TO_PERSISTENT_ARROW
-#define V8_ALLOW_ACCESS_TO_PERSISTENT_IMPLICIT
-
#include "v8.h"
#include "bootstrapper.h"
@@ -341,10 +337,10 @@
exit(1);
}
if (i::FLAG_extra_code != NULL) {
- context->Enter();
// Capture 100 frames if anything happens.
V8::SetCaptureStackTraceForUncaughtExceptions(true, 100);
HandleScope scope(isolate);
+ v8::Context::Scope(v8::Local<v8::Context>::New(isolate, context));
const char* name = i::FLAG_extra_code;
FILE* file = i::OS::FOpen(name, "rb");
if (file == NULL) {
@@ -381,7 +377,6 @@
DumpException(try_catch.Message());
exit(1);
}
- context->Exit();
}
// Make sure all builtin scripts are cached.
{ HandleScope scope(isolate);
@@ -393,7 +388,7 @@
// context even after we have disposed of the context.
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags, "mksnapshot");
i::Object* raw_context = *(v8::Utils::OpenHandle(*context));
- context.Dispose(context->GetIsolate());
+ context.Dispose(isolate);
CppByteSink sink(argv[1]);
// This results in a somewhat smaller snapshot, probably because it gets rid
// of some things that are cached between garbage collections.
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 3dd3fd6..d0958ee 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -3729,6 +3729,7 @@
Code::ExtraICState Code::extended_extra_ic_state() {
ASSERT(is_inline_cache_stub() || ic_state() == DEBUG_STUB);
+ ASSERT(needs_extended_extra_ic_state(kind()));
return ExtractExtendedExtraICStateFromFlags(flags());
}
@@ -3979,17 +3980,7 @@
byte Code::to_boolean_state() {
- ASSERT(is_to_boolean_ic_stub());
- return ToBooleanStateField::decode(
- READ_UINT32_FIELD(this, kKindSpecificFlags1Offset));
-}
-
-
-void Code::set_to_boolean_state(byte value) {
- ASSERT(is_to_boolean_ic_stub());
- int previous = READ_UINT32_FIELD(this, kKindSpecificFlags1Offset);
- int updated = ToBooleanStateField::update(previous, value);
- WRITE_UINT32_FIELD(this, kKindSpecificFlags1Offset, updated);
+ return extended_extra_ic_state();
}
@@ -4052,10 +4043,7 @@
| TypeField::encode(type)
| ExtendedExtraICStateField::encode(extra_ic_state)
| CacheHolderField::encode(holder);
- // TODO(danno): This is a bit of a hack right now since there are still
- // clients of this API that pass "extra" values in for argc. These clients
- // should be retrofitted to used ExtendedExtraICState.
- if (kind != Code::COMPARE_NIL_IC) {
+ if (!Code::needs_extended_extra_ic_state(kind)) {
bits |= (argc << kArgumentsCountShift);
}
return static_cast<Flags>(bits);
diff --git a/src/objects.h b/src/objects.h
index 34d0533..8420069 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -4534,8 +4534,16 @@
inline Kind kind();
inline InlineCacheState ic_state(); // Only valid for IC stubs.
inline ExtraICState extra_ic_state(); // Only valid for IC stubs.
+
inline ExtraICState extended_extra_ic_state(); // Only valid for
// non-call IC stubs.
+ static bool needs_extended_extra_ic_state(Kind kind) {
+ // TODO(danno): This is a bit of a hack right now since there are still
+ // clients of this API that pass "extra" values in for argc. These clients
+ // should be retrofitted to used ExtendedExtraICState.
+ return kind == COMPARE_NIL_IC || kind == TO_BOOLEAN_IC;
+ }
+
inline StubType type(); // Only valid for monomorphic IC stubs.
inline int arguments_count(); // Only valid for call IC stubs.
@@ -4628,7 +4636,6 @@
// [to_boolean_foo]: For kind TO_BOOLEAN_IC tells what state the stub is in.
inline byte to_boolean_state();
- inline void set_to_boolean_state(byte value);
// [compare_nil]: For kind COMPARE_NIL_IC tells what state the stub is in.
byte compare_nil_types();
@@ -4860,9 +4867,6 @@
static const int kUnaryOpTypeFirstBit =
kStackSlotsFirstBit + kStackSlotsBitCount;
static const int kUnaryOpTypeBitCount = 3;
- static const int kToBooleanStateFirstBit =
- kStackSlotsFirstBit + kStackSlotsBitCount;
- static const int kToBooleanStateBitCount = 8;
static const int kHasFunctionCacheFirstBit =
kStackSlotsFirstBit + kStackSlotsBitCount;
static const int kHasFunctionCacheBitCount = 1;
@@ -4872,7 +4876,6 @@
STATIC_ASSERT(kStackSlotsFirstBit + kStackSlotsBitCount <= 32);
STATIC_ASSERT(kUnaryOpTypeFirstBit + kUnaryOpTypeBitCount <= 32);
- STATIC_ASSERT(kToBooleanStateFirstBit + kToBooleanStateBitCount <= 32);
STATIC_ASSERT(kHasFunctionCacheFirstBit + kHasFunctionCacheBitCount <= 32);
STATIC_ASSERT(kMarkedForDeoptimizationFirstBit +
kMarkedForDeoptimizationBitCount <= 32);
@@ -4881,8 +4884,6 @@
kStackSlotsFirstBit, kStackSlotsBitCount> {}; // NOLINT
class UnaryOpTypeField: public BitField<int,
kUnaryOpTypeFirstBit, kUnaryOpTypeBitCount> {}; // NOLINT
- class ToBooleanStateField: public BitField<int,
- kToBooleanStateFirstBit, kToBooleanStateBitCount> {}; // NOLINT
class HasFunctionCacheField: public BitField<bool,
kHasFunctionCacheFirstBit, kHasFunctionCacheBitCount> {}; // NOLINT
class MarkedForDeoptimizationField: public BitField<bool,
diff --git a/src/platform-linux.cc b/src/platform-linux.cc
index a4d03b0..22f2245 100644
--- a/src/platform-linux.cc
+++ b/src/platform-linux.cc
@@ -591,6 +591,10 @@
// kernel log.
int size = sysconf(_SC_PAGESIZE);
FILE* f = fopen(FLAG_gc_fake_mmap, "w+");
+ if (f == NULL) {
+ OS::PrintError("Failed to open %s\n", FLAG_gc_fake_mmap);
+ OS::Abort();
+ }
void* addr = mmap(OS::GetRandomMmapAddr(),
size,
PROT_READ | PROT_EXEC,
diff --git a/src/platform-openbsd.cc b/src/platform-openbsd.cc
index 380c15f..0a7cc80 100644
--- a/src/platform-openbsd.cc
+++ b/src/platform-openbsd.cc
@@ -344,6 +344,10 @@
// kernel log.
int size = sysconf(_SC_PAGESIZE);
FILE* f = fopen(FLAG_gc_fake_mmap, "w+");
+ if (f == NULL) {
+ OS::PrintError("Failed to open %s\n", FLAG_gc_fake_mmap);
+ OS::Abort();
+ }
void* addr = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_PRIVATE,
fileno(f), 0);
ASSERT(addr != MAP_FAILED);
diff --git a/src/runtime.cc b/src/runtime.cc
index 3e77584..7e45753 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -28,8 +28,6 @@
#include <stdlib.h>
#include <limits>
-#define V8_ALLOW_ACCESS_TO_PERSISTENT_IMPLICIT
-
#include "v8.h"
#include "accessors.h"
@@ -708,7 +706,7 @@
SetupArrayBuffer(isolate, array_buffer, false, data, allocated_length);
v8::Isolate* external_isolate = reinterpret_cast<v8::Isolate*>(isolate);
- v8::Persistent<v8::Value> weak_handle = v8::Persistent<v8::Value>::New(
+ v8::Persistent<v8::Value> weak_handle(
external_isolate, v8::Utils::ToLocal(Handle<Object>::cast(array_buffer)));
weak_handle.MakeWeak(external_isolate, data, ArrayBufferWeakCallback);
weak_handle.MarkIndependent(external_isolate);
@@ -13360,7 +13358,9 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_IsObserved) {
NoHandleAllocation ha(isolate);
ASSERT(args.length() == 1);
- CONVERT_ARG_CHECKED(JSReceiver, obj, 0);
+
+ if (!args[0]->IsJSReceiver()) return isolate->heap()->false_value();
+ JSReceiver* obj = JSReceiver::cast(args[0]);
if (obj->IsJSGlobalProxy()) {
Object* proto = obj->GetPrototype();
if (proto->IsNull()) return isolate->heap()->false_value();
diff --git a/src/sampler.cc b/src/sampler.cc
index da186b6..25478a6 100644
--- a/src/sampler.cc
+++ b/src/sampler.cc
@@ -234,13 +234,11 @@
if (sample == NULL) sample = &sample_obj;
#if defined(USE_SIMULATOR)
-#if V8_TARGET_ARCH_ARM
- sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
+ sample->pc = reinterpret_cast<Address>(sim->get_pc());
sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
+#if V8_TARGET_ARCH_ARM
sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::r11));
#elif V8_TARGET_ARCH_MIPS
- sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
- sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::fp));
#endif // V8_TARGET_ARCH_*
#else
@@ -523,13 +521,11 @@
&count) == KERN_SUCCESS) {
sample->state = isolate->current_vm_state();
#if defined(USE_SIMULATOR)
-#if V8_TARGET_ARCH_ARM
- sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
+ sample->pc = reinterpret_cast<Address>(sim->get_pc());
sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
+#if V8_TARGET_ARCH_ARM
sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::r11));
#elif V8_TARGET_ARCH_MIPS
- sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
- sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::fp));
#endif
#else
@@ -577,13 +573,11 @@
context.ContextFlags = CONTEXT_FULL;
if (GetThreadContext(profiled_thread, &context) != 0) {
#if defined(USE_SIMULATOR)
-#if V8_TARGET_ARCH_ARM
- sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
+ sample->pc = reinterpret_cast<Address>(sim->get_pc());
sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
+#if V8_TARGET_ARCH_ARM
sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::r11));
#elif V8_TARGET_ARCH_MIPS
- sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
- sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::fp));
#endif
#else
diff --git a/src/utils.h b/src/utils.h
index 93cded1..b16730b 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -232,6 +232,13 @@
}
+// Returns the negative absolute value of its argument.
+template <typename T>
+T NegAbs(T a) {
+ return a < 0 ? a : -a;
+}
+
+
inline int StrLength(const char* string) {
size_t length = strlen(string);
ASSERT(length == static_cast<size_t>(static_cast<int>(length)));
diff --git a/src/version.cc b/src/version.cc
index aeb9599..7cd381f 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 19
-#define BUILD_NUMBER 6
-#define PATCH_LEVEL 1
+#define BUILD_NUMBER 7
+#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/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index e9f7e46..d2ed601 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -46,7 +46,6 @@
static Register registers[] = { rax, rbx, rcx };
descriptor->register_param_count_ = 3;
descriptor->register_params_ = registers;
- descriptor->stack_parameter_count_ = NULL;
descriptor->deoptimization_handler_ =
Runtime::FunctionForId(Runtime::kCreateArrayLiteralShallow)->entry;
}
@@ -58,7 +57,6 @@
static Register registers[] = { rax, rbx, rcx, rdx };
descriptor->register_param_count_ = 4;
descriptor->register_params_ = registers;
- descriptor->stack_parameter_count_ = NULL;
descriptor->deoptimization_handler_ =
Runtime::FunctionForId(Runtime::kCreateObjectLiteralShallow)->entry;
}
@@ -81,7 +79,6 @@
static Register registers[] = { rax };
descriptor->register_param_count_ = 1;
descriptor->register_params_ = registers;
- descriptor->stack_parameter_count_ = NULL;
descriptor->deoptimization_handler_ = NULL;
}
@@ -92,7 +89,6 @@
static Register registers[] = { rdx };
descriptor->register_param_count_ = 1;
descriptor->register_params_ = registers;
- descriptor->stack_parameter_count_ = NULL;
descriptor->deoptimization_handler_ = NULL;
}
@@ -175,6 +171,19 @@
}
+void ToBooleanStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ static Register registers[] = { rax };
+ descriptor->register_param_count_ = 1;
+ descriptor->register_params_ = registers;
+ descriptor->deoptimization_handler_ =
+ FUNCTION_ADDR(ToBooleanIC_Miss);
+ descriptor->SetMissHandler(
+ ExternalReference(IC_Utility(IC::kToBooleanIC_Miss), isolate));
+}
+
+
#define __ ACCESS_MASM(masm)
@@ -462,106 +471,6 @@
}
-// The stub expects its argument on the stack and returns its result in tos_:
-// zero for false, and a non-zero value for true.
-void ToBooleanStub::Generate(MacroAssembler* masm) {
- // This stub overrides SometimesSetsUpAFrame() to return false. That means
- // we cannot call anything that could cause a GC from this stub.
- Label patch;
- const Register argument = rax;
- const Register map = rdx;
-
- if (!types_.IsEmpty()) {
- __ movq(argument, Operand(rsp, 1 * kPointerSize));
- }
-
- // undefined -> false
- CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false);
-
- // Boolean -> its value
- CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false);
- CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true);
-
- // 'null' -> false.
- CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false);
-
- if (types_.Contains(SMI)) {
- // Smis: 0 -> false, all other -> true
- Label not_smi;
- __ JumpIfNotSmi(argument, ¬_smi, Label::kNear);
- // argument contains the correct return value already
- if (!tos_.is(argument)) {
- __ movq(tos_, argument);
- }
- __ ret(1 * kPointerSize);
- __ bind(¬_smi);
- } else if (types_.NeedsMap()) {
- // If we need a map later and have a Smi -> patch.
- __ JumpIfSmi(argument, &patch, Label::kNear);
- }
-
- if (types_.NeedsMap()) {
- __ movq(map, FieldOperand(argument, HeapObject::kMapOffset));
-
- if (types_.CanBeUndetectable()) {
- __ testb(FieldOperand(map, Map::kBitFieldOffset),
- Immediate(1 << Map::kIsUndetectable));
- // Undetectable -> false.
- Label not_undetectable;
- __ j(zero, ¬_undetectable, Label::kNear);
- __ Set(tos_, 0);
- __ ret(1 * kPointerSize);
- __ bind(¬_undetectable);
- }
- }
-
- if (types_.Contains(SPEC_OBJECT)) {
- // spec object -> true.
- Label not_js_object;
- __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
- __ j(below, ¬_js_object, Label::kNear);
- // argument contains the correct return value already.
- if (!tos_.is(argument)) {
- __ Set(tos_, 1);
- }
- __ ret(1 * kPointerSize);
- __ bind(¬_js_object);
- }
-
- if (types_.Contains(STRING)) {
- // String value -> false iff empty.
- Label not_string;
- __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
- __ j(above_equal, ¬_string, Label::kNear);
- __ movq(tos_, FieldOperand(argument, String::kLengthOffset));
- __ ret(1 * kPointerSize); // the string length is OK as the return value
- __ bind(¬_string);
- }
-
- if (types_.Contains(HEAP_NUMBER)) {
- // heap number -> false iff +0, -0, or NaN.
- Label not_heap_number, false_result;
- __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
- __ j(not_equal, ¬_heap_number, Label::kNear);
- __ xorps(xmm0, xmm0);
- __ ucomisd(xmm0, FieldOperand(argument, HeapNumber::kValueOffset));
- __ j(zero, &false_result, Label::kNear);
- // argument contains the correct return value already.
- if (!tos_.is(argument)) {
- __ Set(tos_, 1);
- }
- __ ret(1 * kPointerSize);
- __ bind(&false_result);
- __ Set(tos_, 0);
- __ ret(1 * kPointerSize);
- __ bind(¬_heap_number);
- }
-
- __ bind(&patch);
- GenerateTypeTransition(masm);
-}
-
-
void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
__ PushCallerSaved(save_doubles_);
const int argument_count = 1;
@@ -578,44 +487,6 @@
}
-void ToBooleanStub::CheckOddball(MacroAssembler* masm,
- Type type,
- Heap::RootListIndex value,
- bool result) {
- const Register argument = rax;
- if (types_.Contains(type)) {
- // If we see an expected oddball, return its ToBoolean value tos_.
- Label different_value;
- __ CompareRoot(argument, value);
- __ j(not_equal, &different_value, Label::kNear);
- if (!result) {
- // If we have to return zero, there is no way around clearing tos_.
- __ Set(tos_, 0);
- } else if (!tos_.is(argument)) {
- // If we have to return non-zero, we can re-use the argument if it is the
- // same register as the result, because we never see Smi-zero here.
- __ Set(tos_, 1);
- }
- __ ret(1 * kPointerSize);
- __ bind(&different_value);
- }
-}
-
-
-void ToBooleanStub::GenerateTypeTransition(MacroAssembler* masm) {
- __ pop(rcx); // Get return address, operand is now on top of stack.
- __ Push(Smi::FromInt(tos_.code()));
- __ Push(Smi::FromInt(types_.ToByte()));
- __ push(rcx); // Push return address.
- // Patch the caller to an appropriate specialized stub and return the
- // operation result to the caller of the stub.
- __ TailCallExternalReference(
- ExternalReference(IC_Utility(IC::kToBoolean_Patch), masm->isolate()),
- 3,
- 1);
-}
-
-
class FloatingPointHelper : public AllStatic {
public:
enum ConvertUndefined {
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index e88e1a5..e03c023 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -652,9 +652,8 @@
Label* if_true,
Label* if_false,
Label* fall_through) {
- ToBooleanStub stub(result_register());
- __ push(result_register());
- __ CallStub(&stub, condition->test_id());
+ Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate());
+ CallIC(ic, RelocInfo::CODE_TARGET, condition->test_id());
__ testq(result_register(), result_register());
// The stub returns nonzero for true.
Split(not_zero, if_true, if_false, fall_through);
@@ -2028,10 +2027,9 @@
__ LoadRoot(rcx, Heap::kdone_stringRootIndex); // "done"
Handle<Code> done_ic = isolate()->builtins()->LoadIC_Initialize();
CallIC(done_ic); // result.done in rax
- ToBooleanStub stub(rax);
- __ push(rax);
- __ CallStub(&stub);
- __ testq(rax, rax);
+ Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate());
+ CallIC(bool_ic);
+ __ testq(result_register(), result_register());
__ j(zero, &l_try);
// result.value
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index 74834a0..c94af7d 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -1560,11 +1560,15 @@
void LCodeGen::DoConstantI(LConstantI* instr) {
- ASSERT(instr->result()->IsRegister());
__ Set(ToRegister(instr->result()), instr->value());
}
+void LCodeGen::DoConstantS(LConstantS* instr) {
+ __ Move(ToRegister(instr->result()), instr->value());
+}
+
+
void LCodeGen::DoConstantD(LConstantD* instr) {
ASSERT(instr->result()->IsDoubleRegister());
XMMRegister res = ToDoubleRegister(instr->result());
@@ -1907,14 +1911,17 @@
Representation r = instr->hydrogen()->value()->representation();
if (r.IsInteger32()) {
+ ASSERT(!info()->IsStub());
Register reg = ToRegister(instr->value());
__ testl(reg, reg);
EmitBranch(true_block, false_block, not_zero);
} else if (r.IsSmi()) {
+ ASSERT(!info()->IsStub());
Register reg = ToRegister(instr->value());
__ testq(reg, reg);
EmitBranch(true_block, false_block, not_zero);
} else if (r.IsDouble()) {
+ ASSERT(!info()->IsStub());
XMMRegister reg = ToDoubleRegister(instr->value());
__ xorps(xmm0, xmm0);
__ ucomisd(reg, xmm0);
@@ -1924,9 +1931,11 @@
Register reg = ToRegister(instr->value());
HType type = instr->hydrogen()->value()->type();
if (type.IsBoolean()) {
+ ASSERT(!info()->IsStub());
__ CompareRoot(reg, Heap::kTrueValueRootIndex);
EmitBranch(true_block, false_block, equal);
} else if (type.IsSmi()) {
+ ASSERT(!info()->IsStub());
__ SmiCompare(reg, Smi::FromInt(0));
EmitBranch(true_block, false_block, not_equal);
} else {
@@ -4679,7 +4688,7 @@
void LCodeGen::EmitNumberUntagD(Register input_reg,
XMMRegister result_reg,
- bool deoptimize_on_undefined,
+ bool allow_undefined_as_nan,
bool deoptimize_on_minus_zero,
LEnvironment* env,
NumberUntagDMode mode) {
@@ -4694,7 +4703,7 @@
// Heap number map check.
__ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset),
Heap::kHeapNumberMapRootIndex);
- if (deoptimize_on_undefined) {
+ if (!allow_undefined_as_nan) {
DeoptimizeIf(not_equal, env);
} else {
Label heap_number, convert;
@@ -4830,7 +4839,7 @@
}
EmitNumberUntagD(input_reg, result_reg,
- instr->hydrogen()->deoptimize_on_undefined(),
+ instr->hydrogen()->allow_undefined_as_nan(),
instr->hydrogen()->deoptimize_on_minus_zero(),
instr->environment(),
mode);
diff --git a/src/x64/lithium-codegen-x64.h b/src/x64/lithium-codegen-x64.h
index 697d49d..9890649 100644
--- a/src/x64/lithium-codegen-x64.h
+++ b/src/x64/lithium-codegen-x64.h
@@ -295,7 +295,7 @@
void EmitNumberUntagD(
Register input,
XMMRegister result,
- bool deoptimize_on_undefined,
+ bool allow_undefined_as_nan,
bool deoptimize_on_minus_zero,
LEnvironment* env,
NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED);
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index 9a88c5b..fe23709 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -1969,12 +1969,14 @@
LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
Representation r = instr->representation();
- if (r.IsInteger32()) {
+ if (r.IsSmi()) {
+ return DefineAsRegister(new(zone()) LConstantS);
+ } else if (r.IsInteger32()) {
return DefineAsRegister(new(zone()) LConstantI);
} else if (r.IsDouble()) {
LOperand* temp = TempRegister();
return DefineAsRegister(new(zone()) LConstantD(temp));
- } else if (r.IsSmiOrTagged()) {
+ } else if (r.IsTagged()) {
return DefineAsRegister(new(zone()) LConstantT);
} else {
UNREACHABLE();
diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h
index c295e34..36b080f 100644
--- a/src/x64/lithium-x64.h
+++ b/src/x64/lithium-x64.h
@@ -87,6 +87,7 @@
V(CmpT) \
V(ConstantD) \
V(ConstantI) \
+ V(ConstantS) \
V(ConstantT) \
V(Context) \
V(DebugBreak) \
@@ -1136,6 +1137,15 @@
};
+class LConstantS: public LTemplateInstruction<1, 0, 0> {
+ public:
+ DECLARE_CONCRETE_INSTRUCTION(ConstantS, "constant-s")
+ DECLARE_HYDROGEN_ACCESSOR(Constant)
+
+ Smi* value() const { return Smi::FromInt(hydrogen()->Integer32Value()); }
+};
+
+
class LConstantD: public LTemplateInstruction<1, 0, 1> {
public:
explicit LConstantD(LOperand* temp) {
diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status
index b0451e9..84a1a70 100644
--- a/test/cctest/cctest.status
+++ b/test/cctest/cctest.status
@@ -70,15 +70,6 @@
test-serialize/DeserializeFromSecondSerialization: SKIP
##############################################################################
-[ $arch == arm || $arch == mipsel ]
-
-# BUG(2628): Signal may come when pc is close to frame enter/exit code and on
-# simulator the stack frame is not set up when it is expected to be for the pc
-# value.
-test-cpu-profiler/CollectCpuProfile: PASS || FAIL
-test-cpu-profiler/SampleWhenFrameIsNotSetup: PASS || FAIL
-
-##############################################################################
[ $arch == android_arm || $arch == android_ia32 ]
# Tests crash as there is no /tmp directory in Android.
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index e52dde3..9eecf94 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -32,11 +32,6 @@
#include <unistd.h> // getpid
#endif // WIN32
-// TODO(dcarney): remove
-#define V8_ALLOW_ACCESS_TO_RAW_HANDLE_CONSTRUCTOR
-#define V8_ALLOW_ACCESS_TO_PERSISTENT_IMPLICIT
-#define V8_ALLOW_ACCESS_TO_PERSISTENT_ARROW
-
#include "v8.h"
#include "api.h"
@@ -1034,6 +1029,7 @@
// variable return values
static bool fast_return_value_bool = false;
static bool fast_return_value_void_is_null = false;
+static bool fast_return_value_object_is_empty = false;
template<>
void FastReturnValueCallback<int32_t>(
@@ -1077,7 +1073,9 @@
template<>
void FastReturnValueCallback<Object>(
const v8::FunctionCallbackInfo<v8::Value>& info) {
- info.GetReturnValue().Set(Object::New());
+ v8::Handle<v8::Object> object;
+ if (!fast_return_value_object_is_empty) object = Object::New();
+ info.GetReturnValue().Set(object);
}
template<typename T>
@@ -1124,8 +1122,13 @@
CHECK(value->IsUndefined());
}
}
+ // check handles
+ fast_return_value_object_is_empty = false;
value = TestFastReturnValues<Object>();
CHECK(value->IsObject());
+ fast_return_value_object_is_empty = true;
+ value = TestFastReturnValues<Object>();
+ CHECK(value->IsUndefined());
}
@@ -2782,71 +2785,75 @@
v8::Persistent<String> global;
{
v8::HandleScope scope(isolate);
- Local<String> str = v8_str("str");
- global = v8::Persistent<String>::New(isolate, str);
+ global.Reset(isolate, v8_str("str"));
}
- CHECK_EQ(global->Length(), 3);
- global.Dispose(isolate);
-
{
v8::HandleScope scope(isolate);
- Local<String> str = v8_str("str");
- global = v8::Persistent<String>::New(isolate, str);
+ CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
}
- CHECK_EQ(global->Length(), 3);
- global.Dispose(isolate);
+ global.Dispose();
+ global.Clear();
+ {
+ v8::HandleScope scope(isolate);
+ global.Reset(isolate, v8_str("str"));
+ }
+ {
+ v8::HandleScope scope(isolate);
+ CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
+ }
+ global.Dispose();
}
THREADED_TEST(ResettingGlobalHandle) {
v8::Isolate* isolate = v8::Isolate::GetCurrent();
- v8::internal::GlobalHandles* global_handles = NULL;
- int initial_handle_count = 0;
v8::Persistent<String> global;
{
v8::HandleScope scope(isolate);
- Local<String> str = v8_str("str");
- global_handles =
- reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
- initial_handle_count = global_handles->NumberOfGlobalHandles();
- global = v8::Persistent<String>::New(isolate, str);
+ global.Reset(isolate, v8_str("str"));
}
- CHECK_EQ(global->Length(), 3);
- CHECK_EQ(global_handles->NumberOfGlobalHandles(), initial_handle_count + 1);
+ v8::internal::GlobalHandles* global_handles =
+ reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
+ int initial_handle_count = global_handles->NumberOfGlobalHandles();
{
v8::HandleScope scope(isolate);
- Local<String> str = v8_str("longer");
- global.Reset(isolate, str);
+ CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
}
- CHECK_EQ(global->Length(), 6);
- CHECK_EQ(global_handles->NumberOfGlobalHandles(), initial_handle_count + 1);
- global.Dispose(isolate);
+ {
+ v8::HandleScope scope(isolate);
+ global.Reset(isolate, v8_str("longer"));
+ }
CHECK_EQ(global_handles->NumberOfGlobalHandles(), initial_handle_count);
+ {
+ v8::HandleScope scope(isolate);
+ CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
+ }
+ global.Dispose(isolate);
+ CHECK_EQ(global_handles->NumberOfGlobalHandles(), initial_handle_count - 1);
}
THREADED_TEST(ResettingGlobalHandleToEmpty) {
v8::Isolate* isolate = v8::Isolate::GetCurrent();
- v8::internal::GlobalHandles* global_handles = NULL;
- int initial_handle_count = 0;
v8::Persistent<String> global;
{
v8::HandleScope scope(isolate);
- Local<String> str = v8_str("str");
- global_handles =
- reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
- initial_handle_count = global_handles->NumberOfGlobalHandles();
- global = v8::Persistent<String>::New(isolate, str);
+ global.Reset(isolate, v8_str("str"));
}
- CHECK_EQ(global->Length(), 3);
- CHECK_EQ(global_handles->NumberOfGlobalHandles(), initial_handle_count + 1);
+ v8::internal::GlobalHandles* global_handles =
+ reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
+ int initial_handle_count = global_handles->NumberOfGlobalHandles();
+ {
+ v8::HandleScope scope(isolate);
+ CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
+ }
{
v8::HandleScope scope(isolate);
Local<String> empty;
global.Reset(isolate, empty);
}
CHECK(global.IsEmpty());
- CHECK_EQ(global_handles->NumberOfGlobalHandles(), initial_handle_count);
+ CHECK_EQ(global_handles->NumberOfGlobalHandles(), initial_handle_count - 1);
}
@@ -2861,7 +2868,7 @@
global_handles =
reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
initial_handle_count = global_handles->NumberOfGlobalHandles();
- global = v8::Persistent<String>::New(isolate, str);
+ global.Reset(isolate, str);
}
CHECK_EQ(global_handles->NumberOfGlobalHandles(), initial_handle_count + 1);
String* str = global.ClearAndLeak();
@@ -2897,7 +2904,7 @@
static void WeakPointerCallback(v8::Isolate* isolate,
- Persistent<Object>* handle,
+ Persistent<Value>* handle,
WeakCallCounter* counter) {
CHECK_EQ(1234, counter->id());
counter->increment();
@@ -2905,128 +2912,47 @@
}
-THREADED_TEST(OldApiObjectGroups) {
- LocalContext env;
- v8::Isolate* iso = env->GetIsolate();
- HandleScope scope(iso);
-
- Persistent<Object> g1s1;
- Persistent<Object> g1s2;
- Persistent<Object> g1c1;
- Persistent<Object> g2s1;
- Persistent<Object> g2s2;
- Persistent<Object> g2c1;
-
- WeakCallCounter counter(1234);
-
- {
- HandleScope scope(iso);
- g1s1 = Persistent<Object>::New(iso, Object::New());
- g1s2 = Persistent<Object>::New(iso, Object::New());
- g1c1 = Persistent<Object>::New(iso, Object::New());
- g1s1.MakeWeak(iso, &counter, &WeakPointerCallback);
- g1s2.MakeWeak(iso, &counter, &WeakPointerCallback);
- g1c1.MakeWeak(iso, &counter, &WeakPointerCallback);
-
- g2s1 = Persistent<Object>::New(iso, Object::New());
- g2s2 = Persistent<Object>::New(iso, Object::New());
- g2c1 = Persistent<Object>::New(iso, Object::New());
- g2s1.MakeWeak(iso, &counter, &WeakPointerCallback);
- g2s2.MakeWeak(iso, &counter, &WeakPointerCallback);
- g2c1.MakeWeak(iso, &counter, &WeakPointerCallback);
- }
-
- Persistent<Object> root = Persistent<Object>::New(iso, g1s1); // make a root.
-
- // Connect group 1 and 2, make a cycle.
- CHECK(g1s2->Set(0, Handle<Object>(*g2s2)));
- CHECK(g2s1->Set(0, Handle<Object>(*g1s1)));
-
- {
- Persistent<Value> g1_objects[] = { g1s1, g1s2 };
- Persistent<Value> g1_children[] = { g1c1 };
- Persistent<Value> g2_objects[] = { g2s1, g2s2 };
- Persistent<Value> g2_children[] = { g2c1 };
- V8::AddObjectGroup(g1_objects, 2);
- V8::AddImplicitReferences(g1s1, g1_children, 1);
- V8::AddObjectGroup(g2_objects, 2);
- V8::AddImplicitReferences(g2s1, g2_children, 1);
- }
- // Do a single full GC, ensure incremental marking is stopped.
- HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
-
- // All object should be alive.
- CHECK_EQ(0, counter.NumberOfWeakCalls());
-
- // Weaken the root.
- root.MakeWeak(iso, &counter, &WeakPointerCallback);
- // But make children strong roots---all the objects (except for children)
- // should be collectable now.
- g1c1.ClearWeak(iso);
- g2c1.ClearWeak(iso);
-
- // Groups are deleted, rebuild groups.
- {
- Persistent<Value> g1_objects[] = { g1s1, g1s2 };
- Persistent<Value> g1_children[] = { g1c1 };
- Persistent<Value> g2_objects[] = { g2s1, g2s2 };
- Persistent<Value> g2_children[] = { g2c1 };
- V8::AddObjectGroup(g1_objects, 2);
- V8::AddImplicitReferences(g1s1, g1_children, 1);
- V8::AddObjectGroup(g2_objects, 2);
- V8::AddImplicitReferences(g2s1, g2_children, 1);
- }
-
- HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
-
- // All objects should be gone. 5 global handles in total.
- CHECK_EQ(5, counter.NumberOfWeakCalls());
-
- // And now make children weak again and collect them.
- g1c1.MakeWeak(iso, &counter, &WeakPointerCallback);
- g2c1.MakeWeak(iso, &counter, &WeakPointerCallback);
-
- HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
- CHECK_EQ(7, counter.NumberOfWeakCalls());
-}
-
-
THREADED_TEST(ApiObjectGroups) {
LocalContext env;
v8::Isolate* iso = env->GetIsolate();
HandleScope scope(iso);
- Persistent<Object> g1s1;
- Persistent<Object> g1s2;
- Persistent<Object> g1c1;
- Persistent<Object> g2s1;
- Persistent<Object> g2s2;
- Persistent<Object> g2c1;
+ Persistent<Value> g1s1;
+ Persistent<Value> g1s2;
+ Persistent<Value> g1c1;
+ Persistent<Value> g2s1;
+ Persistent<Value> g2s2;
+ Persistent<Value> g2c1;
WeakCallCounter counter(1234);
{
HandleScope scope(iso);
- g1s1 = Persistent<Object>::New(iso, Object::New());
- g1s2 = Persistent<Object>::New(iso, Object::New());
- g1c1 = Persistent<Object>::New(iso, Object::New());
+ g1s1.Reset(iso, Object::New());
+ g1s2.Reset(iso, Object::New());
+ g1c1.Reset(iso, Object::New());
g1s1.MakeWeak(iso, &counter, &WeakPointerCallback);
g1s2.MakeWeak(iso, &counter, &WeakPointerCallback);
g1c1.MakeWeak(iso, &counter, &WeakPointerCallback);
- g2s1 = Persistent<Object>::New(iso, Object::New());
- g2s2 = Persistent<Object>::New(iso, Object::New());
- g2c1 = Persistent<Object>::New(iso, Object::New());
+ g2s1.Reset(iso, Object::New());
+ g2s2.Reset(iso, Object::New());
+ g2c1.Reset(iso, Object::New());
g2s1.MakeWeak(iso, &counter, &WeakPointerCallback);
g2s2.MakeWeak(iso, &counter, &WeakPointerCallback);
g2c1.MakeWeak(iso, &counter, &WeakPointerCallback);
}
- Persistent<Object> root = Persistent<Object>::New(iso, g1s1); // make a root.
+ Persistent<Value> root(iso, g1s1); // make a root.
// Connect group 1 and 2, make a cycle.
- CHECK(g1s2->Set(0, Local<Value>(*g2s2)));
- CHECK(g2s1->Set(0, Local<Value>(*g1s1)));
+ {
+ HandleScope scope(iso);
+ CHECK(Local<Object>::New(iso, g1s2.As<Object>())->
+ Set(0, Local<Value>(*g2s2)));
+ CHECK(Local<Object>::New(iso, g2s1.As<Object>())->
+ Set(0, Local<Value>(*g1s1)));
+ }
{
UniqueId id1(reinterpret_cast<intptr_t>(*g1s1));
@@ -3079,112 +3005,6 @@
}
-THREADED_TEST(OldApiObjectGroupsCycle) {
- LocalContext env;
- v8::Isolate* iso = env->GetIsolate();
- HandleScope scope(iso);
-
- WeakCallCounter counter(1234);
-
- Persistent<Object> g1s1;
- Persistent<Object> g1s2;
- Persistent<Object> g2s1;
- Persistent<Object> g2s2;
- Persistent<Object> g3s1;
- Persistent<Object> g3s2;
- Persistent<Object> g4s1;
- Persistent<Object> g4s2;
-
- {
- HandleScope scope(iso);
- g1s1 = Persistent<Object>::New(iso, Object::New());
- g1s2 = Persistent<Object>::New(iso, Object::New());
- g1s1.MakeWeak(iso, &counter, &WeakPointerCallback);
- g1s2.MakeWeak(iso, &counter, &WeakPointerCallback);
- CHECK(g1s1.IsWeak(iso));
- CHECK(g1s2.IsWeak(iso));
-
- g2s1 = Persistent<Object>::New(iso, Object::New());
- g2s2 = Persistent<Object>::New(iso, Object::New());
- g2s1.MakeWeak(iso, &counter, &WeakPointerCallback);
- g2s2.MakeWeak(iso, &counter, &WeakPointerCallback);
- CHECK(g2s1.IsWeak(iso));
- CHECK(g2s2.IsWeak(iso));
-
- g3s1 = Persistent<Object>::New(iso, Object::New());
- g3s2 = Persistent<Object>::New(iso, Object::New());
- g3s1.MakeWeak(iso, &counter, &WeakPointerCallback);
- g3s2.MakeWeak(iso, &counter, &WeakPointerCallback);
- CHECK(g3s1.IsWeak(iso));
- CHECK(g3s2.IsWeak(iso));
-
- g4s1 = Persistent<Object>::New(iso, Object::New());
- g4s2 = Persistent<Object>::New(iso, Object::New());
- g4s1.MakeWeak(iso, &counter, &WeakPointerCallback);
- g4s2.MakeWeak(iso, &counter, &WeakPointerCallback);
- CHECK(g4s1.IsWeak(iso));
- CHECK(g4s2.IsWeak(iso));
- }
-
- Persistent<Object> root = Persistent<Object>::New(iso, g1s1); // make a root.
-
- // Connect groups. We're building the following cycle:
- // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
- // groups.
- {
- Persistent<Value> g1_objects[] = { g1s1, g1s2 };
- Persistent<Value> g1_children[] = { g2s1 };
- Persistent<Value> g2_objects[] = { g2s1, g2s2 };
- Persistent<Value> g2_children[] = { g3s1 };
- Persistent<Value> g3_objects[] = { g3s1, g3s2 };
- Persistent<Value> g3_children[] = { g4s1 };
- Persistent<Value> g4_objects[] = { g4s1, g4s2 };
- Persistent<Value> g4_children[] = { g1s1 };
- V8::AddObjectGroup(g1_objects, 2);
- V8::AddImplicitReferences(g1s1, g1_children, 1);
- V8::AddObjectGroup(g2_objects, 2);
- V8::AddImplicitReferences(g2s1, g2_children, 1);
- V8::AddObjectGroup(g3_objects, 2);
- V8::AddImplicitReferences(g3s1, g3_children, 1);
- V8::AddObjectGroup(iso, g4_objects, 2);
- V8::AddImplicitReferences(g4s1, g4_children, 1);
- }
- // Do a single full GC
- HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
-
- // All object should be alive.
- CHECK_EQ(0, counter.NumberOfWeakCalls());
-
- // Weaken the root.
- root.MakeWeak(iso, &counter, &WeakPointerCallback);
-
- // Groups are deleted, rebuild groups.
- {
- Persistent<Value> g1_objects[] = { g1s1, g1s2 };
- Persistent<Value> g1_children[] = { g2s1 };
- Persistent<Value> g2_objects[] = { g2s1, g2s2 };
- Persistent<Value> g2_children[] = { g3s1 };
- Persistent<Value> g3_objects[] = { g3s1, g3s2 };
- Persistent<Value> g3_children[] = { g4s1 };
- Persistent<Value> g4_objects[] = { g4s1, g4s2 };
- Persistent<Value> g4_children[] = { g1s1 };
- V8::AddObjectGroup(g1_objects, 2);
- V8::AddImplicitReferences(g1s1, g1_children, 1);
- V8::AddObjectGroup(g2_objects, 2);
- V8::AddImplicitReferences(g2s1, g2_children, 1);
- V8::AddObjectGroup(g3_objects, 2);
- V8::AddImplicitReferences(g3s1, g3_children, 1);
- V8::AddObjectGroup(g4_objects, 2);
- V8::AddImplicitReferences(g4s1, g4_children, 1);
- }
-
- HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
-
- // All objects should be gone. 9 global handles in total.
- CHECK_EQ(9, counter.NumberOfWeakCalls());
-}
-
-
THREADED_TEST(ApiObjectGroupsCycle) {
LocalContext env;
v8::Isolate* iso = env->GetIsolate();
@@ -3192,47 +3012,47 @@
WeakCallCounter counter(1234);
- Persistent<Object> g1s1;
- Persistent<Object> g1s2;
- Persistent<Object> g2s1;
- Persistent<Object> g2s2;
- Persistent<Object> g3s1;
- Persistent<Object> g3s2;
- Persistent<Object> g4s1;
- Persistent<Object> g4s2;
+ Persistent<Value> g1s1;
+ Persistent<Value> g1s2;
+ Persistent<Value> g2s1;
+ Persistent<Value> g2s2;
+ Persistent<Value> g3s1;
+ Persistent<Value> g3s2;
+ Persistent<Value> g4s1;
+ Persistent<Value> g4s2;
{
HandleScope scope(iso);
- g1s1 = Persistent<Object>::New(iso, Object::New());
- g1s2 = Persistent<Object>::New(iso, Object::New());
+ g1s1.Reset(iso, Object::New());
+ g1s2.Reset(iso, Object::New());
g1s1.MakeWeak(iso, &counter, &WeakPointerCallback);
g1s2.MakeWeak(iso, &counter, &WeakPointerCallback);
CHECK(g1s1.IsWeak(iso));
CHECK(g1s2.IsWeak(iso));
- g2s1 = Persistent<Object>::New(iso, Object::New());
- g2s2 = Persistent<Object>::New(iso, Object::New());
+ g2s1.Reset(iso, Object::New());
+ g2s2.Reset(iso, Object::New());
g2s1.MakeWeak(iso, &counter, &WeakPointerCallback);
g2s2.MakeWeak(iso, &counter, &WeakPointerCallback);
CHECK(g2s1.IsWeak(iso));
CHECK(g2s2.IsWeak(iso));
- g3s1 = Persistent<Object>::New(iso, Object::New());
- g3s2 = Persistent<Object>::New(iso, Object::New());
+ g3s1.Reset(iso, Object::New());
+ g3s2.Reset(iso, Object::New());
g3s1.MakeWeak(iso, &counter, &WeakPointerCallback);
g3s2.MakeWeak(iso, &counter, &WeakPointerCallback);
CHECK(g3s1.IsWeak(iso));
CHECK(g3s2.IsWeak(iso));
- g4s1 = Persistent<Object>::New(iso, Object::New());
- g4s2 = Persistent<Object>::New(iso, Object::New());
+ g4s1.Reset(iso, Object::New());
+ g4s2.Reset(iso, Object::New());
g4s1.MakeWeak(iso, &counter, &WeakPointerCallback);
g4s2.MakeWeak(iso, &counter, &WeakPointerCallback);
CHECK(g4s1.IsWeak(iso));
CHECK(g4s2.IsWeak(iso));
}
- Persistent<Object> root = Persistent<Object>::New(iso, g1s1); // make a root.
+ Persistent<Value> root(iso, g1s1); // make a root.
// Connect groups. We're building the following cycle:
// G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
@@ -3295,103 +3115,6 @@
// TODO(mstarzinger): This should be a THREADED_TEST but causes failures
// on the buildbots, so was made non-threaded for the time being.
-TEST(OldApiObjectGroupsCycleForScavenger) {
- i::FLAG_stress_compaction = false;
- i::FLAG_gc_global = false;
- LocalContext env;
- v8::Isolate* iso = env->GetIsolate();
- HandleScope scope(iso);
-
- WeakCallCounter counter(1234);
-
- Persistent<Object> g1s1;
- Persistent<Object> g1s2;
- Persistent<Object> g2s1;
- Persistent<Object> g2s2;
- Persistent<Object> g3s1;
- Persistent<Object> g3s2;
-
- {
- HandleScope scope(iso);
- g1s1 = Persistent<Object>::New(iso, Object::New());
- g1s2 = Persistent<Object>::New(iso, Object::New());
- g1s1.MakeWeak(iso, &counter, &WeakPointerCallback);
- g1s2.MakeWeak(iso, &counter, &WeakPointerCallback);
-
- g2s1 = Persistent<Object>::New(iso, Object::New());
- g2s2 = Persistent<Object>::New(iso, Object::New());
- g2s1.MakeWeak(iso, &counter, &WeakPointerCallback);
- g2s2.MakeWeak(iso, &counter, &WeakPointerCallback);
-
- g3s1 = Persistent<Object>::New(iso, Object::New());
- g3s2 = Persistent<Object>::New(iso, Object::New());
- g3s1.MakeWeak(iso, &counter, &WeakPointerCallback);
- g3s2.MakeWeak(iso, &counter, &WeakPointerCallback);
- }
-
- // Make a root.
- Persistent<Object> root = Persistent<Object>::New(iso, g1s1);
- root.MarkPartiallyDependent(iso);
-
- // Connect groups. We're building the following cycle:
- // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
- // groups.
- {
- g1s1.MarkPartiallyDependent(iso);
- g1s2.MarkPartiallyDependent(iso);
- g2s1.MarkPartiallyDependent(iso);
- g2s2.MarkPartiallyDependent(iso);
- g3s1.MarkPartiallyDependent(iso);
- g3s2.MarkPartiallyDependent(iso);
- Persistent<Value> g1_objects[] = { g1s1, g1s2 };
- Persistent<Value> g2_objects[] = { g2s1, g2s2 };
- Persistent<Value> g3_objects[] = { g3s1, g3s2 };
- V8::AddObjectGroup(g1_objects, 2);
- g1s1->Set(v8_str("x"), Handle<Object>(*g2s1));
- V8::AddObjectGroup(g2_objects, 2);
- g2s1->Set(v8_str("x"), Handle<Object>(*g3s1));
- V8::AddObjectGroup(g3_objects, 2);
- g3s1->Set(v8_str("x"), Handle<Object>(*g1s1));
- }
-
- HEAP->CollectGarbage(i::NEW_SPACE);
-
- // All objects should be alive.
- CHECK_EQ(0, counter.NumberOfWeakCalls());
-
- // Weaken the root.
- root.MakeWeak(iso, &counter, &WeakPointerCallback);
- root.MarkPartiallyDependent(iso);
-
- v8::Isolate* isolate = v8::Isolate::GetCurrent();
- // Groups are deleted, rebuild groups.
- {
- g1s1.MarkPartiallyDependent(isolate);
- g1s2.MarkPartiallyDependent(isolate);
- g2s1.MarkPartiallyDependent(isolate);
- g2s2.MarkPartiallyDependent(isolate);
- g3s1.MarkPartiallyDependent(isolate);
- g3s2.MarkPartiallyDependent(isolate);
- Persistent<Value> g1_objects[] = { g1s1, g1s2 };
- Persistent<Value> g2_objects[] = { g2s1, g2s2 };
- Persistent<Value> g3_objects[] = { g3s1, g3s2 };
- V8::AddObjectGroup(g1_objects, 2);
- g1s1->Set(v8_str("x"), Handle<Object>(*g2s1));
- V8::AddObjectGroup(g2_objects, 2);
- g2s1->Set(v8_str("x"), Handle<Object>(*g3s1));
- V8::AddObjectGroup(g3_objects, 2);
- g3s1->Set(v8_str("x"), Handle<Object>(*g1s1));
- }
-
- HEAP->CollectGarbage(i::NEW_SPACE);
-
- // All objects should be gone. 7 global handles in total.
- CHECK_EQ(7, counter.NumberOfWeakCalls());
-}
-
-
-// TODO(mstarzinger): This should be a THREADED_TEST but causes failures
-// on the buildbots, so was made non-threaded for the time being.
TEST(ApiObjectGroupsCycleForScavenger) {
i::FLAG_stress_compaction = false;
i::FLAG_gc_global = false;
@@ -3401,39 +3124,40 @@
WeakCallCounter counter(1234);
- Persistent<Object> g1s1;
- Persistent<Object> g1s2;
- Persistent<Object> g2s1;
- Persistent<Object> g2s2;
- Persistent<Object> g3s1;
- Persistent<Object> g3s2;
+ Persistent<Value> g1s1;
+ Persistent<Value> g1s2;
+ Persistent<Value> g2s1;
+ Persistent<Value> g2s2;
+ Persistent<Value> g3s1;
+ Persistent<Value> g3s2;
{
HandleScope scope(iso);
- g1s1 = Persistent<Object>::New(iso, Object::New());
- g1s2 = Persistent<Object>::New(iso, Object::New());
+ g1s1.Reset(iso, Object::New());
+ g1s2.Reset(iso, Object::New());
g1s1.MakeWeak(iso, &counter, &WeakPointerCallback);
g1s2.MakeWeak(iso, &counter, &WeakPointerCallback);
- g2s1 = Persistent<Object>::New(iso, Object::New());
- g2s2 = Persistent<Object>::New(iso, Object::New());
+ g2s1.Reset(iso, Object::New());
+ g2s2.Reset(iso, Object::New());
g2s1.MakeWeak(iso, &counter, &WeakPointerCallback);
g2s2.MakeWeak(iso, &counter, &WeakPointerCallback);
- g3s1 = Persistent<Object>::New(iso, Object::New());
- g3s2 = Persistent<Object>::New(iso, Object::New());
+ g3s1.Reset(iso, Object::New());
+ g3s2.Reset(iso, Object::New());
g3s1.MakeWeak(iso, &counter, &WeakPointerCallback);
g3s2.MakeWeak(iso, &counter, &WeakPointerCallback);
}
// Make a root.
- Persistent<Object> root = Persistent<Object>::New(iso, g1s1);
+ Persistent<Value> root(iso, g1s1);
root.MarkPartiallyDependent(iso);
// Connect groups. We're building the following cycle:
// G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
// groups.
{
+ HandleScope handle_scope(iso);
g1s1.MarkPartiallyDependent(iso);
g1s2.MarkPartiallyDependent(iso);
g2s1.MarkPartiallyDependent(iso);
@@ -3442,13 +3166,16 @@
g3s2.MarkPartiallyDependent(iso);
iso->SetObjectGroupId(g1s1, UniqueId(1));
iso->SetObjectGroupId(g1s2, UniqueId(1));
- g1s1->Set(v8_str("x"), Local<Value>(*g2s1));
+ Local<Object>::New(iso, g1s1.As<Object>())->Set(v8_str("x"),
+ Local<Value>(*g2s1));
iso->SetObjectGroupId(g2s1, UniqueId(2));
iso->SetObjectGroupId(g2s2, UniqueId(2));
- g2s1->Set(v8_str("x"), Local<Value>(*g3s1));
+ Local<Object>::New(iso, g2s1.As<Object>())->Set(v8_str("x"),
+ Local<Value>(*g3s1));
iso->SetObjectGroupId(g3s1, UniqueId(3));
iso->SetObjectGroupId(g3s2, UniqueId(3));
- g3s1->Set(v8_str("x"), Local<Value>(*g1s1));
+ Local<Object>::New(iso, g3s1.As<Object>())->Set(v8_str("x"),
+ Local<Value>(*g1s1));
}
v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
@@ -3465,6 +3192,7 @@
v8::Isolate* isolate = v8::Isolate::GetCurrent();
// Groups are deleted, rebuild groups.
{
+ HandleScope handle_scope(iso);
g1s1.MarkPartiallyDependent(isolate);
g1s2.MarkPartiallyDependent(isolate);
g2s1.MarkPartiallyDependent(isolate);
@@ -3473,13 +3201,16 @@
g3s2.MarkPartiallyDependent(isolate);
iso->SetObjectGroupId(g1s1, UniqueId(1));
iso->SetObjectGroupId(g1s2, UniqueId(1));
- g1s1->Set(v8_str("x"), Local<Value>(*g2s1));
+ Local<Object>::New(iso, g1s1.As<Object>())->Set(v8_str("x"),
+ Local<Value>(*g2s1));
iso->SetObjectGroupId(g2s1, UniqueId(2));
iso->SetObjectGroupId(g2s2, UniqueId(2));
- g2s1->Set(v8_str("x"), Local<Value>(*g3s1));
+ Local<Object>::New(iso, g2s1.As<Object>())->Set(v8_str("x"),
+ Local<Value>(*g3s1));
iso->SetObjectGroupId(g3s1, UniqueId(3));
iso->SetObjectGroupId(g3s2, UniqueId(3));
- g3s1->Set(v8_str("x"), Local<Value>(*g1s1));
+ Local<Object>::New(iso, g3s1.As<Object>())->Set(v8_str("x"),
+ Local<Value>(*g1s1));
}
heap->CollectGarbage(i::NEW_SPACE);
@@ -4618,8 +4349,7 @@
CHECK(!v8::False()->StrictEquals(v8::Undefined()));
v8::Handle<v8::Object> obj = v8::Object::New();
- v8::Persistent<v8::Object> alias =
- v8::Persistent<v8::Object>::New(isolate, obj);
+ v8::Persistent<v8::Object> alias(isolate, obj);
CHECK(alias->StrictEquals(obj));
alias.Dispose(isolate);
}
@@ -4919,7 +4649,7 @@
CHECK_EQ(info.Data(), v8_str("donut"));
CHECK_EQ(name, v8_str("x"));
CHECK(xValue.IsEmpty());
- xValue = v8::Persistent<Value>::New(info.GetIsolate(), value);
+ xValue.Reset(info.GetIsolate(), value);
}
@@ -4935,7 +4665,7 @@
script->Run();
CHECK_EQ(v8_num(4), Handle<Value>(*xValue));
xValue.Dispose(context->GetIsolate());
- xValue = v8::Persistent<Value>();
+ xValue.Clear();
}
}
@@ -4952,7 +4682,7 @@
script->Run();
CHECK_EQ(v8_num(4), Handle<Value>(*xValue));
xValue.Dispose(context->GetIsolate());
- xValue = v8::Persistent<Value>();
+ xValue.Clear();
}
}
@@ -5815,15 +5545,14 @@
static inline void PersistentHandles(v8::Isolate* isolate) {
USE(PersistentHandles);
Local<String> str = v8_str("foo");
- v8::Persistent<String> p_str = v8::Persistent<String>::New(isolate, str);
- USE(p_str);
+ v8::Persistent<String> p_str(isolate, str);
+ p_str.Dispose();
Local<Script> scr = Script::Compile(v8_str(""));
- v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(isolate, scr);
- USE(p_scr);
+ v8::Persistent<Script> p_scr(isolate, scr);
+ p_scr.Dispose();
Local<ObjectTemplate> templ = ObjectTemplate::New();
- v8::Persistent<ObjectTemplate> p_templ =
- v8::Persistent<ObjectTemplate>::New(isolate, templ);
- USE(p_templ);
+ v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
+ p_templ.Dispose();
}
@@ -6327,10 +6056,7 @@
explicit Whammy(v8::Isolate* isolate) : cursor_(0), isolate_(isolate) { }
~Whammy() { script_.Dispose(isolate_); }
v8::Handle<Script> getScript() {
- if (script_.IsEmpty()) {
- script_ = v8::Persistent<Script>::New(isolate_,
- v8_compile("({}).blammo"));
- }
+ if (script_.IsEmpty()) script_.Reset(isolate_, v8_compile("({}).blammo"));
return Local<Script>(*script_);
}
@@ -6354,11 +6080,9 @@
Whammy* whammy =
static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
- v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
+ v8::Persistent<v8::Object>& prev = whammy->objects_[whammy->cursor_];
v8::Handle<v8::Object> obj = v8::Object::New();
- v8::Persistent<v8::Object> global =
- v8::Persistent<v8::Object>::New(info.GetIsolate(), obj);
if (!prev.IsEmpty()) {
prev->Set(v8_str("next"), obj);
prev.MakeWeak<Value, Snorkel>(info.GetIsolate(),
@@ -6366,7 +6090,7 @@
&HandleWeakReference);
whammy->objects_[whammy->cursor_].Clear();
}
- whammy->objects_[whammy->cursor_] = global;
+ whammy->objects_[whammy->cursor_].Reset(info.GetIsolate(), obj);
whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
return whammy->getScript()->Run();
}
@@ -6419,8 +6143,8 @@
{
v8::HandleScope handle_scope(iso);
- object_a = v8::Persistent<v8::Object>::New(iso, v8::Object::New());
- object_b = v8::Persistent<v8::Object>::New(iso, v8::Object::New());
+ object_a.Reset(iso, v8::Object::New());
+ object_b.Reset(iso, v8::Object::New());
}
bool object_a_disposed = false;
@@ -6484,7 +6208,7 @@
v8::Persistent<v8::Object> object;
{
v8::HandleScope handle_scope(isolate);
- object = v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
+ object.Reset(isolate, v8::Object::New());
}
bool disposed = false;
object.MakeWeak(isolate, &disposed, gc_forcing_callback[inner_gc]);
@@ -6513,7 +6237,7 @@
v8::Persistent<v8::Object> object;
{
v8::HandleScope handle_scope(isolate);
- object = v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
+ object.Reset(isolate, v8::Object::New());
object->Set(v8_str("x"), v8::Integer::New(1));
v8::Local<String> y_str = v8_str("y");
object->Set(y_str, y_str);
@@ -12056,7 +11780,7 @@
v8::HandleScope scope(args.GetIsolate());
v8::Handle<Value> value = CompileRun(code);
CHECK(value.IsEmpty());
- return v8_str("foo");
+ return scope.Close(v8_str("foo"));
}
}
@@ -12224,7 +11948,7 @@
v8::Persistent<v8::Value>* handle,
void*) {
v8::HandleScope scope(isolate);
- bad_handle = v8::Persistent<v8::Object>::New(isolate, some_object);
+ bad_handle.Reset(isolate, some_object);
handle->Dispose(isolate);
}
@@ -12236,9 +11960,9 @@
v8::Persistent<v8::Object> handle1, handle2;
{
v8::HandleScope scope(isolate);
- some_object = v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
- handle1 = v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
- handle2 = v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
+ some_object.Reset(isolate, v8::Object::New());
+ handle1.Reset(isolate, v8::Object::New());
+ handle2.Reset(isolate, v8::Object::New());
}
// Note: order is implementation dependent alas: currently
// global handle nodes are processed by PostGarbageCollectionProcessing
@@ -12270,11 +11994,11 @@
v8::Persistent<v8::Object> handle1, handle2;
{
v8::HandleScope scope(isolate);
- handle1 = v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
- handle2 = v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
+ handle1.Reset(isolate, v8::Object::New());
+ handle2.Reset(isolate, v8::Object::New());
}
handle1.MakeWeak<v8::Value, void>(isolate, NULL, DisposeAndForceGcCallback);
- to_be_disposed = handle2;
+ to_be_disposed.Reset(isolate, handle2);
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
}
@@ -12300,9 +12024,9 @@
v8::Persistent<v8::Object> handle1, handle2, handle3;
{
v8::HandleScope scope(isolate);
- handle3 = v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
- handle2 = v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
- handle1 = v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
+ handle3.Reset(isolate, v8::Object::New());
+ handle2.Reset(isolate, v8::Object::New());
+ handle1.Reset(isolate, v8::Object::New());
}
handle2.MakeWeak<v8::Value, void>(isolate, NULL, DisposingCallback);
handle3.MakeWeak<v8::Value, void>(isolate, NULL, HandleCreatingCallback);
@@ -12761,8 +12485,7 @@
v8::HandleScope inner(isolate);
v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
local->SetInternalFieldCount(1);
- templ =
- v8::Persistent<v8::ObjectTemplate>::New(isolate, inner.Close(local));
+ templ.Reset(isolate, inner.Close(local));
}
v8::Handle<v8::Object> result = templ->NewInstance();
CHECK_EQ(1, result->InternalFieldCount());
@@ -16017,8 +15740,13 @@
"}\n"
"foo();\n"
"}\n"
- "eval('(' + outer +')()//@ sourceURL=eval_url');";
- CHECK(CompileRun(source)->IsUndefined());
+ "eval('(' + outer +')()%s');";
+
+ i::ScopedVector<char> code(1024);
+ i::OS::SNPrintF(code, source, "//# sourceURL=eval_url");
+ CHECK(CompileRun(code.start())->IsUndefined());
+ i::OS::SNPrintF(code, source, "//@ sourceURL=eval_url");
+ CHECK(CompileRun(code.start())->IsUndefined());
}
@@ -16058,9 +15786,13 @@
"}\n"
"foo();\n"
"}\n"
- "outer()\n"
- "//@ sourceURL=source_url";
- CHECK(CompileRunWithOrigin(source, "url", 0, 1)->IsUndefined());
+ "outer()\n%s";
+
+ i::ScopedVector<char> code(1024);
+ i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
+ CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
+ i::OS::SNPrintF(code, source, "//@ sourceURL=source_url");
+ CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
}
@@ -16100,9 +15832,13 @@
"}\n"
"foo();\n"
"}\n"
- "outer()\n"
- "//@ sourceURL=source_url";
- CHECK(CompileRunWithOrigin(source, "url", 0, 0)->IsUndefined());
+ "outer()\n%s";
+
+ i::ScopedVector<char> code(1024);
+ i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
+ CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
+ i::OS::SNPrintF(code, source, "//@ sourceURL=source_url");
+ CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
}
static void CreateGarbageInOldSpace() {
@@ -17782,23 +17518,32 @@
class Visitor42 : public v8::PersistentHandleVisitor {
public:
- explicit Visitor42(v8::Persistent<v8::Object> object)
+ explicit Visitor42(v8::Persistent<v8::Object>* object)
: counter_(0), object_(object) { }
+#ifdef V8_USE_OLD_STYLE_PERSISTENT_HANDLE_VISITORS
virtual void VisitPersistentHandle(Persistent<Value> value,
uint16_t class_id) {
- if (class_id == 42) {
- CHECK(value->IsObject());
- v8::Persistent<v8::Object> visited =
- v8::Persistent<v8::Object>::Cast(value);
- CHECK_EQ(42, visited.WrapperClassId(v8::Isolate::GetCurrent()));
- CHECK_EQ(Handle<Value>(*object_), Handle<Value>(*visited));
- ++counter_;
- }
+ VisitPersistentHandle(&value, class_id);
+ }
+#endif
+
+ virtual void VisitPersistentHandle(Persistent<Value>* value,
+ uint16_t class_id) {
+ if (class_id != 42) return;
+ CHECK_EQ(42, value->WrapperClassId());
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope handle_scope(isolate);
+ v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
+ v8::Handle<v8::Value> object =
+ v8::Local<v8::Object>::New(isolate, *object_);
+ CHECK(handle->IsObject());
+ CHECK_EQ(Handle<Object>::Cast(handle), object);
+ ++counter_;
}
int counter_;
- v8::Persistent<v8::Object> object_;
+ v8::Persistent<v8::Object>* object_;
};
@@ -17806,13 +17551,12 @@
LocalContext context;
v8::Isolate* isolate = context->GetIsolate();
v8::HandleScope scope(isolate);
- v8::Persistent<v8::Object> object =
- v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
+ v8::Persistent<v8::Object> object(isolate, v8::Object::New());
CHECK_EQ(0, object.WrapperClassId(isolate));
object.SetWrapperClassId(isolate, 42);
CHECK_EQ(42, object.WrapperClassId(isolate));
- Visitor42 visitor(object);
+ Visitor42 visitor(&object);
v8::V8::VisitHandlesWithClassIds(&visitor);
CHECK_EQ(1, visitor.counter_);
@@ -17824,8 +17568,7 @@
LocalContext context;
v8::Isolate* isolate = context->GetIsolate();
v8::HandleScope scope(isolate);
- v8::Persistent<v8::Object> object =
- v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
+ v8::Persistent<v8::Object> object(isolate, v8::Object::New());
CHECK_EQ(0, object.WrapperClassId(isolate));
object.SetWrapperClassId(isolate, 65535);
CHECK_EQ(65535, object.WrapperClassId(isolate));
@@ -17837,21 +17580,19 @@
LocalContext context;
v8::Isolate* isolate = context->GetIsolate();
v8::HandleScope scope(isolate);
- v8::Persistent<v8::Object> object1 =
- v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
+ v8::Persistent<v8::Object> object1(isolate, v8::Object::New());
CHECK_EQ(0, object1.WrapperClassId(isolate));
object1.SetWrapperClassId(isolate, 42);
CHECK_EQ(42, object1.WrapperClassId(isolate));
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
- v8::Persistent<v8::Object> object2 =
- v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
+ v8::Persistent<v8::Object> object2(isolate, v8::Object::New());
CHECK_EQ(0, object2.WrapperClassId(isolate));
object2.SetWrapperClassId(isolate, 42);
CHECK_EQ(42, object2.WrapperClassId(isolate));
- Visitor42 visitor(object2);
+ Visitor42 visitor(&object2);
v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
CHECK_EQ(1, visitor.counter_);
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
index 1122fa9..1f1b357 100644
--- a/test/cctest/test-heap.cc
+++ b/test/cctest/test-heap.cc
@@ -3107,3 +3107,19 @@
isolate->handle_scope_implementer()->Iterate(&visitor);
deferred.Detach();
}
+
+
+TEST(IncrementalMarkingStepMakesBigProgressWithLargeObjects) {
+ CcTest::InitializeVM();
+ v8::HandleScope scope(CcTest::isolate());
+ CompileRun("function f(n) {"
+ " var a = new Array(n);"
+ " for (var i = 0; i < n; i += 100) a[i] = i;"
+ "};"
+ "f(10 * 1024 * 1024);");
+ IncrementalMarking* marking = HEAP->incremental_marking();
+ if (marking->IsStopped()) marking->Start();
+ // This big step should be sufficient to mark the whole array.
+ marking->Step(100 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
+ ASSERT(marking->IsComplete());
+}
diff --git a/test/mjsunit/allocation-site-info.js b/test/mjsunit/allocation-site-info.js
index 4560531..d718993 100644
--- a/test/mjsunit/allocation-site-info.js
+++ b/test/mjsunit/allocation-site-info.js
@@ -37,7 +37,7 @@
// support_smi_only_arrays = %HasFastSmiElements(new Array(1,2,3,4,5,6,7,8));
support_smi_only_arrays = true;
-optimize_constructed_arrays = true;
+optimize_constructed_arrays = false;
if (support_smi_only_arrays) {
print("Tests include smi-only arrays.");
diff --git a/test/mjsunit/debug-compile-event.js b/test/mjsunit/debug-compile-event.js
index 94dddfa..89a71dd 100644
--- a/test/mjsunit/debug-compile-event.js
+++ b/test/mjsunit/debug-compile-event.js
@@ -80,7 +80,7 @@
var msg = eval('(' + json + ')');
assertTrue('context' in msg.body.script);
- // Check that we pick script name from //@ sourceURL, iff present
+ // Check that we pick script name from //# sourceURL, iff present
assertEquals(current_source.indexOf('sourceURL') >= 0 ?
'myscript.js' : undefined,
event_data.script().name());
@@ -103,7 +103,7 @@
source_count += 2; // Using eval causes additional compilation event.
compileSource('JSON.parse(\'{"a":1,"b":2}\')');
// Using JSON.parse does not causes additional compilation events.
-compileSource('x=1; //@ sourceURL=myscript.js');
+compileSource('x=1; //# sourceURL=myscript.js');
// Make sure that the debug event listener was invoked.
assertFalse(exception, "exception in listener")
diff --git a/test/mjsunit/debug-set-script-source.js b/test/mjsunit/debug-set-script-source.js
index 34ae848..10ab43c 100644
--- a/test/mjsunit/debug-set-script-source.js
+++ b/test/mjsunit/debug-set-script-source.js
@@ -36,10 +36,10 @@
function listener(event, exec_state, event_data, data) {
if (event == Debug.DebugEvent.BeforeCompile) {
event_data.script().setSource(event_data.script().source() +
- " //@ sourceURL=proper_location_" + (++script_number));
+ " //# sourceURL=proper_location_" + (++script_number));
} else if (event == Debug.DebugEvent.AfterCompile) {
try {
- event_data.script().setSource("a=1 //@ sourceURL=wrong_location");
+ event_data.script().setSource("a=1 //# sourceURL=wrong_location");
} catch(e) {
exception = e;
}
diff --git a/test/mjsunit/debug-setbreakpoint.js b/test/mjsunit/debug-setbreakpoint.js
index 90dfcd1..8531c4e 100644
--- a/test/mjsunit/debug-setbreakpoint.js
+++ b/test/mjsunit/debug-setbreakpoint.js
@@ -146,7 +146,7 @@
};
eval('function h(){}');
-eval('function sourceUrlFunc() { a = 2; }\n//@ sourceURL=sourceUrlScript');
+eval('function sourceUrlFunc() { a = 2; }\n//# sourceURL=sourceUrlScript');
o = {a:function(){},b:function(){}}
diff --git a/test/mjsunit/harmony/object-observe.js b/test/mjsunit/harmony/object-observe.js
index 47b5d8c..4c75e63 100644
--- a/test/mjsunit/harmony/object-observe.js
+++ b/test/mjsunit/harmony/object-observe.js
@@ -1175,11 +1175,13 @@
]);
// Pop
-reset()
-var array = {0: 1, 1: 2, length: 2};
+reset();
+var array = [1, 2];
Object.observe(array, observer.callback);
-Array.prototype.pop.call(array);
-Array.prototype.pop.call(array);
+Array.observe(array, observer2.callback);
+array.pop();
+array.pop();
+array.pop();
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
{ object: array, name: '1', type: 'deleted', oldValue: 2 },
@@ -1187,13 +1189,20 @@
{ object: array, name: '0', type: 'deleted', oldValue: 1 },
{ object: array, name: 'length', type: 'updated', oldValue: 1 },
]);
+Object.deliverChangeRecords(observer2.callback);
+observer2.assertCallbackRecords([
+ { object: array, type: 'splice', index: 1, removed: [2], addedCount: 0 },
+ { object: array, type: 'splice', index: 0, removed: [1], addedCount: 0 }
+]);
// Shift
-reset()
-var array = {0: 1, 1: 2, length: 2};
+reset();
+var array = [1, 2];
Object.observe(array, observer.callback);
-Array.prototype.shift.call(array);
-Array.prototype.shift.call(array);
+Array.observe(array, observer2.callback);
+array.shift();
+array.shift();
+array.shift();
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
{ object: array, name: '0', type: 'updated', oldValue: 1 },
@@ -1202,32 +1211,71 @@
{ object: array, name: '0', type: 'deleted', oldValue: 2 },
{ object: array, name: 'length', type: 'updated', oldValue: 1 },
]);
+Object.deliverChangeRecords(observer2.callback);
+observer2.assertCallbackRecords([
+ { object: array, type: 'splice', index: 0, removed: [1], addedCount: 0 },
+ { object: array, type: 'splice', index: 0, removed: [2], addedCount: 0 }
+]);
// Unshift
-reset()
-var array = {0: 1, 1: 2, length: 2};
+reset();
+var array = [1, 2];
Object.observe(array, observer.callback);
-Array.prototype.unshift.call(array, 3, 4);
+Array.observe(array, observer2.callback);
+array.unshift(3, 4);
+array.unshift(5);
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
{ object: array, name: '3', type: 'new' },
+ { object: array, name: 'length', type: 'updated', oldValue: 2 },
{ object: array, name: '2', type: 'new' },
{ object: array, name: '0', type: 'updated', oldValue: 1 },
{ object: array, name: '1', type: 'updated', oldValue: 2 },
- { object: array, name: 'length', type: 'updated', oldValue: 2 },
+ { object: array, name: '4', type: 'new' },
+ { object: array, name: 'length', type: 'updated', oldValue: 4 },
+ { object: array, name: '3', type: 'updated', oldValue: 2 },
+ { object: array, name: '2', type: 'updated', oldValue: 1 },
+ { object: array, name: '1', type: 'updated', oldValue: 4 },
+ { object: array, name: '0', type: 'updated', oldValue: 3 },
+]);
+Object.deliverChangeRecords(observer2.callback);
+observer2.assertCallbackRecords([
+ { object: array, type: 'splice', index: 0, removed: [], addedCount: 2 },
+ { object: array, type: 'splice', index: 0, removed: [], addedCount: 1 }
]);
// Splice
-reset()
-var array = {0: 1, 1: 2, 2: 3, length: 3};
+reset();
+var array = [1, 2, 3];
Object.observe(array, observer.callback);
-Array.prototype.splice.call(array, 1, 1, 4, 5);
+Array.observe(array, observer2.callback);
+array.splice(1, 0, 4, 5); // 1 4 5 2 3
+array.splice(0, 2); // 5 2 3
+array.splice(1, 2, 6, 7); // 5 6 7
+array.splice(2, 0);
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
+ { object: array, name: '4', type: 'new' },
+ { object: array, name: 'length', type: 'updated', oldValue: 3 },
{ object: array, name: '3', type: 'new' },
{ object: array, name: '1', type: 'updated', oldValue: 2 },
{ object: array, name: '2', type: 'updated', oldValue: 3 },
- { object: array, name: 'length', type: 'updated', oldValue: 3 },
+
+ { object: array, name: '0', type: 'updated', oldValue: 1 },
+ { object: array, name: '1', type: 'updated', oldValue: 4 },
+ { object: array, name: '2', type: 'updated', oldValue: 5 },
+ { object: array, name: '4', type: 'deleted', oldValue: 3 },
+ { object: array, name: '3', type: 'deleted', oldValue: 2 },
+ { object: array, name: 'length', type: 'updated', oldValue: 5 },
+
+ { object: array, name: '1', type: 'updated', oldValue: 2 },
+ { object: array, name: '2', type: 'updated', oldValue: 3 },
+]);
+Object.deliverChangeRecords(observer2.callback);
+observer2.assertCallbackRecords([
+ { object: array, type: 'splice', index: 1, removed: [], addedCount: 2 },
+ { object: array, type: 'splice', index: 0, removed: [1, 4], addedCount: 0 },
+ { object: array, type: 'splice', index: 1, removed: [2, 3], addedCount: 2 },
]);
// Exercise StoreIC_ArrayLength
diff --git a/test/mjsunit/regress/regress-1853.js b/test/mjsunit/regress/regress-1853.js
index f80bade..cfafe82 100644
--- a/test/mjsunit/regress/regress-1853.js
+++ b/test/mjsunit/regress/regress-1853.js
@@ -102,13 +102,13 @@
' assertFalse(test_break_1); \n' +
' assertTrue(test_break_1); \n' +
'} \n' +
- '//@ sourceURL=testScriptOne');
+ '//# sourceURL=testScriptOne');
eval('function test2() { \n' +
' assertFalse(test_break_2); \n' +
' assertTrue(test_break_2); \n' +
'} \n' +
- '//@ sourceURL=testScriptTwo');
+ '//# sourceURL=testScriptTwo');
test1();
test2();
diff --git a/test/mjsunit/regress/regress-convert-hole.js b/test/mjsunit/regress/regress-convert-hole.js
index 1424221..1e9c3f3 100644
--- a/test/mjsunit/regress/regress-convert-hole.js
+++ b/test/mjsunit/regress/regress-convert-hole.js
@@ -27,7 +27,7 @@
// Flags: --allow-natives-syntax
-function f(test, test2, a, i) {
+function f_store(test, test2, a, i) {
var o = [0.5,1,,3];
var d;
if (test) {
@@ -42,11 +42,68 @@
return d;
}
-var a = [0, 0, 0, {}];
-f(true, false, a, 0);
-f(true, true, a, 0);
-f(false, false, a, 1);
-f(false, true, a, 1);
-%OptimizeFunctionOnNextCall(f);
-f(false, false, a, 2);
-assertEquals(undefined, a[2]);
+var a1 = [0, 0, 0, {}];
+f_store(true, false, a1, 0);
+f_store(true, true, a1, 0);
+f_store(false, false, a1, 1);
+f_store(false, true, a1, 1);
+%OptimizeFunctionOnNextCall(f_store);
+f_store(false, false, a1, 2);
+assertEquals(undefined, a1[2]);
+
+function test_arg(expected) {
+ return function(v) {
+ assertEquals(expected, v);
+ }
+}
+
+function f_call(f, test, test2, i) {
+ var o = [0.5,1,,3];
+ var d;
+ if (test) {
+ d = 1.5;
+ } else {
+ d = o[i];
+ }
+ if (test2) {
+ d += 1;
+ }
+ f(d);
+ return d;
+}
+
+f_call(test_arg(1.5), true, false, 0);
+f_call(test_arg(2.5), true, true, 0);
+f_call(test_arg(1), false, false, 1);
+f_call(test_arg(2), false, true, 1);
+%OptimizeFunctionOnNextCall(f_call);
+f_call(test_arg(undefined), false, false, 2);
+
+
+function f_external(test, test2, test3, a, i) {
+ var o = [0.5,1,,3];
+ var d;
+ if (test) {
+ d = 1.5;
+ } else {
+ d = o[i];
+ }
+ if (test2) {
+ d += 1;
+ }
+ if (test3) {
+ d = d|0;
+ }
+ a[d] = 1;
+ assertEquals(1, a[d]);
+ return d;
+}
+
+var a2 = new Int32Array(10);
+f_external(true, false, true, a2, 0);
+f_external(true, true, true, a2, 0);
+f_external(false, false, true, a2, 1);
+f_external(false, true, true, a2, 1);
+%OptimizeFunctionOnNextCall(f_external);
+f_external(false, false, false, a2, 2);
+assertEquals(1, a2[undefined]);
diff --git a/test/mjsunit/stack-traces.js b/test/mjsunit/stack-traces.js
index b5d58fa..4a37ee6 100644
--- a/test/mjsunit/stack-traces.js
+++ b/test/mjsunit/stack-traces.js
@@ -64,13 +64,13 @@
}
function testEvalWithSourceURL() {
- eval("function Doo() { FAIL; }; Doo();\n//@ sourceURL=res://name");
+ eval("function Doo() { FAIL; }; Doo();\n//# sourceURL=res://name");
}
function testNestedEvalWithSourceURL() {
var x = "FAIL";
var innerEval = 'function Inner() { eval(x); }\n//@ sourceURL=res://inner-eval';
- eval("function Outer() { eval(innerEval); Inner(); }; Outer();\n//@ sourceURL=res://outer-eval");
+ eval("function Outer() { eval(innerEval); Inner(); }; Outer();\n//# sourceURL=res://outer-eval");
}
function testValue() {