forked from facebook/hermes
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move the hermes instrumentation tests so they can be open sourced.
Reviewed By: willholen Differential Revision: D21420115 fbshipit-source-id: bf83f283e86e3afc4a70dee9d9bc530e305edd74
- Loading branch information
1 parent
484b88b
commit 9d3ed76
Showing
13 changed files
with
823 additions
and
0 deletions.
There are no files selected for viewing
66 changes: 66 additions & 0 deletions
66
android/test/java/com/facebook/hermes/test/HermesEpilogue.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
/* | ||
* Copyright (c) Facebook, Inc. and its affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
#include "HermesEpilogue.h" | ||
|
||
#include <hermes/hermes.h> | ||
|
||
#include <MappedFileBuffer.h> | ||
|
||
namespace facebook { | ||
namespace jsi { | ||
namespace jni { | ||
|
||
static jni::local_ref<jbyteArray> metadataParserImpl( | ||
const uint8_t *data, | ||
size_t size) { | ||
std::pair<const uint8_t *, size_t> epiPair = | ||
hermes::HermesRuntime::getBytecodeEpilogue(data, size); | ||
size_t epilogueSize = epiPair.second; | ||
const uint8_t *epilogue = epiPair.first; | ||
if (epilogueSize == 0) { | ||
// No data after HBC content. | ||
return jni::JArrayByte::newArray(0); | ||
} else { | ||
jni::local_ref<jbyteArray> res = jni::JArrayByte::newArray(epilogueSize); | ||
auto resPtr = res->pin(); | ||
|
||
// copy epilogue into java land | ||
memcpy(reinterpret_cast<uint8_t *>(resPtr.get()), epilogue, epilogueSize); | ||
return res; | ||
} | ||
} | ||
|
||
jni::local_ref<jbyteArray> HermesEpilogue::getHermesBytecodeMetadata( | ||
jni::alias_ref<jclass>, | ||
jni::alias_ref<jbyteArray> jByteArray) { | ||
auto bytesPrimArr = jByteArray->pin(); | ||
size_t fileSize = bytesPrimArr.size(); | ||
const auto bytes = reinterpret_cast<const uint8_t *>(bytesPrimArr.get()); | ||
return metadataParserImpl(bytes, fileSize); | ||
} | ||
|
||
jni::local_ref<jbyteArray> HermesEpilogue::getHermesBCFileMetadata( | ||
jni::alias_ref<jclass>, | ||
std::string filename) { | ||
MappedFileBuffer buf{filename}; | ||
return metadataParserImpl(buf.data(), buf.size()); | ||
} | ||
|
||
void HermesEpilogue::registerNatives() { | ||
javaClassLocal()->registerNatives({ | ||
makeNativeMethod( | ||
"getHermesBytecodeMetadata", | ||
HermesEpilogue::getHermesBytecodeMetadata), | ||
makeNativeMethod( | ||
"getHermesBCFileMetadata", HermesEpilogue::getHermesBCFileMetadata), | ||
}); | ||
} | ||
|
||
} // namespace jni | ||
} // namespace jsi | ||
} // namespace facebook |
45 changes: 45 additions & 0 deletions
45
android/test/java/com/facebook/hermes/test/HermesEpilogue.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/* | ||
* Copyright (c) Facebook, Inc. and its affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
#ifndef HERMESEPILOGUE_H_ | ||
#define HERMESEPILOGUE_H_ | ||
|
||
#include <fb/fbjni.h> | ||
#include <jni/Registration.h> | ||
#include <jsi/jsi.h> | ||
|
||
namespace facebook { | ||
namespace jsi { | ||
namespace jni { | ||
|
||
namespace jni = ::facebook::jni; | ||
|
||
class HermesEpilogue : public jni::HybridClass<HermesEpilogue> { | ||
public: | ||
constexpr static auto kJavaDescriptor = | ||
"Lcom/facebook/hermes/test/HermesEpilogue;"; | ||
static jni::local_ref<jbyteArray> getHermesBytecodeMetadata( | ||
jni::alias_ref<jclass>, | ||
jni::alias_ref<jbyteArray> bytes); | ||
static jni::local_ref<jbyteArray> getHermesBCFileMetadata( | ||
jni::alias_ref<jclass>, | ||
std::string filename); | ||
|
||
static void registerNatives(); | ||
|
||
private: | ||
friend HybridBase; | ||
HermesEpilogue(std::unique_ptr<jsi::Runtime> rt); | ||
|
||
std::unique_ptr<jsi::Runtime> runtime_; | ||
}; | ||
|
||
} // namespace jni | ||
} // namespace jsi | ||
} // namespace facebook | ||
|
||
#endif /* HERMESEPILOGUE_H_ */ |
45 changes: 45 additions & 0 deletions
45
android/test/java/com/facebook/hermes/test/HermesEpilogue.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/* | ||
* Copyright (c) Facebook, Inc. and its affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
package com.facebook.hermes.test; | ||
|
||
import android.annotation.SuppressLint; | ||
import com.facebook.jni.HybridData; | ||
import com.facebook.proguard.annotations.DoNotStrip; | ||
import com.facebook.soloader.SoLoader; | ||
|
||
public class HermesEpilogue implements AutoCloseable { | ||
static { | ||
SoLoader.loadLibrary("jsijniepi"); | ||
} | ||
|
||
@DoNotStrip | ||
@SuppressLint("NotAccessedPrivateField") | ||
private final HybridData mHybridData; | ||
|
||
/** | ||
* @param bytecode hermes bytecode, note that no validation is done. | ||
* @return Any byte traling the hermes bytecode data in bytes. | ||
*/ | ||
public static native byte[] getHermesBytecodeMetadata(byte[] bytecode); | ||
|
||
/** Same as getHermesBytecodeMetadata but starting from a file. */ | ||
public static native byte[] getHermesBCFileMetadata(String filename); | ||
|
||
private HermesEpilogue(HybridData hybridData) { | ||
mHybridData = hybridData; | ||
} | ||
|
||
/** | ||
* Explicitly deallocate the Runtime. After a particular instance of the Hermes Runtime has been | ||
* closed, any other calls to it will result in a {@link NullPointerException}. | ||
*/ | ||
@Override | ||
public void close() { | ||
mHybridData.resetNative(); | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
android/test/java/com/facebook/hermes/test/HermesEpilogueTestData.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/* | ||
* Copyright (c) Facebook, Inc. and its affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
package com.facebook.hermes.test; | ||
|
||
import java.nio.charset.Charset; | ||
|
||
public class HermesEpilogueTestData { | ||
private static final String SRC = "function f(){}; f()"; | ||
private static final byte[] hermesBytecode = JSRuntime.compileJavaScript(SRC); | ||
|
||
public static byte[] getBytecode() { | ||
return hermesBytecode; | ||
} | ||
|
||
public static byte[] getBytecodeWithEpilogue(String epilogue) { | ||
byte[] epilogueAsBytes = epilogue.getBytes(Charset.forName("UTF-8")); | ||
byte[] hermesBytecodeWithEpilogue = new byte[hermesBytecode.length + epilogueAsBytes.length]; | ||
System.arraycopy(hermesBytecode, 0, hermesBytecodeWithEpilogue, 0, hermesBytecode.length); | ||
System.arraycopy( | ||
epilogueAsBytes, | ||
0, | ||
hermesBytecodeWithEpilogue, | ||
hermesBytecode.length, | ||
epilogueAsBytes.length); | ||
return hermesBytecodeWithEpilogue; | ||
} | ||
} |
166 changes: 166 additions & 0 deletions
166
android/test/java/com/facebook/hermes/test/HermesInstrumentationTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
/* | ||
* Copyright (c) Facebook, Inc. and its affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
package com.facebook.hermes.test; | ||
|
||
import static org.fest.assertions.api.Assertions.assertThat; | ||
|
||
import android.test.InstrumentationTestCase; | ||
import java.util.Locale; | ||
import java.util.TimeZone; | ||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
import org.junit.Test; | ||
|
||
public class HermesInstrumentationTest extends InstrumentationTestCase { | ||
|
||
@Test | ||
public void testEvaluatingJavaScript() { | ||
try (JSRuntime rt = JSRuntime.makeHermesRuntime()) { | ||
rt.evaluateJavaScript("x = 1;"); | ||
} | ||
} | ||
|
||
@Test | ||
public void testLocaleCompare() { | ||
try (JSRuntime rt = JSRuntime.makeHermesRuntime()) { | ||
rt.evaluateJavaScript("compareResult1 = 'a'.localeCompare('a');"); | ||
rt.evaluateJavaScript("compareResult2 = 'a'.localeCompare('b');"); | ||
rt.evaluateJavaScript("compareResult3 = 'a'.localeCompare('A');"); | ||
rt.evaluateJavaScript("compareResult4 = 'b'.localeCompare('A');"); | ||
rt.evaluateJavaScript("compareResult5 = '\u00FC'.localeCompare('\u00FC');"); | ||
rt.evaluateJavaScript("compareResult6 = '\u00FC'.localeCompare('u');"); | ||
|
||
int result1 = rt.getGlobalNumberProperty("compareResult1"); | ||
assertThat(result1).isEqualTo(0); | ||
int result2 = rt.getGlobalNumberProperty("compareResult2"); | ||
assertThat(result2).isEqualTo(-1); | ||
int result3 = rt.getGlobalNumberProperty("compareResult3"); | ||
assertThat(result3).isEqualTo(-1); | ||
int result4 = rt.getGlobalNumberProperty("compareResult4"); | ||
assertThat(result4).isEqualTo(1); | ||
int result5 = rt.getGlobalNumberProperty("compareResult5"); | ||
assertThat(result5).isEqualTo(0); | ||
int result6 = rt.getGlobalNumberProperty("compareResult6"); | ||
assertThat(result6).isEqualTo(1); | ||
} | ||
} | ||
|
||
@Test | ||
public void testDateFormat() { | ||
Locale defaultLocale = Locale.getDefault(); | ||
Locale.setDefault(new Locale("en-US")); | ||
|
||
TimeZone defaultZone = TimeZone.getDefault(); | ||
TimeZone.setDefault(TimeZone.getTimeZone("UTC")); | ||
|
||
try (JSRuntime rt = JSRuntime.makeHermesRuntime()) { | ||
rt.evaluateJavaScript( | ||
new StringBuilder() | ||
.append("var date = new Date(Date.UTC(2012, 11, 20, 3, 0, 0));\n") | ||
.append("d1 = date.toLocaleDateString();\n") | ||
.append("d2 = date.toLocaleTimeString();\n") | ||
.append("d3 = date.toLocaleString();\n") | ||
.toString()); | ||
|
||
String result1 = rt.getGlobalStringProperty("d1"); | ||
assertThat(result1).isEqualTo("Dec 20, 2012"); | ||
String result2 = rt.getGlobalStringProperty("d2"); | ||
assertThat(result2).isEqualTo("3:00:00 AM"); | ||
String result3 = rt.getGlobalStringProperty("d3"); | ||
assertThat(result3).isEqualTo("Dec 20, 2012 3:00:00 AM"); | ||
} finally { | ||
Locale.setDefault(defaultLocale); | ||
TimeZone.setDefault(defaultZone); | ||
} | ||
} | ||
|
||
@Test | ||
public void testCaseConversion() { | ||
Locale defaultLocale = Locale.getDefault(); | ||
Locale.setDefault(new Locale("en-US")); | ||
|
||
try (JSRuntime rt = JSRuntime.makeHermesRuntime()) { | ||
rt.evaluateJavaScript( | ||
new StringBuilder() | ||
.append("var s1 = 'abc'.toUpperCase();") | ||
.append("var s2 = '\u00E0'.toUpperCase();") | ||
.toString()); | ||
String result1 = rt.getGlobalStringProperty("s1"); | ||
assertThat(result1).isEqualTo("ABC"); | ||
String result2 = rt.getGlobalStringProperty("s2"); | ||
assertThat(result2).isEqualTo("\u00C0"); | ||
} | ||
} | ||
|
||
@Test | ||
public void testNormalize() { | ||
Locale defaultLocale = Locale.getDefault(); | ||
Locale.setDefault(new Locale("en-US")); | ||
|
||
try (JSRuntime rt = JSRuntime.makeHermesRuntime()) { | ||
rt.evaluateJavaScript( | ||
new StringBuilder() | ||
.append("var s1 = '\u1E9B\u0323'.normalize('NFC');") | ||
.append("var s2 = '\u1E9B\u0323'.normalize('NFD');") | ||
.append("var s3 = '\u1E9B\u0323'.normalize('NFKC');") | ||
.append("var s4 = '\u1E9B\u0323'.normalize('NFKD');") | ||
.toString()); | ||
String result1 = rt.getGlobalStringProperty("s1"); | ||
String result2 = rt.getGlobalStringProperty("s2"); | ||
String result3 = rt.getGlobalStringProperty("s3"); | ||
String result4 = rt.getGlobalStringProperty("s4"); | ||
assertThat(result1).isEqualTo("\u1E9B\u0323"); | ||
assertThat(result2).isEqualTo("\u017F\u0323\u0307"); | ||
assertThat(result3).isEqualTo("\u1E69"); | ||
assertThat(result4).isEqualTo("\u0073\u0323\u0307"); | ||
} | ||
} | ||
|
||
// Gets the recorded GC stats from the runtime, finds the reported heap size, | ||
// parses is a long, and returns that. | ||
private long getHeapSize(JSRuntime rt) { | ||
String pattern = "\"Heap size\": ([0-9]+),"; | ||
Pattern r = Pattern.compile(pattern, Pattern.MULTILINE); | ||
Matcher m = r.matcher(rt.getRecordedGCStats()); | ||
assertThat(m.find()).isTrue(); | ||
return Long.parseLong(m.group(1)); | ||
} | ||
|
||
@Test | ||
public void testCreateRuntimeWithHeapSpec() { | ||
long M = 1024 * 1024; | ||
// The current default initial heap size is 32M. Verify that. | ||
// In doing such verifications, some heaps, especially NCGen, may round | ||
// the requested size up to meet various constraints -- but never by as much | ||
// as 8MB (the size of an NCGen segment). | ||
try (JSRuntime rt = JSRuntime.makeHermesRuntime(/* shouldRecordGCStats */ true)) { | ||
assertThat(getHeapSize(rt)).isGreaterThanOrEqualTo(32 * M); | ||
assertThat(getHeapSize(rt)).isLessThan(32 * M + 8 * M); | ||
} | ||
|
||
// Now show that we can make runtime with a smaller heap with the alternate | ||
// factory function: | ||
try (JSRuntime rt = | ||
JSRuntime.makeHermesRuntimeWithHeapSpec(8 * M, 8 * M, /* shouldRecordGCStats */ true)) { | ||
assertThat(getHeapSize(rt)).isGreaterThanOrEqualTo(8 * M); | ||
assertThat(getHeapSize(rt)).isLessThan(8 * M + 8 * M); | ||
} | ||
} | ||
|
||
@Test | ||
public void testGetHermesEpilogue() { | ||
final String EXPECTED_EPILOGUE = "{\"foo\" : \"bar\"}\n"; | ||
byte[] s = HermesEpilogue.getHermesBytecodeMetadata(HermesEpilogueTestData.getBytecode()); | ||
assertThat(s.length).isZero(); | ||
|
||
byte[] epilogue = | ||
HermesEpilogue.getHermesBytecodeMetadata( | ||
HermesEpilogueTestData.getBytecodeWithEpilogue(EXPECTED_EPILOGUE)); | ||
assertEquals(EXPECTED_EPILOGUE, new String(epilogue)); | ||
} | ||
} |
Oops, something went wrong.