Revision: 13282
Author: [email protected]
Date: Thu Dec 27 07:57:11 2012
Log: Version 3.16.1
Fixed x64 MathMinMax for negative untagged int32 arguments. (Chromium issue
164442)
Fixed FloatingPointHelper::CheckSSE2OperandIsInt32. (issue 2458)
Performance and stability improvements on all platforms.
http://code.google.com/p/v8/source/detail?r=13282
Added:
/trunk/test/mjsunit/regress/regress-164442.js
Deleted:
/trunk/test/mjsunit/stack-traces-gc.js
Modified:
/trunk/ChangeLog
/trunk/src/api.cc
/trunk/src/deoptimizer.cc
/trunk/src/handles.cc
/trunk/src/heap-inl.h
/trunk/src/heap.cc
/trunk/src/heap.h
/trunk/src/ia32/assembler-ia32.cc
/trunk/src/ia32/assembler-ia32.h
/trunk/src/ia32/code-stubs-ia32.cc
/trunk/src/ia32/disasm-ia32.cc
/trunk/src/ia32/lithium-gap-resolver-ia32.cc
/trunk/src/isolate.cc
/trunk/src/list-inl.h
/trunk/src/list.h
/trunk/src/mark-compact.cc
/trunk/src/messages.js
/trunk/src/runtime.cc
/trunk/src/runtime.h
/trunk/src/version.cc
/trunk/src/x64/assembler-x64.cc
/trunk/src/x64/assembler-x64.h
/trunk/src/x64/disasm-x64.cc
/trunk/src/x64/lithium-codegen-x64.cc
/trunk/test/cctest/test-decls.cc
/trunk/test/cctest/test-heap.cc
/trunk/test/cctest/test-object-observe.cc
/trunk/test/message/overwritten-builtins.out
/trunk/test/mjsunit/eval-stack-trace.js
/trunk/test/mjsunit/stack-traces.js
=======================================
--- /dev/null
+++ /trunk/test/mjsunit/regress/regress-164442.js Thu Dec 27 07:57:11 2012
@@ -0,0 +1,45 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+
+// Should not take a very long time (n^2 algorithms are bad)
+
+
+function ensureNotNegative(x) {
+ return Math.max(0, x | 0);
+}
+
+
+ensureNotNegative(1);
+ensureNotNegative(2);
+
+%OptimizeFunctionOnNextCall(ensureNotNegative);
+
+var r = ensureNotNegative(-1);
+
+assertEquals(0, r);
=======================================
--- /trunk/test/mjsunit/stack-traces-gc.js Fri Dec 21 04:35:02 2012
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2012 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Flags: --expose-gc --allow-natives-syntax
-
-var fired = [];
-for (var i = 0; i < 100; i++) fired[i] = false;
-
-function getter_function(i) {
- return %MarkOneShotGetter( function() { fired[i] = true; } );
-}
-
-// Error objects that die young.
-for (var i = 0; i < 100; i++) {
- var error = new Error();
- // Replace the getter to observe whether it has been fired,
- // and disguise it as original getter.
- var getter = getter_function(i);
- error.__defineGetter__("stack", getter);
-
- error = undefined;
-}
-
-gc();
-for (var i = 0; i < 100; i++) {
- assertFalse(fired[i]);
-}
-
-// Error objects that are kept alive.
-var array = [];
-for (var i = 0; i < 100; i++) {
- var error = new Error();
- var getter = getter_function(i);
- // Replace the getter to observe whether it has been fired,
- // and disguise it as original getter.
- error.__defineGetter__("stack", getter);
-
- array.push(error);
- error = undefined;
-}
-
-gc();
-// We don't expect all stack traces to be formatted after only one GC.
-assertTrue(fired[0]);
-
-for (var i = 0; i < 10; i++) gc();
-for (var i = 0; i < 100; i++) assertTrue(fired[i]);
-
-// Error objects with custom stack getter.
-var custom_error = new Error();
-var custom_getter_fired = false;
-custom_error.__defineGetter__("stack",
- function() { custom_getter_fired = true; });
-gc();
-assertFalse(custom_getter_fired);
-
-// Check that formatting caused by GC is not somehow observable.
-var error;
-
-var obj = { foo: function foo() { throw new Error(); } };
-
-try {
- obj.foo();
-} catch (e) {
- delete obj.foo;
- Object.defineProperty(obj, 'foo', {
- get: function() { assertUnreachable(); }
- });
- error = e;
-}
-
-gc();
-
-Object.defineProperty(Array.prototype, '0', {
- get: function() { assertUnreachable(); }
-});
-
-try {
- throw new Error();
-} catch (e) {
- error = e;
-}
-
-gc();
-
-String.prototype.indexOf = function() { assertUnreachable(); };
-String.prototype.lastIndexOf = function() { assertUnreachable(); };
-var obj = { method: function() { throw Error(); } };
-try {
- obj.method();
-} catch (e) {
- error = e;
-}
-
-gc();
=======================================
--- /trunk/ChangeLog Fri Dec 21 05:47:00 2012
+++ /trunk/ChangeLog Thu Dec 27 07:57:11 2012
@@ -1,3 +1,14 @@
+2012-12-27: Version 3.16.1
+
+ Fixed x64 MathMinMax for negative untagged int32 arguments.
+ (Chromium issue 164442)
+
+ Fixed FloatingPointHelper::CheckSSE2OperandIsInt32.
+ (issue 2458)
+
+ Performance and stability improvements on all platforms.
+
+
2012-12-21: Version 3.16.0
V8_Fatal now prints C++ stack trace in debug mode.
=======================================
--- /trunk/src/api.cc Fri Dec 21 04:35:02 2012
+++ /trunk/src/api.cc Thu Dec 27 07:57:11 2012
@@ -1851,7 +1851,8 @@
if (!raw_obj->IsJSObject()) return v8::Local<Value>();
i::HandleScope scope(isolate_);
i::Handle<i::JSObject> obj(i::JSObject::cast(raw_obj), isolate_);
- i::Handle<i::String> name = isolate_->factory()->stack_symbol();
+ i::Handle<i::String> name =
+
isolate_->factory()->LookupOneByteSymbol(STATIC_ASCII_VECTOR("stack"));
if (!obj->HasProperty(*name)) return v8::Local<Value>();
i::Handle<i::Object> value = i::GetProperty(obj, name);
if (value.is_null()) return v8::Local<Value>();
=======================================
--- /trunk/src/deoptimizer.cc Fri Dec 21 04:35:02 2012
+++ /trunk/src/deoptimizer.cc Thu Dec 27 07:57:11 2012
@@ -502,7 +502,7 @@
return "OSR";
}
UNREACHABLE();
- return false;
+ return NULL;
}
=======================================
--- /trunk/src/handles.cc Fri Dec 21 04:35:02 2012
+++ /trunk/src/handles.cc Thu Dec 27 07:57:11 2012
@@ -375,15 +375,6 @@
Handle<JSFunction> constructor = isolate->script_function();
Handle<JSValue> result =
Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
-
- // The allocation might have triggered a GC, which could have called this
- // function recursively, and a wrapper has already been created and
cached.
- // In that case, simply return the cached wrapper.
- if (script->wrapper()->foreign_address() != NULL) {
- return Handle<JSValue>(
- reinterpret_cast<JSValue**>(script->wrapper()->foreign_address()));
- }
-
result->set_value(*script);
// Create a new weak global handle and use it to cache the wrapper
=======================================
--- /trunk/src/heap-inl.h Fri Dec 21 04:35:02 2012
+++ /trunk/src/heap-inl.h Thu Dec 27 07:57:11 2012
@@ -664,19 +664,6 @@
}
#endif
}
-
-
-void ErrorObjectList::Add(JSObject* object) {
- list_.Add(object);
-}
-
-
-void ErrorObjectList::Iterate(ObjectVisitor* v) {
- if (!list_.is_empty()) {
- Object** start = &list_[0];
- v->VisitPointers(start, start + list_.length());
- }
-}
void Heap::ClearInstanceofCache() {
=======================================
--- /trunk/src/heap.cc Fri Dec 21 04:35:02 2012
+++ /trunk/src/heap.cc Thu Dec 27 07:57:11 2012
@@ -550,8 +550,6 @@
#ifdef ENABLE_DEBUGGER_SUPPORT
isolate_->debug()->AfterGarbageCollection();
#endif // ENABLE_DEBUGGER_SUPPORT
-
- error_object_list_.DeferredFormatStackTrace(isolate());
}
@@ -1356,8 +1354,6 @@
UpdateNewSpaceReferencesInExternalStringTable(
&UpdateNewSpaceReferenceInExternalStringTableEntry);
- error_object_list_.UpdateReferencesInNewSpace(this);
-
promotion_queue_.Destroy();
LiveObjectList::UpdateReferencesForScavengeGC();
@@ -2900,6 +2896,7 @@
RootListIndex writable_roots[] = {
kStoreBufferTopRootIndex,
kStackLimitRootIndex,
+ kNumberStringCacheRootIndex,
kInstanceofCacheFunctionRootIndex,
kInstanceofCacheMapRootIndex,
kInstanceofCacheAnswerRootIndex,
@@ -5936,7 +5933,6 @@
mode != VISIT_ALL_IN_SWEEP_NEWSPACE) {
// Scavenge collections have special processing for this.
external_string_table_.Iterate(v);
- error_object_list_.Iterate(v);
}
v->Synchronize(VisitorSynchronization::kExternalStringsTable);
}
@@ -6310,8 +6306,6 @@
external_string_table_.TearDown();
- error_object_list_.TearDown();
-
new_space_.TearDown();
if (old_pointer_space_ != NULL) {
@@ -7218,8 +7212,6 @@
}
}
new_space_strings_.Rewind(last);
- new_space_strings_.Trim();
-
last = 0;
for (int i = 0; i < old_space_strings_.length(); ++i) {
if (old_space_strings_[i] == heap_->the_hole_value()) {
@@ -7229,7 +7221,6 @@
old_space_strings_[last++] = old_space_strings_[i];
}
old_space_strings_.Rewind(last);
- old_space_strings_.Trim();
#ifdef VERIFY_HEAP
if (FLAG_verify_heap) {
Verify();
@@ -7242,114 +7233,6 @@
new_space_strings_.Free();
old_space_strings_.Free();
}
-
-
-// Update all references.
-void ErrorObjectList::UpdateReferences() {
- for (int i = 0; i < list_.length(); i++) {
- HeapObject* object = HeapObject::cast(list_[i]);
- MapWord first_word = object->map_word();
- if (first_word.IsForwardingAddress()) {
- list_[i] = first_word.ToForwardingAddress();
- }
- }
-}
-
-
-// Unforwarded objects in new space are dead and removed from the list.
-void ErrorObjectList::UpdateReferencesInNewSpace(Heap* heap) {
- if (!nested_) {
- int write_index = 0;
- for (int i = 0; i < list_.length(); i++) {
- MapWord first_word = HeapObject::cast(list_[i])->map_word();
- if (first_word.IsForwardingAddress()) {
- list_[write_index++] = first_word.ToForwardingAddress();
- }
- }
- list_.Rewind(write_index);
- } else {
- // If a GC is triggered during DeferredFormatStackTrace, we do not move
- // objects in the list, just remove dead ones, as to not confuse the
- // loop in DeferredFormatStackTrace.
- for (int i = 0; i < list_.length(); i++) {
- MapWord first_word = HeapObject::cast(list_[i])->map_word();
- list_[i] = first_word.IsForwardingAddress()
- ? first_word.ToForwardingAddress()
- : heap->the_hole_value();
- }
- }
-}
-
-
-void ErrorObjectList::DeferredFormatStackTrace(Isolate* isolate) {
- // If formatting the stack trace causes a GC, this method will be
- // recursively called. In that case, skip the recursive call, since
- // the loop modifies the list while iterating over it.
- if (nested_ || isolate->has_pending_exception()) return;
- nested_ = true;
- HandleScope scope(isolate);
- Handle<String> stack_key = isolate->factory()->stack_symbol();
- int write_index = 0;
- int budget = kBudgetPerGC;
- for (int i = 0; i < list_.length(); i++) {
- Object* object = list_[i];
- JSFunction* getter_fun;
-
- { AssertNoAllocation assert;
- // Skip possible holes in the list.
- if (object->IsTheHole()) continue;
- if (isolate->heap()->InNewSpace(object) || budget == 0) {
- list_[write_index++] = object;
- continue;
- }
-
- // Check whether the stack property is backed by the original getter.
- LookupResult lookup(isolate);
- JSObject::cast(object)->LocalLookupRealNamedProperty(*stack_key,
&lookup);
- if (!lookup.IsFound() || lookup.type() != CALLBACKS) continue;
- Object* callback = lookup.GetCallbackObject();
- if (!callback->IsAccessorPair()) continue;
- Object* getter_obj = AccessorPair::cast(callback)->getter();
- if (!getter_obj->IsJSFunction()) continue;
- getter_fun = JSFunction::cast(getter_obj);
- String* key = isolate->heap()->hidden_stack_trace_symbol();
- if (key != getter_fun->GetHiddenProperty(key)) continue;
- }
-
- budget--;
- HandleScope scope(isolate);
- bool has_exception = false;
- Handle<Object> object_handle(object, isolate);
- Handle<Object> getter_handle(getter_fun, isolate);
- Execution::Call(getter_handle, object_handle, 0, NULL, &has_exception);
- if (has_exception) {
- // Hit an exception (most likely a stack overflow).
- // Wrap up this pass and retry after another GC.
- isolate->clear_pending_exception();
- // We use the handle since calling the getter might have caused a GC.
- list_[write_index++] = *object_handle;
- budget = 0;
- }
- }
- list_.Rewind(write_index);
- list_.Trim();
- nested_ = false;
-}
-
-
-void ErrorObjectList::RemoveUnmarked(Heap* heap) {
- for (int i = 0; i < list_.length(); i++) {
- HeapObject* object = HeapObject::cast(list_[i]);
- if (!Marking::MarkBitFrom(object).Get()) {
- list_[i] = heap->the_hole_value();
- }
- }
-}
-
-
-void ErrorObjectList::TearDown() {
- list_.Free();
-}
void Heap::QueueMemoryChunkForFree(MemoryChunk* chunk) {
=======================================
--- /trunk/src/heap.h Fri Dec 21 04:35:02 2012
+++ /trunk/src/heap.h Thu Dec 27 07:57:11 2012
@@ -209,7 +209,6 @@
V(char_at_symbol, "CharAt") \
V(undefined_symbol, "undefined") \
V(value_of_symbol, "valueOf") \
- V(stack_symbol, "stack") \
V(InitializeVarGlobal_symbol, "InitializeVarGlobal") \
V(InitializeConstGlobal_symbol, "InitializeConstGlobal") \
V(KeyedLoadElementMonomorphic_symbol, \
@@ -428,41 +427,6 @@
};
-// The stack property of an error object is implemented as a getter that
-// formats the attached raw stack trace into a string. This raw stack
trace
-// keeps code and function objects alive until the getter is called the
first
-// time. To release those objects, we call the getter after each GC for
-// newly tenured error objects that are kept in a list.
-class ErrorObjectList {
- public:
- inline void Add(JSObject* object);
-
- inline void Iterate(ObjectVisitor* v);
-
- void TearDown();
-
- void RemoveUnmarked(Heap* heap);
-
- void DeferredFormatStackTrace(Isolate* isolate);
-
- void UpdateReferences();
-
- void UpdateReferencesInNewSpace(Heap* heap);
-
- private:
- static const int kBudgetPerGC = 16;
-
- ErrorObjectList() : nested_(false) { }
-
- friend class Heap;
-
- List<Object*> list_;
- bool nested_;
-
- DISALLOW_COPY_AND_ASSIGN(ErrorObjectList);
-};
-
-
enum ArrayStorageAllocationMode {
DONT_INITIALIZE_ARRAY_ELEMENTS,
INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE
@@ -1612,10 +1576,6 @@
ExternalStringTable* external_string_table() {
return &external_string_table_;
}
-
- ErrorObjectList* error_object_list() {
- return &error_object_list_;
- }
// Returns the current sweep generation.
int sweep_generation() {
@@ -2193,8 +2153,6 @@
ExternalStringTable external_string_table_;
- ErrorObjectList error_object_list_;
-
VisitorDispatchTable<ScavengingCallback> scavenging_visitors_table_;
MemoryChunk* chunks_queued_for_free_;
=======================================
--- /trunk/src/ia32/assembler-ia32.cc Fri Dec 21 04:35:02 2012
+++ /trunk/src/ia32/assembler-ia32.cc Thu Dec 27 07:57:11 2012
@@ -2128,6 +2128,15 @@
EMIT(0x50);
emit_sse_operand(dst, src);
}
+
+
+void Assembler::movmskps(Register dst, XMMRegister src) {
+ ASSERT(CpuFeatures::IsEnabled(SSE2));
+ EnsureSpace ensure_space(this);
+ EMIT(0x0F);
+ EMIT(0x50);
+ emit_sse_operand(dst, src);
+}
void Assembler::pcmpeqd(XMMRegister dst, XMMRegister src) {
=======================================
--- /trunk/src/ia32/assembler-ia32.h Fri Dec 21 04:35:02 2012
+++ /trunk/src/ia32/assembler-ia32.h Thu Dec 27 07:57:11 2012
@@ -1077,6 +1077,7 @@
void roundsd(XMMRegister dst, XMMRegister src, RoundingMode mode);
void movmskpd(Register dst, XMMRegister src);
+ void movmskps(Register dst, XMMRegister src);
void cmpltsd(XMMRegister dst, XMMRegister src);
void pcmpeqd(XMMRegister dst, XMMRegister src);
=======================================
--- /trunk/src/ia32/code-stubs-ia32.cc Fri Dec 21 04:35:02 2012
+++ /trunk/src/ia32/code-stubs-ia32.cc Thu Dec 27 07:57:11 2012
@@ -2871,9 +2871,11 @@
__ cvttsd2si(scratch, Operand(operand));
__ cvtsi2sd(xmm_scratch, scratch);
__ pcmpeqd(xmm_scratch, operand);
- __ movmskpd(scratch, xmm_scratch);
- __ test(scratch, Immediate(1));
- __ j(zero, non_int32);
+ __ movmskps(scratch, xmm_scratch);
+ // Two least significant bits should be both set.
+ __ not_(scratch);
+ __ test(scratch, Immediate(3));
+ __ j(not_zero, non_int32);
}
=======================================
--- /trunk/src/ia32/disasm-ia32.cc Mon Nov 26 06:53:56 2012
+++ /trunk/src/ia32/disasm-ia32.cc Thu Dec 27 07:57:11 2012
@@ -1040,6 +1040,14 @@
NameOfXMMRegister(regop),
NameOfXMMRegister(rm));
data++;
+ } else if (f0byte == 0x50) {
+ data += 2;
+ int mod, regop, rm;
+ get_modrm(*data, &mod, ®op, &rm);
+ AppendToBuffer("movmskps %s,%s",
+ NameOfCPURegister(regop),
+ NameOfXMMRegister(rm));
+ data++;
} else if ((f0byte & 0xF0) == 0x80) {
data += JumpConditional(data, branch_hint);
} else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
=======================================
--- /trunk/src/ia32/lithium-gap-resolver-ia32.cc Fri Dec 21 04:35:02 2012
+++ /trunk/src/ia32/lithium-gap-resolver-ia32.cc Thu Dec 27 07:57:11 2012
@@ -324,37 +324,29 @@
}
} else if (source->IsDoubleRegister()) {
- if (CpuFeatures::IsSupported(SSE2)) {
- CpuFeatures::Scope scope(SSE2);
- XMMRegister src = cgen_->ToDoubleRegister(source);
- if (destination->IsDoubleRegister()) {
- XMMRegister dst = cgen_->ToDoubleRegister(destination);
- __ movaps(dst, src);
- } else {
- ASSERT(destination->IsDoubleStackSlot());
- Operand dst = cgen_->ToOperand(destination);
- __ movdbl(dst, src);
- }
+ CpuFeatures::Scope scope(SSE2);
+ XMMRegister src = cgen_->ToDoubleRegister(source);
+ if (destination->IsDoubleRegister()) {
+ XMMRegister dst = cgen_->ToDoubleRegister(destination);
+ __ movaps(dst, src);
} else {
- UNREACHABLE();
+ ASSERT(destination->IsDoubleStackSlot());
+ Operand dst = cgen_->ToOperand(destination);
+ __ movdbl(dst, src);
}
} else if (source->IsDoubleStackSlot()) {
- if (CpuFeatures::IsSupported(SSE2)) {
- CpuFeatures::Scope scope(SSE2);
- ASSERT(destination->IsDoubleRegister() ||
- destination->IsDoubleStackSlot());
- Operand src = cgen_->ToOperand(source);
- if (destination->IsDoubleRegister()) {
- XMMRegister dst = cgen_->ToDoubleRegister(destination);
- __ movdbl(dst, src);
- } else {
- // We rely on having xmm0 available as a fixed scratch register.
- Operand dst = cgen_->ToOperand(destination);
- __ movdbl(xmm0, src);
- __ movdbl(dst, xmm0);
- }
+ CpuFeatures::Scope scope(SSE2);
+ ASSERT(destination->IsDoubleRegister() ||
+ destination->IsDoubleStackSlot());
+ Operand src = cgen_->ToOperand(source);
+ if (destination->IsDoubleRegister()) {
+ XMMRegister dst = cgen_->ToDoubleRegister(destination);
+ __ movdbl(dst, src);
} else {
- UNREACHABLE();
+ // We rely on having xmm0 available as a fixed scratch register.
+ Operand dst = cgen_->ToOperand(destination);
+ __ movdbl(xmm0, src);
+ __ movdbl(dst, xmm0);
}
} else {
UNREACHABLE();
@@ -429,6 +421,7 @@
__ movaps(dst, xmm0);
} else if (source->IsDoubleRegister() ||
destination->IsDoubleRegister()) {
+ CpuFeatures::Scope scope(SSE2);
// XMM register-memory swap. We rely on having xmm0
// available as a fixed scratch register.
ASSERT(source->IsDoubleStackSlot() ||
destination->IsDoubleStackSlot());
@@ -442,6 +435,7 @@
__ movdbl(reg, Operand(xmm0));
} else if (source->IsDoubleStackSlot() &&
destination->IsDoubleStackSlot()) {
+ CpuFeatures::Scope scope(SSE2);
// Double-width memory-to-memory. Spill on demand to use a general
// purpose temporary register and also rely on having xmm0 available as
// a fixed scratch register.
=======================================
--- /trunk/src/isolate.cc Fri Dec 21 04:35:02 2012
+++ /trunk/src/isolate.cc Thu Dec 27 07:57:11 2012
@@ -634,7 +634,6 @@
}
Handle<JSArray> result = factory()->NewJSArrayWithElements(elements);
result->set_length(Smi::FromInt(cursor));
- heap()->error_object_list()->Add(*error_object);
return result;
}
=======================================
--- /trunk/src/list-inl.h Fri Dec 21 04:35:02 2012
+++ /trunk/src/list-inl.h Thu Dec 27 07:57:11 2012
@@ -85,9 +85,8 @@
template<typename T, class P>
void List<T, P>::Resize(int new_capacity, P alloc) {
- ASSERT_LE(length_, new_capacity);
T* new_data = NewData(new_capacity, alloc);
- memcpy(new_data, data_, length_ * sizeof(T));
+ memcpy(new_data, data_, capacity_ * sizeof(T));
List<T, P>::DeleteData(data_);
data_ = new_data;
capacity_ = new_capacity;
@@ -160,14 +159,6 @@
void List<T, P>::Rewind(int pos) {
length_ = pos;
}
-
-
-template<typename T, class P>
-void List<T, P>::Trim(P alloc) {
- if (length_ < capacity_ / 4) {
- Resize(capacity_ / 2, alloc);
- }
-}
template<typename T, class P>
=======================================
--- /trunk/src/list.h Fri Dec 21 04:35:02 2012
+++ /trunk/src/list.h Thu Dec 27 07:57:11 2012
@@ -148,9 +148,6 @@
// Drop the last 'count' elements from the list.
INLINE(void RewindBy(int count)) { Rewind(length_ - count); }
-
- // Halve the capacity if fill level is less than a quarter.
- INLINE(void Trim(AllocationPolicy allocator = AllocationPolicy()));
bool Contains(const T& elm) const;
int CountOccurrences(const T& elm, int start, int end) const;
=======================================
--- /trunk/src/mark-compact.cc Fri Dec 21 04:35:02 2012
+++ /trunk/src/mark-compact.cc Thu Dec 27 07:57:11 2012
@@ -835,6 +835,8 @@
// GC, because it relies on the new address of certain old space
// objects (empty string, illegal builtin).
heap()->isolate()->stub_cache()->Clear();
+
+ heap()->external_string_table_.CleanUp();
}
@@ -2028,7 +2030,6 @@
symbol_table->ElementsRemoved(v.PointersRemoved());
heap()->external_string_table_.Iterate(&v);
heap()->external_string_table_.CleanUp();
- heap()->error_object_list_.RemoveUnmarked(heap());
// Process the weak references.
MarkCompactWeakObjectRetainer mark_compact_object_retainer;
@@ -3068,9 +3069,6 @@
heap_->UpdateReferencesInExternalStringTable(
&UpdateReferenceInExternalStringTableEntry);
- // Update pointers in the new error object list.
- heap_->error_object_list()->UpdateReferences();
-
if (!FLAG_watch_ic_patching) {
// Update JSFunction pointers from the runtime profiler.
heap()->isolate()->runtime_profiler()->UpdateSamplesAfterCompact(
=======================================
--- /trunk/src/messages.js Fri Dec 21 04:35:02 2012
+++ /trunk/src/messages.js Thu Dec 27 07:57:11 2012
@@ -820,7 +820,7 @@
%_CallFunction(this.receiver,
ownName,
ObjectLookupSetter) === this.fun ||
- %GetDataProperty(this.receiver, ownName) === this.fun)) {
+ this.receiver[ownName] === this.fun)) {
// To handle DontEnum properties we guess that the method has
// the same name as the function.
return ownName;
@@ -829,7 +829,8 @@
for (var prop in this.receiver) {
if (%_CallFunction(this.receiver, prop, ObjectLookupGetter) ===
this.fun ||
%_CallFunction(this.receiver, prop, ObjectLookupSetter) ===
this.fun ||
- %GetDataProperty(this.receiver, prop) === this.fun) {
+ (!%_CallFunction(this.receiver, prop, ObjectLookupGetter) &&
+ this.receiver[prop] === this.fun)) {
// If we find more than one match bail out to avoid confusion.
if (name) {
return null;
@@ -932,14 +933,12 @@
var typeName = GetTypeName(this, true);
var methodName = this.getMethodName();
if (functionName) {
- if (typeName &&
- %_CallFunction(functionName, typeName, StringIndexOf) != 0) {
+ if (typeName && functionName.indexOf(typeName) != 0) {
line += typeName + ".";
}
line += functionName;
- if (methodName &&
- (%_CallFunction(functionName, "." + methodName, StringIndexOf) !=
- functionName.length - methodName.length - 1)) {
+ if (methodName && functionName.lastIndexOf("." + methodName) !=
+ functionName.length - methodName.length - 1) {
line += " [as " + methodName + "]";
}
} else {
@@ -1017,37 +1016,17 @@
return eval_origin;
}
-
-function FormatErrorString(error) {
+function FormatStackTrace(error, frames) {
+ var lines = [];
try {
- return %_CallFunction(error, ErrorToString);
+ lines.push(error.toString());
} catch (e) {
try {
- return "<error: " + e + ">";
+ lines.push("<error: " + e + ">");
} catch (ee) {
- return "<error>";
+ lines.push("<error>");
}
}
-}
-
-
-function GetStackFrames(raw_stack) {
- var frames = new InternalArray();
- for (var i = 0; i < raw_stack.length; i += 4) {
- var recv = raw_stack[i];
- var fun = raw_stack[i + 1];
- var code = raw_stack[i + 2];
- var pc = raw_stack[i + 3];
- var pos = %FunctionGetPositionForOffset(code, pc);
- frames.push(new CallSite(recv, fun, pos));
- }
- return frames;
-}
-
-
-function FormatStackTrace(error_string, frames) {
- var lines = new InternalArray();
- lines.push(error_string);
for (var i = 0; i < frames.length; i++) {
var frame = frames[i];
var line;
@@ -1063,9 +1042,25 @@
}
lines.push(" at " + line);
}
- return %_CallFunction(lines, "\n", ArrayJoin);
+ return lines.join("\n");
}
+function FormatRawStackTrace(error, raw_stack) {
+ var frames = [ ];
+ for (var i = 0; i < raw_stack.length; i += 4) {
+ var recv = raw_stack[i];
+ var fun = raw_stack[i + 1];
+ var code = raw_stack[i + 2];
+ var pc = raw_stack[i + 3];
+ var pos = %FunctionGetPositionForOffset(code, pc);
+ frames.push(new CallSite(recv, fun, pos));
+ }
+ if (IS_FUNCTION($Error.prepareStackTrace)) {
+ return $Error.prepareStackTrace(error, frames);
+ } else {
+ return FormatStackTrace(error, frames);
+ }
+}
function GetTypeName(obj, requireConstructor) {
var constructor = obj.receiver.constructor;
@@ -1080,11 +1075,6 @@
}
return constructorName;
}
-
-
-// Flag to prevent recursive call of Error.prepareStackTrace.
-var formatting_custom_stack_trace = false;
-
function captureStackTrace(obj, cons_opt) {
var stackTraceLimit = $Error.stackTraceLimit;
@@ -1092,40 +1082,17 @@
if (stackTraceLimit < 0 || stackTraceLimit > 10000) {
stackTraceLimit = 10000;
}
- var stack = %CollectStackTrace(obj,
- cons_opt ? cons_opt : captureStackTrace,
- stackTraceLimit);
-
- // Don't be lazy if the error stack formatting is custom (observable).
- if (IS_FUNCTION($Error.prepareStackTrace)
&& !formatting_custom_stack_trace) {
- var array = [];
- %MoveArrayContents(GetStackFrames(stack), array);
- formatting_custom_stack_trace = true;
- try {
- obj.stack = $Error.prepareStackTrace(obj, array);
- } catch (e) {
- throw e; // The custom formatting function threw. Rethrow.
- } finally {
- formatting_custom_stack_trace = false;
- }
- return;
- }
-
- var error_string = FormatErrorString(obj);
+ var raw_stack = %CollectStackTrace(obj,
+ cons_opt ? cons_opt :
captureStackTrace,
+ stackTraceLimit);
// Note that 'obj' and 'this' maybe different when called on objects that
// have the error object on its prototype chain. The getter replaces
itself
// with a data property as soon as the stack trace has been formatted.
- // The getter must not change the object layout as it may be called
after GC.
var getter = function() {
- if (IS_STRING(stack)) return stack;
- // Stack is still a raw array awaiting to be formatted.
- stack = FormatStackTrace(error_string, GetStackFrames(stack));
- // Release context value.
- error_string = void 0;
- return stack;
+ var value = FormatRawStackTrace(obj, raw_stack);
+ %DefineOrRedefineDataProperty(obj, 'stack', value, NONE);
+ return value;
};
- %MarkOneShotGetter(getter);
-
// The 'stack' property of the receiver is set as data property. If
// the receiver is the same as holder, this accessor pair is replaced.
var setter = function(v) {
@@ -1272,32 +1239,23 @@
// error object copy, but can be found on the prototype chain of 'this'.
// When the stack trace is formatted, this accessor property is replaced
by
// a data property.
- var error_string = boilerplate.name + ": " + boilerplate.message;
-
- // The getter must not change the object layout as it may be called
after GC.
function getter() {
var holder = this;
while (!IS_ERROR(holder)) {
holder = %GetPrototype(holder);
if (holder == null) return MakeSyntaxError('illegal_access', []);
}
- var stack = %GetOverflowedStackTrace(holder);
- if (IS_STRING(stack)) return stack;
- if (IS_ARRAY(stack)) {
- var result = FormatStackTrace(error_string, GetStackFrames(stack));
- %SetOverflowedStackTrace(holder, result);
- return result;
- }
- return void 0;
+ var raw_stack = %GetOverflowedRawStackTrace(holder);
+ var result = IS_ARRAY(raw_stack) ? FormatRawStackTrace(holder,
raw_stack)
+ : void 0;
+ %DefineOrRedefineDataProperty(holder, 'stack', result, NONE);
+ return result;
}
- %MarkOneShotGetter(getter);
// The 'stack' property of the receiver is set as data property. If
// the receiver is the same as holder, this accessor pair is replaced.
function setter(v) {
%DefineOrRedefineDataProperty(this, 'stack', v, NONE);
- // Release the stack trace that is stored as hidden property, if
exists.
- %SetOverflowedStackTrace(this, void 0);
}
%DefineOrRedefineAccessorProperty(
=======================================
--- /trunk/src/runtime.cc Fri Dec 21 04:35:02 2012
+++ /trunk/src/runtime.cc Thu Dec 27 07:57:11 2012
@@ -13206,47 +13206,17 @@
}
-// Mark a function to recognize when called after GC to format the stack
trace.
-RUNTIME_FUNCTION(MaybeObject*, Runtime_MarkOneShotGetter) {
- ASSERT_EQ(args.length(), 1);
- CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
- HandleScope scope(isolate);
- Handle<String> key = isolate->factory()->hidden_stack_trace_symbol();
- JSObject::SetHiddenProperty(fun, key, key);
- return *fun;
-}
-
-
-// Retrieve the stack trace. This could be the raw stack trace collected
-// on stack overflow or the already formatted stack trace string.
-RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOverflowedStackTrace) {
- HandleScope scope(isolate);
+// Retrieve the raw stack trace collected on stack overflow and delete
+// it since it is used only once to avoid keeping it alive.
+RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOverflowedRawStackTrace) {
ASSERT_EQ(args.length(), 1);
CONVERT_ARG_CHECKED(JSObject, error_object, 0);
String* key = isolate->heap()->hidden_stack_trace_symbol();
Object* result = error_object->GetHiddenProperty(key);
- RUNTIME_ASSERT(result->IsJSArray() ||
- result->IsString() ||
- result->IsUndefined());
+ RUNTIME_ASSERT(result->IsJSArray() || result->IsUndefined());
+ error_object->DeleteHiddenProperty(key);
return result;
}
-
-
-// Set or clear the stack trace attached to an stack overflow error object.
-RUNTIME_FUNCTION(MaybeObject*, Runtime_SetOverflowedStackTrace) {
- HandleScope scope(isolate);
- ASSERT_EQ(args.length(), 2);
- CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
- CONVERT_ARG_HANDLE_CHECKED(HeapObject, value, 1);
- Handle<String> key = isolate->factory()->hidden_stack_trace_symbol();
- if (value->IsUndefined()) {
- error_object->DeleteHiddenProperty(*key);
- } else {
- RUNTIME_ASSERT(value->IsString());
- JSObject::SetHiddenProperty(error_object, key, value);
- }
- return *error_object;
-}
// Returns V8 version as a string.
=======================================
--- /trunk/src/runtime.h Fri Dec 21 04:35:02 2012
+++ /trunk/src/runtime.h Thu Dec 27 07:57:11 2012
@@ -237,9 +237,7 @@
F(FunctionIsBuiltin, 1, 1) \
F(GetScript, 1, 1) \
F(CollectStackTrace, 3, 1) \
- F(MarkOneShotGetter, 1, 1) \
- F(GetOverflowedStackTrace, 1, 1) \
- F(SetOverflowedStackTrace, 2, 1) \
+ F(GetOverflowedRawStackTrace, 1, 1) \
F(GetV8Version, 0, 1) \
\
F(ClassOf, 1, 1) \
=======================================
--- /trunk/src/version.cc Fri Dec 21 05:47:00 2012
+++ /trunk/src/version.cc Thu Dec 27 07:57:11 2012
@@ -34,7 +34,7 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 3
#define MINOR_VERSION 16
-#define BUILD_NUMBER 0
+#define BUILD_NUMBER 1
#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
=======================================
--- /trunk/src/x64/assembler-x64.cc Fri Dec 21 04:35:02 2012
+++ /trunk/src/x64/assembler-x64.cc Thu Dec 27 07:57:11 2012
@@ -2950,6 +2950,15 @@
emit(0x50);
emit_sse_operand(dst, src);
}
+
+
+void Assembler::movmskps(Register dst, XMMRegister src) {
+ EnsureSpace ensure_space(this);
+ emit_optional_rex_32(dst, src);
+ emit(0x0f);
+ emit(0x50);
+ emit_sse_operand(dst, src);
+}
void Assembler::emit_sse_operand(XMMRegister reg, const Operand& adr) {
=======================================
--- /trunk/src/x64/assembler-x64.h Fri Dec 21 04:35:02 2012
+++ /trunk/src/x64/assembler-x64.h Thu Dec 27 07:57:11 2012
@@ -1394,6 +1394,7 @@
void roundsd(XMMRegister dst, XMMRegister src, RoundingMode mode);
void movmskpd(Register dst, XMMRegister src);
+ void movmskps(Register dst, XMMRegister src);
// The first argument is the reg field, the second argument is the r/m
field.
void emit_sse_operand(XMMRegister dst, XMMRegister src);
=======================================
--- /trunk/src/x64/disasm-x64.cc Thu Jun 21 04:16:20 2012
+++ /trunk/src/x64/disasm-x64.cc Thu Dec 27 07:57:11 2012
@@ -1244,6 +1244,13 @@
AppendToBuffer("xorps %s, ", NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
+ } else if (opcode == 0x50) {
+ // movmskps reg, xmm
+ int mod, regop, rm;
+ get_modrm(*current, &mod, ®op, &rm);
+ AppendToBuffer("movmskps %s, ", NameOfCPURegister(regop));
+ current += PrintRightXMMOperand(current);
+
} else if ((opcode & 0xF0) == 0x80) {
// Jcc: Conditional jump (branch).
current = data + JumpConditional(data);
@@ -1724,6 +1731,11 @@
data += F6F7Instruction(data);
break;
+ case 0x3C:
+ AppendToBuffer("cmp al, 0x%x", *reinterpret_cast<int8_t*>(data +
1));
+ data +=2;
+ break;
+
default:
UnimplementedInstruction();
data += 1;
=======================================
--- /trunk/src/x64/lithium-codegen-x64.cc Fri Dec 21 04:35:02 2012
+++ /trunk/src/x64/lithium-codegen-x64.cc Thu Dec 27 07:57:11 2012
@@ -1642,17 +1642,17 @@
if (right->IsConstantOperand()) {
Immediate right_imm =
Immediate(ToInteger32(LConstantOperand::cast(right)));
- __ cmpq(left_reg, right_imm);
+ __ cmpl(left_reg, right_imm);
__ j(condition, &return_left, Label::kNear);
__ movq(left_reg, right_imm);
} else if (right->IsRegister()) {
Register right_reg = ToRegister(right);
- __ cmpq(left_reg, right_reg);
+ __ cmpl(left_reg, right_reg);
__ j(condition, &return_left, Label::kNear);
__ movq(left_reg, right_reg);
} else {
Operand right_op = ToOperand(right);
- __ cmpq(left_reg, right_op);
+ __ cmpl(left_reg, right_op);
__ j(condition, &return_left, Label::kNear);
__ movq(left_reg, right_op);
}
=======================================
--- /trunk/test/cctest/test-decls.cc Fri Dec 21 04:35:02 2012
+++ /trunk/test/cctest/test-decls.cc Thu Dec 27 07:57:11 2012
@@ -161,7 +161,6 @@
CHECK_EQ(value, catcher.Exception());
}
}
- HEAP->CollectAllAvailableGarbage(); // Clean slate for the next test.
}
=======================================
--- /trunk/test/cctest/test-heap.cc Fri Dec 21 04:35:02 2012
+++ /trunk/test/cctest/test-heap.cc Thu Dec 27 07:57:11 2012
@@ -2429,7 +2429,11 @@
CHECK(!resource->IsDisposed());
}
HEAP->CollectAllAvailableGarbage();
+ // External source is being retained by the stack trace.
+ CHECK(!resource->IsDisposed());
+ CompileRun("error.stack;");
+ HEAP->CollectAllAvailableGarbage();
// External source has been released.
CHECK(resource->IsDisposed());
delete resource;
=======================================
--- /trunk/test/cctest/test-object-observe.cc Fri Dec 21 04:35:02 2012
+++ /trunk/test/cctest/test-object-observe.cc Thu Dec 27 07:57:11 2012
@@ -278,6 +278,7 @@
}
CHECK_EQ(3, CompileRun("records.length")->Int32Value());
}
+
struct RecordExpectation {
Handle<Value> object;
@@ -309,6 +310,9 @@
}
}
}
+
+#define EXPECT_RECORDS(records, expectations) \
+ ExpectRecords(records, expectations, ARRAY_SIZE(expectations))
TEST(APITestBasicMutation) {
HarmonyIsolate isolate;
@@ -348,7 +352,48 @@
{ obj, "deleted", "1", Number::New(5) },
{ obj, "deleted", "1.1", Number::New(6) }
};
- ExpectRecords(CompileRun("records"),
- expected_records,
- ARRAY_SIZE(expected_records));
+ EXPECT_RECORDS(CompileRun("records"), expected_records);
+}
+
+TEST(HiddenPrototypeObservation) {
+ HarmonyIsolate isolate;
+ HandleScope scope;
+ LocalContext context;
+ Handle<FunctionTemplate> tmpl = FunctionTemplate::New();
+ tmpl->SetHiddenPrototype(true);
+ tmpl->InstanceTemplate()->Set(String::New("foo"), Number::New(75));
+ Handle<Object> proto = tmpl->GetFunction()->NewInstance();
+ Handle<Object> obj = Object::New();
+ obj->SetPrototype(proto);
+ context->Global()->Set(String::New("obj"), obj);
+ context->Global()->Set(String::New("proto"), proto);
+ CompileRun(
+ "var records;"
+ "function observer(r) { records = r; };"
+ "Object.observe(obj, observer);"
+ "obj.foo = 41;" // triggers a notification
+ "proto.foo = 42;"); // does not trigger a notification
+ const RecordExpectation expected_records[] = {
+ { obj, "updated", "foo", Number::New(75) }
+ };
+ EXPECT_RECORDS(CompileRun("records"), expected_records);
+ obj->SetPrototype(Null());
+ CompileRun("obj.foo = 43");
+ const RecordExpectation expected_records2[] = {
+ { obj, "new", "foo", Handle<Value>() }
+ };
+ EXPECT_RECORDS(CompileRun("records"), expected_records2);
+ obj->SetPrototype(proto);
+ CompileRun(
+ "Object.observe(proto, observer);"
+ "proto.bar = 1;"
+ "Object.unobserve(obj, observer);"
+ "obj.foo = 44;");
+ const RecordExpectation expected_records3[] = {
+ { proto, "new", "bar", Handle<Value>() }
+ // TODO(adamk): The below record should be emitted since proto is
observed
+ // and has been modified. Not clear if this happens in practice.
+ // { proto, "updated", "foo", Number::New(43) }
+ };
+ EXPECT_RECORDS(CompileRun("records"), expected_records3);
}
=======================================
--- /trunk/test/message/overwritten-builtins.out Fri Dec 21 04:35:02 2012
+++ /trunk/test/message/overwritten-builtins.out Thu Dec 27 07:57:11 2012
@@ -28,6 +28,3 @@
*%(basename)s:31: TypeError: Cannot read property 'x' of undefined
undefined.x
^
-TypeError: Cannot read property 'x' of undefined
- at *%(basename)s:31:10
-
=======================================
--- /trunk/test/mjsunit/eval-stack-trace.js Fri Dec 21 04:35:02 2012
+++ /trunk/test/mjsunit/eval-stack-trace.js Thu Dec 27 07:57:11 2012
@@ -26,13 +26,12 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Return the stack frames of an Error object.
-
-Error.prepareStackTrace = function(error, frames) {
- return frames;
-}
-
Error.prototype.getFrames = function() {
+ Error.prepareStackTrace = function(error, frames) {
+ return frames;
+ }
var frames = this.stack;
+ Error.prepareStackTrace = undefined;
return frames;
}
=======================================
--- /trunk/test/mjsunit/stack-traces.js Fri Dec 21 04:35:02 2012
+++ /trunk/test/mjsunit/stack-traces.js Thu Dec 27 07:57:11 2012
@@ -289,41 +289,3 @@
// Omitted because ADD from runtime.js is non-native builtin.
testOmittedBuiltin(function(){ thrower + 2; }, "ADD");
-
-var error = new Error();
-error.toString = function() { assertUnreachable(); };
-error.stack;
-
-error = new Error();
-error.name = { toString: function() { assertUnreachable(); }};
-error.message = { toString: function() { assertUnreachable(); }};
-error.stack;
-
-error = new Error();
-Array.prototype.push = function(x) { assertUnreachable(); };
-Array.prototype.join = function(x) { assertUnreachable(); };
-error.stack;
-
-var fired = false;
-error = new Error({ toString: function() { fired = true; } });
-assertTrue(fired);
-error.stack;
-assertTrue(fired);
-
-// Check that throwing exception in a custom stack trace formatting
function
-// does not lead to recursion.
-Error.prepareStackTrace = function() { throw new Error("abc"); };
-var message;
-try {
- throw new Error();
-} catch (e) {
- message = e.message;
-}
-
-assertEquals("abc", message);
-
-// Test that modifying Error.prepareStackTrace by itself works.
-Error.prepareStackTrace = function() { Error.prepareStackTrace = "custom";
};
-new Error();
-
-assertEquals("custom", Error.prepareStackTrace);
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev