Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(109)

Side by Side Diff: runtime/vm/precompiler.cc

Issue 3003583002: [VM, Precompiler] PoC Obfuscator (Closed)
Patch Set: Fix bad refactoring in NewAtomicRename Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/vm/precompiler.h ('k') | runtime/vm/raw_object.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 27 matching lines...) Expand all
38 #include "vm/redundancy_elimination.h" 38 #include "vm/redundancy_elimination.h"
39 #include "vm/regexp_assembler.h" 39 #include "vm/regexp_assembler.h"
40 #include "vm/regexp_parser.h" 40 #include "vm/regexp_parser.h"
41 #include "vm/resolver.h" 41 #include "vm/resolver.h"
42 #include "vm/runtime_entry.h" 42 #include "vm/runtime_entry.h"
43 #include "vm/symbols.h" 43 #include "vm/symbols.h"
44 #include "vm/tags.h" 44 #include "vm/tags.h"
45 #include "vm/timeline.h" 45 #include "vm/timeline.h"
46 #include "vm/timer.h" 46 #include "vm/timer.h"
47 #include "vm/type_table.h" 47 #include "vm/type_table.h"
48 #include "vm/unicode.h"
48 #include "vm/version.h" 49 #include "vm/version.h"
49 50
50 namespace dart { 51 namespace dart {
51 52
52 #define T (thread()) 53 #define T (thread())
53 #define I (isolate()) 54 #define I (isolate())
54 #define Z (zone()) 55 #define Z (zone())
55 56
56 DEFINE_FLAG(bool, print_unique_targets, false, "Print unique dynamic targets"); 57 DEFINE_FLAG(bool, print_unique_targets, false, "Print unique dynamic targets");
57 DEFINE_FLAG(bool, trace_precompiler, false, "Trace precompiler."); 58 DEFINE_FLAG(bool, trace_precompiler, false, "Trace precompiler.");
(...skipping 424 matching lines...) Expand 10 before | Expand all | Expand 10 after
482 I->object_store()->set_async_star_move_next_helper(null_function); 483 I->object_store()->set_async_star_move_next_helper(null_function);
483 I->object_store()->set_complete_on_async_return(null_function); 484 I->object_store()->set_complete_on_async_return(null_function);
484 I->object_store()->set_async_star_stream_controller(null_class); 485 I->object_store()->set_async_star_stream_controller(null_class);
485 DropLibraryEntries(); 486 DropLibraryEntries();
486 } 487 }
487 DropClasses(); 488 DropClasses();
488 DropLibraries(); 489 DropLibraries();
489 490
490 BindStaticCalls(); 491 BindStaticCalls();
491 SwitchICCalls(); 492 SwitchICCalls();
493 Obfuscate();
492 494
493 ProgramVisitor::Dedup(); 495 ProgramVisitor::Dedup();
494 496
495 zone_ = NULL; 497 zone_ = NULL;
496 } 498 }
497 499
498 intptr_t symbols_before = -1; 500 intptr_t symbols_before = -1;
499 intptr_t symbols_after = -1; 501 intptr_t symbols_after = -1;
500 intptr_t capacity = -1; 502 intptr_t capacity = -1;
501 if (FLAG_trace_precompiler) { 503 if (FLAG_trace_precompiler) {
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
603 current->field_->set_guarded_cid(cid); 605 current->field_->set_guarded_cid(cid);
604 current->field_->set_is_nullable(cid == kNullCid || cid == kDynamicCid); 606 current->field_->set_is_nullable(cid == kNullCid || cid == kDynamicCid);
605 if (FLAG_trace_precompiler) { 607 if (FLAG_trace_precompiler) {
606 THR_Print( 608 THR_Print(
607 "Field %s <- Type %s\n", current->field_->ToCString(), 609 "Field %s <- Type %s\n", current->field_->ToCString(),
608 Class::Handle(T->isolate()->class_table()->At(cid)).ToCString()); 610 Class::Handle(T->isolate()->class_table()->At(cid)).ToCString());
609 } 611 }
610 } 612 }
611 } 613 }
612 614
613 void Precompiler::AddRoots(Dart_QualifiedFunctionName embedder_entry_points[]) { 615 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 616 // Functions
638 {"dart:core", "::", "_completeDeferredLoads"}, 617 {"dart:core", "::", "_completeDeferredLoads"},
639 {"dart:core", "::", "identityHashCode"}, 618 {"dart:core", "::", "identityHashCode"},
640 {"dart:core", "AbstractClassInstantiationError", 619 {"dart:core", "AbstractClassInstantiationError",
641 "AbstractClassInstantiationError._create"}, 620 "AbstractClassInstantiationError._create"},
642 {"dart:core", "ArgumentError", "ArgumentError."}, 621 {"dart:core", "ArgumentError", "ArgumentError."},
643 {"dart:core", "ArgumentError", "ArgumentError.value"}, 622 {"dart:core", "ArgumentError", "ArgumentError.value"},
644 {"dart:core", "CyclicInitializationError", "CyclicInitializationError."}, 623 {"dart:core", "CyclicInitializationError", "CyclicInitializationError."},
645 {"dart:core", "FallThroughError", "FallThroughError._create"}, 624 {"dart:core", "FallThroughError", "FallThroughError._create"},
646 {"dart:core", "FormatException", "FormatException."}, 625 {"dart:core", "FormatException", "FormatException."},
(...skipping 19 matching lines...) Expand all
666 {"dart:typed_data", "_ByteBuffer", "_ByteBuffer._New"}, 645 {"dart:typed_data", "_ByteBuffer", "_ByteBuffer._New"},
667 {"dart:_vmservice", "::", "boot"}, 646 {"dart:_vmservice", "::", "boot"},
668 #if !defined(PRODUCT) 647 #if !defined(PRODUCT)
669 {"dart:_vmservice", "::", "_registerIsolate"}, 648 {"dart:_vmservice", "::", "_registerIsolate"},
670 {"dart:developer", "Metrics", "_printMetrics"}, 649 {"dart:developer", "Metrics", "_printMetrics"},
671 {"dart:developer", "::", "_runExtension"}, 650 {"dart:developer", "::", "_runExtension"},
672 {"dart:isolate", "::", "_runPendingImmediateCallback"}, 651 {"dart:isolate", "::", "_runPendingImmediateCallback"},
673 #endif // !PRODUCT 652 #endif // !PRODUCT
674 // Fields 653 // Fields
675 {"dart:core", "Error", "_stackTrace"}, 654 {"dart:core", "Error", "_stackTrace"},
655 {"dart:core", "::", "_uriBaseClosure"},
676 {"dart:math", "_Random", "_state"}, 656 {"dart:math", "_Random", "_state"},
677 {NULL, NULL, NULL} // Must be terminated with NULL entries. 657 {NULL, NULL, NULL} // Must be terminated with NULL entries.
678 }; 658 };
659
660 void Precompiler::AddRoots(Dart_QualifiedFunctionName embedder_entry_points[]) {
661 // Note that <rootlibrary>.main is not a root. The appropriate main will be
662 // discovered through _getMainClosure.
663
664 AddSelector(Symbols::NoSuchMethod());
665
666 AddSelector(Symbols::Call()); // For speed, not correctness.
667
668 // Allocated from C++.
669 Class& cls = Class::Handle(Z);
670 for (intptr_t cid = kInstanceCid; cid < kNumPredefinedCids; cid++) {
671 ASSERT(isolate()->class_table()->IsValidIndex(cid));
672 if (!isolate()->class_table()->HasValidClassAt(cid)) {
673 continue;
674 }
675 if ((cid == kDynamicCid) || (cid == kVoidCid) ||
676 (cid == kFreeListElement) || (cid == kForwardingCorpse)) {
677 continue;
678 }
679 cls = isolate()->class_table()->At(cid);
680 AddInstantiatedClass(cls);
681 }
679 682
680 AddEntryPoints(vm_entry_points); 683 AddEntryPoints(vm_entry_points);
681 AddEntryPoints(embedder_entry_points); 684 AddEntryPoints(embedder_entry_points);
682 const Library& lib = Library::Handle(I->object_store()->root_library()); 685 const Library& lib = Library::Handle(I->object_store()->root_library());
683 const String& name = String::Handle(String::New("main")); 686 const String& name = String::Handle(String::New("main"));
684 const Object& main_closure = Object::Handle(lib.GetFunctionClosure(name)); 687 const Object& main_closure = Object::Handle(lib.GetFunctionClosure(name));
685 if (main_closure.IsClosure()) { 688 if (main_closure.IsClosure()) {
686 if (lib.LookupLocalFunction(name) == Function::null()) { 689 if (lib.LookupLocalFunction(name) == Function::null()) {
687 // Check whether the function is in exported namespace of library, in 690 // Check whether the function is in exported namespace of library, in
688 // this case we have to retain the root library caches. 691 // this case we have to retain the root library caches.
(...skipping 1582 matching lines...) Expand 10 before | Expand all | Expand 10 after
2271 Code& target_code_; 2274 Code& target_code_;
2272 UnlinkedCallSet canonical_unlinked_calls_; 2275 UnlinkedCallSet canonical_unlinked_calls_;
2273 }; 2276 };
2274 2277
2275 ASSERT(!I->compilation_allowed()); 2278 ASSERT(!I->compilation_allowed());
2276 SwitchICCallsVisitor visitor(Z); 2279 SwitchICCallsVisitor visitor(Z);
2277 ProgramVisitor::VisitFunctions(&visitor); 2280 ProgramVisitor::VisitFunctions(&visitor);
2278 #endif 2281 #endif
2279 } 2282 }
2280 2283
2284 void Precompiler::Obfuscate() {
2285 if (!I->obfuscate()) {
2286 return;
2287 }
2288
2289 class ScriptsCollector : public ObjectVisitor {
2290 public:
2291 explicit ScriptsCollector(Zone* zone,
2292 GrowableHandlePtrArray<const Script>* scripts)
2293 : script_(Script::Handle(zone)), scripts_(scripts) {}
2294
2295 void VisitObject(RawObject* obj) {
2296 if (obj->GetClassId() == kScriptCid) {
2297 script_ ^= obj;
2298 scripts_->Add(Script::Cast(script_));
2299 }
2300 }
2301
2302 private:
2303 Script& script_;
2304 GrowableHandlePtrArray<const Script>* scripts_;
2305 };
2306
2307 GrowableHandlePtrArray<const Script> scripts(Z, 100);
2308 Isolate::Current()->heap()->CollectAllGarbage();
2309 {
2310 HeapIterationScope his(T);
2311 ScriptsCollector visitor(Z, &scripts);
2312 I->heap()->VisitObjects(&visitor);
2313 }
2314
2315 {
2316 // Note: when this object is destroyed it will commit obfuscation
2317 // mappings into the ObjectStore. Hence the block around it - to
2318 // ensure that destructor is called before we save obfuscation
2319 // mappings and clear the ObjectStore.
2320 Obfuscator obfuscator(T, /*private_key=*/String::Handle(Z));
2321 String& str = String::Handle(Z);
2322 for (intptr_t i = 0; i < scripts.length(); i++) {
2323 const Script& script = scripts.At(i);
2324
2325 str = script.url();
2326 str = Symbols::New(T, str);
2327 str = obfuscator.Rename(str, /*atomic=*/true);
2328 script.set_url(str);
2329
2330 str = script.resolved_url();
2331 str = Symbols::New(T, str);
2332 str = obfuscator.Rename(str, /*atomic=*/true);
2333 script.set_resolved_url(str);
2334 }
2335
2336 Library& lib = Library::Handle();
2337 for (intptr_t i = 0; i < libraries_.Length(); i++) {
2338 lib ^= libraries_.At(i);
2339 if (!lib.is_dart_scheme()) {
2340 str = lib.name();
2341 str = obfuscator.Rename(str, /*atomic=*/true);
2342 lib.set_name(str);
2343
2344 str = lib.url();
2345 str = Symbols::New(T, str);
2346 str = obfuscator.Rename(str, /*atomic=*/true);
2347 lib.set_url(str);
2348 }
2349 }
2350 Library::RegisterLibraries(T, libraries_);
2351 }
2352
2353 // Obfuscation is done. Move obfuscation map into malloced memory.
2354 I->set_obfuscation_map(Obfuscator::SerializeMap(T));
2355
2356 // Discard obfuscation mappings to avoid including them into snapshot.
2357 I->object_store()->set_obfuscation_map(Array::Handle(Z));
2358 }
2359
2281 void Precompiler::FinalizeAllClasses() { 2360 void Precompiler::FinalizeAllClasses() {
2282 Library& lib = Library::Handle(Z); 2361 Library& lib = Library::Handle(Z);
2283 Class& cls = Class::Handle(Z); 2362 Class& cls = Class::Handle(Z);
2284 2363
2285 for (intptr_t i = 0; i < libraries_.Length(); i++) { 2364 for (intptr_t i = 0; i < libraries_.Length(); i++) {
2286 lib ^= libraries_.At(i); 2365 lib ^= libraries_.At(i);
2287 if (!lib.Loaded()) { 2366 if (!lib.Loaded()) {
2288 String& uri = String::Handle(Z, lib.url()); 2367 String& uri = String::Handle(Z, lib.url());
2289 String& msg = String::Handle( 2368 String& msg = String::Handle(
2290 Z, 2369 Z,
(...skipping 1032 matching lines...) Expand 10 before | Expand all | Expand 10 after
3323 FieldTypeMap* field_type_map) { 3402 FieldTypeMap* field_type_map) {
3324 VMTagScope tagScope(thread, VMTag::kCompileUnoptimizedTagId); 3403 VMTagScope tagScope(thread, VMTag::kCompileUnoptimizedTagId);
3325 TIMELINE_FUNCTION_COMPILATION_DURATION(thread, "CompileFunction", function); 3404 TIMELINE_FUNCTION_COMPILATION_DURATION(thread, "CompileFunction", function);
3326 3405
3327 ASSERT(FLAG_precompiled_mode); 3406 ASSERT(FLAG_precompiled_mode);
3328 const bool optimized = function.IsOptimizable(); // False for natives. 3407 const bool optimized = function.IsOptimizable(); // False for natives.
3329 DartPrecompilationPipeline pipeline(zone, field_type_map); 3408 DartPrecompilationPipeline pipeline(zone, field_type_map);
3330 return PrecompileFunctionHelper(precompiler, &pipeline, function, optimized); 3409 return PrecompileFunctionHelper(precompiler, &pipeline, function, optimized);
3331 } 3410 }
3332 3411
3412 Obfuscator::Obfuscator(Thread* thread, const String& private_key)
3413 : state_(NULL) {
3414 Isolate* isolate = thread->isolate();
3415 Zone* zone = thread->zone();
3416 if (!isolate->obfuscate()) {
3417 // Nothing to do.
3418 return;
3419 }
3420
3421 // Create ObfuscationState from ObjectStore::obfusction_map().
3422 ObjectStore* store = thread->isolate()->object_store();
3423 Array& obfuscation_state = Array::Handle(zone, store->obfuscation_map());
3424
3425 if (store->obfuscation_map() == Array::null()) {
3426 // We are just starting the obfuscation. Create initial state.
3427 const int kInitialPrivateCapacity = 256;
3428 obfuscation_state = Array::New(kSavedStateSize);
3429 obfuscation_state.SetAt(
3430 1, Array::Handle(zone, HashTables::New<ObfuscationMap>(
3431 kInitialPrivateCapacity, Heap::kOld)));
3432 }
3433
3434 state_ = new (zone) ObfuscationState(thread, obfuscation_state, private_key);
3435
3436 if (store->obfuscation_map() == Array::null()) {
3437 // We are just starting the obfuscation. Initialize the renaming map.
3438 // Note: InitializeRenamingMap uses state_.
3439 InitializeRenamingMap(isolate);
3440 }
3441 }
3442
3443 Obfuscator::~Obfuscator() {
3444 if (state_ != NULL) {
3445 state_->SaveState();
3446 }
3447 }
3448
3449 void Obfuscator::InitializeRenamingMap(Isolate* isolate) {
3450 // Prevent renaming of classes and method names mentioned in the
3451 // entry points lists.
3452 PreventRenaming(vm_entry_points);
3453 PreventRenaming(isolate->embedder_entry_points());
3454
3455 // Prevent renaming of all pseudo-keywords and operators.
3456 // Note: not all pseudo-keywords are mentioned in DART_KEYWORD_LIST
3457 // (for example 'hide', 'show' and async related keywords are omitted).
3458 // Those are protected from renaming as part of all symbols.
3459 #define PREVENT_RENAMING(name, value, priority, attr) \
3460 do { \
3461 if (Token::CanBeOverloaded(Token::name) || \
3462 ((Token::attr & Token::kPseudoKeyword) != 0)) { \
3463 PreventRenaming(value); \
3464 } \
3465 } while (0);
3466
3467 DART_TOKEN_LIST(PREVENT_RENAMING)
3468 DART_KEYWORD_LIST(PREVENT_RENAMING)
3469 #undef PREVENT_RENAMING
3470
3471 // this is a keyword token unless it occurs in the string interpolation
3472 // which causes it to be obfuscated.
3473 PreventRenaming("this");
3474
3475 // Protect all symbols from renaming.
3476 #define PREVENT_RENAMING(name, value) PreventRenaming(value);
3477 PREDEFINED_SYMBOLS_LIST(PREVENT_RENAMING)
3478 #undef PREVENT_RENAMING
3479
3480 // Protect NativeFieldWrapperClassX names from being obfuscated. Those
3481 // classes are created manually by the runtime system.
3482 // TODO(dartbug.com/30524) instead call to Obfuscator::Rename from a place
3483 // where these are created.
3484 PreventRenaming("NativeFieldWrapperClass1");
3485 PreventRenaming("NativeFieldWrapperClass2");
3486 PreventRenaming("NativeFieldWrapperClass3");
3487 PreventRenaming("NativeFieldWrapperClass4");
3488
3489 // Prevent renaming of ClassID.cid* fields. These fields are injected by
3490 // runtime.
3491 // TODO(dartbug.com/30524) instead call to Obfuscator::Rename from a place
3492 // where these are created.
3493 #define CLASS_LIST_WITH_NULL(V) \
3494 V(Null) \
3495 CLASS_LIST_NO_OBJECT(V)
3496 #define PREVENT_RENAMING(clazz) PreventRenaming("cid" #clazz);
3497 CLASS_LIST_WITH_NULL(PREVENT_RENAMING)
3498 #undef PREVENT_RENAMING
3499 #undef CLASS_LIST_WITH_NULL
3500
3501 // Prevent renaming of methods that are looked up by method recognizer.
3502 // TODO(dartbug.com/30524) instead call to Obfuscator::Rename from a place
3503 // where these are looked up.
3504 #define PREVENT_RENAMING(class_name, function_name, recognized_enum, \
3505 result_type, fingerprint) \
3506 do { \
3507 PreventRenaming(#class_name); \
3508 PreventRenaming(#function_name); \
3509 } while (0);
3510 RECOGNIZED_LIST(PREVENT_RENAMING)
3511 #undef PREVENT_RENAMING
3512
3513 // Prevent renaming of methods that are looked up by method recognizer.
3514 // TODO(dartbug.com/30524) instead call to Obfuscator::Rename from a place
3515 // where these are looked up.
3516 #define PREVENT_RENAMING(class_name, function_name, recognized_enum, \
3517 fingerprint) \
3518 do { \
3519 PreventRenaming(#class_name); \
3520 PreventRenaming(#function_name); \
3521 } while (0);
3522 INLINE_WHITE_LIST(PREVENT_RENAMING)
3523 INLINE_BLACK_LIST(PREVENT_RENAMING)
3524 POLYMORPHIC_TARGET_LIST(PREVENT_RENAMING)
3525 #undef PREVENT_RENAMING
3526
3527 // These are not mentioned by entry points but are still looked up by name.
3528 // (They are not mentioned in the entry points because we don't need them
3529 // after the compilation)
3530 PreventRenaming("_resolveScriptUri");
3531
3532 // Precompiler is looking up "main".
3533 // TODO(dartbug.com/30524) instead call to Obfuscator::Rename from a place
3534 // where these are created.
3535 PreventRenaming("main");
3536
3537 // Fast path for common conditional import. See Deobfuscate method.
3538 PreventRenaming("dart");
3539 PreventRenaming("library");
3540 PreventRenaming("io");
3541 PreventRenaming("html");
3542 }
3543
3544 RawString* Obfuscator::ObfuscationState::RenameImpl(const String& name,
3545 bool atomic) {
3546 ASSERT(name.IsSymbol());
3547
3548 renamed_ ^= renames_.GetOrNull(name);
3549 if (renamed_.IsNull()) {
3550 renamed_ = BuildRename(name, atomic);
3551 renames_.UpdateOrInsert(name, renamed_);
3552 }
3553 return renamed_.raw();
3554 }
3555
3556 void Obfuscator::PreventRenaming(Dart_QualifiedFunctionName entry_points[]) {
3557 for (intptr_t i = 0; entry_points[i].function_name != NULL; i++) {
3558 const char* class_name = entry_points[i].class_name;
3559 const char* function_name = entry_points[i].function_name;
3560
3561 const size_t class_name_len = strlen(class_name);
3562 if (strncmp(function_name, class_name, class_name_len) == 0 &&
3563 function_name[class_name_len] == '.') {
3564 const char* ctor_name = function_name + class_name_len + 1;
3565 if (ctor_name[0] != '\0') {
3566 PreventRenaming(ctor_name);
3567 }
3568 } else {
3569 PreventRenaming(function_name);
3570 }
3571 PreventRenaming(class_name);
3572 }
3573 }
3574
3575 static const char* const kGetterPrefix = "get:";
3576 static const intptr_t kGetterPrefixLength = strlen(kGetterPrefix);
3577 static const char* const kSetterPrefix = "set:";
3578 static const intptr_t kSetterPrefixLength = strlen(kSetterPrefix);
3579
3580 void Obfuscator::PreventRenaming(const char* name) {
3581 // For constructor names Class.name skip class name (if any) and a dot.
3582 const char* dot = strchr(name, '.');
3583 if (dot != NULL) {
3584 name = dot + 1;
3585 }
3586
3587 // Empty name: do nothing.
3588 if (name[0] == '\0') {
3589 return;
3590 }
3591
3592 // Skip get: and set: prefixes.
3593 if (strncmp(name, kGetterPrefix, kGetterPrefixLength) == 0) {
3594 name = name + kGetterPrefixLength;
3595 } else if (strncmp(name, kSetterPrefix, kSetterPrefixLength) == 0) {
3596 name = name + kSetterPrefixLength;
3597 }
3598
3599 state_->PreventRenaming(name);
3600 }
3601
3602 void Obfuscator::ObfuscationState::SaveState() {
3603 saved_state_.SetAt(kSavedStateNameIndex, String::Handle(String::New(name_)));
3604 saved_state_.SetAt(kSavedStateRenamesIndex, renames_.Release());
3605 thread_->isolate()->object_store()->set_obfuscation_map(saved_state_);
3606 }
3607
3608 void Obfuscator::ObfuscationState::PreventRenaming(const char* name) {
3609 string_ = Symbols::New(thread_, name);
3610 PreventRenaming(string_);
3611 }
3612
3613 void Obfuscator::ObfuscationState::PreventRenaming(const String& name) {
3614 renames_.UpdateOrInsert(name, name);
3615 }
3616
3617 void Obfuscator::ObfuscationState::NextName() {
3618 // We apply the following rules:
3619 //
3620 // inc(a) = b, ... , inc(z) = A, ..., inc(Z) = a & carry.
3621 //
3622 for (intptr_t i = 0;; i++) {
3623 const char digit = name_[i];
3624 if (digit == '\0') {
3625 name_[i] = 'a';
3626 } else if (digit < 'Z') {
3627 name_[i]++;
3628 } else if (digit == 'Z') {
3629 name_[i] = 'a';
3630 continue; // Carry.
3631 } else if (digit < 'z') {
3632 name_[i]++;
3633 } else {
3634 name_[i] = 'A';
3635 }
3636 break;
3637 }
3638 }
3639
3640 RawString* Obfuscator::ObfuscationState::NewAtomicRename(
3641 bool should_be_private) {
3642 do {
3643 NextName();
3644 renamed_ = Symbols::NewFormatted(thread_, "%s%s",
3645 should_be_private ? "_" : "", name_);
3646 // Must check if our generated name clashes with something that will
3647 // have an identity renaming.
3648 } while (renames_.GetOrNull(renamed_) == renamed_.raw());
3649 return renamed_.raw();
3650 }
3651
3652 RawString* Obfuscator::ObfuscationState::BuildRename(const String& name,
3653 bool atomic) {
3654 const bool is_private = name.CharAt(0) == '_';
3655 if (!atomic && is_private) {
3656 // Find the first '@'.
3657 intptr_t i = 0;
3658 while (i < name.Length() && name.CharAt(i) != '@') {
3659 i++;
3660 }
3661 const intptr_t end = i;
3662
3663 // Follow the rule:
3664 //
3665 // Rename(_ident@key) = Rename(_ident)@private_key_.
3666 //
3667 string_ = Symbols::New(thread_, name, 0, end);
3668 string_ = RenameImpl(string_, /*atomic=*/true);
3669 return Symbols::FromConcat(thread_, string_, private_key_);
3670 } else {
3671 return NewAtomicRename(is_private);
3672 }
3673 }
3674
3675 void Obfuscator::ObfuscateSymbolInstance(Thread* thread,
3676 const Instance& symbol) {
3677 // Note: this must match dart:internal.Symbol declaration.
3678 const intptr_t kSymbolNameOffset = kWordSize;
3679
3680 Object& name_value = String::Handle();
3681 name_value = symbol.RawGetFieldAtOffset(kSymbolNameOffset);
3682 if (!name_value.IsString()) {
3683 // dart:internal.Symbol constructor does not validate its input.
3684 return;
3685 }
3686
3687 String& name = String::Handle();
3688 name ^= name_value.raw();
3689
3690 // TODO(vegorov) it is quite wasteful to create an obfuscator per-symbol.
3691 Obfuscator obfuscator(thread, /*private_key=*/String::Handle());
3692
3693 // Symbol can be a sequence of identifiers separated by dots.
3694 // We split such symbols into components and obfuscate individual identifiers
3695 // separately.
3696 String& component = String::Handle();
3697 GrowableHandlePtrArray<const String> renamed(thread->zone(), 2);
3698
3699 const intptr_t length = name.Length();
3700 intptr_t i = 0, start = 0;
3701 while (i < length) {
3702 // First look for a '.' in the symbol.
3703 start = i;
3704 while (i < length && name.CharAt(i) != '.') {
3705 i++;
3706 }
3707 const intptr_t end = i;
3708 if (end == length) {
3709 break;
3710 }
3711
3712 if (start != end) {
3713 component = Symbols::New(thread, name, start, end - start);
3714 component = obfuscator.Rename(component, /*atomic=*/true);
3715 renamed.Add(component);
3716 }
3717
3718 renamed.Add(Symbols::Dot());
3719 i++; // Skip '.'
3720 }
3721
3722 // Handle the last component [start, length).
3723 // If symbol ends up at = and it is not one of '[]=', '==', '<=' or
3724 // '>=' then we treat it as a setter symbol and follow the rule:
3725 //
3726 // Rename('ident=') = Rename('ident') '='
3727 //
3728 const bool is_setter = (length - start) > 1 &&
3729 name.CharAt(length - 1) == '=' &&
3730 !(name.Equals(Symbols::AssignIndexToken()) ||
3731 name.Equals(Symbols::EqualOperator()) ||
3732 name.Equals(Symbols::GreaterEqualOperator()) ||
3733 name.Equals(Symbols::LessEqualOperator()));
3734 const intptr_t end = length - (is_setter ? 1 : 0);
3735
3736 if ((start == 0) && (end == length) && name.IsSymbol()) {
3737 component = name.raw();
3738 } else {
3739 component = Symbols::New(thread, name, start, end - start);
3740 }
3741 component = obfuscator.Rename(component, /*atomic=*/true);
3742 renamed.Add(component);
3743
3744 if (is_setter) {
3745 renamed.Add(Symbols::Equals());
3746 }
3747
3748 name = Symbols::FromConcatAll(thread, renamed);
3749 symbol.RawSetFieldAtOffset(kSymbolNameOffset, name);
3750 }
3751
3752 void Obfuscator::Deobfuscate(Thread* thread,
3753 const GrowableObjectArray& pieces) {
3754 const Array& obfuscation_state = Array::Handle(
3755 thread->zone(), thread->isolate()->object_store()->obfuscation_map());
3756 if (obfuscation_state.IsNull()) {
3757 return;
3758 }
3759
3760 const Array& renames = Array::Handle(
3761 thread->zone(), GetRenamesFromSavedState(obfuscation_state));
3762
3763 ObfuscationMap renames_map(renames.raw());
3764 String& piece = String::Handle();
3765 for (intptr_t i = 0; i < pieces.Length(); i++) {
3766 piece ^= pieces.At(i);
3767 ASSERT(piece.IsSymbol());
3768
3769 // Fast path: skip '.'
3770 if (piece.raw() == Symbols::Dot().raw()) {
3771 continue;
3772 }
3773
3774 // Fast path: check if piece has an identity obfuscation.
3775 if (renames_map.GetOrNull(piece) == piece.raw()) {
3776 continue;
3777 }
3778
3779 // Search through the whole obfuscation map until matching value is found.
3780 // We are using linear search instead of generating a reverse mapping
3781 // because we assume that Deobfuscate() method is almost never called.
3782 ObfuscationMap::Iterator it(&renames_map);
3783 while (it.MoveNext()) {
3784 const intptr_t entry = it.Current();
3785 if (renames_map.GetPayload(entry, 0) == piece.raw()) {
3786 piece ^= renames_map.GetKey(entry);
3787 pieces.SetAt(i, piece);
3788 break;
3789 }
3790 }
3791 }
3792 renames_map.Release();
3793 }
3794
3795 static const char* StringToCString(const String& str) {
3796 const intptr_t len = Utf8::Length(str);
3797 char* result = new char[len + 1];
3798 str.ToUTF8(reinterpret_cast<uint8_t*>(result), len);
3799 result[len] = 0;
3800 return result;
3801 }
3802
3803 const char** Obfuscator::SerializeMap(Thread* thread) {
3804 const Array& obfuscation_state = Array::Handle(
3805 thread->zone(), thread->isolate()->object_store()->obfuscation_map());
3806 if (obfuscation_state.IsNull()) {
3807 return NULL;
3808 }
3809
3810 const Array& renames = Array::Handle(
3811 thread->zone(), GetRenamesFromSavedState(obfuscation_state));
3812 ObfuscationMap renames_map(renames.raw());
3813
3814 const char** result = new const char*[renames_map.NumOccupied() * 2 + 1];
3815 intptr_t idx = 0;
3816 String& str = String::Handle();
3817
3818 ObfuscationMap::Iterator it(&renames_map);
3819 while (it.MoveNext()) {
3820 const intptr_t entry = it.Current();
3821 str ^= renames_map.GetKey(entry);
3822 result[idx++] = StringToCString(str);
3823 str ^= renames_map.GetPayload(entry, 0);
3824 result[idx++] = StringToCString(str);
3825 }
3826 result[idx++] = NULL;
3827 renames_map.Release();
3828
3829 return result;
3830 }
3831
3333 #endif // DART_PRECOMPILER 3832 #endif // DART_PRECOMPILER
3334 3833
3335 } // namespace dart 3834 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/precompiler.h ('k') | runtime/vm/raw_object.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698