1// Copyright 2010 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#ifndef V8_LIVEEDIT_H_
29#define V8_LIVEEDIT_H_
30
31
32
33// Live Edit feature implementation.
34// User should be able to change script on already running VM. This feature
35// matches hot swap features in other frameworks.
36//
37// The basic use-case is when user spots some mistake in function body
38// from debugger and wishes to change the algorithm without restart.
39//
40// A single change always has a form of a simple replacement (in pseudo-code):
41//   script.source[positions, positions+length] = new_string;
42// Implementation first determines, which function's body includes this
43// change area. Then both old and new versions of script are fully compiled
44// in order to analyze, whether the function changed its outer scope
45// expectations (or number of parameters). If it didn't, function's code is
46// patched with a newly compiled code. If it did change, enclosing function
47// gets patched. All inner functions are left untouched, whatever happened
48// to them in a new script version. However, new version of code will
49// instantiate newly compiled functions.
50
51
52#include "allocation.h"
53#include "compiler.h"
54
55namespace v8 {
56namespace internal {
57
58// This class collects some specific information on structure of functions
59// in a particular script. It gets called from compiler all the time, but
60// actually records any data only when liveedit operation is in process;
61// in any other time this class is very cheap.
62//
63// The primary interest of the Tracker is to record function scope structures
64// in order to analyze whether function code maybe safely patched (with new
65// code successfully reading existing data from function scopes). The Tracker
66// also collects compiled function codes.
67class LiveEditFunctionTracker {
68 public:
69  explicit LiveEditFunctionTracker(Isolate* isolate, FunctionLiteral* fun);
70  ~LiveEditFunctionTracker();
71  void RecordFunctionInfo(Handle<SharedFunctionInfo> info,
72                          FunctionLiteral* lit);
73  void RecordRootFunctionInfo(Handle<Code> code);
74
75  static bool IsActive(Isolate* isolate);
76
77 private:
78#ifdef ENABLE_DEBUGGER_SUPPORT
79  Isolate* isolate_;
80#endif
81};
82
83#ifdef ENABLE_DEBUGGER_SUPPORT
84
85class LiveEdit : AllStatic {
86 public:
87  static JSArray* GatherCompileInfo(Handle<Script> script,
88                                    Handle<String> source);
89
90  static void WrapSharedFunctionInfos(Handle<JSArray> array);
91
92  MUST_USE_RESULT static MaybeObject* ReplaceFunctionCode(
93      Handle<JSArray> new_compile_info_array,
94      Handle<JSArray> shared_info_array);
95
96  static MaybeObject* FunctionSourceUpdated(Handle<JSArray> shared_info_array);
97
98  // Updates script field in FunctionSharedInfo.
99  static void SetFunctionScript(Handle<JSValue> function_wrapper,
100                                Handle<Object> script_handle);
101
102  MUST_USE_RESULT static MaybeObject* PatchFunctionPositions(
103      Handle<JSArray> shared_info_array, Handle<JSArray> position_change_array);
104
105  // For a script updates its source field. If old_script_name is provided
106  // (i.e. is a String), also creates a copy of the script with its original
107  // source and sends notification to debugger.
108  static Object* ChangeScriptSource(Handle<Script> original_script,
109                                    Handle<String> new_source,
110                                    Handle<Object> old_script_name);
111
112  // In a code of a parent function replaces original function as embedded
113  // object with a substitution one.
114  static void ReplaceRefToNestedFunction(Handle<JSValue> parent_function_shared,
115                                         Handle<JSValue> orig_function_shared,
116                                         Handle<JSValue> subst_function_shared);
117
118  // Checks listed functions on stack and return array with corresponding
119  // FunctionPatchabilityStatus statuses; extra array element may
120  // contain general error message. Modifies the current stack and
121  // has restart the lowest found frames and drops all other frames above
122  // if possible and if do_drop is true.
123  static Handle<JSArray> CheckAndDropActivations(
124      Handle<JSArray> shared_info_array, bool do_drop);
125
126  // A copy of this is in liveedit-debugger.js.
127  enum FunctionPatchabilityStatus {
128    FUNCTION_AVAILABLE_FOR_PATCH = 1,
129    FUNCTION_BLOCKED_ON_ACTIVE_STACK = 2,
130    FUNCTION_BLOCKED_ON_OTHER_STACK = 3,
131    FUNCTION_BLOCKED_UNDER_NATIVE_CODE = 4,
132    FUNCTION_REPLACED_ON_ACTIVE_STACK = 5
133  };
134
135  // Compares 2 strings line-by-line, then token-wise and returns diff in form
136  // of array of triplets (pos1, pos1_end, pos2_end) describing list
137  // of diff chunks.
138  static Handle<JSArray> CompareStrings(Handle<String> s1,
139                                        Handle<String> s2);
140};
141
142
143// A general-purpose comparator between 2 arrays.
144class Comparator {
145 public:
146  // Holds 2 arrays of some elements allowing to compare any pair of
147  // element from the first array and element from the second array.
148  class Input {
149   public:
150    virtual int GetLength1() = 0;
151    virtual int GetLength2() = 0;
152    virtual bool Equals(int index1, int index2) = 0;
153
154   protected:
155    virtual ~Input() {}
156  };
157
158  // Receives compare result as a series of chunks.
159  class Output {
160   public:
161    // Puts another chunk in result list. Note that technically speaking
162    // only 3 arguments actually needed with 4th being derivable.
163    virtual void AddChunk(int pos1, int pos2, int len1, int len2) = 0;
164
165   protected:
166    virtual ~Output() {}
167  };
168
169  // Finds the difference between 2 arrays of elements.
170  static void CalculateDifference(Input* input,
171                                  Output* result_writer);
172};
173
174#endif  // ENABLE_DEBUGGER_SUPPORT
175
176
177} }  // namespace v8::internal
178
179#endif /* V*_LIVEEDIT_H_ */
180