Index: runtime/vm/precompiler.h |
diff --git a/runtime/vm/precompiler.h b/runtime/vm/precompiler.h |
index 2aff2a4d0cac1f6ef279bce0da3f815b4a4eb876..0acef6e25feb1f566efb1355ba6ac58cb7613b2e 100644 |
--- a/runtime/vm/precompiler.h |
+++ b/runtime/vm/precompiler.h |
@@ -398,6 +398,8 @@ class Precompiler : public ValueObject { |
void SwitchICCalls(); |
void ResetPrecompilerState(); |
+ void Obfuscate(); |
+ |
void CollectDynamicFunctionNames(); |
void PrecompileStaticInitializers(); |
@@ -476,6 +478,212 @@ class FunctionsTraits { |
typedef UnorderedHashSet<FunctionsTraits> UniqueFunctionsSet; |
+#if defined(DART_PRECOMPILER) |
+// ObfuscationMap maps Strings to Strings. |
+class ObfuscationMapTraits { |
+ public: |
+ static const char* Name() { return "ObfuscationMapTraits"; } |
+ static bool ReportStats() { return false; } |
+ |
+ // Only for non-descriptor lookup and table expansion. |
+ static bool IsMatch(const Object& a, const Object& b) { |
+ return a.raw() == b.raw(); |
+ } |
+ |
+ static uword Hash(const Object& key) { return String::Cast(key).Hash(); } |
+}; |
+typedef UnorderedHashMap<ObfuscationMapTraits> ObfuscationMap; |
+ |
+// Obfuscator is a helper class that is responsible for obfuscating |
+// identifiers when obfuscation is enabled via isolate flags. |
+// |
+class Obfuscator : public ValueObject { |
+ public: |
+ // Create Obfuscator for the given |thread|, with the given |private_key|. |
+ // This private key will be used when obfuscating private identifiers |
+ // (those starting with '_'). |
+ // |
+ // If obfuscation is enabled constructor will restore obfuscation state |
+ // from ObjectStore::obfuscation_map() |
+ // |
+ // Note: only a single instance of obfuscator should exist at any given |
+ // moment on the stack because Obfuscator takes ownership of obfuscation |
+ // map. ObjectStore::obfuscation_map() will only be updated when |
+ // this Obfuscator is destroyed. |
+ Obfuscator(Thread* thread, const String& private_key); |
+ |
+ // If obfuscation is enabled - commit accumulated renames to ObjectStore. |
+ ~Obfuscator(); |
+ |
+ // If obfuscation is enabled return a rename for the given |name|, |
+ // otherwise it is a no-op. |
+ // |
+ // Note: |name| *must* be a Symbol. |
+ // |
+ // By default renames are aware about mangling scheme used for private names: |
+ // '_ident@key' and '_ident' will be renamed consistently. If such |
+ // interpretation is undesirable e.g. it is known that name does not |
+ // contain a private key suffix or name is not a Dart identifier at all |
+ // then this function should be called with |atomic| set to true. |
+ // |
+ // Note: if obfuscator was created with private_key then all |
+ // renames *must* be atomic. |
+ // |
+ // This method is guaranteed to return the same value for the same |
+ // input and it always preserves leading '_' even for atomic renames. |
+ RawString* Rename(const String& name, bool atomic = false) { |
+ if (state_ == NULL) { |
+ return name.raw(); |
+ } |
+ |
+ return state_->RenameImpl(name, atomic); |
+ } |
+ |
+ // Given a constant |instance| of dart:internal.Symbol rename it by updating |
+ // its |name| field. |
+ static void ObfuscateSymbolInstance(Thread* thread, const Instance& instance); |
+ |
+ // Given a sequence of obfuscated identifiers deobfuscate it. |
+ // |
+ // This method is only used by parser when resolving conditional imports |
+ // because it needs deobfuscated names to lookup in the environment. |
+ // |
+ // Note: this operation is not optimized because is very infrequent. |
+ static void Deobfuscate(Thread* thread, const GrowableObjectArray& pieces); |
+ |
+ // Serialize renaming map as a malloced array of strings. |
+ static const char** SerializeMap(Thread* thread); |
+ |
+ private: |
+ // Populate renaming map with names that should have identity renaming. |
+ // (or in other words: with those names that should not be renamed). |
+ void InitializeRenamingMap(Isolate* isolate); |
+ void PreventRenaming(Dart_QualifiedFunctionName* entry_points); |
+ void PreventRenaming(const char* name); |
+ void PreventRenaming(const String& name) { state_->PreventRenaming(name); } |
+ |
+ // ObjectStore::obfuscation_map() is an Array with two elements: |
+ // first element is the last used rename and the second element is |
+ // renaming map. |
+ static const intptr_t kSavedStateNameIndex = 0; |
+ static const intptr_t kSavedStateRenamesIndex = 1; |
+ static const intptr_t kSavedStateSize = 2; |
+ |
+ static RawArray* GetRenamesFromSavedState(const Array& saved_state) { |
+ Array& renames = Array::Handle(); |
+ renames ^= saved_state.At(kSavedStateRenamesIndex); |
+ return renames.raw(); |
+ } |
+ |
+ static RawString* GetNameFromSavedState(const Array& saved_state) { |
+ String& name = String::Handle(); |
+ name ^= saved_state.At(kSavedStateNameIndex); |
+ return name.raw(); |
+ } |
+ |
+ class ObfuscationState : public ZoneAllocated { |
+ public: |
+ ObfuscationState(Thread* thread, |
+ const Array& saved_state, |
+ const String& private_key) |
+ : thread_(thread), |
+ saved_state_(saved_state), |
+ renames_(GetRenamesFromSavedState(saved_state)), |
+ private_key_(private_key), |
+ string_(String::Handle(thread->zone())), |
+ renamed_(String::Handle(thread->zone())) { |
+ memset(name_, 0, sizeof(name_)); |
+ |
+ // Restore last used rename. |
+ string_ = GetNameFromSavedState(saved_state); |
+ if (!string_.IsNull()) { |
+ string_.ToUTF8(reinterpret_cast<uint8_t*>(name_), sizeof(name_)); |
+ } |
+ } |
+ |
+ void SaveState(); |
+ |
+ // Return a rename for the given |name|. |
+ // |
+ // Note: |name| *must* be a Symbol. |
+ // |
+ // By default renames are aware about mangling scheme used for private |
+ // names: '_ident@key' and '_ident' will be renamed consistently. If such |
+ // interpretation is undesirable e.g. it is known that name does not |
+ // contain a private key suffix or name is not a Dart identifier at all |
+ // then this function should be called with |atomic| set to true. |
+ // |
+ // Note: if obfuscator was created with private_key then all |
+ // renames *must* be atomic. |
+ // |
+ // This method is guaranteed to return the same value for the same |
+ // input. |
+ RawString* RenameImpl(const String& name, bool atomic); |
+ |
+ // Register an identity (name -> name) mapping in the renaming map. |
+ // |
+ // This essentially prevents the given name from being renamed. |
+ void PreventRenaming(const String& name); |
+ void PreventRenaming(const char* name); |
+ |
+ private: |
+ // Build rename for the given |name|. |
+ // |
+ // For atomic renames BuildRename just returns the next |
+ // available rename generated by AtomicRename(...). |
+ // |
+ // For non-atomic renames BuildRename ensures that private mangled |
+ // identifiers (_ident@key) are renamed consistently with non-mangled |
+ // counterparts (_ident). |
+ RawString* BuildRename(const String& name, bool atomic); |
+ |
+ // Generate a new rename. If |should_be_private| is set to true |
+ // then we prefix returned identifier with '_'. |
+ RawString* NewAtomicRename(bool should_be_private); |
+ |
+ // Update next_ to generate the next free rename. |
+ void NextName(); |
+ |
+ Thread* thread_; |
+ |
+ // Saved obfuscation state (ObjectStore::obfuscation_map()) |
+ const Array& saved_state_; |
+ |
+ // Last used rename. Renames are only using a-zA-Z characters |
+ // and are generated in order: a, b, ..., z, A, ..., Z, aa, ba, ... |
+ char name_[100]; |
+ |
+ ObfuscationMap renames_; |
+ |
+ const String& private_key_; |
+ |
+ // Temporary handles. |
+ String& string_; |
+ String& renamed_; |
+ }; |
+ |
+ // Current obfucation state or NULL if obfuscation is not enabled. |
+ ObfuscationState* state_; |
+}; |
+#else |
+// Minimal do-nothing implementation of an Obfuscator for non-precompiler |
+// builds. |
+class Obfuscator { |
+ public: |
+ Obfuscator(Thread* thread, const String& private_key) {} |
+ ~Obfuscator() {} |
+ |
+ RawString* Rename(const String& name, bool atomic = false) { |
+ return name.raw(); |
+ } |
+ |
+ static void ObfuscateSymbolInstance(Thread* thread, |
+ const Instance& instance) {} |
+ |
+ static void Deobfuscate(Thread* thread, const GrowableObjectArray& pieces) {} |
+}; |
+#endif // DART_PRECOMPILER |
+ |
} // namespace dart |
#endif // RUNTIME_VM_PRECOMPILER_H_ |