11cb0ef41Sopenharmony_ci// Copyright 2015 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include "src/asmjs/asm-js.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include "src/asmjs/asm-names.h"
81cb0ef41Sopenharmony_ci#include "src/asmjs/asm-parser.h"
91cb0ef41Sopenharmony_ci#include "src/ast/ast.h"
101cb0ef41Sopenharmony_ci#include "src/base/optional.h"
111cb0ef41Sopenharmony_ci#include "src/base/platform/elapsed-timer.h"
121cb0ef41Sopenharmony_ci#include "src/base/vector.h"
131cb0ef41Sopenharmony_ci#include "src/codegen/compiler.h"
141cb0ef41Sopenharmony_ci#include "src/codegen/unoptimized-compilation-info.h"
151cb0ef41Sopenharmony_ci#include "src/common/assert-scope.h"
161cb0ef41Sopenharmony_ci#include "src/common/message-template.h"
171cb0ef41Sopenharmony_ci#include "src/execution/execution.h"
181cb0ef41Sopenharmony_ci#include "src/execution/isolate.h"
191cb0ef41Sopenharmony_ci#include "src/handles/handles.h"
201cb0ef41Sopenharmony_ci#include "src/heap/factory.h"
211cb0ef41Sopenharmony_ci#include "src/logging/counters.h"
221cb0ef41Sopenharmony_ci#include "src/objects/heap-number-inl.h"
231cb0ef41Sopenharmony_ci#include "src/objects/objects-inl.h"
241cb0ef41Sopenharmony_ci#include "src/parsing/parse-info.h"
251cb0ef41Sopenharmony_ci#include "src/parsing/scanner-character-streams.h"
261cb0ef41Sopenharmony_ci#include "src/parsing/scanner.h"
271cb0ef41Sopenharmony_ci#include "src/wasm/wasm-engine.h"
281cb0ef41Sopenharmony_ci#include "src/wasm/wasm-js.h"
291cb0ef41Sopenharmony_ci#include "src/wasm/wasm-limits.h"
301cb0ef41Sopenharmony_ci#include "src/wasm/wasm-module-builder.h"
311cb0ef41Sopenharmony_ci#include "src/wasm/wasm-objects-inl.h"
321cb0ef41Sopenharmony_ci#include "src/wasm/wasm-result.h"
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_cinamespace v8 {
351cb0ef41Sopenharmony_cinamespace internal {
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ciconst char* const AsmJs::kSingleFunctionName = "__single_function__";
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_cinamespace {
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_ciHandle<Object> StdlibMathMember(Isolate* isolate, Handle<JSReceiver> stdlib,
421cb0ef41Sopenharmony_ci                                Handle<Name> name) {
431cb0ef41Sopenharmony_ci  Handle<Name> math_name(
441cb0ef41Sopenharmony_ci      isolate->factory()->InternalizeString(base::StaticCharVector("Math")));
451cb0ef41Sopenharmony_ci  Handle<Object> math = JSReceiver::GetDataProperty(isolate, stdlib, math_name);
461cb0ef41Sopenharmony_ci  if (!math->IsJSReceiver()) return isolate->factory()->undefined_value();
471cb0ef41Sopenharmony_ci  Handle<JSReceiver> math_receiver = Handle<JSReceiver>::cast(math);
481cb0ef41Sopenharmony_ci  Handle<Object> value =
491cb0ef41Sopenharmony_ci      JSReceiver::GetDataProperty(isolate, math_receiver, name);
501cb0ef41Sopenharmony_ci  return value;
511cb0ef41Sopenharmony_ci}
521cb0ef41Sopenharmony_ci
531cb0ef41Sopenharmony_cibool AreStdlibMembersValid(Isolate* isolate, Handle<JSReceiver> stdlib,
541cb0ef41Sopenharmony_ci                           wasm::AsmJsParser::StdlibSet members,
551cb0ef41Sopenharmony_ci                           bool* is_typed_array) {
561cb0ef41Sopenharmony_ci  if (members.contains(wasm::AsmJsParser::StandardMember::kInfinity)) {
571cb0ef41Sopenharmony_ci    members.Remove(wasm::AsmJsParser::StandardMember::kInfinity);
581cb0ef41Sopenharmony_ci    Handle<Name> name = isolate->factory()->Infinity_string();
591cb0ef41Sopenharmony_ci    Handle<Object> value = JSReceiver::GetDataProperty(isolate, stdlib, name);
601cb0ef41Sopenharmony_ci    if (!value->IsNumber() || !std::isinf(value->Number())) return false;
611cb0ef41Sopenharmony_ci  }
621cb0ef41Sopenharmony_ci  if (members.contains(wasm::AsmJsParser::StandardMember::kNaN)) {
631cb0ef41Sopenharmony_ci    members.Remove(wasm::AsmJsParser::StandardMember::kNaN);
641cb0ef41Sopenharmony_ci    Handle<Name> name = isolate->factory()->NaN_string();
651cb0ef41Sopenharmony_ci    Handle<Object> value = JSReceiver::GetDataProperty(isolate, stdlib, name);
661cb0ef41Sopenharmony_ci    if (!value->IsNaN()) return false;
671cb0ef41Sopenharmony_ci  }
681cb0ef41Sopenharmony_ci#define STDLIB_MATH_FUNC(fname, FName, ignore1, ignore2)                   \
691cb0ef41Sopenharmony_ci  if (members.contains(wasm::AsmJsParser::StandardMember::kMath##FName)) { \
701cb0ef41Sopenharmony_ci    members.Remove(wasm::AsmJsParser::StandardMember::kMath##FName);       \
711cb0ef41Sopenharmony_ci    Handle<Name> name(isolate->factory()->InternalizeString(               \
721cb0ef41Sopenharmony_ci        base::StaticCharVector(#fname)));                                  \
731cb0ef41Sopenharmony_ci    Handle<Object> value = StdlibMathMember(isolate, stdlib, name);        \
741cb0ef41Sopenharmony_ci    if (!value->IsJSFunction()) return false;                              \
751cb0ef41Sopenharmony_ci    SharedFunctionInfo shared = Handle<JSFunction>::cast(value)->shared(); \
761cb0ef41Sopenharmony_ci    if (!shared.HasBuiltinId() ||                                          \
771cb0ef41Sopenharmony_ci        shared.builtin_id() != Builtin::kMath##FName) {                    \
781cb0ef41Sopenharmony_ci      return false;                                                        \
791cb0ef41Sopenharmony_ci    }                                                                      \
801cb0ef41Sopenharmony_ci    DCHECK_EQ(shared.GetCode(),                                            \
811cb0ef41Sopenharmony_ci              isolate->builtins()->code(Builtin::kMath##FName));           \
821cb0ef41Sopenharmony_ci  }
831cb0ef41Sopenharmony_ci  STDLIB_MATH_FUNCTION_LIST(STDLIB_MATH_FUNC)
841cb0ef41Sopenharmony_ci#undef STDLIB_MATH_FUNC
851cb0ef41Sopenharmony_ci#define STDLIB_MATH_CONST(cname, const_value)                               \
861cb0ef41Sopenharmony_ci  if (members.contains(wasm::AsmJsParser::StandardMember::kMath##cname)) {  \
871cb0ef41Sopenharmony_ci    members.Remove(wasm::AsmJsParser::StandardMember::kMath##cname);        \
881cb0ef41Sopenharmony_ci    Handle<Name> name(isolate->factory()->InternalizeString(                \
891cb0ef41Sopenharmony_ci        base::StaticCharVector(#cname)));                                   \
901cb0ef41Sopenharmony_ci    Handle<Object> value = StdlibMathMember(isolate, stdlib, name);         \
911cb0ef41Sopenharmony_ci    if (!value->IsNumber() || value->Number() != const_value) return false; \
921cb0ef41Sopenharmony_ci  }
931cb0ef41Sopenharmony_ci  STDLIB_MATH_VALUE_LIST(STDLIB_MATH_CONST)
941cb0ef41Sopenharmony_ci#undef STDLIB_MATH_CONST
951cb0ef41Sopenharmony_ci#define STDLIB_ARRAY_TYPE(fname, FName)                                        \
961cb0ef41Sopenharmony_ci  if (members.contains(wasm::AsmJsParser::StandardMember::k##FName)) {         \
971cb0ef41Sopenharmony_ci    members.Remove(wasm::AsmJsParser::StandardMember::k##FName);               \
981cb0ef41Sopenharmony_ci    *is_typed_array = true;                                                    \
991cb0ef41Sopenharmony_ci    Handle<Name> name(isolate->factory()->InternalizeString(                   \
1001cb0ef41Sopenharmony_ci        base::StaticCharVector(#FName)));                                      \
1011cb0ef41Sopenharmony_ci    Handle<Object> value = JSReceiver::GetDataProperty(isolate, stdlib, name); \
1021cb0ef41Sopenharmony_ci    if (!value->IsJSFunction()) return false;                                  \
1031cb0ef41Sopenharmony_ci    Handle<JSFunction> func = Handle<JSFunction>::cast(value);                 \
1041cb0ef41Sopenharmony_ci    if (!func.is_identical_to(isolate->fname())) return false;                 \
1051cb0ef41Sopenharmony_ci  }
1061cb0ef41Sopenharmony_ci  STDLIB_ARRAY_TYPE(int8_array_fun, Int8Array)
1071cb0ef41Sopenharmony_ci  STDLIB_ARRAY_TYPE(uint8_array_fun, Uint8Array)
1081cb0ef41Sopenharmony_ci  STDLIB_ARRAY_TYPE(int16_array_fun, Int16Array)
1091cb0ef41Sopenharmony_ci  STDLIB_ARRAY_TYPE(uint16_array_fun, Uint16Array)
1101cb0ef41Sopenharmony_ci  STDLIB_ARRAY_TYPE(int32_array_fun, Int32Array)
1111cb0ef41Sopenharmony_ci  STDLIB_ARRAY_TYPE(uint32_array_fun, Uint32Array)
1121cb0ef41Sopenharmony_ci  STDLIB_ARRAY_TYPE(float32_array_fun, Float32Array)
1131cb0ef41Sopenharmony_ci  STDLIB_ARRAY_TYPE(float64_array_fun, Float64Array)
1141cb0ef41Sopenharmony_ci#undef STDLIB_ARRAY_TYPE
1151cb0ef41Sopenharmony_ci  // All members accounted for.
1161cb0ef41Sopenharmony_ci  DCHECK(members.empty());
1171cb0ef41Sopenharmony_ci  return true;
1181cb0ef41Sopenharmony_ci}
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_civoid Report(Handle<Script> script, int position, base::Vector<const char> text,
1211cb0ef41Sopenharmony_ci            MessageTemplate message_template,
1221cb0ef41Sopenharmony_ci            v8::Isolate::MessageErrorLevel level) {
1231cb0ef41Sopenharmony_ci  Isolate* isolate = script->GetIsolate();
1241cb0ef41Sopenharmony_ci  MessageLocation location(script, position, position);
1251cb0ef41Sopenharmony_ci  Handle<String> text_object = isolate->factory()->InternalizeUtf8String(text);
1261cb0ef41Sopenharmony_ci  Handle<JSMessageObject> message = MessageHandler::MakeMessageObject(
1271cb0ef41Sopenharmony_ci      isolate, message_template, &location, text_object,
1281cb0ef41Sopenharmony_ci      Handle<FixedArray>::null());
1291cb0ef41Sopenharmony_ci  message->set_error_level(level);
1301cb0ef41Sopenharmony_ci  MessageHandler::ReportMessage(isolate, &location, message);
1311cb0ef41Sopenharmony_ci}
1321cb0ef41Sopenharmony_ci
1331cb0ef41Sopenharmony_ci// Hook to report successful execution of {AsmJs::CompileAsmViaWasm} phase.
1341cb0ef41Sopenharmony_civoid ReportCompilationSuccess(Handle<Script> script, int position,
1351cb0ef41Sopenharmony_ci                              double compile_time, size_t module_size) {
1361cb0ef41Sopenharmony_ci  if (FLAG_suppress_asm_messages || !FLAG_trace_asm_time) return;
1371cb0ef41Sopenharmony_ci  base::EmbeddedVector<char, 100> text;
1381cb0ef41Sopenharmony_ci  int length = SNPrintF(text, "success, compile time %0.3f ms, %zu bytes",
1391cb0ef41Sopenharmony_ci                        compile_time, module_size);
1401cb0ef41Sopenharmony_ci  CHECK_NE(-1, length);
1411cb0ef41Sopenharmony_ci  text.Truncate(length);
1421cb0ef41Sopenharmony_ci  Report(script, position, text, MessageTemplate::kAsmJsCompiled,
1431cb0ef41Sopenharmony_ci         v8::Isolate::kMessageInfo);
1441cb0ef41Sopenharmony_ci}
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_ci// Hook to report failed execution of {AsmJs::CompileAsmViaWasm} phase.
1471cb0ef41Sopenharmony_civoid ReportCompilationFailure(ParseInfo* parse_info, int position,
1481cb0ef41Sopenharmony_ci                              const char* reason) {
1491cb0ef41Sopenharmony_ci  if (FLAG_suppress_asm_messages) return;
1501cb0ef41Sopenharmony_ci  parse_info->pending_error_handler()->ReportWarningAt(
1511cb0ef41Sopenharmony_ci      position, position, MessageTemplate::kAsmJsInvalid, reason);
1521cb0ef41Sopenharmony_ci}
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_ci// Hook to report successful execution of {AsmJs::InstantiateAsmWasm} phase.
1551cb0ef41Sopenharmony_civoid ReportInstantiationSuccess(Handle<Script> script, int position,
1561cb0ef41Sopenharmony_ci                                double instantiate_time) {
1571cb0ef41Sopenharmony_ci  if (FLAG_suppress_asm_messages || !FLAG_trace_asm_time) return;
1581cb0ef41Sopenharmony_ci  base::EmbeddedVector<char, 50> text;
1591cb0ef41Sopenharmony_ci  int length = SNPrintF(text, "success, %0.3f ms", instantiate_time);
1601cb0ef41Sopenharmony_ci  CHECK_NE(-1, length);
1611cb0ef41Sopenharmony_ci  text.Truncate(length);
1621cb0ef41Sopenharmony_ci  Report(script, position, text, MessageTemplate::kAsmJsInstantiated,
1631cb0ef41Sopenharmony_ci         v8::Isolate::kMessageInfo);
1641cb0ef41Sopenharmony_ci}
1651cb0ef41Sopenharmony_ci
1661cb0ef41Sopenharmony_ci// Hook to report failed execution of {AsmJs::InstantiateAsmWasm} phase.
1671cb0ef41Sopenharmony_civoid ReportInstantiationFailure(Handle<Script> script, int position,
1681cb0ef41Sopenharmony_ci                                const char* reason) {
1691cb0ef41Sopenharmony_ci  if (FLAG_suppress_asm_messages) return;
1701cb0ef41Sopenharmony_ci  base::Vector<const char> text = base::CStrVector(reason);
1711cb0ef41Sopenharmony_ci  Report(script, position, text, MessageTemplate::kAsmJsLinkingFailed,
1721cb0ef41Sopenharmony_ci         v8::Isolate::kMessageWarning);
1731cb0ef41Sopenharmony_ci}
1741cb0ef41Sopenharmony_ci
1751cb0ef41Sopenharmony_ci}  // namespace
1761cb0ef41Sopenharmony_ci
1771cb0ef41Sopenharmony_ci// The compilation of asm.js modules is split into two distinct steps:
1781cb0ef41Sopenharmony_ci//  [1] ExecuteJobImpl: The asm.js module source is parsed, validated, and
1791cb0ef41Sopenharmony_ci//      translated to a valid WebAssembly module. The result are two vectors
1801cb0ef41Sopenharmony_ci//      representing the encoded module as well as encoded source position
1811cb0ef41Sopenharmony_ci//      information and a StdlibSet bit set.
1821cb0ef41Sopenharmony_ci//  [2] FinalizeJobImpl: The module is handed to WebAssembly which decodes it
1831cb0ef41Sopenharmony_ci//      into an internal representation and eventually compiles it to machine
1841cb0ef41Sopenharmony_ci//      code.
1851cb0ef41Sopenharmony_ciclass AsmJsCompilationJob final : public UnoptimizedCompilationJob {
1861cb0ef41Sopenharmony_ci public:
1871cb0ef41Sopenharmony_ci  explicit AsmJsCompilationJob(ParseInfo* parse_info, FunctionLiteral* literal,
1881cb0ef41Sopenharmony_ci                               AccountingAllocator* allocator)
1891cb0ef41Sopenharmony_ci      : UnoptimizedCompilationJob(parse_info->stack_limit(), parse_info,
1901cb0ef41Sopenharmony_ci                                  &compilation_info_),
1911cb0ef41Sopenharmony_ci        allocator_(allocator),
1921cb0ef41Sopenharmony_ci        zone_(allocator, ZONE_NAME),
1931cb0ef41Sopenharmony_ci        compilation_info_(&zone_, parse_info, literal),
1941cb0ef41Sopenharmony_ci        module_(nullptr),
1951cb0ef41Sopenharmony_ci        asm_offsets_(nullptr),
1961cb0ef41Sopenharmony_ci        compile_time_(0),
1971cb0ef41Sopenharmony_ci        module_source_size_(0) {}
1981cb0ef41Sopenharmony_ci
1991cb0ef41Sopenharmony_ci  AsmJsCompilationJob(const AsmJsCompilationJob&) = delete;
2001cb0ef41Sopenharmony_ci  AsmJsCompilationJob& operator=(const AsmJsCompilationJob&) = delete;
2011cb0ef41Sopenharmony_ci
2021cb0ef41Sopenharmony_ci protected:
2031cb0ef41Sopenharmony_ci  Status ExecuteJobImpl() final;
2041cb0ef41Sopenharmony_ci  Status FinalizeJobImpl(Handle<SharedFunctionInfo> shared_info,
2051cb0ef41Sopenharmony_ci                         Isolate* isolate) final;
2061cb0ef41Sopenharmony_ci  Status FinalizeJobImpl(Handle<SharedFunctionInfo> shared_info,
2071cb0ef41Sopenharmony_ci                         LocalIsolate* isolate) final {
2081cb0ef41Sopenharmony_ci    return CompilationJob::RETRY_ON_MAIN_THREAD;
2091cb0ef41Sopenharmony_ci  }
2101cb0ef41Sopenharmony_ci
2111cb0ef41Sopenharmony_ci private:
2121cb0ef41Sopenharmony_ci  void RecordHistograms(Isolate* isolate);
2131cb0ef41Sopenharmony_ci
2141cb0ef41Sopenharmony_ci  AccountingAllocator* allocator_;
2151cb0ef41Sopenharmony_ci  Zone zone_;
2161cb0ef41Sopenharmony_ci  UnoptimizedCompilationInfo compilation_info_;
2171cb0ef41Sopenharmony_ci  wasm::ZoneBuffer* module_;
2181cb0ef41Sopenharmony_ci  wasm::ZoneBuffer* asm_offsets_;
2191cb0ef41Sopenharmony_ci  wasm::AsmJsParser::StdlibSet stdlib_uses_;
2201cb0ef41Sopenharmony_ci
2211cb0ef41Sopenharmony_ci  double compile_time_;     // Time (milliseconds) taken to execute step [2].
2221cb0ef41Sopenharmony_ci  int module_source_size_;  // Module source size in bytes.
2231cb0ef41Sopenharmony_ci};
2241cb0ef41Sopenharmony_ci
2251cb0ef41Sopenharmony_ciUnoptimizedCompilationJob::Status AsmJsCompilationJob::ExecuteJobImpl() {
2261cb0ef41Sopenharmony_ci  DisallowHeapAccess no_heap_access;
2271cb0ef41Sopenharmony_ci
2281cb0ef41Sopenharmony_ci  // Step 1: Translate asm.js module to WebAssembly module.
2291cb0ef41Sopenharmony_ci  Zone* compile_zone = &zone_;
2301cb0ef41Sopenharmony_ci  Zone translate_zone(allocator_, ZONE_NAME);
2311cb0ef41Sopenharmony_ci
2321cb0ef41Sopenharmony_ci  Utf16CharacterStream* stream = parse_info()->character_stream();
2331cb0ef41Sopenharmony_ci  base::Optional<AllowHandleDereference> allow_deref;
2341cb0ef41Sopenharmony_ci  if (stream->can_access_heap()) {
2351cb0ef41Sopenharmony_ci    allow_deref.emplace();
2361cb0ef41Sopenharmony_ci  }
2371cb0ef41Sopenharmony_ci  stream->Seek(compilation_info()->literal()->start_position());
2381cb0ef41Sopenharmony_ci  wasm::AsmJsParser parser(&translate_zone, stack_limit(), stream);
2391cb0ef41Sopenharmony_ci  if (!parser.Run()) {
2401cb0ef41Sopenharmony_ci    if (!FLAG_suppress_asm_messages) {
2411cb0ef41Sopenharmony_ci      ReportCompilationFailure(parse_info(), parser.failure_location(),
2421cb0ef41Sopenharmony_ci                               parser.failure_message());
2431cb0ef41Sopenharmony_ci    }
2441cb0ef41Sopenharmony_ci    return FAILED;
2451cb0ef41Sopenharmony_ci  }
2461cb0ef41Sopenharmony_ci  module_ = compile_zone->New<wasm::ZoneBuffer>(compile_zone);
2471cb0ef41Sopenharmony_ci  parser.module_builder()->WriteTo(module_);
2481cb0ef41Sopenharmony_ci  asm_offsets_ = compile_zone->New<wasm::ZoneBuffer>(compile_zone);
2491cb0ef41Sopenharmony_ci  parser.module_builder()->WriteAsmJsOffsetTable(asm_offsets_);
2501cb0ef41Sopenharmony_ci  stdlib_uses_ = *parser.stdlib_uses();
2511cb0ef41Sopenharmony_ci
2521cb0ef41Sopenharmony_ci  module_source_size_ = compilation_info()->literal()->end_position() -
2531cb0ef41Sopenharmony_ci                        compilation_info()->literal()->start_position();
2541cb0ef41Sopenharmony_ci  return SUCCEEDED;
2551cb0ef41Sopenharmony_ci}
2561cb0ef41Sopenharmony_ci
2571cb0ef41Sopenharmony_ciUnoptimizedCompilationJob::Status AsmJsCompilationJob::FinalizeJobImpl(
2581cb0ef41Sopenharmony_ci    Handle<SharedFunctionInfo> shared_info, Isolate* isolate) {
2591cb0ef41Sopenharmony_ci  // Step 2: Compile and decode the WebAssembly module.
2601cb0ef41Sopenharmony_ci  base::ElapsedTimer compile_timer;
2611cb0ef41Sopenharmony_ci  compile_timer.Start();
2621cb0ef41Sopenharmony_ci
2631cb0ef41Sopenharmony_ci  Handle<HeapNumber> uses_bitset =
2641cb0ef41Sopenharmony_ci      isolate->factory()->NewHeapNumberFromBits(stdlib_uses_.ToIntegral());
2651cb0ef41Sopenharmony_ci
2661cb0ef41Sopenharmony_ci  // The result is a compiled module and serialized standard library uses.
2671cb0ef41Sopenharmony_ci  wasm::ErrorThrower thrower(isolate, "AsmJs::Compile");
2681cb0ef41Sopenharmony_ci  Handle<AsmWasmData> result =
2691cb0ef41Sopenharmony_ci      wasm::GetWasmEngine()
2701cb0ef41Sopenharmony_ci          ->SyncCompileTranslatedAsmJs(
2711cb0ef41Sopenharmony_ci              isolate, &thrower,
2721cb0ef41Sopenharmony_ci              wasm::ModuleWireBytes(module_->begin(), module_->end()),
2731cb0ef41Sopenharmony_ci              base::VectorOf(*asm_offsets_), uses_bitset,
2741cb0ef41Sopenharmony_ci              shared_info->language_mode())
2751cb0ef41Sopenharmony_ci          .ToHandleChecked();
2761cb0ef41Sopenharmony_ci  DCHECK(!thrower.error());
2771cb0ef41Sopenharmony_ci  compile_time_ = compile_timer.Elapsed().InMillisecondsF();
2781cb0ef41Sopenharmony_ci
2791cb0ef41Sopenharmony_ci  compilation_info()->SetAsmWasmData(result);
2801cb0ef41Sopenharmony_ci
2811cb0ef41Sopenharmony_ci  RecordHistograms(isolate);
2821cb0ef41Sopenharmony_ci  ReportCompilationSuccess(handle(Script::cast(shared_info->script()), isolate),
2831cb0ef41Sopenharmony_ci                           shared_info->StartPosition(), compile_time_,
2841cb0ef41Sopenharmony_ci                           module_->size());
2851cb0ef41Sopenharmony_ci  return SUCCEEDED;
2861cb0ef41Sopenharmony_ci}
2871cb0ef41Sopenharmony_ci
2881cb0ef41Sopenharmony_civoid AsmJsCompilationJob::RecordHistograms(Isolate* isolate) {
2891cb0ef41Sopenharmony_ci  isolate->counters()->asm_module_size_bytes()->AddSample(module_source_size_);
2901cb0ef41Sopenharmony_ci}
2911cb0ef41Sopenharmony_ci
2921cb0ef41Sopenharmony_cistd::unique_ptr<UnoptimizedCompilationJob> AsmJs::NewCompilationJob(
2931cb0ef41Sopenharmony_ci    ParseInfo* parse_info, FunctionLiteral* literal,
2941cb0ef41Sopenharmony_ci    AccountingAllocator* allocator) {
2951cb0ef41Sopenharmony_ci  return std::make_unique<AsmJsCompilationJob>(parse_info, literal, allocator);
2961cb0ef41Sopenharmony_ci}
2971cb0ef41Sopenharmony_ci
2981cb0ef41Sopenharmony_cinamespace {
2991cb0ef41Sopenharmony_ciinline bool IsValidAsmjsMemorySize(size_t size) {
3001cb0ef41Sopenharmony_ci  // Enforce asm.js spec minimum size.
3011cb0ef41Sopenharmony_ci  if (size < (1u << 12u)) return false;
3021cb0ef41Sopenharmony_ci  // Enforce engine-limited and flag-limited maximum allocation size.
3031cb0ef41Sopenharmony_ci  if (size > wasm::max_mem_bytes()) return false;
3041cb0ef41Sopenharmony_ci  // Enforce power-of-2 sizes for 2^12 - 2^24.
3051cb0ef41Sopenharmony_ci  if (size < (1u << 24u)) {
3061cb0ef41Sopenharmony_ci    uint32_t size32 = static_cast<uint32_t>(size);
3071cb0ef41Sopenharmony_ci    return base::bits::IsPowerOfTwo(size32);
3081cb0ef41Sopenharmony_ci  }
3091cb0ef41Sopenharmony_ci  // Enforce multiple of 2^24 for sizes >= 2^24
3101cb0ef41Sopenharmony_ci  if ((size % (1u << 24u)) != 0) return false;
3111cb0ef41Sopenharmony_ci  // All checks passed!
3121cb0ef41Sopenharmony_ci  return true;
3131cb0ef41Sopenharmony_ci}
3141cb0ef41Sopenharmony_ci}  // namespace
3151cb0ef41Sopenharmony_ci
3161cb0ef41Sopenharmony_ciMaybeHandle<Object> AsmJs::InstantiateAsmWasm(Isolate* isolate,
3171cb0ef41Sopenharmony_ci                                              Handle<SharedFunctionInfo> shared,
3181cb0ef41Sopenharmony_ci                                              Handle<AsmWasmData> wasm_data,
3191cb0ef41Sopenharmony_ci                                              Handle<JSReceiver> stdlib,
3201cb0ef41Sopenharmony_ci                                              Handle<JSReceiver> foreign,
3211cb0ef41Sopenharmony_ci                                              Handle<JSArrayBuffer> memory) {
3221cb0ef41Sopenharmony_ci  base::ElapsedTimer instantiate_timer;
3231cb0ef41Sopenharmony_ci  instantiate_timer.Start();
3241cb0ef41Sopenharmony_ci  Handle<HeapNumber> uses_bitset(wasm_data->uses_bitset(), isolate);
3251cb0ef41Sopenharmony_ci  Handle<Script> script(Script::cast(shared->script()), isolate);
3261cb0ef41Sopenharmony_ci  auto* wasm_engine = wasm::GetWasmEngine();
3271cb0ef41Sopenharmony_ci
3281cb0ef41Sopenharmony_ci  // Allocate the WasmModuleObject.
3291cb0ef41Sopenharmony_ci  Handle<WasmModuleObject> module =
3301cb0ef41Sopenharmony_ci      wasm_engine->FinalizeTranslatedAsmJs(isolate, wasm_data, script);
3311cb0ef41Sopenharmony_ci
3321cb0ef41Sopenharmony_ci  // TODO(asmjs): The position currently points to the module definition
3331cb0ef41Sopenharmony_ci  // but should instead point to the instantiation site (more intuitive).
3341cb0ef41Sopenharmony_ci  int position = shared->StartPosition();
3351cb0ef41Sopenharmony_ci
3361cb0ef41Sopenharmony_ci  // Check that the module is not instantiated as a generator or async function.
3371cb0ef41Sopenharmony_ci  if (IsResumableFunction(shared->scope_info().function_kind())) {
3381cb0ef41Sopenharmony_ci    ReportInstantiationFailure(script, position,
3391cb0ef41Sopenharmony_ci                               "Cannot be instantiated as resumable function");
3401cb0ef41Sopenharmony_ci    return MaybeHandle<Object>();
3411cb0ef41Sopenharmony_ci  }
3421cb0ef41Sopenharmony_ci
3431cb0ef41Sopenharmony_ci  // Check that all used stdlib members are valid.
3441cb0ef41Sopenharmony_ci  bool stdlib_use_of_typed_array_present = false;
3451cb0ef41Sopenharmony_ci  wasm::AsmJsParser::StdlibSet stdlib_uses =
3461cb0ef41Sopenharmony_ci      wasm::AsmJsParser::StdlibSet::FromIntegral(
3471cb0ef41Sopenharmony_ci          uses_bitset->value_as_bits(kRelaxedLoad));
3481cb0ef41Sopenharmony_ci  if (!stdlib_uses.empty()) {  // No checking needed if no uses.
3491cb0ef41Sopenharmony_ci    if (stdlib.is_null()) {
3501cb0ef41Sopenharmony_ci      ReportInstantiationFailure(script, position, "Requires standard library");
3511cb0ef41Sopenharmony_ci      return MaybeHandle<Object>();
3521cb0ef41Sopenharmony_ci    }
3531cb0ef41Sopenharmony_ci    if (!AreStdlibMembersValid(isolate, stdlib, stdlib_uses,
3541cb0ef41Sopenharmony_ci                               &stdlib_use_of_typed_array_present)) {
3551cb0ef41Sopenharmony_ci      ReportInstantiationFailure(script, position, "Unexpected stdlib member");
3561cb0ef41Sopenharmony_ci      return MaybeHandle<Object>();
3571cb0ef41Sopenharmony_ci    }
3581cb0ef41Sopenharmony_ci  }
3591cb0ef41Sopenharmony_ci
3601cb0ef41Sopenharmony_ci  // Check that a valid heap buffer is provided if required.
3611cb0ef41Sopenharmony_ci  if (stdlib_use_of_typed_array_present) {
3621cb0ef41Sopenharmony_ci    if (memory.is_null()) {
3631cb0ef41Sopenharmony_ci      ReportInstantiationFailure(script, position, "Requires heap buffer");
3641cb0ef41Sopenharmony_ci      return MaybeHandle<Object>();
3651cb0ef41Sopenharmony_ci    }
3661cb0ef41Sopenharmony_ci    // AsmJs memory must be an ArrayBuffer.
3671cb0ef41Sopenharmony_ci    if (memory->is_shared()) {
3681cb0ef41Sopenharmony_ci      ReportInstantiationFailure(script, position,
3691cb0ef41Sopenharmony_ci                                 "Invalid heap type: SharedArrayBuffer");
3701cb0ef41Sopenharmony_ci      return MaybeHandle<Object>();
3711cb0ef41Sopenharmony_ci    }
3721cb0ef41Sopenharmony_ci    // Mark the buffer as being used as an asm.js memory. This implies two
3731cb0ef41Sopenharmony_ci    // things: 1) if the buffer is from a Wasm memory, that memory can no longer
3741cb0ef41Sopenharmony_ci    // be grown, since that would detach this buffer, and 2) the buffer cannot
3751cb0ef41Sopenharmony_ci    // be postMessage()'d, as that also detaches the buffer.
3761cb0ef41Sopenharmony_ci    memory->set_is_asmjs_memory(true);
3771cb0ef41Sopenharmony_ci    memory->set_is_detachable(false);
3781cb0ef41Sopenharmony_ci    size_t size = memory->byte_length();
3791cb0ef41Sopenharmony_ci    // Check the asm.js heap size against the valid limits.
3801cb0ef41Sopenharmony_ci    if (!IsValidAsmjsMemorySize(size)) {
3811cb0ef41Sopenharmony_ci      ReportInstantiationFailure(script, position, "Invalid heap size");
3821cb0ef41Sopenharmony_ci      return MaybeHandle<Object>();
3831cb0ef41Sopenharmony_ci    }
3841cb0ef41Sopenharmony_ci  } else {
3851cb0ef41Sopenharmony_ci    memory = Handle<JSArrayBuffer>::null();
3861cb0ef41Sopenharmony_ci  }
3871cb0ef41Sopenharmony_ci
3881cb0ef41Sopenharmony_ci  wasm::ErrorThrower thrower(isolate, "AsmJs::Instantiate");
3891cb0ef41Sopenharmony_ci  MaybeHandle<WasmInstanceObject> maybe_instance =
3901cb0ef41Sopenharmony_ci      wasm_engine->SyncInstantiate(isolate, &thrower, module, foreign, memory);
3911cb0ef41Sopenharmony_ci  if (maybe_instance.is_null()) {
3921cb0ef41Sopenharmony_ci    // An exception caused by the module start function will be set as pending
3931cb0ef41Sopenharmony_ci    // and bypass the {ErrorThrower}, this happens in case of a stack overflow.
3941cb0ef41Sopenharmony_ci    if (isolate->has_pending_exception()) isolate->clear_pending_exception();
3951cb0ef41Sopenharmony_ci    if (thrower.error()) {
3961cb0ef41Sopenharmony_ci      base::ScopedVector<char> error_reason(100);
3971cb0ef41Sopenharmony_ci      SNPrintF(error_reason, "Internal wasm failure: %s", thrower.error_msg());
3981cb0ef41Sopenharmony_ci      ReportInstantiationFailure(script, position, error_reason.begin());
3991cb0ef41Sopenharmony_ci    } else {
4001cb0ef41Sopenharmony_ci      ReportInstantiationFailure(script, position, "Internal wasm failure");
4011cb0ef41Sopenharmony_ci    }
4021cb0ef41Sopenharmony_ci    thrower.Reset();  // Ensure exceptions do not propagate.
4031cb0ef41Sopenharmony_ci    return MaybeHandle<Object>();
4041cb0ef41Sopenharmony_ci  }
4051cb0ef41Sopenharmony_ci  DCHECK(!thrower.error());
4061cb0ef41Sopenharmony_ci  Handle<WasmInstanceObject> instance = maybe_instance.ToHandleChecked();
4071cb0ef41Sopenharmony_ci
4081cb0ef41Sopenharmony_ci  ReportInstantiationSuccess(script, position,
4091cb0ef41Sopenharmony_ci                             instantiate_timer.Elapsed().InMillisecondsF());
4101cb0ef41Sopenharmony_ci
4111cb0ef41Sopenharmony_ci  Handle<Name> single_function_name(
4121cb0ef41Sopenharmony_ci      isolate->factory()->InternalizeUtf8String(AsmJs::kSingleFunctionName));
4131cb0ef41Sopenharmony_ci  MaybeHandle<Object> single_function =
4141cb0ef41Sopenharmony_ci      Object::GetProperty(isolate, instance, single_function_name);
4151cb0ef41Sopenharmony_ci  if (!single_function.is_null() &&
4161cb0ef41Sopenharmony_ci      !single_function.ToHandleChecked()->IsUndefined(isolate)) {
4171cb0ef41Sopenharmony_ci    return single_function;
4181cb0ef41Sopenharmony_ci  }
4191cb0ef41Sopenharmony_ci
4201cb0ef41Sopenharmony_ci  // Here we rely on the fact that the exports object is eagerly created.
4211cb0ef41Sopenharmony_ci  // The following check is a weak indicator for that. If this ever changes,
4221cb0ef41Sopenharmony_ci  // then we'll have to call the "exports" getter, and be careful about
4231cb0ef41Sopenharmony_ci  // handling possible stack overflow exceptions.
4241cb0ef41Sopenharmony_ci  DCHECK(instance->exports_object().IsJSObject());
4251cb0ef41Sopenharmony_ci  return handle(instance->exports_object(), isolate);
4261cb0ef41Sopenharmony_ci}
4271cb0ef41Sopenharmony_ci
4281cb0ef41Sopenharmony_ci}  // namespace internal
4291cb0ef41Sopenharmony_ci}  // namespace v8
430