V8 Project
liveedit.h
Go to the documentation of this file.
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef V8_LIVEEDIT_H_
6 #define V8_LIVEEDIT_H_
7 
8 
9 
10 // Live Edit feature implementation.
11 // User should be able to change script on already running VM. This feature
12 // matches hot swap features in other frameworks.
13 //
14 // The basic use-case is when user spots some mistake in function body
15 // from debugger and wishes to change the algorithm without restart.
16 //
17 // A single change always has a form of a simple replacement (in pseudo-code):
18 // script.source[positions, positions+length] = new_string;
19 // Implementation first determines, which function's body includes this
20 // change area. Then both old and new versions of script are fully compiled
21 // in order to analyze, whether the function changed its outer scope
22 // expectations (or number of parameters). If it didn't, function's code is
23 // patched with a newly compiled code. If it did change, enclosing function
24 // gets patched. All inner functions are left untouched, whatever happened
25 // to them in a new script version. However, new version of code will
26 // instantiate newly compiled functions.
27 
28 
29 #include "src/allocation.h"
30 #include "src/compiler.h"
31 
32 namespace v8 {
33 namespace internal {
34 
35 // This class collects some specific information on structure of functions
36 // in a particular script. It gets called from compiler all the time, but
37 // actually records any data only when liveedit operation is in process;
38 // in any other time this class is very cheap.
39 //
40 // The primary interest of the Tracker is to record function scope structures
41 // in order to analyze whether function code maybe safely patched (with new
42 // code successfully reading existing data from function scopes). The Tracker
43 // also collects compiled function codes.
45  public:
46  explicit LiveEditFunctionTracker(Isolate* isolate, FunctionLiteral* fun);
49  FunctionLiteral* lit, Zone* zone);
51 
52  static bool IsActive(Isolate* isolate);
53 
54  private:
56 };
57 
58 
60  public:
61  // Describes how exactly a frame has been dropped from stack.
63  // No frame has been dropped.
65  // The top JS frame had been calling IC stub. IC stub mustn't be called now.
67  // The top JS frame had been calling debug break slot stub. Patch the
68  // address this stub jumps to in the end.
70  // The top JS frame had been calling some C++ function. The return address
71  // gets patched automatically.
75  };
76 
77  static void InitializeThreadLocal(Debug* debug);
78 
79  static bool SetAfterBreakTarget(Debug* debug);
80 
82  Handle<Script> script,
83  Handle<String> source);
84 
85  static void WrapSharedFunctionInfos(Handle<JSArray> array);
86 
87  static void ReplaceFunctionCode(Handle<JSArray> new_compile_info_array,
88  Handle<JSArray> shared_info_array);
89 
90  static void FunctionSourceUpdated(Handle<JSArray> shared_info_array);
91 
92  // Updates script field in FunctionSharedInfo.
93  static void SetFunctionScript(Handle<JSValue> function_wrapper,
94  Handle<Object> script_handle);
95 
96  static void PatchFunctionPositions(Handle<JSArray> shared_info_array,
97  Handle<JSArray> position_change_array);
98 
99  // For a script updates its source field. If old_script_name is provided
100  // (i.e. is a String), also creates a copy of the script with its original
101  // source and sends notification to debugger.
102  static Handle<Object> ChangeScriptSource(Handle<Script> original_script,
103  Handle<String> new_source,
104  Handle<Object> old_script_name);
105 
106  // In a code of a parent function replaces original function as embedded
107  // object with a substitution one.
108  static void ReplaceRefToNestedFunction(Handle<JSValue> parent_function_shared,
109  Handle<JSValue> orig_function_shared,
110  Handle<JSValue> subst_function_shared);
111 
112  // Find open generator activations, and set corresponding "result" elements to
113  // FUNCTION_BLOCKED_ACTIVE_GENERATOR.
114  static bool FindActiveGenerators(Handle<FixedArray> shared_info_array,
115  Handle<FixedArray> result, int len);
116 
117  // Checks listed functions on stack and return array with corresponding
118  // FunctionPatchabilityStatus statuses; extra array element may
119  // contain general error message. Modifies the current stack and
120  // has restart the lowest found frames and drops all other frames above
121  // if possible and if do_drop is true.
123  Handle<JSArray> shared_info_array, bool do_drop);
124 
125  // Restarts the call frame and completely drops all frames above it.
126  // Return error message or NULL.
127  static const char* RestartFrame(JavaScriptFrame* frame);
128 
129  // A copy of this is in liveedit-debugger.js.
138  };
139 
140  // Compares 2 strings line-by-line, then token-wise and returns diff in form
141  // of array of triplets (pos1, pos1_end, pos2_end) describing list
142  // of diff chunks.
145 
146  // Architecture-specific constant.
147  static const bool kFrameDropperSupported;
148 
149  /**
150  * Defines layout of a stack frame that supports padding. This is a regular
151  * internal frame that has a flexible stack structure. LiveEdit can shift
152  * its lower part up the stack, taking up the 'padding' space when additional
153  * stack memory is required.
154  * Such frame is expected immediately above the topmost JavaScript frame.
155  *
156  * Stack Layout:
157  * --- Top
158  * LiveEdit routine frames
159  * ---
160  * C frames of debug handler
161  * ---
162  * ...
163  * ---
164  * An internal frame that has n padding words:
165  * - any number of words as needed by code -- upper part of frame
166  * - padding size: a Smi storing n -- current size of padding
167  * - padding: n words filled with kPaddingValue in form of Smi
168  * - 3 context/type words of a regular InternalFrame
169  * - fp
170  * ---
171  * Topmost JavaScript frame
172  * ---
173  * ...
174  * --- Bottom
175  */
176  // A size of frame base including fp. Padding words starts right above
177  // the base.
178  static const int kFrameDropperFrameSize = 4;
179  // A number of words that should be reserved on stack for the LiveEdit use.
180  // Stored on stack in form of Smi.
181  static const int kFramePaddingInitialSize = 1;
182  // A value that padding words are filled with (in form of Smi). Going
183  // bottom-top, the first word not having this value is a counter word.
185 };
186 
187 
188 // A general-purpose comparator between 2 arrays.
189 class Comparator {
190  public:
191  // Holds 2 arrays of some elements allowing to compare any pair of
192  // element from the first array and element from the second array.
193  class Input {
194  public:
195  virtual int GetLength1() = 0;
196  virtual int GetLength2() = 0;
197  virtual bool Equals(int index1, int index2) = 0;
198 
199  protected:
200  virtual ~Input() {}
201  };
202 
203  // Receives compare result as a series of chunks.
204  class Output {
205  public:
206  // Puts another chunk in result list. Note that technically speaking
207  // only 3 arguments actually needed with 4th being derivable.
208  virtual void AddChunk(int pos1, int pos2, int len1, int len2) = 0;
209 
210  protected:
211  virtual ~Output() {}
212  };
213 
214  // Finds the difference between 2 arrays of elements.
215  static void CalculateDifference(Input* input,
216  Output* result_writer);
217 };
218 
219 
220 
221 // Simple helper class that creates more or less typed structures over
222 // JSArray object. This is an adhoc method of passing structures from C++
223 // to JavaScript.
224 template<typename S>
226  public:
227  static S Create(Isolate* isolate) {
228  Factory* factory = isolate->factory();
229  Handle<JSArray> array = factory->NewJSArray(S::kSize_);
230  return S(array);
231  }
232 
233  static S cast(Object* object) {
234  JSArray* array = JSArray::cast(object);
235  Handle<JSArray> array_handle(array);
236  return S(array_handle);
237  }
238 
239  explicit JSArrayBasedStruct(Handle<JSArray> array) : array_(array) {
240  }
241 
243  return array_;
244  }
245 
246  Isolate* isolate() const {
247  return array_->GetIsolate();
248  }
249 
250  protected:
251  void SetField(int field_position, Handle<Object> value) {
252  JSObject::SetElement(array_, field_position, value, NONE, SLOPPY).Assert();
253  }
254 
255  void SetSmiValueField(int field_position, int value) {
256  SetField(field_position, Handle<Smi>(Smi::FromInt(value), isolate()));
257  }
258 
259  Handle<Object> GetField(int field_position) {
260  return Object::GetElement(
261  isolate(), array_, field_position).ToHandleChecked();
262  }
263 
264  int GetSmiValueField(int field_position) {
265  Handle<Object> res = GetField(field_position);
266  return Handle<Smi>::cast(res)->value();
267  }
268 
269  private:
271 };
272 
273 
274 // Represents some function compilation details. This structure will be used
275 // from JavaScript. It contains Code object, which is kept wrapped
276 // into a BlindReference for sanitizing reasons.
277 class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> {
278  public:
281  }
282 
284  int start_position,
285  int end_position,
286  int param_num,
287  int literal_count,
288  int slot_count,
289  int parent_index);
290 
291  void SetFunctionCode(Handle<Code> function_code,
292  Handle<HeapObject> code_scope_info);
293 
294  void SetFunctionScopeInfo(Handle<Object> scope_info_array) {
295  this->SetField(kFunctionScopeInfoOffset_, scope_info_array);
296  }
297 
299 
301  return this->GetSmiValueField(kLiteralNumOffset_);
302  }
303 
306  }
307 
309 
311 
313 
316  }
317 
319 
320  int GetSlotCount() {
321  return this->GetSmiValueField(kSlotNumOffset_);
322  }
323 
324  private:
325  static const int kFunctionNameOffset_ = 0;
326  static const int kStartPositionOffset_ = 1;
327  static const int kEndPositionOffset_ = 2;
328  static const int kParamNumOffset_ = 3;
329  static const int kCodeOffset_ = 4;
330  static const int kCodeScopeInfoOffset_ = 5;
331  static const int kFunctionScopeInfoOffset_ = 6;
332  static const int kParentIndexOffset_ = 7;
333  static const int kSharedFunctionInfoOffset_ = 8;
334  static const int kLiteralNumOffset_ = 9;
335  static const int kSlotNumOffset_ = 10;
336  static const int kSize_ = 11;
337 
339 };
340 
341 
342 // Wraps SharedFunctionInfo along with some of its fields for passing it
343 // back to JavaScript. SharedFunctionInfo object itself is additionally
344 // wrapped into BlindReference for sanitizing reasons.
345 class SharedInfoWrapper : public JSArrayBasedStruct<SharedInfoWrapper> {
346  public:
347  static bool IsInstance(Handle<JSArray> array) {
348  if (array->length() != Smi::FromInt(kSize_)) return false;
349  Handle<Object> element(
350  Object::GetElement(array->GetIsolate(),
351  array,
352  kSharedInfoOffset_).ToHandleChecked());
353  if (!element->IsJSValue()) return false;
354  return Handle<JSValue>::cast(element)->value()->IsSharedFunctionInfo();
355  }
356 
359  }
360 
362  int start_position,
363  int end_position,
365 
367 
368  private:
369  static const int kFunctionNameOffset_ = 0;
370  static const int kStartPositionOffset_ = 1;
371  static const int kEndPositionOffset_ = 2;
372  static const int kSharedInfoOffset_ = 3;
373  static const int kSize_ = 4;
374 
376 };
377 
378 } } // namespace v8::internal
379 
380 #endif /* V*_LIVEEDIT_H_ */
virtual bool Equals(int index1, int index2)=0
virtual void AddChunk(int pos1, int pos2, int len1, int len2)=0
static void CalculateDifference(Input *input, Output *result_writer)
Definition: liveedit.cc:235
static const int kParamNumOffset_
Definition: liveedit.h:328
static const int kParentIndexOffset_
Definition: liveedit.h:332
static const int kSlotNumOffset_
Definition: liveedit.h:335
static const int kFunctionScopeInfoOffset_
Definition: liveedit.h:331
static const int kSharedFunctionInfoOffset_
Definition: liveedit.h:333
Handle< Object > GetCodeScopeInfo()
Definition: liveedit.cc:672
static const int kFunctionNameOffset_
Definition: liveedit.h:325
static const int kCodeOffset_
Definition: liveedit.h:329
static const int kStartPositionOffset_
Definition: liveedit.h:326
void SetInitialProperties(Handle< String > name, int start_position, int end_position, int param_num, int literal_count, int slot_count, int parent_index)
Definition: liveedit.cc:608
void SetSharedFunctionInfo(Handle< SharedFunctionInfo > info)
Definition: liveedit.cc:636
static const int kCodeScopeInfoOffset_
Definition: liveedit.h:330
static const int kLiteralNumOffset_
Definition: liveedit.h:334
void SetFunctionScopeInfo(Handle< Object > scope_info_array)
Definition: liveedit.h:294
Handle< TypeFeedbackVector > GetFeedbackVector()
Definition: liveedit.cc:652
void SetFunctionCode(Handle< Code > function_code, Handle< HeapObject > code_scope_info)
Definition: liveedit.cc:626
static const int kEndPositionOffset_
Definition: liveedit.h:327
Handle< Code > GetFunctionCode()
Definition: liveedit.cc:643
FunctionInfoWrapper(Handle< JSArray > array)
Definition: liveedit.h:279
static Handle< T > cast(Handle< S > that)
Definition: handles.h:116
Factory * factory()
Definition: isolate.h:982
static S cast(Object *object)
Definition: liveedit.h:233
void SetField(int field_position, Handle< Object > value)
Definition: liveedit.h:251
int GetSmiValueField(int field_position)
Definition: liveedit.h:264
JSArrayBasedStruct(Handle< JSArray > array)
Definition: liveedit.h:239
Isolate * isolate() const
Definition: liveedit.h:246
Handle< JSArray > array_
Definition: liveedit.h:270
static S Create(Isolate *isolate)
Definition: liveedit.h:227
void SetSmiValueField(int field_position, int value)
Definition: liveedit.h:255
Handle< JSArray > GetJSArray()
Definition: liveedit.h:242
Handle< Object > GetField(int field_position)
Definition: liveedit.h:259
static MUST_USE_RESULT MaybeHandle< Object > SetElement(Handle< JSObject > object, uint32_t index, Handle< Object > value, PropertyAttributes attributes, StrictMode strict_mode, bool check_prototype=true, SetPropertyMode set_mode=SET_PROPERTY)
Definition: objects.cc:12336
LiveEditFunctionTracker(Isolate *isolate, FunctionLiteral *fun)
Definition: liveedit.cc:2052
void RecordRootFunctionInfo(Handle< Code > code)
Definition: liveedit.cc:2078
static bool IsActive(Isolate *isolate)
Definition: liveedit.cc:2083
void RecordFunctionInfo(Handle< SharedFunctionInfo > info, FunctionLiteral *lit, Zone *zone)
Definition: liveedit.cc:2068
static const int kFramePaddingValue
Definition: liveedit.h:184
static const bool kFrameDropperSupported
Definition: liveedit.h:147
@ FUNCTION_BLOCKED_UNDER_NATIVE_CODE
Definition: liveedit.h:134
static const char * RestartFrame(JavaScriptFrame *frame)
Definition: liveedit.cc:2034
static bool FindActiveGenerators(Handle< FixedArray > shared_info_array, Handle< FixedArray > result, int len)
Definition: liveedit.cc:1892
static Handle< JSArray > CheckAndDropActivations(Handle< JSArray > shared_info_array, bool do_drop)
Definition: liveedit.cc:1955
static MUST_USE_RESULT MaybeHandle< JSArray > GatherCompileInfo(Handle< Script > script, Handle< String > source)
Definition: liveedit.cc:843
static void ReplaceRefToNestedFunction(Handle< JSValue > parent_function_shared, Handle< JSValue > orig_function_shared, Handle< JSValue > subst_function_shared)
Definition: liveedit.cc:1495
static void ReplaceFunctionCode(Handle< JSArray > new_compile_info_array, Handle< JSArray > shared_info_array)
Definition: liveedit.cc:1187
@ FRAME_DROPPED_IN_DEBUG_SLOT_CALL
Definition: liveedit.h:69
static bool SetAfterBreakTarget(Debug *debug)
Definition: liveedit.cc:813
static Handle< Object > ChangeScriptSource(Handle< Script > original_script, Handle< String > new_source, Handle< Object > old_script_name)
Definition: liveedit.cc:1471
static void InitializeThreadLocal(Debug *debug)
Definition: liveedit.cc:808
static void WrapSharedFunctionInfos(Handle< JSArray > array)
Definition: liveedit.cc:909
static void PatchFunctionPositions(Handle< JSArray > shared_info_array, Handle< JSArray > position_change_array)
Definition: liveedit.cc:1415
static void FunctionSourceUpdated(Handle< JSArray > shared_info_array)
Definition: liveedit.cc:1233
static const int kFramePaddingInitialSize
Definition: liveedit.h:181
static Handle< JSArray > CompareStrings(Handle< String > s1, Handle< String > s2)
Definition: liveedit.cc:556
static void SetFunctionScript(Handle< JSValue > function_wrapper, Handle< Object > script_handle)
Definition: liveedit.cc:1242
static const int kFrameDropperFrameSize
Defines layout of a stack frame that supports padding.
Definition: liveedit.h:178
static MUST_USE_RESULT MaybeHandle< Object > GetElement(Isolate *isolate, Handle< Object > object, uint32_t index)
Definition: objects-inl.h:1113
SharedInfoWrapper(Handle< JSArray > array)
Definition: liveedit.h:357
static bool IsInstance(Handle< JSArray > array)
Definition: liveedit.h:347
Handle< SharedFunctionInfo > GetInfo()
Definition: liveedit.cc:691
static const int kEndPositionOffset_
Definition: liveedit.h:371
static const int kFunctionNameOffset_
Definition: liveedit.h:369
static const int kSharedInfoOffset_
Definition: liveedit.h:372
void SetProperties(Handle< String > name, int start_position, int end_position, Handle< SharedFunctionInfo > info)
Definition: liveedit.cc:678
static const int kStartPositionOffset_
Definition: liveedit.h:370
static Smi * FromInt(int value)
Definition: objects-inl.h:1321
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be expose gc extension under the specified name show built in functions in stack traces use random jit cookie to mask large constants minimum length for automatic enable preparsing CPU profiler sampling interval in microseconds trace out of bounds accesses to external arrays default size of stack region v8 is allowed to maximum length of function source code printed in a stack trace min size of a semi the new space consists of two semi spaces print one trace line following each garbage collection do not print trace line after scavenger collection print cumulative GC statistics in name
#define MUST_USE_RESULT
Definition: macros.h:266
const SwVfpRegister s1
const SwVfpRegister s2
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20
@ NONE