Skip to content

Commit

Permalink
Add source visibility support for lazy and S/D
Browse files Browse the repository at this point in the history
Summary:
The tricky case was to support `toString` on lazy function that
haven't been invoked once (hence not parsed/compiled yet). Luckily,
previous diffs had already set up everything.

Before this diff, we already recorded directives from the
preParse pass and restore the directive nodes for lazy function in
lazyParse, and SemanticValidator will compute sourceVisibility
for lazy functions no different with any other non-lazy functions.
That means, lazy function with non-normal sources have already been
reserved ahead of time in the "root" bytecode module.

So the only thing this diff is doing is to make the `toString`
implementation looking for lazy root bc module instead.

To make sure source visibility works for S/D, we also need to
specialize `getLazyRootModule` return the root RM under S/D.
Note that lazy and S/D are not intended to work together.

Reviewed By: avp

Differential Revision: D26796465

fbshipit-source-id: e847422ba5a177124d763b00690176d10350b2fb
  • Loading branch information
Huxpro authored and facebook-github-bot committed Jul 10, 2021
1 parent d7c7752 commit 6a4b95a
Show file tree
Hide file tree
Showing 10 changed files with 46 additions and 3 deletions.
4 changes: 3 additions & 1 deletion include/hermes/VM/RuntimeModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,10 @@ class RuntimeModule final : public llvh::ilist_node<RuntimeModule> {
/// file's global function (i.e. the first RM created when we started
/// interpreting and lazily compiling the source code). For other RMs,
/// e.g. those loaded from precompiled bytecode, this is just itself.
/// We also return this for RM created from serialization/deserialization.
/// Note that lazy and serialization are not intended to work together.
RuntimeModule *getLazyRootModule() {
#ifdef HERMESVM_LEAN
#if defined(HERMESVM_LEAN) || defined(HERMESVM_SERIALIZE)
return this;
#else
return lazyRoot_;
Expand Down
7 changes: 6 additions & 1 deletion lib/VM/CodeBlock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -255,8 +255,13 @@ OptValue<hbc::DebugSourceLocation> CodeBlock::getSourceLocation(
}

OptValue<uint32_t> CodeBlock::getFunctionSourceID() const {
// Note that for the case of lazy compilation, the function sources had been
// reserved into the function source table of the root bytecode module.
// For non-lazy module, the lazy root module is itself.
llvh::ArrayRef<std::pair<uint32_t, uint32_t>> table =
runtimeModule_->getBytecode()->getFunctionSourceTable();
runtimeModule_->getLazyRootModule()
->getBytecode()
->getFunctionSourceTable();

// Performs a binary search since the function source table is sorted by the
// 1st value. We could further optimize the lookup by loading it as a map in
Expand Down
1 change: 1 addition & 0 deletions lib/VM/JSLib/Function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ functionPrototypeToString(void *, Runtime *runtime, NativeArgs args) {
StringPrimitive *source =
jsFunc->getCodeBlock()
->getRuntimeModule()
->getLazyRootModule()
->getStringPrimFromStringIDMayAllocate(*sourceID);
// Empty source marks implementation-hidden function, fabricate a source
// code string that imitate a NativeFunction.
Expand Down
7 changes: 6 additions & 1 deletion test/hermes/function-toString.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@

// RUN: %hermes %s | %FileCheck --match-full-lines %s
// RUN: %hermes -O %s | %FileCheck --match-full-lines %s
// RUN: %hermes -lazy %s | %FileCheck --match-full-lines %s
// RUN: %hermes -O -target=HBC %s | %FileCheck --match-full-lines %s
// RUN: %hermes -O -target=HBC -emit-binary -out %t.hbc %s && %hermes %t.hbc | %FileCheck --match-full-lines %s
// UNSUPPORTED: serializer

print('Function.prototype.toString');
// CHECK-LABEL: Function.prototype.toString
Expand Down Expand Up @@ -42,11 +44,14 @@ print((function now() { 'hide source' }).toString());
// CHECK-NEXT: function now() { [native code] }


/// --- Function Expression / Arrow / Anonymous ---
/// --- Function Expression ---

print((function fe() { 'show source' }).toString());
// CHECK-NEXT: function fe() { 'show source' }


/// --- Arrow Function Expression ---

print((() => { 'show source' }).toString());
// CHECK-NEXT: () => { 'show source' }

Expand Down
18 changes: 18 additions & 0 deletions test/hermes/lazy-function-toString.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* 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.
*/

// RUN: %hermes -non-strict -O0 %s 2>&1 | %FileCheck --match-full-lines %s
// RUN: %hermes -lazy -non-strict -O0 %s 2>&1 | %FileCheck --match-full-lines %s
// UNSUPPORTED: serializer

// foo is never called, but its source needs to be reserved ahead of time.
function foo(x) { "show source"; }

(function bar() {
print(foo.toString());
// CHECK: function foo(x) { "show source"; }
})()
2 changes: 2 additions & 0 deletions test/hermes/source-visibility/global-hide-source.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
*/

// RUN: %hermes -O %s | %FileCheck --match-full-lines %s
// RUN: %hermes -lazy %s | %FileCheck --match-full-lines %s
// UNSUPPORTED: serializer

'hide source';

Expand Down
2 changes: 2 additions & 0 deletions test/hermes/source-visibility/global-show-source.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
*/

// RUN: %hermes -O %s | %FileCheck --match-full-lines %s
// RUN: %hermes -lazy %s | %FileCheck --match-full-lines %s
// UNSUPPORTED: serializer

'show source';

Expand Down
2 changes: 2 additions & 0 deletions test/hermes/source-visibility/override.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
*/

// RUN: %hermes -O %s | %FileCheck --match-full-lines %s
// RUN: %hermes -lazy %s | %FileCheck --match-full-lines %s
// UNSUPPORTED: serializer

// Inner HideSource can override outer ShowSource
function showSource1() {
Expand Down
1 change: 1 addition & 0 deletions test/hermes/source-visibility/with-eval.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

// RUN: %hermes -O %s | %FileCheck --match-full-lines %s
// RUN: %hermes -lazy %s | %FileCheck --match-full-lines %s

print("with eval");
// CHECK-LABEL: with eval
Expand Down
5 changes: 5 additions & 0 deletions test/serialize/function-usercode.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ var F = function(x) { return x; };
var f = new F(1);
var F2 = function(a,b,c,d,e,f,g,h,i,j,k){}
var foo = function badlength(a, b, c){};
var bar = function showSource(a, b, c){"show source"};
Object.defineProperty(foo, "length", {value:"aa"});
var f2 = function(a, b) {
print(arguments.length, this, a, b);
Expand Down Expand Up @@ -60,6 +61,10 @@ serializeVM(function() {
print(foo);
// CHECK-NEXT: function badlength() { [bytecode] }

// Source visibility directives
print(bar);
// CHECK-NEXT: function showSource(a, b, c){"show source"}

print('call');
// CHECK-LABEL: call
print(f2.length);
Expand Down

0 comments on commit 6a4b95a

Please sign in to comment.