LCOV - code coverage report
Current view: top level - src/runtime - runtime-liveedit.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 131 149 87.9 %
Date: 2017-10-20 Functions: 11 24 45.8 %

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

Generated by: LCOV version 1.10