blob: 189ec08d33d4428a3674d29564c583549fbd27b5 [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
73 Handle<JSArray> result;
74 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
75 isolate, result, LiveEdit::GatherCompileInfo(script_handle, source));
76 return *result;
77}
78
79
80// Changes the source of the script to a new_source.
81// If old_script_name is provided (i.e. is a String), also creates a copy of
82// the script with its original source and sends notification to debugger.
83RUNTIME_FUNCTION(Runtime_LiveEditReplaceScript) {
84 HandleScope scope(isolate);
85 CHECK(isolate->debug()->live_edit_enabled());
86 DCHECK(args.length() == 3);
87 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
88 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
89 CONVERT_ARG_HANDLE_CHECKED(Object, old_script_name, 2);
90
91 RUNTIME_ASSERT(original_script_value->value()->IsScript());
92 Handle<Script> original_script(Script::cast(original_script_value->value()));
93
94 Handle<Object> old_script = LiveEdit::ChangeScriptSource(
95 original_script, new_source, old_script_name);
96
97 if (old_script->IsScript()) {
98 Handle<Script> script_handle = Handle<Script>::cast(old_script);
99 return *Script::GetWrapper(script_handle);
100 } else {
101 return isolate->heap()->null_value();
102 }
103}
104
105
106RUNTIME_FUNCTION(Runtime_LiveEditFunctionSourceUpdated) {
107 HandleScope scope(isolate);
108 CHECK(isolate->debug()->live_edit_enabled());
109 DCHECK(args.length() == 1);
110 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
111 RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_info));
112
113 LiveEdit::FunctionSourceUpdated(shared_info);
114 return isolate->heap()->undefined_value();
115}
116
117
118// Replaces code of SharedFunctionInfo with a new one.
119RUNTIME_FUNCTION(Runtime_LiveEditReplaceFunctionCode) {
120 HandleScope scope(isolate);
121 CHECK(isolate->debug()->live_edit_enabled());
122 DCHECK(args.length() == 2);
123 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
124 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
125 RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_info));
126
127 LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
128 return isolate->heap()->undefined_value();
129}
130
131
132// Connects SharedFunctionInfo to another script.
133RUNTIME_FUNCTION(Runtime_LiveEditFunctionSetScript) {
134 HandleScope scope(isolate);
135 CHECK(isolate->debug()->live_edit_enabled());
136 DCHECK(args.length() == 2);
137 CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0);
138 CONVERT_ARG_HANDLE_CHECKED(Object, script_object, 1);
139
140 if (function_object->IsJSValue()) {
141 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
142 if (script_object->IsJSValue()) {
143 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
144 Script* script = Script::cast(JSValue::cast(*script_object)->value());
145 script_object = Handle<Object>(script, isolate);
146 }
147 RUNTIME_ASSERT(function_wrapper->value()->IsSharedFunctionInfo());
148 LiveEdit::SetFunctionScript(function_wrapper, script_object);
149 } else {
150 // Just ignore this. We may not have a SharedFunctionInfo for some functions
151 // and we check it in this function.
152 }
153
154 return isolate->heap()->undefined_value();
155}
156
157
158// In a code of a parent function replaces original function as embedded object
159// with a substitution one.
160RUNTIME_FUNCTION(Runtime_LiveEditReplaceRefToNestedFunction) {
161 HandleScope scope(isolate);
162 CHECK(isolate->debug()->live_edit_enabled());
163 DCHECK(args.length() == 3);
164
165 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
166 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
167 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
168 RUNTIME_ASSERT(parent_wrapper->value()->IsSharedFunctionInfo());
169 RUNTIME_ASSERT(orig_wrapper->value()->IsSharedFunctionInfo());
170 RUNTIME_ASSERT(subst_wrapper->value()->IsSharedFunctionInfo());
171
172 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
173 subst_wrapper);
174 return isolate->heap()->undefined_value();
175}
176
177
178// Updates positions of a shared function info (first parameter) according
179// to script source change. Text change is described in second parameter as
180// array of groups of 3 numbers:
181// (change_begin, change_end, change_end_new_position).
182// Each group describes a change in text; groups are sorted by change_begin.
183RUNTIME_FUNCTION(Runtime_LiveEditPatchFunctionPositions) {
184 HandleScope scope(isolate);
185 CHECK(isolate->debug()->live_edit_enabled());
186 DCHECK(args.length() == 2);
187 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
188 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
189 RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_array))
190
191 LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
192 return isolate->heap()->undefined_value();
193}
194
195
196// For array of SharedFunctionInfo's (each wrapped in JSValue)
197// checks that none of them have activations on stacks (of any thread).
198// Returns array of the same length with corresponding results of
199// LiveEdit::FunctionPatchabilityStatus type.
200RUNTIME_FUNCTION(Runtime_LiveEditCheckAndDropActivations) {
201 HandleScope scope(isolate);
202 CHECK(isolate->debug()->live_edit_enabled());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000203 DCHECK(args.length() == 3);
204 CONVERT_ARG_HANDLE_CHECKED(JSArray, old_shared_array, 0);
205 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_shared_array, 1);
206 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 2);
207 USE(new_shared_array);
208 RUNTIME_ASSERT(old_shared_array->length()->IsSmi());
209 RUNTIME_ASSERT(new_shared_array->length() == old_shared_array->length());
210 RUNTIME_ASSERT(old_shared_array->HasFastElements())
211 RUNTIME_ASSERT(new_shared_array->HasFastElements())
212 int array_length = Smi::cast(old_shared_array->length())->value();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400213 for (int i = 0; i < array_length; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000214 Handle<Object> old_element;
215 Handle<Object> new_element;
216 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
217 isolate, old_element, Object::GetElement(isolate, old_shared_array, i));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400218 RUNTIME_ASSERT(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000219 old_element->IsJSValue() &&
220 Handle<JSValue>::cast(old_element)->value()->IsSharedFunctionInfo());
221 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
222 isolate, new_element, Object::GetElement(isolate, new_shared_array, i));
223 RUNTIME_ASSERT(
224 new_element->IsUndefined() ||
225 (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);
245 uint32_t array_length;
246 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