Showing with 840 additions and 284 deletions.
  1. +1 −14 deps/v8/src/api.cc
  2. +20 −25 deps/v8/src/arm/lithium-arm.cc
  3. +0 −2 deps/v8/src/arm/lithium-arm.h
  4. +12 −3 deps/v8/src/arm/lithium-codegen-arm.cc
  5. +1 −0 deps/v8/src/arm/lithium-codegen-arm.h
  6. +4 −1 deps/v8/src/arraybuffer.js
  7. +1 −1 deps/v8/src/code-stubs-hydrogen.cc
  8. +9 −2 deps/v8/src/code-stubs.h
  9. +2 −0 deps/v8/src/codegen.cc
  10. +9 −5 deps/v8/src/compiler.cc
  11. +5 −0 deps/v8/src/compiler.h
  12. +32 −5 deps/v8/src/deoptimizer.cc
  13. +4 −3 deps/v8/src/flag-definitions.h
  14. +3 −0 deps/v8/src/heap.cc
  15. +18 −5 deps/v8/src/hydrogen-instructions.cc
  16. +96 −34 deps/v8/src/hydrogen-instructions.h
  17. +3 −2 deps/v8/src/hydrogen-representation-changes.cc
  18. +177 −50 deps/v8/src/hydrogen.cc
  19. +72 −17 deps/v8/src/hydrogen.h
  20. +8 −3 deps/v8/src/ia32/lithium-codegen-ia32.cc
  21. +20 −25 deps/v8/src/ia32/lithium-ia32.cc
  22. +1 −5 deps/v8/src/ia32/lithium-ia32.h
  23. +2 −1 deps/v8/src/isolate.cc
  24. +10 −0 deps/v8/src/isolate.h
  25. +3 −5 deps/v8/src/lithium-codegen.cc
  26. +12 −2 deps/v8/src/mips/lithium-codegen-mips.cc
  27. +1 −0 deps/v8/src/mips/lithium-codegen-mips.h
  28. +20 −24 deps/v8/src/mips/lithium-mips.cc
  29. +1 −5 deps/v8/src/mips/lithium-mips.h
  30. +3 −1 deps/v8/src/objects.h
  31. +48 −2 deps/v8/src/runtime.cc
  32. +3 −0 deps/v8/src/runtime.h
  33. +3 −0 deps/v8/src/safepoint-table.h
  34. +1 −1 deps/v8/src/serialize.h
  35. +30 −8 deps/v8/src/typedarray.js
  36. +1 −1 deps/v8/src/version.cc
  37. +12 −3 deps/v8/src/x64/lithium-codegen-x64.cc
  38. +1 −0 deps/v8/src/x64/lithium-codegen-x64.h
  39. +20 −24 deps/v8/src/x64/lithium-x64.cc
  40. +1 −5 deps/v8/src/x64/lithium-x64.h
  41. +45 −0 deps/v8/test/cctest/test-api.cc
  42. +51 −0 deps/v8/test/mjsunit/regress/regress-352982.js
  43. +74 −0 deps/v8/test/mjsunit/regress/regress-353004.js
@@ -5805,20 +5805,7 @@ void v8::ArrayBuffer::Neuter() {
"Only externalized ArrayBuffers can be neutered");
LOG_API(obj->GetIsolate(), "v8::ArrayBuffer::Neuter()");
ENTER_V8(isolate);

for (i::Handle<i::Object> view_obj(obj->weak_first_view(), isolate);
!view_obj->IsUndefined();) {
i::Handle<i::JSArrayBufferView> view(i::JSArrayBufferView::cast(*view_obj));
if (view->IsJSTypedArray()) {
i::JSTypedArray::cast(*view)->Neuter();
} else if (view->IsJSDataView()) {
i::JSDataView::cast(*view)->Neuter();
} else {
UNREACHABLE();
}
view_obj = i::handle(view->weak_next(), isolate);
}
obj->Neuter();
i::Runtime::NeuterArrayBuffer(obj);
}


@@ -614,15 +614,6 @@ LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
instr->MarkAsCall();
instr = AssignPointerMap(instr);

if (hinstr->HasObservableSideEffects()) {
ASSERT(hinstr->next()->IsSimulate());
HSimulate* sim = HSimulate::cast(hinstr->next());
ASSERT(instruction_pending_deoptimization_environment_ == NULL);
ASSERT(pending_deoptimization_ast_id_.IsNone());
instruction_pending_deoptimization_environment_ = instr;
pending_deoptimization_ast_id_ = sim->ast_id();
}

// If instruction does not have side-effects lazy deoptimization
// after the call will try to deoptimize to the point before the call.
// Thus we still need to attach environment to this call even if
@@ -840,7 +831,6 @@ void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
void LChunkBuilder::VisitInstruction(HInstruction* current) {
HInstruction* old_current = current_instruction_;
current_instruction_ = current;
if (current->has_position()) position_ = current->position();

LInstruction* instr = NULL;
if (current->CanReplaceWithDummyUses()) {
@@ -906,6 +896,26 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
instr = AssignEnvironment(instr);
}
chunk_->AddInstruction(instr, current_block_);

if (instr->IsCall()) {
HValue* hydrogen_value_for_lazy_bailout = current;
LInstruction* instruction_needing_environment = NULL;
if (current->HasObservableSideEffects()) {
HSimulate* sim = HSimulate::cast(current->next());
instruction_needing_environment = instr;
sim->ReplayEnvironment(current_block_->last_environment());
hydrogen_value_for_lazy_bailout = sim;
}
LInstruction* bailout = AssignEnvironment(new(zone()) LLazyBailout());
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
chunk_->AddInstruction(bailout, current_block_);
if (instruction_needing_environment != NULL) {
// Store the lazy deopt environment with the instruction if needed.
// Right now it is only used for LInstanceOfKnownGlobal.
instruction_needing_environment->
SetDeferredLazyDeoptimizationEnvironment(bailout->environment());
}
}
}
current_instruction_ = old_current;
}
@@ -2378,21 +2388,6 @@ LInstruction* LChunkBuilder::DoIsConstructCallAndBranch(

LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
instr->ReplayEnvironment(current_block_->last_environment());

// If there is an instruction pending deoptimization environment create a
// lazy bailout instruction to capture the environment.
if (pending_deoptimization_ast_id_ == instr->ast_id()) {
LInstruction* result = new(zone()) LLazyBailout;
result = AssignEnvironment(result);
// Store the lazy deopt environment with the instruction if needed. Right
// now it is only used for LInstanceOfKnownGlobal.
instruction_pending_deoptimization_environment_->
SetDeferredLazyDeoptimizationEnvironment(result->environment());
instruction_pending_deoptimization_environment_ = NULL;
pending_deoptimization_ast_id_ = BailoutId::None();
return result;
}

return NULL;
}

@@ -2580,7 +2580,6 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
current_block_(NULL),
next_block_(NULL),
allocator_(allocator),
position_(RelocInfo::kNoPosition),
instruction_pending_deoptimization_environment_(NULL),
pending_deoptimization_ast_id_(BailoutId::None()) { }

@@ -2717,7 +2716,6 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
HBasicBlock* current_block_;
HBasicBlock* next_block_;
LAllocator* allocator_;
int position_;
LInstruction* instruction_pending_deoptimization_environment_;
BailoutId pending_deoptimization_ast_id_;

@@ -269,6 +269,13 @@ void LCodeGen::GenerateOsrPrologue() {
}


void LCodeGen::GenerateBodyInstructionPre(LInstruction* instr) {
if (!instr->IsLazyBailout() && !instr->IsGap()) {
safepoints_.BumpLastLazySafepointIndex();
}
}


bool LCodeGen::GenerateDeferredCode() {
ASSERT(is_generating());
if (deferred_.length() > 0) {
@@ -277,7 +284,8 @@ bool LCodeGen::GenerateDeferredCode() {

HValue* value =
instructions_->at(code->instruction_index())->hydrogen_value();
RecordAndWritePosition(value->position());
RecordAndWritePosition(
chunk()->graph()->SourcePositionToScriptPosition(value->position()));

Comment(";;; <@%d,#%d> "
"-------------------- Deferred %s --------------------",
@@ -906,6 +914,7 @@ void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
translations_.CreateByteArray(isolate()->factory());
data->SetTranslationByteArray(*translations);
data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
data->SetOptimizationId(Smi::FromInt(info_->optimization_id()));

Handle<FixedArray> literals =
factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
@@ -2112,7 +2121,6 @@ void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
// is in the correct position.
Assembler::BlockConstPoolScope block_const_pool(masm());
CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
__ nop(); // Signals no inlined code.
}


@@ -4402,7 +4410,8 @@ void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
this, Safepoint::kWithRegistersAndDoubles);
__ Move(r0, object_reg);
__ Move(r1, to_map);
TransitionElementsKindStub stub(from_kind, to_kind);
bool is_js_array = from_map->instance_type() == JS_ARRAY_TYPE;
TransitionElementsKindStub stub(from_kind, to_kind, is_js_array);
__ CallStub(&stub);
RecordSafepointWithRegistersAndDoubles(
instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
@@ -191,6 +191,7 @@ class LCodeGen: public LCodeGenBase {

// Code generation passes. Returns true if code generation should
// continue.
void GenerateBodyInstructionPre(LInstruction* instr) V8_OVERRIDE;
bool GeneratePrologue();
bool GenerateDeferredCode();
bool GenerateDeoptJumpTable();
@@ -56,14 +56,17 @@ function ArrayBufferSlice(start, end) {
}

var relativeStart = TO_INTEGER(start);
if (!IS_UNDEFINED(end)) {
end = TO_INTEGER(end);
}
var first;
var byte_length = %ArrayBufferGetByteLength(this);
if (relativeStart < 0) {
first = MathMax(byte_length + relativeStart, 0);
} else {
first = MathMin(relativeStart, byte_length);
}
var relativeEnd = IS_UNDEFINED(end) ? byte_length : TO_INTEGER(end);
var relativeEnd = IS_UNDEFINED(end) ? byte_length : end;
var fin;
if (relativeEnd < 0) {
fin = MathMax(byte_length + relativeEnd, 0);
@@ -618,7 +618,7 @@ HValue* CodeStubGraphBuilder<TransitionElementsKindStub>::BuildCodeStub() {
GetParameter(1),
casted_stub()->from_kind(),
casted_stub()->to_kind(),
true);
casted_stub()->is_js_array());

return GetParameter(0);
}
@@ -2009,9 +2009,11 @@ class KeyedStoreFastElementStub : public HydrogenCodeStub {
class TransitionElementsKindStub : public HydrogenCodeStub {
public:
TransitionElementsKindStub(ElementsKind from_kind,
ElementsKind to_kind) {
ElementsKind to_kind,
bool is_js_array) {
bit_field_ = FromKindBits::encode(from_kind) |
ToKindBits::encode(to_kind);
ToKindBits::encode(to_kind) |
IsJSArrayBits::encode(is_js_array);
}

ElementsKind from_kind() const {
@@ -2022,6 +2024,10 @@ class TransitionElementsKindStub : public HydrogenCodeStub {
return ToKindBits::decode(bit_field_);
}

bool is_js_array() const {
return IsJSArrayBits::decode(bit_field_);
}

virtual Handle<Code> GenerateCode(Isolate* isolate);

virtual void InitializeInterfaceDescriptor(
@@ -2031,6 +2037,7 @@ class TransitionElementsKindStub : public HydrogenCodeStub {
private:
class FromKindBits: public BitField<ElementsKind, 8, 8> {};
class ToKindBits: public BitField<ElementsKind, 0, 8> {};
class IsJSArrayBits: public BitField<bool, 16, 1> {};
uint32_t bit_field_;

Major MajorKey() { return TransitionElementsKind; }
@@ -165,6 +165,8 @@ void CodeGenerator::PrintCode(Handle<Code> code, CompilationInfo* info) {
function->debug_name()->ToCString().get(), tracing_scope.file());
}
PrintF(tracing_scope.file(), "--- Optimized code ---\n");
PrintF(tracing_scope.file(),
"optimization_id = %d\n", info->optimization_id());
} else {
PrintF(tracing_scope.file(), "--- Code ---\n");
}
@@ -60,7 +60,8 @@ CompilationInfo::CompilationInfo(Handle<Script> script,
script_(script),
osr_ast_id_(BailoutId::None()),
parameter_count_(0),
this_has_uses_(true) {
this_has_uses_(true),
optimization_id_(-1) {
Initialize(script->GetIsolate(), BASE, zone);
}

@@ -72,7 +73,8 @@ CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info,
script_(Handle<Script>(Script::cast(shared_info->script()))),
osr_ast_id_(BailoutId::None()),
parameter_count_(0),
this_has_uses_(true) {
this_has_uses_(true),
optimization_id_(-1) {
Initialize(script_->GetIsolate(), BASE, zone);
}

@@ -86,7 +88,8 @@ CompilationInfo::CompilationInfo(Handle<JSFunction> closure,
context_(closure->context()),
osr_ast_id_(BailoutId::None()),
parameter_count_(0),
this_has_uses_(true) {
this_has_uses_(true),
optimization_id_(-1) {
Initialize(script_->GetIsolate(), BASE, zone);
}

@@ -98,7 +101,8 @@ CompilationInfo::CompilationInfo(HydrogenCodeStub* stub,
IsLazy::encode(true)),
osr_ast_id_(BailoutId::None()),
parameter_count_(0),
this_has_uses_(true) {
this_has_uses_(true),
optimization_id_(-1) {
Initialize(isolate, STUB, zone);
code_stub_ = stub;
}
@@ -398,7 +402,7 @@ OptimizedCompileJob::Status OptimizedCompileJob::CreateGraph() {
// Type-check the function.
AstTyper::Run(info());

graph_builder_ = FLAG_emit_opt_code_positions
graph_builder_ = FLAG_hydrogen_track_positions
? new(info()->zone()) HOptimizedGraphBuilderWithPositions(info())
: new(info()->zone()) HOptimizedGraphBuilder(info());

@@ -229,6 +229,7 @@ class CompilationInfo {
SetMode(OPTIMIZE);
osr_ast_id_ = osr_ast_id;
unoptimized_code_ = unoptimized;
optimization_id_ = isolate()->NextOptimizationId();
}
void DisableOptimization();

@@ -317,6 +318,8 @@ class CompilationInfo {
return osr_ast_id_ == osr_ast_id && function.is_identical_to(closure_);
}

int optimization_id() const { return optimization_id_; }

protected:
CompilationInfo(Handle<Script> script,
Zone* zone);
@@ -452,6 +455,8 @@ class CompilationInfo {

Handle<Foreign> object_wrapper_;

int optimization_id_;

DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
};

@@ -393,9 +393,33 @@ void Deoptimizer::DeoptimizeMarkedCodeForContext(Context* context) {
element = next;
}

#ifdef DEBUG
// Make sure all activations of optimized code can deopt at their current PC.
for (StackFrameIterator it(isolate, isolate->thread_local_top());
!it.done(); it.Advance()) {
StackFrame::Type type = it.frame()->type();
if (type == StackFrame::OPTIMIZED) {
Code* code = it.frame()->LookupCode();
if (FLAG_trace_deopt) {
JSFunction* function =
static_cast<OptimizedFrame*>(it.frame())->function();
CodeTracer::Scope scope(isolate->GetCodeTracer());
PrintF(scope.file(), "[deoptimizer patches for lazy deopt: ");
function->PrintName(scope.file());
PrintF(scope.file(),
" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
}
SafepointEntry safepoint = code->GetSafepointEntry(it.frame()->pc());
int deopt_index = safepoint.deoptimization_index();
CHECK(deopt_index != Safepoint::kNoDeoptimizationIndex);
}
}
#endif

// TODO(titzer): we need a handle scope only because of the macro assembler,
// which is only used in EnsureCodeForDeoptimizationEntry.
HandleScope scope(isolate);

// Now patch all the codes for deoptimization.
for (int i = 0; i < codes.length(); i++) {
// It is finally time to die, code object.
@@ -731,6 +755,12 @@ void Deoptimizer::DoComputeOutputFrames() {
LOG(isolate(), CodeDeoptEvent(compiled_code_));
}
ElapsedTimer timer;

// Determine basic deoptimization information. The optimized frame is
// described by the input data.
DeoptimizationInputData* input_data =
DeoptimizationInputData::cast(compiled_code_->deoptimization_data());

if (trace_scope_ != NULL) {
timer.Start();
PrintF(trace_scope_->file(),
@@ -739,18 +769,15 @@ void Deoptimizer::DoComputeOutputFrames() {
reinterpret_cast<intptr_t>(function_));
PrintFunctionName();
PrintF(trace_scope_->file(),
" @%d, FP to SP delta: %d]\n",
" (opt #%d) @%d, FP to SP delta: %d]\n",
input_data->OptimizationId()->value(),
bailout_id_,
fp_to_sp_delta_);
if (bailout_type_ == EAGER || bailout_type_ == SOFT) {
compiled_code_->PrintDeoptLocation(trace_scope_->file(), bailout_id_);
}
}

// Determine basic deoptimization information. The optimized frame is
// described by the input data.
DeoptimizationInputData* input_data =
DeoptimizationInputData::cast(compiled_code_->deoptimization_data());
BailoutId node_id = input_data->AstId(bailout_id_);
ByteArray* translations = input_data->TranslationByteArray();
unsigned translation_index =