Source/JavaScriptCore/ChangeLog

 12016-10-20 Keith Miller <keith_miller@apple.com>
 2
 3 Add support for WASM calls
 4 https://bugs.webkit.org/show_bug.cgi?id=161727
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Add support for WASM calls. Since most of the work for this was already done when we added
 9 WASM Memory, this is mostly just cleanup work. The main interesting part of this patch is
 10 how we link calls to other WASM functions in the same module. Since a WASM callee may not
 11 have been compiled by the time current function has started compilation we don't know what
 12 address we need to call to. For each callsite in the compiling function WASM remembers what
 13 the CodeLocationCall and the target function index. Once all WASM functions are compiled,
 14 each functions callsites are linked to the appropriate entrypoint.
 15
 16 * testWASM.cpp:
 17 (runWASMTests):
 18 * wasm/WASMB3IRGenerator.cpp:
 19 (JSC::WASM::createJSWrapper):
 20 (JSC::WASM::parseAndCompile):
 21 * wasm/WASMB3IRGenerator.h:
 22 * wasm/WASMCallingConvention.h:
 23 (JSC::WASM::CallingConvention::loadArguments):
 24 (JSC::WASM::CallingConvention::setupCall):
 25 (JSC::WASM::CallingConvention::iterate): Deleted.
 26 * wasm/WASMFormat.h:
 27 * wasm/WASMFunctionParser.h:
 28 (JSC::WASM::FunctionParser<Context>::FunctionParser):
 29 (JSC::WASM::FunctionParser<Context>::parseBlock):
 30 (JSC::WASM::FunctionParser<Context>::parseExpression):
 31 * wasm/WASMModuleParser.cpp:
 32 (JSC::WASM::ModuleParser::parse):
 33 * wasm/WASMOps.h:
 34 * wasm/WASMParser.h:
 35 (JSC::WASM::Parser::parseVarUInt32):
 36 (JSC::WASM::Parser::parseVarUInt64):
 37 * wasm/WASMPlan.cpp:
 38 (JSC::WASM::Plan::Plan):
 39
1402016-10-18 Yusuke Suzuki <utatane.tea@gmail.com>
241
342 [DOMJIT] Not emit exception case if it is not necessary

Source/WTF/ChangeLog

 12016-10-20 Keith Miller <keith_miller@apple.com>
 2
 3 Add support for WASM calls
 4 https://bugs.webkit.org/show_bug.cgi?id=161727
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Added a new decodeUInt64. Also, added WTF::LEBDecoder namespace.
 9
 10 * wtf/LEBDecoder.h:
 11 (WTF::LEBDecoder::decodeUInt):
 12 (WTF::LEBDecoder::decodeUInt32):
 13 (WTF::LEBDecoder::decodeUInt64):
 14 (WTF::LEBDecoder::decodeInt32):
 15 (decodeUInt32): Deleted.
 16 (decodeInt32): Deleted.
 17
1182016-10-17 Simon Fraser <simon.fraser@apple.com>
219
320 Implement DOMRect/DOMRectReadOnly

Source/JavaScriptCore/testWASM.cpp

@@StaticLock crashLock;
135135 Vector<uint8_t> vector = Vector<uint8_t> init; \
136136 size_t offset = startOffset; \
137137 uint32_t result; \
138  bool status = decodeUInt32(vector.data(), vector.size(), offset, result); \
 138 bool status = WTF::LEBDecoder::decodeUInt32(vector.data(), vector.size(), offset, result); \
139139 CHECK_EQ(status, expectedStatus); \
140140 if (expectedStatus) { \
141141 CHECK_EQ(result, expectedResult); \

@@StaticLock crashLock;
183183 Vector<uint8_t> vector = Vector<uint8_t> init; \
184184 size_t offset = startOffset; \
185185 int32_t result; \
186  bool status = decodeInt32(vector.data(), vector.size(), offset, result); \
 186 bool status = WTF::LEBDecoder::decodeInt32(vector.data(), vector.size(), offset, result); \
187187 CHECK_EQ(status, expectedStatus); \
188188 if (expectedStatus) { \
189189 int32_t expected = expectedResult; \

@@static void runWASMTests()
244244{
245245 {
246246 // Generated from:
 247 // (module
 248 // (memory 1)
 249 // (func $fac (export "fac") (param i64) (result i64)
 250 // (if (i64.eqz (get_local 0))
 251 // (return (i64.const 1))
 252 // )
 253 // (return (i64.mul (get_local 0) (call $fac (i64.sub (get_local 0) (i64.const 1)))))
 254 // )
 255 // )
 256 Vector<uint8_t> vector = {
 257 0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x86, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
 258 0x01, 0x02, 0x01, 0x02, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80, 0x80,
 259 0x80, 0x00, 0x01, 0x00, 0x01, 0x07, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x03, 0x66, 0x61, 0x63,
 260 0x00, 0x00, 0x0a, 0x9e, 0x80, 0x80, 0x80, 0x00, 0x01, 0x98, 0x80, 0x80, 0x80, 0x00, 0x00, 0x14,
 261 0x00, 0x11, 0x00, 0x68, 0x03, 0x00, 0x11, 0x01, 0x09, 0x0f, 0x14, 0x00, 0x14, 0x00, 0x11, 0x01,
 262 0x5c, 0x16, 0x00, 0x5d, 0x09, 0x0f
 263 };
 264
 265 Plan plan(*vm, vector);
 266 if (plan.result.size() != 1 || !plan.result[0]) {
 267 dataLogLn("Module failed to compile correctly.");
 268 CRASH();
 269 }
 270
 271 // Test this doesn't crash.
 272 CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0) }), 1);
 273 CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1) }), 1);
 274 CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2) }), 2);
 275 CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(4) }), 24);
 276 }
 277
 278 {
 279 // Generated from:
 280 // (module
 281 // (memory 1)
 282 // (func (export "double") (param i64) (result i64) (return (call 1 (get_local 0) (get_local 0))))
 283 // (func $sum (param i64) (param i64) (result i64) (return (i64.add (get_local 0) (get_local 1))))
 284 // )
 285 Vector<uint8_t> vector = {
 286 0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x8c, 0x80, 0x80, 0x80, 0x00, 0x02, 0x40,
 287 0x01, 0x02, 0x01, 0x02, 0x40, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x83, 0x80, 0x80, 0x80, 0x00,
 288 0x02, 0x00, 0x01, 0x05, 0x83, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x01, 0x07, 0x8a, 0x80, 0x80,
 289 0x80, 0x00, 0x01, 0x06, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x00, 0x00, 0x0a, 0x9c, 0x80, 0x80,
 290 0x80, 0x00, 0x02, 0x89, 0x80, 0x80, 0x80, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x16, 0x01, 0x09,
 291 0x0f, 0x88, 0x80, 0x80, 0x80, 0x00, 0x00, 0x14, 0x00, 0x14, 0x01, 0x5b, 0x09, 0x0f
 292 };
 293
 294 Plan plan(*vm, vector);
 295 if (plan.result.size() != 2 || !plan.result[0] || !plan.result[1]) {
 296 dataLogLn("Module failed to compile correctly.");
 297 CRASH();
 298 }
 299
 300 // Test this doesn't crash.
 301 CHECK_EQ(invoke<int>(*plan.result[1]->jsEntryPoint, { box(0), box(0) }), 0);
 302 CHECK_EQ(invoke<int>(*plan.result[1]->jsEntryPoint, { box(100), box(0) }), 100);
 303 CHECK_EQ(invoke<int>(*plan.result[1]->jsEntryPoint, { box(1), box(15) }), 16);
 304 CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0) }), 0);
 305 CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100) }), 200);
 306 CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1) }), 2);
 307 }
 308
 309 {
 310 // Generated from:
 311 // (module
 312 // (memory 1)
 313 // (func $id (param $value i32) (result i32) (return (get_local $value)))
 314 // (func (export "id-call") (param $value i32) (result i32) (return (call $id (get_local $value))))
 315 // )
 316 Vector<uint8_t> vector = {
 317 0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x86, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
 318 0x01, 0x01, 0x01, 0x01, 0x03, 0x83, 0x80, 0x80, 0x80, 0x00, 0x02, 0x00, 0x00, 0x05, 0x83, 0x80,
 319 0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8b, 0x80, 0x80, 0x80, 0x00, 0x01, 0x07, 0x69, 0x64,
 320 0x2d, 0x63, 0x61, 0x6c, 0x6c, 0x00, 0x01, 0x0a, 0x97, 0x80, 0x80, 0x80, 0x00, 0x02, 0x85, 0x80,
 321 0x80, 0x80, 0x00, 0x00, 0x14, 0x00, 0x09, 0x0f, 0x87, 0x80, 0x80, 0x80, 0x00, 0x00, 0x14, 0x00,
 322 0x16, 0x00, 0x09, 0x0f
 323 };
 324
 325 Plan plan(*vm, vector);
 326 if (plan.result.size() != 2 || !plan.result[0] || !plan.result[1]) {
 327 dataLogLn("Module failed to compile correctly.");
 328 CRASH();
 329 }
 330
 331 // Test this doesn't crash.
 332 CHECK_EQ(invoke<int>(*plan.result[1]->jsEntryPoint, { box(0) }), 0);
 333 CHECK_EQ(invoke<int>(*plan.result[1]->jsEntryPoint, { box(100) }), 100);
 334 CHECK_EQ(invoke<int>(*plan.result[1]->jsEntryPoint, { box(1) }), 1);
 335 CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0) }), 0);
 336 CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100) }), 100);
 337 CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1) }), 1);
 338 }
 339
 340 {
 341 // Generated from:
247342 // (module
248343 // (memory 1)
249344 // (func (export "i32_load8_s") (param $i i32) (param $ptr i32) (result i32)

Source/JavaScriptCore/wasm/WASMB3IRGenerator.cpp

@@public:
170170 typedef Vector<Variable*, 1> ResultList;
171171 static constexpr ExpressionType emptyExpression = nullptr;
172172
173  B3IRGenerator(Memory*, Procedure&);
 173 B3IRGenerator(Memory*, Procedure&, Vector<UnlinkedLocationInfo>& unlinkedCalls);
174174
175175 void addArguments(const Vector<Type>&);
176176 void addLocal(Type, uint32_t);

@@public:
198198 bool WARN_UNUSED_RETURN addBranch(ControlData&, ExpressionType condition, const ExpressionList& returnValues);
199199 bool WARN_UNUSED_RETURN endBlock(ControlData&, ExpressionList& expressionStack);
200200
 201 bool WARN_UNUSED_RETURN addCall(unsigned calleeIndex, const FunctionInformation&, Vector<ExpressionType>& args, ExpressionType& result);
 202
201203 bool isContinuationReachable(ControlData&);
202204
203205 void dump(const Vector<ControlType>& controlStack, const ExpressionList& expressionStack);

@@private:
214216 Procedure& m_proc;
215217 BasicBlock* m_currentBlock;
216218 Vector<Variable*> m_locals;
 219 // m_unlinkedCalls is a mapping from a function's index to a list of callsites that need to be linked.
 220 Vector<UnlinkedLocationInfo>& m_unlinkedCalls;
217221 GPRReg m_memoryBaseGPR;
218222 GPRReg m_memorySizeGPR;
219223};
220224
221 B3IRGenerator::B3IRGenerator(Memory* memory, Procedure& procedure)
 225B3IRGenerator::B3IRGenerator(Memory* memory, Procedure& procedure, Vector<UnlinkedLocationInfo>& unlinkedCalls)
222226 : m_memory(memory)
223227 , m_proc(procedure)
 228 , m_unlinkedCalls(unlinkedCalls)
224229{
225230 m_currentBlock = m_proc.addBlock();
226231

@@B3IRGenerator::B3IRGenerator(Memory* memory, Procedure& procedure)
231236 m_memorySizeGPR = m_memory->pinnedRegisters().sizeRegisters[0].sizeRegister;
232237 for (const PinnedSizeRegisterInfo& info : m_memory->pinnedRegisters().sizeRegisters)
233238 m_proc.pinRegister(info.sizeRegister);
234  }
235239
236  m_proc.setWasmBoundsCheckGenerator([=] (CCallHelpers& jit, GPRReg pinnedGPR, unsigned) {
237  ASSERT_UNUSED(pinnedGPR, m_memorySizeGPR == pinnedGPR);
238  // FIXME: This should unwind the stack and throw a JS exception. See: https://bugs.webkit.org/show_bug.cgi?id=163351
239  jit.breakpoint();
240  });
 240 m_proc.setWasmBoundsCheckGenerator([=] (CCallHelpers& jit, GPRReg pinnedGPR, unsigned) {
 241 ASSERT_UNUSED(pinnedGPR, m_memorySizeGPR == pinnedGPR);
 242 // FIXME: This should unwind the stack and throw a JS exception. See: https://bugs.webkit.org/show_bug.cgi?id=163351
 243 jit.breakpoint();
 244 });
 245 }
241246}
242247
243248void B3IRGenerator::addLocal(Type type, uint32_t count)

@@void B3IRGenerator::addArguments(const Vector<Type>& types)
251256{
252257 ASSERT(!m_locals.size());
253258 m_locals.grow(types.size());
254  jscCallingConvention().iterate(types, m_proc, m_currentBlock, Origin(),
 259 jscCallingConvention().loadArguments(types, m_proc, m_currentBlock, Origin(),
255260 [&] (ExpressionType argument, unsigned i) {
256261 Variable* argumentVariable = m_proc.addVariable(argument->type());
257262 m_locals[i] = argumentVariable;

@@bool B3IRGenerator::endBlock(ControlData& data, ExpressionList& expressionStack)
561566 return true;
562567}
563568
 569bool B3IRGenerator::addCall(unsigned functionIndex, const FunctionInformation& info, Vector<ExpressionType>& args, ExpressionType& result)
 570{
 571 ASSERT(info.signature->arguments.size() == args.size());
 572
 573 Type returnType = info.signature->returnType;
 574
 575 m_unlinkedCalls.grow(m_unlinkedCalls.size() + 1);
 576 UnlinkedLocationInfo* callSiteLinkLocation = &m_unlinkedCalls.last();
 577 result = jscCallingConvention().setupCall(m_proc, m_currentBlock, Origin(), args, toB3Type(returnType),
 578 [&] (PatchpointValue* patchpoint) {
 579 patchpoint->effects.writesPinned = true;
 580 patchpoint->effects.readsPinned = true;
 581
 582 patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
 583 AllowMacroScratchRegisterUsage allowScratch(jit);
 584
 585 CCallHelpers::Call call = jit.call();
 586
 587 jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
 588 *callSiteLinkLocation = { linkBuffer.locationOf(call), functionIndex };
 589 });
 590 });
 591 });
 592 return true;
 593}
 594
564595bool B3IRGenerator::isContinuationReachable(ControlData& data)
565596{
566597 // If nothing targets the continuation of the current block then we don't want to create

@@static std::unique_ptr<Compilation> createJSWrapper(VM& vm, const Signature* sig
642673
643674 // Get our arguments.
644675 Vector<Value*> arguments;
645  jscCallingConvention().iterate(signature->arguments, proc, block, Origin(), [&] (Value* argument, unsigned) {
 676 jscCallingConvention().loadArguments(signature->arguments, proc, block, Origin(), [&] (Value* argument, unsigned) {
646677 arguments.append(argument);
647678 });
648679
649680 // Move the arguments into place.
650  Value* result = jscCallingConvention().setupCall(proc, block, Origin(), mainFunction, arguments, toB3Type(signature->returnType), [&] (PatchpointValue* patchpoint) {
 681 Value* result = jscCallingConvention().setupCall(proc, block, Origin(), arguments, toB3Type(signature->returnType), [&] (PatchpointValue* patchpoint) {
651682 if (memory) {
652683 ASSERT(sizes.size() == memory->pinnedRegisters().sizeRegisters.size());
653684 patchpoint->append(ConstrainedValue(baseMemory, ValueRep::reg(memory->pinnedRegisters().baseMemoryPointer)));
654685 for (unsigned i = 0; i < sizes.size(); ++i)
655686 patchpoint->append(ConstrainedValue(sizes[i], ValueRep::reg(memory->pinnedRegisters().sizeRegisters[i].sizeRegister)));
656687 }
 688
 689 patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
 690 AllowMacroScratchRegisterUsage allowScratch(jit);
 691
 692 CCallHelpers::Call call = jit.call();
 693 jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
 694 linkBuffer.link(call, FunctionPtr(mainFunction.executableAddress()));
 695 });
 696 });
657697 });
658698
659699 // Return the result, if needed.

@@static std::unique_ptr<Compilation> createJSWrapper(VM& vm, const Signature* sig
665705 return std::make_unique<Compilation>(vm, proc);
666706}
667707
668 std::unique_ptr<FunctionCompilation> parseAndCompile(VM& vm, Vector<uint8_t>& source, Memory* memory, FunctionInformation info, unsigned optLevel)
 708std::unique_ptr<FunctionCompilation> parseAndCompile(VM& vm, Vector<uint8_t>& source, Memory* memory, FunctionInformation info, const Vector<FunctionInformation>& functions, unsigned optLevel)
669709{
 710 auto result = std::make_unique<FunctionCompilation>();
 711
670712 Procedure procedure;
671  B3IRGenerator context(memory, procedure);
672  FunctionParser<B3IRGenerator> parser(context, source, info);
 713 B3IRGenerator context(memory, procedure, result->unlinkedCalls);
 714 FunctionParser<B3IRGenerator> parser(context, source, info, functions);
673715 if (!parser.parse())
674716 RELEASE_ASSERT_NOT_REACHED();
675717

@@std::unique_ptr<FunctionCompilation> parseAndCompile(VM& vm, Vector<uint8_t>& so
679721 fixSSA(procedure);
680722 if (verbose)
681723 dataLog("Post SSA: ", procedure);
682  auto result = std::make_unique<FunctionCompilation>();
683724
684725 result->code = std::make_unique<Compilation>(vm, procedure, optLevel);
685726 result->jsEntryPoint = createJSWrapper(vm, info.signature, result->code->code(), memory);

Source/JavaScriptCore/wasm/WASMB3IRGenerator.h

@@namespace JSC { namespace WASM {
3737
3838class Memory;
3939
40 std::unique_ptr<FunctionCompilation> parseAndCompile(VM&, Vector<uint8_t>&, Memory*, FunctionInformation, unsigned optLevel = 1);
 40std::unique_ptr<FunctionCompilation> parseAndCompile(VM&, Vector<uint8_t>&, Memory*, FunctionInformation, const Vector<FunctionInformation>&, unsigned optLevel = 1);
4141
4242} } // namespace JSC::WASM
4343

Source/JavaScriptCore/wasm/WASMCallingConvention.h

@@public:
5555 }
5656
5757 template<typename Functor>
58  void iterate(const Vector<Type>& argumentTypes, B3::Procedure& proc, B3::BasicBlock* block, B3::Origin origin, const Functor& functor) const
 58 void loadArguments(const Vector<Type>& argumentTypes, B3::Procedure& proc, B3::BasicBlock* block, B3::Origin origin, const Functor& functor) const
5959 {
6060 unsigned currentOffset = headerSize;
6161 B3::Value* framePointer = block->appendNew<B3::Value>(proc, B3::FramePointer, origin);

@@public:
7474 }
7575 }
7676
 77 // It's expected that the pachpointFunctor sets the generator for the call operation.
7778 template<typename Functor>
78  B3::Value* setupCall(B3::Procedure& proc, B3::BasicBlock* block, B3::Origin origin, MacroAssemblerCodePtr target, const Vector<B3::Value*>& arguments, B3::Type returnType, const Functor& patchpointFunctor) const
 79 B3::Value* setupCall(B3::Procedure& proc, B3::BasicBlock* block, B3::Origin origin, const Vector<B3::Value*>& arguments, B3::Type returnType, const Functor& patchpointFunctor) const
7980 {
8081 size_t stackArgumentCount = arguments.size() < m_registerArguments.size() ? 0 : arguments.size() - m_registerArguments.size();
8182 unsigned offset = headerSize - sizeof(CallerFrameAndPC);

@@public:
9394 }
9495
9596 B3::PatchpointValue* patchpoint = block->appendNew<B3::PatchpointValue>(proc, returnType, origin);
 97 patchpoint->clobberEarly(RegisterSet::macroScratchRegisters());
 98 patchpoint->clobberLate(RegisterSet::volatileRegistersForJSCall());
9699 patchpoint->appendVector(constrainedArguments);
97100 patchpointFunctor(patchpoint);
98  patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
99  AllowMacroScratchRegisterUsage allowScratch(jit);
100 
101  CCallHelpers::Call call = jit.call();
102  jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
103  linkBuffer.link(call, FunctionPtr(target.executableAddress()));
104  });
105  });
106101
107102 if (returnType == B3::Void)
108103 return nullptr;

Source/JavaScriptCore/wasm/WASMFormat.h

4646
4747#include "B3Compilation.h"
4848#include "B3Type.h"
 49#include "CodeLocation.h"
4950#include <wtf/Vector.h>
5051#include <wtf/text/WTFString.h>
5152

@@struct FunctionInformation {
127128 size_t end;
128129};
129130
 131struct UnlinkedLocationInfo {
 132 CodeLocationCall callLocation;
 133 size_t functionIndex;
 134};
 135
130136struct FunctionCompilation {
 137 Vector<UnlinkedLocationInfo> unlinkedCalls;
131138 std::unique_ptr<B3::Compilation> code;
132139 std::unique_ptr<B3::Compilation> jsEntryPoint;
133140};

Source/JavaScriptCore/wasm/WASMFunctionParser.h

@@public:
4444 typedef typename Context::ExpressionType ExpressionType;
4545 typedef typename Context::ControlType ControlType;
4646
47  FunctionParser(Context&, const Vector<uint8_t>& sourceBuffer, const FunctionInformation&);
 47 FunctionParser(Context&, const Vector<uint8_t>& sourceBuffer, const FunctionInformation&, const Vector<FunctionInformation>& functions);
4848
4949 bool WARN_UNUSED_RETURN parse();
5050

@@private:
6060 Vector<ExpressionType, 1> m_expressionStack;
6161 Vector<ControlType> m_controlStack;
6262 const Signature& m_signature;
 63 const Vector<FunctionInformation>& m_functions;
6364 unsigned m_unreachableBlocks { 0 };
6465};
6566
6667template<typename Context>
67 FunctionParser<Context>::FunctionParser(Context& context, const Vector<uint8_t>& sourceBuffer, const FunctionInformation& info)
 68FunctionParser<Context>::FunctionParser(Context& context, const Vector<uint8_t>& sourceBuffer, const FunctionInformation& info, const Vector<FunctionInformation>& functions)
6869 : Parser(sourceBuffer, info.start, info.end)
6970 , m_context(context)
7071 , m_signature(*info.signature)
 72 , m_functions(functions)
7173{
7274 if (verbose)
7375 dataLogLn("Parsing function starting at: ", info.start, " ending at: ", info.end);

@@bool FunctionParser<Context>::parseBlock()
101103{
102104 while (true) {
103105 uint8_t op;
104  if (!parseUInt7(op) || !isValidOpType(op))
 106 if (!parseUInt7(op) || !isValidOpType(op)) {
 107 if (verbose)
 108 WTF::dataLogLn("attempted to decode invalid op: ", RawPointer(reinterpret_cast<void*>(op)), " at offset: ", RawPointer(reinterpret_cast<void*>(m_offset)));
105109 return false;
 110 }
106111
107112 if (verbose) {
108113 dataLogLn("processing op (", m_unreachableBlocks, "): ", RawPointer(reinterpret_cast<void*>(op)), " at offset: ", RawPointer(reinterpret_cast<void*>(m_offset)));

@@bool FunctionParser<Context>::parseExpression(OpType op)
193198 return true;
194199 }
195200
 201 case OpType::I64Const: {
 202 uint64_t constant;
 203 if (!parseVarUInt64(constant))
 204 return false;
 205 m_expressionStack.append(m_context.addConstant(I64, constant));
 206 return true;
 207 }
 208
196209 case OpType::GetLocal: {
197210 uint32_t index;
198211 if (!parseVarUInt32(index))

@@bool FunctionParser<Context>::parseExpression(OpType op)
213226 return m_context.setLocal(index, value);
214227 }
215228
 229 case OpType::Call: {
 230 uint32_t functionIndex;
 231 if (!parseVarUInt32(functionIndex))
 232 return false;
 233
 234 if (functionIndex >= m_functions.size())
 235 return false;
 236
 237 const FunctionInformation& info = m_functions[functionIndex];
 238
 239 Vector<ExpressionType> args;
 240 for (unsigned i = 0; i < info.signature->arguments.size(); ++i)
 241 args.append(m_expressionStack.takeLast());
 242
 243 ExpressionType result = Context::emptyExpression;
 244 if (!m_context.addCall(functionIndex, info, args, result))
 245 return false;
 246
 247 if (result != Context::emptyExpression)
 248 m_expressionStack.append(result);
 249
 250 return true;
 251 }
 252
216253 case OpType::Block: {
217254 Type inlineSignature;
218255 if (!parseValueType(inlineSignature))

@@bool FunctionParser<Context>::parseExpression(OpType op)
281318 case OpType::BrTable:
282319 case OpType::Nop:
283320 case OpType::Drop:
284  case OpType::I64Const:
285321 case OpType::F32Const:
286322 case OpType::F64Const:
287323 case OpType::TeeLocal:
288324 case OpType::GetGlobal:
289325 case OpType::SetGlobal:
 326 case OpType::CallIndirect:
290327 // FIXME: Not yet implemented.
291328 return false;
292329 }

Source/JavaScriptCore/wasm/WASMModuleParser.cpp

@@bool ModuleParser::parse()
8282 return false;
8383
8484 // Make sure we can read up to the section's size.
85  if (m_offset + sectionNameLength + maxLEBByteLength >= m_sourceLength)
 85 if (m_offset + sectionNameLength + WTF::LEBDecoder::max32BitLEBByteLength >= m_sourceLength)
8686 return false;
8787
8888 // We don't support any custom sections yet.

Source/JavaScriptCore/wasm/WASMOps.h

@@namespace JSC { namespace WASM {
4242 macro(SetLocal, 0x15, Oops) \
4343 macro(TeeLocal, 0x19, Oops) \
4444 macro(GetGlobal, 0xbb, Oops) \
45  macro(SetGlobal, 0xbc, Oops)
 45 macro(SetGlobal, 0xbc, Oops) \
 46 macro(Call, 0x16, Oops) \
 47 macro(CallIndirect, 0x17, Oops)
4648
4749#define FOR_EACH_WASM_CONTROL_FLOW_OP(macro) \
4850 macro(Unreachable, 0x0, Oops) \

Source/JavaScriptCore/wasm/WASMParser.h

@@protected:
4646 bool WARN_UNUSED_RETURN parseVarUInt1(uint8_t& result);
4747 bool WARN_UNUSED_RETURN parseUInt7(uint8_t& result);
4848 bool WARN_UNUSED_RETURN parseUInt32(uint32_t& result);
49  bool WARN_UNUSED_RETURN parseVarUInt32(uint32_t& result) { return decodeUInt32(m_source.data(), m_sourceLength, m_offset, result); }
 49 bool WARN_UNUSED_RETURN parseVarUInt32(uint32_t& result) { return WTF::LEBDecoder::decodeUInt32(m_source.data(), m_sourceLength, m_offset, result); }
 50 bool WARN_UNUSED_RETURN parseVarUInt64(uint64_t& result) { return WTF::LEBDecoder::decodeUInt64(m_source.data(), m_sourceLength, m_offset, result); }
5051
5152
5253 bool WARN_UNUSED_RETURN parseValueType(Type& result);

Source/JavaScriptCore/wasm/WASMPlan.cpp

@@Plan::Plan(VM& vm, Vector<uint8_t> source)
5454 for (const FunctionInformation& info : moduleParser.functionInformation()) {
5555 if (verbose)
5656 dataLogLn("Processing funcion starting at: ", info.start, " and ending at: ", info.end);
57  result.append(parseAndCompile(vm, source, moduleParser.memory().get(), info));
 57 result.append(parseAndCompile(vm, source, moduleParser.memory().get(), info, moduleParser.functionInformation()));
5858 }
 59
 60 // Patch the call sites for each function.
 61 for (std::unique_ptr<FunctionCompilation>& functionPtr : result) {
 62 FunctionCompilation* function = functionPtr.get();
 63 for (auto& call : function->unlinkedCalls)
 64 MacroAssembler::repatchCall(call.callLocation, CodeLocationLabel(result[call.functionIndex]->code->code()));
 65 }
 66
5967 memory = WTFMove(moduleParser.memory());
6068}
6169

Source/WTF/wtf/LEBDecoder.h

3232// See https://en.wikipedia.org/wiki/LEB128 for more information about the
3333// LEB format.
3434
35 const size_t maxLEBByteLength = 5;
 35namespace WTF { namespace LEBDecoder {
3636
37 inline bool WARN_UNUSED_RETURN decodeUInt32(const uint8_t* bytes, size_t length, size_t& offset, uint32_t& result)
 37template<size_t maxByteLength, typename T>
 38inline bool WARN_UNUSED_RETURN decodeUInt(const uint8_t* bytes, size_t length, size_t& offset, T& result)
3839{
3940 ASSERT(length > offset);
4041 result = 0;
4142 unsigned shift = 0;
42  size_t last = std::min(maxLEBByteLength, length - offset - 1);
 43 size_t last = std::min(maxByteLength, length - offset - 1);
4344 for (unsigned i = 0; true; ++i) {
4445 uint8_t byte = bytes[offset++];
4546 result |= (byte & 0x7f) << shift;

@@inline bool WARN_UNUSED_RETURN decodeUInt32(const uint8_t* bytes, size_t length,
5354 return true;
5455}
5556
 57const size_t max32BitLEBByteLength = 5;
 58const size_t max64BitLEBByteLength = 10;
 59
 60inline bool WARN_UNUSED_RETURN decodeUInt32(const uint8_t* bytes, size_t length, size_t& offset, uint32_t& result)
 61{
 62 return decodeUInt<max32BitLEBByteLength, uint32_t>(bytes, length, offset, result);
 63}
 64
 65inline bool WARN_UNUSED_RETURN decodeUInt64(const uint8_t* bytes, size_t length, size_t& offset, uint64_t& result)
 66{
 67 return decodeUInt<max64BitLEBByteLength, uint64_t>(bytes, length, offset, result);
 68}
 69
5670inline bool WARN_UNUSED_RETURN decodeInt32(const uint8_t* bytes, size_t length, size_t& offset, int32_t& result)
5771{
5872 ASSERT(length > offset);
5973 result = 0;
6074 unsigned shift = 0;
61  size_t last = std::min(maxLEBByteLength, length - offset - 1);
 75 size_t last = std::min(max32BitLEBByteLength, length - offset - 1);
6276 uint8_t byte;
6377 for (unsigned i = 0; true; ++i) {
6478 byte = bytes[offset++];

@@inline bool WARN_UNUSED_RETURN decodeInt32(const uint8_t* bytes, size_t length,
7488 result |= ((-1u) << shift);
7589 return true;
7690}
 91
 92} } // WTF::LEBDecoder

JSTests/ChangeLog

 12016-10-20 Keith Miller <keith_miller@apple.com>
 2
 3 Add support for WASM calls
 4 https://bugs.webkit.org/show_bug.cgi?id=161727
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Add members of the Call category to the WASMOps special group.
 9
 10 * wasm/generate-wasmops-header.js:
 11
1122016-10-18 Caitlin Potter <caitp@igalia.com>
213
314 [JSC] ES6 Method functions should not have prototype

JSTests/wasm/generate-wasmops-header.js

@@function* opcodeMacroizer(filter) {
2929
3030const defines = [
3131 "#define FOR_EACH_WASM_SPECIAL_OP(macro)",
32  ...opcodeMacroizer(op => op.category === "special"),
 32 ...opcodeMacroizer(op => op.category === "special" || op.category === "call"),
3333 "\n\n#define FOR_EACH_WASM_CONTROL_FLOW_OP(macro)",
3434 ...opcodeMacroizer(op => op.category === "control"),
3535 "\n\n#define FOR_EACH_WASM_UNARY_OP(macro)",