1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "vm/bootstrap_natives.h"
6#include "vm/exceptions.h"
7#include "vm/object_store.h"
8#include "vm/runtime_entry.h"
9#include "vm/stack_frame.h"
10#include "vm/symbols.h"
11
12namespace dart {
13
14// Scan the stack until we hit the first function in the _AssertionError
15// class. We then return the next frame's script taking inlining into account.
16static ScriptPtr FindScript(DartFrameIterator* iterator) {
17#if defined(DART_PRECOMPILED_RUNTIME)
18 // The precompiled runtime faces two issues in recovering the correct
19 // assertion text. First, the precompiled runtime does not include
20 // the inlining meta-data so we cannot walk the inline-aware stack trace.
21 // Second, the script text itself is missing so whatever script is returned
22 // from here will be missing the assertion expression text.
23 iterator->NextFrame(); // Skip _AssertionError._evaluateAssertion frame
24 return Exceptions::GetCallerScript(iterator);
25#else
26 StackFrame* stack_frame = iterator->NextFrame();
27 Code& code = Code::Handle();
28 Function& func = Function::Handle();
29 const Class& assert_error_class =
30 Class::Handle(ptr: Library::LookupCoreClass(class_name: Symbols::AssertionError()));
31 ASSERT(!assert_error_class.IsNull());
32 bool hit_assertion_error = false;
33 for (; stack_frame != nullptr; stack_frame = iterator->NextFrame()) {
34 code = stack_frame->LookupDartCode();
35 if (code.is_optimized()) {
36 InlinedFunctionsIterator inlined_iterator(code, stack_frame->pc());
37 while (!inlined_iterator.Done()) {
38 func = inlined_iterator.function();
39 if (hit_assertion_error) {
40 return func.script();
41 }
42 ASSERT(!hit_assertion_error);
43 hit_assertion_error = (func.Owner() == assert_error_class.ptr());
44 inlined_iterator.Advance();
45 }
46 continue;
47 } else {
48 func = code.function();
49 }
50 ASSERT(!func.IsNull());
51 if (hit_assertion_error) {
52 return func.script();
53 }
54 ASSERT(!hit_assertion_error);
55 hit_assertion_error = (func.Owner() == assert_error_class.ptr());
56 }
57 UNREACHABLE();
58 return Script::null();
59#endif // defined(DART_PRECOMPILED_RUNTIME)
60}
61
62// Allocate and throw a new AssertionError.
63// Arg0: index of the first token of the failed assertion.
64// Arg1: index of the first token after the failed assertion.
65// Arg2: Message object or null.
66// Return value: none, throws an exception.
67DEFINE_NATIVE_ENTRY(AssertionError_throwNew, 0, 3) {
68 // No need to type check the arguments. This function can only be called
69 // internally from the VM.
70 const TokenPosition assertion_start = TokenPosition::Deserialize(
71 value: Smi::CheckedHandle(zone, ptr: arguments->NativeArgAt(index: 0)).Value());
72 const TokenPosition assertion_end = TokenPosition::Deserialize(
73 value: Smi::CheckedHandle(zone, ptr: arguments->NativeArgAt(index: 1)).Value());
74
75 const Instance& message =
76 Instance::CheckedHandle(zone, ptr: arguments->NativeArgAt(index: 2));
77 const Array& args = Array::Handle(zone, ptr: Array::New(len: 5));
78
79 DartFrameIterator iterator(thread,
80 StackFrameIterator::kNoCrossThreadIteration);
81 iterator.NextFrame(); // Skip native call.
82 const Script& script = Script::Handle(ptr: FindScript(iterator: &iterator));
83
84 // Initialize argument 'failed_assertion' with source snippet.
85 auto& condition_text = String::Handle();
86 // Extract the assertion condition text (if source is available).
87 intptr_t from_line = -1, from_column = -1;
88 if (script.GetTokenLocation(token_pos: assertion_start, line: &from_line, column: &from_column)) {
89 // Extract the assertion condition text (if source is available).
90 intptr_t to_line, to_column;
91 script.GetTokenLocation(token_pos: assertion_end, line: &to_line, column: &to_column);
92 condition_text =
93 script.GetSnippet(from_line, from_column, to_line, to_column);
94 }
95 if (condition_text.IsNull()) {
96 condition_text = Symbols::OptimizedOut().ptr();
97 }
98 args.SetAt(index: 0, value: condition_text);
99
100 // Initialize location arguments starting at position 1.
101 args.SetAt(index: 1, value: String::Handle(ptr: script.url()));
102 args.SetAt(index: 2, value: Smi::Handle(ptr: Smi::New(value: from_line)));
103 args.SetAt(index: 3, value: Smi::Handle(ptr: Smi::New(value: from_column)));
104 args.SetAt(index: 4, value: message);
105
106 Exceptions::ThrowByType(type: Exceptions::kAssertion, arguments: args);
107 UNREACHABLE();
108 return Object::null();
109}
110
111// Allocate and throw a new AssertionError.
112// Arg0: Source code snippet of failed assertion.
113// Arg1: Line number.
114// Arg2: Column number.
115// Arg3: Message object or null.
116// Return value: none, throws an exception.
117DEFINE_NATIVE_ENTRY(AssertionError_throwNewSource, 0, 4) {
118 // No need to type check the arguments. This function can only be called
119 // internally from the VM.
120 const String& failed_assertion =
121 String::CheckedHandle(zone, ptr: arguments->NativeArgAt(index: 0));
122 const intptr_t line =
123 Smi::CheckedHandle(zone, ptr: arguments->NativeArgAt(index: 1)).Value();
124 const intptr_t column =
125 Smi::CheckedHandle(zone, ptr: arguments->NativeArgAt(index: 2)).Value();
126 const Instance& message =
127 Instance::CheckedHandle(zone, ptr: arguments->NativeArgAt(index: 3));
128
129 const Array& args = Array::Handle(zone, ptr: Array::New(len: 5));
130
131 DartFrameIterator iterator(thread,
132 StackFrameIterator::kNoCrossThreadIteration);
133 iterator.NextFrame(); // Skip native call.
134 const Script& script = Script::Handle(zone, ptr: FindScript(iterator: &iterator));
135
136 args.SetAt(index: 0, value: failed_assertion);
137 args.SetAt(index: 1, value: String::Handle(zone, ptr: script.url()));
138 args.SetAt(index: 2, value: Smi::Handle(zone, ptr: Smi::New(value: line)));
139 args.SetAt(index: 3, value: Smi::Handle(zone, ptr: Smi::New(value: column)));
140 args.SetAt(index: 4, value: message);
141
142 Exceptions::ThrowByType(type: Exceptions::kAssertion, arguments: args);
143 UNREACHABLE();
144 return Object::null();
145}
146
147// Allocate and throw a new TypeError.
148// Arg0: index of the token of the failed type check.
149// Arg1: src value.
150// Arg2: dst type.
151// Arg3: dst name.
152// Return value: none, throws an exception.
153DEFINE_NATIVE_ENTRY(TypeError_throwNew, 0, 4) {
154 // No need to type check the arguments. This function can only be called
155 // internally from the VM.
156 const TokenPosition location = TokenPosition::Deserialize(
157 value: Smi::CheckedHandle(zone, ptr: arguments->NativeArgAt(index: 0)).Value());
158 const Instance& src_value =
159 Instance::CheckedHandle(zone, ptr: arguments->NativeArgAt(index: 1));
160 const AbstractType& dst_type =
161 AbstractType::CheckedHandle(zone, ptr: arguments->NativeArgAt(index: 2));
162 const String& dst_name =
163 String::CheckedHandle(zone, ptr: arguments->NativeArgAt(index: 3));
164 const AbstractType& src_type =
165 AbstractType::Handle(ptr: src_value.GetType(space: Heap::kNew));
166 Exceptions::CreateAndThrowTypeError(location, src_type, dst_type, dst_name);
167 UNREACHABLE();
168 return Object::null();
169}
170
171// Rethrow an error with a stacktrace.
172DEFINE_NATIVE_ENTRY(Error_throwWithStackTrace, 0, 2) {
173 GET_NON_NULL_NATIVE_ARGUMENT(Instance, error, arguments->NativeArgAt(0));
174 GET_NON_NULL_NATIVE_ARGUMENT(Instance, stacktrace, arguments->NativeArgAt(1));
175 Exceptions::ThrowWithStackTrace(thread, exception: error, stacktrace);
176 return Object::null();
177}
178
179} // namespace dart
180

source code of flutter_engine/third_party/dart/runtime/lib/errors.cc