blob: 72e8648a423224b9d66748e80afdda226069954b [file] [log] [blame]
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001// 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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005#include "src/runtime/runtime-utils.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006
7#include "src/arguments.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008#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"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013#include "src/runtime/runtime.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014
15namespace v8 {
16namespace internal {
17
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018// For a script finds all SharedFunctionInfo's in the heap that points
19// to this script. Returns JSArray of SharedFunctionInfo wrapped
20// in OpaqueReferences.
21RUNTIME_FUNCTION(Runtime_LiveEditFindSharedFunctionInfosForScript) {
22 HandleScope scope(isolate);
23 CHECK(isolate->debug()->live_edit_enabled());
24 DCHECK(args.length() == 1);
25 CONVERT_ARG_CHECKED(JSValue, script_value, 0);
26
27 RUNTIME_ASSERT(script_value->value()->IsScript());
28 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
29
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000030 List<Handle<SharedFunctionInfo> > found;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040031 Heap* heap = isolate->heap();
32 {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000033 HeapIterator iterator(heap);
34 HeapObject* heap_obj;
35 while ((heap_obj = iterator.next())) {
36 if (!heap_obj->IsSharedFunctionInfo()) continue;
37 SharedFunctionInfo* shared = SharedFunctionInfo::cast(heap_obj);
38 if (shared->script() != *script) continue;
39 found.Add(Handle<SharedFunctionInfo>(shared));
40 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040041 }
42
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000043 Handle<FixedArray> result = isolate->factory()->NewFixedArray(found.length());
44 for (int i = 0; i < found.length(); ++i) {
45 Handle<SharedFunctionInfo> shared = found[i];
46 SharedInfoWrapper info_wrapper = SharedInfoWrapper::Create(isolate);
47 Handle<String> name(String::cast(shared->name()));
48 info_wrapper.SetProperties(name, shared->start_position(),
49 shared->end_position(), shared);
50 result->set(i, *info_wrapper.GetJSArray());
51 }
52 return *isolate->factory()->NewJSArrayWithElements(result);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040053}
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.
63RUNTIME_FUNCTION(Runtime_LiveEditGatherCompileInfo) {
64 HandleScope scope(isolate);
65 CHECK(isolate->debug()->live_edit_enabled());
66 DCHECK(args.length() == 2);
67 CONVERT_ARG_CHECKED(JSValue, script, 0);
68 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
69
70 RUNTIME_ASSERT(script->value()->IsScript());
71 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
72
Ben Murdoch61f157c2016-09-16 13:49:30 +010073 RETURN_RESULT_OR_FAILURE(isolate,
74 LiveEdit::GatherCompileInfo(script_handle, source));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040075}
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.
81RUNTIME_FUNCTION(Runtime_LiveEditReplaceScript) {
82 HandleScope scope(isolate);
83 CHECK(isolate->debug()->live_edit_enabled());
84 DCHECK(args.length() == 3);
85 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
86 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
87 CONVERT_ARG_HANDLE_CHECKED(Object, old_script_name, 2);
88
89 RUNTIME_ASSERT(original_script_value->value()->IsScript());
90 Handle<Script> original_script(Script::cast(original_script_value->value()));
91
92 Handle<Object> old_script = LiveEdit::ChangeScriptSource(
93 original_script, new_source, old_script_name);
94
95 if (old_script->IsScript()) {
96 Handle<Script> script_handle = Handle<Script>::cast(old_script);
97 return *Script::GetWrapper(script_handle);
98 } else {
99 return isolate->heap()->null_value();
100 }
101}
102
103
104RUNTIME_FUNCTION(Runtime_LiveEditFunctionSourceUpdated) {
105 HandleScope scope(isolate);
106 CHECK(isolate->debug()->live_edit_enabled());
107 DCHECK(args.length() == 1);
108 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
109 RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_info));
110
111 LiveEdit::FunctionSourceUpdated(shared_info);
112 return isolate->heap()->undefined_value();
113}
114
115
116// Replaces code of SharedFunctionInfo with a new one.
117RUNTIME_FUNCTION(Runtime_LiveEditReplaceFunctionCode) {
118 HandleScope scope(isolate);
119 CHECK(isolate->debug()->live_edit_enabled());
120 DCHECK(args.length() == 2);
121 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
122 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
123 RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_info));
124
125 LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
126 return isolate->heap()->undefined_value();
127}
128
129
130// Connects SharedFunctionInfo to another script.
131RUNTIME_FUNCTION(Runtime_LiveEditFunctionSetScript) {
132 HandleScope scope(isolate);
133 CHECK(isolate->debug()->live_edit_enabled());
134 DCHECK(args.length() == 2);
135 CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0);
136 CONVERT_ARG_HANDLE_CHECKED(Object, script_object, 1);
137
138 if (function_object->IsJSValue()) {
139 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
140 if (script_object->IsJSValue()) {
141 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
142 Script* script = Script::cast(JSValue::cast(*script_object)->value());
143 script_object = Handle<Object>(script, isolate);
144 }
145 RUNTIME_ASSERT(function_wrapper->value()->IsSharedFunctionInfo());
146 LiveEdit::SetFunctionScript(function_wrapper, script_object);
147 } else {
148 // Just ignore this. We may not have a SharedFunctionInfo for some functions
149 // and we check it in this function.
150 }
151
152 return isolate->heap()->undefined_value();
153}
154
155
156// In a code of a parent function replaces original function as embedded object
157// with a substitution one.
158RUNTIME_FUNCTION(Runtime_LiveEditReplaceRefToNestedFunction) {
159 HandleScope scope(isolate);
160 CHECK(isolate->debug()->live_edit_enabled());
161 DCHECK(args.length() == 3);
162
163 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
164 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
165 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
166 RUNTIME_ASSERT(parent_wrapper->value()->IsSharedFunctionInfo());
167 RUNTIME_ASSERT(orig_wrapper->value()->IsSharedFunctionInfo());
168 RUNTIME_ASSERT(subst_wrapper->value()->IsSharedFunctionInfo());
169
170 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
171 subst_wrapper);
172 return isolate->heap()->undefined_value();
173}
174
175
176// Updates positions of a shared function info (first parameter) according
177// to script source change. Text change is described in second parameter as
178// array of groups of 3 numbers:
179// (change_begin, change_end, change_end_new_position).
180// Each group describes a change in text; groups are sorted by change_begin.
181RUNTIME_FUNCTION(Runtime_LiveEditPatchFunctionPositions) {
182 HandleScope scope(isolate);
183 CHECK(isolate->debug()->live_edit_enabled());
184 DCHECK(args.length() == 2);
185 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
186 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
Ben Murdochda12d292016-06-02 14:46:10 +0100187 RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_array));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400188
189 LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
190 return isolate->heap()->undefined_value();
191}
192
193
194// For array of SharedFunctionInfo's (each wrapped in JSValue)
195// checks that none of them have activations on stacks (of any thread).
196// Returns array of the same length with corresponding results of
197// LiveEdit::FunctionPatchabilityStatus type.
198RUNTIME_FUNCTION(Runtime_LiveEditCheckAndDropActivations) {
199 HandleScope scope(isolate);
200 CHECK(isolate->debug()->live_edit_enabled());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000201 DCHECK(args.length() == 3);
202 CONVERT_ARG_HANDLE_CHECKED(JSArray, old_shared_array, 0);
203 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_shared_array, 1);
204 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 2);
205 USE(new_shared_array);
206 RUNTIME_ASSERT(old_shared_array->length()->IsSmi());
207 RUNTIME_ASSERT(new_shared_array->length() == old_shared_array->length());
Ben Murdochda12d292016-06-02 14:46:10 +0100208 RUNTIME_ASSERT(old_shared_array->HasFastElements());
209 RUNTIME_ASSERT(new_shared_array->HasFastElements());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000210 int array_length = Smi::cast(old_shared_array->length())->value();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400211 for (int i = 0; i < array_length; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000212 Handle<Object> old_element;
213 Handle<Object> new_element;
214 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
Ben Murdochda12d292016-06-02 14:46:10 +0100215 isolate, old_element,
216 JSReceiver::GetElement(isolate, old_shared_array, i));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400217 RUNTIME_ASSERT(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000218 old_element->IsJSValue() &&
219 Handle<JSValue>::cast(old_element)->value()->IsSharedFunctionInfo());
220 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
Ben Murdochda12d292016-06-02 14:46:10 +0100221 isolate, new_element,
222 JSReceiver::GetElement(isolate, new_shared_array, i));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000223 RUNTIME_ASSERT(
Ben Murdoch61f157c2016-09-16 13:49:30 +0100224 new_element->IsUndefined(isolate) ||
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000225 (new_element->IsJSValue() &&
226 Handle<JSValue>::cast(new_element)->value()->IsSharedFunctionInfo()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400227 }
228
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000229 return *LiveEdit::CheckAndDropActivations(old_shared_array, new_shared_array,
230 do_drop);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400231}
232
233
234// Compares 2 strings line-by-line, then token-wise and returns diff in form
235// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
236// of diff chunks.
237RUNTIME_FUNCTION(Runtime_LiveEditCompareStrings) {
238 HandleScope scope(isolate);
239 CHECK(isolate->debug()->live_edit_enabled());
240 DCHECK(args.length() == 2);
241 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
242 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
243
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000244 Handle<JSArray> result = LiveEdit::CompareStrings(s1, s2);
Ben Murdochda12d292016-06-02 14:46:10 +0100245 uint32_t array_length = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000246 CHECK(result->length()->ToArrayLength(&array_length));
247 if (array_length > 0) {
248 isolate->debug()->feature_tracker()->Track(DebugFeatureTracker::kLiveEdit);
249 }
250
251 return *result;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400252}
253
254
255// Restarts a call frame and completely drops all frames above.
256// Returns true if successful. Otherwise returns undefined or an error message.
257RUNTIME_FUNCTION(Runtime_LiveEditRestartFrame) {
258 HandleScope scope(isolate);
259 CHECK(isolate->debug()->live_edit_enabled());
260 DCHECK(args.length() == 2);
261 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
262 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
263
264 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
265 Heap* heap = isolate->heap();
266
267 // Find the relevant frame with the requested index.
268 StackFrame::Id id = isolate->debug()->break_frame_id();
269 if (id == StackFrame::NO_ID) {
270 // If there are no JavaScript stack frames return undefined.
271 return heap->undefined_value();
272 }
273
274 JavaScriptFrameIterator it(isolate, id);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000275 int inlined_jsframe_index =
276 DebugFrameHelper::FindIndexedNonNativeFrame(&it, index);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400277 if (inlined_jsframe_index == -1) return heap->undefined_value();
278 // We don't really care what the inlined frame index is, since we are
279 // throwing away the entire frame anyways.
280 const char* error_message = LiveEdit::RestartFrame(it.frame());
281 if (error_message) {
282 return *(isolate->factory()->InternalizeUtf8String(error_message));
283 }
284 return heap->true_value();
285}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000286} // namespace internal
287} // namespace v8