summaryrefslogtreecommitdiff
path: root/deps/v8
diff options
context:
space:
mode:
authorMichaƫl Zasso <mic.besace@gmail.com>2015-07-27 08:43:54 +0200
committerRod Vagg <rod@vagg.org>2015-08-04 11:56:17 -0700
commit3d3c687012be3304f7951e47eec103478c7ec366 (patch)
treec53cca04915f5eaa3fb77de5566f9854bf0f74f7 /deps/v8
parent2965442308ea72e76f2b982d0c1ee74304676d5a (diff)
downloadnode-new-3d3c687012be3304f7951e47eec103478c7ec366.tar.gz
deps: update V8 to 4.4.63.26
Includes cherry-picks for: * JitCodeEvent patch: https://crrev.com/f7969b1d5a55e66237221a463daf422ac7611788 * argparse patch: https://crrev.com/44bc918458481d60b08d5566f0f31a79e39b85d7 PR-URL: https://github.com/nodejs/io.js/pull/2220 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com> Reviewed-By: Rod Vagg <rod@vagg.org>
Diffstat (limited to 'deps/v8')
-rw-r--r--deps/v8/include/v8-version.h2
-rw-r--r--deps/v8/src/api.cc4
-rw-r--r--deps/v8/src/arm/assembler-arm-inl.h4
-rw-r--r--deps/v8/src/arm/assembler-arm.cc23
-rw-r--r--deps/v8/src/arm/assembler-arm.h20
-rw-r--r--deps/v8/src/arm64/code-stubs-arm64.cc32
-rw-r--r--deps/v8/src/bootstrapper.cc1
-rw-r--r--deps/v8/src/compiler/arm/code-generator-arm.cc2
-rw-r--r--deps/v8/src/flag-definitions.h2
-rw-r--r--deps/v8/src/hydrogen.cc5
-rw-r--r--deps/v8/src/ic/ic.cc48
-rw-r--r--deps/v8/src/isolate.h1
-rw-r--r--deps/v8/src/mips/assembler-mips-inl.h4
-rw-r--r--deps/v8/src/mips/assembler-mips.cc4
-rw-r--r--deps/v8/src/mips/assembler-mips.h2
-rw-r--r--deps/v8/src/mips/code-stubs-mips.cc4
-rw-r--r--deps/v8/src/mips64/assembler-mips64-inl.h4
-rw-r--r--deps/v8/src/mips64/assembler-mips64.cc4
-rw-r--r--deps/v8/src/mips64/assembler-mips64.h2
-rw-r--r--deps/v8/src/mips64/code-stubs-mips64.cc16
-rw-r--r--deps/v8/src/objects.cc91
-rw-r--r--deps/v8/src/objects.h1
-rw-r--r--deps/v8/src/snapshot/serialize.cc285
-rw-r--r--deps/v8/src/snapshot/serialize.h91
-rw-r--r--deps/v8/src/unicode-decoder.cc2
-rw-r--r--deps/v8/src/x64/lithium-x64.cc16
-rw-r--r--deps/v8/test/cctest/test-api.cc90
-rw-r--r--deps/v8/test/cctest/test-assembler-arm.cc59
-rw-r--r--deps/v8/test/cctest/test-assembler-mips.cc3
-rw-r--r--deps/v8/test/cctest/test-assembler-mips64.cc3
-rw-r--r--deps/v8/test/cctest/test-macro-assembler-mips.cc90
-rw-r--r--deps/v8/test/cctest/test-macro-assembler-mips64.cc89
-rw-r--r--deps/v8/test/cctest/test-serialize.cc95
-rw-r--r--deps/v8/test/mjsunit/es6/regress/regress-cr493566.js80
-rw-r--r--deps/v8/test/mjsunit/mjsunit.status4
-rw-r--r--deps/v8/test/mjsunit/regress/regress-487981.js22
-rw-r--r--deps/v8/test/mjsunit/regress/regress-crbug-478612.js52
-rw-r--r--deps/v8/test/mjsunit/regress/regress-crbug-500497.js33
-rw-r--r--deps/v8/test/mjsunit/regress/regress-crbug-502930.js27
-rw-r--r--deps/v8/test/mjsunit/regress/regress-crbug-514268.js23
40 files changed, 1102 insertions, 238 deletions
diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h
index 2f2ea55333..c52267e024 100644
--- a/deps/v8/include/v8-version.h
+++ b/deps/v8/include/v8-version.h
@@ -11,7 +11,7 @@
#define V8_MAJOR_VERSION 4
#define V8_MINOR_VERSION 4
#define V8_BUILD_NUMBER 63
-#define V8_PATCH_LEVEL 12
+#define V8_PATCH_LEVEL 26
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc
index 01441351c5..4f06873036 100644
--- a/deps/v8/src/api.cc
+++ b/deps/v8/src/api.cc
@@ -345,12 +345,14 @@ StartupData V8::CreateSnapshotDataBlob(const char* custom_source) {
base::ElapsedTimer timer;
timer.Start();
Isolate::Scope isolate_scope(isolate);
+ internal_isolate->set_creating_default_snapshot(true);
internal_isolate->Init(NULL);
Persistent<Context> context;
i::Snapshot::Metadata metadata;
{
HandleScope handle_scope(isolate);
Handle<Context> new_context = Context::New(isolate);
+ internal_isolate->set_creating_default_snapshot(false);
context.Reset(isolate, new_context);
if (custom_source != NULL) {
metadata.set_embeds_script(true);
@@ -379,7 +381,7 @@ StartupData V8::CreateSnapshotDataBlob(const char* custom_source) {
i::SnapshotByteSink context_sink;
i::PartialSerializer context_ser(internal_isolate, &ser, &context_sink);
context_ser.Serialize(&raw_context);
- ser.SerializeWeakReferences();
+ ser.SerializeWeakReferencesAndDeferred();
result = i::Snapshot::CreateSnapshotBlob(ser, context_ser, metadata);
}
diff --git a/deps/v8/src/arm/assembler-arm-inl.h b/deps/v8/src/arm/assembler-arm-inl.h
index 0b5ced5159..1227156eda 100644
--- a/deps/v8/src/arm/assembler-arm-inl.h
+++ b/deps/v8/src/arm/assembler-arm-inl.h
@@ -432,9 +432,7 @@ void Assembler::CheckBuffer() {
if (buffer_space() <= kGap) {
GrowBuffer();
}
- if (pc_offset() >= next_buffer_check_) {
- CheckConstPool(false, true);
- }
+ MaybeCheckConstPool();
}
diff --git a/deps/v8/src/arm/assembler-arm.cc b/deps/v8/src/arm/assembler-arm.cc
index da1ab68a76..a396d0fe6c 100644
--- a/deps/v8/src/arm/assembler-arm.cc
+++ b/deps/v8/src/arm/assembler-arm.cc
@@ -1298,7 +1298,7 @@ void Assembler::addrmod5(Instr instr, CRegister crd, const MemOperand& x) {
}
-int Assembler::branch_offset(Label* L, bool jump_elimination_allowed) {
+int Assembler::branch_offset(Label* L) {
int target_pos;
if (L->is_bound()) {
target_pos = L->pos();
@@ -1315,7 +1315,8 @@ int Assembler::branch_offset(Label* L, bool jump_elimination_allowed) {
// Block the emission of the constant pool, since the branch instruction must
// be emitted at the pc offset recorded by the label.
- BlockConstPoolFor(1);
+ if (!is_const_pool_blocked()) BlockConstPoolFor(1);
+
return target_pos - (pc_offset() + kPcLoadDelta);
}
@@ -1367,6 +1368,24 @@ void Assembler::bx(Register target, Condition cond) { // v5 and above, plus v4t
}
+void Assembler::b(Label* L, Condition cond) {
+ CheckBuffer();
+ b(branch_offset(L), cond);
+}
+
+
+void Assembler::bl(Label* L, Condition cond) {
+ CheckBuffer();
+ bl(branch_offset(L), cond);
+}
+
+
+void Assembler::blx(Label* L) {
+ CheckBuffer();
+ blx(branch_offset(L));
+}
+
+
// Data-processing instructions.
void Assembler::and_(Register dst, Register src1, const Operand& src2,
diff --git a/deps/v8/src/arm/assembler-arm.h b/deps/v8/src/arm/assembler-arm.h
index 836ff4f3d0..5422b3f20e 100644
--- a/deps/v8/src/arm/assembler-arm.h
+++ b/deps/v8/src/arm/assembler-arm.h
@@ -746,7 +746,7 @@ class Assembler : public AssemblerBase {
// Returns the branch offset to the given label from the current code position
// Links the label to the current position if it is still unbound
// Manages the jump elimination optimization if the second parameter is true.
- int branch_offset(Label* L, bool jump_elimination_allowed);
+ int branch_offset(Label* L);
// Returns true if the given pc address is the start of a constant pool load
// instruction sequence.
@@ -852,13 +852,11 @@ class Assembler : public AssemblerBase {
void bx(Register target, Condition cond = al); // v5 and above, plus v4t
// Convenience branch instructions using labels
- void b(Label* L, Condition cond = al) {
- b(branch_offset(L, cond == al), cond);
- }
- void b(Condition cond, Label* L) { b(branch_offset(L, cond == al), cond); }
- void bl(Label* L, Condition cond = al) { bl(branch_offset(L, false), cond); }
- void bl(Condition cond, Label* L) { bl(branch_offset(L, false), cond); }
- void blx(Label* L) { blx(branch_offset(L, false)); } // v5 and above
+ void b(Label* L, Condition cond = al);
+ void b(Condition cond, Label* L) { b(L, cond); }
+ void bl(Label* L, Condition cond = al);
+ void bl(Condition cond, Label* L) { bl(L, cond); }
+ void blx(Label* L); // v5 and above
// Data-processing instructions
@@ -1536,6 +1534,12 @@ class Assembler : public AssemblerBase {
// Check if is time to emit a constant pool.
void CheckConstPool(bool force_emit, bool require_jump);
+ void MaybeCheckConstPool() {
+ if (pc_offset() >= next_buffer_check_) {
+ CheckConstPool(false, true);
+ }
+ }
+
// Allocate a constant pool of the correct size for the generated code.
Handle<ConstantPoolArray> NewConstantPool(Isolate* isolate);
diff --git a/deps/v8/src/arm64/code-stubs-arm64.cc b/deps/v8/src/arm64/code-stubs-arm64.cc
index 9ce5a05ce5..7f3c995204 100644
--- a/deps/v8/src/arm64/code-stubs-arm64.cc
+++ b/deps/v8/src/arm64/code-stubs-arm64.cc
@@ -2286,27 +2286,16 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
Register last_match_info_elements = x21;
Register code_object = x22;
- // TODO(jbramley): Is it necessary to preserve these? I don't think ARM does.
- CPURegList used_callee_saved_registers(subject,
- regexp_data,
- last_match_info_elements,
- code_object);
- __ PushCPURegList(used_callee_saved_registers);
-
// Stack frame.
- // jssp[0] : x19
- // jssp[8] : x20
- // jssp[16]: x21
- // jssp[24]: x22
- // jssp[32]: last_match_info (JSArray)
- // jssp[40]: previous index
- // jssp[48]: subject string
- // jssp[56]: JSRegExp object
-
- const int kLastMatchInfoOffset = 4 * kPointerSize;
- const int kPreviousIndexOffset = 5 * kPointerSize;
- const int kSubjectOffset = 6 * kPointerSize;
- const int kJSRegExpOffset = 7 * kPointerSize;
+ // jssp[00]: last_match_info (JSArray)
+ // jssp[08]: previous index
+ // jssp[16]: subject string
+ // jssp[24]: JSRegExp object
+
+ const int kLastMatchInfoOffset = 0 * kPointerSize;
+ const int kPreviousIndexOffset = 1 * kPointerSize;
+ const int kSubjectOffset = 2 * kPointerSize;
+ const int kJSRegExpOffset = 3 * kPointerSize;
// Ensure that a RegExp stack is allocated.
ExternalReference address_of_regexp_stack_memory_address =
@@ -2673,7 +2662,6 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// Return last match info.
__ Peek(x0, kLastMatchInfoOffset);
- __ PopCPURegList(used_callee_saved_registers);
// Drop the 4 arguments of the stub from the stack.
__ Drop(4);
__ Ret();
@@ -2696,13 +2684,11 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ Bind(&failure);
__ Mov(x0, Operand(isolate()->factory()->null_value()));
- __ PopCPURegList(used_callee_saved_registers);
// Drop the 4 arguments of the stub from the stack.
__ Drop(4);
__ Ret();
__ Bind(&runtime);
- __ PopCPURegList(used_callee_saved_registers);
__ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
// Deferred code for string handling.
diff --git a/deps/v8/src/bootstrapper.cc b/deps/v8/src/bootstrapper.cc
index f3dd682871..c56c429937 100644
--- a/deps/v8/src/bootstrapper.cc
+++ b/deps/v8/src/bootstrapper.cc
@@ -2813,6 +2813,7 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
if (value->IsPropertyCell()) {
value = handle(PropertyCell::cast(*value)->value(), isolate());
}
+ if (value->IsTheHole()) continue;
PropertyDetails details = properties->DetailsAt(i);
DCHECK_EQ(kData, details.kind());
JSObject::AddProperty(to, key, value, details.attributes());
diff --git a/deps/v8/src/compiler/arm/code-generator-arm.cc b/deps/v8/src/compiler/arm/code-generator-arm.cc
index 306c347f8a..cc93cf4451 100644
--- a/deps/v8/src/compiler/arm/code-generator-arm.cc
+++ b/deps/v8/src/compiler/arm/code-generator-arm.cc
@@ -316,6 +316,8 @@ void CodeGenerator::AssembleDeconstructActivationRecord() {
void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
ArmOperandConverter i(this, instr);
+ masm()->MaybeCheckConstPool();
+
switch (ArchOpcodeField::decode(instr->opcode())) {
case kArchCallCodeObject: {
EnsureSpaceForLazyDeopt();
diff --git a/deps/v8/src/flag-definitions.h b/deps/v8/src/flag-definitions.h
index 93e61df082..2b905e31d4 100644
--- a/deps/v8/src/flag-definitions.h
+++ b/deps/v8/src/flag-definitions.h
@@ -199,7 +199,7 @@ DEFINE_IMPLICATION(es_staging, harmony)
#define HARMONY_STAGED(V) \
V(harmony_rest_parameters, "harmony rest parameters") \
V(harmony_spreadcalls, "harmony spread-calls") \
- V(harmony_tostring, "harmony toString") \
+ V(harmony_tostring, "harmony toString")
// Features that are shipping (turned on by default, but internal flag remains).
#define HARMONY_SHIPPING(V) \
diff --git a/deps/v8/src/hydrogen.cc b/deps/v8/src/hydrogen.cc
index a1b0648207..6a86c736ee 100644
--- a/deps/v8/src/hydrogen.cc
+++ b/deps/v8/src/hydrogen.cc
@@ -5219,9 +5219,12 @@ void HOptimizedGraphBuilder::BuildForInBody(ForInStatement* stmt,
HValue* function = AddLoadJSBuiltin(Builtins::FILTER_KEY);
Add<HPushArguments>(enumerable, key);
key = Add<HInvokeFunction>(function, 2);
+ Push(key);
+ Add<HSimulate>(stmt->FilterId());
+ key = Pop();
Bind(each_var, key);
- Add<HSimulate>(stmt->AssignmentId());
Add<HCheckHeapObject>(key);
+ Add<HSimulate>(stmt->AssignmentId());
}
BreakAndContinueInfo break_info(stmt, scope(), 5);
diff --git a/deps/v8/src/ic/ic.cc b/deps/v8/src/ic/ic.cc
index daf7704c71..65b2e3df9a 100644
--- a/deps/v8/src/ic/ic.cc
+++ b/deps/v8/src/ic/ic.cc
@@ -1112,7 +1112,39 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) {
code = slow_stub();
}
} else {
- code = ComputeHandler(lookup);
+ if (lookup->state() == LookupIterator::ACCESSOR) {
+ Handle<Object> accessors = lookup->GetAccessors();
+ Handle<Map> map = receiver_map();
+ if (accessors->IsExecutableAccessorInfo()) {
+ Handle<ExecutableAccessorInfo> info =
+ Handle<ExecutableAccessorInfo>::cast(accessors);
+ if ((v8::ToCData<Address>(info->getter()) != 0) &&
+ !ExecutableAccessorInfo::IsCompatibleReceiverMap(isolate(), info,
+ map)) {
+ TRACE_GENERIC_IC(isolate(), "LoadIC", "incompatible receiver type");
+ code = slow_stub();
+ }
+ } else if (accessors->IsAccessorPair()) {
+ Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
+ isolate());
+ Handle<JSObject> holder = lookup->GetHolder<JSObject>();
+ Handle<Object> receiver = lookup->GetReceiver();
+ if (getter->IsJSFunction() && holder->HasFastProperties()) {
+ Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
+ if (receiver->IsJSObject() || function->IsBuiltin() ||
+ !is_sloppy(function->shared()->language_mode())) {
+ CallOptimization call_optimization(function);
+ if (call_optimization.is_simple_api_call() &&
+ !call_optimization.IsCompatibleReceiver(receiver, holder)) {
+ TRACE_GENERIC_IC(isolate(), "LoadIC",
+ "incompatible receiver type");
+ code = slow_stub();
+ }
+ }
+ }
+ }
+ }
+ if (code.is_null()) code = ComputeHandler(lookup);
}
PatchCache(lookup->name(), code);
@@ -1242,6 +1274,8 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
if (v8::ToCData<Address>(info->getter()) == 0) break;
if (!ExecutableAccessorInfo::IsCompatibleReceiverMap(isolate(), info,
map)) {
+ // This case should be already handled in LoadIC::UpdateCaches.
+ UNREACHABLE();
break;
}
if (!holder->HasFastProperties()) break;
@@ -1262,10 +1296,14 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
}
CallOptimization call_optimization(function);
NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
- if (call_optimization.is_simple_api_call() &&
- call_optimization.IsCompatibleReceiver(receiver, holder)) {
- return compiler.CompileLoadCallback(lookup->name(), call_optimization,
- lookup->GetAccessorIndex());
+ if (call_optimization.is_simple_api_call()) {
+ if (call_optimization.IsCompatibleReceiver(receiver, holder)) {
+ return compiler.CompileLoadCallback(
+ lookup->name(), call_optimization, lookup->GetAccessorIndex());
+ } else {
+ // This case should be already handled in LoadIC::UpdateCaches.
+ UNREACHABLE();
+ }
}
int expected_arguments =
function->shared()->internal_formal_parameter_count();
diff --git a/deps/v8/src/isolate.h b/deps/v8/src/isolate.h
index 749eb4fd57..84190801f0 100644
--- a/deps/v8/src/isolate.h
+++ b/deps/v8/src/isolate.h
@@ -389,6 +389,7 @@ typedef List<HeapObject*> DebugObjectCache;
V(uint32_t, per_isolate_assert_data, 0xFFFFFFFFu) \
V(PromiseRejectCallback, promise_reject_callback, NULL) \
V(const v8::StartupData*, snapshot_blob, NULL) \
+ V(bool, creating_default_snapshot, false) \
ISOLATE_INIT_SIMULATOR_LIST(V)
#define THREAD_LOCAL_TOP_ACCESSOR(type, name) \
diff --git a/deps/v8/src/mips/assembler-mips-inl.h b/deps/v8/src/mips/assembler-mips-inl.h
index afca7d00a6..bb422a3fcd 100644
--- a/deps/v8/src/mips/assembler-mips-inl.h
+++ b/deps/v8/src/mips/assembler-mips-inl.h
@@ -500,8 +500,8 @@ void Assembler::CheckBuffer() {
}
-void Assembler::CheckTrampolinePoolQuick() {
- if (pc_offset() >= next_buffer_check_) {
+void Assembler::CheckTrampolinePoolQuick(int extra_instructions) {
+ if (pc_offset() >= next_buffer_check_ - extra_instructions * kInstrSize) {
CheckTrampolinePool();
}
}
diff --git a/deps/v8/src/mips/assembler-mips.cc b/deps/v8/src/mips/assembler-mips.cc
index e05fc015a8..1d38f3a3dc 100644
--- a/deps/v8/src/mips/assembler-mips.cc
+++ b/deps/v8/src/mips/assembler-mips.cc
@@ -795,7 +795,7 @@ void Assembler::bind_to(Label* L, int pos) {
trampoline_pos = get_trampoline_entry(fixup_pos);
CHECK(trampoline_pos != kInvalidSlotPos);
}
- DCHECK((trampoline_pos - fixup_pos) <= kMaxBranchOffset);
+ CHECK((trampoline_pos - fixup_pos) <= kMaxBranchOffset);
target_at_put(fixup_pos, trampoline_pos, false);
fixup_pos = trampoline_pos;
dist = pos - fixup_pos;
@@ -1415,6 +1415,7 @@ void Assembler::jal(int32_t target) {
void Assembler::jalr(Register rs, Register rd) {
+ DCHECK(rs.code() != rd.code());
BlockTrampolinePoolScope block_trampoline_pool(this);
positions_recorder()->WriteRecordedPositions();
GenInstrRegister(SPECIAL, rs, zero_reg, rd, 0, JALR);
@@ -2633,6 +2634,7 @@ void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
void Assembler::BlockTrampolinePoolFor(int instructions) {
+ CheckTrampolinePoolQuick(instructions);
BlockTrampolinePoolBefore(pc_offset() + instructions * kInstrSize);
}
diff --git a/deps/v8/src/mips/assembler-mips.h b/deps/v8/src/mips/assembler-mips.h
index 6cdfcfdabd..69201dc32c 100644
--- a/deps/v8/src/mips/assembler-mips.h
+++ b/deps/v8/src/mips/assembler-mips.h
@@ -1253,7 +1253,7 @@ class Assembler : public AssemblerBase {
inline void CheckBuffer();
void GrowBuffer();
inline void emit(Instr x);
- inline void CheckTrampolinePoolQuick();
+ inline void CheckTrampolinePoolQuick(int extra_instructions = 0);
// Instruction generation.
// We have 3 different kind of encoding layout on MIPS.
diff --git a/deps/v8/src/mips/code-stubs-mips.cc b/deps/v8/src/mips/code-stubs-mips.cc
index 5b5e050f51..e1cf6d6641 100644
--- a/deps/v8/src/mips/code-stubs-mips.cc
+++ b/deps/v8/src/mips/code-stubs-mips.cc
@@ -4028,8 +4028,8 @@ void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
intptr_t loc =
reinterpret_cast<intptr_t>(GetCode().location());
__ Move(t9, target);
- __ li(ra, Operand(loc, RelocInfo::CODE_TARGET), CONSTANT_SIZE);
- __ Call(ra);
+ __ li(at, Operand(loc, RelocInfo::CODE_TARGET), CONSTANT_SIZE);
+ __ Call(at);
}
diff --git a/deps/v8/src/mips64/assembler-mips64-inl.h b/deps/v8/src/mips64/assembler-mips64-inl.h
index 76117d08e3..7f18335b59 100644
--- a/deps/v8/src/mips64/assembler-mips64-inl.h
+++ b/deps/v8/src/mips64/assembler-mips64-inl.h
@@ -504,8 +504,8 @@ void Assembler::CheckBuffer() {
}
-void Assembler::CheckTrampolinePoolQuick() {
- if (pc_offset() >= next_buffer_check_) {
+void Assembler::CheckTrampolinePoolQuick(int extra_instructions) {
+ if (pc_offset() >= next_buffer_check_ - extra_instructions * kInstrSize) {
CheckTrampolinePool();
}
}
diff --git a/deps/v8/src/mips64/assembler-mips64.cc b/deps/v8/src/mips64/assembler-mips64.cc
index 7a30915303..685100f59a 100644
--- a/deps/v8/src/mips64/assembler-mips64.cc
+++ b/deps/v8/src/mips64/assembler-mips64.cc
@@ -780,7 +780,7 @@ void Assembler::bind_to(Label* L, int pos) {
trampoline_pos = get_trampoline_entry(fixup_pos);
CHECK(trampoline_pos != kInvalidSlotPos);
}
- DCHECK((trampoline_pos - fixup_pos) <= kMaxBranchOffset);
+ CHECK((trampoline_pos - fixup_pos) <= kMaxBranchOffset);
target_at_put(fixup_pos, trampoline_pos, false);
fixup_pos = trampoline_pos;
dist = pos - fixup_pos;
@@ -1396,6 +1396,7 @@ void Assembler::jal(int64_t target) {
void Assembler::jalr(Register rs, Register rd) {
+ DCHECK(rs.code() != rd.code());
BlockTrampolinePoolScope block_trampoline_pool(this);
positions_recorder()->WriteRecordedPositions();
GenInstrRegister(SPECIAL, rs, zero_reg, rd, 0, JALR);
@@ -2809,6 +2810,7 @@ void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
void Assembler::BlockTrampolinePoolFor(int instructions) {
+ CheckTrampolinePoolQuick(instructions);
BlockTrampolinePoolBefore(pc_offset() + instructions * kInstrSize);
}
diff --git a/deps/v8/src/mips64/assembler-mips64.h b/deps/v8/src/mips64/assembler-mips64.h
index bb7fac4607..7f026bf57c 100644
--- a/deps/v8/src/mips64/assembler-mips64.h
+++ b/deps/v8/src/mips64/assembler-mips64.h
@@ -1288,7 +1288,7 @@ class Assembler : public AssemblerBase {
void GrowBuffer();
inline void emit(Instr x);
inline void emit(uint64_t x);
- inline void CheckTrampolinePoolQuick();
+ inline void CheckTrampolinePoolQuick(int extra_instructions = 0);
// Instruction generation.
// We have 3 different kind of encoding layout on MIPS.
diff --git a/deps/v8/src/mips64/code-stubs-mips64.cc b/deps/v8/src/mips64/code-stubs-mips64.cc
index fb9c4ee068..e53064f05a 100644
--- a/deps/v8/src/mips64/code-stubs-mips64.cc
+++ b/deps/v8/src/mips64/code-stubs-mips64.cc
@@ -4071,8 +4071,8 @@ void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
intptr_t loc =
reinterpret_cast<intptr_t>(GetCode().location());
__ Move(t9, target);
- __ li(ra, Operand(loc, RelocInfo::CODE_TARGET), CONSTANT_SIZE);
- __ Call(ra);
+ __ li(at, Operand(loc, RelocInfo::CODE_TARGET), CONSTANT_SIZE);
+ __ Call(at);
}
@@ -5285,9 +5285,9 @@ static void CallApiFunctionAndReturn(
__ li(s3, Operand(next_address));
__ ld(s0, MemOperand(s3, kNextOffset));
__ ld(s1, MemOperand(s3, kLimitOffset));
- __ ld(s2, MemOperand(s3, kLevelOffset));
- __ Daddu(s2, s2, Operand(1));
- __ sd(s2, MemOperand(s3, kLevelOffset));
+ __ lw(s2, MemOperand(s3, kLevelOffset));
+ __ Addu(s2, s2, Operand(1));
+ __ sw(s2, MemOperand(s3, kLevelOffset));
if (FLAG_log_timer_events) {
FrameScope frame(masm, StackFrame::MANUAL);
@@ -5328,11 +5328,11 @@ static void CallApiFunctionAndReturn(
// previous handle scope.
__ sd(s0, MemOperand(s3, kNextOffset));
if (__ emit_debug_code()) {
- __ ld(a1, MemOperand(s3, kLevelOffset));
+ __ lw(a1, MemOperand(s3, kLevelOffset));
__ Check(eq, kUnexpectedLevelAfterReturnFromApiCall, a1, Operand(s2));
}
- __ Dsubu(s2, s2, Operand(1));
- __ sd(s2, MemOperand(s3, kLevelOffset));
+ __ Subu(s2, s2, Operand(1));
+ __ sw(s2, MemOperand(s3, kLevelOffset));
__ ld(at, MemOperand(s3, kLimitOffset));
__ Branch(&delete_allocated_handles, ne, s1, Operand(at));
diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc
index 67a7b2bc7a..82a27f4d21 100644
--- a/deps/v8/src/objects.cc
+++ b/deps/v8/src/objects.cc
@@ -3275,54 +3275,58 @@ MaybeHandle<Object> Object::SetSuperProperty(LookupIterator* it,
if (found) return result;
LookupIterator own_lookup(it->GetReceiver(), it->name(), LookupIterator::OWN);
+ for (; own_lookup.IsFound(); own_lookup.Next()) {
+ switch (own_lookup.state()) {
+ case LookupIterator::ACCESS_CHECK:
+ if (!own_lookup.HasAccess()) {
+ return JSObject::SetPropertyWithFailedAccessCheck(&own_lookup, value,
+ SLOPPY);
+ }
+ break;
- switch (own_lookup.state()) {
- case LookupIterator::NOT_FOUND:
- return JSObject::AddDataProperty(&own_lookup, value, NONE, language_mode,
- store_mode);
-
- case LookupIterator::INTEGER_INDEXED_EXOTIC:
- return result;
+ case LookupIterator::INTEGER_INDEXED_EXOTIC:
+ return RedefineNonconfigurableProperty(it->isolate(), it->name(), value,
+ language_mode);
- case LookupIterator::DATA: {
- PropertyDetails details = own_lookup.property_details();
- if (details.IsConfigurable() || !details.IsReadOnly()) {
- return JSObject::SetOwnPropertyIgnoreAttributes(
- Handle<JSObject>::cast(it->GetReceiver()), it->name(), value,
- details.attributes());
+ case LookupIterator::DATA: {
+ PropertyDetails details = own_lookup.property_details();
+ if (details.IsConfigurable() || !details.IsReadOnly()) {
+ return JSObject::SetOwnPropertyIgnoreAttributes(
+ Handle<JSObject>::cast(it->GetReceiver()), it->name(), value,
+ details.attributes());
+ }
+ return WriteToReadOnlyProperty(&own_lookup, value, language_mode);
}
- return WriteToReadOnlyProperty(&own_lookup, value, language_mode);
- }
- case LookupIterator::ACCESSOR: {
- PropertyDetails details = own_lookup.property_details();
- if (details.IsConfigurable()) {
- return JSObject::SetOwnPropertyIgnoreAttributes(
- Handle<JSObject>::cast(it->GetReceiver()), it->name(), value,
- details.attributes());
- }
+ case LookupIterator::ACCESSOR: {
+ PropertyDetails details = own_lookup.property_details();
+ if (details.IsConfigurable()) {
+ return JSObject::SetOwnPropertyIgnoreAttributes(
+ Handle<JSObject>::cast(it->GetReceiver()), it->name(), value,
+ details.attributes());
+ }
- return RedefineNonconfigurableProperty(it->isolate(), it->name(), value,
- language_mode);
- }
+ return RedefineNonconfigurableProperty(it->isolate(), it->name(), value,
+ language_mode);
+ }
- case LookupIterator::TRANSITION:
- UNREACHABLE();
- break;
+ case LookupIterator::INTERCEPTOR:
+ case LookupIterator::JSPROXY: {
+ bool found = false;
+ MaybeHandle<Object> result = SetPropertyInternal(
+ &own_lookup, value, language_mode, store_mode, &found);
+ if (found) return result;
+ break;
+ }
- case LookupIterator::INTERCEPTOR:
- case LookupIterator::JSPROXY:
- case LookupIterator::ACCESS_CHECK: {
- bool found = false;
- MaybeHandle<Object> result = SetPropertyInternal(
- &own_lookup, value, language_mode, store_mode, &found);
- if (found) return result;
- return SetDataProperty(&own_lookup, value);
+ case LookupIterator::NOT_FOUND:
+ case LookupIterator::TRANSITION:
+ UNREACHABLE();
}
}
- UNREACHABLE();
- return MaybeHandle<Object>();
+ return JSObject::AddDataProperty(&own_lookup, value, NONE, language_mode,
+ store_mode);
}
@@ -14697,9 +14701,10 @@ Handle<Derived> HashTable<Derived, Shape, Key>::New(
PretenureFlag pretenure) {
DCHECK(0 <= at_least_space_for);
DCHECK(!capacity_option || base::bits::IsPowerOfTwo32(at_least_space_for));
+
int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY)
? at_least_space_for
- : isolate->serializer_enabled()
+ : isolate->creating_default_snapshot()
? ComputeCapacityForSerialization(at_least_space_for)
: ComputeCapacity(at_least_space_for);
if (capacity > HashTable::kMaxCapacity) {
@@ -15692,6 +15697,14 @@ Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) {
}
+String* StringTable::LookupKeyIfExists(Isolate* isolate, HashTableKey* key) {
+ Handle<StringTable> table = isolate->factory()->string_table();
+ int entry = table->FindEntry(key);
+ if (entry != kNotFound) return String::cast(table->KeyAt(entry));
+ return NULL;
+}
+
+
Handle<Object> CompilationCacheTable::Lookup(Handle<String> src,
Handle<Context> context,
LanguageMode language_mode) {
diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h
index 4823243f23..5ec1d7d27b 100644
--- a/deps/v8/src/objects.h
+++ b/deps/v8/src/objects.h
@@ -3553,6 +3553,7 @@ class StringTable: public HashTable<StringTable,
// added. The return value is the string found.
static Handle<String> LookupString(Isolate* isolate, Handle<String> key);
static Handle<String> LookupKey(Isolate* isolate, HashTableKey* key);
+ static String* LookupKeyIfExists(Isolate* isolate, HashTableKey* key);
// Tries to internalize given string and returns string handle on success
// or an empty handle otherwise.
diff --git a/deps/v8/src/snapshot/serialize.cc b/deps/v8/src/snapshot/serialize.cc
index dbe92a6acc..7f123a3fbe 100644
--- a/deps/v8/src/snapshot/serialize.cc
+++ b/deps/v8/src/snapshot/serialize.cc
@@ -516,10 +516,18 @@ void Deserializer::DecodeReservation(
void Deserializer::FlushICacheForNewCodeObjects() {
- PageIterator it(isolate_->heap()->code_space());
- while (it.has_next()) {
- Page* p = it.next();
- CpuFeatures::FlushICache(p->area_start(), p->area_end() - p->area_start());
+ if (!deserializing_user_code_) {
+ // The entire isolate is newly deserialized. Simply flush all code pages.
+ PageIterator it(isolate_->heap()->code_space());
+ while (it.has_next()) {
+ Page* p = it.next();
+ CpuFeatures::FlushICache(p->area_start(),
+ p->area_end() - p->area_start());
+ }
+ }
+ for (Code* code : new_code_objects_) {
+ CpuFeatures::FlushICache(code->instruction_start(),
+ code->instruction_size());
}
}
@@ -556,10 +564,15 @@ void Deserializer::Deserialize(Isolate* isolate) {
DCHECK_NULL(isolate_->thread_manager()->FirstThreadStateInUse());
// No active handles.
DCHECK(isolate_->handle_scope_implementer()->blocks()->is_empty());
- isolate_->heap()->IterateSmiRoots(this);
- isolate_->heap()->IterateStrongRoots(this, VISIT_ONLY_STRONG);
- isolate_->heap()->RepairFreeListsAfterDeserialization();
- isolate_->heap()->IterateWeakRoots(this, VISIT_ALL);
+
+ {
+ DisallowHeapAllocation no_gc;
+ isolate_->heap()->IterateSmiRoots(this);
+ isolate_->heap()->IterateStrongRoots(this, VISIT_ONLY_STRONG);
+ isolate_->heap()->RepairFreeListsAfterDeserialization();
+ isolate_->heap()->IterateWeakRoots(this, VISIT_ALL);
+ DeserializeDeferredObjects();
+ }
isolate_->heap()->set_native_contexts_list(
isolate_->heap()->undefined_value());
@@ -608,11 +621,12 @@ MaybeHandle<Object> Deserializer::DeserializePartial(
Object* root;
Object* outdated_contexts;
VisitPointer(&root);
+ DeserializeDeferredObjects();
VisitPointer(&outdated_contexts);
- // There's no code deserialized here. If this assert fires
- // then that's changed and logging should be added to notify
- // the profiler et al of the new code.
+ // There's no code deserialized here. If this assert fires then that's
+ // changed and logging should be added to notify the profiler et al of the
+ // new code, which also has to be flushed from instruction cache.
CHECK_EQ(start_address, code_space->top());
CHECK(outdated_contexts->IsFixedArray());
*outdated_contexts_out =
@@ -628,10 +642,17 @@ MaybeHandle<SharedFunctionInfo> Deserializer::DeserializeCode(
return Handle<SharedFunctionInfo>();
} else {
deserializing_user_code_ = true;
- DisallowHeapAllocation no_gc;
- Object* root;
- VisitPointer(&root);
- return Handle<SharedFunctionInfo>(SharedFunctionInfo::cast(root));
+ HandleScope scope(isolate);
+ Handle<SharedFunctionInfo> result;
+ {
+ DisallowHeapAllocation no_gc;
+ Object* root;
+ VisitPointer(&root);
+ DeserializeDeferredObjects();
+ result = Handle<SharedFunctionInfo>(SharedFunctionInfo::cast(root));
+ }
+ CommitNewInternalizedStrings(isolate);
+ return scope.CloseAndEscape(result);
}
}
@@ -652,13 +673,21 @@ void Deserializer::VisitPointers(Object** start, Object** end) {
}
-void Deserializer::RelinkAllocationSite(AllocationSite* site) {
- if (isolate_->heap()->allocation_sites_list() == Smi::FromInt(0)) {
- site->set_weak_next(isolate_->heap()->undefined_value());
- } else {
- site->set_weak_next(isolate_->heap()->allocation_sites_list());
+void Deserializer::DeserializeDeferredObjects() {
+ for (int code = source_.Get(); code != kSynchronize; code = source_.Get()) {
+ int space = code & kSpaceMask;
+ DCHECK(space <= kNumberOfSpaces);
+ DCHECK(code - space == kNewObject);
+ HeapObject* object = GetBackReferencedObject(space);
+ int size = source_.GetInt() << kPointerSizeLog2;
+ Address obj_address = object->address();
+ Object** start = reinterpret_cast<Object**>(obj_address + kPointerSize);
+ Object** end = reinterpret_cast<Object**>(obj_address + size);
+ bool filled = ReadData(start, end, space, obj_address);
+ CHECK(filled);
+ DCHECK(CanBeDeferred(object));
+ PostProcessNewObject(object, space);
}
- isolate_->heap()->set_allocation_sites_list(site);
}
@@ -688,31 +717,76 @@ class StringTableInsertionKey : public HashTableKey {
return handle(string_, isolate);
}
+ private:
String* string_;
uint32_t hash_;
+ DisallowHeapAllocation no_gc;
};
-HeapObject* Deserializer::ProcessNewObjectFromSerializedCode(HeapObject* obj) {
- if (obj->IsString()) {
- String* string = String::cast(obj);
- // Uninitialize hash field as the hash seed may have changed.
- string->set_hash_field(String::kEmptyHashField);
- if (string->IsInternalizedString()) {
- DisallowHeapAllocation no_gc;
- HandleScope scope(isolate_);
- StringTableInsertionKey key(string);
- String* canonical = *StringTable::LookupKey(isolate_, &key);
- string->SetForwardedInternalizedString(canonical);
- return canonical;
+HeapObject* Deserializer::PostProcessNewObject(HeapObject* obj, int space) {
+ if (deserializing_user_code()) {
+ if (obj->IsString()) {
+ String* string = String::cast(obj);
+ // Uninitialize hash field as the hash seed may have changed.
+ string->set_hash_field(String::kEmptyHashField);
+ if (string->IsInternalizedString()) {
+ // Canonicalize the internalized string. If it already exists in the
+ // string table, set it to forward to the existing one.
+ StringTableInsertionKey key(string);
+ String* canonical = StringTable::LookupKeyIfExists(isolate_, &key);
+ if (canonical == NULL) {
+ new_internalized_strings_.Add(handle(string));
+ return string;
+ } else {
+ string->SetForwardedInternalizedString(canonical);
+ return canonical;
+ }
+ }
+ } else if (obj->IsScript()) {
+ // Assign a new script id to avoid collision.
+ Script::cast(obj)->set_id(isolate_->heap()->NextScriptId());
+ } else {
+ DCHECK(CanBeDeferred(obj));
+ }
+ }
+ if (obj->IsAllocationSite()) {
+ DCHECK(obj->IsAllocationSite());
+ // Allocation sites are present in the snapshot, and must be linked into
+ // a list at deserialization time.
+ AllocationSite* site = AllocationSite::cast(obj);
+ // TODO(mvstanton): consider treating the heap()->allocation_sites_list()
+ // as a (weak) root. If this root is relocated correctly, this becomes
+ // unnecessary.
+ if (isolate_->heap()->allocation_sites_list() == Smi::FromInt(0)) {
+ site->set_weak_next(isolate_->heap()->undefined_value());
+ } else {
+ site->set_weak_next(isolate_->heap()->allocation_sites_list());
+ }
+ isolate_->heap()->set_allocation_sites_list(site);
+ } else if (obj->IsCode()) {
+ // We flush all code pages after deserializing the startup snapshot. In that
+ // case, we only need to remember code objects in the large object space.
+ // When deserializing user code, remember each individual code object.
+ if (deserializing_user_code() || space == LO_SPACE) {
+ new_code_objects_.Add(Code::cast(obj));
}
- } else if (obj->IsScript()) {
- Script::cast(obj)->set_id(isolate_->heap()->NextScriptId());
}
return obj;
}
+void Deserializer::CommitNewInternalizedStrings(Isolate* isolate) {
+ StringTable::EnsureCapacityForDeserialization(
+ isolate, new_internalized_strings_.length());
+ for (Handle<String> string : new_internalized_strings_) {
+ StringTableInsertionKey key(*string);
+ DCHECK_NULL(StringTable::LookupKeyIfExists(isolate, &key));
+ StringTable::LookupKey(isolate, &key);
+ }
+}
+
+
HeapObject* Deserializer::GetBackReferencedObject(int space) {
HeapObject* obj;
BackReference back_reference(source_.GetInt());
@@ -746,21 +820,10 @@ void Deserializer::ReadObject(int space_number, Object** write_back) {
HeapObject* obj;
int next_int = source_.GetInt();
- bool double_align = false;
-#ifndef V8_HOST_ARCH_64_BIT
- double_align = next_int == kDoubleAlignmentSentinel;
- if (double_align) next_int = source_.GetInt();
-#endif
-
DCHECK_NE(kDoubleAlignmentSentinel, next_int);
int size = next_int << kObjectAlignmentBits;
- int reserved_size = size + (double_align ? kPointerSize : 0);
- address = Allocate(space_number, reserved_size);
+ address = Allocate(space_number, size);
obj = HeapObject::FromAddress(address);
- if (double_align) {
- obj = isolate_->heap()->DoubleAlignForDeserialization(obj, reserved_size);
- address = obj->address();
- }
isolate_->heap()->OnAllocationEvent(obj, size);
Object** current = reinterpret_cast<Object**>(address);
@@ -768,24 +831,17 @@ void Deserializer::ReadObject(int space_number, Object** write_back) {
if (FLAG_log_snapshot_positions) {
LOG(isolate_, SnapshotPositionEvent(address, source_.position()));
}
- ReadData(current, limit, space_number, address);
-
- // TODO(mvstanton): consider treating the heap()->allocation_sites_list()
- // as a (weak) root. If this root is relocated correctly,
- // RelinkAllocationSite() isn't necessary.
- if (obj->IsAllocationSite()) RelinkAllocationSite(AllocationSite::cast(obj));
- // Fix up strings from serialized user code.
- if (deserializing_user_code()) obj = ProcessNewObjectFromSerializedCode(obj);
+ if (ReadData(current, limit, space_number, address)) {
+ // Only post process if object content has not been deferred.
+ obj = PostProcessNewObject(obj, space_number);
+ }
Object* write_back_obj = obj;
UnalignedCopy(write_back, &write_back_obj);
#ifdef DEBUG
if (obj->IsCode()) {
DCHECK(space_number == CODE_SPACE || space_number == LO_SPACE);
-#ifdef VERIFY_HEAP
- obj->ObjectVerify();
-#endif // VERIFY_HEAP
} else {
DCHECK(space_number != CODE_SPACE);
}
@@ -829,7 +885,7 @@ Address Deserializer::Allocate(int space_index, int size) {
}
-void Deserializer::ReadData(Object** current, Object** limit, int source_space,
+bool Deserializer::ReadData(Object** current, Object** limit, int source_space,
Address current_object_address) {
Isolate* const isolate = isolate_;
// Write barrier support costs around 1% in startup time. In fact there
@@ -1086,6 +1142,18 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space,
break;
}
+ case kDeferred: {
+ // Deferred can only occur right after the heap object header.
+ DCHECK(current == reinterpret_cast<Object**>(current_object_address +
+ kPointerSize));
+ HeapObject* obj = HeapObject::FromAddress(current_object_address);
+ // If the deferred object is a map, its instance type may be used
+ // during deserialization. Initialize it with a temporary value.
+ if (obj->IsMap()) Map::cast(obj)->set_instance_type(FILLER_TYPE);
+ current = limit;
+ return false;
+ }
+
case kSynchronize:
// If we get here then that indicates that you have a mismatch between
// the number of GC roots when serializing and deserializing.
@@ -1192,6 +1260,7 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space,
}
}
CHECK_EQ(limit, current);
+ return true;
}
@@ -1200,6 +1269,7 @@ Serializer::Serializer(Isolate* isolate, SnapshotByteSink* sink)
sink_(sink),
external_reference_encoder_(isolate),
root_index_map_(isolate),
+ recursion_depth_(0),
code_address_map_(NULL),
large_objects_total_size_(0),
seen_large_objects_index_(0) {
@@ -1275,6 +1345,16 @@ void Serializer::OutputStatistics(const char* name) {
}
+void Serializer::SerializeDeferredObjects() {
+ while (deferred_objects_.length() > 0) {
+ HeapObject* obj = deferred_objects_.RemoveLast();
+ ObjectSerializer obj_serializer(this, obj, sink_, kPlain, kStartOfObject);
+ obj_serializer.SerializeDeferred();
+ }
+ sink_->Put(kSynchronize, "Finished with deferred objects");
+}
+
+
void StartupSerializer::SerializeStrongReferences() {
Isolate* isolate = this->isolate();
// No active threads.
@@ -1318,6 +1398,7 @@ void PartialSerializer::Serialize(Object** o) {
back_reference_map()->AddGlobalProxy(context->global_proxy());
}
VisitPointer(o);
+ SerializeDeferredObjects();
SerializeOutdatedContextsAsFixedArray();
Pad();
}
@@ -1342,10 +1423,10 @@ void PartialSerializer::SerializeOutdatedContextsAsFixedArray() {
sink_->Put(reinterpret_cast<byte*>(&length_smi)[i], "Byte");
}
for (int i = 0; i < length; i++) {
- BackReference back_ref = outdated_contexts_[i];
- DCHECK(BackReferenceIsAlreadyAllocated(back_ref));
- sink_->Put(kBackref + back_ref.space(), "BackRef");
- sink_->PutInt(back_ref.reference(), "BackRefValue");
+ Context* context = outdated_contexts_[i];
+ BackReference back_reference = back_reference_map_.Lookup(context);
+ sink_->Put(kBackref + back_reference.space(), "BackRef");
+ PutBackReference(context, back_reference);
}
}
}
@@ -1508,10 +1589,7 @@ bool Serializer::SerializeKnownObject(HeapObject* obj, HowToCode how_to_code,
"BackRefWithSkip");
sink_->PutInt(skip, "BackRefSkipDistance");
}
- DCHECK(BackReferenceIsAlreadyAllocated(back_reference));
- sink_->PutInt(back_reference.reference(), "BackRefValue");
-
- hot_objects_.Add(obj);
+ PutBackReference(obj, back_reference);
}
return true;
}
@@ -1547,7 +1625,7 @@ void StartupSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
}
-void StartupSerializer::SerializeWeakReferences() {
+void StartupSerializer::SerializeWeakReferencesAndDeferred() {
// This phase comes right after the serialization (of the snapshot).
// After we have done the partial serialization the partial snapshot cache
// will contain some references needed to decode the partial snapshot. We
@@ -1556,6 +1634,7 @@ void StartupSerializer::SerializeWeakReferences() {
Object* undefined = isolate()->heap()->undefined_value();
VisitPointer(&undefined);
isolate()->heap()->IterateWeakRoots(this, VISIT_ALL);
+ SerializeDeferredObjects();
Pad();
}
@@ -1588,6 +1667,13 @@ void Serializer::PutRoot(int root_index,
}
+void Serializer::PutBackReference(HeapObject* object, BackReference reference) {
+ DCHECK(BackReferenceIsAlreadyAllocated(reference));
+ sink_->PutInt(reference.reference(), "BackRefValue");
+ hot_objects_.Add(object);
+}
+
+
void PartialSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
WhereToPoint where_to_point, int skip) {
if (obj->IsMap()) {
@@ -1641,9 +1727,7 @@ void PartialSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
Context::cast(obj)->global_object() == global_object_) {
// Context refers to the current global object. This reference will
// become outdated after deserialization.
- BackReference back_reference = back_reference_map_.Lookup(obj);
- DCHECK(back_reference.is_valid());
- outdated_contexts_.Add(back_reference);
+ outdated_contexts_.Add(Context::cast(obj));
}
}
@@ -1671,17 +1755,8 @@ void Serializer::ObjectSerializer::SerializePrologue(AllocationSpace space,
}
back_reference = serializer_->AllocateLargeObject(size);
} else {
- bool needs_double_align = false;
- if (object_->NeedsToEnsureDoubleAlignment()) {
- // Add wriggle room for double alignment padding.
- back_reference = serializer_->Allocate(space, size + kPointerSize);
- needs_double_align = true;
- } else {
- back_reference = serializer_->Allocate(space, size);
- }
+ back_reference = serializer_->Allocate(space, size);
sink_->Put(kNewObject + reference_representation_ + space, "NewObject");
- if (needs_double_align)
- sink_->PutInt(kDoubleAlignmentSentinel, "DoubleAlignSentinel");
int encoded_size = size >> kObjectAlignmentBits;
DCHECK_NE(kDoubleAlignmentSentinel, encoded_size);
sink_->PutInt(encoded_size, "ObjectSizeInWords");
@@ -1773,6 +1848,9 @@ void Serializer::ObjectSerializer::Serialize() {
// We cannot serialize typed array objects correctly.
DCHECK(!object_->IsJSTypedArray());
+ // We don't expect fillers.
+ DCHECK(!object_->IsFiller());
+
if (object_->IsPrototypeInfo()) {
Object* prototype_users = PrototypeInfo::cast(object_)->prototype_users();
if (prototype_users->IsWeakFixedArray()) {
@@ -1810,6 +1888,39 @@ void Serializer::ObjectSerializer::Serialize() {
CHECK_EQ(0, bytes_processed_so_far_);
bytes_processed_so_far_ = kPointerSize;
+ RecursionScope recursion(serializer_);
+ // Objects that are immediately post processed during deserialization
+ // cannot be deferred, since post processing requires the object content.
+ if (recursion.ExceedsMaximum() && CanBeDeferred(object_)) {
+ serializer_->QueueDeferredObject(object_);
+ sink_->Put(kDeferred, "Deferring object content");
+ return;
+ }
+
+ object_->IterateBody(map->instance_type(), size, this);
+ OutputRawData(object_->address() + size);
+}
+
+
+void Serializer::ObjectSerializer::SerializeDeferred() {
+ if (FLAG_trace_serializer) {
+ PrintF(" Encoding deferred heap object: ");
+ object_->ShortPrint();
+ PrintF("\n");
+ }
+
+ int size = object_->Size();
+ Map* map = object_->map();
+ BackReference reference = serializer_->back_reference_map()->Lookup(object_);
+
+ // Serialize the rest of the object.
+ CHECK_EQ(0, bytes_processed_so_far_);
+ bytes_processed_so_far_ = kPointerSize;
+
+ sink_->Put(kNewObject + reference.space(), "deferred object");
+ serializer_->PutBackReference(object_, reference);
+ sink_->PutInt(size >> kPointerSizeLog2, "deferred object size");
+
object_->IterateBody(map->instance_type(), size, this);
OutputRawData(object_->address() + size);
}
@@ -2134,6 +2245,7 @@ ScriptData* CodeSerializer::Serialize(Isolate* isolate,
DisallowHeapAllocation no_gc;
Object** location = Handle<Object>::cast(info).location();
cs.VisitPointer(location);
+ cs.SerializeDeferredObjects();
cs.Pad();
SerializedCodeData data(sink.data(), cs);
@@ -2212,8 +2324,6 @@ void CodeSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
void CodeSerializer::SerializeGeneric(HeapObject* heap_object,
HowToCode how_to_code,
WhereToPoint where_to_point) {
- if (heap_object->IsInternalizedString()) num_internalized_strings_++;
-
// Object has not yet been serialized. Serialize it here.
ObjectSerializer serializer(this, heap_object, sink_, how_to_code,
where_to_point);
@@ -2325,10 +2435,6 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
return MaybeHandle<SharedFunctionInfo>();
}
- // Eagerly expand string table to avoid allocations during deserialization.
- StringTable::EnsureCapacityForDeserialization(isolate,
- scd->NumInternalizedStrings());
-
// Prepare and register list of attached objects.
Vector<const uint32_t> code_stub_keys = scd->CodeStubKeys();
Vector<Handle<Object> > attached_objects = Vector<Handle<Object> >::New(
@@ -2492,7 +2598,6 @@ SerializedCodeData::SerializedCodeData(const List<byte>& payload,
SetHeaderValue(kCpuFeaturesOffset,
static_cast<uint32_t>(CpuFeatures::SupportedFeatures()));
SetHeaderValue(kFlagHashOffset, FlagList::Hash());
- SetHeaderValue(kNumInternalizedStringsOffset, cs.num_internalized_strings());
SetHeaderValue(kNumReservationsOffset, reservations.length());
SetHeaderValue(kNumCodeStubKeysOffset, num_stub_keys);
SetHeaderValue(kPayloadLengthOffset, payload.length());
@@ -2570,10 +2675,6 @@ Vector<const byte> SerializedCodeData::Payload() const {
}
-int SerializedCodeData::NumInternalizedStrings() const {
- return GetHeaderValue(kNumInternalizedStringsOffset);
-}
-
Vector<const uint32_t> SerializedCodeData::CodeStubKeys() const {
int reservations_size = GetHeaderValue(kNumReservationsOffset) * kInt32Size;
const byte* start = data_ + kHeaderSize + reservations_size;
diff --git a/deps/v8/src/snapshot/serialize.h b/deps/v8/src/snapshot/serialize.h
index 36514e13d3..67ce69ab94 100644
--- a/deps/v8/src/snapshot/serialize.h
+++ b/deps/v8/src/snapshot/serialize.h
@@ -306,6 +306,10 @@ class SerializerDeserializer: public ObjectVisitor {
static const int kNumberOfSpaces = LAST_SPACE + 1;
protected:
+ static bool CanBeDeferred(HeapObject* o) {
+ return !o->IsString() && !o->IsScript();
+ }
+
// ---------- byte code range 0x00..0x7f ----------
// Byte codes in this range represent Where, HowToCode and WhereToPoint.
// Where the pointed-to object can be found:
@@ -373,6 +377,8 @@ class SerializerDeserializer: public ObjectVisitor {
static const int kNop = 0x3d;
// Move to next reserved chunk.
static const int kNextChunk = 0x3e;
+ // Deferring object content.
+ static const int kDeferred = 0x3f;
// A tag emitted at strategic points in the snapshot to delineate sections.
// If the deserializer does not find these at the expected moments then it
// is an indication that the snapshot and the VM do not fit together.
@@ -553,22 +559,22 @@ class Deserializer: public SerializerDeserializer {
memcpy(dest, src, sizeof(*src));
}
- // Allocation sites are present in the snapshot, and must be linked into
- // a list at deserialization time.
- void RelinkAllocationSite(AllocationSite* site);
+ void DeserializeDeferredObjects();
+
+ void CommitNewInternalizedStrings(Isolate* isolate);
// Fills in some heap data in an area from start to end (non-inclusive). The
// space id is used for the write barrier. The object_address is the address
// of the object we are writing into, or NULL if we are not writing into an
// object, i.e. if we are writing a series of tagged values that are not on
- // the heap.
- void ReadData(Object** start, Object** end, int space,
+ // the heap. Return false if the object content has been deferred.
+ bool ReadData(Object** start, Object** end, int space,
Address object_address);
void ReadObject(int space_number, Object** write_back);
Address Allocate(int space_index, int size);
// Special handling for serialized code like hooking up internalized strings.
- HeapObject* ProcessNewObjectFromSerializedCode(HeapObject* obj);
+ HeapObject* PostProcessNewObject(HeapObject* obj, int space);
// This returns the address of an object that has been described in the
// snapshot by chunk index and offset.
@@ -594,6 +600,8 @@ class Deserializer: public SerializerDeserializer {
ExternalReferenceTable* external_reference_table_;
List<HeapObject*> deserialized_large_objects_;
+ List<Code*> new_code_objects_;
+ List<Handle<String> > new_internalized_strings_;
bool deserializing_user_code_;
@@ -612,6 +620,8 @@ class Serializer : public SerializerDeserializer {
void EncodeReservations(List<SerializedData::Reservation>* out) const;
+ void SerializeDeferredObjects();
+
Isolate* isolate() const { return isolate_; }
BackReferenceMap* back_reference_map() { return &back_reference_map_; }
@@ -634,6 +644,7 @@ class Serializer : public SerializerDeserializer {
is_code_object_(o->IsCode()),
code_has_been_output_(false) {}
void Serialize();
+ void SerializeDeferred();
void VisitPointers(Object** start, Object** end);
void VisitEmbeddedPointer(RelocInfo* target);
void VisitExternalReference(Address* p);
@@ -675,12 +686,29 @@ class Serializer : public SerializerDeserializer {
bool code_has_been_output_;
};
+ class RecursionScope {
+ public:
+ explicit RecursionScope(Serializer* serializer) : serializer_(serializer) {
+ serializer_->recursion_depth_++;
+ }
+ ~RecursionScope() { serializer_->recursion_depth_--; }
+ bool ExceedsMaximum() {
+ return serializer_->recursion_depth_ >= kMaxRecursionDepth;
+ }
+
+ private:
+ static const int kMaxRecursionDepth = 32;
+ Serializer* serializer_;
+ };
+
virtual void SerializeObject(HeapObject* o, HowToCode how_to_code,
WhereToPoint where_to_point, int skip) = 0;
void PutRoot(int index, HeapObject* object, HowToCode how, WhereToPoint where,
int skip);
+ void PutBackReference(HeapObject* object, BackReference reference);
+
// Returns true if the object was successfully serialized.
bool SerializeKnownObject(HeapObject* obj, HowToCode how_to_code,
WhereToPoint where_to_point, int skip);
@@ -722,6 +750,11 @@ class Serializer : public SerializerDeserializer {
SnapshotByteSink* sink() const { return sink_; }
+ void QueueDeferredObject(HeapObject* obj) {
+ DCHECK(back_reference_map_.Lookup(obj).is_valid());
+ deferred_objects_.Add(obj);
+ }
+
void OutputStatistics(const char* name);
Isolate* isolate_;
@@ -732,8 +765,11 @@ class Serializer : public SerializerDeserializer {
BackReferenceMap back_reference_map_;
RootIndexMap root_index_map_;
+ int recursion_depth_;
+
friend class Deserializer;
friend class ObjectSerializer;
+ friend class RecursionScope;
friend class SnapshotData;
private:
@@ -752,6 +788,9 @@ class Serializer : public SerializerDeserializer {
List<byte> code_buffer_;
+ // To handle stack overflow.
+ List<HeapObject*> deferred_objects_;
+
#ifdef OBJECT_PRINT
static const int kInstanceTypes = 256;
int* instance_type_count_;
@@ -797,7 +836,7 @@ class PartialSerializer : public Serializer {
void SerializeOutdatedContextsAsFixedArray();
Serializer* startup_serializer_;
- List<BackReference> outdated_contexts_;
+ List<Context*> outdated_contexts_;
Object* global_object_;
PartialCacheIndexMap partial_cache_index_map_;
DISALLOW_COPY_AND_ASSIGN(PartialSerializer);
@@ -829,11 +868,10 @@ class StartupSerializer : public Serializer {
virtual void SerializeStrongReferences();
virtual void SerializeObject(HeapObject* o, HowToCode how_to_code,
WhereToPoint where_to_point, int skip) override;
- void SerializeWeakReferences();
+ void SerializeWeakReferencesAndDeferred();
void Serialize() {
SerializeStrongReferences();
- SerializeWeakReferences();
- Pad();
+ SerializeWeakReferencesAndDeferred();
}
private:
@@ -862,15 +900,11 @@ class CodeSerializer : public Serializer {
}
const List<uint32_t>* stub_keys() const { return &stub_keys_; }
- int num_internalized_strings() const { return num_internalized_strings_; }
private:
CodeSerializer(Isolate* isolate, SnapshotByteSink* sink, String* source,
Code* main_code)
- : Serializer(isolate, sink),
- source_(source),
- main_code_(main_code),
- num_internalized_strings_(0) {
+ : Serializer(isolate, sink), source_(source), main_code_(main_code) {
back_reference_map_.AddSourceString(source);
}
@@ -892,7 +926,6 @@ class CodeSerializer : public Serializer {
DisallowHeapAllocation no_gc_;
String* source_;
Code* main_code_;
- int num_internalized_strings_;
List<uint32_t> stub_keys_;
DISALLOW_COPY_AND_ASSIGN(CodeSerializer);
};
@@ -951,7 +984,6 @@ class SerializedCodeData : public SerializedData {
Vector<const Reservation> Reservations() const;
Vector<const byte> Payload() const;
- int NumInternalizedStrings() const;
Vector<const uint32_t> CodeStubKeys() const;
private:
@@ -972,17 +1004,16 @@ class SerializedCodeData : public SerializedData {
uint32_t SourceHash(String* source) const { return source->length(); }
// The data header consists of uint32_t-sized entries:
- // [ 0] magic number and external reference count
- // [ 1] version hash
- // [ 2] source hash
- // [ 3] cpu features
- // [ 4] flag hash
- // [ 5] number of internalized strings
- // [ 6] number of code stub keys
- // [ 7] number of reservation size entries
- // [ 8] payload length
- // [ 9] payload checksum part 1
- // [10] payload checksum part 2
+ // [0] magic number and external reference count
+ // [1] version hash
+ // [2] source hash
+ // [3] cpu features
+ // [4] flag hash
+ // [5] number of code stub keys
+ // [6] number of reservation size entries
+ // [7] payload length
+ // [8] payload checksum part 1
+ // [9] payload checksum part 2
// ... reservations
// ... code stub keys
// ... serialized payload
@@ -990,9 +1021,7 @@ class SerializedCodeData : public SerializedData {
static const int kSourceHashOffset = kVersionHashOffset + kInt32Size;
static const int kCpuFeaturesOffset = kSourceHashOffset + kInt32Size;
static const int kFlagHashOffset = kCpuFeaturesOffset + kInt32Size;
- static const int kNumInternalizedStringsOffset = kFlagHashOffset + kInt32Size;
- static const int kNumReservationsOffset =
- kNumInternalizedStringsOffset + kInt32Size;
+ static const int kNumReservationsOffset = kFlagHashOffset + kInt32Size;
static const int kNumCodeStubKeysOffset = kNumReservationsOffset + kInt32Size;
static const int kPayloadLengthOffset = kNumCodeStubKeysOffset + kInt32Size;
static const int kChecksum1Offset = kPayloadLengthOffset + kInt32Size;
diff --git a/deps/v8/src/unicode-decoder.cc b/deps/v8/src/unicode-decoder.cc
index bb520990f0..2289e08342 100644
--- a/deps/v8/src/unicode-decoder.cc
+++ b/deps/v8/src/unicode-decoder.cc
@@ -67,6 +67,7 @@ void Utf8DecoderBase::WriteUtf16Slow(const uint8_t* stream,
// There's a total lack of bounds checking for stream
// as it was already done in Reset.
stream += cursor;
+ DCHECK(stream_length >= cursor);
stream_length -= cursor;
if (character > unibrow::Utf16::kMaxNonSurrogateCharCode) {
*data++ = Utf16::LeadSurrogate(character);
@@ -78,7 +79,6 @@ void Utf8DecoderBase::WriteUtf16Slow(const uint8_t* stream,
data_length -= 1;
}
}
- DCHECK(stream_length >= 0);
}
} // namespace unibrow
diff --git a/deps/v8/src/x64/lithium-x64.cc b/deps/v8/src/x64/lithium-x64.cc
index 54aed57b89..b8ac5592de 100644
--- a/deps/v8/src/x64/lithium-x64.cc
+++ b/deps/v8/src/x64/lithium-x64.cc
@@ -1313,7 +1313,13 @@ LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
DCHECK(instr->CheckFlag(HValue::kTruncatingToInt32));
LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
- LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
+ LOperand* right;
+ if (SmiValuesAre32Bits() && instr->representation().IsSmi()) {
+ // We don't support tagged immediates, so we request it in a register.
+ right = UseRegisterAtStart(instr->BetterRightOperand());
+ } else {
+ right = UseOrConstantAtStart(instr->BetterRightOperand());
+ }
return DefineSameAsFirst(new(zone()) LBitI(left, right));
} else {
return DoArithmeticT(instr->op(), instr);
@@ -1555,7 +1561,13 @@ LInstruction* LChunkBuilder::DoSub(HSub* instr) {
DCHECK(instr->left()->representation().Equals(instr->representation()));
DCHECK(instr->right()->representation().Equals(instr->representation()));
LOperand* left = UseRegisterAtStart(instr->left());
- LOperand* right = UseOrConstantAtStart(instr->right());
+ LOperand* right;
+ if (SmiValuesAre32Bits() && instr->representation().IsSmi()) {
+ // We don't support tagged immediates, so we request it in a register.
+ right = UseRegisterAtStart(instr->right());
+ } else {
+ right = UseOrConstantAtStart(instr->right());
+ }
LSubI* sub = new(zone()) LSubI(left, right);
LInstruction* result = DefineSameAsFirst(sub);
if (instr->CheckFlag(HValue::kCanOverflow)) {
diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc
index da40058a35..35e27c3118 100644
--- a/deps/v8/test/cctest/test-api.cc
+++ b/deps/v8/test/cctest/test-api.cc
@@ -7318,6 +7318,57 @@ THREADED_TEST(Utf16Symbol) {
}
+THREADED_TEST(Utf16MissingTrailing) {
+ LocalContext context;
+ v8::HandleScope scope(context->GetIsolate());
+
+ // Make sure it will go past the buffer, so it will call `WriteUtf16Slow`
+ int size = 1024 * 64;
+ uint8_t* buffer = new uint8_t[size];
+ for (int i = 0; i < size; i += 4) {
+ buffer[i] = 0xf0;
+ buffer[i + 1] = 0x9d;
+ buffer[i + 2] = 0x80;
+ buffer[i + 3] = 0x9e;
+ }
+
+ // Now invoke the decoder without last 3 bytes
+ v8::Local<v8::String> str =
+ v8::String::NewFromUtf8(
+ context->GetIsolate(), reinterpret_cast<char*>(buffer),
+ v8::NewStringType::kNormal, size - 3).ToLocalChecked();
+ USE(str);
+ delete[] buffer;
+}
+
+
+THREADED_TEST(Utf16Trailing3Byte) {
+ LocalContext context;
+ v8::HandleScope scope(context->GetIsolate());
+
+ // Make sure it will go past the buffer, so it will call `WriteUtf16Slow`
+ int size = 1024 * 63;
+ uint8_t* buffer = new uint8_t[size];
+ for (int i = 0; i < size; i += 3) {
+ buffer[i] = 0xe2;
+ buffer[i + 1] = 0x80;
+ buffer[i + 2] = 0xa6;
+ }
+
+ // Now invoke the decoder without last 3 bytes
+ v8::Local<v8::String> str =
+ v8::String::NewFromUtf8(
+ context->GetIsolate(), reinterpret_cast<char*>(buffer),
+ v8::NewStringType::kNormal, size).ToLocalChecked();
+
+ v8::String::Value value(str);
+ CHECK_EQ(value.length(), size / 3);
+ CHECK_EQ((*value)[value.length() - 1], 0x2026);
+
+ delete[] buffer;
+}
+
+
THREADED_TEST(ToArrayIndex) {
LocalContext context;
v8::Isolate* isolate = context->GetIsolate();
@@ -20927,3 +20978,42 @@ TEST(SealHandleScopeNested) {
USE(obj);
}
}
+
+
+TEST(CompatibleReceiverCheckOnCachedICHandler) {
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::HandleScope scope(isolate);
+ v8::Local<v8::FunctionTemplate> parent = FunctionTemplate::New(isolate);
+ v8::Local<v8::Signature> signature = v8::Signature::New(isolate, parent);
+ auto returns_42 =
+ v8::FunctionTemplate::New(isolate, Returns42, Local<Value>(), signature);
+ parent->PrototypeTemplate()->SetAccessorProperty(v8_str("age"), returns_42);
+ v8::Local<v8::FunctionTemplate> child = v8::FunctionTemplate::New(isolate);
+ child->Inherit(parent);
+ LocalContext env;
+ env->Global()->Set(v8_str("Child"), child->GetFunction());
+
+ // Make sure there's a compiled stub for "Child.prototype.age" in the cache.
+ CompileRun(
+ "var real = new Child();\n"
+ "for (var i = 0; i < 3; ++i) {\n"
+ " real.age;\n"
+ "}\n");
+
+ // Check that the cached stub is never used.
+ ExpectInt32(
+ "var fake = Object.create(Child.prototype);\n"
+ "var result = 0;\n"
+ "function test(d) {\n"
+ " if (d == 3) return;\n"
+ " try {\n"
+ " fake.age;\n"
+ " result = 1;\n"
+ " } catch (e) {\n"
+ " }\n"
+ " test(d+1);\n"
+ "}\n"
+ "test(0);\n"
+ "result;\n",
+ 0);
+}
diff --git a/deps/v8/test/cctest/test-assembler-arm.cc b/deps/v8/test/cctest/test-assembler-arm.cc
index cb89577991..059c04ad40 100644
--- a/deps/v8/test/cctest/test-assembler-arm.cc
+++ b/deps/v8/test/cctest/test-assembler-arm.cc
@@ -1981,4 +1981,63 @@ TEST(ARMv8_vrintX) {
#undef CHECK_VRINT
}
}
+
+
+TEST(regress4292_b) {
+ CcTest::InitializeVM();
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+
+ Assembler assm(isolate, NULL, 0);
+ Label end;
+ __ mov(r0, Operand(isolate->factory()->infinity_value()));
+ for (int i = 0; i < 1020; ++i) {
+ __ b(hi, &end);
+ }
+ __ bind(&end);
+}
+
+
+TEST(regress4292_bl) {
+ CcTest::InitializeVM();
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+
+ Assembler assm(isolate, NULL, 0);
+ Label end;
+ __ mov(r0, Operand(isolate->factory()->infinity_value()));
+ for (int i = 0; i < 1020; ++i) {
+ __ bl(hi, &end);
+ }
+ __ bind(&end);
+}
+
+
+TEST(regress4292_blx) {
+ CcTest::InitializeVM();
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+
+ Assembler assm(isolate, NULL, 0);
+ Label end;
+ __ mov(r0, Operand(isolate->factory()->infinity_value()));
+ for (int i = 0; i < 1020; ++i) {
+ __ blx(&end);
+ }
+ __ bind(&end);
+}
+
+
+TEST(regress4292_CheckConstPool) {
+ CcTest::InitializeVM();
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+
+ Assembler assm(isolate, NULL, 0);
+ __ mov(r0, Operand(isolate->factory()->infinity_value()));
+ __ BlockConstPoolFor(1019);
+ for (int i = 0; i < 1019; ++i) __ nop();
+ __ vldr(d0, MemOperand(r0, 0));
+}
+
#undef __
diff --git a/deps/v8/test/cctest/test-assembler-mips.cc b/deps/v8/test/cctest/test-assembler-mips.cc
index 7d0e105401..7a8beaa578 100644
--- a/deps/v8/test/cctest/test-assembler-mips.cc
+++ b/deps/v8/test/cctest/test-assembler-mips.cc
@@ -1672,6 +1672,7 @@ TEST(jump_tables1) {
Label done;
{
+ __ BlockTrampolinePoolFor(kNumCases + 7);
PredictableCodeSizeScope predictable(
&assm, (kNumCases + 7) * Assembler::kInstrSize);
Label here;
@@ -1748,6 +1749,7 @@ TEST(jump_tables2) {
__ bind(&dispatch);
{
+ __ BlockTrampolinePoolFor(kNumCases + 7);
PredictableCodeSizeScope predictable(
&assm, (kNumCases + 7) * Assembler::kInstrSize);
Label here;
@@ -1823,6 +1825,7 @@ TEST(jump_tables3) {
__ bind(&dispatch);
{
+ __ BlockTrampolinePoolFor(kNumCases + 7);
PredictableCodeSizeScope predictable(
&assm, (kNumCases + 7) * Assembler::kInstrSize);
Label here;
diff --git a/deps/v8/test/cctest/test-assembler-mips64.cc b/deps/v8/test/cctest/test-assembler-mips64.cc
index a6673d8e13..3b422a2716 100644
--- a/deps/v8/test/cctest/test-assembler-mips64.cc
+++ b/deps/v8/test/cctest/test-assembler-mips64.cc
@@ -1889,6 +1889,7 @@ TEST(jump_tables1) {
Label done;
{
+ __ BlockTrampolinePoolFor(kNumCases * 2 + 7);
PredictableCodeSizeScope predictable(
&assm, (kNumCases * 2 + 7) * Assembler::kInstrSize);
Label here;
@@ -1968,6 +1969,7 @@ TEST(jump_tables2) {
}
__ bind(&dispatch);
{
+ __ BlockTrampolinePoolFor(kNumCases * 2 + 7);
PredictableCodeSizeScope predictable(
&assm, (kNumCases * 2 + 7) * Assembler::kInstrSize);
Label here;
@@ -2049,6 +2051,7 @@ TEST(jump_tables3) {
}
__ bind(&dispatch);
{
+ __ BlockTrampolinePoolFor(kNumCases * 2 + 7);
PredictableCodeSizeScope predictable(
&assm, (kNumCases * 2 + 7) * Assembler::kInstrSize);
Label here;
diff --git a/deps/v8/test/cctest/test-macro-assembler-mips.cc b/deps/v8/test/cctest/test-macro-assembler-mips.cc
index 3a97d2137f..515bac9d3a 100644
--- a/deps/v8/test/cctest/test-macro-assembler-mips.cc
+++ b/deps/v8/test/cctest/test-macro-assembler-mips.cc
@@ -26,18 +26,20 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdlib.h>
+#include <iostream> // NOLINT(readability/streams)
-#include "src/v8.h"
-#include "test/cctest/cctest.h"
-
+#include "src/base/utils/random-number-generator.h"
#include "src/macro-assembler.h"
#include "src/mips/macro-assembler-mips.h"
#include "src/mips/simulator-mips.h"
+#include "src/v8.h"
+#include "test/cctest/cctest.h"
using namespace v8::internal;
typedef void* (*F)(int x, int y, int p2, int p3, int p4);
+typedef Object* (*F1)(int x, int p1, int p2, int p3, int p4);
#define __ masm->
@@ -174,4 +176,86 @@ TEST(NaN1) {
}
+TEST(jump_tables4) {
+ // Similar to test-assembler-mips jump_tables1, with extra test for branch
+ // trampoline required before emission of the dd table (where trampolines are
+ // blocked), and proper transition to long-branch mode.
+ // Regression test for v8:4294.
+ CcTest::InitializeVM();
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+ MacroAssembler assembler(isolate, NULL, 0);
+ MacroAssembler* masm = &assembler;
+
+ const int kNumCases = 512;
+ int values[kNumCases];
+ isolate->random_number_generator()->NextBytes(values, sizeof(values));
+ Label labels[kNumCases];
+ Label near_start, end;
+
+ __ addiu(sp, sp, -4);
+ __ sw(ra, MemOperand(sp));
+
+ __ mov(v0, zero_reg);
+
+ __ Branch(&end);
+ __ bind(&near_start);
+
+ // Generate slightly less than 32K instructions, which will soon require
+ // trampoline for branch distance fixup.
+ for (int i = 0; i < 32768 - 256; ++i) {
+ __ addiu(v0, v0, 1);
+ }
+
+ Label done;
+ {
+ __ BlockTrampolinePoolFor(kNumCases + 6);
+ PredictableCodeSizeScope predictable(
+ masm, (kNumCases + 6) * Assembler::kInstrSize);
+ Label here;
+
+ __ bal(&here);
+ __ sll(at, a0, 2); // In delay slot.
+ __ bind(&here);
+ __ addu(at, at, ra);
+ __ lw(at, MemOperand(at, 4 * Assembler::kInstrSize));
+ __ jr(at);
+ __ nop(); // Branch delay slot nop.
+ for (int i = 0; i < kNumCases; ++i) {
+ __ dd(&labels[i]);
+ }
+ }
+
+ for (int i = 0; i < kNumCases; ++i) {
+ __ bind(&labels[i]);
+ __ lui(v0, (values[i] >> 16) & 0xffff);
+ __ ori(v0, v0, values[i] & 0xffff);
+ __ Branch(&done);
+ }
+
+ __ bind(&done);
+ __ lw(ra, MemOperand(sp));
+ __ addiu(sp, sp, 4);
+ __ jr(ra);
+ __ nop();
+
+ __ bind(&end);
+ __ Branch(&near_start);
+
+ CodeDesc desc;
+ masm->GetCode(&desc);
+ Handle<Code> code = isolate->factory()->NewCode(
+ desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+ code->Print(std::cout);
+#endif
+ F1 f = FUNCTION_CAST<F1>(code->entry());
+ for (int i = 0; i < kNumCases; ++i) {
+ int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, i, 0, 0, 0, 0));
+ ::printf("f(%d) = %d\n", i, res);
+ CHECK_EQ(values[i], res);
+ }
+}
+
+
#undef __
diff --git a/deps/v8/test/cctest/test-macro-assembler-mips64.cc b/deps/v8/test/cctest/test-macro-assembler-mips64.cc
index eef658de67..fadd45f43b 100644
--- a/deps/v8/test/cctest/test-macro-assembler-mips64.cc
+++ b/deps/v8/test/cctest/test-macro-assembler-mips64.cc
@@ -26,10 +26,12 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdlib.h>
+#include <iostream> // NOLINT(readability/streams)
#include "src/v8.h"
#include "test/cctest/cctest.h"
+#include "src/base/utils/random-number-generator.h"
#include "src/macro-assembler.h"
#include "src/mips64/macro-assembler-mips64.h"
#include "src/mips64/simulator-mips64.h"
@@ -38,6 +40,7 @@
using namespace v8::internal;
typedef void* (*F)(int64_t x, int64_t y, int p2, int p3, int p4);
+typedef Object* (*F1)(int x, int p1, int p2, int p3, int p4);
#define __ masm->
@@ -214,4 +217,90 @@ TEST(LoadAddress) {
// Check results.
}
+
+TEST(jump_tables4) {
+ // Similar to test-assembler-mips jump_tables1, with extra test for branch
+ // trampoline required before emission of the dd table (where trampolines are
+ // blocked), and proper transition to long-branch mode.
+ // Regression test for v8:4294.
+ CcTest::InitializeVM();
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+ MacroAssembler assembler(isolate, NULL, 0);
+ MacroAssembler* masm = &assembler;
+
+ const int kNumCases = 512;
+ int values[kNumCases];
+ isolate->random_number_generator()->NextBytes(values, sizeof(values));
+ Label labels[kNumCases];
+ Label near_start, end;
+
+ __ daddiu(sp, sp, -8);
+ __ sd(ra, MemOperand(sp));
+ if ((masm->pc_offset() & 7) == 0) {
+ __ nop();
+ }
+
+ __ mov(v0, zero_reg);
+
+ __ Branch(&end);
+ __ bind(&near_start);
+
+ // Generate slightly less than 32K instructions, which will soon require
+ // trampoline for branch distance fixup.
+ for (int i = 0; i < 32768 - 256; ++i) {
+ __ addiu(v0, v0, 1);
+ }
+
+ Label done;
+ {
+ __ BlockTrampolinePoolFor(kNumCases * 2 + 6);
+ PredictableCodeSizeScope predictable(
+ masm, (kNumCases * 2 + 6) * Assembler::kInstrSize);
+ Label here;
+
+ __ bal(&here);
+ __ dsll(at, a0, 3); // In delay slot.
+ __ bind(&here);
+ __ daddu(at, at, ra);
+ __ ld(at, MemOperand(at, 4 * Assembler::kInstrSize));
+ __ jr(at);
+ __ nop(); // Branch delay slot nop.
+ for (int i = 0; i < kNumCases; ++i) {
+ __ dd(&labels[i]);
+ }
+ }
+
+ for (int i = 0; i < kNumCases; ++i) {
+ __ bind(&labels[i]);
+ __ lui(v0, (values[i] >> 16) & 0xffff);
+ __ ori(v0, v0, values[i] & 0xffff);
+ __ Branch(&done);
+ }
+
+ __ bind(&done);
+ __ ld(ra, MemOperand(sp));
+ __ daddiu(sp, sp, 8);
+ __ jr(ra);
+ __ nop();
+
+ __ bind(&end);
+ __ Branch(&near_start);
+
+ CodeDesc desc;
+ masm->GetCode(&desc);
+ Handle<Code> code = isolate->factory()->NewCode(
+ desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+ code->Print(std::cout);
+#endif
+ F1 f = FUNCTION_CAST<F1>(code->entry());
+ for (int i = 0; i < kNumCases; ++i) {
+ int64_t res =
+ reinterpret_cast<int64_t>(CALL_GENERATED_CODE(f, i, 0, 0, 0, 0));
+ ::printf("f(%d) = %" PRId64 "\n", i, res);
+ CHECK_EQ(values[i], res);
+ }
+}
+
#undef __
diff --git a/deps/v8/test/cctest/test-serialize.cc b/deps/v8/test/cctest/test-serialize.cc
index 1ed43ac338..938178efb9 100644
--- a/deps/v8/test/cctest/test-serialize.cc
+++ b/deps/v8/test/cctest/test-serialize.cc
@@ -329,7 +329,7 @@ UNINITIALIZED_TEST(PartialSerialization) {
&partial_sink);
partial_serializer.Serialize(&raw_foo);
- startup_serializer.SerializeWeakReferences();
+ startup_serializer.SerializeWeakReferencesAndDeferred();
SnapshotData startup_snapshot(startup_serializer);
SnapshotData partial_snapshot(partial_serializer);
@@ -447,7 +447,7 @@ UNINITIALIZED_TEST(ContextSerialization) {
PartialSerializer partial_serializer(isolate, &startup_serializer,
&partial_sink);
partial_serializer.Serialize(&raw_context);
- startup_serializer.SerializeWeakReferences();
+ startup_serializer.SerializeWeakReferencesAndDeferred();
SnapshotData startup_snapshot(startup_serializer);
SnapshotData partial_snapshot(partial_serializer);
@@ -582,7 +582,7 @@ UNINITIALIZED_TEST(CustomContextSerialization) {
PartialSerializer partial_serializer(isolate, &startup_serializer,
&partial_sink);
partial_serializer.Serialize(&raw_context);
- startup_serializer.SerializeWeakReferences();
+ startup_serializer.SerializeWeakReferencesAndDeferred();
SnapshotData startup_snapshot(startup_serializer);
SnapshotData partial_snapshot(partial_serializer);
@@ -702,6 +702,57 @@ TEST(PerIsolateSnapshotBlobs) {
}
+static void SerializationFunctionTemplate(
+ const v8::FunctionCallbackInfo<v8::Value>& args) {
+ args.GetReturnValue().Set(args[0]);
+}
+
+
+TEST(PerIsolateSnapshotBlobsOutdatedContextWithOverflow) {
+ DisableTurbofan();
+
+ const char* source1 =
+ "var o = {};"
+ "(function() {"
+ " function f1(x) { return f2(x) instanceof Array; }"
+ " function f2(x) { return foo.bar(x); }"
+ " o.a = f2.bind(null);"
+ " o.b = 1;"
+ " o.c = 2;"
+ " o.d = 3;"
+ " o.e = 4;"
+ "})();\n";
+
+ const char* source2 = "o.a(42)";
+
+ v8::StartupData data = v8::V8::CreateSnapshotDataBlob(source1);
+
+ v8::Isolate::CreateParams params;
+ params.snapshot_blob = &data;
+ params.array_buffer_allocator = CcTest::array_buffer_allocator();
+
+ v8::Isolate* isolate = v8::Isolate::New(params);
+ {
+ v8::Isolate::Scope i_scope(isolate);
+ v8::HandleScope h_scope(isolate);
+
+ v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
+ v8::Local<v8::ObjectTemplate> property = v8::ObjectTemplate::New(isolate);
+ v8::Local<v8::FunctionTemplate> function =
+ v8::FunctionTemplate::New(isolate, SerializationFunctionTemplate);
+ property->Set(isolate, "bar", function);
+ global->Set(isolate, "foo", property);
+
+ v8::Local<v8::Context> context = v8::Context::New(isolate, NULL, global);
+ delete[] data.data; // We can dispose of the snapshot blob now.
+ v8::Context::Scope c_scope(context);
+ v8::Local<v8::Value> result = CompileRun(source2);
+ CHECK(v8_str("42")->Equals(result));
+ }
+ isolate->Dispose();
+}
+
+
TEST(PerIsolateSnapshotBlobsWithLocker) {
DisableTurbofan();
v8::Isolate::CreateParams create_params;
@@ -738,6 +789,44 @@ TEST(PerIsolateSnapshotBlobsWithLocker) {
}
+TEST(SnapshotBlobsStackOverflow) {
+ DisableTurbofan();
+ const char* source =
+ "var a = [0];"
+ "var b = a;"
+ "for (var i = 0; i < 10000; i++) {"
+ " var c = [i];"
+ " b.push(c);"
+ " b.push(c);"
+ " b = c;"
+ "}";
+
+ v8::StartupData data = v8::V8::CreateSnapshotDataBlob(source);
+
+ v8::Isolate::CreateParams params;
+ params.snapshot_blob = &data;
+ params.array_buffer_allocator = CcTest::array_buffer_allocator();
+
+ v8::Isolate* isolate = v8::Isolate::New(params);
+ {
+ v8::Isolate::Scope i_scope(isolate);
+ v8::HandleScope h_scope(isolate);
+ v8::Local<v8::Context> context = v8::Context::New(isolate);
+ delete[] data.data; // We can dispose of the snapshot blob now.
+ v8::Context::Scope c_scope(context);
+ const char* test =
+ "var sum = 0;"
+ "while (a) {"
+ " sum += a[0];"
+ " a = a[1];"
+ "}"
+ "sum";
+ CHECK_EQ(9999 * 5000, CompileRun(test)->ToInt32(isolate)->Int32Value());
+ }
+ isolate->Dispose();
+}
+
+
TEST(TestThatAlwaysSucceeds) {
}
diff --git a/deps/v8/test/mjsunit/es6/regress/regress-cr493566.js b/deps/v8/test/mjsunit/es6/regress/regress-cr493566.js
new file mode 100644
index 0000000000..9bb313ffbe
--- /dev/null
+++ b/deps/v8/test/mjsunit/es6/regress/regress-cr493566.js
@@ -0,0 +1,80 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-proxies
+
+"use strict";
+
+
+var global = this;
+
+
+(function TestGlobalReceiver() {
+ class A {
+ s() {
+ super.bla = 10;
+ }
+ }
+ new A().s.call(global);
+ assertEquals(10, global.bla);
+})();
+
+
+(function TestProxyProto() {
+ var calls = 0;
+ var handler = {
+ getPropertyDescriptor: function(name) {
+ calls++;
+ return undefined;
+ }
+ };
+
+ var proto = {};
+ var proxy = Proxy.create(handler, proto);
+ var object = {
+ __proto__: proxy,
+ setX(v) {
+ super.x = v;
+ },
+ setSymbol(sym, v) {
+ super[sym] = v;
+ }
+ };
+
+ object.setX(1);
+ assertEquals(1, Object.getOwnPropertyDescriptor(object, 'x').value);
+ assertEquals(1, calls);
+
+ var sym = Symbol();
+ object.setSymbol.call(global, sym, 2);
+ assertEquals(2, Object.getOwnPropertyDescriptor(global, sym).value);
+ // We currently do not invoke proxy traps for symbols
+ assertEquals(1, calls);
+})();
+
+
+(function TestProxyReceiver() {
+ var object = {
+ setY(v) {
+ super.y = v;
+ }
+ };
+
+ var calls = 0;
+ var handler = {
+ getPropertyDescriptor(name) {
+ assertUnreachable();
+ },
+ set(receiver, name, value) {
+ calls++;
+ assertEquals(proxy, receiver);
+ assertEquals('y', name);
+ assertEquals(3, value);
+ }
+ };
+
+ var proxy = Proxy.create(handler);
+ object.setY.call(proxy, 3);
+ assertEquals(1, calls);
+})();
diff --git a/deps/v8/test/mjsunit/mjsunit.status b/deps/v8/test/mjsunit/mjsunit.status
index dfbe3b5d63..71a7de4ec7 100644
--- a/deps/v8/test/mjsunit/mjsunit.status
+++ b/deps/v8/test/mjsunit/mjsunit.status
@@ -561,10 +561,6 @@
'math-floor-of-div-minus-zero': [SKIP],
}], # 'arch == mips64el'
-['arch == mips64el and simulator_run == False', {
- # Random failures on HW, need investigation.
- 'debug-*': [SKIP],
-}],
##############################################################################
['system == windows', {
# TODO(mstarzinger): Too slow with turbo fan.
diff --git a/deps/v8/test/mjsunit/regress/regress-487981.js b/deps/v8/test/mjsunit/regress/regress-487981.js
new file mode 100644
index 0000000000..829c25c59d
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-487981.js
@@ -0,0 +1,22 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --stress-compaction
+
+// To reliably reproduce the crash use --verify-heap --random-seed=-133185440
+
+function __f_2(o) {
+ return o.field.b.x;
+}
+
+try {
+ %OptimizeFunctionOnNextCall(__f_2);
+ __v_1 = __f_2();
+} catch(e) { }
+
+function __f_3() { __f_3(/./.test()); };
+
+try {
+__f_3();
+} catch(e) { }
diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-478612.js b/deps/v8/test/mjsunit/regress/regress-crbug-478612.js
new file mode 100644
index 0000000000..3419722cd0
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-crbug-478612.js
@@ -0,0 +1,52 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+// This is used to force binary operations below to have tagged representation.
+var z = {valueOf: function() { return 3; }};
+
+
+function f() {
+ var y = -2;
+ return (1 & z) - y++;
+}
+
+assertEquals(3, f());
+assertEquals(3, f());
+%OptimizeFunctionOnNextCall(f);
+assertEquals(3, f());
+
+
+function g() {
+ var y = 2;
+ return (1 & z) | y++;
+}
+
+assertEquals(3, g());
+assertEquals(3, g());
+%OptimizeFunctionOnNextCall(g);
+assertEquals(3, g());
+
+
+function h() {
+ var y = 3;
+ return (3 & z) & y++;
+}
+
+assertEquals(3, h());
+assertEquals(3, h());
+%OptimizeFunctionOnNextCall(h);
+assertEquals(3, h());
+
+
+function i() {
+ var y = 2;
+ return (1 & z) ^ y++;
+}
+
+assertEquals(3, i());
+assertEquals(3, i());
+%OptimizeFunctionOnNextCall(i);
+assertEquals(3, i());
diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-500497.js b/deps/v8/test/mjsunit/regress/regress-crbug-500497.js
new file mode 100644
index 0000000000..9117440c2c
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-crbug-500497.js
@@ -0,0 +1,33 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// New space must be at max capacity to trigger pretenuring decision.
+// Flags: --allow-natives-syntax --verify-heap --max-semi-space-size=1
+
+var global = []; // Used to keep some objects alive.
+
+function Ctor() {
+ var result = {a: {}, b: {}, c: {}, d: {}, e: {}, f: {}, g: {}};
+ return result;
+}
+
+for (var i = 0; i < 120; i++) {
+ // Make the "a" property long-lived, while everything else is short-lived.
+ global.push(Ctor().a);
+ (function FillNewSpace() { new Array(10000); })();
+}
+
+// The bad situation is only triggered if Ctor wasn't optimized too early.
+assertUnoptimized(Ctor);
+// Optimized code for Ctor will pretenure the "a" property, so it will have
+// three allocations:
+// #1 Allocate the "result" object in new-space.
+// #2 Allocate the object stored in the "a" property in old-space.
+// #3 Allocate the objects for the "b" through "g" properties in new-space.
+%OptimizeFunctionOnNextCall(Ctor);
+for (var i = 0; i < 10000; i++) {
+ // At least one of these calls will run out of new space. The bug is
+ // triggered when it is allocation #3 that triggers GC.
+ Ctor();
+}
diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-502930.js b/deps/v8/test/mjsunit/regress/regress-crbug-502930.js
new file mode 100644
index 0000000000..ef21a1a69e
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-crbug-502930.js
@@ -0,0 +1,27 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+var accessor_to_data_case = (function() {
+ var v = {};
+ Object.defineProperty(v, "foo", { get: function() { return 42; }, configurable: true});
+
+ var obj = {};
+ obj["boom"] = v;
+
+ Object.defineProperty(v, "foo", { value: 0, writable: true, configurable: true });
+ return obj;
+})();
+
+
+var data_to_accessor_case = (function() {
+ var v = {};
+ Object.defineProperty(v, "bar", { value: 0, writable: true, configurable: true });
+
+ var obj = {};
+ obj["bam"] = v;
+
+ Object.defineProperty(v, "bar", { get: function() { return 42; }, configurable: true});
+ return obj;
+})();
diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-514268.js b/deps/v8/test/mjsunit/regress/regress-crbug-514268.js
new file mode 100644
index 0000000000..75d9970eed
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-crbug-514268.js
@@ -0,0 +1,23 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function bar(a) {
+ a.pop();
+}
+function foo(a) {
+ assertEquals(2, a.length);
+ var d;
+ for (d in a) {
+ bar(a);
+ }
+ // If this fails, bar was not called exactly once.
+ assertEquals(1, a.length);
+}
+
+foo([1,2]);
+foo([2,3]);
+%OptimizeFunctionOnNextCall(foo);
+foo([1,2]);