LCOV - code coverage report
Current view: top level - src/runtime - runtime-liveedit.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 145 148 98.0 %
Date: 2017-04-26 Functions: 12 24 50.0 %

          Line data    Source code
       1             : // Copyright 2014 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             : #include "src/runtime/runtime-utils.h"
       6             : 
       7             : #include "src/arguments.h"
       8             : #include "src/debug/debug.h"
       9             : #include "src/debug/debug-frames.h"
      10             : #include "src/debug/liveedit.h"
      11             : #include "src/frames-inl.h"
      12             : #include "src/isolate-inl.h"
      13             : #include "src/runtime/runtime.h"
      14             : 
      15             : namespace v8 {
      16             : namespace internal {
      17             : 
      18             : // For a script finds all SharedFunctionInfo's in the heap that points
      19             : // to this script. Returns JSArray of SharedFunctionInfo wrapped
      20             : // in OpaqueReferences.
      21        2466 : RUNTIME_FUNCTION(Runtime_LiveEditFindSharedFunctionInfosForScript) {
      22         822 :   HandleScope scope(isolate);
      23         822 :   CHECK(isolate->debug()->live_edit_enabled());
      24             :   DCHECK_EQ(1, args.length());
      25        1644 :   CONVERT_ARG_CHECKED(JSValue, script_value, 0);
      26             : 
      27        1644 :   CHECK(script_value->value()->IsScript());
      28         822 :   Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
      29             : 
      30         822 :   List<Handle<SharedFunctionInfo> > found;
      31         822 :   Heap* heap = isolate->heap();
      32             :   {
      33         822 :     HeapIterator iterator(heap);
      34             :     HeapObject* heap_obj;
      35    19563186 :     while ((heap_obj = iterator.next()) != nullptr) {
      36    19562364 :       if (!heap_obj->IsSharedFunctionInfo()) continue;
      37             :       SharedFunctionInfo* shared = SharedFunctionInfo::cast(heap_obj);
      38     2416446 :       if (shared->script() != *script) continue;
      39        2420 :       found.Add(Handle<SharedFunctionInfo>(shared));
      40         822 :     }
      41             :   }
      42             : 
      43         822 :   Handle<FixedArray> result = isolate->factory()->NewFixedArray(found.length());
      44        2420 :   for (int i = 0; i < found.length(); ++i) {
      45        2420 :     Handle<SharedFunctionInfo> shared = found[i];
      46        2420 :     SharedInfoWrapper info_wrapper = SharedInfoWrapper::Create(isolate);
      47        2420 :     Handle<String> name(String::cast(shared->name()));
      48             :     info_wrapper.SetProperties(name, shared->start_position(),
      49        2420 :                                shared->end_position(), shared);
      50        4840 :     result->set(i, *info_wrapper.GetJSArray());
      51             :   }
      52        2466 :   return *isolate->factory()->NewJSArrayWithElements(result);
      53             : }
      54             : 
      55             : 
      56             : // For a script calculates compilation information about all its functions.
      57             : // The script source is explicitly specified by the second argument.
      58             : // The source of the actual script is not used, however it is important that
      59             : // all generated code keeps references to this particular instance of script.
      60             : // Returns a JSArray of compilation infos. The array is ordered so that
      61             : // each function with all its descendant is always stored in a continues range
      62             : // with the function itself going first. The root function is a script function.
      63        4932 : RUNTIME_FUNCTION(Runtime_LiveEditGatherCompileInfo) {
      64        1644 :   HandleScope scope(isolate);
      65        1644 :   CHECK(isolate->debug()->live_edit_enabled());
      66             :   DCHECK_EQ(2, args.length());
      67        3288 :   CONVERT_ARG_CHECKED(JSValue, script, 0);
      68        3288 :   CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
      69             : 
      70        3288 :   CHECK(script->value()->IsScript());
      71        1644 :   Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
      72             : 
      73        3288 :   RETURN_RESULT_OR_FAILURE(isolate,
      74        1644 :                            LiveEdit::GatherCompileInfo(script_handle, source));
      75             : }
      76             : 
      77             : 
      78             : // Changes the source of the script to a new_source.
      79             : // If old_script_name is provided (i.e. is a String), also creates a copy of
      80             : // the script with its original source and sends notification to debugger.
      81        1926 : RUNTIME_FUNCTION(Runtime_LiveEditReplaceScript) {
      82         642 :   HandleScope scope(isolate);
      83         642 :   CHECK(isolate->debug()->live_edit_enabled());
      84             :   DCHECK_EQ(3, args.length());
      85        1284 :   CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
      86        1284 :   CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
      87         642 :   CONVERT_ARG_HANDLE_CHECKED(Object, old_script_name, 2);
      88             : 
      89        1284 :   CHECK(original_script_value->value()->IsScript());
      90         642 :   Handle<Script> original_script(Script::cast(original_script_value->value()));
      91             : 
      92             :   Handle<Object> old_script = LiveEdit::ChangeScriptSource(
      93         642 :       original_script, new_source, old_script_name);
      94             : 
      95         642 :   if (old_script->IsScript()) {
      96          26 :     Handle<Script> script_handle = Handle<Script>::cast(old_script);
      97          52 :     return *Script::GetWrapper(script_handle);
      98             :   } else {
      99         616 :     return isolate->heap()->null_value();
     100         642 :   }
     101             : }
     102             : 
     103             : // Recreate the shared function infos array after changing the IDs of all
     104             : // SharedFunctionInfos.
     105        1926 : RUNTIME_FUNCTION(Runtime_LiveEditFixupScript) {
     106         642 :   HandleScope scope(isolate);
     107         642 :   CHECK(isolate->debug()->live_edit_enabled());
     108             :   DCHECK_EQ(args.length(), 2);
     109        1284 :   CONVERT_ARG_CHECKED(JSValue, script_value, 0);
     110        1284 :   CONVERT_INT32_ARG_CHECKED(max_function_literal_id, 1);
     111             : 
     112        1284 :   CHECK(script_value->value()->IsScript());
     113         642 :   Handle<Script> script(Script::cast(script_value->value()));
     114             : 
     115         642 :   LiveEdit::FixupScript(script, max_function_literal_id);
     116         642 :   return isolate->heap()->undefined_value();
     117             : }
     118             : 
     119        4068 : RUNTIME_FUNCTION(Runtime_LiveEditFunctionSourceUpdated) {
     120        1356 :   HandleScope scope(isolate);
     121        1356 :   CHECK(isolate->debug()->live_edit_enabled());
     122             :   DCHECK_EQ(args.length(), 2);
     123        2712 :   CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
     124        2712 :   CONVERT_INT32_ARG_CHECKED(new_function_literal_id, 1);
     125        1356 :   CHECK(SharedInfoWrapper::IsInstance(shared_info));
     126             : 
     127        1356 :   LiveEdit::FunctionSourceUpdated(shared_info, new_function_literal_id);
     128        1356 :   return isolate->heap()->undefined_value();
     129             : }
     130             : 
     131             : 
     132             : // Replaces code of SharedFunctionInfo with a new one.
     133        2010 : RUNTIME_FUNCTION(Runtime_LiveEditReplaceFunctionCode) {
     134         670 :   HandleScope scope(isolate);
     135         670 :   CHECK(isolate->debug()->live_edit_enabled());
     136             :   DCHECK_EQ(2, args.length());
     137        1340 :   CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
     138        1340 :   CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
     139         670 :   CHECK(SharedInfoWrapper::IsInstance(shared_info));
     140             : 
     141         670 :   LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
     142         670 :   return isolate->heap()->undefined_value();
     143             : }
     144             : 
     145             : 
     146             : // Connects SharedFunctionInfo to another script.
     147       14820 : RUNTIME_FUNCTION(Runtime_LiveEditFunctionSetScript) {
     148        4940 :   HandleScope scope(isolate);
     149        4940 :   CHECK(isolate->debug()->live_edit_enabled());
     150             :   DCHECK_EQ(2, args.length());
     151        4940 :   CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0);
     152        4940 :   CONVERT_ARG_HANDLE_CHECKED(Object, script_object, 1);
     153             : 
     154        4940 :   if (function_object->IsJSValue()) {
     155        4940 :     Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
     156        4940 :     if (script_object->IsJSValue()) {
     157         120 :       CHECK(JSValue::cast(*script_object)->value()->IsScript());
     158          60 :       Script* script = Script::cast(JSValue::cast(*script_object)->value());
     159             :       script_object = Handle<Object>(script, isolate);
     160             :     }
     161        9880 :     CHECK(function_wrapper->value()->IsSharedFunctionInfo());
     162        4940 :     LiveEdit::SetFunctionScript(function_wrapper, script_object);
     163             :   } else {
     164             :     // Just ignore this. We may not have a SharedFunctionInfo for some functions
     165             :     // and we check it in this function.
     166             :   }
     167             : 
     168        4940 :   return isolate->heap()->undefined_value();
     169             : }
     170             : 
     171             : 
     172             : // In a code of a parent function replaces original function as embedded object
     173             : // with a substitution one.
     174         168 : RUNTIME_FUNCTION(Runtime_LiveEditReplaceRefToNestedFunction) {
     175          56 :   HandleScope scope(isolate);
     176          56 :   CHECK(isolate->debug()->live_edit_enabled());
     177             :   DCHECK_EQ(3, args.length());
     178             : 
     179         112 :   CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
     180         112 :   CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
     181         112 :   CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
     182         112 :   CHECK(parent_wrapper->value()->IsSharedFunctionInfo());
     183         112 :   CHECK(orig_wrapper->value()->IsSharedFunctionInfo());
     184         112 :   CHECK(subst_wrapper->value()->IsSharedFunctionInfo());
     185             : 
     186             :   LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
     187          56 :                                        subst_wrapper);
     188          56 :   return isolate->heap()->undefined_value();
     189             : }
     190             : 
     191             : 
     192             : // Updates positions of a shared function info (first parameter) according
     193             : // to script source change. Text change is described in second parameter as
     194             : // array of groups of 3 numbers:
     195             : // (change_begin, change_end, change_end_new_position).
     196             : // Each group describes a change in text; groups are sorted by change_begin.
     197        4068 : RUNTIME_FUNCTION(Runtime_LiveEditPatchFunctionPositions) {
     198        1356 :   HandleScope scope(isolate);
     199        1356 :   CHECK(isolate->debug()->live_edit_enabled());
     200             :   DCHECK_EQ(2, args.length());
     201        2712 :   CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
     202        2712 :   CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
     203        1356 :   CHECK(SharedInfoWrapper::IsInstance(shared_array));
     204             : 
     205        1356 :   LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
     206        1356 :   return isolate->heap()->undefined_value();
     207             : }
     208             : 
     209             : 
     210             : // For array of SharedFunctionInfo's (each wrapped in JSValue)
     211             : // checks that none of them have activations on stacks (of any thread).
     212             : // Returns array of the same length with corresponding results of
     213             : // LiveEdit::FunctionPatchabilityStatus type.
     214        2388 : RUNTIME_FUNCTION(Runtime_LiveEditCheckAndDropActivations) {
     215         796 :   HandleScope scope(isolate);
     216         796 :   CHECK(isolate->debug()->live_edit_enabled());
     217             :   DCHECK_EQ(3, args.length());
     218        1592 :   CONVERT_ARG_HANDLE_CHECKED(JSArray, old_shared_array, 0);
     219        1592 :   CONVERT_ARG_HANDLE_CHECKED(JSArray, new_shared_array, 1);
     220        1592 :   CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 2);
     221             :   USE(new_shared_array);
     222        1592 :   CHECK(old_shared_array->length()->IsSmi());
     223         796 :   CHECK(new_shared_array->length() == old_shared_array->length());
     224         796 :   CHECK(old_shared_array->HasFastElements());
     225         796 :   CHECK(new_shared_array->HasFastElements());
     226         796 :   int array_length = Smi::cast(old_shared_array->length())->value();
     227         824 :   for (int i = 0; i < array_length; i++) {
     228             :     Handle<Object> old_element;
     229             :     Handle<Object> new_element;
     230        2472 :     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     231             :         isolate, old_element,
     232             :         JSReceiver::GetElement(isolate, old_shared_array, i));
     233        2472 :     CHECK(old_element->IsJSValue() &&
     234             :           Handle<JSValue>::cast(old_element)->value()->IsSharedFunctionInfo());
     235        1648 :     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     236             :         isolate, new_element,
     237             :         JSReceiver::GetElement(isolate, new_shared_array, i));
     238        3296 :     CHECK(
     239             :         new_element->IsUndefined(isolate) ||
     240             :         (new_element->IsJSValue() &&
     241             :          Handle<JSValue>::cast(new_element)->value()->IsSharedFunctionInfo()));
     242             :   }
     243             : 
     244             :   return *LiveEdit::CheckAndDropActivations(old_shared_array, new_shared_array,
     245        1592 :                                             do_drop);
     246             : }
     247             : 
     248             : 
     249             : // Compares 2 strings line-by-line, then token-wise and returns diff in form
     250             : // of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
     251             : // of diff chunks.
     252        3562 : RUNTIME_FUNCTION(Runtime_LiveEditCompareStrings) {
     253         920 :   HandleScope scope(isolate);
     254         920 :   CHECK(isolate->debug()->live_edit_enabled());
     255             :   DCHECK_EQ(2, args.length());
     256        1840 :   CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
     257        1840 :   CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
     258             : 
     259         920 :   Handle<JSArray> result = LiveEdit::CompareStrings(s1, s2);
     260         920 :   uint32_t array_length = 0;
     261         920 :   CHECK(result->length()->ToArrayLength(&array_length));
     262         920 :   if (array_length > 0) {
     263         802 :     isolate->debug()->feature_tracker()->Track(DebugFeatureTracker::kLiveEdit);
     264             :   }
     265             : 
     266         920 :   return *result;
     267             : }
     268             : 
     269             : 
     270             : // Restarts a call frame and completely drops all frames above.
     271             : // Returns true if successful. Otherwise returns undefined or an error message.
     272         770 : RUNTIME_FUNCTION(Runtime_LiveEditRestartFrame) {
     273         154 :   HandleScope scope(isolate);
     274         154 :   CHECK(isolate->debug()->live_edit_enabled());
     275             :   DCHECK_EQ(2, args.length());
     276         308 :   CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
     277         154 :   CHECK(isolate->debug()->CheckExecutionState(break_id));
     278             : 
     279         308 :   CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
     280         308 :   Heap* heap = isolate->heap();
     281             : 
     282             :   // Find the relevant frame with the requested index.
     283         154 :   StackFrame::Id id = isolate->debug()->break_frame_id();
     284         154 :   if (id == StackFrame::NO_ID) {
     285             :     // If there are no JavaScript stack frames return undefined.
     286           0 :     return heap->undefined_value();
     287             :   }
     288             : 
     289         308 :   StackTraceFrameIterator it(isolate, id);
     290             :   int inlined_jsframe_index =
     291         154 :       DebugFrameHelper::FindIndexedNonNativeFrame(&it, index);
     292             :   // Liveedit is not supported on Wasm.
     293         154 :   if (inlined_jsframe_index == -1 || it.is_wasm()) {
     294           0 :     return heap->undefined_value();
     295             :   }
     296             :   // We don't really care what the inlined frame index is, since we are
     297             :   // throwing away the entire frame anyways.
     298         154 :   const char* error_message = LiveEdit::RestartFrame(it.javascript_frame());
     299         154 :   if (error_message) {
     300           0 :     return *(isolate->factory()->InternalizeUtf8String(error_message));
     301             :   }
     302         308 :   return heap->true_value();
     303             : }
     304             : }  // namespace internal
     305             : }  // namespace v8

Generated by: LCOV version 1.10