[asm.js] Switch StdlibSet to be a uint64_t bit set.
This switches the {StdlibSet} to be a data structure that does not require dynamic memory allocation. This makes it easier to carry it around as part of a {CompilationJob} and serialize it into the heap. R=clemensh@chromium.org Change-Id: I77b2353cfdcd9438a26f04d00749159fed9b9b6c Reviewed-on: https://chromium-review.googlesource.com/584868 Commit-Queue: Michael Starzinger <mstarzinger@chromium.org> Reviewed-by: Clemens Hammacher <clemensh@chromium.org> Cr-Commit-Position: refs/heads/master@{#46889}
This commit is contained in:
parent
6e4d2a60ba
commit
637b7d645c
@ -34,7 +34,7 @@ const char* const AsmJs::kSingleFunctionName = "__single_function__";
|
|||||||
namespace {
|
namespace {
|
||||||
enum WasmDataEntries {
|
enum WasmDataEntries {
|
||||||
kWasmDataCompiledModule,
|
kWasmDataCompiledModule,
|
||||||
kWasmDataUsesArray,
|
kWasmDataUsesBitSet,
|
||||||
kWasmDataEntryCount,
|
kWasmDataEntryCount,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -49,62 +49,69 @@ Handle<Object> StdlibMathMember(Isolate* isolate, Handle<JSReceiver> stdlib,
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsStdlibMemberValid(Isolate* isolate, Handle<JSReceiver> stdlib,
|
bool AreStdlibMembersValid(Isolate* isolate, Handle<JSReceiver> stdlib,
|
||||||
wasm::AsmJsParser::StandardMember member,
|
wasm::AsmJsParser::StdlibSet members,
|
||||||
bool* is_typed_array) {
|
bool* is_typed_array) {
|
||||||
switch (member) {
|
if (members.Contains(wasm::AsmJsParser::StandardMember::kInfinity)) {
|
||||||
case wasm::AsmJsParser::StandardMember::kInfinity: {
|
members.Remove(wasm::AsmJsParser::StandardMember::kInfinity);
|
||||||
Handle<Name> name = isolate->factory()->Infinity_string();
|
Handle<Name> name = isolate->factory()->Infinity_string();
|
||||||
Handle<Object> value = JSReceiver::GetDataProperty(stdlib, name);
|
Handle<Object> value = JSReceiver::GetDataProperty(stdlib, name);
|
||||||
return value->IsNumber() && std::isinf(value->Number());
|
if (!value->IsNumber() || !std::isinf(value->Number())) return false;
|
||||||
}
|
|
||||||
case wasm::AsmJsParser::StandardMember::kNaN: {
|
|
||||||
Handle<Name> name = isolate->factory()->NaN_string();
|
|
||||||
Handle<Object> value = JSReceiver::GetDataProperty(stdlib, name);
|
|
||||||
return value->IsNaN();
|
|
||||||
}
|
|
||||||
#define STDLIB_MATH_FUNC(fname, FName, ignore1, ignore2) \
|
|
||||||
case wasm::AsmJsParser::StandardMember::kMath##FName: { \
|
|
||||||
Handle<Name> name(isolate->factory()->InternalizeOneByteString( \
|
|
||||||
STATIC_CHAR_VECTOR(#fname))); \
|
|
||||||
Handle<Object> value = StdlibMathMember(isolate, stdlib, name); \
|
|
||||||
if (!value->IsJSFunction()) return false; \
|
|
||||||
Handle<JSFunction> func = Handle<JSFunction>::cast(value); \
|
|
||||||
return func->shared()->code() == \
|
|
||||||
isolate->builtins()->builtin(Builtins::kMath##FName); \
|
|
||||||
}
|
}
|
||||||
STDLIB_MATH_FUNCTION_LIST(STDLIB_MATH_FUNC)
|
if (members.Contains(wasm::AsmJsParser::StandardMember::kNaN)) {
|
||||||
|
members.Remove(wasm::AsmJsParser::StandardMember::kNaN);
|
||||||
|
Handle<Name> name = isolate->factory()->NaN_string();
|
||||||
|
Handle<Object> value = JSReceiver::GetDataProperty(stdlib, name);
|
||||||
|
if (!value->IsNaN()) return false;
|
||||||
|
}
|
||||||
|
#define STDLIB_MATH_FUNC(fname, FName, ignore1, ignore2) \
|
||||||
|
if (members.Contains(wasm::AsmJsParser::StandardMember::kMath##FName)) { \
|
||||||
|
members.Remove(wasm::AsmJsParser::StandardMember::kMath##FName); \
|
||||||
|
Handle<Name> name(isolate->factory()->InternalizeOneByteString( \
|
||||||
|
STATIC_CHAR_VECTOR(#fname))); \
|
||||||
|
Handle<Object> value = StdlibMathMember(isolate, stdlib, name); \
|
||||||
|
if (!value->IsJSFunction()) return false; \
|
||||||
|
Handle<JSFunction> func = Handle<JSFunction>::cast(value); \
|
||||||
|
if (func->shared()->code() != \
|
||||||
|
isolate->builtins()->builtin(Builtins::kMath##FName)) { \
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
STDLIB_MATH_FUNCTION_LIST(STDLIB_MATH_FUNC)
|
||||||
#undef STDLIB_MATH_FUNC
|
#undef STDLIB_MATH_FUNC
|
||||||
#define STDLIB_MATH_CONST(cname, const_value) \
|
#define STDLIB_MATH_CONST(cname, const_value) \
|
||||||
case wasm::AsmJsParser::StandardMember::kMath##cname: { \
|
if (members.Contains(wasm::AsmJsParser::StandardMember::kMath##cname)) { \
|
||||||
Handle<Name> name(isolate->factory()->InternalizeOneByteString( \
|
members.Remove(wasm::AsmJsParser::StandardMember::kMath##cname); \
|
||||||
STATIC_CHAR_VECTOR(#cname))); \
|
Handle<Name> name(isolate->factory()->InternalizeOneByteString( \
|
||||||
Handle<Object> value = StdlibMathMember(isolate, stdlib, name); \
|
STATIC_CHAR_VECTOR(#cname))); \
|
||||||
return value->IsNumber() && value->Number() == const_value; \
|
Handle<Object> value = StdlibMathMember(isolate, stdlib, name); \
|
||||||
|
if (!value->IsNumber() || value->Number() != const_value) return false; \
|
||||||
}
|
}
|
||||||
STDLIB_MATH_VALUE_LIST(STDLIB_MATH_CONST)
|
STDLIB_MATH_VALUE_LIST(STDLIB_MATH_CONST)
|
||||||
#undef STDLIB_MATH_CONST
|
#undef STDLIB_MATH_CONST
|
||||||
#define STDLIB_ARRAY_TYPE(fname, FName) \
|
#define STDLIB_ARRAY_TYPE(fname, FName) \
|
||||||
case wasm::AsmJsParser::StandardMember::k##FName: { \
|
if (members.Contains(wasm::AsmJsParser::StandardMember::k##FName)) { \
|
||||||
*is_typed_array = true; \
|
members.Remove(wasm::AsmJsParser::StandardMember::k##FName); \
|
||||||
Handle<Name> name(isolate->factory()->InternalizeOneByteString( \
|
*is_typed_array = true; \
|
||||||
STATIC_CHAR_VECTOR(#FName))); \
|
Handle<Name> name(isolate->factory()->InternalizeOneByteString( \
|
||||||
Handle<Object> value = JSReceiver::GetDataProperty(stdlib, name); \
|
STATIC_CHAR_VECTOR(#FName))); \
|
||||||
if (!value->IsJSFunction()) return false; \
|
Handle<Object> value = JSReceiver::GetDataProperty(stdlib, name); \
|
||||||
Handle<JSFunction> func = Handle<JSFunction>::cast(value); \
|
if (!value->IsJSFunction()) return false; \
|
||||||
return func.is_identical_to(isolate->fname()); \
|
Handle<JSFunction> func = Handle<JSFunction>::cast(value); \
|
||||||
|
if (!func.is_identical_to(isolate->fname())) return false; \
|
||||||
}
|
}
|
||||||
STDLIB_ARRAY_TYPE(int8_array_fun, Int8Array)
|
STDLIB_ARRAY_TYPE(int8_array_fun, Int8Array)
|
||||||
STDLIB_ARRAY_TYPE(uint8_array_fun, Uint8Array)
|
STDLIB_ARRAY_TYPE(uint8_array_fun, Uint8Array)
|
||||||
STDLIB_ARRAY_TYPE(int16_array_fun, Int16Array)
|
STDLIB_ARRAY_TYPE(int16_array_fun, Int16Array)
|
||||||
STDLIB_ARRAY_TYPE(uint16_array_fun, Uint16Array)
|
STDLIB_ARRAY_TYPE(uint16_array_fun, Uint16Array)
|
||||||
STDLIB_ARRAY_TYPE(int32_array_fun, Int32Array)
|
STDLIB_ARRAY_TYPE(int32_array_fun, Int32Array)
|
||||||
STDLIB_ARRAY_TYPE(uint32_array_fun, Uint32Array)
|
STDLIB_ARRAY_TYPE(uint32_array_fun, Uint32Array)
|
||||||
STDLIB_ARRAY_TYPE(float32_array_fun, Float32Array)
|
STDLIB_ARRAY_TYPE(float32_array_fun, Float32Array)
|
||||||
STDLIB_ARRAY_TYPE(float64_array_fun, Float64Array)
|
STDLIB_ARRAY_TYPE(float64_array_fun, Float64Array)
|
||||||
#undef STDLIB_ARRAY_TYPE
|
#undef STDLIB_ARRAY_TYPE
|
||||||
}
|
// All members accounted for.
|
||||||
UNREACHABLE();
|
DCHECK(members.IsEmpty());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Report(Handle<Script> script, int position, Vector<const char> text,
|
void Report(Handle<Script> script, int position, Vector<const char> text,
|
||||||
@ -171,7 +178,7 @@ void ReportInstantiationFailure(Handle<Script> script, int position,
|
|||||||
// [1] PrepareJobImpl: The asm.js module source is parsed, validated, and
|
// [1] PrepareJobImpl: The asm.js module source is parsed, validated, and
|
||||||
// translated to a valid WebAssembly module. The result are two vectors
|
// translated to a valid WebAssembly module. The result are two vectors
|
||||||
// representing the encoded module as well as encoded source position
|
// representing the encoded module as well as encoded source position
|
||||||
// information and a StdlibSet.
|
// information and a StdlibSet bit set.
|
||||||
// [2] FinalizeJobImp: The module is handed to WebAssembly which decodes it
|
// [2] FinalizeJobImp: The module is handed to WebAssembly which decodes it
|
||||||
// into an internal representation and eventually compiles it to machine
|
// into an internal representation and eventually compiles it to machine
|
||||||
// code.
|
// code.
|
||||||
@ -192,7 +199,6 @@ class AsmJsCompilationJob final : public CompilationJob {
|
|||||||
private:
|
private:
|
||||||
wasm::ZoneBuffer* module_;
|
wasm::ZoneBuffer* module_;
|
||||||
wasm::ZoneBuffer* asm_offsets_;
|
wasm::ZoneBuffer* asm_offsets_;
|
||||||
// TODO(mstarzinger) Replace with a bitvector.
|
|
||||||
wasm::AsmJsParser::StdlibSet stdlib_uses_;
|
wasm::AsmJsParser::StdlibSet stdlib_uses_;
|
||||||
|
|
||||||
double translate_time_; // Time (milliseconds) taken to execute step [1].
|
double translate_time_; // Time (milliseconds) taken to execute step [1].
|
||||||
@ -228,7 +234,7 @@ CompilationJob::Status AsmJsCompilationJob::PrepareJobImpl() {
|
|||||||
parser.module_builder()->WriteTo(*module_);
|
parser.module_builder()->WriteTo(*module_);
|
||||||
asm_offsets_ = new (compile_zone) wasm::ZoneBuffer(compile_zone);
|
asm_offsets_ = new (compile_zone) wasm::ZoneBuffer(compile_zone);
|
||||||
parser.module_builder()->WriteAsmJsOffsetTable(*asm_offsets_);
|
parser.module_builder()->WriteAsmJsOffsetTable(*asm_offsets_);
|
||||||
stdlib_uses_.swap(*parser.stdlib_uses());
|
stdlib_uses_ = *parser.stdlib_uses();
|
||||||
|
|
||||||
size_t compile_zone_size =
|
size_t compile_zone_size =
|
||||||
info()->zone()->allocation_size() - compile_zone_start;
|
info()->zone()->allocation_size() - compile_zone_start;
|
||||||
@ -259,12 +265,9 @@ CompilationJob::Status AsmJsCompilationJob::FinalizeJobImpl() {
|
|||||||
base::ElapsedTimer compile_timer;
|
base::ElapsedTimer compile_timer;
|
||||||
compile_timer.Start();
|
compile_timer.Start();
|
||||||
|
|
||||||
Handle<FixedArray> uses_array = info()->isolate()->factory()->NewFixedArray(
|
Handle<HeapNumber> uses_bitset =
|
||||||
static_cast<int>(stdlib_uses_.size()));
|
info()->isolate()->factory()->NewHeapNumberFromBits(
|
||||||
int count = 0;
|
stdlib_uses_.ToIntegral());
|
||||||
for (auto i : stdlib_uses_) {
|
|
||||||
uses_array->set(count++, Smi::FromInt(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
wasm::ErrorThrower thrower(info()->isolate(), "AsmJs::Compile");
|
wasm::ErrorThrower thrower(info()->isolate(), "AsmJs::Compile");
|
||||||
Handle<WasmModuleObject> compiled =
|
Handle<WasmModuleObject> compiled =
|
||||||
@ -281,7 +284,7 @@ CompilationJob::Status AsmJsCompilationJob::FinalizeJobImpl() {
|
|||||||
Handle<FixedArray> result =
|
Handle<FixedArray> result =
|
||||||
info()->isolate()->factory()->NewFixedArray(kWasmDataEntryCount);
|
info()->isolate()->factory()->NewFixedArray(kWasmDataEntryCount);
|
||||||
result->set(kWasmDataCompiledModule, *compiled);
|
result->set(kWasmDataCompiledModule, *compiled);
|
||||||
result->set(kWasmDataUsesArray, *uses_array);
|
result->set(kWasmDataUsesBitSet, *uses_bitset);
|
||||||
info()->SetAsmWasmData(result);
|
info()->SetAsmWasmData(result);
|
||||||
info()->SetCode(info()->isolate()->builtins()->InstantiateAsmJs());
|
info()->SetCode(info()->isolate()->builtins()->InstantiateAsmJs());
|
||||||
|
|
||||||
@ -302,8 +305,8 @@ MaybeHandle<Object> AsmJs::InstantiateAsmWasm(Isolate* isolate,
|
|||||||
Handle<JSArrayBuffer> memory) {
|
Handle<JSArrayBuffer> memory) {
|
||||||
base::ElapsedTimer instantiate_timer;
|
base::ElapsedTimer instantiate_timer;
|
||||||
instantiate_timer.Start();
|
instantiate_timer.Start();
|
||||||
Handle<FixedArray> stdlib_uses(
|
Handle<HeapNumber> uses_bitset(
|
||||||
FixedArray::cast(wasm_data->get(kWasmDataUsesArray)));
|
HeapNumber::cast(wasm_data->get(kWasmDataUsesBitSet)));
|
||||||
Handle<WasmModuleObject> module(
|
Handle<WasmModuleObject> module(
|
||||||
WasmModuleObject::cast(wasm_data->get(kWasmDataCompiledModule)));
|
WasmModuleObject::cast(wasm_data->get(kWasmDataCompiledModule)));
|
||||||
Handle<Script> script(Script::cast(shared->script()));
|
Handle<Script> script(Script::cast(shared->script()));
|
||||||
@ -313,16 +316,14 @@ MaybeHandle<Object> AsmJs::InstantiateAsmWasm(Isolate* isolate,
|
|||||||
|
|
||||||
// Check that all used stdlib members are valid.
|
// Check that all used stdlib members are valid.
|
||||||
bool stdlib_use_of_typed_array_present = false;
|
bool stdlib_use_of_typed_array_present = false;
|
||||||
for (int i = 0; i < stdlib_uses->length(); ++i) {
|
wasm::AsmJsParser::StdlibSet stdlib_uses(uses_bitset->value_as_bits());
|
||||||
|
if (!stdlib_uses.IsEmpty()) { // No checking needed if no uses.
|
||||||
if (stdlib.is_null()) {
|
if (stdlib.is_null()) {
|
||||||
ReportInstantiationFailure(script, position, "Requires standard library");
|
ReportInstantiationFailure(script, position, "Requires standard library");
|
||||||
return MaybeHandle<Object>();
|
return MaybeHandle<Object>();
|
||||||
}
|
}
|
||||||
int member_id = Smi::ToInt(stdlib_uses->get(i));
|
if (!AreStdlibMembersValid(isolate, stdlib, stdlib_uses,
|
||||||
wasm::AsmJsParser::StandardMember member =
|
&stdlib_use_of_typed_array_present)) {
|
||||||
static_cast<wasm::AsmJsParser::StandardMember>(member_id);
|
|
||||||
if (!IsStdlibMemberValid(isolate, stdlib, member,
|
|
||||||
&stdlib_use_of_typed_array_present)) {
|
|
||||||
ReportInstantiationFailure(script, position, "Unexpected stdlib member");
|
ReportInstantiationFailure(script, position, "Unexpected stdlib member");
|
||||||
return MaybeHandle<Object>();
|
return MaybeHandle<Object>();
|
||||||
}
|
}
|
||||||
|
@ -550,7 +550,7 @@ void AsmJsParser::ValidateModuleVarNewStdlib(VarInfo* info) {
|
|||||||
#define V(name, _junk1, _junk2, _junk3) \
|
#define V(name, _junk1, _junk2, _junk3) \
|
||||||
case TOK(name): \
|
case TOK(name): \
|
||||||
DeclareStdlibFunc(info, VarKind::kSpecial, AsmType::name()); \
|
DeclareStdlibFunc(info, VarKind::kSpecial, AsmType::name()); \
|
||||||
stdlib_uses_.insert(StandardMember::k##name); \
|
stdlib_uses_.Add(StandardMember::k##name); \
|
||||||
break;
|
break;
|
||||||
STDLIB_ARRAY_TYPE_LIST(V)
|
STDLIB_ARRAY_TYPE_LIST(V)
|
||||||
#undef V
|
#undef V
|
||||||
@ -573,14 +573,14 @@ void AsmJsParser::ValidateModuleVarStdlib(VarInfo* info) {
|
|||||||
case TOK(name): \
|
case TOK(name): \
|
||||||
DeclareGlobal(info, false, AsmType::Double(), kWasmF64, \
|
DeclareGlobal(info, false, AsmType::Double(), kWasmF64, \
|
||||||
WasmInitExpr(const_value)); \
|
WasmInitExpr(const_value)); \
|
||||||
stdlib_uses_.insert(StandardMember::kMath##name); \
|
stdlib_uses_.Add(StandardMember::kMath##name); \
|
||||||
break;
|
break;
|
||||||
STDLIB_MATH_VALUE_LIST(V)
|
STDLIB_MATH_VALUE_LIST(V)
|
||||||
#undef V
|
#undef V
|
||||||
#define V(name, Name, op, sig) \
|
#define V(name, Name, op, sig) \
|
||||||
case TOK(name): \
|
case TOK(name): \
|
||||||
DeclareStdlibFunc(info, VarKind::kMath##Name, stdlib_##sig##_); \
|
DeclareStdlibFunc(info, VarKind::kMath##Name, stdlib_##sig##_); \
|
||||||
stdlib_uses_.insert(StandardMember::kMath##Name); \
|
stdlib_uses_.Add(StandardMember::kMath##Name); \
|
||||||
break;
|
break;
|
||||||
STDLIB_MATH_FUNCTION_LIST(V)
|
STDLIB_MATH_FUNCTION_LIST(V)
|
||||||
#undef V
|
#undef V
|
||||||
@ -590,11 +590,11 @@ void AsmJsParser::ValidateModuleVarStdlib(VarInfo* info) {
|
|||||||
} else if (Check(TOK(Infinity))) {
|
} else if (Check(TOK(Infinity))) {
|
||||||
DeclareGlobal(info, false, AsmType::Double(), kWasmF64,
|
DeclareGlobal(info, false, AsmType::Double(), kWasmF64,
|
||||||
WasmInitExpr(std::numeric_limits<double>::infinity()));
|
WasmInitExpr(std::numeric_limits<double>::infinity()));
|
||||||
stdlib_uses_.insert(StandardMember::kInfinity);
|
stdlib_uses_.Add(StandardMember::kInfinity);
|
||||||
} else if (Check(TOK(NaN))) {
|
} else if (Check(TOK(NaN))) {
|
||||||
DeclareGlobal(info, false, AsmType::Double(), kWasmF64,
|
DeclareGlobal(info, false, AsmType::Double(), kWasmF64,
|
||||||
WasmInitExpr(std::numeric_limits<double>::quiet_NaN()));
|
WasmInitExpr(std::numeric_limits<double>::quiet_NaN()));
|
||||||
stdlib_uses_.insert(StandardMember::kNaN);
|
stdlib_uses_.Add(StandardMember::kNaN);
|
||||||
} else {
|
} else {
|
||||||
FAIL("Invalid member of stdlib");
|
FAIL("Invalid member of stdlib");
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ class AsmJsParser {
|
|||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
typedef std::unordered_set<StandardMember, std::hash<int>> StdlibSet;
|
typedef EnumSet<StandardMember, uint64_t> StdlibSet;
|
||||||
|
|
||||||
explicit AsmJsParser(Zone* zone, uintptr_t stack_limit,
|
explicit AsmJsParser(Zone* zone, uintptr_t stack_limit,
|
||||||
std::unique_ptr<Utf16CharacterStream> stream);
|
std::unique_ptr<Utf16CharacterStream> stream);
|
||||||
@ -55,7 +55,7 @@ class AsmJsParser {
|
|||||||
const char* failure_message() const { return failure_message_; }
|
const char* failure_message() const { return failure_message_; }
|
||||||
int failure_location() const { return failure_location_; }
|
int failure_location() const { return failure_location_; }
|
||||||
WasmModuleBuilder* module_builder() { return module_builder_; }
|
WasmModuleBuilder* module_builder() { return module_builder_; }
|
||||||
StdlibSet* stdlib_uses() { return &stdlib_uses_; }
|
const StdlibSet* stdlib_uses() const { return &stdlib_uses_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
Loading…
Reference in New Issue
Block a user