Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/precompiler.h" | 5 #include "vm/precompiler.h" |
| 6 | 6 |
| 7 #include "vm/aot_optimizer.h" | 7 #include "vm/aot_optimizer.h" |
| 8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
| 9 #include "vm/ast_printer.h" | 9 #include "vm/ast_printer.h" |
| 10 #include "vm/branch_optimizer.h" | 10 #include "vm/branch_optimizer.h" |
| (...skipping 471 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 482 I->object_store()->set_async_star_move_next_helper(null_function); | 482 I->object_store()->set_async_star_move_next_helper(null_function); |
| 483 I->object_store()->set_complete_on_async_return(null_function); | 483 I->object_store()->set_complete_on_async_return(null_function); |
| 484 I->object_store()->set_async_star_stream_controller(null_class); | 484 I->object_store()->set_async_star_stream_controller(null_class); |
| 485 DropLibraryEntries(); | 485 DropLibraryEntries(); |
| 486 } | 486 } |
| 487 DropClasses(); | 487 DropClasses(); |
| 488 DropLibraries(); | 488 DropLibraries(); |
| 489 | 489 |
| 490 BindStaticCalls(); | 490 BindStaticCalls(); |
| 491 SwitchICCalls(); | 491 SwitchICCalls(); |
| 492 Obfuscate(); | |
| 492 | 493 |
|
rmacnak
2017/08/23 01:16:50
We should clear the obfuscation table from the obj
Vyacheslav Egorov (Google)
2017/08/23 15:54:52
This is done at the end of Obfuscate()
| |
| 493 ProgramVisitor::Dedup(); | 494 ProgramVisitor::Dedup(); |
| 494 | 495 |
| 495 zone_ = NULL; | 496 zone_ = NULL; |
| 496 } | 497 } |
| 497 | 498 |
| 498 intptr_t symbols_before = -1; | 499 intptr_t symbols_before = -1; |
| 499 intptr_t symbols_after = -1; | 500 intptr_t symbols_after = -1; |
| 500 intptr_t capacity = -1; | 501 intptr_t capacity = -1; |
| 501 if (FLAG_trace_precompiler) { | 502 if (FLAG_trace_precompiler) { |
| 502 Symbols::GetStats(I, &symbols_before, &capacity); | 503 Symbols::GetStats(I, &symbols_before, &capacity); |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 603 current->field_->set_guarded_cid(cid); | 604 current->field_->set_guarded_cid(cid); |
| 604 current->field_->set_is_nullable(cid == kNullCid || cid == kDynamicCid); | 605 current->field_->set_is_nullable(cid == kNullCid || cid == kDynamicCid); |
| 605 if (FLAG_trace_precompiler) { | 606 if (FLAG_trace_precompiler) { |
| 606 THR_Print( | 607 THR_Print( |
| 607 "Field %s <- Type %s\n", current->field_->ToCString(), | 608 "Field %s <- Type %s\n", current->field_->ToCString(), |
| 608 Class::Handle(T->isolate()->class_table()->At(cid)).ToCString()); | 609 Class::Handle(T->isolate()->class_table()->At(cid)).ToCString()); |
| 609 } | 610 } |
| 610 } | 611 } |
| 611 } | 612 } |
| 612 | 613 |
| 613 void Precompiler::AddRoots(Dart_QualifiedFunctionName embedder_entry_points[]) { | 614 static Dart_QualifiedFunctionName vm_entry_points[] = { |
| 614 // Note that <rootlibrary>.main is not a root. The appropriate main will be | |
| 615 // discovered through _getMainClosure. | |
| 616 | |
| 617 AddSelector(Symbols::NoSuchMethod()); | |
| 618 | |
| 619 AddSelector(Symbols::Call()); // For speed, not correctness. | |
| 620 | |
| 621 // Allocated from C++. | |
| 622 Class& cls = Class::Handle(Z); | |
| 623 for (intptr_t cid = kInstanceCid; cid < kNumPredefinedCids; cid++) { | |
| 624 ASSERT(isolate()->class_table()->IsValidIndex(cid)); | |
| 625 if (!isolate()->class_table()->HasValidClassAt(cid)) { | |
| 626 continue; | |
| 627 } | |
| 628 if ((cid == kDynamicCid) || (cid == kVoidCid) || | |
| 629 (cid == kFreeListElement) || (cid == kForwardingCorpse)) { | |
| 630 continue; | |
| 631 } | |
| 632 cls = isolate()->class_table()->At(cid); | |
| 633 AddInstantiatedClass(cls); | |
| 634 } | |
| 635 | |
| 636 Dart_QualifiedFunctionName vm_entry_points[] = { | |
| 637 // Functions | 615 // Functions |
| 638 {"dart:core", "::", "_completeDeferredLoads"}, | 616 {"dart:core", "::", "_completeDeferredLoads"}, |
| 639 {"dart:core", "::", "identityHashCode"}, | 617 {"dart:core", "::", "identityHashCode"}, |
| 640 {"dart:core", "AbstractClassInstantiationError", | 618 {"dart:core", "AbstractClassInstantiationError", |
| 641 "AbstractClassInstantiationError._create"}, | 619 "AbstractClassInstantiationError._create"}, |
| 642 {"dart:core", "ArgumentError", "ArgumentError."}, | 620 {"dart:core", "ArgumentError", "ArgumentError."}, |
| 643 {"dart:core", "ArgumentError", "ArgumentError.value"}, | 621 {"dart:core", "ArgumentError", "ArgumentError.value"}, |
| 644 {"dart:core", "CyclicInitializationError", "CyclicInitializationError."}, | 622 {"dart:core", "CyclicInitializationError", "CyclicInitializationError."}, |
| 645 {"dart:core", "FallThroughError", "FallThroughError._create"}, | 623 {"dart:core", "FallThroughError", "FallThroughError._create"}, |
| 646 {"dart:core", "FormatException", "FormatException."}, | 624 {"dart:core", "FormatException", "FormatException."}, |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 668 #if !defined(PRODUCT) | 646 #if !defined(PRODUCT) |
| 669 {"dart:_vmservice", "::", "_registerIsolate"}, | 647 {"dart:_vmservice", "::", "_registerIsolate"}, |
| 670 {"dart:developer", "Metrics", "_printMetrics"}, | 648 {"dart:developer", "Metrics", "_printMetrics"}, |
| 671 {"dart:developer", "::", "_runExtension"}, | 649 {"dart:developer", "::", "_runExtension"}, |
| 672 {"dart:isolate", "::", "_runPendingImmediateCallback"}, | 650 {"dart:isolate", "::", "_runPendingImmediateCallback"}, |
| 673 #endif // !PRODUCT | 651 #endif // !PRODUCT |
| 674 // Fields | 652 // Fields |
| 675 {"dart:core", "Error", "_stackTrace"}, | 653 {"dart:core", "Error", "_stackTrace"}, |
| 676 {"dart:math", "_Random", "_state"}, | 654 {"dart:math", "_Random", "_state"}, |
| 677 {NULL, NULL, NULL} // Must be terminated with NULL entries. | 655 {NULL, NULL, NULL} // Must be terminated with NULL entries. |
| 678 }; | 656 }; |
| 657 | |
| 658 void Precompiler::AddRoots(Dart_QualifiedFunctionName embedder_entry_points[]) { | |
| 659 // Note that <rootlibrary>.main is not a root. The appropriate main will be | |
| 660 // discovered through _getMainClosure. | |
| 661 | |
| 662 AddSelector(Symbols::NoSuchMethod()); | |
| 663 | |
| 664 AddSelector(Symbols::Call()); // For speed, not correctness. | |
| 665 | |
| 666 // Allocated from C++. | |
| 667 Class& cls = Class::Handle(Z); | |
| 668 for (intptr_t cid = kInstanceCid; cid < kNumPredefinedCids; cid++) { | |
| 669 ASSERT(isolate()->class_table()->IsValidIndex(cid)); | |
| 670 if (!isolate()->class_table()->HasValidClassAt(cid)) { | |
| 671 continue; | |
| 672 } | |
| 673 if ((cid == kDynamicCid) || (cid == kVoidCid) || | |
| 674 (cid == kFreeListElement) || (cid == kForwardingCorpse)) { | |
| 675 continue; | |
| 676 } | |
| 677 cls = isolate()->class_table()->At(cid); | |
| 678 AddInstantiatedClass(cls); | |
| 679 } | |
| 679 | 680 |
| 680 AddEntryPoints(vm_entry_points); | 681 AddEntryPoints(vm_entry_points); |
| 681 AddEntryPoints(embedder_entry_points); | 682 AddEntryPoints(embedder_entry_points); |
| 682 const Library& lib = Library::Handle(I->object_store()->root_library()); | 683 const Library& lib = Library::Handle(I->object_store()->root_library()); |
| 683 const String& name = String::Handle(String::New("main")); | 684 const String& name = String::Handle(String::New("main")); |
| 684 const Object& main_closure = Object::Handle(lib.GetFunctionClosure(name)); | 685 const Object& main_closure = Object::Handle(lib.GetFunctionClosure(name)); |
| 685 if (main_closure.IsClosure()) { | 686 if (main_closure.IsClosure()) { |
| 686 if (lib.LookupLocalFunction(name) == Function::null()) { | 687 if (lib.LookupLocalFunction(name) == Function::null()) { |
| 687 // Check whether the function is in exported namespace of library, in | 688 // Check whether the function is in exported namespace of library, in |
| 688 // this case we have to retain the root library caches. | 689 // this case we have to retain the root library caches. |
| (...skipping 1582 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2271 Code& target_code_; | 2272 Code& target_code_; |
| 2272 UnlinkedCallSet canonical_unlinked_calls_; | 2273 UnlinkedCallSet canonical_unlinked_calls_; |
| 2273 }; | 2274 }; |
| 2274 | 2275 |
| 2275 ASSERT(!I->compilation_allowed()); | 2276 ASSERT(!I->compilation_allowed()); |
| 2276 SwitchICCallsVisitor visitor(Z); | 2277 SwitchICCallsVisitor visitor(Z); |
| 2277 ProgramVisitor::VisitFunctions(&visitor); | 2278 ProgramVisitor::VisitFunctions(&visitor); |
| 2278 #endif | 2279 #endif |
| 2279 } | 2280 } |
| 2280 | 2281 |
| 2282 void Precompiler::Obfuscate() { | |
| 2283 // TODO(dartbug.com/XXX) remove URIs from Scripts and Libraries. | |
| 2284 | |
| 2285 // Discard obfuscation mappings to avoid including them into snapshot. | |
| 2286 I->object_store()->set_obfuscation_map(Array::Handle(Z)); | |
| 2287 } | |
| 2288 | |
| 2281 void Precompiler::FinalizeAllClasses() { | 2289 void Precompiler::FinalizeAllClasses() { |
| 2282 Library& lib = Library::Handle(Z); | 2290 Library& lib = Library::Handle(Z); |
| 2283 Class& cls = Class::Handle(Z); | 2291 Class& cls = Class::Handle(Z); |
| 2284 | 2292 |
| 2285 for (intptr_t i = 0; i < libraries_.Length(); i++) { | 2293 for (intptr_t i = 0; i < libraries_.Length(); i++) { |
| 2286 lib ^= libraries_.At(i); | 2294 lib ^= libraries_.At(i); |
| 2287 if (!lib.Loaded()) { | 2295 if (!lib.Loaded()) { |
| 2288 String& uri = String::Handle(Z, lib.url()); | 2296 String& uri = String::Handle(Z, lib.url()); |
| 2289 String& msg = String::Handle( | 2297 String& msg = String::Handle( |
| 2290 Z, | 2298 Z, |
| (...skipping 1032 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3323 FieldTypeMap* field_type_map) { | 3331 FieldTypeMap* field_type_map) { |
| 3324 VMTagScope tagScope(thread, VMTag::kCompileUnoptimizedTagId); | 3332 VMTagScope tagScope(thread, VMTag::kCompileUnoptimizedTagId); |
| 3325 TIMELINE_FUNCTION_COMPILATION_DURATION(thread, "CompileFunction", function); | 3333 TIMELINE_FUNCTION_COMPILATION_DURATION(thread, "CompileFunction", function); |
| 3326 | 3334 |
| 3327 ASSERT(FLAG_precompiled_mode); | 3335 ASSERT(FLAG_precompiled_mode); |
| 3328 const bool optimized = function.IsOptimizable(); // False for natives. | 3336 const bool optimized = function.IsOptimizable(); // False for natives. |
| 3329 DartPrecompilationPipeline pipeline(zone, field_type_map); | 3337 DartPrecompilationPipeline pipeline(zone, field_type_map); |
| 3330 return PrecompileFunctionHelper(precompiler, &pipeline, function, optimized); | 3338 return PrecompileFunctionHelper(precompiler, &pipeline, function, optimized); |
| 3331 } | 3339 } |
| 3332 | 3340 |
| 3341 Obfuscator::Obfuscator(Thread* thread, const String& private_key) | |
| 3342 : state_(NULL) { | |
| 3343 Isolate* isolate = thread->isolate(); | |
| 3344 Zone* zone = thread->zone(); | |
| 3345 | |
| 3346 if (isolate->obfuscate()) { | |
| 3347 ObjectStore* store = thread->isolate()->object_store(); | |
| 3348 Array& obfuscation_state = Array::Handle(zone, store->obfuscation_map()); | |
| 3349 | |
| 3350 if (store->obfuscation_map() == Array::null()) { | |
| 3351 const int kInitialPrivateCapacity = 256; | |
| 3352 obfuscation_state = Array::New(kSavedStateSize); | |
| 3353 obfuscation_state.SetAt( | |
| 3354 1, Array::Handle(zone, HashTables::New<ObfuscationMap>( | |
| 3355 kInitialPrivateCapacity, Heap::kOld))); | |
| 3356 } | |
| 3357 | |
| 3358 state_ = | |
| 3359 new (zone) ObfuscationState(thread, obfuscation_state, private_key); | |
| 3360 | |
| 3361 if (store->obfuscation_map() == Array::null()) { | |
| 3362 InitializeRenamingMap(isolate); | |
| 3363 } | |
| 3364 } | |
| 3365 } | |
| 3366 | |
| 3367 Obfuscator::~Obfuscator() { | |
| 3368 if (state_ != NULL) { | |
| 3369 state_->SaveState(); | |
| 3370 } | |
| 3371 } | |
| 3372 | |
| 3373 void Obfuscator::InitializeRenamingMap(Isolate* isolate) { | |
| 3374 // Prevent renaming of classes and method names mentioned in the | |
| 3375 // entry points lists. | |
| 3376 PreventRenaming(vm_entry_points); | |
| 3377 PreventRenaming(isolate->embedder_entry_points()); | |
| 3378 | |
| 3379 // Prevent renaming of all pseudo-keywords and operators. | |
| 3380 // Note: not all pseudo-keywords are mentioned in DART_KEYWORD_LIST | |
| 3381 // (for example 'hide', 'show' and async related keywords are omitted). | |
| 3382 // Those are protected from renaming as part of all symbols. | |
| 3383 #define PREVENT_RENAMING(name, value, priority, attr) \ | |
| 3384 do { \ | |
| 3385 if (Token::CanBeOverloaded(Token::name) || \ | |
| 3386 ((Token::attr & Token::kPseudoKeyword) != 0)) { \ | |
| 3387 PreventRenaming(value); \ | |
| 3388 } \ | |
| 3389 } while (0); | |
| 3390 | |
| 3391 DART_TOKEN_LIST(PREVENT_RENAMING) | |
| 3392 DART_KEYWORD_LIST(PREVENT_RENAMING) | |
| 3393 #undef PREVENT_RENAMING | |
| 3394 | |
| 3395 // Protect all symbols from renaming. | |
| 3396 #define PREVENT_RENAMING(name, value) PreventRenaming(value); | |
| 3397 PREDEFINED_SYMBOLS_LIST(PREVENT_RENAMING) | |
| 3398 #undef PREVENT_RENAMING | |
| 3399 | |
| 3400 // Protect NativeFieldWrapperClassX names from being obfuscated. Those | |
| 3401 // classes are created manually by the runtime system. | |
| 3402 // TODO(dartbug.com/XXX) instead call to Obfuscator::Rename from a place | |
| 3403 // where these are created. | |
| 3404 PreventRenaming("NativeFieldWrapperClass1"); | |
| 3405 PreventRenaming("NativeFieldWrapperClass2"); | |
| 3406 PreventRenaming("NativeFieldWrapperClass3"); | |
| 3407 PreventRenaming("NativeFieldWrapperClass4"); | |
| 3408 | |
| 3409 // Prevent renaming of ClassID.cid* fields. These fields are injected by | |
| 3410 // runtime. | |
| 3411 // TODO(dartbug.com/XXX) instead call to Obfuscator::Rename from a place | |
| 3412 // where these are created. | |
| 3413 #define CLASS_LIST_WITH_NULL(V) \ | |
| 3414 V(Null) \ | |
| 3415 CLASS_LIST_NO_OBJECT(V) | |
| 3416 #define PREVENT_RENAMING(clazz) PreventRenaming("cid" #clazz); | |
| 3417 CLASS_LIST_WITH_NULL(PREVENT_RENAMING) | |
| 3418 #undef PREVENT_RENAMING | |
| 3419 #undef CLASS_LIST_WITH_NULL | |
| 3420 | |
| 3421 // Prevent renaming of methods that are looked up by method recognizer. | |
| 3422 // TODO(dartbug.com/XXX) instead call to Obfuscator::Rename from a place | |
| 3423 // where these are looked up. | |
| 3424 #define PREVENT_RENAMING(class_name, function_name, recognized_enum, \ | |
| 3425 result_type, fingerprint) \ | |
| 3426 do { \ | |
| 3427 PreventRenaming(#class_name); \ | |
| 3428 PreventRenaming(#function_name); \ | |
| 3429 } while (0); | |
| 3430 RECOGNIZED_LIST(PREVENT_RENAMING) | |
| 3431 #undef PREVENT_RENAMING | |
| 3432 | |
| 3433 // Prevent renaming of methods that are looked up by method recognizer. | |
| 3434 // TODO(dartbug.com/XXX) instead call to Obfuscator::Rename from a place | |
| 3435 // where these are looked up. | |
| 3436 #define PREVENT_RENAMING(class_name, function_name, recognized_enum, \ | |
| 3437 fingerprint) \ | |
| 3438 do { \ | |
| 3439 PreventRenaming(#class_name); \ | |
| 3440 PreventRenaming(#function_name); \ | |
| 3441 } while (0); | |
| 3442 INLINE_WHITE_LIST(PREVENT_RENAMING) | |
| 3443 INLINE_BLACK_LIST(PREVENT_RENAMING) | |
| 3444 POLYMORPHIC_TARGET_LIST(PREVENT_RENAMING) | |
| 3445 #undef PREVENT_RENAMING | |
| 3446 | |
| 3447 // These are not mentioned by entry points but are still looked up by name. | |
|
rmacnak
2017/08/23 01:16:50
They should be mentioned by the entry points. We'r
Vyacheslav Egorov (Google)
2017/08/23 15:54:52
Done.
| |
| 3448 PreventRenaming("_resolveScriptUri"); | |
| 3449 PreventRenaming("_printClosure"); | |
| 3450 PreventRenaming("_uriBaseClosure"); | |
| 3451 PreventRenaming("_isolateId"); | |
| 3452 PreventRenaming("_loadPort"); | |
| 3453 PreventRenaming("_ip"); | |
| 3454 PreventRenaming("_port"); | |
| 3455 PreventRenaming("_autoStart"); | |
| 3456 PreventRenaming("_originCheckDisabled"); | |
| 3457 PreventRenaming("_isWindows"); | |
| 3458 PreventRenaming("_isFuchsia"); | |
| 3459 PreventRenaming("_traceLoading"); | |
| 3460 PreventRenaming("_getWatchSignalInternal"); | |
| 3461 PreventRenaming("_signalWatch"); | |
| 3462 PreventRenaming("main"); | |
| 3463 | |
| 3464 // Fast path for common conditional import. See Deobfuscate method. | |
| 3465 PreventRenaming("dart"); | |
| 3466 PreventRenaming("library"); | |
| 3467 PreventRenaming("io"); | |
| 3468 PreventRenaming("html"); | |
| 3469 } | |
| 3470 | |
| 3471 RawString* Obfuscator::ObfuscationState::RenameImpl(const String& name, | |
| 3472 bool atomic) { | |
| 3473 ASSERT(name.IsSymbol()); | |
| 3474 | |
| 3475 renamed_ ^= renames_.GetOrNull(name); | |
| 3476 if (renamed_.IsNull()) { | |
| 3477 renamed_ = BuildRename(name, atomic); | |
| 3478 renames_.UpdateOrInsert(name, renamed_); | |
| 3479 } | |
| 3480 return renamed_.raw(); | |
| 3481 } | |
| 3482 | |
| 3483 void Obfuscator::PreventRenaming(Dart_QualifiedFunctionName entry_points[]) { | |
| 3484 for (intptr_t i = 0; entry_points[i].function_name != NULL; i++) { | |
| 3485 const char* class_name = entry_points[i].class_name; | |
| 3486 const char* function_name = entry_points[i].function_name; | |
| 3487 | |
| 3488 const size_t class_name_len = strlen(class_name); | |
| 3489 if (strncmp(function_name, class_name, class_name_len) == 0 && | |
| 3490 function_name[class_name_len] == '.') { | |
| 3491 const char* ctor_name = function_name + class_name_len + 1; | |
| 3492 if (ctor_name[0] != '\0') { | |
| 3493 PreventRenaming(ctor_name); | |
| 3494 } | |
| 3495 } else { | |
| 3496 PreventRenaming(function_name); | |
| 3497 } | |
| 3498 PreventRenaming(class_name); | |
| 3499 } | |
| 3500 } | |
| 3501 | |
| 3502 static const char* const kGetterPrefix = "get:"; | |
| 3503 static const intptr_t kGetterPrefixLength = strlen(kGetterPrefix); | |
| 3504 static const char* const kSetterPrefix = "set:"; | |
| 3505 static const intptr_t kSetterPrefixLength = strlen(kSetterPrefix); | |
| 3506 | |
| 3507 void Obfuscator::PreventRenaming(const char* name) { | |
| 3508 const char* dot = strchr(name, '.'); | |
| 3509 if (dot != NULL) { | |
| 3510 name = dot + 1; | |
| 3511 } | |
| 3512 | |
| 3513 if (name[0] == '\0') { | |
| 3514 return; | |
| 3515 } | |
| 3516 | |
| 3517 if (strncmp(name, kGetterPrefix, kGetterPrefixLength) == 0) { | |
| 3518 name = name + kGetterPrefixLength; | |
| 3519 } else if (strncmp(name, kSetterPrefix, kSetterPrefixLength) == 0) { | |
| 3520 name = name + kSetterPrefixLength; | |
| 3521 } | |
| 3522 | |
| 3523 state_->PreventRenaming(name); | |
| 3524 } | |
| 3525 | |
| 3526 void Obfuscator::ObfuscationState::SaveState() { | |
| 3527 saved_state_.SetAt(kSavedStateNameIndex, String::Handle(String::New(name_))); | |
| 3528 saved_state_.SetAt(kSavedStateRenamesIndex, renames_.Release()); | |
| 3529 thread_->isolate()->object_store()->set_obfuscation_map(saved_state_); | |
| 3530 } | |
| 3531 | |
| 3532 void Obfuscator::ObfuscationState::PreventRenaming(const char* name) { | |
| 3533 string_ = Symbols::New(thread_, name); | |
| 3534 PreventRenaming(string_); | |
| 3535 } | |
| 3536 | |
| 3537 void Obfuscator::ObfuscationState::PreventRenaming(const String& name) { | |
| 3538 renames_.UpdateOrInsert(name, name); | |
| 3539 } | |
| 3540 | |
| 3541 void Obfuscator::ObfuscationState::NextName() { | |
| 3542 for (intptr_t i = 0;; i++) { | |
| 3543 const char digit = name_[i]; | |
| 3544 if (digit == '\0') { | |
| 3545 name_[i] = 'a'; | |
| 3546 } else if (digit < 'Z') { | |
| 3547 name_[i]++; | |
| 3548 } else if (digit == 'Z') { | |
| 3549 name_[i] = 'a'; | |
| 3550 continue; | |
| 3551 } else if (digit < 'z') { | |
| 3552 name_[i]++; | |
| 3553 } else { | |
| 3554 name_[i] = 'A'; | |
| 3555 } | |
| 3556 break; | |
| 3557 } | |
| 3558 } | |
| 3559 | |
| 3560 RawString* Obfuscator::ObfuscationState::NewAtomicRename( | |
| 3561 bool should_be_private) { | |
| 3562 do { | |
| 3563 NextName(); | |
| 3564 renamed_ = Symbols::NewFormatted(thread_, "%s%s", | |
| 3565 should_be_private ? "_" : "", name_); | |
| 3566 } while (renames_.ContainsKey(renamed_)); | |
| 3567 return renamed_.raw(); | |
| 3568 } | |
| 3569 | |
| 3570 RawString* Obfuscator::ObfuscationState::BuildRename(const String& name, | |
| 3571 bool atomic) { | |
| 3572 const bool is_private = name.CharAt(0) == '_'; | |
| 3573 if (!atomic && is_private) { | |
| 3574 intptr_t i = 0; | |
| 3575 while (i < name.Length() && name.CharAt(i) != '@') { | |
| 3576 i++; | |
| 3577 } | |
| 3578 const intptr_t end = i; | |
| 3579 | |
| 3580 string_ = Symbols::New(thread_, name, 0, end); | |
| 3581 | |
| 3582 string_ = RenameImpl(string_, /*atomic=*/true); | |
| 3583 return Symbols::FromConcat(thread_, string_, private_key_); | |
| 3584 } else { | |
| 3585 return NewAtomicRename(is_private); | |
| 3586 } | |
| 3587 } | |
| 3588 | |
| 3589 void Obfuscator::ObfuscateSymbolInstance(Thread* thread, | |
| 3590 const Instance& symbol) { | |
| 3591 const intptr_t kSymbolNameOffset = kWordSize; | |
| 3592 | |
| 3593 Object& name_value = String::Handle(); | |
| 3594 name_value = symbol.RawGetFieldAtOffset(kSymbolNameOffset); | |
| 3595 if (!name_value.IsString()) { | |
| 3596 // dart.internal.Symbol constructor does not validate its input. | |
| 3597 return; | |
| 3598 } | |
| 3599 | |
| 3600 String& name = String::Handle(); | |
| 3601 name ^= name_value.raw(); | |
| 3602 | |
| 3603 // TODO(vegorov) it is quite wasteful to create an obfuscator per-symbol. | |
| 3604 Obfuscator obfuscator(thread, /*private_key=*/String::Handle()); | |
| 3605 | |
| 3606 String& component = String::Handle(); | |
| 3607 GrowableHandlePtrArray<const String> renamed(thread->zone(), 2); | |
| 3608 | |
| 3609 const intptr_t length = name.Length(); | |
| 3610 intptr_t i = 0, start = 0; | |
| 3611 while (i < length) { | |
| 3612 // First look for a '.' in the symbol. | |
| 3613 start = i; | |
| 3614 while (i < length && name.CharAt(i) != '.') { | |
| 3615 i++; | |
| 3616 } | |
| 3617 const intptr_t end = i; | |
| 3618 if (end == length) { | |
| 3619 break; | |
| 3620 } | |
| 3621 | |
| 3622 if (start != end) { | |
| 3623 component = Symbols::New(thread, name, start, end - start); | |
| 3624 component = obfuscator.Rename(component, /*atomic=*/true); | |
| 3625 renamed.Add(component); | |
| 3626 } | |
| 3627 | |
| 3628 renamed.Add(Symbols::Dot()); | |
| 3629 i++; // Skip '.' | |
| 3630 } | |
| 3631 | |
| 3632 // Handle the last component [start, length). | |
| 3633 // If symbol ends up at = and it is not one of '[]=', '==', '<=' or | |
| 3634 // '>=' then we treat it as a setter symbol of form 'name=' and | |
| 3635 // obfuscate to rename('name') + '='. | |
| 3636 const bool is_setter = (length - start) > 1 && | |
| 3637 name.CharAt(length - 1) == '=' && | |
| 3638 !(name.Equals(Symbols::AssignIndexToken()) || | |
| 3639 name.Equals(Symbols::EqualOperator()) || | |
| 3640 name.Equals(Symbols::GreaterEqualOperator()) || | |
| 3641 name.Equals(Symbols::LessEqualOperator())); | |
| 3642 const intptr_t end = length - (is_setter ? 1 : 0); | |
| 3643 | |
| 3644 if ((start == 0) && (end == length) && name.IsSymbol()) { | |
| 3645 component = name.raw(); | |
| 3646 } else { | |
| 3647 component = Symbols::New(thread, name, start, end - start); | |
| 3648 } | |
| 3649 component = obfuscator.Rename(component, /*atomic=*/true); | |
| 3650 renamed.Add(component); | |
| 3651 | |
| 3652 if (is_setter) { | |
| 3653 renamed.Add(Symbols::Equals()); | |
| 3654 } | |
| 3655 | |
| 3656 name = Symbols::FromConcatAll(thread, renamed); | |
| 3657 symbol.RawSetFieldAtOffset(kSymbolNameOffset, name); | |
| 3658 } | |
| 3659 | |
| 3660 void Obfuscator::Deobfuscate(Thread* thread, | |
| 3661 const GrowableObjectArray& pieces) { | |
| 3662 const Array& obfuscation_state = Array::Handle( | |
| 3663 thread->zone(), thread->isolate()->object_store()->obfuscation_map()); | |
| 3664 if (obfuscation_state.IsNull()) { | |
| 3665 return; | |
| 3666 } | |
| 3667 | |
| 3668 const Array& renames = Array::Handle( | |
| 3669 thread->zone(), GetRenamesFromSavedState(obfuscation_state)); | |
| 3670 | |
| 3671 ObfuscationMap renames_map(renames.raw()); | |
| 3672 String& piece = String::Handle(); | |
| 3673 for (intptr_t i = 0; i < pieces.Length(); i++) { | |
| 3674 piece ^= pieces.At(i); | |
| 3675 ASSERT(piece.IsSymbol()); | |
| 3676 | |
| 3677 // Fast path: skip '.' | |
| 3678 if (piece.raw() == Symbols::Dot().raw()) { | |
| 3679 continue; | |
| 3680 } | |
| 3681 | |
| 3682 // Fast path: check if piece has an identity obfuscation. | |
| 3683 if (renames_map.GetOrNull(piece) == piece.raw()) { | |
| 3684 continue; | |
| 3685 } | |
| 3686 | |
| 3687 ObfuscationMap::Iterator it(&renames_map); | |
| 3688 while (it.MoveNext()) { | |
| 3689 const intptr_t entry = it.Current(); | |
| 3690 if (renames_map.GetPayload(entry, 0) == piece.raw()) { | |
| 3691 piece ^= renames_map.GetKey(entry); | |
| 3692 pieces.SetAt(i, piece); | |
| 3693 break; | |
| 3694 } | |
| 3695 } | |
| 3696 } | |
| 3697 renames_map.Release(); | |
| 3698 } | |
| 3699 | |
| 3333 #endif // DART_PRECOMPILER | 3700 #endif // DART_PRECOMPILER |
| 3334 | 3701 |
| 3335 } // namespace dart | 3702 } // namespace dart |
| OLD | NEW |