Version 3.16.10
Avoid excessive memory usage during redundant phi elimination. (issue 2510)
Fixed additional spec violations wrt RegExp.lastIndex. (issue 2437)
Added Isolate parameter to Persistent class. (issue 2487)
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@13508 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index c4450e8..418c75e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2013-01-25: Version 3.16.10
+
+ Avoid excessive memory usage during redundant phi elimination.
+ (issue 2510)
+
+ Fixed additional spec violations wrt RegExp.lastIndex.
+ (issue 2437)
+
+ Added Isolate parameter to Persistent class.
+ (issue 2487)
+
+ Performance and stability improvements on all platforms.
+
+
2013-01-24: Version 3.16.9
Made embedded maps in optimized code weak.
diff --git a/include/v8.h b/include/v8.h
index 5f3e2ed..bf3beff 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -157,6 +157,10 @@
typedef void (*WeakReferenceCallback)(Persistent<Value> object,
void* parameter);
+// TODO(svenpanne) Temporary definition until Chrome is in sync.
+typedef void (*NearDeathCallback)(Isolate* isolate,
+ Persistent<Value> object,
+ void* parameter);
// --- Handles ---
@@ -389,11 +393,16 @@
return Persistent<S>::Cast(*this);
}
+ /** Deprecated. Use Isolate version instead. */
+ V8_DEPRECATED(static Persistent<T> New(Handle<T> that));
+
/**
- * Creates a new persistent handle for an existing local or
- * persistent handle.
+ * Creates a new persistent handle for an existing local or persistent handle.
*/
- V8_INLINE(static Persistent<T> New(Handle<T> that));
+ V8_INLINE(static Persistent<T> New(Isolate* isolate, Handle<T> that));
+
+ /** Deprecated. Use Isolate version instead. */
+ V8_DEPRECATED(void Dispose());
/**
* Releases the storage cell referenced by this persistent handle.
@@ -401,66 +410,87 @@
* This handle's reference, and any other references to the storage
* cell remain and IsEmpty will still return false.
*/
- V8_INLINE(void Dispose());
V8_INLINE(void Dispose(Isolate* isolate));
+ /** Deprecated. Use Isolate version instead. */
+ V8_DEPRECATED(void MakeWeak(void* parameters,
+ WeakReferenceCallback callback));
+
/**
* Make the reference to this object weak. When only weak handles
* refer to the object, the garbage collector will perform a
- * callback to the given V8::WeakReferenceCallback function, passing
+ * callback to the given V8::NearDeathCallback function, passing
* it the object reference and the given parameters.
*/
- V8_INLINE(void MakeWeak(void* parameters, WeakReferenceCallback callback));
V8_INLINE(void MakeWeak(Isolate* isolate,
void* parameters,
- WeakReferenceCallback callback));
+ NearDeathCallback callback));
+
+ /** Deprecated. Use Isolate version instead. */
+ V8_DEPRECATED(void ClearWeak());
/** Clears the weak reference to this object. */
- V8_INLINE(void ClearWeak());
+ V8_INLINE(void ClearWeak(Isolate* isolate));
+
+ /** Deprecated. Use Isolate version instead. */
+ V8_DEPRECATED(void MarkIndependent());
/**
- * Marks the reference to this object independent. Garbage collector
- * is free to ignore any object groups containing this object.
- * Weak callback for an independent handle should not
- * assume that it will be preceded by a global GC prologue callback
- * or followed by a global GC epilogue callback.
+ * Marks the reference to this object independent. Garbage collector is free
+ * to ignore any object groups containing this object. Weak callback for an
+ * independent handle should not assume that it will be preceded by a global
+ * GC prologue callback or followed by a global GC epilogue callback.
*/
- V8_INLINE(void MarkIndependent());
V8_INLINE(void MarkIndependent(Isolate* isolate));
+ /** Deprecated. Use Isolate version instead. */
+ V8_DEPRECATED(void MarkPartiallyDependent());
+
/**
- * Marks the reference to this object partially dependent. Partially
- * dependent handles only depend on other partially dependent handles and
- * these dependencies are provided through object groups. It provides a way
- * to build smaller object groups for young objects that represent only a
- * subset of all external dependencies. This mark is automatically cleared
- * after each garbage collection.
+ * Marks the reference to this object partially dependent. Partially dependent
+ * handles only depend on other partially dependent handles and these
+ * dependencies are provided through object groups. It provides a way to build
+ * smaller object groups for young objects that represent only a subset of all
+ * external dependencies. This mark is automatically cleared after each
+ * garbage collection.
*/
- V8_INLINE(void MarkPartiallyDependent());
V8_INLINE(void MarkPartiallyDependent(Isolate* isolate));
+ /** Deprecated. Use Isolate version instead. */
+ V8_DEPRECATED(bool IsIndependent() const);
+
/** Returns true if this handle was previously marked as independent. */
- V8_INLINE(bool IsIndependent() const);
V8_INLINE(bool IsIndependent(Isolate* isolate) const);
+ /** Deprecated. Use Isolate version instead. */
+ V8_DEPRECATED(bool IsNearDeath() const);
+
/** Checks if the handle holds the only reference to an object. */
- V8_INLINE(bool IsNearDeath() const);
+ V8_INLINE(bool IsNearDeath(Isolate* isolate) const);
+
+ /** Deprecated. Use Isolate version instead. */
+ V8_DEPRECATED(bool IsWeak() const);
/** Returns true if the handle's reference is weak. */
- V8_INLINE(bool IsWeak() const);
V8_INLINE(bool IsWeak(Isolate* isolate) const);
- /**
- * Assigns a wrapper class ID to the handle. See RetainedObjectInfo
- * interface description in v8-profiler.h for details.
- */
- V8_INLINE(void SetWrapperClassId(uint16_t class_id));
+ /** Deprecated. Use Isolate version instead. */
+ V8_DEPRECATED(void SetWrapperClassId(uint16_t class_id));
/**
- * Returns the class ID previously assigned to this handle or 0 if no class
- * ID was previously assigned.
+ * Assigns a wrapper class ID to the handle. See RetainedObjectInfo interface
+ * description in v8-profiler.h for details.
*/
- V8_INLINE(uint16_t WrapperClassId() const);
+ V8_INLINE(void SetWrapperClassId(Isolate* isolate, uint16_t class_id));
+
+ /** Deprecated. Use Isolate version instead. */
+ V8_DEPRECATED(uint16_t WrapperClassId() const);
+
+ /**
+ * Returns the class ID previously assigned to this handle or 0 if no class ID
+ * was previously assigned.
+ */
+ V8_INLINE(uint16_t WrapperClassId(Isolate* isolate) const);
private:
friend class ImplementationUtilities;
@@ -3529,31 +3559,17 @@
private:
V8();
- static internal::Object** GlobalizeReference(internal::Object** handle);
- static void DisposeGlobal(internal::Object** global_handle);
+ static internal::Object** GlobalizeReference(internal::Isolate* isolate,
+ internal::Object** handle);
static void DisposeGlobal(internal::Isolate* isolate,
internal::Object** global_handle);
- static void MakeWeak(internal::Object** global_handle,
- void* data,
- WeakReferenceCallback);
static void MakeWeak(internal::Isolate* isolate,
internal::Object** global_handle,
void* data,
- WeakReferenceCallback);
- static void ClearWeak(internal::Object** global_handle);
- static void MarkIndependent(internal::Object** global_handle);
- static void MarkIndependent(internal::Isolate* isolate,
- internal::Object** global_handle);
- static void MarkPartiallyDependent(internal::Object** global_handle);
- static void MarkPartiallyDependent(internal::Isolate* isolate,
- internal::Object** global_handle);
- static bool IsGlobalIndependent(internal::Object** global_handle);
- static bool IsGlobalIndependent(internal::Isolate* isolate,
- internal::Object** global_handle);
- static bool IsGlobalNearDeath(internal::Object** global_handle);
- static bool IsGlobalWeak(internal::Object** global_handle);
- static bool IsGlobalWeak(internal::Isolate* isolate,
- internal::Object** global_handle);
+ WeakReferenceCallback weak_reference_callback,
+ NearDeathCallback near_death_callback);
+ static void ClearWeak(internal::Isolate* isolate,
+ internal::Object** global_handle);
template <class T> friend class Handle;
template <class T> friend class Local;
@@ -3974,9 +3990,7 @@
*/
V8_INLINE(explicit Unlocker(Isolate* isolate)) { Initialize(isolate); }
- /**
- * Deprecated. Use Isolate version instead.
- */
+ /** Deprecated. Use Isolate version instead. */
V8_DEPRECATED(Unlocker());
~Unlocker();
@@ -3994,9 +4008,7 @@
*/
V8_INLINE(explicit Locker(Isolate* isolate)) { Initialize(isolate); }
- /**
- * Deprecated. Use Isolate version instead.
- */
+ /** Deprecated. Use Isolate version instead. */
V8_DEPRECATED(Locker());
~Locker();
@@ -4175,14 +4187,17 @@
static const int kIsolateStateOffset = 0;
static const int kIsolateEmbedderDataOffset = 1 * kApiPointerSize;
static const int kIsolateRootsOffset = 3 * kApiPointerSize;
- static const int kNodeClassIdOffset = 1 * kApiPointerSize;
- static const int kNodeFlagsOffset = 1 * kApiPointerSize + 3;
static const int kUndefinedValueRootIndex = 5;
static const int kNullValueRootIndex = 7;
static const int kTrueValueRootIndex = 8;
static const int kFalseValueRootIndex = 9;
static const int kEmptySymbolRootIndex = 119;
+ static const int kNodeClassIdOffset = 1 * kApiPointerSize;
+ static const int kNodeFlagsOffset = 1 * kApiPointerSize + 3;
+ static const int kNodeStateMask = 0xf;
+ static const int kNodeStateIsWeakValue = 2;
+ static const int kNodeStateIsNearDeathValue = 4;
static const int kNodeIsIndependentShift = 4;
static const int kNodeIsPartiallyDependentShift = 5;
@@ -4236,6 +4251,17 @@
*addr = (*addr & ~mask) | (value << shift);
}
+ V8_INLINE(static uint8_t GetNodeState(internal::Object** obj)) {
+ uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
+ return *addr & kNodeStateMask;
+ }
+
+ V8_INLINE(static void UpdateNodeState(internal::Object** obj,
+ uint8_t value)) {
+ uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
+ *addr = (*addr & ~kNodeStateMask) | value;
+ }
+
V8_INLINE(static void SetEmbedderData(v8::Isolate* isolate, void* data)) {
uint8_t* addr = reinterpret_cast<uint8_t*>(isolate) +
kIsolateEmbedderDataOffset;
@@ -4303,7 +4329,7 @@
template <class T>
- Local<T> Local<T>::New(Isolate* isolate, Handle<T> that) {
+Local<T> Local<T>::New(Isolate* isolate, Handle<T> that) {
if (that.IsEmpty()) return Local<T>();
T* that_ptr = *that;
internal::Object** p = reinterpret_cast<internal::Object**>(that_ptr);
@@ -4314,16 +4340,23 @@
template <class T>
Persistent<T> Persistent<T>::New(Handle<T> that) {
+ return New(Isolate::GetCurrent(), that);
+}
+
+
+template <class T>
+Persistent<T> Persistent<T>::New(Isolate* isolate, Handle<T> that) {
if (that.IsEmpty()) return Persistent<T>();
internal::Object** p = reinterpret_cast<internal::Object**>(*that);
- return Persistent<T>(reinterpret_cast<T*>(V8::GlobalizeReference(p)));
+ return Persistent<T>(reinterpret_cast<T*>(
+ V8::GlobalizeReference(reinterpret_cast<internal::Isolate*>(isolate),
+ p)));
}
template <class T>
bool Persistent<T>::IsIndependent() const {
- if (this->IsEmpty()) return false;
- return V8::IsGlobalIndependent(reinterpret_cast<internal::Object**>(**this));
+ return IsIndependent(Isolate::GetCurrent());
}
@@ -4339,30 +4372,39 @@
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;
- return V8::IsGlobalNearDeath(reinterpret_cast<internal::Object**>(**this));
+ if (!I::IsInitialized(isolate)) return false;
+ return I::GetNodeState(reinterpret_cast<internal::Object**>(**this)) ==
+ I::kNodeStateIsNearDeathValue;
}
template <class T>
bool Persistent<T>::IsWeak() const {
- if (this->IsEmpty()) return false;
- return V8::IsGlobalWeak(reinterpret_cast<internal::Object**>(**this));
+ return IsWeak(Isolate::GetCurrent());
}
template <class T>
bool Persistent<T>::IsWeak(Isolate* isolate) const {
+ typedef internal::Internals I;
if (this->IsEmpty()) return false;
- return V8::IsGlobalWeak(reinterpret_cast<internal::Isolate*>(isolate),
- reinterpret_cast<internal::Object**>(**this));
+ if (!I::IsInitialized(isolate)) return false;
+ return I::GetNodeState(reinterpret_cast<internal::Object**>(**this)) ==
+ I::kNodeStateIsWeakValue;
}
template <class T>
void Persistent<T>::Dispose() {
- if (this->IsEmpty()) return;
- V8::DisposeGlobal(reinterpret_cast<internal::Object**>(**this));
+ Dispose(Isolate::GetCurrent());
}
@@ -4379,28 +4421,39 @@
template <class T>
void Persistent<T>::MakeWeak(void* parameters, WeakReferenceCallback callback) {
- V8::MakeWeak(reinterpret_cast<internal::Object**>(**this),
- parameters,
- callback);
-}
-
-template <class T>
-void Persistent<T>::MakeWeak(Isolate* isolate, void* parameters,
- WeakReferenceCallback callback) {
+ Isolate* isolate = Isolate::GetCurrent();
V8::MakeWeak(reinterpret_cast<internal::Isolate*>(isolate),
reinterpret_cast<internal::Object**>(**this),
parameters,
+ callback,
+ NULL);
+}
+
+template <class T>
+void Persistent<T>::MakeWeak(Isolate* isolate,
+ void* parameters,
+ NearDeathCallback callback) {
+ V8::MakeWeak(reinterpret_cast<internal::Isolate*>(isolate),
+ reinterpret_cast<internal::Object**>(**this),
+ parameters,
+ NULL,
callback);
}
template <class T>
void Persistent<T>::ClearWeak() {
- V8::ClearWeak(reinterpret_cast<internal::Object**>(**this));
+ ClearWeak(Isolate::GetCurrent());
+}
+
+template <class T>
+void Persistent<T>::ClearWeak(Isolate* isolate) {
+ V8::ClearWeak(reinterpret_cast<internal::Isolate*>(isolate),
+ reinterpret_cast<internal::Object**>(**this));
}
template <class T>
void Persistent<T>::MarkIndependent() {
- V8::MarkIndependent(reinterpret_cast<internal::Object**>(**this));
+ MarkIndependent(Isolate::GetCurrent());
}
template <class T>
@@ -4409,12 +4462,13 @@
if (this->IsEmpty()) return;
if (!I::IsInitialized(isolate)) return;
I::UpdateNodeFlag(reinterpret_cast<internal::Object**>(**this),
- true, I::kNodeIsIndependentShift);
+ true,
+ I::kNodeIsIndependentShift);
}
template <class T>
void Persistent<T>::MarkPartiallyDependent() {
- V8::MarkPartiallyDependent(reinterpret_cast<internal::Object**>(**this));
+ MarkPartiallyDependent(Isolate::GetCurrent());
}
template <class T>
@@ -4423,12 +4477,20 @@
if (this->IsEmpty()) return;
if (!I::IsInitialized(isolate)) return;
I::UpdateNodeFlag(reinterpret_cast<internal::Object**>(**this),
- true, I::kNodeIsPartiallyDependentShift);
+ 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>::SetWrapperClassId(Isolate* isolate, 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);
uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + I::kNodeClassIdOffset;
*reinterpret_cast<uint16_t*>(addr) = class_id;
@@ -4436,7 +4498,14 @@
template <class T>
uint16_t Persistent<T>::WrapperClassId() const {
+ return WrapperClassId(Isolate::GetCurrent());
+}
+
+template <class T>
+uint16_t Persistent<T>::WrapperClassId(Isolate* isolate) const {
typedef internal::Internals I;
+ if (this->IsEmpty()) return 0;
+ if (!I::IsInitialized(isolate)) return 0;
internal::Object** obj = reinterpret_cast<internal::Object**>(**this);
uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + I::kNodeClassIdOffset;
return *reinterpret_cast<uint16_t*>(addr);
diff --git a/samples/lineprocessor.cc b/samples/lineprocessor.cc
index 4fc28b7..6549f4c 100644
--- a/samples/lineprocessor.cc
+++ b/samples/lineprocessor.cc
@@ -212,9 +212,10 @@
v8::Context::Scope context_scope(context);
#ifdef ENABLE_DEBUGGER_SUPPORT
- debug_message_context = v8::Persistent<v8::Context>::New(context);
+ debug_message_context =
+ v8::Persistent<v8::Context>::New(context->GetIsolate(), context);
- v8::Locker locker(v8::Isolate::GetCurrent());
+ v8::Locker locker(context->GetIsolate());
if (support_callback) {
v8::Debug::SetDebugMessageDispatchHandler(DispatchDebugMessages, true);
diff --git a/samples/process.cc b/samples/process.cc
index ae6a550..c3d1773 100644
--- a/samples/process.cc
+++ b/samples/process.cc
@@ -116,11 +116,13 @@
// Utility methods for wrapping C++ objects as JavaScript objects,
// and going back again.
- static Handle<Object> WrapMap(map<string, string>* obj);
+ Handle<Object> WrapMap(map<string, string>* obj);
static map<string, string>* UnwrapMap(Handle<Object> obj);
- static Handle<Object> WrapRequest(HttpRequest* obj);
+ Handle<Object> WrapRequest(HttpRequest* obj);
static HttpRequest* UnwrapRequest(Handle<Object> obj);
+ Isolate* GetIsolate() { return context_->GetIsolate(); }
+
Handle<String> script_;
Persistent<Context> context_;
Persistent<Function> process_;
@@ -187,7 +189,7 @@
// Store the function in a Persistent handle, since we also want
// that to remain after this call returns
- process_ = Persistent<Function>::New(process_fun);
+ process_ = Persistent<Function>::New(GetIsolate(), process_fun);
// All done; all went well
return true;
@@ -273,8 +275,9 @@
// Dispose the persistent handles. When noone else has any
// references to the objects stored in the handles they will be
// automatically reclaimed.
- context_.Dispose();
- process_.Dispose();
+ v8::Isolate* isolate = GetIsolate();
+ context_.Dispose(isolate);
+ process_.Dispose(isolate);
}
@@ -296,7 +299,7 @@
// It only has to be created once, which we do on demand.
if (map_template_.IsEmpty()) {
Handle<ObjectTemplate> raw_template = MakeMapTemplate();
- map_template_ = Persistent<ObjectTemplate>::New(raw_template);
+ map_template_ = Persistent<ObjectTemplate>::New(GetIsolate(), raw_template);
}
Handle<ObjectTemplate> templ = map_template_;
@@ -401,7 +404,8 @@
// It only has to be created once, which we do on demand.
if (request_template_.IsEmpty()) {
Handle<ObjectTemplate> raw_template = MakeRequestTemplate();
- request_template_ = Persistent<ObjectTemplate>::New(raw_template);
+ request_template_ =
+ Persistent<ObjectTemplate>::New(GetIsolate(), raw_template);
}
Handle<ObjectTemplate> templ = request_template_;
diff --git a/samples/shell.cc b/samples/shell.cc
index 62f4045..e9057f9 100644
--- a/samples/shell.cc
+++ b/samples/shell.cc
@@ -79,7 +79,7 @@
result = RunMain(argc, argv);
if (run_shell) RunShell(context);
context->Exit();
- context.Dispose();
+ context.Dispose(context->GetIsolate());
}
v8::V8::Dispose();
return result;
diff --git a/src/api.cc b/src/api.cc
index 1561f24..d3d472d 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -626,95 +626,34 @@
}
-i::Object** V8::GlobalizeReference(i::Object** obj) {
- i::Isolate* isolate = i::Isolate::Current();
+i::Object** V8::GlobalizeReference(i::Isolate* isolate, i::Object** obj) {
if (IsDeadCheck(isolate, "V8::Persistent::New")) return NULL;
LOG_API(isolate, "Persistent::New");
- i::Handle<i::Object> result =
- isolate->global_handles()->Create(*obj);
+ i::Handle<i::Object> result = isolate->global_handles()->Create(*obj);
return result.location();
}
-void V8::MakeWeak(i::Object** object, void* parameters,
- WeakReferenceCallback callback) {
- i::Isolate* isolate = i::Isolate::Current();
- LOG_API(isolate, "MakeWeak");
- isolate->global_handles()->MakeWeak(object, parameters,
- callback);
-}
-
-
-void V8::MakeWeak(i::Isolate* isolate, i::Object** object,
- void* parameters, WeakReferenceCallback callback) {
+void V8::MakeWeak(i::Isolate* isolate,
+ i::Object** object,
+ void* parameters,
+ WeakReferenceCallback weak_reference_callback,
+ NearDeathCallback near_death_callback) {
ASSERT(isolate == i::Isolate::Current());
LOG_API(isolate, "MakeWeak");
- isolate->global_handles()->MakeWeak(object, parameters,
- callback);
+ isolate->global_handles()->MakeWeak(object,
+ parameters,
+ weak_reference_callback,
+ near_death_callback);
}
-void V8::ClearWeak(i::Object** obj) {
- i::Isolate* isolate = i::Isolate::Current();
+void V8::ClearWeak(i::Isolate* isolate, i::Object** obj) {
LOG_API(isolate, "ClearWeak");
isolate->global_handles()->ClearWeakness(obj);
}
-void V8::MarkIndependent(i::Object** object) {
- i::Isolate* isolate = i::Isolate::Current();
- LOG_API(isolate, "MarkIndependent");
- isolate->global_handles()->MarkIndependent(object);
-}
-
-
-void V8::MarkPartiallyDependent(i::Object** object) {
- i::Isolate* isolate = i::Isolate::Current();
- LOG_API(isolate, "MarkPartiallyDependent");
- isolate->global_handles()->MarkPartiallyDependent(object);
-}
-
-
-bool V8::IsGlobalIndependent(i::Object** obj) {
- i::Isolate* isolate = i::Isolate::Current();
- LOG_API(isolate, "IsGlobalIndependent");
- if (!isolate->IsInitialized()) return false;
- return i::GlobalHandles::IsIndependent(obj);
-}
-
-
-bool V8::IsGlobalNearDeath(i::Object** obj) {
- i::Isolate* isolate = i::Isolate::Current();
- LOG_API(isolate, "IsGlobalNearDeath");
- if (!isolate->IsInitialized()) return false;
- return i::GlobalHandles::IsNearDeath(obj);
-}
-
-
-bool V8::IsGlobalWeak(i::Object** obj) {
- i::Isolate* isolate = i::Isolate::Current();
- LOG_API(isolate, "IsGlobalWeak");
- if (!isolate->IsInitialized()) return false;
- return i::GlobalHandles::IsWeak(obj);
-}
-
-
-bool V8::IsGlobalWeak(i::Isolate* isolate, i::Object** obj) {
- ASSERT(isolate == i::Isolate::Current());
- LOG_API(isolate, "IsGlobalWeak");
- if (!isolate->IsInitialized()) return false;
- return i::GlobalHandles::IsWeak(obj);
-}
-
-
-void V8::DisposeGlobal(i::Object** obj) {
- i::Isolate* isolate = i::Isolate::Current();
- LOG_API(isolate, "DisposeGlobal");
- if (!isolate->IsInitialized()) return;
- isolate->global_handles()->Destroy(obj);
-}
-
-
void V8::DisposeGlobal(i::Isolate* isolate, i::Object** obj) {
ASSERT(isolate == i::Isolate::Current());
LOG_API(isolate, "DisposeGlobal");
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index 780eca3..8889e75 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -4601,6 +4601,76 @@
}
+void StoreArrayLengthStub::Generate(MacroAssembler* masm) {
+ // This accepts as a receiver anything JSArray::SetElementsLength accepts
+ // (currently anything except for external arrays which means anything with
+ // elements of FixedArray type). Value must be a number, but only smis are
+ // accepted as the most common case.
+ Label miss;
+
+ Register receiver;
+ Register value;
+ if (kind() == Code::KEYED_STORE_IC) {
+ // ----------- S t a t e -------------
+ // -- lr : return address
+ // -- r0 : value
+ // -- r1 : key
+ // -- r2 : receiver
+ // -----------------------------------
+ __ cmp(r1, Operand(masm->isolate()->factory()->length_symbol()));
+ __ b(ne, &miss);
+ receiver = r2;
+ value = r0;
+ } else {
+ ASSERT(kind() == Code::STORE_IC);
+ // ----------- S t a t e -------------
+ // -- lr : return address
+ // -- r0 : value
+ // -- r1 : receiver
+ // -- r2 : key
+ // -----------------------------------
+ receiver = r1;
+ value = r0;
+ }
+ Register scratch = r3;
+
+ // Check that the receiver isn't a smi.
+ __ JumpIfSmi(receiver, &miss);
+
+ // Check that the object is a JS array.
+ __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
+ __ b(ne, &miss);
+
+ // Check that elements are FixedArray.
+ // We rely on StoreIC_ArrayLength below to deal with all types of
+ // fast elements (including COW).
+ __ ldr(scratch, FieldMemOperand(receiver, JSArray::kElementsOffset));
+ __ CompareObjectType(scratch, scratch, scratch, FIXED_ARRAY_TYPE);
+ __ b(ne, &miss);
+
+ // Check that the array has fast properties, otherwise the length
+ // property might have been redefined.
+ __ ldr(scratch, FieldMemOperand(receiver, JSArray::kPropertiesOffset));
+ __ ldr(scratch, FieldMemOperand(scratch, FixedArray::kMapOffset));
+ __ CompareRoot(scratch, Heap::kHashTableMapRootIndex);
+ __ b(eq, &miss);
+
+ // Check that value is a smi.
+ __ JumpIfNotSmi(value, &miss);
+
+ // Prepare tail call to StoreIC_ArrayLength.
+ __ Push(receiver, value);
+
+ ExternalReference ref =
+ ExternalReference(IC_Utility(IC::kStoreIC_ArrayLength), masm->isolate());
+ __ TailCallExternalReference(ref, 2, 1);
+
+ __ bind(&miss);
+
+ StubCompiler::GenerateStoreMiss(masm, kind());
+}
+
+
Register InstanceofStub::left() { return r0; }
diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc
index 1867baf..4a5d920 100644
--- a/src/arm/ic-arm.cc
+++ b/src/arm/ic-arm.cc
@@ -1538,62 +1538,6 @@
}
-void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- r0 : value
- // -- r1 : receiver
- // -- r2 : name
- // -- lr : return address
- // -----------------------------------
- //
- // This accepts as a receiver anything JSArray::SetElementsLength accepts
- // (currently anything except for external arrays which means anything with
- // elements of FixedArray type). Value must be a number, but only smis are
- // accepted as the most common case.
-
- Label miss;
-
- Register receiver = r1;
- Register value = r0;
- Register scratch = r3;
-
- // Check that the receiver isn't a smi.
- __ JumpIfSmi(receiver, &miss);
-
- // Check that the object is a JS array.
- __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
- __ b(ne, &miss);
-
- // Check that elements are FixedArray.
- // We rely on StoreIC_ArrayLength below to deal with all types of
- // fast elements (including COW).
- __ ldr(scratch, FieldMemOperand(receiver, JSArray::kElementsOffset));
- __ CompareObjectType(scratch, scratch, scratch, FIXED_ARRAY_TYPE);
- __ b(ne, &miss);
-
- // Check that the array has fast properties, otherwise the length
- // property might have been redefined.
- __ ldr(scratch, FieldMemOperand(receiver, JSArray::kPropertiesOffset));
- __ ldr(scratch, FieldMemOperand(scratch, FixedArray::kMapOffset));
- __ CompareRoot(scratch, Heap::kHashTableMapRootIndex);
- __ b(eq, &miss);
-
- // Check that value is a smi.
- __ JumpIfNotSmi(value, &miss);
-
- // Prepare tail call to StoreIC_ArrayLength.
- __ Push(receiver, value);
-
- ExternalReference ref =
- ExternalReference(IC_Utility(kStoreIC_ArrayLength), masm->isolate());
- __ TailCallExternalReference(ref, 2, 1);
-
- __ bind(&miss);
-
- GenerateMiss(masm);
-}
-
-
void StoreIC::GenerateNormal(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r0 : value
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index 30c02da..f513c8a 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -592,6 +592,15 @@
}
+void StubCompiler::GenerateStoreMiss(MacroAssembler* masm, Code::Kind kind) {
+ ASSERT(kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC);
+ Handle<Code> code = (kind == Code::STORE_IC)
+ ? masm->isolate()->builtins()->StoreIC_Miss()
+ : masm->isolate()->builtins()->KeyedStoreIC_Miss();
+ __ Jump(code, RelocInfo::CODE_TARGET);
+}
+
+
static void GenerateCallFunction(MacroAssembler* masm,
Handle<Object> object,
const ParameterCount& arguments,
diff --git a/src/builtins.cc b/src/builtins.cc
index 72477c0..16e672c 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -1560,16 +1560,6 @@
}
-static void Generate_StoreIC_ArrayLength(MacroAssembler* masm) {
- StoreIC::GenerateArrayLength(masm);
-}
-
-
-static void Generate_StoreIC_ArrayLength_Strict(MacroAssembler* masm) {
- StoreIC::GenerateArrayLength(masm);
-}
-
-
static void Generate_StoreIC_GlobalProxy(MacroAssembler* masm) {
StoreIC::GenerateGlobalProxy(masm, kNonStrictMode);
}
diff --git a/src/builtins.h b/src/builtins.h
index c874d8b..b53297a 100644
--- a/src/builtins.h
+++ b/src/builtins.h
@@ -154,8 +154,6 @@
\
V(StoreIC_Initialize, STORE_IC, UNINITIALIZED, \
Code::kNoExtraICState) \
- V(StoreIC_ArrayLength, STORE_IC, MONOMORPHIC, \
- Code::kNoExtraICState) \
V(StoreIC_Normal, STORE_IC, MONOMORPHIC, \
Code::kNoExtraICState) \
V(StoreIC_Megamorphic, STORE_IC, MEGAMORPHIC, \
@@ -164,8 +162,6 @@
Code::kNoExtraICState) \
V(StoreIC_Initialize_Strict, STORE_IC, UNINITIALIZED, \
kStrictMode) \
- V(StoreIC_ArrayLength_Strict, STORE_IC, MONOMORPHIC, \
- kStrictMode) \
V(StoreIC_Normal_Strict, STORE_IC, MONOMORPHIC, \
kStrictMode) \
V(StoreIC_Megamorphic_Strict, STORE_IC, MEGAMORPHIC, \
diff --git a/src/code-stubs.cc b/src/code-stubs.cc
index 7b1d1b4..2d23ddb 100644
--- a/src/code-stubs.cc
+++ b/src/code-stubs.cc
@@ -98,7 +98,7 @@
// Copy the generated code into a heap object.
Code::Flags flags = Code::ComputeFlags(
- static_cast<Code::Kind>(GetCodeKind()), GetICState());
+ static_cast<Code::Kind>(GetCodeKind()), GetICState(), GetExtraICState());
Handle<Code> new_object = factory->NewCode(
desc, flags, masm.CodeObject(), NeedsImmovableCode());
return new_object;
diff --git a/src/code-stubs.h b/src/code-stubs.h
index 7ec43c6..bf0e261 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -50,6 +50,7 @@
V(ArrayLength) \
V(StringLength) \
V(FunctionPrototype) \
+ V(StoreArrayLength) \
V(RecordWrite) \
V(StoreBufferOverflow) \
V(RegExpExec) \
@@ -179,6 +180,9 @@
virtual InlineCacheState GetICState() {
return UNINITIALIZED;
}
+ virtual Code::ExtraICState GetExtraICState() {
+ return Code::kNoExtraICState;
+ }
// Returns whether the code generated for this stub needs to be allocated as
// a fixed (non-moveable) code object.
@@ -605,6 +609,37 @@
};
+class StoreICStub: public ICStub {
+ public:
+ StoreICStub(Code::Kind kind, StrictModeFlag strict_mode)
+ : ICStub(kind), strict_mode_(strict_mode) { }
+
+ protected:
+ virtual Code::ExtraICState GetExtraICState() {
+ return strict_mode_;
+ }
+
+ private:
+ class StrictModeBits: public BitField<bool, 4, 1> {};
+ virtual int MinorKey() {
+ return KindBits::encode(kind()) | StrictModeBits::encode(strict_mode_);
+ }
+
+ StrictModeFlag strict_mode_;
+};
+
+
+class StoreArrayLengthStub: public StoreICStub {
+ public:
+ explicit StoreArrayLengthStub(Code::Kind kind, StrictModeFlag strict_mode)
+ : StoreICStub(kind, strict_mode) { }
+ virtual void Generate(MacroAssembler* masm);
+
+ private:
+ virtual CodeStub::Major MajorKey() { return StoreArrayLength; }
+};
+
+
class BinaryOpStub: public PlatformCodeStub {
public:
BinaryOpStub(Token::Value op, OverwriteMode mode)
diff --git a/src/d8.cc b/src/d8.cc
index 407488f..6d63ef1 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -95,14 +95,14 @@
explicit Symbols(Isolate* isolate) : isolate_(isolate) {
HandleScope scope;
#define INIT_SYMBOL(name, value) \
- name##_ = Persistent<String>::New(String::NewSymbol(value));
+ name##_ = Persistent<String>::New(isolate, String::NewSymbol(value));
FOR_EACH_SYMBOL(INIT_SYMBOL)
#undef INIT_SYMBOL
isolate->SetData(this);
}
~Symbols() {
-#define DISPOSE_SYMBOL(name, value) name##_.Dispose();
+#define DISPOSE_SYMBOL(name, value) name##_.Dispose(isolate_);
FOR_EACH_SYMBOL(DISPOSE_SYMBOL)
#undef DISPOSE_SYMBOL
isolate_->SetData(NULL); // Not really needed, just to be sure...
@@ -399,9 +399,10 @@
memset(data, 0, length);
buffer->SetHiddenValue(Symbols::ArrayBufferMarkerPropName(isolate), True());
- Persistent<Object> persistent_array = Persistent<Object>::New(buffer);
- persistent_array.MakeWeak(data, ExternalArrayWeakCallback);
- persistent_array.MarkIndependent();
+ Persistent<Object> persistent_array =
+ Persistent<Object>::New(isolate, buffer);
+ persistent_array.MakeWeak(isolate, data, ExternalArrayWeakCallback);
+ persistent_array.MarkIndependent(isolate);
V8::AdjustAmountOfExternalAllocatedMemory(length);
buffer->SetIndexedPropertiesToExternalArrayData(
@@ -826,14 +827,15 @@
}
-void Shell::ExternalArrayWeakCallback(Persistent<Value> object, void* data) {
+void Shell::ExternalArrayWeakCallback(v8::Isolate* isolate,
+ Persistent<Value> object,
+ void* data) {
HandleScope scope;
- Isolate* isolate = Isolate::GetCurrent();
int32_t length =
object->ToObject()->Get(Symbols::byteLength(isolate))->Uint32Value();
V8::AdjustAmountOfExternalAllocatedMemory(-length);
delete[] static_cast<uint8_t*>(data);
- object.Dispose();
+ object.Dispose(isolate);
}
@@ -1442,9 +1444,10 @@
Isolate* isolate = args.GetIsolate();
Handle<Object> buffer = Object::New();
buffer->SetHiddenValue(Symbols::ArrayBufferMarkerPropName(isolate), True());
- Persistent<Object> persistent_buffer = Persistent<Object>::New(buffer);
- persistent_buffer.MakeWeak(data, ExternalArrayWeakCallback);
- persistent_buffer.MarkIndependent();
+ Persistent<Object> persistent_buffer =
+ Persistent<Object>::New(isolate, buffer);
+ persistent_buffer.MakeWeak(isolate, data, ExternalArrayWeakCallback);
+ persistent_buffer.MarkIndependent(isolate);
V8::AdjustAmountOfExternalAllocatedMemory(length);
buffer->SetIndexedPropertiesToExternalArrayData(
@@ -1565,7 +1568,7 @@
Shell::ExecuteString(str, String::New(filename), false, false);
}
- thread_context.Dispose();
+ thread_context.Dispose(thread_context->GetIsolate());
ptr = next_line;
}
}
@@ -1649,7 +1652,7 @@
Context::Scope cscope(context);
Execute(isolate);
}
- context.Dispose();
+ context.Dispose(isolate);
if (Shell::options.send_idle_notification) {
const int kLongIdlePauseInMs = 1000;
V8::ContextDisposedNotification();
@@ -1858,7 +1861,7 @@
options.isolate_sources[0].Execute(isolate);
}
if (!options.last_run) {
- context.Dispose();
+ context.Dispose(isolate);
if (options.send_idle_notification) {
const int kLongIdlePauseInMs = 1000;
V8::ContextDisposedNotification();
diff --git a/src/d8.h b/src/d8.h
index 63efd66..1c3ce0a 100644
--- a/src/d8.h
+++ b/src/d8.h
@@ -404,7 +404,9 @@
static Handle<Value> CreateExternalArray(const Arguments& args,
ExternalArrayType type,
int32_t element_size);
- static void ExternalArrayWeakCallback(Persistent<Value> object, void* data);
+ static void ExternalArrayWeakCallback(Isolate* isolate,
+ Persistent<Value> object,
+ void* data);
};
diff --git a/src/debug.cc b/src/debug.cc
index 7baed88..866839d 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -617,10 +617,10 @@
Handle<Script> script_ =
Handle<Script>::cast(
(global_handles->Create(*script)));
- global_handles->MakeWeak(
- reinterpret_cast<Object**>(script_.location()),
- this,
- ScriptCache::HandleWeakScript);
+ global_handles->MakeWeak(reinterpret_cast<Object**>(script_.location()),
+ this,
+ NULL,
+ ScriptCache::HandleWeakScript);
entry->value = script_.location();
}
@@ -663,7 +663,9 @@
}
-void ScriptCache::HandleWeakScript(v8::Persistent<v8::Value> obj, void* data) {
+void ScriptCache::HandleWeakScript(v8::Isolate* isolate,
+ v8::Persistent<v8::Value> obj,
+ void* data) {
ScriptCache* script_cache = reinterpret_cast<ScriptCache*>(data);
// Find the location of the global handle.
Script** location =
@@ -676,7 +678,7 @@
script_cache->collected_scripts_.Add(id);
// Clear the weak handle.
- obj.Dispose();
+ obj.Dispose(isolate);
obj.Clear();
}
@@ -696,8 +698,10 @@
}
-void Debug::HandleWeakDebugInfo(v8::Persistent<v8::Value> obj, void* data) {
- Debug* debug = Isolate::Current()->debug();
+void Debug::HandleWeakDebugInfo(v8::Isolate* isolate,
+ v8::Persistent<v8::Value> obj,
+ void* data) {
+ Debug* debug = reinterpret_cast<Isolate*>(isolate)->debug();
DebugInfoListNode* node = reinterpret_cast<DebugInfoListNode*>(data);
// We need to clear all breakpoints associated with the function to restore
// original code and avoid patching the code twice later because
@@ -721,10 +725,10 @@
// Globalize the request debug info object and make it weak.
debug_info_ = Handle<DebugInfo>::cast(
(global_handles->Create(debug_info)));
- global_handles->MakeWeak(
- reinterpret_cast<Object**>(debug_info_.location()),
- this,
- Debug::HandleWeakDebugInfo);
+ global_handles->MakeWeak(reinterpret_cast<Object**>(debug_info_.location()),
+ this,
+ NULL,
+ Debug::HandleWeakDebugInfo);
}
diff --git a/src/debug.h b/src/debug.h
index 4363df9..0558afd 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -189,7 +189,9 @@
void Clear();
// Weak handle callback for scripts in the cache.
- static void HandleWeakScript(v8::Persistent<v8::Value> obj, void* data);
+ static void HandleWeakScript(v8::Isolate* isolate,
+ v8::Persistent<v8::Value> obj,
+ void* data);
// List used during GC to temporarily store id's of collected scripts.
List<int> collected_scripts_;
@@ -384,7 +386,9 @@
static const int kEstimatedNofBreakPointsInFunction = 16;
// Passed to MakeWeak.
- static void HandleWeakDebugInfo(v8::Persistent<v8::Value> obj, void* data);
+ static void HandleWeakDebugInfo(v8::Isolate* isolate,
+ v8::Persistent<v8::Value> obj,
+ void* data);
friend class Debugger;
friend Handle<FixedArray> GetDebuggedFunctions(); // In test-debug.cc
diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc
index bc0c61c..3d07ca9 100644
--- a/src/deoptimizer.cc
+++ b/src/deoptimizer.cc
@@ -456,11 +456,13 @@
}
-void Deoptimizer::HandleWeakDeoptimizedCode(v8::Persistent<v8::Value> obj,
+void Deoptimizer::HandleWeakDeoptimizedCode(v8::Isolate* isolate,
+ v8::Persistent<v8::Value> obj,
void* parameter) {
DeoptimizingCodeListNode* node =
reinterpret_cast<DeoptimizingCodeListNode*>(parameter);
- DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
+ DeoptimizerData* data =
+ reinterpret_cast<Isolate*>(isolate)->deoptimizer_data();
data->RemoveDeoptimizingCode(*node->code());
#ifdef DEBUG
for (DeoptimizingCodeListNode* current = data->deoptimizing_code_list_;
@@ -1913,6 +1915,7 @@
code_ = Handle<Code>::cast(global_handles->Create(code));
global_handles->MakeWeak(reinterpret_cast<Object**>(code_.location()),
this,
+ NULL,
Deoptimizer::HandleWeakDeoptimizedCode);
}
diff --git a/src/deoptimizer.h b/src/deoptimizer.h
index 870fdb2..0c2252e 100644
--- a/src/deoptimizer.h
+++ b/src/deoptimizer.h
@@ -372,8 +372,9 @@
MacroAssembler* masm, int count, BailoutType type);
// Weak handle callback for deoptimizing code objects.
- static void HandleWeakDeoptimizedCode(
- v8::Persistent<v8::Value> obj, void* data);
+ static void HandleWeakDeoptimizedCode(v8::Isolate* isolate,
+ v8::Persistent<v8::Value> obj,
+ void* data);
// Deoptimize function assuming that function->next_function_link() points
// to a list that contains all functions that share the same optimized code.
diff --git a/src/global-handles.cc b/src/global-handles.cc
index 23b3918..51e904e 100644
--- a/src/global-handles.cc
+++ b/src/global-handles.cc
@@ -60,12 +60,16 @@
}
Node() {
- ASSERT(OFFSET_OF(Node, flags_) == Internals::kNodeFlagsOffset);
ASSERT(OFFSET_OF(Node, class_id_) == Internals::kNodeClassIdOffset);
- ASSERT(static_cast<int>(IsIndependent::kShift) ==
- Internals::kNodeIsIndependentShift);
- ASSERT(static_cast<int>(IsPartiallyDependent::kShift) ==
- Internals::kNodeIsPartiallyDependentShift);
+ ASSERT(OFFSET_OF(Node, flags_) == Internals::kNodeFlagsOffset);
+ STATIC_ASSERT(static_cast<int>(NodeState::kMask) ==
+ Internals::kNodeStateMask);
+ STATIC_ASSERT(WEAK == Internals::kNodeStateIsWeakValue);
+ STATIC_ASSERT(NEAR_DEATH == Internals::kNodeStateIsNearDeathValue);
+ STATIC_ASSERT(static_cast<int>(IsIndependent::kShift) ==
+ Internals::kNodeIsIndependentShift);
+ STATIC_ASSERT(static_cast<int>(IsPartiallyDependent::kShift) ==
+ Internals::kNodeIsPartiallyDependentShift);
}
#ifdef DEBUG
@@ -79,7 +83,8 @@
set_partially_dependent(false);
set_in_new_space_list(false);
parameter_or_next_free_.next_free = NULL;
- callback_ = NULL;
+ weak_reference_callback_ = NULL;
+ near_death_callback_ = NULL;
}
#endif
@@ -100,7 +105,8 @@
set_partially_dependent(false);
set_state(NORMAL);
parameter_or_next_free_.parameter = NULL;
- callback_ = NULL;
+ weak_reference_callback_ = NULL;
+ near_death_callback_ = NULL;
IncreaseBlockUses(global_handles);
}
@@ -189,7 +195,8 @@
void clear_partially_dependent() { set_partially_dependent(false); }
// Callback accessor.
- WeakReferenceCallback callback() { return callback_; }
+ // TODO(svenpanne) Re-enable or nuke later.
+ // WeakReferenceCallback callback() { return callback_; }
// Callback parameter accessors.
void set_parameter(void* parameter) {
@@ -213,11 +220,13 @@
void MakeWeak(GlobalHandles* global_handles,
void* parameter,
- WeakReferenceCallback callback) {
+ WeakReferenceCallback weak_reference_callback,
+ NearDeathCallback near_death_callback) {
ASSERT(state() != FREE);
set_state(WEAK);
set_parameter(parameter);
- callback_ = callback;
+ weak_reference_callback_ = weak_reference_callback;
+ near_death_callback_ = near_death_callback;
}
void ClearWeakness(GlobalHandles* global_handles) {
@@ -229,8 +238,8 @@
bool PostGarbageCollectionProcessing(Isolate* isolate,
GlobalHandles* global_handles) {
if (state() != Node::PENDING) return false;
- WeakReferenceCallback func = callback();
- if (func == NULL) {
+ if (weak_reference_callback_ == NULL &&
+ near_death_callback_ == NULL) {
Release(global_handles);
return false;
}
@@ -248,7 +257,14 @@
ExternalTwoByteString::cast(object_)->resource() != NULL);
// Leaving V8.
VMState state(isolate, EXTERNAL);
- func(object, par);
+ if (weak_reference_callback_ != NULL) {
+ weak_reference_callback_(object, par);
+ }
+ if (near_death_callback_ != NULL) {
+ near_death_callback_(reinterpret_cast<v8::Isolate*>(isolate),
+ object,
+ par);
+ }
}
// Absence of explicit cleanup or revival of weak handle
// in most of the cases would lead to memory leak.
@@ -284,7 +300,8 @@
uint8_t flags_;
// Handle specific callback.
- WeakReferenceCallback callback_;
+ WeakReferenceCallback weak_reference_callback_;
+ NearDeathCallback near_death_callback_;
// Provided data for callback. In FREE state, this is used for
// the free list link.
@@ -450,10 +467,16 @@
}
-void GlobalHandles::MakeWeak(Object** location, void* parameter,
- WeakReferenceCallback callback) {
- ASSERT(callback != NULL);
- Node::FromLocation(location)->MakeWeak(this, parameter, callback);
+void GlobalHandles::MakeWeak(Object** location,
+ void* parameter,
+ WeakReferenceCallback weak_reference_callback,
+ NearDeathCallback near_death_callback) {
+ ASSERT((weak_reference_callback != NULL) !=
+ (near_death_callback != NULL));
+ Node::FromLocation(location)->MakeWeak(this,
+ parameter,
+ weak_reference_callback,
+ near_death_callback);
}
diff --git a/src/global-handles.h b/src/global-handles.h
index 18bfc11..9900144 100644
--- a/src/global-handles.h
+++ b/src/global-handles.h
@@ -126,7 +126,8 @@
// reason is that Smi::FromInt(0) does not change during garage collection.
void MakeWeak(Object** location,
void* parameter,
- WeakReferenceCallback callback);
+ WeakReferenceCallback weak_reference_callback,
+ NearDeathCallback near_death_callback);
void RecordStats(HeapStats* stats);
diff --git a/src/handles.cc b/src/handles.cc
index c0dea20..e97dcad 100644
--- a/src/handles.cc
+++ b/src/handles.cc
@@ -350,14 +350,16 @@
// collector will call the weak callback on the global handle
// associated with the wrapper and get rid of both the wrapper and the
// handle.
-static void ClearWrapperCache(Persistent<v8::Value> handle, void*) {
+static void ClearWrapperCache(v8::Isolate* v8_isolate,
+ Persistent<v8::Value> handle,
+ void*) {
Handle<Object> cache = Utils::OpenHandle(*handle);
JSValue* wrapper = JSValue::cast(*cache);
Foreign* foreign = Script::cast(wrapper->value())->wrapper();
ASSERT(foreign->foreign_address() ==
reinterpret_cast<Address>(cache.location()));
foreign->set_foreign_address(0);
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
isolate->global_handles()->Destroy(cache.location());
isolate->counters()->script_wrappers()->Decrement();
}
@@ -390,7 +392,9 @@
// for future use. The cache will automatically be cleared by the
// garbage collector when it is not used anymore.
Handle<Object> handle = isolate->global_handles()->Create(*result);
- isolate->global_handles()->MakeWeak(handle.location(), NULL,
+ isolate->global_handles()->MakeWeak(handle.location(),
+ NULL,
+ NULL,
&ClearWrapperCache);
script->wrapper()->set_foreign_address(
reinterpret_cast<Address>(handle.location()));
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index 0bf208b..38f3dac 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -571,6 +571,11 @@
}
+bool HValue::HasMonomorphicJSObjectType() {
+ return !GetMonomorphicJSObjectMap().is_null();
+}
+
+
bool HValue::UpdateInferredType() {
HType type = CalculateInferredType();
bool result = (!type.Equals(type_));
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index 367d2b3..aa513e7 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -770,6 +770,14 @@
const char* Mnemonic() const;
+ // Type information helpers.
+ bool HasMonomorphicJSObjectType();
+
+ // TODO(mstarzinger): For now instructions can override this function to
+ // specify statically known types, once HType can convey more information
+ // it should be based on the HType.
+ virtual Handle<Map> GetMonomorphicJSObjectMap() { return Handle<Map>(); }
+
// Updated the inferred type of this instruction and returns true if
// it has changed.
bool UpdateInferredType();
@@ -5019,6 +5027,10 @@
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
+ virtual Handle<Map> GetMonomorphicJSObjectMap() {
+ ASSERT(constructor()->has_initial_map());
+ return Handle<Map>(constructor()->initial_map());
+ }
virtual HType CalculateInferredType();
DECLARE_CONCRETE_INSTRUCTION(AllocateObject)
@@ -5086,6 +5098,9 @@
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
+ virtual Handle<Map> GetMonomorphicJSObjectMap() {
+ return Handle<Map>(boilerplate()->map());
+ }
virtual HType CalculateInferredType();
DECLARE_CONCRETE_INSTRUCTION(FastLiteral)
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 8de8e52..e9e5746 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -1329,37 +1329,50 @@
}
+// Replace all phis consisting of a single non-loop operand plus any number of
+// loop operands by that single non-loop operand.
void HGraph::EliminateRedundantPhis() {
HPhase phase("H_Redundant phi elimination", this);
- // Worklist of phis that can potentially be eliminated. Initialized with
- // all phi nodes. When elimination of a phi node modifies another phi node
- // the modified phi node is added to the worklist.
- ZoneList<HPhi*> worklist(blocks_.length(), zone());
- for (int i = 0; i < blocks_.length(); ++i) {
- worklist.AddAll(*blocks_[i]->phis(), zone());
- }
-
- while (!worklist.is_empty()) {
- HPhi* phi = worklist.RemoveLast();
- HBasicBlock* block = phi->block();
-
- // Skip phi node if it was already replaced.
- if (block == NULL) continue;
-
- // Get replacement value if phi is redundant.
- HValue* replacement = phi->GetRedundantReplacement();
-
- if (replacement != NULL) {
- // Iterate through the uses and replace them all.
- for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) {
- HValue* value = it.value();
- value->SetOperandAt(it.index(), replacement);
- if (value->IsPhi()) worklist.Add(HPhi::cast(value), zone());
+ // We do a simple fixed point iteration without any work list, because
+ // machine-generated JavaScript can lead to a very dense Hydrogen graph with
+ // an enormous work list and will consequently result in OOM. Experiments
+ // showed that this simple algorithm is good enough, and even e.g. tracking
+ // the set or range of blocks to consider is not a real improvement.
+ bool need_another_iteration;
+ ZoneList<HPhi*> redundant_phis(blocks_.length(), zone());
+ do {
+ need_another_iteration = false;
+ for (int i = 0; i < blocks_.length(); ++i) {
+ HBasicBlock* block = blocks_[i];
+ for (int j = 0; j < block->phis()->length(); j++) {
+ HPhi* phi = block->phis()->at(j);
+ HValue* replacement = phi->GetRedundantReplacement();
+ if (replacement != NULL) {
+ // Remember phi to avoid concurrent modification of the block's phis.
+ redundant_phis.Add(phi, zone());
+ for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) {
+ HValue* value = it.value();
+ value->SetOperandAt(it.index(), replacement);
+ need_another_iteration |= value->IsPhi();
+ }
+ }
}
- block->RemovePhi(phi);
+ for (int i = 0; i < redundant_phis.length(); i++) {
+ block->RemovePhi(redundant_phis[i]);
+ }
+ redundant_phis.Clear();
+ }
+ } while (need_another_iteration);
+
+#if DEBUG
+ // Make sure that we *really* removed all redundant phis.
+ for (int i = 0; i < blocks_.length(); ++i) {
+ for (int j = 0; j < blocks_[i]->phis()->length(); j++) {
+ ASSERT(blocks_[i]->phis()->at(j)->GetRedundantReplacement() == NULL);
}
}
+#endif
}
@@ -6796,12 +6809,16 @@
} else if (expr->key()->IsPropertyName()) {
Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
SmallMapList* types = expr->GetReceiverTypes();
+ HValue* object = Top();
- bool monomorphic = expr->IsMonomorphic();
Handle<Map> map;
+ bool monomorphic = false;
if (expr->IsMonomorphic()) {
map = types->first();
- if (map->is_dictionary_map()) monomorphic = false;
+ monomorphic = !map->is_dictionary_map();
+ } else if (object->HasMonomorphicJSObjectType()) {
+ map = object->GetMonomorphicJSObjectMap();
+ monomorphic = !map->is_dictionary_map();
}
if (monomorphic) {
Handle<JSFunction> getter;
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index 4e4a609..35bda31 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -3317,6 +3317,70 @@
}
+void StoreArrayLengthStub::Generate(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- eax : value
+ // -- ecx : name
+ // -- edx : receiver
+ // -- esp[0] : return address
+ // -----------------------------------
+ //
+ // This accepts as a receiver anything JSArray::SetElementsLength accepts
+ // (currently anything except for external arrays which means anything with
+ // elements of FixedArray type). Value must be a number, but only smis are
+ // accepted as the most common case.
+
+ Label miss;
+
+ Register receiver = edx;
+ Register value = eax;
+ Register scratch = ebx;
+
+ if (kind() == Code::KEYED_LOAD_IC) {
+ __ cmp(ecx, Immediate(masm->isolate()->factory()->length_symbol()));
+ __ j(not_equal, &miss);
+ }
+
+ // Check that the receiver isn't a smi.
+ __ JumpIfSmi(receiver, &miss);
+
+ // Check that the object is a JS array.
+ __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
+ __ j(not_equal, &miss);
+
+ // Check that elements are FixedArray.
+ // We rely on StoreIC_ArrayLength below to deal with all types of
+ // fast elements (including COW).
+ __ mov(scratch, FieldOperand(receiver, JSArray::kElementsOffset));
+ __ CmpObjectType(scratch, FIXED_ARRAY_TYPE, scratch);
+ __ j(not_equal, &miss);
+
+ // Check that the array has fast properties, otherwise the length
+ // property might have been redefined.
+ __ mov(scratch, FieldOperand(receiver, JSArray::kPropertiesOffset));
+ __ CompareRoot(FieldOperand(scratch, FixedArray::kMapOffset),
+ Heap::kHashTableMapRootIndex);
+ __ j(equal, &miss);
+
+ // Check that value is a smi.
+ __ JumpIfNotSmi(value, &miss);
+
+ // Prepare tail call to StoreIC_ArrayLength.
+ __ pop(scratch);
+ __ push(receiver);
+ __ push(value);
+ __ push(scratch); // return address
+
+ ExternalReference ref =
+ ExternalReference(IC_Utility(IC::kStoreIC_ArrayLength), masm->isolate());
+ __ TailCallExternalReference(ref, 2, 1);
+
+ __ bind(&miss);
+
+ StubCompiler::GenerateStoreMiss(masm, kind());
+}
+
+
void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
// The key is in edx and the parameter count is in eax.
diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc
index bfca89f..3c7b285 100644
--- a/src/ia32/ic-ia32.cc
+++ b/src/ia32/ic-ia32.cc
@@ -1426,65 +1426,6 @@
}
-void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- eax : value
- // -- ecx : name
- // -- edx : receiver
- // -- esp[0] : return address
- // -----------------------------------
- //
- // This accepts as a receiver anything JSArray::SetElementsLength accepts
- // (currently anything except for external arrays which means anything with
- // elements of FixedArray type). Value must be a number, but only smis are
- // accepted as the most common case.
-
- Label miss;
-
- Register receiver = edx;
- Register value = eax;
- Register scratch = ebx;
-
- // Check that the receiver isn't a smi.
- __ JumpIfSmi(receiver, &miss);
-
- // Check that the object is a JS array.
- __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
- __ j(not_equal, &miss);
-
- // Check that elements are FixedArray.
- // We rely on StoreIC_ArrayLength below to deal with all types of
- // fast elements (including COW).
- __ mov(scratch, FieldOperand(receiver, JSArray::kElementsOffset));
- __ CmpObjectType(scratch, FIXED_ARRAY_TYPE, scratch);
- __ j(not_equal, &miss);
-
- // Check that the array has fast properties, otherwise the length
- // property might have been redefined.
- __ mov(scratch, FieldOperand(receiver, JSArray::kPropertiesOffset));
- __ CompareRoot(FieldOperand(scratch, FixedArray::kMapOffset),
- Heap::kHashTableMapRootIndex);
- __ j(equal, &miss);
-
- // Check that value is a smi.
- __ JumpIfNotSmi(value, &miss);
-
- // Prepare tail call to StoreIC_ArrayLength.
- __ pop(scratch);
- __ push(receiver);
- __ push(value);
- __ push(scratch); // return address
-
- ExternalReference ref =
- ExternalReference(IC_Utility(kStoreIC_ArrayLength), masm->isolate());
- __ TailCallExternalReference(ref, 2, 1);
-
- __ bind(&miss);
-
- GenerateMiss(masm);
-}
-
-
void StoreIC::GenerateNormal(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : value
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index 68e7b97..805016e 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -737,6 +737,15 @@
}
+void StubCompiler::GenerateStoreMiss(MacroAssembler* masm, Code::Kind kind) {
+ ASSERT(kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC);
+ Handle<Code> code = (kind == Code::STORE_IC)
+ ? masm->isolate()->builtins()->StoreIC_Miss()
+ : masm->isolate()->builtins()->KeyedStoreIC_Miss();
+ __ jmp(code, RelocInfo::CODE_TARGET);
+}
+
+
void StubCompiler::GenerateKeyedLoadMissForceGeneric(MacroAssembler* masm) {
Handle<Code> code =
masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
diff --git a/src/ic.cc b/src/ic.cc
index 65d3f65..7fa7eaf 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -795,23 +795,23 @@
return TypeError("non_object_property_call", object, key);
}
- if (FLAG_use_ic && state != MEGAMORPHIC && object->IsHeapObject()) {
- ASSERT(state != GENERIC);
+ bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded();
+ ASSERT(!(use_ic && object->IsJSGlobalProxy()));
+
+ if (use_ic && state != MEGAMORPHIC) {
int argc = target()->arguments_count();
- Handle<Map> map =
- isolate()->factory()->non_strict_arguments_elements_map();
- if (object->IsJSObject() &&
- Handle<JSObject>::cast(object)->elements()->map() == *map) {
- Handle<Code> code = isolate()->stub_cache()->ComputeCallArguments(
- argc, Code::KEYED_CALL_IC);
- set_target(*code);
- TRACE_IC("KeyedCallIC", key, state, target());
- } else if (!object->IsAccessCheckNeeded()) {
- Handle<Code> code = isolate()->stub_cache()->ComputeCallMegamorphic(
- argc, Code::KEYED_CALL_IC, Code::kNoExtraICState);
- set_target(*code);
- TRACE_IC("KeyedCallIC", key, state, target());
+ Handle<Code> stub = isolate()->stub_cache()->ComputeCallMegamorphic(
+ argc, Code::KEYED_CALL_IC, Code::kNoExtraICState);
+ if (object->IsJSObject()) {
+ Handle<JSObject> receiver = Handle<JSObject>::cast(object);
+ if (receiver->elements()->map() ==
+ isolate()->heap()->non_strict_arguments_elements_map()) {
+ stub = isolate()->stub_cache()->ComputeCallArguments(argc);
+ }
}
+ ASSERT(!stub.is_null());
+ set_target(*stub);
+ TRACE_IC("KeyedCallIC", key, state, target());
}
Handle<Object> result = GetProperty(object, key);
@@ -963,6 +963,45 @@
}
+void IC::PatchCache(State state,
+ StrictModeFlag strict_mode,
+ Handle<JSObject> receiver,
+ Handle<String> name,
+ Handle<Code> code) {
+ switch (state) {
+ case UNINITIALIZED:
+ case PREMONOMORPHIC:
+ case MONOMORPHIC_PROTOTYPE_FAILURE:
+ case POLYMORPHIC:
+ set_target(*code);
+ break;
+ case MONOMORPHIC:
+ // Only move to megamorphic if the target changes.
+ if (target() != *code) {
+ // We are transitioning from monomorphic to megamorphic case.
+ // Place the current monomorphic stub and stub compiled for
+ // the receiver into stub cache.
+ Map* map = target()->FindFirstMap();
+ if (map != NULL) {
+ UpdateMegamorphicCache(map, *name, target());
+ }
+ UpdateMegamorphicCache(receiver->map(), *name, *code);
+ set_target((strict_mode == kStrictMode)
+ ? *megamorphic_stub_strict()
+ : *megamorphic_stub());
+ }
+ break;
+ case MEGAMORPHIC:
+ // Update the stub cache.
+ UpdateMegamorphicCache(receiver->map(), *name, *code);
+ break;
+ case GENERIC:
+ case DEBUG_STUB:
+ break;
+ }
+}
+
+
void LoadIC::UpdateCaches(LookupResult* lookup,
State state,
Handle<Object> object,
@@ -988,42 +1027,12 @@
if (code.is_null()) return;
}
- // Patch the call site depending on the state of the cache.
- switch (state) {
- case UNINITIALIZED:
- case PREMONOMORPHIC:
- case MONOMORPHIC_PROTOTYPE_FAILURE:
- set_target(*code);
- break;
- case MONOMORPHIC:
- if (target() != *code) {
- // We are transitioning from monomorphic to megamorphic case.
- // Place the current monomorphic stub and stub compiled for
- // the receiver into stub cache.
- Map* map = target()->FindFirstMap();
- if (map != NULL) {
- UpdateMegamorphicCache(map, *name, target());
- }
- UpdateMegamorphicCache(receiver->map(), *name, *code);
- set_target(*megamorphic_stub());
- }
- break;
- case MEGAMORPHIC:
- UpdateMegamorphicCache(receiver->map(), *name, *code);
- break;
- case DEBUG_STUB:
- break;
- case POLYMORPHIC:
- case GENERIC:
- UNREACHABLE();
- break;
- }
-
+ PatchCache(state, kNonStrictMode, receiver, name, code);
TRACE_IC("LoadIC", name, state, target());
}
-void LoadIC::UpdateMegamorphicCache(Map* map, String* name, Code* code) {
+void IC::UpdateMegamorphicCache(Map* map, String* name, Code* code) {
// Cache code holding map should be consistent with
// GenerateMonomorphicCacheProbe.
isolate()->stub_cache()->Set(name, map, code);
@@ -1234,9 +1243,8 @@
return LoadIC::Load(state, object, Handle<String>::cast(key));
}
- // Do not use ICs for objects that require access checks (including
- // the global object).
bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded();
+ ASSERT(!(use_ic && object->IsJSGlobalProxy()));
if (use_ic) {
Handle<Code> stub = generic_stub();
@@ -1259,12 +1267,12 @@
} else {
TRACE_GENERIC_IC("KeyedLoadIC", "force generic");
}
- if (!stub.is_null()) set_target(*stub);
+ ASSERT(!stub.is_null());
+ set_target(*stub);
+ TRACE_IC("KeyedLoadIC", key, state, target());
}
- TRACE_IC("KeyedLoadIC", key, state, target());
- // Get the property.
return Runtime::GetObjectProperty(isolate(), object, key);
}
@@ -1398,11 +1406,8 @@
receiver->IsJSArray() &&
name->Equals(isolate()->heap()->length_symbol()) &&
Handle<JSArray>::cast(receiver)->AllowsSetElementsLength() &&
- receiver->HasFastProperties() &&
- kind() != Code::KEYED_STORE_IC) {
- Handle<Code> stub = (strict_mode == kStrictMode)
- ? isolate()->builtins()->StoreIC_ArrayLength_Strict()
- : isolate()->builtins()->StoreIC_ArrayLength();
+ receiver->HasFastProperties()) {
+ Handle<Code> stub = StoreArrayLengthStub(kind(), strict_mode).GetCode();
set_target(*stub);
TRACE_IC("StoreIC", name, state, *stub);
return receiver->SetProperty(*name, *value, NONE, strict_mode, store_mode);
@@ -1424,7 +1429,7 @@
LookupResult lookup(isolate());
if (LookupForWrite(receiver, name, &lookup)) {
if (FLAG_use_ic) {
- UpdateStoreCaches(&lookup, state, strict_mode, receiver, name, value);
+ UpdateCaches(&lookup, state, strict_mode, receiver, name, value);
}
} else if (strict_mode == kStrictMode &&
!(lookup.IsProperty() && lookup.IsReadOnly()) &&
@@ -1438,12 +1443,12 @@
}
-void StoreIC::UpdateStoreCaches(LookupResult* lookup,
- State state,
- StrictModeFlag strict_mode,
- Handle<JSObject> receiver,
- Handle<String> name,
- Handle<Object> value) {
+void StoreIC::UpdateCaches(LookupResult* lookup,
+ State state,
+ StrictModeFlag strict_mode,
+ Handle<JSObject> receiver,
+ Handle<String> name,
+ Handle<Object> value) {
ASSERT(!receiver->IsJSGlobalProxy());
ASSERT(StoreICableLookup(lookup));
ASSERT(lookup->IsFound());
@@ -1451,22 +1456,25 @@
// These are not cacheable, so we never see such LookupResults here.
ASSERT(!lookup->IsHandler());
- // If the property has a non-field type allowing map transitions
- // where there is extra room in the object, we leave the IC in its
- // current state.
- PropertyType type = lookup->type();
+ Handle<Code> code =
+ ComputeStoreMonomorphic(lookup, strict_mode, receiver, name);
+ if (code.is_null()) return;
- // Compute the code stub for this store; used for rewriting to
- // monomorphic state and making sure that the code stub is in the
- // stub cache.
+ PatchCache(state, strict_mode, receiver, name, code);
+ TRACE_IC("StoreIC", name, state, target());
+}
+
+
+Handle<Code> StoreIC::ComputeStoreMonomorphic(LookupResult* lookup,
+ StrictModeFlag strict_mode,
+ Handle<JSObject> receiver,
+ Handle<String> name) {
Handle<JSObject> holder(lookup->holder());
- Handle<Code> code;
- switch (type) {
+ switch (lookup->type()) {
case FIELD:
- code = isolate()->stub_cache()->ComputeStoreField(
+ return isolate()->stub_cache()->ComputeStoreField(
name, receiver, lookup->GetFieldIndex().field_index(),
Handle<Map>::null(), strict_mode);
- break;
case NORMAL:
if (receiver->IsGlobalObject()) {
// The stub generated for the global object picks the value directly
@@ -1474,44 +1482,39 @@
// global object.
Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(lookup));
- code = isolate()->stub_cache()->ComputeStoreGlobal(
+ return isolate()->stub_cache()->ComputeStoreGlobal(
name, global, cell, strict_mode);
- } else {
- if (!holder.is_identical_to(receiver)) return;
- code = isolate()->stub_cache()->ComputeStoreNormal(strict_mode);
}
- break;
+ if (!holder.is_identical_to(receiver)) break;
+ return isolate()->stub_cache()->ComputeStoreNormal(strict_mode);
case CALLBACKS: {
Handle<Object> callback(lookup->GetCallbackObject());
if (callback->IsAccessorInfo()) {
Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(callback);
- if (v8::ToCData<Address>(info->setter()) == 0) return;
- if (!holder->HasFastProperties()) return;
- if (!info->IsCompatibleReceiver(*receiver)) return;
- code = isolate()->stub_cache()->ComputeStoreCallback(
+ if (v8::ToCData<Address>(info->setter()) == 0) break;
+ if (!holder->HasFastProperties()) break;
+ if (!info->IsCompatibleReceiver(*receiver)) break;
+ return isolate()->stub_cache()->ComputeStoreCallback(
name, receiver, holder, info, strict_mode);
} else if (callback->IsAccessorPair()) {
Handle<Object> setter(Handle<AccessorPair>::cast(callback)->setter());
- if (!setter->IsJSFunction()) return;
- if (holder->IsGlobalObject()) return;
- if (!holder->HasFastProperties()) return;
- code = isolate()->stub_cache()->ComputeStoreViaSetter(
+ if (!setter->IsJSFunction()) break;
+ if (holder->IsGlobalObject()) break;
+ if (!holder->HasFastProperties()) break;
+ return isolate()->stub_cache()->ComputeStoreViaSetter(
name, receiver, holder, Handle<JSFunction>::cast(setter),
strict_mode);
- } else {
- ASSERT(callback->IsForeign());
- // No IC support for old-style native accessors.
- return;
}
+ ASSERT(callback->IsForeign());
+ // No IC support for old-style native accessors.
break;
}
case INTERCEPTOR:
ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined());
- code = isolate()->stub_cache()->ComputeStoreInterceptor(
+ return isolate()->stub_cache()->ComputeStoreInterceptor(
name, receiver, strict_mode);
- break;
case CONSTANT_FUNCTION:
- return;
+ break;
case TRANSITION: {
Handle<Map> transition(lookup->GetTransitionTarget());
int descriptor = transition->LastAdded();
@@ -1519,56 +1522,18 @@
DescriptorArray* target_descriptors = transition->instance_descriptors();
PropertyDetails details = target_descriptors->GetDetails(descriptor);
- if (details.type() != FIELD || details.attributes() != NONE) return;
+ if (details.type() != FIELD || details.attributes() != NONE) break;
int field_index = target_descriptors->GetFieldIndex(descriptor);
- code = isolate()->stub_cache()->ComputeStoreField(
+ return isolate()->stub_cache()->ComputeStoreField(
name, receiver, field_index, transition, strict_mode);
-
- break;
}
case NONEXISTENT:
case HANDLER:
UNREACHABLE();
- return;
- }
-
- // Patch the call site depending on the state of the cache.
- switch (state) {
- case UNINITIALIZED:
- case PREMONOMORPHIC:
- case MONOMORPHIC_PROTOTYPE_FAILURE:
- set_target(*code);
- break;
- case MONOMORPHIC:
- // Only move to megamorphic if the target changes.
- if (target() != *code) {
- // We are transitioning from monomorphic to megamorphic case.
- // Place the current monomorphic stub and stub compiled for
- // the receiver into stub cache.
- Map* map = target()->FindFirstMap();
- if (map != NULL) {
- isolate()->stub_cache()->Set(*name, map, target());
- }
- isolate()->stub_cache()->Set(*name, receiver->map(), *code);
- set_target((strict_mode == kStrictMode)
- ? *megamorphic_stub_strict()
- : *megamorphic_stub());
- }
- break;
- case MEGAMORPHIC:
- // Update the stub cache.
- isolate()->stub_cache()->Set(*name, receiver->map(), *code);
- break;
- case DEBUG_STUB:
- break;
- case POLYMORPHIC:
- case GENERIC:
- UNREACHABLE();
break;
}
-
- TRACE_IC("StoreIC", name, state, target());
+ return Handle<Code>::null();
}
@@ -1759,17 +1724,14 @@
key = TryConvertKey(key, isolate());
if (key->IsSymbol()) {
- Handle<String> name = Handle<String>::cast(key);
return StoreIC::Store(state,
strict_mode,
object,
- name,
+ Handle<String>::cast(key),
value,
JSReceiver::MAY_BE_STORE_FROM_KEYED);
}
- // Do not use ICs for objects that require access checks (including
- // the global object), or are observed.
bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded() &&
!(FLAG_harmony_observation && object->IsJSObject() &&
JSObject::cast(*object)->map()->is_observed());
@@ -1779,60 +1741,42 @@
Handle<Code> stub = (strict_mode == kStrictMode)
? generic_stub_strict()
: generic_stub();
- if (object->IsJSObject()) {
- Handle<JSObject> receiver = Handle<JSObject>::cast(object);
- if (receiver->elements()->map() ==
- isolate()->heap()->non_strict_arguments_elements_map()) {
- stub = non_strict_arguments_stub();
- } else if (miss_mode != MISS_FORCE_GENERIC) {
- if (key->IsSmi() && (target() != *non_strict_arguments_stub())) {
+ if (miss_mode != MISS_FORCE_GENERIC) {
+ if (object->IsJSObject()) {
+ Handle<JSObject> receiver = Handle<JSObject>::cast(object);
+ if (receiver->elements()->map() ==
+ isolate()->heap()->non_strict_arguments_elements_map()) {
+ stub = non_strict_arguments_stub();
+ } else if (key->IsSmi() && (target() != *non_strict_arguments_stub())) {
StubKind stub_kind = GetStubKind(receiver, key, value);
stub = StoreElementStub(receiver, stub_kind, strict_mode);
}
- } else {
- TRACE_GENERIC_IC("KeyedStoreIC", "force generic");
}
+ } else {
+ TRACE_GENERIC_IC("KeyedStoreIC", "force generic");
}
- if (!stub.is_null()) set_target(*stub);
+ ASSERT(!stub.is_null());
+ set_target(*stub);
+ TRACE_IC("KeyedStoreIC", key, state, target());
}
- TRACE_IC("KeyedStoreIC", key, state, target());
-
- // Set the property.
return Runtime::SetObjectProperty(
isolate(), object , key, value, NONE, strict_mode);
}
-void KeyedStoreIC::UpdateStoreCaches(LookupResult* lookup,
- State state,
- StrictModeFlag strict_mode,
- Handle<JSObject> receiver,
- Handle<String> name,
- Handle<Object> value) {
- ASSERT(!receiver->IsJSGlobalProxy());
- ASSERT(StoreICableLookup(lookup));
- ASSERT(lookup->IsFound());
-
- // These are not cacheable, so we never see such LookupResults here.
- ASSERT(!lookup->IsHandler());
-
+Handle<Code> KeyedStoreIC::ComputeStoreMonomorphic(LookupResult* lookup,
+ StrictModeFlag strict_mode,
+ Handle<JSObject> receiver,
+ Handle<String> name) {
// If the property has a non-field type allowing map transitions
// where there is extra room in the object, we leave the IC in its
// current state.
- PropertyType type = lookup->type();
-
- // Compute the code stub for this store; used for rewriting to
- // monomorphic state and making sure that the code stub is in the
- // stub cache.
- Handle<Code> code;
-
- switch (type) {
+ switch (lookup->type()) {
case FIELD:
- code = isolate()->stub_cache()->ComputeKeyedStoreField(
+ return isolate()->stub_cache()->ComputeKeyedStoreField(
name, receiver, lookup->GetFieldIndex().field_index(),
Handle<Map>::null(), strict_mode);
- break;
case TRANSITION: {
Handle<Map> transition(lookup->GetTransitionTarget());
int descriptor = transition->LastAdded();
@@ -1842,9 +1786,8 @@
if (details.type() == FIELD && details.attributes() == NONE) {
int field_index = target_descriptors->GetFieldIndex(descriptor);
- code = isolate()->stub_cache()->ComputeKeyedStoreField(
+ return isolate()->stub_cache()->ComputeKeyedStoreField(
name, receiver, field_index, transition, strict_mode);
- break;
}
// fall through.
}
@@ -1854,43 +1797,15 @@
case INTERCEPTOR:
// Always rewrite to the generic case so that we do not
// repeatedly try to rewrite.
- code = (strict_mode == kStrictMode)
+ return (strict_mode == kStrictMode)
? generic_stub_strict()
: generic_stub();
- break;
case HANDLER:
case NONEXISTENT:
UNREACHABLE();
- return;
- }
-
- ASSERT(!code.is_null());
-
- // Patch the call site depending on the state of the cache.
- switch (state) {
- case UNINITIALIZED:
- case PREMONOMORPHIC:
- case POLYMORPHIC:
- set_target(*code);
- break;
- case MONOMORPHIC:
- // Only move to megamorphic if the target changes.
- if (target() != *code) {
- set_target((strict_mode == kStrictMode)
- ? *megamorphic_stub_strict()
- : *megamorphic_stub());
- }
- break;
- case MEGAMORPHIC:
- case GENERIC:
- case DEBUG_STUB:
- break;
- case MONOMORPHIC_PROTOTYPE_FAILURE:
- UNREACHABLE();
break;
}
-
- TRACE_IC("KeyedStoreIC", name, state, target());
+ return Handle<Code>::null();
}
@@ -2013,9 +1928,9 @@
#endif
Object* result;
- { MaybeObject* maybe_result = receiver->SetElementsLength(len);
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
+ MaybeObject* maybe_result = receiver->SetElementsLength(len);
+ if (!maybe_result->To(&result)) return maybe_result;
+
return len;
}
diff --git a/src/ic.h b/src/ic.h
index 3ffe4e0..cea308b 100644
--- a/src/ic.h
+++ b/src/ic.h
@@ -165,6 +165,21 @@
static inline void SetTargetAtAddress(Address address, Code* target);
static void PostPatching(Address address, Code* target, Code* old_target);
+ void PatchCache(State state,
+ StrictModeFlag strict_mode,
+ Handle<JSObject> receiver,
+ Handle<String> name,
+ Handle<Code> code);
+ virtual void UpdateMegamorphicCache(Map* map, String* name, Code* code);
+ virtual Handle<Code> megamorphic_stub() {
+ UNREACHABLE();
+ return Handle<Code>::null();
+ }
+ virtual Handle<Code> megamorphic_stub_strict() {
+ UNREACHABLE();
+ return Handle<Code>::null();
+ }
+
private:
// Frame pointer for the frame that uses (calls) the IC.
Address fp_;
@@ -332,10 +347,6 @@
static void GenerateMegamorphic(MacroAssembler* masm);
static void GenerateNormal(MacroAssembler* masm);
- // Specialized code generator routines.
- static void GenerateArrayLength(MacroAssembler* masm);
- static void GenerateFunctionPrototype(MacroAssembler* masm);
-
MUST_USE_RESULT MaybeObject* Load(State state,
Handle<Object> object,
Handle<String> name);
@@ -361,7 +372,6 @@
virtual Handle<Code> ComputeLoadMonomorphic(LookupResult* lookup,
Handle<JSObject> receiver,
Handle<String> name);
- virtual void UpdateMegamorphicCache(Map* map, String* name, Code* code);
private:
// Stub accessors.
@@ -469,7 +479,6 @@
static void GenerateMiss(MacroAssembler* masm);
static void GenerateMegamorphic(MacroAssembler* masm,
StrictModeFlag strict_mode);
- static void GenerateArrayLength(MacroAssembler* masm);
static void GenerateNormal(MacroAssembler* masm);
static void GenerateGlobalProxy(MacroAssembler* masm,
StrictModeFlag strict_mode);
@@ -502,12 +511,19 @@
// Update the inline cache and the global stub cache based on the
// lookup result.
- virtual void UpdateStoreCaches(LookupResult* lookup,
- State state,
- StrictModeFlag strict_mode,
- Handle<JSObject> receiver,
- Handle<String> name,
- Handle<Object> value);
+ void UpdateCaches(LookupResult* lookup,
+ State state,
+ StrictModeFlag strict_mode,
+ Handle<JSObject> receiver,
+ Handle<String> name,
+ Handle<Object> value);
+ // Compute the code stub for this store; used for rewriting to
+ // monomorphic state and making sure that the code stub is in the
+ // stub cache.
+ virtual Handle<Code> ComputeStoreMonomorphic(LookupResult* lookup,
+ StrictModeFlag strict_mode,
+ Handle<JSObject> receiver,
+ Handle<String> name);
private:
void set_target(Code* code) {
@@ -607,13 +623,11 @@
protected:
virtual Code::Kind kind() const { return Code::KEYED_STORE_IC; }
- // Update the inline cache.
- virtual void UpdateStoreCaches(LookupResult* lookup,
- State state,
- StrictModeFlag strict_mode,
- Handle<JSObject> receiver,
- Handle<String> name,
- Handle<Object> value);
+ virtual Handle<Code> ComputeStoreMonomorphic(LookupResult* lookup,
+ StrictModeFlag strict_mode,
+ Handle<JSObject> receiver,
+ Handle<String> name);
+ virtual void UpdateMegamorphicCache(Map* map, String* name, Code* code) { }
virtual Handle<Code> megamorphic_stub() {
return isolate()->builtins()->KeyedStoreIC_Generic();
diff --git a/src/mksnapshot.cc b/src/mksnapshot.cc
index d777551..a3665e9 100644
--- a/src/mksnapshot.cc
+++ b/src/mksnapshot.cc
@@ -384,7 +384,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.Dispose(context->GetIsolate());
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 ef506fa..28d8762 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -3522,6 +3522,8 @@
kind() == COMPARE_IC ||
kind() == LOAD_IC ||
kind() == KEYED_LOAD_IC ||
+ kind() == STORE_IC ||
+ kind() == KEYED_STORE_IC ||
kind() == TO_BOOLEAN_IC);
ASSERT(0 <= major && major < 256);
int previous = READ_UINT32_FIELD(this, kKindSpecificFlags2Offset);
@@ -4927,7 +4929,9 @@
ASSERT(kind() == COMPARE_IC ||
kind() == BINARY_OP_IC ||
kind() == LOAD_IC ||
- kind() == KEYED_LOAD_IC);
+ kind() == KEYED_LOAD_IC ||
+ kind() == STORE_IC ||
+ kind() == KEYED_STORE_IC);
WRITE_FIELD(this, kTypeFeedbackInfoOffset, Smi::FromInt(value));
}
@@ -5075,17 +5079,6 @@
}
-void JSRegExp::ResetLastIndex(Isolate* isolate,
- Handle<JSRegExp> regexp) {
- // Reset lastIndex property to 0.
- SetProperty(regexp,
- isolate->factory()->last_index_symbol(),
- Handle<Smi>(Smi::FromInt(0)),
- ::NONE,
- kNonStrictMode);
-}
-
-
ElementsKind JSObject::GetElementsKind() {
ElementsKind kind = map()->elements_kind();
#if DEBUG
diff --git a/src/objects.h b/src/objects.h
index 958e1ef..975fdf8 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -6622,8 +6622,6 @@
inline void SetDataAtUnchecked(int index, Object* value, Heap* heap);
inline Type TypeTagUnchecked();
- static inline void ResetLastIndex(Isolate* isolate, Handle<JSRegExp> regexp);
-
static int code_index(bool is_ascii) {
if (is_ascii) {
return kIrregexpASCIICodeIndex;
diff --git a/src/profile-generator.cc b/src/profile-generator.cc
index a4e6596..0c7dc14 100644
--- a/src/profile-generator.cc
+++ b/src/profile-generator.cc
@@ -66,7 +66,9 @@
Handle<Object> handle = isolate->global_handles()->Create(token);
// handle.location() points to a memory cell holding a pointer
// to a token object in the V8's heap.
- isolate->global_handles()->MakeWeak(handle.location(), this,
+ isolate->global_handles()->MakeWeak(handle.location(),
+ this,
+ NULL,
TokenRemovedCallback);
token_locations_.Add(handle.location());
token_removed_.Add(false);
@@ -74,11 +76,12 @@
}
-void TokenEnumerator::TokenRemovedCallback(v8::Persistent<v8::Value> handle,
+void TokenEnumerator::TokenRemovedCallback(v8::Isolate* isolate,
+ v8::Persistent<v8::Value> handle,
void* parameter) {
reinterpret_cast<TokenEnumerator*>(parameter)->TokenRemoved(
Utils::OpenHandle(*handle).location());
- handle.Dispose();
+ handle.Dispose(isolate);
}
diff --git a/src/profile-generator.h b/src/profile-generator.h
index f306659..086e5c6 100644
--- a/src/profile-generator.h
+++ b/src/profile-generator.h
@@ -45,7 +45,8 @@
static const int kInheritsSecurityToken = -2;
private:
- static void TokenRemovedCallback(v8::Persistent<v8::Value> handle,
+ static void TokenRemovedCallback(v8::Isolate* isolate,
+ v8::Persistent<v8::Value> handle,
void* parameter);
void TokenRemoved(Object** token_location);
diff --git a/src/runtime.cc b/src/runtime.cc
index 5047dbd..e8003b6 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -2912,8 +2912,7 @@
int matches = indices.length();
if (matches == 0) {
- JSRegExp::ResetLastIndex(isolate, pattern_regexp);
- return *subject;
+ return isolate->heap()->undefined_value();
}
// Detect integer overflow.
@@ -3015,8 +3014,7 @@
int32_t* current_match = global_cache.FetchNext();
if (current_match == NULL) {
if (global_cache.HasException()) return Failure::Exception();
- JSRegExp::ResetLastIndex(isolate, regexp);
- return *subject;
+ return isolate->heap()->undefined_value();
}
// Guessing the number of parts that the final result string is built
@@ -3114,8 +3112,7 @@
int32_t* current_match = global_cache.FetchNext();
if (current_match == NULL) {
if (global_cache.HasException()) return Failure::Exception();
- JSRegExp::ResetLastIndex(isolate, regexp);
- return *subject;
+ return isolate->heap()->undefined_value();
}
int start = current_match[0];
diff --git a/src/string.js b/src/string.js
index 60a5abe..b39976c 100644
--- a/src/string.js
+++ b/src/string.js
@@ -194,6 +194,7 @@
// lastMatchInfo is defined in regexp.js.
var result = %StringMatch(subject, regexp, lastMatchInfo);
if (result !== null) lastMatchInfoOverride = null;
+ regexp.lastIndex = 0;
return result;
}
// Non-regexp argument.
@@ -244,13 +245,19 @@
}
} else {
if (lastMatchInfoOverride == null) {
- return %StringReplaceRegExpWithString(subject,
- search,
- TO_STRING_INLINE(replace),
- lastMatchInfo);
+ var answer = %StringReplaceRegExpWithString(subject,
+ search,
+ TO_STRING_INLINE(replace),
+ lastMatchInfo);
+ if (IS_UNDEFINED(answer)) { // No match. Return subject string.
+ search.lastIndex = 0;
+ return subject;
+ }
+ if (search.global) search.lastIndex = 0;
+ return answer;
} else {
// We use this hack to detect whether StringReplaceRegExpWithString
- // found at least one hit. In that case we need to remove any
+ // found at least one hit. In that case we need to remove any
// override.
var saved_subject = lastMatchInfo[LAST_SUBJECT_INDEX];
lastMatchInfo[LAST_SUBJECT_INDEX] = 0;
@@ -258,11 +265,17 @@
search,
TO_STRING_INLINE(replace),
lastMatchInfo);
+ if (IS_UNDEFINED(answer)) { // No match. Return subject string.
+ search.lastIndex = 0;
+ lastMatchInfo[LAST_SUBJECT_INDEX] = saved_subject;
+ return subject;
+ }
if (%_IsSmi(lastMatchInfo[LAST_SUBJECT_INDEX])) {
lastMatchInfo[LAST_SUBJECT_INDEX] = saved_subject;
} else {
lastMatchInfoOverride = null;
}
+ if (search.global) search.lastIndex = 0;
return answer;
}
}
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index 43d0ab9..e6722f7 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -774,11 +774,10 @@
}
-Handle<Code> StubCache::ComputeCallArguments(int argc, Code::Kind kind) {
- ASSERT(kind == Code::KEYED_CALL_IC);
+Handle<Code> StubCache::ComputeCallArguments(int argc) {
Code::Flags flags =
- Code::ComputeFlags(kind, MEGAMORPHIC, Code::kNoExtraICState,
- Code::NORMAL, argc);
+ Code::ComputeFlags(Code::KEYED_CALL_IC, MEGAMORPHIC,
+ Code::kNoExtraICState, Code::NORMAL, argc);
Handle<UnseededNumberDictionary> cache =
isolate_->factory()->non_monomorphic_cache();
int entry = cache->FindEntry(isolate_, flags);
diff --git a/src/stub-cache.h b/src/stub-cache.h
index b26519c..5becb11 100644
--- a/src/stub-cache.h
+++ b/src/stub-cache.h
@@ -227,7 +227,7 @@
Code::Kind kind,
Code::ExtraICState state);
- Handle<Code> ComputeCallArguments(int argc, Code::Kind kind);
+ Handle<Code> ComputeCallArguments(int argc);
Handle<Code> ComputeCallMegamorphic(int argc,
Code::Kind kind,
@@ -485,8 +485,8 @@
Register scratch2,
Label* miss_label);
- static void GenerateLoadMiss(MacroAssembler* masm,
- Code::Kind kind);
+ static void GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind);
+ static void GenerateStoreMiss(MacroAssembler* masm, Code::Kind kind);
static void GenerateKeyedLoadMissForceGeneric(MacroAssembler* masm);
diff --git a/src/version.cc b/src/version.cc
index d1f6a48..e9e38f2 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 3
#define MINOR_VERSION 16
-#define BUILD_NUMBER 9
+#define BUILD_NUMBER 10
#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index 6bef42f..a0424ac 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -2442,6 +2442,68 @@
}
+void StoreArrayLengthStub::Generate(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- rax : value
+ // -- rcx : key
+ // -- rdx : receiver
+ // -- rsp[0] : return address
+ // -----------------------------------
+ //
+ // This accepts as a receiver anything JSArray::SetElementsLength accepts
+ // (currently anything except for external arrays which means anything with
+ // elements of FixedArray type). Value must be a number, but only smis are
+ // accepted as the most common case.
+
+ Label miss;
+
+ Register receiver = rdx;
+ Register value = rax;
+ Register scratch = rbx;
+ if (kind() == Code::KEYED_STORE_IC) {
+ __ Cmp(rcx, masm->isolate()->factory()->length_symbol());
+ }
+
+ // Check that the receiver isn't a smi.
+ __ JumpIfSmi(receiver, &miss);
+
+ // Check that the object is a JS array.
+ __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
+ __ j(not_equal, &miss);
+
+ // Check that elements are FixedArray.
+ // We rely on StoreIC_ArrayLength below to deal with all types of
+ // fast elements (including COW).
+ __ movq(scratch, FieldOperand(receiver, JSArray::kElementsOffset));
+ __ CmpObjectType(scratch, FIXED_ARRAY_TYPE, scratch);
+ __ j(not_equal, &miss);
+
+ // Check that the array has fast properties, otherwise the length
+ // property might have been redefined.
+ __ movq(scratch, FieldOperand(receiver, JSArray::kPropertiesOffset));
+ __ CompareRoot(FieldOperand(scratch, FixedArray::kMapOffset),
+ Heap::kHashTableMapRootIndex);
+ __ j(equal, &miss);
+
+ // Check that value is a smi.
+ __ JumpIfNotSmi(value, &miss);
+
+ // Prepare tail call to StoreIC_ArrayLength.
+ __ pop(scratch);
+ __ push(receiver);
+ __ push(value);
+ __ push(scratch); // return address
+
+ ExternalReference ref =
+ ExternalReference(IC_Utility(IC::kStoreIC_ArrayLength), masm->isolate());
+ __ TailCallExternalReference(ref, 2, 1);
+
+ __ bind(&miss);
+
+ StubCompiler::GenerateStoreMiss(masm, kind());
+}
+
+
void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
// The key is in rdx and the parameter count is in rax.
diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc
index fc7f9b1..3911438 100644
--- a/src/x64/ic-x64.cc
+++ b/src/x64/ic-x64.cc
@@ -1455,65 +1455,6 @@
}
-void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- rax : value
- // -- rcx : name
- // -- rdx : receiver
- // -- rsp[0] : return address
- // -----------------------------------
- //
- // This accepts as a receiver anything JSArray::SetElementsLength accepts
- // (currently anything except for external arrays which means anything with
- // elements of FixedArray type). Value must be a number, but only smis are
- // accepted as the most common case.
-
- Label miss;
-
- Register receiver = rdx;
- Register value = rax;
- Register scratch = rbx;
-
- // Check that the receiver isn't a smi.
- __ JumpIfSmi(receiver, &miss);
-
- // Check that the object is a JS array.
- __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
- __ j(not_equal, &miss);
-
- // Check that elements are FixedArray.
- // We rely on StoreIC_ArrayLength below to deal with all types of
- // fast elements (including COW).
- __ movq(scratch, FieldOperand(receiver, JSArray::kElementsOffset));
- __ CmpObjectType(scratch, FIXED_ARRAY_TYPE, scratch);
- __ j(not_equal, &miss);
-
- // Check that the array has fast properties, otherwise the length
- // property might have been redefined.
- __ movq(scratch, FieldOperand(receiver, JSArray::kPropertiesOffset));
- __ CompareRoot(FieldOperand(scratch, FixedArray::kMapOffset),
- Heap::kHashTableMapRootIndex);
- __ j(equal, &miss);
-
- // Check that value is a smi.
- __ JumpIfNotSmi(value, &miss);
-
- // Prepare tail call to StoreIC_ArrayLength.
- __ pop(scratch);
- __ push(receiver);
- __ push(value);
- __ push(scratch); // return address
-
- ExternalReference ref =
- ExternalReference(IC_Utility(kStoreIC_ArrayLength), masm->isolate());
- __ TailCallExternalReference(ref, 2, 1);
-
- __ bind(&miss);
-
- GenerateMiss(masm);
-}
-
-
void StoreIC::GenerateNormal(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : value
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index 384e5c0..ba6321a 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -723,6 +723,15 @@
}
+void StubCompiler::GenerateStoreMiss(MacroAssembler* masm, Code::Kind kind) {
+ ASSERT(kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC);
+ Handle<Code> code = (kind == Code::STORE_IC)
+ ? masm->isolate()->builtins()->StoreIC_Miss()
+ : masm->isolate()->builtins()->KeyedStoreIC_Miss();
+ __ Jump(code, RelocInfo::CODE_TARGET);
+}
+
+
void StubCompiler::GenerateKeyedLoadMissForceGeneric(MacroAssembler* masm) {
Handle<Code> code =
masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
diff --git a/test/cctest/cctest.h b/test/cctest/cctest.h
index f9f3b42..44690b3 100644
--- a/test/cctest/cctest.h
+++ b/test/cctest/cctest.h
@@ -179,11 +179,13 @@
v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>())
: context_(v8::Context::New(extensions, global_template, global_object)) {
context_->Enter();
+ // We can't do this later perhaps because of a fatal error.
+ isolate_ = context_->GetIsolate();
}
virtual ~LocalContext() {
context_->Exit();
- context_.Dispose();
+ context_.Dispose(isolate_);
}
v8::Context* operator->() { return *context_; }
@@ -196,6 +198,7 @@
private:
v8::Persistent<v8::Context> context_;
+ v8::Isolate* isolate_;
};
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index ca027df..341459e 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -181,7 +181,7 @@
CHECK(!env->InContext());
CHECK(env->GetIsolate() == v8::Isolate::GetCurrent());
- env.Dispose();
+ env.Dispose(env->GetIsolate());
}
@@ -2317,22 +2317,23 @@
THREADED_TEST(GlobalHandle) {
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Persistent<String> global;
{
v8::HandleScope scope;
Local<String> str = v8_str("str");
- global = v8::Persistent<String>::New(str);
+ global = v8::Persistent<String>::New(isolate, str);
}
CHECK_EQ(global->Length(), 3);
- global.Dispose();
+ global.Dispose(isolate);
{
v8::HandleScope scope;
Local<String> str = v8_str("str");
- global = v8::Persistent<String>::New(str);
+ global = v8::Persistent<String>::New(isolate, str);
}
CHECK_EQ(global->Length(), 3);
- global.Dispose(v8::Isolate::GetCurrent());
+ global.Dispose(isolate);
}
@@ -2358,17 +2359,20 @@
};
-static void WeakPointerCallback(Persistent<Value> handle, void* id) {
+static void WeakPointerCallback(v8::Isolate* isolate,
+ Persistent<Value> handle,
+ void* id) {
WeakCallCounter* counter = reinterpret_cast<WeakCallCounter*>(id);
CHECK_EQ(1234, counter->id());
counter->increment();
- handle.Dispose();
+ handle.Dispose(isolate);
}
THREADED_TEST(ApiObjectGroups) {
HandleScope scope;
LocalContext env;
+ v8::Isolate* iso = env->GetIsolate();
Persistent<Object> g1s1;
Persistent<Object> g1s2;
@@ -2381,22 +2385,22 @@
{
HandleScope scope;
- g1s1 = Persistent<Object>::New(Object::New());
- g1s2 = Persistent<Object>::New(Object::New());
- g1c1 = Persistent<Object>::New(Object::New());
- g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
- g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
- g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
+ g1s1 = Persistent<Object>::New(iso, Object::New());
+ g1s2 = Persistent<Object>::New(iso, Object::New());
+ g1c1 = Persistent<Object>::New(iso, Object::New());
+ g1s1.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
+ g1s2.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
+ g1c1.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
- g2s1 = Persistent<Object>::New(Object::New());
- g2s2 = Persistent<Object>::New(Object::New());
- g2c1 = Persistent<Object>::New(Object::New());
- g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
- g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
- g2c1.MakeWeak(reinterpret_cast<void*>(&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, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
+ g2s2.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
+ g2c1.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
}
- Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
+ Persistent<Object> root = Persistent<Object>::New(iso, g1s1); // make a root.
// Connect group 1 and 2, make a cycle.
CHECK(g1s2->Set(0, g2s2));
@@ -2419,11 +2423,11 @@
CHECK_EQ(0, counter.NumberOfWeakCalls());
// Weaken the root.
- root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
+ root.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
// But make children strong roots---all the objects (except for children)
// should be collectable now.
- g1c1.ClearWeak();
- g2c1.ClearWeak();
+ g1c1.ClearWeak(iso);
+ g2c1.ClearWeak(iso);
// Groups are deleted, rebuild groups.
{
@@ -2443,8 +2447,8 @@
CHECK_EQ(5, counter.NumberOfWeakCalls());
// And now make children weak again and collect them.
- g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
- g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
+ g1c1.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
+ g2c1.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
CHECK_EQ(7, counter.NumberOfWeakCalls());
@@ -2454,6 +2458,7 @@
THREADED_TEST(ApiObjectGroupsCycle) {
HandleScope scope;
LocalContext env;
+ v8::Isolate* iso = env->GetIsolate();
WeakCallCounter counter(1234);
@@ -2466,41 +2471,38 @@
Persistent<Object> g4s1;
Persistent<Object> g4s2;
- v8::Isolate* isolate = v8::Isolate::GetCurrent();
{
HandleScope scope;
- g1s1 = Persistent<Object>::New(Object::New());
- g1s2 = Persistent<Object>::New(Object::New());
- g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
- g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
- CHECK(g1s1.IsWeak());
- CHECK(g1s2.IsWeak());
+ g1s1 = Persistent<Object>::New(iso, Object::New());
+ g1s2 = Persistent<Object>::New(iso, Object::New());
+ g1s1.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
+ g1s2.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
+ CHECK(g1s1.IsWeak(iso));
+ CHECK(g1s2.IsWeak(iso));
- g2s1 = Persistent<Object>::New(Object::New());
- g2s2 = Persistent<Object>::New(Object::New());
- g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
- g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
- CHECK(g2s1.IsWeak());
- CHECK(g2s2.IsWeak());
+ g2s1 = Persistent<Object>::New(iso, Object::New());
+ g2s2 = Persistent<Object>::New(iso, Object::New());
+ g2s1.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
+ g2s2.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
+ CHECK(g2s1.IsWeak(iso));
+ CHECK(g2s2.IsWeak(iso));
- g3s1 = Persistent<Object>::New(Object::New());
- g3s2 = Persistent<Object>::New(Object::New());
- g3s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
- g3s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
- CHECK(g3s1.IsWeak());
- CHECK(g3s2.IsWeak());
+ g3s1 = Persistent<Object>::New(iso, Object::New());
+ g3s2 = Persistent<Object>::New(iso, Object::New());
+ g3s1.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
+ g3s2.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
+ CHECK(g3s1.IsWeak(iso));
+ CHECK(g3s2.IsWeak(iso));
- g4s1 = Persistent<Object>::New(Object::New());
- g4s2 = Persistent<Object>::New(Object::New());
- g4s1.MakeWeak(isolate,
- reinterpret_cast<void*>(&counter), &WeakPointerCallback);
- g4s2.MakeWeak(isolate,
- reinterpret_cast<void*>(&counter), &WeakPointerCallback);
- CHECK(g4s1.IsWeak(isolate));
- CHECK(g4s2.IsWeak(isolate));
+ g4s1 = Persistent<Object>::New(iso, Object::New());
+ g4s2 = Persistent<Object>::New(iso, Object::New());
+ g4s1.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
+ g4s2.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
+ CHECK(g4s1.IsWeak(iso));
+ CHECK(g4s2.IsWeak(iso));
}
- Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
+ 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
@@ -2520,7 +2522,7 @@
V8::AddImplicitReferences(g2s1, g2_children, 1);
V8::AddObjectGroup(g3_objects, 2);
V8::AddImplicitReferences(g3s1, g3_children, 1);
- V8::AddObjectGroup(isolate, g4_objects, 2);
+ V8::AddObjectGroup(iso, g4_objects, 2);
V8::AddImplicitReferences(g4s1, g4_children, 1);
}
// Do a single full GC
@@ -2530,7 +2532,7 @@
CHECK_EQ(0, counter.NumberOfWeakCalls());
// Weaken the root.
- root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
+ root.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
// Groups are deleted, rebuild groups.
{
@@ -2566,6 +2568,7 @@
i::FLAG_gc_global = false;
HandleScope scope;
LocalContext env;
+ v8::Isolate* iso = env->GetIsolate();
WeakCallCounter counter(1234);
@@ -2578,36 +2581,36 @@
{
HandleScope scope;
- g1s1 = Persistent<Object>::New(Object::New());
- g1s2 = Persistent<Object>::New(Object::New());
- g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
- g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
+ g1s1 = Persistent<Object>::New(iso, Object::New());
+ g1s2 = Persistent<Object>::New(iso, Object::New());
+ g1s1.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
+ g1s2.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
- g2s1 = Persistent<Object>::New(Object::New());
- g2s2 = Persistent<Object>::New(Object::New());
- g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
- g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
+ g2s1 = Persistent<Object>::New(iso, Object::New());
+ g2s2 = Persistent<Object>::New(iso, Object::New());
+ g2s1.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
+ g2s2.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
- g3s1 = Persistent<Object>::New(Object::New());
- g3s2 = Persistent<Object>::New(Object::New());
- g3s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
- g3s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
+ g3s1 = Persistent<Object>::New(iso, Object::New());
+ g3s2 = Persistent<Object>::New(iso, Object::New());
+ g3s1.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
+ g3s2.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
}
// Make a root.
- Persistent<Object> root = Persistent<Object>::New(g1s1);
- root.MarkPartiallyDependent();
+ 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();
- g1s2.MarkPartiallyDependent();
- g2s1.MarkPartiallyDependent();
- g2s2.MarkPartiallyDependent();
- g3s1.MarkPartiallyDependent();
- g3s2.MarkPartiallyDependent();
+ 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 };
@@ -2625,8 +2628,8 @@
CHECK_EQ(0, counter.NumberOfWeakCalls());
// Weaken the root.
- root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
- root.MarkPartiallyDependent();
+ root.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
+ root.MarkPartiallyDependent(iso);
v8::Isolate* isolate = v8::Isolate::GetCurrent();
// Groups are deleted, rebuild groups.
@@ -3759,6 +3762,7 @@
THREADED_TEST(Equality) {
v8::HandleScope scope;
LocalContext context;
+ v8::Isolate* isolate = context->GetIsolate();
// Check that equality works at all before relying on CHECK_EQ
CHECK(v8_str("a")->Equals(v8_str("a")));
CHECK(!v8_str("a")->Equals(v8_str("b")));
@@ -3782,9 +3786,10 @@
CHECK(!v8::False()->StrictEquals(v8::Undefined()));
v8::Handle<v8::Object> obj = v8::Object::New();
- v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
+ v8::Persistent<v8::Object> alias =
+ v8::Persistent<v8::Object>::New(isolate, obj);
CHECK(alias->StrictEquals(obj));
- alias.Dispose();
+ alias.Dispose(isolate);
}
@@ -4082,7 +4087,7 @@
CHECK_EQ(info.Data(), v8_str("donut"));
CHECK_EQ(name, v8_str("x"));
CHECK(xValue.IsEmpty());
- xValue = v8::Persistent<Value>::New(value);
+ xValue = v8::Persistent<Value>::New(info.GetIsolate(), value);
}
@@ -4097,7 +4102,7 @@
CHECK(xValue.IsEmpty());
script->Run();
CHECK_EQ(v8_num(4), xValue);
- xValue.Dispose();
+ xValue.Dispose(context->GetIsolate());
xValue = v8::Persistent<Value>();
}
}
@@ -4114,7 +4119,7 @@
CHECK(xValue.IsEmpty());
script->Run();
CHECK_EQ(v8_num(4), xValue);
- xValue.Dispose();
+ xValue.Dispose(context->GetIsolate());
xValue = v8::Persistent<Value>();
}
}
@@ -4224,7 +4229,7 @@
CompileRun("var obj = { x : 0 }; delete obj.x;");
context1->Exit();
- context1.Dispose();
+ context1.Dispose(context1->GetIsolate());
}
@@ -4977,17 +4982,17 @@
// This test is not intended to be run, just type checked.
-static inline void PersistentHandles() {
+static inline void PersistentHandles(v8::Isolate* isolate) {
USE(PersistentHandles);
Local<String> str = v8_str("foo");
- v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
+ v8::Persistent<String> p_str = v8::Persistent<String>::New(isolate, str);
USE(p_str);
Local<Script> scr = Script::Compile(v8_str(""));
- v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
+ v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(isolate, scr);
USE(p_scr);
Local<ObjectTemplate> templ = ObjectTemplate::New();
v8::Persistent<ObjectTemplate> p_templ =
- v8::Persistent<ObjectTemplate>::New(templ);
+ v8::Persistent<ObjectTemplate>::New(isolate, templ);
USE(p_templ);
}
@@ -5006,7 +5011,7 @@
v8::Persistent<Context> context = Context::New(0, global_template);
Context::Scope context_scope(context);
Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
- context.Dispose();
+ context.Dispose(context->GetIsolate());
}
@@ -5475,29 +5480,30 @@
class Whammy {
public:
- Whammy() {
- cursor_ = 0;
- }
- ~Whammy() {
- script_.Dispose();
- }
+ 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(v8_compile("({}).blammo"));
+ if (script_.IsEmpty()) {
+ script_ = v8::Persistent<Script>::New(isolate_,
+ v8_compile("({}).blammo"));
+ }
return Local<Script>(*script_);
}
public:
static const int kObjectCount = 256;
int cursor_;
+ v8::Isolate* isolate_;
v8::Persistent<v8::Object> objects_[kObjectCount];
v8::Persistent<Script> script_;
};
-static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
+static void HandleWeakReference(v8::Isolate* isolate,
+ v8::Persistent<v8::Value> obj,
+ void* data) {
Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
delete snorkel;
- obj.ClearWeak();
+ obj.ClearWeak(isolate);
}
v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
@@ -5508,10 +5514,11 @@
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(obj);
+ v8::Persistent<v8::Object> global =
+ v8::Persistent<v8::Object>::New(info.GetIsolate(), obj);
if (!prev.IsEmpty()) {
prev->Set(v8_str("next"), obj);
- prev.MakeWeak(new Snorkel(), &HandleWeakReference);
+ prev.MakeWeak(info.GetIsolate(), new Snorkel(), &HandleWeakReference);
whammy->objects_[whammy->cursor_].Clear();
}
whammy->objects_[whammy->cursor_] = global;
@@ -5522,7 +5529,7 @@
THREADED_TEST(WeakReference) {
v8::HandleScope handle_scope;
v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
- Whammy* whammy = new Whammy();
+ Whammy* whammy = new Whammy(v8::Isolate::GetCurrent());
templ->SetNamedPropertyHandler(WhammyPropertyGetter,
0, 0, 0, 0,
v8::External::New(whammy));
@@ -5545,12 +5552,14 @@
v8::Handle<Value> result = CompileRun(code);
CHECK_EQ(4.0, result->NumberValue());
delete whammy;
- context.Dispose();
+ context.Dispose(context->GetIsolate());
}
-static void DisposeAndSetFlag(v8::Persistent<v8::Value> obj, void* data) {
- obj.Dispose();
+static void DisposeAndSetFlag(v8::Isolate* isolate,
+ v8::Persistent<v8::Value> obj,
+ void* data) {
+ obj.Dispose(isolate);
obj.Clear();
*(reinterpret_cast<bool*>(data)) = true;
}
@@ -5558,27 +5567,25 @@
THREADED_TEST(IndependentWeakHandle) {
v8::Persistent<Context> context = Context::New();
+ v8::Isolate* iso = context->GetIsolate();
Context::Scope context_scope(context);
v8::Persistent<v8::Object> object_a, object_b;
{
v8::HandleScope handle_scope;
- object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
- object_b = v8::Persistent<v8::Object>::New(v8::Object::New());
+ object_a = v8::Persistent<v8::Object>::New(iso, v8::Object::New());
+ object_b = v8::Persistent<v8::Object>::New(iso, v8::Object::New());
}
- v8::Isolate* isolate = v8::Isolate::GetCurrent();
bool object_a_disposed = false;
bool object_b_disposed = false;
- object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
- object_b.MakeWeak(&object_b_disposed, &DisposeAndSetFlag);
- CHECK(!object_a.IsIndependent());
- CHECK(!object_b.IsIndependent(isolate));
- object_a.MarkIndependent();
- object_b.MarkIndependent(isolate);
- CHECK(object_a.IsIndependent());
- CHECK(object_b.IsIndependent(isolate));
+ object_a.MakeWeak(iso, &object_a_disposed, &DisposeAndSetFlag);
+ object_b.MakeWeak(iso, &object_b_disposed, &DisposeAndSetFlag);
+ CHECK(!object_b.IsIndependent(iso));
+ object_a.MarkIndependent(iso);
+ object_b.MarkIndependent(iso);
+ CHECK(object_b.IsIndependent(iso));
HEAP->PerformScavenge();
CHECK(object_a_disposed);
CHECK(object_b_disposed);
@@ -5595,16 +5602,20 @@
}
-static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
- obj.Dispose();
+static void ForceScavenge(v8::Isolate* isolate,
+ v8::Persistent<v8::Value> obj,
+ void* data) {
+ obj.Dispose(isolate);
obj.Clear();
*(reinterpret_cast<bool*>(data)) = true;
InvokeScavenge();
}
-static void ForceMarkSweep(v8::Persistent<v8::Value> obj, void* data) {
- obj.Dispose();
+static void ForceMarkSweep(v8::Isolate* isolate,
+ v8::Persistent<v8::Value> obj,
+ void* data) {
+ obj.Dispose(isolate);
obj.Clear();
*(reinterpret_cast<bool*>(data)) = true;
InvokeMarkSweep();
@@ -5613,10 +5624,11 @@
THREADED_TEST(GCFromWeakCallbacks) {
v8::Persistent<Context> context = Context::New();
+ v8::Isolate* isolate = context->GetIsolate();
Context::Scope context_scope(context);
static const int kNumberOfGCTypes = 2;
- v8::WeakReferenceCallback gc_forcing_callback[kNumberOfGCTypes] =
+ v8::NearDeathCallback gc_forcing_callback[kNumberOfGCTypes] =
{&ForceScavenge, &ForceMarkSweep};
typedef void (*GCInvoker)();
@@ -5627,11 +5639,11 @@
v8::Persistent<v8::Object> object;
{
v8::HandleScope handle_scope;
- object = v8::Persistent<v8::Object>::New(v8::Object::New());
+ object = v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
}
bool disposed = false;
- object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
- object.MarkIndependent();
+ object.MakeWeak(isolate, &disposed, gc_forcing_callback[inner_gc]);
+ object.MarkIndependent(isolate);
invoke_gc[outer_gc]();
CHECK(disposed);
}
@@ -5639,8 +5651,10 @@
}
-static void RevivingCallback(v8::Persistent<v8::Value> obj, void* data) {
- obj.ClearWeak();
+static void RevivingCallback(v8::Isolate* isolate,
+ v8::Persistent<v8::Value> obj,
+ void* data) {
+ obj.ClearWeak(isolate);
*(reinterpret_cast<bool*>(data)) = true;
}
@@ -5648,18 +5662,19 @@
THREADED_TEST(IndependentHandleRevival) {
v8::Persistent<Context> context = Context::New();
Context::Scope context_scope(context);
+ v8::Isolate* isolate = context->GetIsolate();
v8::Persistent<v8::Object> object;
{
v8::HandleScope handle_scope;
- object = v8::Persistent<v8::Object>::New(v8::Object::New());
+ object = v8::Persistent<v8::Object>::New(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);
}
bool revived = false;
- object.MakeWeak(&revived, &RevivingCallback);
- object.MarkIndependent();
+ object.MakeWeak(isolate, &revived, &RevivingCallback);
+ object.MarkIndependent(isolate);
HEAP->PerformScavenge();
CHECK(revived);
HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
@@ -6755,10 +6770,10 @@
}
context1->Exit();
- context1.Dispose();
+ context1.Dispose(context1->GetIsolate());
context0->Exit();
- context0.Dispose();
+ context0.Dispose(context0->GetIsolate());
}
@@ -6802,7 +6817,7 @@
CHECK(try_catch.HasCaught());
}
- env2.Dispose();
+ env2.Dispose(env2->GetIsolate());
}
@@ -6871,7 +6886,7 @@
CHECK(!access_f3->Run()->Equals(v8_num(101)));
CHECK(access_f3->Run()->IsUndefined());
}
- other.Dispose();
+ other.Dispose(other->GetIsolate());
}
@@ -6904,7 +6919,7 @@
CHECK(v->IsNumber());
CHECK_EQ(3, v->Int32Value());
- env2.Dispose();
+ env2.Dispose(env2->GetIsolate());
}
@@ -6939,7 +6954,7 @@
CHECK(result->IsFalse());
}
- env2.Dispose();
+ env2.Dispose(env2->GetIsolate());
}
@@ -6972,7 +6987,7 @@
"return true;})()");
CHECK(result->IsTrue());
}
- env2.Dispose();
+ env2.Dispose(env2->GetIsolate());
}
@@ -7035,8 +7050,8 @@
CHECK(r->IsUndefined());
}
- env2.Dispose();
- env3.Dispose();
+ env2.Dispose(env2->GetIsolate());
+ env3.Dispose(env3->GetIsolate());
}
@@ -7114,8 +7129,8 @@
CHECK(result->IsInt32());
CHECK_EQ(42, result->Int32Value());
- env2.Dispose();
- env3.Dispose();
+ env2.Dispose(env2->GetIsolate());
+ env3.Dispose(env3->GetIsolate());
}
@@ -7405,8 +7420,8 @@
context1->Exit();
context0->Exit();
- context1.Dispose();
- context0.Dispose();
+ context1.Dispose(context1->GetIsolate());
+ context0.Dispose(context0->GetIsolate());
}
@@ -7534,8 +7549,8 @@
context1->Exit();
context0->Exit();
- context1.Dispose();
- context0.Dispose();
+ context1.Dispose(context1->GetIsolate());
+ context0.Dispose(context0->GetIsolate());
}
@@ -7618,8 +7633,8 @@
context1->Exit();
context0->Exit();
- context1.Dispose();
- context0.Dispose();
+ context1.Dispose(context1->GetIsolate());
+ context0.Dispose(context0->GetIsolate());
}
@@ -7753,8 +7768,8 @@
context1->Exit();
context0->Exit();
- context1.Dispose();
- context0.Dispose();
+ context1.Dispose(context1->GetIsolate());
+ context0.Dispose(context0->GetIsolate());
}
@@ -7828,8 +7843,8 @@
context1->Exit();
context0->Exit();
- context1.Dispose();
- context0.Dispose();
+ context1.Dispose(context1->GetIsolate());
+ context0.Dispose(context0->GetIsolate());
}
@@ -7920,8 +7935,8 @@
context1->Exit();
context0->Exit();
- context1.Dispose();
- context0.Dispose();
+ context1.Dispose(context1->GetIsolate());
+ context0.Dispose(context0->GetIsolate());
}
@@ -8811,8 +8826,8 @@
CHECK(catcher.HasCaught());
context1->Exit();
- context1.Dispose();
- context0.Dispose();
+ context1.Dispose(context1->GetIsolate());
+ context0.Dispose(context0->GetIsolate());
}
@@ -11329,79 +11344,90 @@
v8::Persistent<v8::Object> some_object;
v8::Persistent<v8::Object> bad_handle;
-void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
+void NewPersistentHandleCallback(v8::Isolate* isolate,
+ v8::Persistent<v8::Value> handle,
+ void*) {
v8::HandleScope scope;
- bad_handle = v8::Persistent<v8::Object>::New(some_object);
- handle.Dispose();
+ bad_handle = v8::Persistent<v8::Object>::New(isolate, some_object);
+ handle.Dispose(isolate);
}
THREADED_TEST(NewPersistentHandleFromWeakCallback) {
LocalContext context;
+ v8::Isolate* isolate = context->GetIsolate();
v8::Persistent<v8::Object> handle1, handle2;
{
v8::HandleScope scope;
- some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
- handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
- handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
+ 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());
}
// Note: order is implementation dependent alas: currently
// global handle nodes are processed by PostGarbageCollectionProcessing
// in reverse allocation order, so if second allocated handle is deleted,
// weak callback of the first handle would be able to 'reallocate' it.
- handle1.MakeWeak(NULL, NewPersistentHandleCallback);
- handle2.Dispose();
+ handle1.MakeWeak(isolate, NULL, NewPersistentHandleCallback);
+ handle2.Dispose(isolate);
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
}
v8::Persistent<v8::Object> to_be_disposed;
-void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
- to_be_disposed.Dispose();
+void DisposeAndForceGcCallback(v8::Isolate* isolate,
+ v8::Persistent<v8::Value> handle,
+ void*) {
+ to_be_disposed.Dispose(isolate);
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
- handle.Dispose();
+ handle.Dispose(isolate);
}
THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
LocalContext context;
+ v8::Isolate* isolate = context->GetIsolate();
v8::Persistent<v8::Object> handle1, handle2;
{
v8::HandleScope scope;
- handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
- handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
+ handle1 = v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
+ handle2 = v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
}
- handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
+ handle1.MakeWeak(isolate, NULL, DisposeAndForceGcCallback);
to_be_disposed = handle2;
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
}
-void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
- handle.Dispose();
+void DisposingCallback(v8::Isolate* isolate,
+ v8::Persistent<v8::Value> handle,
+ void*) {
+ handle.Dispose(isolate);
}
-void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
+void HandleCreatingCallback(v8::Isolate* isolate,
+ v8::Persistent<v8::Value> handle,
+ void*) {
v8::HandleScope scope;
- v8::Persistent<v8::Object>::New(v8::Object::New());
- handle.Dispose();
+ v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
+ handle.Dispose(isolate);
}
THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
LocalContext context;
+ v8::Isolate* isolate = context->GetIsolate();
v8::Persistent<v8::Object> handle1, handle2, handle3;
{
v8::HandleScope scope;
- handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
- handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
- handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
+ 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());
}
- handle2.MakeWeak(NULL, DisposingCallback);
- handle3.MakeWeak(NULL, HandleCreatingCallback);
+ handle2.MakeWeak(isolate, NULL, DisposingCallback);
+ handle3.MakeWeak(isolate, NULL, HandleCreatingCallback);
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
}
@@ -11447,7 +11473,7 @@
v8::Handle<String> str(value->ToString());
CHECK(!str.IsEmpty());
env->Exit();
- env.Dispose();
+ env.Dispose(env->GetIsolate());
}
@@ -11769,7 +11795,7 @@
LocalContext outer;
{ v8::Persistent<v8::Context> inner = v8::Context::New();
inner->Enter();
- inner.Dispose();
+ inner.Dispose(inner->GetIsolate());
inner.Clear();
inner->Exit();
}
@@ -11782,12 +11808,14 @@
THREADED_TEST(Regress54) {
v8::HandleScope outer;
LocalContext context;
+ v8::Isolate* isolate = context->GetIsolate();
static v8::Persistent<v8::ObjectTemplate> templ;
if (templ.IsEmpty()) {
v8::HandleScope inner;
v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
local->SetInternalFieldCount(1);
- templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
+ templ =
+ v8::Persistent<v8::ObjectTemplate>::New(isolate, inner.Close(local));
}
v8::Handle<v8::Object> result = templ->NewInstance();
CHECK_EQ(1, result->InternalFieldCount());
@@ -12476,8 +12504,8 @@
context1->Exit();
// Dispose the contexts to allow them to be garbage collected.
- context0.Dispose();
- context1.Dispose();
+ context0.Dispose(context0->GetIsolate());
+ context1.Dispose(context1->GetIsolate());
}
@@ -13292,9 +13320,9 @@
"ReferenceError: G is not defined");
ctx2->Exit();
ctx1->Exit();
- ctx1.Dispose();
+ ctx1.Dispose(ctx1->GetIsolate());
}
- ctx2.Dispose();
+ ctx2.Dispose(ctx2->GetIsolate());
}
@@ -13353,9 +13381,9 @@
calling_context2->Exit();
// Dispose the contexts to allow them to be garbage collected.
- calling_context0.Dispose();
- calling_context1.Dispose();
- calling_context2.Dispose();
+ calling_context0.Dispose(calling_context0->GetIsolate());
+ calling_context1.Dispose(calling_context1->GetIsolate());
+ calling_context2.Dispose(calling_context2->GetIsolate());
calling_context0.Clear();
calling_context1.Clear();
calling_context2.Clear();
@@ -15077,7 +15105,7 @@
ctx->Enter();
CreateGarbageInOldSpace();
ctx->Exit();
- ctx.Dispose();
+ ctx.Dispose(ctx->GetIsolate());
v8::V8::ContextDisposedNotification();
v8::V8::IdleNotification(kLongIdlePauseInMs);
}
@@ -15429,7 +15457,7 @@
CompileRun(source_simple);
context->Exit();
}
- context.Dispose();
+ context.Dispose(context->GetIsolate());
v8::V8::ContextDisposedNotification();
for (gc_count = 1; gc_count < 10; gc_count++) {
other_context->Enter();
@@ -15452,7 +15480,7 @@
CompileRun(source_eval);
context->Exit();
}
- context.Dispose();
+ context.Dispose(context->GetIsolate());
v8::V8::ContextDisposedNotification();
for (gc_count = 1; gc_count < 10; gc_count++) {
other_context->Enter();
@@ -15480,7 +15508,7 @@
CHECK_EQ(1, message->GetLineNumber());
context->Exit();
}
- context.Dispose();
+ context.Dispose(context->GetIsolate());
v8::V8::ContextDisposedNotification();
for (gc_count = 1; gc_count < 10; gc_count++) {
other_context->Enter();
@@ -15492,7 +15520,7 @@
CHECK_GE(2, gc_count);
CHECK_EQ(1, GetGlobalObjectsCount());
- other_context.Dispose();
+ other_context.Dispose(other_context->GetIsolate());
v8::V8::ContextDisposedNotification();
}
@@ -16282,10 +16310,10 @@
{
v8::Isolate::Scope iscope(isolate2);
- context2.Dispose();
+ context2.Dispose(context2->GetIsolate());
}
- context1.Dispose();
+ context1.Dispose(context1->GetIsolate());
isolate1->Exit();
v8::V8::SetFatalErrorHandler(StoringErrorCallback);
@@ -16659,7 +16687,7 @@
CHECK(value->IsObject());
v8::Persistent<v8::Object> visited =
v8::Persistent<v8::Object>::Cast(value);
- CHECK_EQ(42, visited.WrapperClassId());
+ CHECK_EQ(42, visited.WrapperClassId(v8::Isolate::GetCurrent()));
CHECK_EQ(object_, visited);
++counter_;
}
@@ -16673,55 +16701,58 @@
TEST(PersistentHandleVisitor) {
v8::HandleScope scope;
LocalContext context;
+ v8::Isolate* isolate = context->GetIsolate();
v8::Persistent<v8::Object> object =
- v8::Persistent<v8::Object>::New(v8::Object::New());
- CHECK_EQ(0, object.WrapperClassId());
- object.SetWrapperClassId(42);
- CHECK_EQ(42, object.WrapperClassId());
+ v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
+ CHECK_EQ(0, object.WrapperClassId(isolate));
+ object.SetWrapperClassId(isolate, 42);
+ CHECK_EQ(42, object.WrapperClassId(isolate));
Visitor42 visitor(object);
v8::V8::VisitHandlesWithClassIds(&visitor);
CHECK_EQ(1, visitor.counter_);
- object.Dispose();
+ object.Dispose(isolate);
}
TEST(WrapperClassId) {
v8::HandleScope scope;
LocalContext context;
+ v8::Isolate* isolate = context->GetIsolate();
v8::Persistent<v8::Object> object =
- v8::Persistent<v8::Object>::New(v8::Object::New());
- CHECK_EQ(0, object.WrapperClassId());
- object.SetWrapperClassId(65535);
- CHECK_EQ(65535, object.WrapperClassId());
- object.Dispose();
+ v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
+ CHECK_EQ(0, object.WrapperClassId(isolate));
+ object.SetWrapperClassId(isolate, 65535);
+ CHECK_EQ(65535, object.WrapperClassId(isolate));
+ object.Dispose(isolate);
}
TEST(PersistentHandleInNewSpaceVisitor) {
v8::HandleScope scope;
LocalContext context;
+ v8::Isolate* isolate = context->GetIsolate();
v8::Persistent<v8::Object> object1 =
- v8::Persistent<v8::Object>::New(v8::Object::New());
- CHECK_EQ(0, object1.WrapperClassId());
- object1.SetWrapperClassId(42);
- CHECK_EQ(42, object1.WrapperClassId());
+ v8::Persistent<v8::Object>::New(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(v8::Object::New());
- CHECK_EQ(0, object2.WrapperClassId());
- object2.SetWrapperClassId(42);
- CHECK_EQ(42, object2.WrapperClassId());
+ v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
+ CHECK_EQ(0, object2.WrapperClassId(isolate));
+ object2.SetWrapperClassId(isolate, 42);
+ CHECK_EQ(42, object2.WrapperClassId(isolate));
Visitor42 visitor(object2);
- v8::V8::VisitHandlesForPartialDependence(v8::Isolate::GetCurrent(), &visitor);
+ v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
CHECK_EQ(1, visitor.counter_);
- object1.Dispose();
- object2.Dispose();
+ object1.Dispose(isolate);
+ object2.Dispose(isolate);
}
@@ -16951,9 +16982,9 @@
CheckContextId(instance2, 2);
}
- context1.Dispose();
- context2.Dispose();
- context3.Dispose();
+ context1.Dispose(context1->GetIsolate());
+ context2.Dispose(context2->GetIsolate());
+ context3.Dispose(context3->GetIsolate());
}
@@ -16971,7 +17002,7 @@
CHECK(function->CreationContext() == context);
CheckContextId(function, 1);
- context.Dispose();
+ context.Dispose(context->GetIsolate());
}
@@ -17347,7 +17378,7 @@
Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
CHECK(result6->Equals(Undefined()));
- context.Dispose();
+ context.Dispose(context->GetIsolate());
}
@@ -17475,7 +17506,7 @@
// Calling with no base.
TestReceiver(o, context->Global(), "(1,func)()");
- foreign_context.Dispose();
+ foreign_context.Dispose(foreign_context->GetIsolate());
}
diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc
index 1e4261c..deabe7f 100644
--- a/test/cctest/test-debug.cc
+++ b/test/cctest/test-debug.cc
@@ -137,7 +137,7 @@
}
inline ~DebugLocalContext() {
context_->Exit();
- context_.Dispose();
+ context_.Dispose(context_->GetIsolate());
}
inline v8::Context* operator->() { return *context_; }
inline v8::Context* operator*() { return *context_; }
@@ -4231,7 +4231,7 @@
const char* extension_names[] = { "simpletest" };
v8::ExtensionConfiguration extensions(1, extension_names);
v8::Persistent<v8::Context> context = v8::Context::New(&extensions);
- context.Dispose();
+ context.Dispose(context->GetIsolate());
}
// Check that no DebugBreak events occured during the context creation.
CHECK_EQ(0, break_point_hit_count);
@@ -7069,7 +7069,7 @@
expected_context = v8::Context::New();
v8::Context::Scope context_scope(expected_context);
v8::Script::Compile(v8::String::New("(function(){debugger;})();"))->Run();
- expected_context.Dispose();
+ expected_context.Dispose(expected_context->GetIsolate());
expected_context.Clear();
v8::Debug::SetDebugEventListener(NULL);
expected_context_data = v8::Handle<v8::Value>();
diff --git a/test/cctest/test-decls.cc b/test/cctest/test-decls.cc
index d379fbb..efdc394 100644
--- a/test/cctest/test-decls.cc
+++ b/test/cctest/test-decls.cc
@@ -53,7 +53,7 @@
virtual ~DeclarationContext() {
if (is_initialized_) {
context_->Exit();
- context_.Dispose();
+ context_.Dispose(context_->GetIsolate());
}
}
@@ -701,7 +701,7 @@
virtual ~SimpleContext() {
context_->Exit();
- context_.Dispose();
+ context_.Dispose(context_->GetIsolate());
}
void Check(const char* source,
diff --git a/test/cctest/test-heap-profiler.cc b/test/cctest/test-heap-profiler.cc
index 29fb1c1..a8a45b7 100644
--- a/test/cctest/test-heap-profiler.cc
+++ b/test/cctest/test-heap-profiler.cc
@@ -1045,20 +1045,21 @@
TEST(HeapSnapshotRetainedObjectInfo) {
v8::HandleScope scope;
LocalContext env;
+ v8::Isolate* isolate = env->GetIsolate();
v8::HeapProfiler::DefineWrapperClass(
1, TestRetainedObjectInfo::WrapperInfoCallback);
v8::HeapProfiler::DefineWrapperClass(
2, TestRetainedObjectInfo::WrapperInfoCallback);
v8::Persistent<v8::String> p_AAA =
- v8::Persistent<v8::String>::New(v8_str("AAA"));
- p_AAA.SetWrapperClassId(1);
+ v8::Persistent<v8::String>::New(isolate, v8_str("AAA"));
+ p_AAA.SetWrapperClassId(isolate, 1);
v8::Persistent<v8::String> p_BBB =
- v8::Persistent<v8::String>::New(v8_str("BBB"));
- p_BBB.SetWrapperClassId(1);
+ v8::Persistent<v8::String>::New(isolate, v8_str("BBB"));
+ p_BBB.SetWrapperClassId(isolate, 1);
v8::Persistent<v8::String> p_CCC =
- v8::Persistent<v8::String>::New(v8_str("CCC"));
- p_CCC.SetWrapperClassId(2);
+ v8::Persistent<v8::String>::New(isolate, v8_str("CCC"));
+ p_CCC.SetWrapperClassId(isolate, 2);
CHECK_EQ(0, TestRetainedObjectInfo::instances.length());
const v8::HeapSnapshot* snapshot =
v8::HeapProfiler::TakeSnapshot(v8_str("retained"));
@@ -1107,8 +1108,9 @@
explicit GraphWithImplicitRefs(LocalContext* env) {
CHECK_EQ(NULL, instance_);
instance_ = this;
+ v8::Isolate* isolate = (*env)->GetIsolate();
for (int i = 0; i < kObjectsCount; i++) {
- objects_[i] = v8::Persistent<v8::Object>::New(v8::Object::New());
+ objects_[i] = v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
}
(*env)->Global()->Set(v8_str("root_object"), objects_[0]);
}
@@ -1478,8 +1480,10 @@
}
-static void PersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
- handle.Dispose();
+static void PersistentHandleCallback(v8::Isolate* isolate,
+ v8::Persistent<v8::Value> handle,
+ void*) {
+ handle.Dispose(isolate);
}
@@ -1490,8 +1494,8 @@
CHECK(!HasWeakGlobalHandle());
v8::Persistent<v8::Object> handle =
- v8::Persistent<v8::Object>::New(v8::Object::New());
- handle.MakeWeak(NULL, PersistentHandleCallback);
+ v8::Persistent<v8::Object>::New(env->GetIsolate(), v8::Object::New());
+ handle.MakeWeak(env->GetIsolate(), NULL, PersistentHandleCallback);
CHECK(HasWeakGlobalHandle());
}
@@ -1564,6 +1568,7 @@
TEST(PersistentHandleCount) {
v8::HandleScope scope;
LocalContext env;
+ v8::Isolate* isolate = env->GetIsolate();
// V8 also uses global handles internally, so we can't test for an absolute
// number.
@@ -1571,26 +1576,26 @@
// Create some persistent handles.
v8::Persistent<v8::String> p_AAA =
- v8::Persistent<v8::String>::New(v8_str("AAA"));
+ v8::Persistent<v8::String>::New(isolate, v8_str("AAA"));
CHECK_EQ(global_handle_count + 1,
v8::HeapProfiler::GetPersistentHandleCount());
v8::Persistent<v8::String> p_BBB =
- v8::Persistent<v8::String>::New(v8_str("BBB"));
+ v8::Persistent<v8::String>::New(isolate, v8_str("BBB"));
CHECK_EQ(global_handle_count + 2,
v8::HeapProfiler::GetPersistentHandleCount());
v8::Persistent<v8::String> p_CCC =
- v8::Persistent<v8::String>::New(v8_str("CCC"));
+ v8::Persistent<v8::String>::New(isolate, v8_str("CCC"));
CHECK_EQ(global_handle_count + 3,
v8::HeapProfiler::GetPersistentHandleCount());
// Dipose the persistent handles in a different order.
- p_AAA.Dispose();
+ p_AAA.Dispose(env->GetIsolate());
CHECK_EQ(global_handle_count + 2,
v8::HeapProfiler::GetPersistentHandleCount());
- p_CCC.Dispose();
+ p_CCC.Dispose(env->GetIsolate());
CHECK_EQ(global_handle_count + 1,
v8::HeapProfiler::GetPersistentHandleCount());
- p_BBB.Dispose();
+ p_BBB.Dispose(env->GetIsolate());
CHECK_EQ(global_handle_count, v8::HeapProfiler::GetPersistentHandleCount());
}
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
index 88ff1d4..c9b64ae 100644
--- a/test/cctest/test-heap.cc
+++ b/test/cctest/test-heap.cc
@@ -358,10 +358,11 @@
static bool WeakPointerCleared = false;
-static void TestWeakGlobalHandleCallback(v8::Persistent<v8::Value> handle,
+static void TestWeakGlobalHandleCallback(v8::Isolate* isolate,
+ v8::Persistent<v8::Value> handle,
void* id) {
if (1234 == reinterpret_cast<intptr_t>(id)) WeakPointerCleared = true;
- handle.Dispose();
+ handle.Dispose(isolate);
}
@@ -386,6 +387,7 @@
global_handles->MakeWeak(h2.location(),
reinterpret_cast<void*>(1234),
+ NULL,
&TestWeakGlobalHandleCallback);
// Scavenge treats weak pointers as normal roots.
@@ -429,6 +431,7 @@
global_handles->MakeWeak(h2.location(),
reinterpret_cast<void*>(1234),
+ NULL,
&TestWeakGlobalHandleCallback);
CHECK(!GlobalHandles::IsNearDeath(h1.location()));
CHECK(!GlobalHandles::IsNearDeath(h2.location()));
@@ -462,6 +465,7 @@
global_handles->MakeWeak(h.location(),
reinterpret_cast<void*>(1234),
+ NULL,
&TestWeakGlobalHandleCallback);
// Scanvenge does not recognize weak reference.
@@ -1314,7 +1318,7 @@
// Dispose the native contexts one by one.
for (int i = 0; i < kNumTestContexts; i++) {
- ctx[i].Dispose();
+ ctx[i].Dispose(ctx[i]->GetIsolate());
ctx[i].Clear();
// Scavenge treats these references as strong.
@@ -1617,12 +1621,12 @@
ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
ctx2->Exit();
ctx1->Exit();
- ctx1.Dispose();
+ ctx1.Dispose(ctx1->GetIsolate());
v8::V8::ContextDisposedNotification();
}
HEAP->CollectAllAvailableGarbage();
CHECK_EQ(2, NumberOfGlobalObjects());
- ctx2.Dispose();
+ ctx2.Dispose(ctx2->GetIsolate());
HEAP->CollectAllAvailableGarbage();
CHECK_EQ(0, NumberOfGlobalObjects());
}
@@ -1655,12 +1659,12 @@
ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
ctx2->Exit();
ctx1->Exit();
- ctx1.Dispose();
+ ctx1.Dispose(ctx1->GetIsolate());
v8::V8::ContextDisposedNotification();
}
HEAP->CollectAllAvailableGarbage();
CHECK_EQ(2, NumberOfGlobalObjects());
- ctx2.Dispose();
+ ctx2.Dispose(ctx2->GetIsolate());
HEAP->CollectAllAvailableGarbage();
CHECK_EQ(0, NumberOfGlobalObjects());
}
@@ -1691,12 +1695,12 @@
ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
ctx2->Exit();
ctx1->Exit();
- ctx1.Dispose();
+ ctx1.Dispose(ctx1->GetIsolate());
v8::V8::ContextDisposedNotification();
}
HEAP->CollectAllAvailableGarbage();
CHECK_EQ(2, NumberOfGlobalObjects());
- ctx2.Dispose();
+ ctx2.Dispose(ctx2->GetIsolate());
HEAP->CollectAllAvailableGarbage();
CHECK_EQ(0, NumberOfGlobalObjects());
}
@@ -1731,12 +1735,12 @@
ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
ctx2->Exit();
ctx1->Exit();
- ctx1.Dispose();
+ ctx1.Dispose(ctx1->GetIsolate());
v8::V8::ContextDisposedNotification();
}
HEAP->CollectAllAvailableGarbage();
CHECK_EQ(2, NumberOfGlobalObjects());
- ctx2.Dispose();
+ ctx2.Dispose(ctx2->GetIsolate());
HEAP->CollectAllAvailableGarbage();
CHECK_EQ(0, NumberOfGlobalObjects());
}
diff --git a/test/cctest/test-lockers.cc b/test/cctest/test-lockers.cc
index 3e93110..b0f2b62 100644
--- a/test/cctest/test-lockers.cc
+++ b/test/cctest/test-lockers.cc
@@ -649,7 +649,7 @@
v8::Handle<Script> script = v8::Script::Compile(source);
v8::Handle<Value> result = script->Run();
v8::String::AsciiValue ascii(result);
- context.Dispose();
+ context.Dispose(isolate);
}
isolate->Dispose();
}
@@ -677,7 +677,7 @@
v8::ExtensionConfiguration extensions(count_, extension_names_);
v8::Persistent<v8::Context> context = v8::Context::New(&extensions);
CHECK(i::Isolate::Current()->has_installed_extensions());
- context.Dispose();
+ context.Dispose(isolate);
}
isolate->Dispose();
}
diff --git a/test/cctest/test-log.cc b/test/cctest/test-log.cc
index 892a542..9883bfa 100644
--- a/test/cctest/test-log.cc
+++ b/test/cctest/test-log.cc
@@ -370,7 +370,8 @@
ScopedLoggerInitializer initialize_logger(false);
v8::Persistent<v8::FunctionTemplate> obj =
- v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New());
+ v8::Persistent<v8::FunctionTemplate>::New(v8::Isolate::GetCurrent(),
+ v8::FunctionTemplate::New());
obj->SetClassName(v8_str("Obj"));
v8::Handle<v8::ObjectTemplate> proto = obj->PrototypeTemplate();
v8::Local<v8::Signature> signature = v8::Signature::New(obj);
@@ -397,7 +398,7 @@
CHECK_NE(NULL, StrNStr(log.start(), ref_data.start(), log.length()));
- obj.Dispose();
+ obj.Dispose(v8::Isolate::GetCurrent());
}
@@ -420,7 +421,8 @@
ScopedLoggerInitializer initialize_logger(false);
v8::Persistent<v8::FunctionTemplate> obj =
- v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New());
+ v8::Persistent<v8::FunctionTemplate>::New(v8::Isolate::GetCurrent(),
+ v8::FunctionTemplate::New());
obj->SetClassName(v8_str("Obj"));
v8::Handle<v8::ObjectTemplate> inst = obj->InstanceTemplate();
inst->SetAccessor(v8_str("prop1"), Prop1Getter, Prop1Setter);
@@ -454,7 +456,7 @@
CHECK_NE(NULL,
StrNStr(log.start(), prop2_getter_record.start(), log.length()));
- obj.Dispose();
+ obj.Dispose(v8::Isolate::GetCurrent());
}
diff --git a/test/cctest/test-mark-compact.cc b/test/cctest/test-mark-compact.cc
index 682b327..949e413 100644
--- a/test/cctest/test-mark-compact.cc
+++ b/test/cctest/test-mark-compact.cc
@@ -304,10 +304,12 @@
static int NumberOfWeakCalls = 0;
-static void WeakPointerCallback(v8::Persistent<v8::Value> handle, void* id) {
+static void WeakPointerCallback(v8::Isolate* isolate,
+ v8::Persistent<v8::Value> handle,
+ void* id) {
ASSERT(id == reinterpret_cast<void*>(1234));
NumberOfWeakCalls++;
- handle.Dispose();
+ handle.Dispose(isolate);
}
TEST(ObjectGroups) {
@@ -326,12 +328,15 @@
global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
global_handles->MakeWeak(g1s1.location(),
reinterpret_cast<void*>(1234),
+ NULL,
&WeakPointerCallback);
global_handles->MakeWeak(g1s2.location(),
reinterpret_cast<void*>(1234),
+ NULL,
&WeakPointerCallback);
global_handles->MakeWeak(g1c1.location(),
reinterpret_cast<void*>(1234),
+ NULL,
&WeakPointerCallback);
Handle<Object> g2s1 =
@@ -342,12 +347,15 @@
global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
global_handles->MakeWeak(g2s1.location(),
reinterpret_cast<void*>(1234),
+ NULL,
&WeakPointerCallback);
global_handles->MakeWeak(g2s2.location(),
reinterpret_cast<void*>(1234),
+ NULL,
&WeakPointerCallback);
global_handles->MakeWeak(g2c1.location(),
reinterpret_cast<void*>(1234),
+ NULL,
&WeakPointerCallback);
Handle<Object> root = global_handles->Create(*g1s1); // make a root.
@@ -377,6 +385,7 @@
// Weaken the root.
global_handles->MakeWeak(root.location(),
reinterpret_cast<void*>(1234),
+ NULL,
&WeakPointerCallback);
// But make children strong roots---all the objects (except for children)
// should be collectable now.
@@ -405,9 +414,11 @@
// And now make children weak again and collect them.
global_handles->MakeWeak(g1c1.location(),
reinterpret_cast<void*>(1234),
+ NULL,
&WeakPointerCallback);
global_handles->MakeWeak(g2c1.location(),
reinterpret_cast<void*>(1234),
+ NULL,
&WeakPointerCallback);
HEAP->CollectGarbage(OLD_POINTER_SPACE);
diff --git a/test/cctest/test-regexp.cc b/test/cctest/test-regexp.cc
index ac605a8..083bbcc 100644
--- a/test/cctest/test-regexp.cc
+++ b/test/cctest/test-regexp.cc
@@ -714,7 +714,7 @@
}
~ContextInitializer() {
env_->Exit();
- env_.Dispose();
+ env_.Dispose(env_->GetIsolate());
}
private:
v8::Persistent<v8::Context> env_;
diff --git a/test/cctest/test-serialize.cc b/test/cctest/test-serialize.cc
index b647090..888c842 100644
--- a/test/cctest/test-serialize.cc
+++ b/test/cctest/test-serialize.cc
@@ -251,7 +251,7 @@
// will clear the pending fixups array, which would otherwise contain GC roots
// that would confuse the serialization/deserialization process.
v8::Persistent<v8::Context> env = v8::Context::New();
- env.Dispose();
+ env.Dispose(env->GetIsolate());
WriteToFile(FLAG_testing_serialization_file);
}
@@ -390,7 +390,7 @@
OS::SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
env->Exit();
- env.Dispose();
+ env.Dispose(env->GetIsolate());
FileByteSink startup_sink(startup_name.start());
StartupSerializer startup_serializer(&startup_sink);
@@ -518,7 +518,7 @@
Object* raw_context = *(v8::Utils::OpenHandle(*env));
- env.Dispose();
+ env.Dispose(env->GetIsolate());
FileByteSink startup_sink(startup_name.start());
StartupSerializer startup_serializer(&startup_sink);
diff --git a/test/cctest/test-thread-termination.cc b/test/cctest/test-thread-termination.cc
index 7712a2c..b249c7a 100644
--- a/test/cctest/test-thread-termination.cc
+++ b/test/cctest/test-thread-termination.cc
@@ -134,7 +134,7 @@
// Test that we can run the code again after thread termination.
CHECK(!v8::V8::IsExecutionTerminating());
v8::Script::Compile(source)->Run();
- context.Dispose();
+ context.Dispose(context->GetIsolate());
}
@@ -154,7 +154,7 @@
CHECK(!v8::V8::IsExecutionTerminating());
// Test that we can run the code again after thread termination.
v8::Script::Compile(source)->Run();
- context.Dispose();
+ context.Dispose(context->GetIsolate());
}
@@ -194,7 +194,7 @@
thread.Join();
delete semaphore;
semaphore = NULL;
- context.Dispose();
+ context.Dispose(context->GetIsolate());
}
@@ -214,7 +214,7 @@
v8::Handle<v8::String> source =
v8::String::New("try { loop(); fail(); } catch(e) { fail(); }");
v8::Script::Compile(source)->Run();
- context.Dispose();
+ context.Dispose(context->GetIsolate());
}
int GetV8ThreadId() { return v8_thread_id_; }
@@ -326,7 +326,7 @@
CHECK(!v8::V8::IsExecutionTerminating());
call_count = 0;
v8::Script::Compile(source)->Run();
- context.Dispose();
+ context.Dispose(context->GetIsolate());
}
v8::Handle<v8::Value> ReenterAfterTermination(const v8::Arguments& args) {
@@ -370,5 +370,5 @@
// Check we can run JS again after termination.
CHECK(v8::Script::Compile(v8::String::New("function f() { return true; }"
"f()"))->Run()->IsTrue());
- context.Dispose();
+ context.Dispose(context->GetIsolate());
}
diff --git a/test/cctest/test-weakmaps.cc b/test/cctest/test-weakmaps.cc
index 7c98c57..edbd94c 100644
--- a/test/cctest/test-weakmaps.cc
+++ b/test/cctest/test-weakmaps.cc
@@ -57,10 +57,12 @@
}
static int NumberOfWeakCalls = 0;
-static void WeakPointerCallback(v8::Persistent<v8::Value> handle, void* id) {
+static void WeakPointerCallback(v8::Isolate* isolate,
+ v8::Persistent<v8::Value> handle,
+ void* id) {
ASSERT(id == reinterpret_cast<void*>(1234));
NumberOfWeakCalls++;
- handle.Dispose();
+ handle.Dispose(isolate);
}
@@ -102,6 +104,7 @@
v8::HandleScope scope;
global_handles->MakeWeak(key.location(),
reinterpret_cast<void*>(1234),
+ NULL,
&WeakPointerCallback);
}
CHECK(global_handles->IsWeak(key.location()));
diff --git a/test/mjsunit/compiler/property-static.js b/test/mjsunit/compiler/property-static.js
new file mode 100644
index 0000000..0702134
--- /dev/null
+++ b/test/mjsunit/compiler/property-static.js
@@ -0,0 +1,69 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+
+// Test usage of static type information for loads that would otherwise
+// turn into polymorphic or generic loads.
+
+// Prepare a highly polymorphic load to be used by all tests.
+Object.prototype.load = function() { return this.property; };
+Object.prototype.load.call({ A:0, property:10 });
+Object.prototype.load.call({ A:0, B:0, property:11 });
+Object.prototype.load.call({ A:0, B:0, C:0, property:12 });
+Object.prototype.load.call({ A:0, B:0, C:0, D:0, property:13 });
+Object.prototype.load.call({ A:0, B:0, C:0, D:0, E:0, property:14 });
+Object.prototype.load.call({ A:0, B:0, C:0, D:0, E:0, F:0, property:15 });
+
+// Test for object literals.
+(function() {
+ function f(x) {
+ var object = { property:x };
+ return object.load();
+ }
+
+ assertSame(1, f(1));
+ assertSame(2, f(2));
+ %OptimizeFunctionOnNextCall(f);
+ assertSame(3, f(3));
+})();
+
+// Test for inlined constructors.
+(function() {
+ function c(x) {
+ this.property = x;
+ }
+ function f(x) {
+ var object = new c(x);
+ return object.load();
+ }
+
+ assertSame(1, f(1));
+ assertSame(2, f(2));
+ %OptimizeFunctionOnNextCall(f);
+ assertSame(3, f(3));
+})();
diff --git a/test/mjsunit/regress/regress-2437.js b/test/mjsunit/regress/regress-2437.js
index 06b69b2..c82293a 100644
--- a/test/mjsunit/regress/regress-2437.js
+++ b/test/mjsunit/regress/regress-2437.js
@@ -25,6 +25,14 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// Summary of the spec: lastIndex is reset to 0 if
+// - a regexp fails to match, regardless of global or non-global.
+// - a global regexp is used in a function that returns multiple results,
+// such as String.prototype.replace or String.prototype.match, since it
+// repeats the regexp until it fails to match.
+// Otherwise lastIndex is only set when a global regexp matches, to the index
+// after the match.
+
// Test Regexp.prototype.exec
r = /a/;
r.lastIndex = 1;
@@ -73,3 +81,76 @@
"zzzz".replace(r, function() { return ""; });
assertEquals(0, r.lastIndex);
+// Regexp functions that returns multiple results:
+// A global regexp always resets lastIndex regardless of whether it matches.
+r = /a/g;
+r.lastIndex = -1;
+"0123abcd".replace(r, "x");
+assertEquals(0, r.lastIndex);
+
+r.lastIndex = -1;
+"01234567".replace(r, "x");
+assertEquals(0, r.lastIndex);
+
+r.lastIndex = -1;
+"0123abcd".match(r);
+assertEquals(0, r.lastIndex);
+
+r.lastIndex = -1;
+"01234567".match(r);
+assertEquals(0, r.lastIndex);
+
+// A non-global regexp resets lastIndex iff it does not match.
+r = /a/;
+r.lastIndex = -1;
+"0123abcd".replace(r, "x");
+assertEquals(-1, r.lastIndex);
+
+r.lastIndex = -1;
+"01234567".replace(r, "x");
+assertEquals(0, r.lastIndex);
+
+r.lastIndex = -1;
+"0123abcd".match(r);
+assertEquals(-1, r.lastIndex);
+
+r.lastIndex = -1;
+"01234567".match(r);
+assertEquals(0, r.lastIndex);
+
+// Also test RegExp.prototype.exec and RegExp.prototype.test
+r = /a/g;
+r.lastIndex = 1;
+r.exec("01234567");
+assertEquals(0, r.lastIndex);
+
+r.lastIndex = 1;
+r.exec("0123abcd");
+assertEquals(5, r.lastIndex);
+
+r = /a/;
+r.lastIndex = 1;
+r.exec("01234567");
+assertEquals(0, r.lastIndex);
+
+r.lastIndex = 1;
+r.exec("0123abcd");
+assertEquals(1, r.lastIndex);
+
+r = /a/g;
+r.lastIndex = 1;
+r.test("01234567");
+assertEquals(0, r.lastIndex);
+
+r.lastIndex = 1;
+r.test("0123abcd");
+assertEquals(5, r.lastIndex);
+
+r = /a/;
+r.lastIndex = 1;
+r.test("01234567");
+assertEquals(0, r.lastIndex);
+
+r.lastIndex = 1;
+r.test("0123abcd");
+assertEquals(1, r.lastIndex);