Chromium Code Reviews| Index: src/liveedit.cc |
| diff --git a/src/liveedit.cc b/src/liveedit.cc |
| index dc7d4b157d01ec1a9b405e36d8ed5373ac87a091..cb771c60a4808642177de2b6342227a63be771fa 100644 |
| --- a/src/liveedit.cc |
| +++ b/src/liveedit.cc |
| @@ -703,12 +703,14 @@ class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> { |
| : JSArrayBasedStruct<FunctionInfoWrapper>(array) { |
| } |
| void SetInitialProperties(Handle<String> name, int start_position, |
| - int end_position, int param_num, int parent_index) { |
| + int end_position, int param_num, |
| + int literal_count, int parent_index) { |
| HandleScope scope; |
| this->SetField(kFunctionNameOffset_, name); |
| this->SetSmiValueField(kStartPositionOffset_, start_position); |
| this->SetSmiValueField(kEndPositionOffset_, end_position); |
| this->SetSmiValueField(kParamNumOffset_, param_num); |
| + this->SetSmiValueField(kLiteralNumOffset_, literal_count); |
| this->SetSmiValueField(kParentIndexOffset_, parent_index); |
| } |
| void SetFunctionCode(Handle<Code> function_code, |
| @@ -726,6 +728,9 @@ class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> { |
| Handle<JSValue> info_holder = WrapInJSValue(info); |
| this->SetField(kSharedFunctionInfoOffset_, info_holder); |
| } |
| + int GetLiteralCount() { |
| + return this->GetSmiValueField(kLiteralNumOffset_); |
| + } |
| int GetParentIndex() { |
| return this->GetSmiValueField(kParentIndexOffset_); |
| } |
| @@ -759,7 +764,8 @@ class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> { |
| static const int kOuterScopeInfoOffset_ = 6; |
| static const int kParentIndexOffset_ = 7; |
| static const int kSharedFunctionInfoOffset_ = 8; |
| - static const int kSize_ = 9; |
| + static const int kLiteralNumOffset_ = 9; |
| + static const int kSize_ = 10; |
| friend class JSArrayBasedStruct<FunctionInfoWrapper>; |
| }; |
| @@ -819,6 +825,7 @@ class FunctionInfoListener { |
| FunctionInfoWrapper info = FunctionInfoWrapper::Create(); |
| info.SetInitialProperties(fun->name(), fun->start_position(), |
| fun->end_position(), fun->parameter_count(), |
| + fun->materialized_literal_count(), |
| current_parent_index_); |
| current_parent_index_ = len_; |
| SetElementNonStrict(result_, len_, info.GetJSArray()); |
| @@ -1014,6 +1021,129 @@ static void ReplaceCodeObject(Handle<Code> original, |
| } |
| +// Patch function literals. |
| +// Name 'literals' is a misnomer. Rather it's a cache for complex object |
| +// boilerplates and for a native context. We must clean cached values. |
| +// Additionally we may need to allocate a new array if number of literals |
| +// changed. |
| +class LiteralFixer { |
| + public: |
| + |
| + static void PatchLiterals(FunctionInfoWrapper* compile_info_wrapper, |
| + Handle<SharedFunctionInfo> shared_info, |
| + Isolate* isolate) { |
| + int new_literal_count = compile_info_wrapper->GetLiteralCount(); |
| + if (new_literal_count > 0) { |
| + new_literal_count += JSFunction::kLiteralsPrefixSize; |
| + } |
| + int old_literal_count = shared_info->num_literals(); |
| + |
| + if (old_literal_count == new_literal_count) { |
| + // If literal count didn't change, simply go over all functions |
| + // and clear literal arrays. |
| + ClearValuesProcessor processor; |
| + IterateJSFunctions(*shared_info, &processor); |
|
Yang
2012/11/12 14:40:57
We usually call this kind of callback *Visitor, as
|
| + } else { |
| + // When literal count changes, we have to create new array instances. |
| + // Since we cannot create instances when iterating heap, we should first |
| + // collect all functions and fix their literal arrays. |
| + Handle<FixedArray> function_instances = |
| + CollectJSFunctions(shared_info, isolate); |
| + for (int i = 0; i < function_instances->length(); i++) { |
| + Handle<JSFunction> fun(JSFunction::cast(function_instances->get(i))); |
| + Handle<FixedArray> old_literals(fun->literals()); |
| + Handle<FixedArray> new_literals = |
| + isolate->factory()->NewFixedArray(new_literal_count); |
| + if (new_literal_count > 0) { |
| + Handle<Context> native_context; |
| + if (old_literals->length() > |
| + JSFunction::kLiteralNativeContextIndex) { |
| + native_context = Handle<Context>( |
| + JSFunction::NativeContextFromLiterals(fun->literals())); |
| + } else { |
| + native_context = Handle<Context>(fun->context()->native_context()); |
| + } |
| + new_literals->set(JSFunction::kLiteralNativeContextIndex, |
| + *native_context); |
| + } |
| + fun->set_literals(*new_literals); |
| + } |
| + |
| + shared_info->set_num_literals(new_literal_count); |
| + } |
| + } |
| + |
| + private: |
| + // Iterates all function instances in the HEAP that refers to the |
| + // provided shared_info. |
| + template<typename PROCESSOR> |
|
Yang
2012/11/12 14:40:57
I think we usually use lowercase for typename. Als
|
| + static void IterateJSFunctions(SharedFunctionInfo* shared_info, |
| + PROCESSOR* processor) { |
| + AssertNoAllocation no_allocations_please; |
| + |
| + HeapIterator iterator; |
| + for (HeapObject* obj = iterator.next(); obj != NULL; |
| + obj = iterator.next()) { |
| + if (obj->IsJSFunction()) { |
| + JSFunction* function = JSFunction::cast(obj); |
| + if (function->shared() == shared_info) { |
| + processor->process(function); |
| + } |
| + } |
| + } |
| + } |
| + |
| + // Finds all instances of JSFunction that refers to the provided shared_info |
| + // and returns array with them. |
| + static Handle<FixedArray> CollectJSFunctions( |
| + Handle<SharedFunctionInfo> shared_info, Isolate* isolate) { |
| + CountProcessor count_processor; |
| + count_processor.count = 0; |
| + IterateJSFunctions(*shared_info, &count_processor); |
| + int size = count_processor.count; |
| + |
| + Handle<FixedArray> result = isolate->factory()->NewFixedArray(size); |
| + if (size > 0) { |
| + CollectProcessor collect_processor(result); |
| + IterateJSFunctions(*shared_info, &collect_processor); |
| + } |
| + return result; |
| + } |
| + |
| + class ClearValuesProcessor { |
| + public: |
| + void process(JSFunction* fun) { |
| + FixedArray* literals = fun->literals(); |
| + int len = literals->length(); |
| + for (int j = JSFunction::kLiteralsPrefixSize; j < len; j++) { |
| + literals->set_undefined(j); |
| + } |
| + } |
| + }; |
| + |
| + class CountProcessor { |
| + public: |
| + void process(JSFunction* fun) { |
| + count++; |
| + } |
| + int count; |
| + }; |
| + |
| + class CollectProcessor { |
| + public: |
| + CollectProcessor(Handle<FixedArray> output) : m_output(output), m_pos(0) {} |
| + |
| + void process(JSFunction* fun) { |
| + m_output->set(m_pos, fun); |
| + m_pos++; |
| + } |
| + private: |
| + Handle<FixedArray> m_output; |
| + int m_pos; |
| + }; |
| +}; |
| + |
| + |
| // Check whether the code is natural function code (not a lazy-compile stub |
| // code). |
| static bool IsJSFunctionCode(Code* code) { |
| @@ -1080,9 +1210,10 @@ MaybeObject* LiveEdit::ReplaceFunctionCode( |
| Handle<JSArray> new_compile_info_array, |
| Handle<JSArray> shared_info_array) { |
| HandleScope scope; |
| + Isolate* isolate = Isolate::Current(); |
| if (!SharedInfoWrapper::IsInstance(shared_info_array)) { |
| - return Isolate::Current()->ThrowIllegalOperation(); |
| + return isolate->ThrowIllegalOperation(); |
| } |
| FunctionInfoWrapper compile_info_wrapper(new_compile_info_array); |
| @@ -1113,6 +1244,8 @@ MaybeObject* LiveEdit::ReplaceFunctionCode( |
| shared_info->set_start_position(start_position); |
| shared_info->set_end_position(end_position); |
| + LiteralFixer::PatchLiterals(&compile_info_wrapper, shared_info, isolate); |
| + |
| shared_info->set_construct_stub( |
| Isolate::Current()->builtins()->builtin( |
| Builtins::kJSConstructStubGeneric)); |