blob: e26f955f151388a93f71eab539693e6a66905bf6 [file] [log] [blame]
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +01001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "transaction.h"
18
19#include "base/stl_util.h"
20#include "base/logging.h"
21#include "gc/accounting/card_table-inl.h"
22#include "intern_table.h"
23#include "mirror/object-inl.h"
24#include "mirror/object_array-inl.h"
25
26#include <list>
27
28namespace art {
29
30// TODO: remove (only used for debugging purpose).
31static constexpr bool kEnableTransactionStats = false;
32
Sebastien Hertz1c80bec2015-02-03 11:58:06 +010033Transaction::Transaction()
34 : log_lock_("transaction log lock", kTransactionLogLock), aborted_(false) {
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080035 CHECK(Runtime::Current()->IsAotCompiler());
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010036}
37
38Transaction::~Transaction() {
39 if (kEnableTransactionStats) {
40 MutexLock mu(Thread::Current(), log_lock_);
41 size_t objects_count = object_logs_.size();
42 size_t field_values_count = 0;
43 for (auto it : object_logs_) {
44 field_values_count += it.second.Size();
45 }
46 size_t array_count = array_logs_.size();
47 size_t array_values_count = 0;
48 for (auto it : array_logs_) {
49 array_values_count += it.second.Size();
50 }
51 size_t string_count = intern_string_logs_.size();
52 LOG(INFO) << "Transaction::~Transaction"
53 << ": objects_count=" << objects_count
54 << ", field_values_count=" << field_values_count
55 << ", array_count=" << array_count
56 << ", array_values_count=" << array_values_count
57 << ", string_count=" << string_count;
58 }
59}
60
Sebastien Hertz1c80bec2015-02-03 11:58:06 +010061void Transaction::Abort(const std::string& abort_message) {
62 MutexLock mu(Thread::Current(), log_lock_);
63 // We may abort more than once if the java.lang.InternalError thrown at the
64 // time of the abort has been caught during execution of a class initializer.
65 // We just keep the message of the first abort because it will cause the
66 // transaction to be rolled back anyway.
67 if (!aborted_) {
68 aborted_ = true;
69 abort_message_ = abort_message;
70 }
71}
72
73void Transaction::ThrowInternalError(Thread* self) {
74 DCHECK(IsAborted());
75 std::string abort_msg(GetAbortMessage());
76 self->ThrowNewException(self->GetCurrentLocationForThrow(), "Ljava/lang/InternalError;",
77 abort_msg.c_str());
78}
79
80bool Transaction::IsAborted() {
81 MutexLock mu(Thread::Current(), log_lock_);
82 return aborted_;
83}
84
85const std::string& Transaction::GetAbortMessage() {
86 MutexLock mu(Thread::Current(), log_lock_);
87 return abort_message_;
88}
89
Fred Shih37f05ef2014-07-16 18:38:08 -070090void Transaction::RecordWriteFieldBoolean(mirror::Object* obj, MemberOffset field_offset,
91 uint8_t value, bool is_volatile) {
92 DCHECK(obj != nullptr);
93 MutexLock mu(Thread::Current(), log_lock_);
94 ObjectLog& object_log = object_logs_[obj];
95 object_log.LogBooleanValue(field_offset, value, is_volatile);
96}
97
98void Transaction::RecordWriteFieldByte(mirror::Object* obj, MemberOffset field_offset,
99 int8_t value, bool is_volatile) {
100 DCHECK(obj != nullptr);
101 MutexLock mu(Thread::Current(), log_lock_);
102 ObjectLog& object_log = object_logs_[obj];
103 object_log.LogByteValue(field_offset, value, is_volatile);
104}
105
106void Transaction::RecordWriteFieldChar(mirror::Object* obj, MemberOffset field_offset,
107 uint16_t value, bool is_volatile) {
108 DCHECK(obj != nullptr);
109 MutexLock mu(Thread::Current(), log_lock_);
110 ObjectLog& object_log = object_logs_[obj];
111 object_log.LogCharValue(field_offset, value, is_volatile);
112}
113
114
115void Transaction::RecordWriteFieldShort(mirror::Object* obj, MemberOffset field_offset,
116 int16_t value, bool is_volatile) {
117 DCHECK(obj != nullptr);
118 MutexLock mu(Thread::Current(), log_lock_);
119 ObjectLog& object_log = object_logs_[obj];
120 object_log.LogShortValue(field_offset, value, is_volatile);
121}
122
123
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100124void Transaction::RecordWriteField32(mirror::Object* obj, MemberOffset field_offset, uint32_t value,
125 bool is_volatile) {
126 DCHECK(obj != nullptr);
127 MutexLock mu(Thread::Current(), log_lock_);
128 ObjectLog& object_log = object_logs_[obj];
129 object_log.Log32BitsValue(field_offset, value, is_volatile);
130}
131
132void Transaction::RecordWriteField64(mirror::Object* obj, MemberOffset field_offset, uint64_t value,
133 bool is_volatile) {
134 DCHECK(obj != nullptr);
135 MutexLock mu(Thread::Current(), log_lock_);
136 ObjectLog& object_log = object_logs_[obj];
137 object_log.Log64BitsValue(field_offset, value, is_volatile);
138}
139
140void Transaction::RecordWriteFieldReference(mirror::Object* obj, MemberOffset field_offset,
141 mirror::Object* value, bool is_volatile) {
142 DCHECK(obj != nullptr);
143 MutexLock mu(Thread::Current(), log_lock_);
144 ObjectLog& object_log = object_logs_[obj];
145 object_log.LogReferenceValue(field_offset, value, is_volatile);
146}
147
148void Transaction::RecordWriteArray(mirror::Array* array, size_t index, uint64_t value) {
149 DCHECK(array != nullptr);
150 DCHECK(array->IsArrayInstance());
Sebastien Hertzee1d79a2014-02-21 15:46:30 +0100151 DCHECK(!array->IsObjectArray());
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100152 MutexLock mu(Thread::Current(), log_lock_);
153 ArrayLog& array_log = array_logs_[array];
154 array_log.LogValue(index, value);
155}
156
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700157void Transaction::RecordStrongStringInsertion(mirror::String* s) {
158 InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kInsert);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100159 LogInternedString(log);
160}
161
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700162void Transaction::RecordWeakStringInsertion(mirror::String* s) {
163 InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kInsert);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100164 LogInternedString(log);
165}
166
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700167void Transaction::RecordStrongStringRemoval(mirror::String* s) {
168 InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kRemove);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100169 LogInternedString(log);
170}
171
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700172void Transaction::RecordWeakStringRemoval(mirror::String* s) {
173 InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kRemove);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100174 LogInternedString(log);
175}
176
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700177void Transaction::LogInternedString(const InternStringLog& log) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100178 Locks::intern_table_lock_->AssertExclusiveHeld(Thread::Current());
179 MutexLock mu(Thread::Current(), log_lock_);
180 intern_string_logs_.push_front(log);
181}
182
Sebastien Hertz1c80bec2015-02-03 11:58:06 +0100183void Transaction::Rollback() {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100184 CHECK(!Runtime::Current()->IsActiveTransaction());
185 Thread* self = Thread::Current();
186 self->AssertNoPendingException();
187 MutexLock mu1(self, *Locks::intern_table_lock_);
188 MutexLock mu2(self, log_lock_);
189 UndoObjectModifications();
190 UndoArrayModifications();
191 UndoInternStringTableModifications();
192}
193
194void Transaction::UndoObjectModifications() {
195 // TODO we may not need to restore objects allocated during this transaction. Or we could directly
196 // remove them from the heap.
197 for (auto it : object_logs_) {
198 it.second.Undo(it.first);
199 }
200 object_logs_.clear();
201}
202
203void Transaction::UndoArrayModifications() {
204 // TODO we may not need to restore array allocated during this transaction. Or we could directly
205 // remove them from the heap.
206 for (auto it : array_logs_) {
207 it.second.Undo(it.first);
208 }
209 array_logs_.clear();
210}
211
212void Transaction::UndoInternStringTableModifications() {
213 InternTable* const intern_table = Runtime::Current()->GetInternTable();
214 // We want to undo each operation from the most recent to the oldest. List has been filled so the
215 // most recent operation is at list begin so just have to iterate over it.
216 for (InternStringLog& string_log : intern_string_logs_) {
217 string_log.Undo(intern_table);
218 }
219 intern_string_logs_.clear();
220}
221
222void Transaction::VisitRoots(RootCallback* callback, void* arg) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100223 MutexLock mu(Thread::Current(), log_lock_);
224 VisitObjectLogs(callback, arg);
225 VisitArrayLogs(callback, arg);
226 VisitStringLogs(callback, arg);
227}
228
229void Transaction::VisitObjectLogs(RootCallback* callback, void* arg) {
230 // List of moving roots.
231 typedef std::pair<mirror::Object*, mirror::Object*> ObjectPair;
232 std::list<ObjectPair> moving_roots;
233
234 // Visit roots.
235 for (auto it : object_logs_) {
236 it.second.VisitRoots(callback, arg);
237 mirror::Object* old_root = it.first;
Mathieu Chartier815873e2014-02-13 18:02:13 -0800238 mirror::Object* new_root = old_root;
Mathieu Chartiere34fa1d2015-01-14 14:55:47 -0800239 callback(&new_root, arg, RootInfo(kRootUnknown));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100240 if (new_root != old_root) {
241 moving_roots.push_back(std::make_pair(old_root, new_root));
242 }
243 }
244
245 // Update object logs with moving roots.
246 for (const ObjectPair& pair : moving_roots) {
247 mirror::Object* old_root = pair.first;
248 mirror::Object* new_root = pair.second;
249 auto old_root_it = object_logs_.find(old_root);
250 CHECK(old_root_it != object_logs_.end());
251 CHECK(object_logs_.find(new_root) == object_logs_.end());
252 object_logs_.insert(std::make_pair(new_root, old_root_it->second));
253 object_logs_.erase(old_root_it);
254 }
255}
256
257void Transaction::VisitArrayLogs(RootCallback* callback, void* arg) {
258 // List of moving roots.
259 typedef std::pair<mirror::Array*, mirror::Array*> ArrayPair;
260 std::list<ArrayPair> moving_roots;
261
262 for (auto it : array_logs_) {
263 mirror::Array* old_root = it.first;
Sebastien Hertzee1d79a2014-02-21 15:46:30 +0100264 CHECK(!old_root->IsObjectArray());
Mathieu Chartier815873e2014-02-13 18:02:13 -0800265 mirror::Array* new_root = old_root;
Mathieu Chartiere34fa1d2015-01-14 14:55:47 -0800266 callback(reinterpret_cast<mirror::Object**>(&new_root), arg, RootInfo(kRootUnknown));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100267 if (new_root != old_root) {
268 moving_roots.push_back(std::make_pair(old_root, new_root));
269 }
270 }
271
272 // Update array logs with moving roots.
273 for (const ArrayPair& pair : moving_roots) {
274 mirror::Array* old_root = pair.first;
275 mirror::Array* new_root = pair.second;
276 auto old_root_it = array_logs_.find(old_root);
277 CHECK(old_root_it != array_logs_.end());
278 CHECK(array_logs_.find(new_root) == array_logs_.end());
279 array_logs_.insert(std::make_pair(new_root, old_root_it->second));
280 array_logs_.erase(old_root_it);
281 }
282}
283
284void Transaction::VisitStringLogs(RootCallback* callback, void* arg) {
285 for (InternStringLog& log : intern_string_logs_) {
286 log.VisitRoots(callback, arg);
287 }
288}
289
Fred Shih37f05ef2014-07-16 18:38:08 -0700290void Transaction::ObjectLog::LogBooleanValue(MemberOffset offset, uint8_t value, bool is_volatile) {
291 LogValue(ObjectLog::kBoolean, offset, value, is_volatile);
292}
293
294void Transaction::ObjectLog::LogByteValue(MemberOffset offset, int8_t value, bool is_volatile) {
295 LogValue(ObjectLog::kByte, offset, value, is_volatile);
296}
297
298void Transaction::ObjectLog::LogCharValue(MemberOffset offset, uint16_t value, bool is_volatile) {
299 LogValue(ObjectLog::kChar, offset, value, is_volatile);
300}
301
302void Transaction::ObjectLog::LogShortValue(MemberOffset offset, int16_t value, bool is_volatile) {
303 LogValue(ObjectLog::kShort, offset, value, is_volatile);
304}
305
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100306void Transaction::ObjectLog::Log32BitsValue(MemberOffset offset, uint32_t value, bool is_volatile) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700307 LogValue(ObjectLog::k32Bits, offset, value, is_volatile);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100308}
309
310void Transaction::ObjectLog::Log64BitsValue(MemberOffset offset, uint64_t value, bool is_volatile) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700311 LogValue(ObjectLog::k64Bits, offset, value, is_volatile);
312}
313
314void Transaction::ObjectLog::LogReferenceValue(MemberOffset offset, mirror::Object* obj, bool is_volatile) {
315 LogValue(ObjectLog::kReference, offset, reinterpret_cast<uintptr_t>(obj), is_volatile);
316}
317
318void Transaction::ObjectLog::LogValue(ObjectLog::FieldValueKind kind,
319 MemberOffset offset, uint64_t value, bool is_volatile) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100320 auto it = field_values_.find(offset.Uint32Value());
321 if (it == field_values_.end()) {
322 ObjectLog::FieldValue field_value;
323 field_value.value = value;
324 field_value.is_volatile = is_volatile;
Fred Shih37f05ef2014-07-16 18:38:08 -0700325 field_value.kind = kind;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100326 field_values_.insert(std::make_pair(offset.Uint32Value(), field_value));
327 }
328}
329
330void Transaction::ObjectLog::Undo(mirror::Object* obj) {
331 for (auto& it : field_values_) {
332 // Garbage collector needs to access object's class and array's length. So we don't rollback
333 // these values.
334 MemberOffset field_offset(it.first);
335 if (field_offset.Uint32Value() == mirror::Class::ClassOffset().Uint32Value()) {
336 // Skip Object::class field.
337 continue;
338 }
339 if (obj->IsArrayInstance() &&
340 field_offset.Uint32Value() == mirror::Array::LengthOffset().Uint32Value()) {
341 // Skip Array::length field.
342 continue;
343 }
344 FieldValue& field_value = it.second;
345 UndoFieldWrite(obj, field_offset, field_value);
346 }
347}
348
349void Transaction::ObjectLog::UndoFieldWrite(mirror::Object* obj, MemberOffset field_offset,
350 const FieldValue& field_value) {
351 // TODO We may want to abort a transaction while still being in transaction mode. In this case,
352 // we'd need to disable the check.
353 constexpr bool kCheckTransaction = true;
354 switch (field_value.kind) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700355 case kBoolean:
356 if (UNLIKELY(field_value.is_volatile)) {
357 obj->SetFieldBooleanVolatile<false, kCheckTransaction>(field_offset,
358 static_cast<bool>(field_value.value));
359 } else {
360 obj->SetFieldBoolean<false, kCheckTransaction>(field_offset,
361 static_cast<bool>(field_value.value));
362 }
363 break;
364 case kByte:
365 if (UNLIKELY(field_value.is_volatile)) {
366 obj->SetFieldByteVolatile<false, kCheckTransaction>(field_offset,
367 static_cast<int8_t>(field_value.value));
368 } else {
369 obj->SetFieldByte<false, kCheckTransaction>(field_offset,
370 static_cast<int8_t>(field_value.value));
371 }
372 break;
373 case kChar:
374 if (UNLIKELY(field_value.is_volatile)) {
375 obj->SetFieldCharVolatile<false, kCheckTransaction>(field_offset,
376 static_cast<uint16_t>(field_value.value));
377 } else {
378 obj->SetFieldChar<false, kCheckTransaction>(field_offset,
379 static_cast<uint16_t>(field_value.value));
380 }
381 break;
382 case kShort:
383 if (UNLIKELY(field_value.is_volatile)) {
384 obj->SetFieldShortVolatile<false, kCheckTransaction>(field_offset,
385 static_cast<int16_t>(field_value.value));
386 } else {
387 obj->SetFieldShort<false, kCheckTransaction>(field_offset,
388 static_cast<int16_t>(field_value.value));
389 }
390 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100391 case k32Bits:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700392 if (UNLIKELY(field_value.is_volatile)) {
393 obj->SetField32Volatile<false, kCheckTransaction>(field_offset,
394 static_cast<uint32_t>(field_value.value));
395 } else {
396 obj->SetField32<false, kCheckTransaction>(field_offset,
397 static_cast<uint32_t>(field_value.value));
398 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100399 break;
400 case k64Bits:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700401 if (UNLIKELY(field_value.is_volatile)) {
402 obj->SetField64Volatile<false, kCheckTransaction>(field_offset, field_value.value);
403 } else {
404 obj->SetField64<false, kCheckTransaction>(field_offset, field_value.value);
405 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100406 break;
407 case kReference:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700408 if (UNLIKELY(field_value.is_volatile)) {
409 obj->SetFieldObjectVolatile<false, kCheckTransaction>(field_offset,
410 reinterpret_cast<mirror::Object*>(field_value.value));
411 } else {
412 obj->SetFieldObject<false, kCheckTransaction>(field_offset,
413 reinterpret_cast<mirror::Object*>(field_value.value));
414 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100415 break;
416 default:
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700417 LOG(FATAL) << "Unknown value kind " << static_cast<int>(field_value.kind);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100418 break;
419 }
420}
421
422void Transaction::ObjectLog::VisitRoots(RootCallback* callback, void* arg) {
423 for (auto it : field_values_) {
424 FieldValue& field_value = it.second;
425 if (field_value.kind == ObjectLog::kReference) {
Mathieu Chartier815873e2014-02-13 18:02:13 -0800426 mirror::Object* obj =
427 reinterpret_cast<mirror::Object*>(static_cast<uintptr_t>(field_value.value));
Sebastien Hertza559ccb2014-02-21 15:36:13 +0100428 if (obj != nullptr) {
Mathieu Chartiere34fa1d2015-01-14 14:55:47 -0800429 callback(&obj, arg, RootInfo(kRootUnknown));
Sebastien Hertza559ccb2014-02-21 15:36:13 +0100430 field_value.value = reinterpret_cast<uintptr_t>(obj);
431 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100432 }
433 }
434}
435
436void Transaction::InternStringLog::Undo(InternTable* intern_table) {
437 DCHECK(intern_table != nullptr);
438 switch (string_op_) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700439 case InternStringLog::kInsert: {
440 switch (string_kind_) {
441 case InternStringLog::kStrongString:
442 intern_table->RemoveStrongFromTransaction(str_);
443 break;
444 case InternStringLog::kWeakString:
445 intern_table->RemoveWeakFromTransaction(str_);
446 break;
447 default:
448 LOG(FATAL) << "Unknown interned string kind";
449 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100450 }
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700451 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100452 }
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700453 case InternStringLog::kRemove: {
454 switch (string_kind_) {
455 case InternStringLog::kStrongString:
456 intern_table->InsertStrongFromTransaction(str_);
457 break;
458 case InternStringLog::kWeakString:
459 intern_table->InsertWeakFromTransaction(str_);
460 break;
461 default:
462 LOG(FATAL) << "Unknown interned string kind";
463 break;
464 }
465 break;
466 }
467 default:
468 LOG(FATAL) << "Unknown interned string op";
469 break;
470 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100471}
472
473void Transaction::InternStringLog::VisitRoots(RootCallback* callback, void* arg) {
Mathieu Chartiere34fa1d2015-01-14 14:55:47 -0800474 callback(reinterpret_cast<mirror::Object**>(&str_), arg, RootInfo(kRootInternedString));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100475}
476
477void Transaction::ArrayLog::LogValue(size_t index, uint64_t value) {
478 auto it = array_values_.find(index);
479 if (it == array_values_.end()) {
480 array_values_.insert(std::make_pair(index, value));
481 }
482}
483
484void Transaction::ArrayLog::Undo(mirror::Array* array) {
485 DCHECK(array != nullptr);
486 DCHECK(array->IsArrayInstance());
487 Primitive::Type type = array->GetClass()->GetComponentType()->GetPrimitiveType();
488 for (auto it : array_values_) {
489 UndoArrayWrite(array, type, it.first, it.second);
490 }
491}
492
493void Transaction::ArrayLog::UndoArrayWrite(mirror::Array* array, Primitive::Type array_type,
494 size_t index, uint64_t value) {
495 // TODO We may want to abort a transaction while still being in transaction mode. In this case,
496 // we'd need to disable the check.
497 switch (array_type) {
498 case Primitive::kPrimBoolean:
499 array->AsBooleanArray()->SetWithoutChecks<false>(index, static_cast<uint8_t>(value));
500 break;
501 case Primitive::kPrimByte:
502 array->AsByteArray()->SetWithoutChecks<false>(index, static_cast<int8_t>(value));
503 break;
504 case Primitive::kPrimChar:
505 array->AsCharArray()->SetWithoutChecks<false>(index, static_cast<uint16_t>(value));
506 break;
507 case Primitive::kPrimShort:
508 array->AsShortArray()->SetWithoutChecks<false>(index, static_cast<int16_t>(value));
509 break;
510 case Primitive::kPrimInt:
511 array->AsIntArray()->SetWithoutChecks<false>(index, static_cast<int32_t>(value));
512 break;
513 case Primitive::kPrimFloat:
514 array->AsFloatArray()->SetWithoutChecks<false>(index, static_cast<float>(value));
515 break;
516 case Primitive::kPrimLong:
517 array->AsLongArray()->SetWithoutChecks<false>(index, static_cast<int64_t>(value));
518 break;
519 case Primitive::kPrimDouble:
520 array->AsDoubleArray()->SetWithoutChecks<false>(index, static_cast<double>(value));
521 break;
Sebastien Hertzee1d79a2014-02-21 15:46:30 +0100522 case Primitive::kPrimNot:
523 LOG(FATAL) << "ObjectArray should be treated as Object";
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100524 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100525 default:
526 LOG(FATAL) << "Unsupported type " << array_type;
527 }
528}
529
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100530} // namespace art