Version 3.9.1
Fixed memory leak in NativeObjectsExplorer::FindOrAddGroupInfo (Chromium issue 112315).
Fixed a crash in dev tools (Chromium issue 107996).
Added 'dependencies_traverse': 1 to v8 GYP target.
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@10594 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index f69a5b7..79beb3b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2012-02-02: Version 3.9.1
+
+ Fixed memory leak in NativeObjectsExplorer::FindOrAddGroupInfo
+ (Chromium issue 112315).
+
+ Fixed a crash in dev tools (Chromium issue 107996).
+
+ Added 'dependencies_traverse': 1 to v8 GYP target.
+
+ Performance and stability improvements on all platforms.
+
+
2012-02-01: Version 3.9.0
Reduce memory use immediately after starting V8.
diff --git a/include/v8.h b/include/v8.h
index 08c2fa2..66a649d 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -3539,6 +3539,12 @@
void AllowCodeGenerationFromStrings(bool allow);
/**
+ * Returns true if code generation from strings is allowed for the context.
+ * For more details see AllowCodeGenerationFromStrings(bool) documentation.
+ */
+ bool IsCodeGenerationFromStringsAllowed();
+
+ /**
* Stack-allocated class which sets the execution context for all
* operations executed within a local scope.
*/
diff --git a/src/api.cc b/src/api.cc
index ff7ab2d..0b67516 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -4313,6 +4313,20 @@
}
+bool Context::IsCodeGenerationFromStringsAllowed() {
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate,
+ "v8::Context::IsCodeGenerationFromStringsAllowed()")) {
+ return false;
+ }
+ ENTER_V8(isolate);
+ i::Object** ctx = reinterpret_cast<i::Object**>(this);
+ i::Handle<i::Context> context =
+ i::Handle<i::Context>::cast(i::Handle<i::Object>(ctx));
+ return !context->allow_code_gen_from_strings()->IsFalse();
+}
+
+
void V8::SetWrapperClassId(i::Object** global_handle, uint16_t class_id) {
i::GlobalHandles::SetWrapperClassId(global_handle, class_id);
}
diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc
index 756634d..186d06e 100644
--- a/src/arm/builtins-arm.cc
+++ b/src/arm/builtins-arm.cc
@@ -114,7 +114,7 @@
Label* gc_required) {
const int initial_capacity = JSArray::kPreallocatedArrayElements;
STATIC_ASSERT(initial_capacity >= 0);
- __ LoadGlobalInitialConstructedArrayMap(array_function, scratch2, scratch1);
+ __ LoadInitialArrayMap(array_function, scratch2, scratch1);
// Allocate the JSArray object together with space for a fixed array with the
// requested elements.
@@ -208,8 +208,7 @@
bool fill_with_hole,
Label* gc_required) {
// Load the initial map from the array function.
- __ LoadGlobalInitialConstructedArrayMap(array_function, scratch2,
- elements_array_storage);
+ __ LoadInitialArrayMap(array_function, scratch2, elements_array_storage);
if (FLAG_debug_code) { // Assert that array size is not zero.
__ tst(array_size, array_size);
diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc
index dfd4d2e..14daada 100644
--- a/src/arm/ic-arm.cc
+++ b/src/arm/ic-arm.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// 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:
@@ -1312,14 +1312,16 @@
Label slow, array, extra, check_if_double_array;
Label fast_object_with_map_check, fast_object_without_map_check;
Label fast_double_with_map_check, fast_double_without_map_check;
+ Label transition_smi_elements, finish_object_store, non_double_value;
+ Label transition_double_elements;
// Register usage.
Register value = r0;
Register key = r1;
Register receiver = r2;
- Register elements = r3; // Elements array of the receiver.
+ Register receiver_map = r3;
Register elements_map = r6;
- Register receiver_map = r7;
+ Register elements = r7; // Elements array of the receiver.
// r4 and r5 are used as general scratch registers.
// Check that the key is a smi.
@@ -1417,9 +1419,11 @@
__ Ret();
__ bind(&non_smi_value);
- // Escape to slow case when writing non-smi into smi-only array.
- __ CheckFastObjectElements(receiver_map, scratch_value, &slow);
+ // Escape to elements kind transition case.
+ __ CheckFastObjectElements(receiver_map, scratch_value,
+ &transition_smi_elements);
// Fast elements array, store the value to the elements backing store.
+ __ bind(&finish_object_store);
__ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
__ add(address, address, Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize));
__ str(value, MemOperand(address));
@@ -1445,12 +1449,56 @@
key,
receiver,
elements,
+ r3,
r4,
r5,
r6,
- r7,
- &slow);
+ &transition_double_elements);
__ Ret();
+
+ __ bind(&transition_smi_elements);
+ // Transition the array appropriately depending on the value type.
+ __ ldr(r4, FieldMemOperand(value, HeapObject::kMapOffset));
+ __ CompareRoot(r4, Heap::kHeapNumberMapRootIndex);
+ __ b(ne, &non_double_value);
+
+ // Value is a double. Transition FAST_SMI_ONLY_ELEMENTS ->
+ // FAST_DOUBLE_ELEMENTS and complete the store.
+ __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+ FAST_DOUBLE_ELEMENTS,
+ receiver_map,
+ r4,
+ &slow);
+ ASSERT(receiver_map.is(r3)); // Transition code expects map in r3
+ ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &slow);
+ __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
+ __ jmp(&fast_double_without_map_check);
+
+ __ bind(&non_double_value);
+ // Value is not a double, FAST_SMI_ONLY_ELEMENTS -> FAST_ELEMENTS
+ __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+ FAST_ELEMENTS,
+ receiver_map,
+ r4,
+ &slow);
+ ASSERT(receiver_map.is(r3)); // Transition code expects map in r3
+ ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm);
+ __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
+ __ jmp(&finish_object_store);
+
+ __ bind(&transition_double_elements);
+ // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
+ // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
+ // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
+ __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
+ FAST_ELEMENTS,
+ receiver_map,
+ r4,
+ &slow);
+ ASSERT(receiver_map.is(r3)); // Transition code expects map in r3
+ ElementsTransitionGenerator::GenerateDoubleToObject(masm, &slow);
+ __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
+ __ jmp(&finish_object_store);
}
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index 22970e4..c92b943 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -2879,27 +2879,42 @@
}
-void MacroAssembler::LoadGlobalInitialConstructedArrayMap(
+void MacroAssembler::LoadTransitionedArrayMapConditional(
+ ElementsKind expected_kind,
+ ElementsKind transitioned_kind,
+ Register map_in_out,
+ Register scratch,
+ Label* no_map_match) {
+ // Load the global or builtins object from the current context.
+ ldr(scratch, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
+ ldr(scratch, FieldMemOperand(scratch, GlobalObject::kGlobalContextOffset));
+
+ // Check that the function's map is the same as the expected cached map.
+ int expected_index =
+ Context::GetContextMapIndexFromElementsKind(expected_kind);
+ ldr(ip, MemOperand(scratch, Context::SlotOffset(expected_index)));
+ cmp(map_in_out, ip);
+ b(ne, no_map_match);
+
+ // Use the transitioned cached map.
+ int trans_index =
+ Context::GetContextMapIndexFromElementsKind(transitioned_kind);
+ ldr(map_in_out, MemOperand(scratch, Context::SlotOffset(trans_index)));
+}
+
+
+void MacroAssembler::LoadInitialArrayMap(
Register function_in, Register scratch, Register map_out) {
ASSERT(!function_in.is(map_out));
Label done;
ldr(map_out, FieldMemOperand(function_in,
JSFunction::kPrototypeOrInitialMapOffset));
if (!FLAG_smi_only_arrays) {
- // Load the global or builtins object from the current context.
- ldr(scratch, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
- ldr(scratch, FieldMemOperand(scratch, GlobalObject::kGlobalContextOffset));
-
- // Check that the function's map is same as the cached map.
- ldr(ip, MemOperand(
- scratch, Context::SlotOffset(Context::SMI_JS_ARRAY_MAP_INDEX)));
- cmp(map_out, ip);
- b(ne, &done);
-
- // Use the cached transitioned map.
- ldr(map_out,
- MemOperand(scratch,
- Context::SlotOffset(Context::OBJECT_JS_ARRAY_MAP_INDEX)));
+ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+ FAST_ELEMENTS,
+ map_out,
+ scratch,
+ &done);
}
bind(&done);
}
diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h
index f228bdd..368ca5c 100644
--- a/src/arm/macro-assembler-arm.h
+++ b/src/arm/macro-assembler-arm.h
@@ -491,10 +491,21 @@
void LoadContext(Register dst, int context_chain_length);
- // Load the initial map for new Arrays of a given type.
- void LoadGlobalInitialConstructedArrayMap(Register function_in,
- Register scratch,
- Register map_out);
+ // Conditionally load the cached Array transitioned map of type
+ // transitioned_kind from the global context if the map in register
+ // map_in_out is the cached Array map in the global context of
+ // expected_kind.
+ void LoadTransitionedArrayMapConditional(
+ ElementsKind expected_kind,
+ ElementsKind transitioned_kind,
+ Register map_in_out,
+ Register scratch,
+ Label* no_map_match);
+
+ // Load the initial map for new Arrays from a JSFunction.
+ void LoadInitialArrayMap(Register function_in,
+ Register scratch,
+ Register map_out);
void LoadGlobalFunction(int index, Register function);
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index 33fbee5..d8fc2e4 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -45,6 +45,7 @@
StubCache::Table table,
Register name,
Register offset,
+ int offset_shift_bits,
Register scratch,
Register scratch2) {
ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
@@ -63,23 +64,34 @@
// Check that the key in the entry matches the name.
__ mov(offsets_base_addr, Operand(key_offset));
- __ ldr(ip, MemOperand(offsets_base_addr, offset, LSL, 1));
+ __ ldr(ip, MemOperand(offsets_base_addr, offset, LSL, 1 + offset_shift_bits));
__ cmp(name, ip);
__ b(ne, &miss);
// Get the code entry from the cache.
__ add(offsets_base_addr, offsets_base_addr,
Operand(value_off_addr - key_off_addr));
- __ ldr(scratch2, MemOperand(offsets_base_addr, offset, LSL, 1));
+ __ ldr(scratch2,
+ MemOperand(offsets_base_addr, offset, LSL, 1 + offset_shift_bits));
// Check that the flags match what we're looking for.
__ ldr(scratch2, FieldMemOperand(scratch2, Code::kFlagsOffset));
- __ bic(scratch2, scratch2, Operand(Code::kFlagsNotUsedInLookup));
- __ cmp(scratch2, Operand(flags));
+ // It's a nice optimization if this constant is encodable in the bic insn.
+
+ uint32_t mask = Code::kFlagsNotUsedInLookup;
+ ASSERT(__ ImmediateFitsAddrMode1Instruction(mask));
+ __ bic(scratch2, scratch2, Operand(mask));
+ // Using cmn and the negative instead of cmp means we can use movw.
+ if (flags < 0) {
+ __ cmn(scratch2, Operand(-flags));
+ } else {
+ __ cmp(scratch2, Operand(flags));
+ }
__ b(ne, &miss);
// Re-load code entry from cache.
- __ ldr(offset, MemOperand(offsets_base_addr, offset, LSL, 1));
+ __ ldr(offset,
+ MemOperand(offsets_base_addr, offset, LSL, 1 + offset_shift_bits));
// Jump to the first instruction in the code stub.
__ add(offset, offset, Operand(Code::kHeaderSize - kHeapObjectTag));
@@ -189,23 +201,39 @@
__ ldr(scratch, FieldMemOperand(name, String::kHashFieldOffset));
__ ldr(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
__ add(scratch, scratch, Operand(ip));
- __ eor(scratch, scratch, Operand(flags));
- __ and_(scratch,
- scratch,
- Operand((kPrimaryTableSize - 1) << kHeapObjectTagSize));
+ uint32_t mask = (kPrimaryTableSize - 1) << kHeapObjectTagSize;
+ // Mask down the eor argument to the minimum to keep the immediate
+ // ARM-encodable.
+ __ eor(scratch, scratch, Operand(flags & mask));
+ // Prefer ubfx to and_ here because the mask is not ARM-encodable.
+ __ Ubfx(scratch, scratch, kHeapObjectTagSize, kPrimaryTableBits);
// Probe the primary table.
- ProbeTable(isolate, masm, flags, kPrimary, name, scratch, extra, extra2);
+ ProbeTable(isolate,
+ masm,
+ flags,
+ kPrimary,
+ name,
+ scratch,
+ kHeapObjectTagSize,
+ extra,
+ extra2);
// Primary miss: Compute hash for secondary probe.
- __ sub(scratch, scratch, Operand(name));
+ __ rsb(scratch, name, Operand(scratch, LSL, kHeapObjectTagSize));
__ add(scratch, scratch, Operand(flags));
- __ and_(scratch,
- scratch,
- Operand((kSecondaryTableSize - 1) << kHeapObjectTagSize));
+ __ Ubfx(scratch, scratch, kHeapObjectTagSize, kSecondaryTableBits);
// Probe the secondary table.
- ProbeTable(isolate, masm, flags, kSecondary, name, scratch, extra, extra2);
+ ProbeTable(isolate,
+ masm,
+ flags,
+ kSecondary,
+ name,
+ scratch,
+ kHeapObjectTagSize,
+ extra,
+ extra2);
// Cache miss: Fall-through and let caller handle the miss by
// entering the runtime system.
diff --git a/src/contexts.h b/src/contexts.h
index 102d997..1f88c94 100644
--- a/src/contexts.h
+++ b/src/contexts.h
@@ -369,6 +369,18 @@
Object* OptimizedFunctionsListHead();
void ClearOptimizedFunctions();
+ static int GetContextMapIndexFromElementsKind(
+ ElementsKind elements_kind) {
+ if (elements_kind == FAST_DOUBLE_ELEMENTS) {
+ return Context::DOUBLE_JS_ARRAY_MAP_INDEX;
+ } else if (elements_kind == FAST_ELEMENTS) {
+ return Context::OBJECT_JS_ARRAY_MAP_INDEX;
+ } else {
+ ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
+ return Context::SMI_JS_ARRAY_MAP_INDEX;
+ }
+ }
+
#define GLOBAL_CONTEXT_FIELD_ACCESSORS(index, type, name) \
void set_##name(type* value) { \
ASSERT(IsGlobalContext()); \
diff --git a/src/d8.cc b/src/d8.cc
index e555c15..94e3270 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -1485,6 +1485,14 @@
}
printf("======== Full Deoptimization =======\n");
Testing::DeoptimizeAll();
+#if !defined(V8_SHARED)
+ } else if (i::FLAG_stress_runs > 0) {
+ int stress_runs = i::FLAG_stress_runs;
+ for (int i = 0; i < stress_runs && result == 0; i++) {
+ printf("============ Run %d/%d ============\n", i + 1, stress_runs);
+ result = RunMain(argc, argv);
+ }
+#endif
} else {
result = RunMain(argc, argv);
}
diff --git a/src/heap.cc b/src/heap.cc
index ff978cf..3b77714 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -6513,7 +6513,8 @@
GCTracer::GCTracer(Heap* heap)
: start_time_(0.0),
- start_size_(0),
+ start_object_size_(0),
+ start_memory_size_(0),
gc_count_(0),
full_gc_count_(0),
allocated_since_last_gc_(0),
@@ -6522,7 +6523,8 @@
heap_(heap) {
if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return;
start_time_ = OS::TimeCurrentMillis();
- start_size_ = heap_->SizeOfObjects();
+ start_object_size_ = heap_->SizeOfObjects();
+ start_memory_size_ = heap_->isolate()->memory_allocator()->Size();
for (int i = 0; i < Scope::kNumberOfScopes; i++) {
scopes_[i] = 0;
@@ -6572,10 +6574,15 @@
if (!FLAG_trace_gc_nvp) {
int external_time = static_cast<int>(scopes_[Scope::EXTERNAL]);
- PrintF("%s %.1f -> %.1f MB, ",
+ double end_memory_size_mb =
+ static_cast<double>(heap_->isolate()->memory_allocator()->Size()) / MB;
+
+ PrintF("%s %.1f (%.1f) -> %.1f (%.1f) MB, ",
CollectorString(),
- static_cast<double>(start_size_) / MB,
- SizeOfHeapObjects());
+ static_cast<double>(start_object_size_) / MB,
+ static_cast<double>(start_memory_size_) / MB,
+ SizeOfHeapObjects(),
+ end_memory_size_mb);
if (external_time > 0) PrintF("%d / ", external_time);
PrintF("%d ms", time);
@@ -6629,7 +6636,7 @@
PrintF("misc_compaction=%d ",
static_cast<int>(scopes_[Scope::MC_UPDATE_MISC_POINTERS]));
- PrintF("total_size_before=%" V8_PTR_PREFIX "d ", start_size_);
+ PrintF("total_size_before=%" V8_PTR_PREFIX "d ", start_object_size_);
PrintF("total_size_after=%" V8_PTR_PREFIX "d ", heap_->SizeOfObjects());
PrintF("holes_size_before=%" V8_PTR_PREFIX "d ",
in_free_list_or_wasted_before_gc_);
diff --git a/src/heap.h b/src/heap.h
index e9cbb52..4b0c05f 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -2387,9 +2387,17 @@
// Returns size of object in heap (in MB).
inline double SizeOfHeapObjects();
- double start_time_; // Timestamp set in the constructor.
- intptr_t start_size_; // Size of objects in heap set in constructor.
- GarbageCollector collector_; // Type of collector.
+ // Timestamp set in the constructor.
+ double start_time_;
+
+ // Size of objects in heap set in constructor.
+ intptr_t start_object_size_;
+
+ // Size of memory allocated from OS set in constructor.
+ intptr_t start_memory_size_;
+
+ // Type of collector.
+ GarbageCollector collector_;
// A count (including this one, e.g. the first collection is 1) of the
// number of garbage collections.
diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc
index 1837f20..efa3456 100644
--- a/src/ia32/builtins-ia32.cc
+++ b/src/ia32/builtins-ia32.cc
@@ -894,7 +894,7 @@
const int initial_capacity = JSArray::kPreallocatedArrayElements;
STATIC_ASSERT(initial_capacity >= 0);
- __ LoadGlobalInitialConstructedArrayMap(array_function, scratch2, scratch1);
+ __ LoadInitialArrayMap(array_function, scratch2, scratch1);
// Allocate the JSArray object together with space for a fixed array with the
// requested elements.
@@ -997,9 +997,7 @@
ASSERT(!fill_with_hole || array_size.is(ecx)); // rep stos count
ASSERT(!fill_with_hole || !result.is(eax)); // result is never eax
- __ LoadGlobalInitialConstructedArrayMap(array_function,
- scratch,
- elements_array);
+ __ LoadInitialArrayMap(array_function, scratch, elements_array);
// Allocate the JSArray object together with space for a FixedArray with the
// requested elements.
diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc
index 3a93790..dbb0554 100644
--- a/src/ia32/ic-ia32.cc
+++ b/src/ia32/ic-ia32.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// 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:
@@ -765,7 +765,8 @@
// -----------------------------------
Label slow, fast_object_with_map_check, fast_object_without_map_check;
Label fast_double_with_map_check, fast_double_without_map_check;
- Label check_if_double_array, array, extra;
+ Label check_if_double_array, array, extra, transition_smi_elements;
+ Label finish_object_store, non_double_value, transition_double_elements;
// Check that the object isn't a smi.
__ JumpIfSmi(edx, &slow);
@@ -862,11 +863,12 @@
__ ret(0);
__ bind(&non_smi_value);
- // Escape to slow case when writing non-smi into smi-only array.
+ // Escape to elements kind transition case.
__ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
- __ CheckFastObjectElements(edi, &slow, Label::kNear);
+ __ CheckFastObjectElements(edi, &transition_smi_elements);
// Fast elements array, store the value to the elements backing store.
+ __ bind(&finish_object_store);
__ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax);
// Update write barrier for the elements array address.
__ mov(edx, eax); // Preserve the value which is returned.
@@ -882,8 +884,54 @@
__ bind(&fast_double_without_map_check);
// If the value is a number, store it as a double in the FastDoubleElements
// array.
- __ StoreNumberToDoubleElements(eax, ebx, ecx, edx, xmm0, &slow, false);
+ __ StoreNumberToDoubleElements(eax, ebx, ecx, edx, xmm0,
+ &transition_double_elements, false);
__ ret(0);
+
+ __ bind(&transition_smi_elements);
+ __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
+
+ // Transition the array appropriately depending on the value type.
+ __ CheckMap(eax,
+ masm->isolate()->factory()->heap_number_map(),
+ &non_double_value,
+ DONT_DO_SMI_CHECK);
+
+ // Value is a double. Transition FAST_SMI_ONLY_ELEMENTS ->
+ // FAST_DOUBLE_ELEMENTS and complete the store.
+ __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+ FAST_DOUBLE_ELEMENTS,
+ ebx,
+ edi,
+ &slow);
+ ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &slow);
+ __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
+ __ jmp(&fast_double_without_map_check);
+
+ __ bind(&non_double_value);
+ // Value is not a double, FAST_SMI_ONLY_ELEMENTS -> FAST_ELEMENTS
+ __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+ FAST_ELEMENTS,
+ ebx,
+ edi,
+ &slow);
+ ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm);
+ __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
+ __ jmp(&finish_object_store);
+
+ __ bind(&transition_double_elements);
+ // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
+ // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
+ // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
+ __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
+ __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
+ FAST_ELEMENTS,
+ ebx,
+ edi,
+ &slow);
+ ElementsTransitionGenerator::GenerateDoubleToObject(masm, &slow);
+ __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
+ __ jmp(&finish_object_store);
}
diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc
index 505fac6..6a20808 100644
--- a/src/ia32/macro-assembler-ia32.cc
+++ b/src/ia32/macro-assembler-ia32.cc
@@ -2168,27 +2168,41 @@
}
-void MacroAssembler::LoadGlobalInitialConstructedArrayMap(
+void MacroAssembler::LoadTransitionedArrayMapConditional(
+ ElementsKind expected_kind,
+ ElementsKind transitioned_kind,
+ Register map_in_out,
+ Register scratch,
+ Label* no_map_match) {
+ // Load the global or builtins object from the current context.
+ mov(scratch, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
+ mov(scratch, FieldOperand(scratch, GlobalObject::kGlobalContextOffset));
+
+ // Check that the function's map is the same as the expected cached map.
+ int expected_index =
+ Context::GetContextMapIndexFromElementsKind(expected_kind);
+ cmp(map_in_out, Operand(scratch, Context::SlotOffset(expected_index)));
+ j(not_equal, no_map_match);
+
+ // Use the transitioned cached map.
+ int trans_index =
+ Context::GetContextMapIndexFromElementsKind(transitioned_kind);
+ mov(map_in_out, Operand(scratch, Context::SlotOffset(trans_index)));
+}
+
+
+void MacroAssembler::LoadInitialArrayMap(
Register function_in, Register scratch, Register map_out) {
ASSERT(!function_in.is(map_out));
Label done;
mov(map_out, FieldOperand(function_in,
JSFunction::kPrototypeOrInitialMapOffset));
if (!FLAG_smi_only_arrays) {
- // Load the global or builtins object from the current context.
- mov(scratch, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
- mov(scratch, FieldOperand(scratch, GlobalObject::kGlobalContextOffset));
-
- // Check that the function's map is same as the cached map.
- cmp(map_out,
- Operand(scratch,
- Context::SlotOffset(Context::SMI_JS_ARRAY_MAP_INDEX)));
- j(not_equal, &done);
-
- // Use the cached transitioned map.
- mov(map_out,
- Operand(scratch,
- Context::SlotOffset(Context::OBJECT_JS_ARRAY_MAP_INDEX)));
+ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+ FAST_ELEMENTS,
+ map_out,
+ scratch,
+ &done);
}
bind(&done);
}
diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h
index fc91d7c..d1d40eb 100644
--- a/src/ia32/macro-assembler-ia32.h
+++ b/src/ia32/macro-assembler-ia32.h
@@ -221,10 +221,21 @@
// Find the function context up the context chain.
void LoadContext(Register dst, int context_chain_length);
- // Load the initial map for new Arrays of a given type.
- void LoadGlobalInitialConstructedArrayMap(Register function_in,
- Register scratch,
- Register map_out);
+ // Conditionally load the cached Array transitioned map of type
+ // transitioned_kind from the global context if the map in register
+ // map_in_out is the cached Array map in the global context of
+ // expected_kind.
+ void LoadTransitionedArrayMapConditional(
+ ElementsKind expected_kind,
+ ElementsKind transitioned_kind,
+ Register map_in_out,
+ Register scratch,
+ Label* no_map_match);
+
+ // Load the initial map for new Arrays from a JSFunction.
+ void LoadInitialArrayMap(Register function_in,
+ Register scratch,
+ Register map_out);
// Load the global function with the given index.
void LoadGlobalFunction(int index, Register function);
diff --git a/src/objects-printer.cc b/src/objects-printer.cc
index eca9bab..67adad6 100644
--- a/src/objects-printer.cc
+++ b/src/objects-printer.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// 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:
@@ -569,7 +569,11 @@
HeapObject::PrintHeader(out, "FixedDoubleArray");
PrintF(out, " - length: %d", length());
for (int i = 0; i < length(); i++) {
- PrintF(out, "\n [%d]: %g", i, get_scalar(i));
+ if (is_the_hole(i)) {
+ PrintF(out, "\n [%d]: <the hole>", i);
+ } else {
+ PrintF(out, "\n [%d]: %g", i, get_scalar(i));
+ }
}
PrintF(out, "\n");
}
diff --git a/src/objects.h b/src/objects.h
index 9ec0ea6..9cd8d72 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -4364,8 +4364,8 @@
// Flags layout. BitField<type, shift, size>.
class ICStateField: public BitField<InlineCacheState, 0, 3> {};
class TypeField: public BitField<PropertyType, 3, 4> {};
- class KindField: public BitField<Kind, 7, 4> {};
- class CacheHolderField: public BitField<InlineCacheHolderFlag, 11, 1> {};
+ class CacheHolderField: public BitField<InlineCacheHolderFlag, 7, 1> {};
+ class KindField: public BitField<Kind, 8, 4> {};
class ExtraICStateField: public BitField<ExtraICState, 12, 2> {};
class IsPregeneratedField: public BitField<bool, 14, 1> {};
@@ -4373,6 +4373,7 @@
static const int kArgumentsCountShift = 15;
static const int kArgumentsCountMask = ~((1 << kArgumentsCountShift) - 1);
+ // This constant should be encodable in an ARM instruction.
static const int kFlagsNotUsedInLookup =
TypeField::kMask | CacheHolderField::kMask;
diff --git a/src/profile-generator.cc b/src/profile-generator.cc
index 409c24c..614287f 100644
--- a/src/profile-generator.cc
+++ b/src/profile-generator.cc
@@ -2720,6 +2720,13 @@
reinterpret_cast<List<HeapObject*>* >(p->value);
delete objects;
}
+ for (HashMap::Entry* p = native_groups_.Start();
+ p != NULL;
+ p = native_groups_.Next(p)) {
+ v8::RetainedObjectInfo* info =
+ reinterpret_cast<v8::RetainedObjectInfo*>(p->value);
+ info->Dispose();
+ }
}
@@ -2824,6 +2831,7 @@
virtual void Dispose() {
CHECK(!disposed_);
disposed_ = true;
+ delete this;
}
virtual bool IsEquivalent(RetainedObjectInfo* other) {
return hash_ == other->GetHash() && !strcmp(label_, other->GetLabel());
diff --git a/src/scopes.cc b/src/scopes.cc
index d0ee8ec..a7ff287 100644
--- a/src/scopes.cc
+++ b/src/scopes.cc
@@ -149,12 +149,10 @@
SetDefaults(type, NULL, scope_info);
if (!scope_info.is_null()) {
num_heap_slots_ = scope_info_->ContextLength();
- if (*scope_info != ScopeInfo::Empty()) {
- language_mode_ = scope_info->language_mode();
- }
- } else if (is_with_scope()) {
- num_heap_slots_ = Context::MIN_CONTEXT_SLOTS;
}
+ // Ensure at least MIN_CONTEXT_SLOTS to indicate a materialized context.
+ num_heap_slots_ = Max(num_heap_slots_,
+ static_cast<int>(Context::MIN_CONTEXT_SLOTS));
AddInnerScope(inner_scope);
}
diff --git a/src/stub-cache.h b/src/stub-cache.h
index 720ad8b..398d9f4 100644
--- a/src/stub-cache.h
+++ b/src/stub-cache.h
@@ -343,8 +343,10 @@
reinterpret_cast<Address>(table) + (offset << shift_amount));
}
- static const int kPrimaryTableSize = 2048;
- static const int kSecondaryTableSize = 512;
+ static const int kPrimaryTableBits = 11;
+ static const int kPrimaryTableSize = (1 << kPrimaryTableBits);
+ static const int kSecondaryTableBits = 9;
+ static const int kSecondaryTableSize = (1 << kSecondaryTableBits);
Entry primary_[kPrimaryTableSize];
Entry secondary_[kSecondaryTableSize];
diff --git a/src/version.cc b/src/version.cc
index f53b7b2..0f3c6c2 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 9
-#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.)
diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc
index 4a94f23..d9361fd 100644
--- a/src/x64/builtins-x64.cc
+++ b/src/x64/builtins-x64.cc
@@ -972,7 +972,7 @@
const int initial_capacity = JSArray::kPreallocatedArrayElements;
STATIC_ASSERT(initial_capacity >= 0);
- __ LoadGlobalInitialConstructedArrayMap(array_function, scratch2, scratch1);
+ __ LoadInitialArrayMap(array_function, scratch2, scratch1);
// Allocate the JSArray object together with space for a fixed array with the
// requested elements.
@@ -1071,9 +1071,7 @@
Register scratch,
bool fill_with_hole,
Label* gc_required) {
- __ LoadGlobalInitialConstructedArrayMap(array_function,
- scratch,
- elements_array);
+ __ LoadInitialArrayMap(array_function, scratch, elements_array);
if (FLAG_debug_code) { // Assert that array size is not zero.
__ testq(array_size, array_size);
diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc
index 1fdffa2..0632ce4 100644
--- a/src/x64/ic-x64.cc
+++ b/src/x64/ic-x64.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// 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:
@@ -635,6 +635,8 @@
Label slow, slow_with_tagged_index, fast, array, extra, check_extra_double;
Label fast_object_with_map_check, fast_object_without_map_check;
Label fast_double_with_map_check, fast_double_without_map_check;
+ Label transition_smi_elements, finish_object_store, non_double_value;
+ Label transition_double_elements;
// Check that the object isn't a smi.
__ JumpIfSmi(rdx, &slow_with_tagged_index);
@@ -737,7 +739,8 @@
__ bind(&non_smi_value);
// Writing a non-smi, check whether array allows non-smi elements.
// r9: receiver's map
- __ CheckFastObjectElements(r9, &slow, Label::kNear);
+ __ CheckFastObjectElements(r9, &transition_smi_elements);
+ __ bind(&finish_object_store);
__ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize),
rax);
__ movq(rdx, rax); // Preserve the value which is returned.
@@ -754,8 +757,53 @@
__ bind(&fast_double_without_map_check);
// If the value is a number, store it as a double in the FastDoubleElements
// array.
- __ StoreNumberToDoubleElements(rax, rbx, rcx, xmm0, &slow);
+ __ StoreNumberToDoubleElements(rax, rbx, rcx, xmm0,
+ &transition_double_elements);
__ ret(0);
+
+ __ bind(&transition_smi_elements);
+ __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
+
+ // Transition the array appropriately depending on the value type.
+ __ movq(r9, FieldOperand(rax, HeapObject::kMapOffset));
+ __ CompareRoot(r9, Heap::kHeapNumberMapRootIndex);
+ __ j(not_equal, &non_double_value);
+
+ // Value is a double. Transition FAST_SMI_ONLY_ELEMENTS ->
+ // FAST_DOUBLE_ELEMENTS and complete the store.
+ __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+ FAST_DOUBLE_ELEMENTS,
+ rbx,
+ rdi,
+ &slow);
+ ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &slow);
+ __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
+ __ jmp(&fast_double_without_map_check);
+
+ __ bind(&non_double_value);
+ // Value is not a double, FAST_SMI_ONLY_ELEMENTS -> FAST_ELEMENTS
+ __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+ FAST_ELEMENTS,
+ rbx,
+ rdi,
+ &slow);
+ ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm);
+ __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
+ __ jmp(&finish_object_store);
+
+ __ bind(&transition_double_elements);
+ // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
+ // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
+ // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
+ __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
+ __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
+ FAST_ELEMENTS,
+ rbx,
+ rdi,
+ &slow);
+ ElementsTransitionGenerator::GenerateDoubleToObject(masm, &slow);
+ __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
+ __ jmp(&finish_object_store);
}
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index 684ec15..670bd05 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -4034,27 +4034,41 @@
}
-void MacroAssembler::LoadGlobalInitialConstructedArrayMap(
+void MacroAssembler::LoadTransitionedArrayMapConditional(
+ ElementsKind expected_kind,
+ ElementsKind transitioned_kind,
+ Register map_in_out,
+ Register scratch,
+ Label* no_map_match) {
+ // Load the global or builtins object from the current context.
+ movq(scratch, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
+ movq(scratch, FieldOperand(scratch, GlobalObject::kGlobalContextOffset));
+
+ // Check that the function's map is the same as the expected cached map.
+ int expected_index =
+ Context::GetContextMapIndexFromElementsKind(expected_kind);
+ cmpq(map_in_out, Operand(scratch, Context::SlotOffset(expected_index)));
+ j(not_equal, no_map_match);
+
+ // Use the transitioned cached map.
+ int trans_index =
+ Context::GetContextMapIndexFromElementsKind(transitioned_kind);
+ movq(map_in_out, Operand(scratch, Context::SlotOffset(trans_index)));
+}
+
+
+void MacroAssembler::LoadInitialArrayMap(
Register function_in, Register scratch, Register map_out) {
ASSERT(!function_in.is(map_out));
Label done;
movq(map_out, FieldOperand(function_in,
JSFunction::kPrototypeOrInitialMapOffset));
if (!FLAG_smi_only_arrays) {
- // Load the global or builtins object from the current context.
- movq(scratch, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
- movq(scratch, FieldOperand(scratch, GlobalObject::kGlobalContextOffset));
-
- // Check that the function's map is same as the cached map.
- cmpq(map_out,
- Operand(scratch,
- Context::SlotOffset(Context::SMI_JS_ARRAY_MAP_INDEX)));
- j(not_equal, &done);
-
- // Use the cached transitioned map.
- movq(map_out,
- Operand(scratch,
- Context::SlotOffset(Context::OBJECT_JS_ARRAY_MAP_INDEX)));
+ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+ FAST_ELEMENTS,
+ map_out,
+ scratch,
+ &done);
}
bind(&done);
}
diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h
index 90b0790..b5ba32d 100644
--- a/src/x64/macro-assembler-x64.h
+++ b/src/x64/macro-assembler-x64.h
@@ -1123,10 +1123,21 @@
// Find the function context up the context chain.
void LoadContext(Register dst, int context_chain_length);
- // Load the initial map for new Arrays of a given type.
- void LoadGlobalInitialConstructedArrayMap(Register function_in,
- Register scratch,
- Register map_out);
+ // Conditionally load the cached Array transitioned map of type
+ // transitioned_kind from the global context if the map in register
+ // map_in_out is the cached Array map in the global context of
+ // expected_kind.
+ void LoadTransitionedArrayMapConditional(
+ ElementsKind expected_kind,
+ ElementsKind transitioned_kind,
+ Register map_in_out,
+ Register scratch,
+ Label* no_map_match);
+
+ // Load the initial map for new Arrays from a JSFunction.
+ void LoadInitialArrayMap(Register function_in,
+ Register scratch,
+ Register map_out);
// Load the global function with the given index.
void LoadGlobalFunction(int index, Register function);
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 59d6d19..e4e8462 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -15558,10 +15558,12 @@
LocalContext context;
// eval and the Function constructor allowed by default.
+ CHECK(context->IsCodeGenerationFromStringsAllowed());
CheckCodeGenerationAllowed();
// Disallow eval and the Function constructor.
context->AllowCodeGenerationFromStrings(false);
+ CHECK(!context->IsCodeGenerationFromStringsAllowed());
CheckCodeGenerationDisallowed();
// Allow again.
@@ -15571,10 +15573,12 @@
// Disallow but setting a global callback that will allow the calls.
context->AllowCodeGenerationFromStrings(false);
V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
+ CHECK(!context->IsCodeGenerationFromStringsAllowed());
CheckCodeGenerationAllowed();
// Set a callback that disallows the code generation.
V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
+ CHECK(!context->IsCodeGenerationFromStringsAllowed());
CheckCodeGenerationDisallowed();
}
diff --git a/test/mjsunit/regress/regress-crbug-107996.js b/test/mjsunit/regress/regress-crbug-107996.js
new file mode 100644
index 0000000..dfe07e5
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-107996.js
@@ -0,0 +1,64 @@
+// 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-debug-as debug
+
+Debug = debug.Debug;
+
+Debug.setListener(listener);
+
+var fourteen;
+var four_in_debugger = [];
+
+function listener(event, exec_state, event_data, data) {
+ if (event == Debug.DebugEvent.Break) {
+ for (var i = 0; i < exec_state.frameCount(); i++) {
+ var frame = exec_state.frame(i);
+ four_in_debugger[i] = frame.evaluate("four", false).value();
+ }
+ }
+}
+
+function f1() {
+ var three = 3;
+ var four = 4;
+ (function f2() {
+ var seven = 7;
+ (function f3() {
+ debugger;
+ fourteen = three + four + seven;
+ })();
+ })();
+}
+
+f1();
+assertEquals(14, fourteen);
+assertEquals(4, four_in_debugger[0]);
+assertEquals(4, four_in_debugger[1]);
+assertEquals(4, four_in_debugger[2]);
+
+Debug.setListener(null);
diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp
index a659782..0eeda18 100644
--- a/tools/gyp/v8.gyp
+++ b/tools/gyp/v8.gyp
@@ -32,6 +32,7 @@
'targets': [
{
'target_name': 'v8',
+ 'dependencies_traverse': 1,
'conditions': [
['want_separate_host_toolset==1', {
'toolsets': ['host', 'target'],
diff --git a/tools/merge-to-branch.sh b/tools/merge-to-branch.sh
index ef7cee4..abe5fc2 100644
--- a/tools/merge-to-branch.sh
+++ b/tools/merge-to-branch.sh
@@ -233,11 +233,26 @@
restore_if_unset "MERGE_TO_BRANCH"
restore_patch_commit_hashes_if_unset "PATCH_COMMIT_HASHES"
echo "${PATCH_COMMIT_HASHES[@]}"
- echo ">>> Step $CURRENT_STEP: Apply the revision patch and create commit message."
+ echo ">>> Step $CURRENT_STEP: Apply patches for selected revisions."
+ rm -f "$TOUCHED_FILES_FILE"
for HASH in ${PATCH_COMMIT_HASHES[@]} ; do
git log -1 -p $HASH | patch -p1 \
- || die "Cannot apply the patch for $HASH to $MERGE_TO_BRANCH"
+ | tee >(awk '{print $NF}' >> "$TOUCHED_FILES_FILE")
+ [[ $? -eq 0 ]] \
+ || die "Cannot apply the patch for $HASH to $MERGE_TO_BRANCH."
done
+ # Stage added and modified files.
+ TOUCHED_FILES=$(cat "$TOUCHED_FILES_FILE")
+ for FILE in $TOUCHED_FILES ; do
+ git add "$FILE"
+ done
+ # Stage deleted files.
+ DELETED_FILES=$(git status -s -uno --porcelain | grep "^ D" \
+ | awk '{print $NF}')
+ for FILE in $DELETED_FILES ; do
+ git rm "$FILE"
+ done
+ rm -f "$TOUCHED_FILES_FILE"
fi
let CURRENT_STEP+=1