| Index: src/liveedit.cc
|
| diff --git a/src/liveedit.cc b/src/liveedit.cc
|
| index dc7d4b157d01ec1a9b405e36d8ed5373ac87a091..574a37691c0a0e99e0e46617455d734ff7e50d2c 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.
|
| + ClearValuesVisitor visitor;
|
| + IterateJSFunctions(*shared_info, &visitor);
|
| + } 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 Visitor>
|
| + static void IterateJSFunctions(SharedFunctionInfo* shared_info,
|
| + Visitor* visitor) {
|
| + 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) {
|
| + visitor->visit(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) {
|
| + CountVisitor count_visitor;
|
| + count_visitor.count = 0;
|
| + IterateJSFunctions(*shared_info, &count_visitor);
|
| + int size = count_visitor.count;
|
| +
|
| + Handle<FixedArray> result = isolate->factory()->NewFixedArray(size);
|
| + if (size > 0) {
|
| + CollectVisitor collect_visitor(result);
|
| + IterateJSFunctions(*shared_info, &collect_visitor);
|
| + }
|
| + return result;
|
| + }
|
| +
|
| + class ClearValuesVisitor {
|
| + public:
|
| + void visit(JSFunction* fun) {
|
| + FixedArray* literals = fun->literals();
|
| + int len = literals->length();
|
| + for (int j = JSFunction::kLiteralsPrefixSize; j < len; j++) {
|
| + literals->set_undefined(j);
|
| + }
|
| + }
|
| + };
|
| +
|
| + class CountVisitor {
|
| + public:
|
| + void visit(JSFunction* fun) {
|
| + count++;
|
| + }
|
| + int count;
|
| + };
|
| +
|
| + class CollectVisitor {
|
| + public:
|
| + explicit CollectVisitor(Handle<FixedArray> output)
|
| + : m_output(output), m_pos(0) {}
|
| +
|
| + void visit(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));
|
|
|