diff --git a/src/bailout-reason.h b/src/bailout-reason.h index 91421bbd9c..490d7b2a3d 100644 --- a/src/bailout-reason.h +++ b/src/bailout-reason.h @@ -110,6 +110,7 @@ namespace internal { V(kInvalidLhsInCompoundAssignment, "Invalid lhs in compound assignment") \ V(kInvalidLhsInCountOperation, "Invalid lhs in count operation") \ V(kInvalidMinLength, "Invalid min_length") \ + V(kInvalidRegisterFileInGenerator, "invalid register file in generator") \ V(kJSGlobalObjectNativeContextShouldBeANativeContext, \ "JSGlobalObject::native_context should be a native context") \ V(kJSGlobalProxyContextShouldNotBeNull, \ diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc index 5fa440ca6d..fe00ddfa8e 100644 --- a/src/code-stub-assembler.cc +++ b/src/code-stub-assembler.cc @@ -46,6 +46,10 @@ Node* CodeStubAssembler::UndefinedConstant() { return LoadRoot(Heap::kUndefinedValueRootIndex); } +Node* CodeStubAssembler::StaleRegisterConstant() { + return LoadRoot(Heap::kStaleRegisterRootIndex); +} + Node* CodeStubAssembler::Float64Round(Node* x) { Node* one = Float64Constant(1.0); Node* one_half = Float64Constant(0.5); diff --git a/src/code-stub-assembler.h b/src/code-stub-assembler.h index baad983870..af416b0fb9 100644 --- a/src/code-stub-assembler.h +++ b/src/code-stub-assembler.h @@ -38,6 +38,7 @@ class CodeStubAssembler : public compiler::CodeAssembler { compiler::Node* NoContextConstant(); compiler::Node* NullConstant(); compiler::Node* UndefinedConstant(); + compiler::Node* StaleRegisterConstant(); // Float64 operations. compiler::Node* Float64Ceil(compiler::Node* x); diff --git a/src/heap/heap.cc b/src/heap/heap.cc index d95da5e022..2f0fc1b2fa 100644 --- a/src/heap/heap.cc +++ b/src/heap/heap.cc @@ -2290,6 +2290,7 @@ bool Heap::CreateInitialMaps() { ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, exception); ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, termination_exception); ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, optimized_out); + ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, stale_register); for (unsigned i = 0; i < arraysize(string_type_table); i++) { const StringTypeTable& entry = string_type_table[i]; @@ -2664,6 +2665,11 @@ void Heap::CreateInitialObjects() { handle(Smi::FromInt(-6), isolate()), false, "undefined", Oddball::kOptimizedOut)); + set_stale_register( + *factory->NewOddball(factory->stale_register_map(), "stale_register", + handle(Smi::FromInt(-7), isolate()), false, + "undefined", Oddball::kStaleRegister)); + for (unsigned i = 0; i < arraysize(constant_string_table); i++) { Handle str = factory->InternalizeUtf8String(constant_string_table[i].contents); diff --git a/src/heap/heap.h b/src/heap/heap.h index 75267d4255..5599f1b4ff 100644 --- a/src/heap/heap.h +++ b/src/heap/heap.h @@ -78,6 +78,7 @@ using v8::MemoryPressureLevel; V(Oddball, exception, Exception) \ V(Oddball, termination_exception, TerminationException) \ V(Oddball, optimized_out, OptimizedOut) \ + V(Oddball, stale_register, StaleRegister) \ V(FixedArray, number_string_cache, NumberStringCache) \ V(Object, instanceof_cache_function, InstanceofCacheFunction) \ V(Object, instanceof_cache_map, InstanceofCacheMap) \ @@ -152,6 +153,7 @@ using v8::MemoryPressureLevel; V(Map, exception_map, ExceptionMap) \ V(Map, termination_exception_map, TerminationExceptionMap) \ V(Map, optimized_out_map, OptimizedOutMap) \ + V(Map, stale_register_map, StaleRegisterMap) \ V(Map, message_object_map, JSMessageObjectMap) \ V(Map, foreign_map, ForeignMap) \ V(Map, neander_map, NeanderMap) \ diff --git a/src/interpreter/interpreter-assembler.cc b/src/interpreter/interpreter-assembler.cc index 9415a22c91..db9b0cb3c0 100644 --- a/src/interpreter/interpreter-assembler.cc +++ b/src/interpreter/interpreter-assembler.cc @@ -715,10 +715,12 @@ Node* InterpreterAssembler::RegisterCount() { return Word32Sar(frame_size, Int32Constant(kPointerSizeLog2)); } -Node* InterpreterAssembler::ExportRegisterFile() { - Node* register_count = RegisterCount(); - Node* array = - AllocateUninitializedFixedArray(ChangeInt32ToIntPtr(register_count)); +Node* InterpreterAssembler::ExportRegisterFile(Node* array) { + if (FLAG_debug_code) { + Node* array_size = SmiUntag(LoadFixedArrayBaseLength(array)); + AbortIfWordNotEqual( + array_size, RegisterCount(), kInvalidRegisterFileInGenerator); + } Variable var_index(this, MachineRepresentation::kWord32); var_index.Bind(Int32Constant(0)); @@ -729,16 +731,14 @@ Node* InterpreterAssembler::ExportRegisterFile() { Bind(&loop); { Node* index = var_index.value(); - Node* condition = Int32LessThan(index, register_count); + Node* condition = Int32LessThan(index, RegisterCount()); GotoUnless(condition, &done_loop); Node* reg_index = Int32Sub(Int32Constant(Register(0).ToOperand()), index); Node* value = LoadRegister(ChangeInt32ToIntPtr(reg_index)); - // No write barrier needed for writing into freshly allocated object. - StoreFixedArrayElementNoWriteBarrier( - array, ChangeInt32ToIntPtr(index), value); + StoreFixedArrayElementInt32Index(array, index, value); var_index.Bind(Int32Add(index, Int32Constant(1))); Goto(&loop); @@ -749,18 +749,23 @@ Node* InterpreterAssembler::ExportRegisterFile() { } Node* InterpreterAssembler::ImportRegisterFile(Node* array) { - Node* register_count = RegisterCount(); + if (FLAG_debug_code) { + Node* array_size = SmiUntag(LoadFixedArrayBaseLength(array)); + AbortIfWordNotEqual( + array_size, RegisterCount(), kInvalidRegisterFileInGenerator); + } Variable var_index(this, MachineRepresentation::kWord32); var_index.Bind(Int32Constant(0)); - // Iterate over array and write values into register file. + // Iterate over array and write values into register file. Also erase the + // array contents to not keep them alive artificially. Label loop(this, &var_index), done_loop(this); Goto(&loop); Bind(&loop); { Node* index = var_index.value(); - Node* condition = Int32LessThan(index, register_count); + Node* condition = Int32LessThan(index, RegisterCount()); GotoUnless(condition, &done_loop); Node* value = LoadFixedArrayElementInt32Index(array, index); @@ -769,6 +774,8 @@ Node* InterpreterAssembler::ImportRegisterFile(Node* array) { Int32Sub(Int32Constant(Register(0).ToOperand()), index); StoreRegister(value, ChangeInt32ToIntPtr(reg_index)); + StoreFixedArrayElementInt32Index(array, index, StaleRegisterConstant()); + var_index.Bind(Int32Add(index, Int32Constant(1))); Goto(&loop); } diff --git a/src/interpreter/interpreter-assembler.h b/src/interpreter/interpreter-assembler.h index eccba20e96..147ba50287 100644 --- a/src/interpreter/interpreter-assembler.h +++ b/src/interpreter/interpreter-assembler.h @@ -53,8 +53,8 @@ class InterpreterAssembler : public CodeStubAssembler { // Number of registers. compiler::Node* RegisterCount(); - // Backup/restore register file to/from a fixed array. - compiler::Node* ExportRegisterFile(); + // Backup/restore register file to/from a fixed array of the correct length. + compiler::Node* ExportRegisterFile(compiler::Node* array); compiler::Node* ImportRegisterFile(compiler::Node* array); // Loads from and stores to the interpreter register file. diff --git a/src/interpreter/interpreter.cc b/src/interpreter/interpreter.cc index 25924d3117..99001d055c 100644 --- a/src/interpreter/interpreter.cc +++ b/src/interpreter/interpreter.cc @@ -1736,11 +1736,12 @@ void Interpreter::DoSuspendGenerator(InterpreterAssembler* assembler) { Node* generator_reg = __ BytecodeOperandReg(0); Node* generator = __ LoadRegister(generator_reg); - Node* array = __ ExportRegisterFile(); + Node* array = + __ LoadObjectField(generator, JSGeneratorObject::kOperandStackOffset); Node* context = __ GetContext(); Node* state = __ GetAccumulator(); - __ StoreObjectField(generator, JSGeneratorObject::kOperandStackOffset, array); + __ ExportRegisterFile(array); __ StoreObjectField(generator, JSGeneratorObject::kContextOffset, context); __ StoreObjectField(generator, JSGeneratorObject::kContinuationOffset, state); @@ -1758,8 +1759,6 @@ void Interpreter::DoResumeGenerator(InterpreterAssembler* assembler) { __ ImportRegisterFile( __ LoadObjectField(generator, JSGeneratorObject::kOperandStackOffset)); - __ StoreObjectField(generator, JSGeneratorObject::kOperandStackOffset, - __ HeapConstant(isolate_->factory()->empty_fixed_array())); Node* old_state = __ LoadObjectField(generator, JSGeneratorObject::kContinuationOffset); diff --git a/src/objects-debug.cc b/src/objects-debug.cc index cd939cb33d..d9b41e96a5 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -609,7 +609,7 @@ void Oddball::OddballVerify() { CHECK(number->IsSmi()); int value = Smi::cast(number)->value(); // Hidden oddballs have negative smis. - const int kLeastHiddenOddballNumber = -6; + const int kLeastHiddenOddballNumber = -7; CHECK_LE(value, 1); CHECK(value >= kLeastHiddenOddballNumber); } @@ -634,6 +634,8 @@ void Oddball::OddballVerify() { CHECK(this == heap->exception()); } else if (map() == heap->optimized_out_map()) { CHECK(this == heap->optimized_out()); + } else if (map() == heap->stale_register_map()) { + CHECK(this == heap->stale_register()); } else { UNREACHABLE(); } diff --git a/src/objects.h b/src/objects.h index b07f3a3ad4..b144c9cf81 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1009,7 +1009,8 @@ template inline bool Is(Object* obj); V(True) \ V(False) \ V(ArgumentsMarker) \ - V(OptimizedOut) + V(OptimizedOut) \ + V(StaleRegister) // The element types selection for CreateListFromArrayLike. enum class ElementTypes { kAll, kStringAndSymbol }; @@ -9493,6 +9494,7 @@ class Oddball: public HeapObject { static const byte kOther = 7; static const byte kException = 8; static const byte kOptimizedOut = 9; + static const byte kStaleRegister = 10; typedef FixedBodyDescriptor BodyDescriptor; diff --git a/src/runtime/runtime-generator.cc b/src/runtime/runtime-generator.cc index 602b2c66cc..71d7059bf8 100644 --- a/src/runtime/runtime-generator.cc +++ b/src/runtime/runtime-generator.cc @@ -19,12 +19,21 @@ RUNTIME_FUNCTION(Runtime_CreateJSGeneratorObject) { CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 1); RUNTIME_ASSERT(function->shared()->is_generator()); + Handle operand_stack; + if (FLAG_ignition && FLAG_ignition_generators) { + int size = function->shared()->bytecode_array()->register_count(); + operand_stack = isolate->factory()->NewFixedArray(size); + } else { + DCHECK(!function->shared()->HasBytecodeArray()); + operand_stack = handle(isolate->heap()->empty_fixed_array()); + } + Handle generator = isolate->factory()->NewJSGeneratorObject(function); generator->set_function(*function); generator->set_context(isolate->context()); generator->set_receiver(*receiver); - generator->set_operand_stack(isolate->heap()->empty_fixed_array()); + generator->set_operand_stack(*operand_stack); generator->set_continuation(JSGeneratorObject::kGeneratorExecuting); return *generator; }