diff --git a/Runtime/src/index.ts b/Runtime/src/index.ts
index 605ce2d06..90f977c81 100644
--- a/Runtime/src/index.ts
+++ b/Runtime/src/index.ts
@@ -141,6 +141,7 @@ export class SwiftRuntime {
     importObjects = () => this.wasmImports;
 
     get wasmImports(): ImportedFunctions {
+        const decodeString = JSValue.makeStringDecoder(this.options.sharedMemory == true, this.textDecoder);
         return {
             swjs_set_prop: (
                 ref: ref,
@@ -174,6 +175,39 @@ export class SwiftRuntime {
                 );
             },
 
+            swjs_set_prop_with_string_key: (
+                ref: ref,
+                prop_ptr: pointer,
+                prop_length: number,
+                kind: JSValue.Kind,
+                payload1: number,
+                payload2: number
+            ) => {
+                const memory = this.memory;
+                const obj = memory.getObject(ref);
+                const key = decodeString(prop_ptr, prop_length, memory);
+                const value = JSValue.decode(kind, payload1, payload2, memory);
+                obj[key] = value;
+            },
+            swjs_get_prop_with_string_key: (
+                ref: ref,
+                prop_ptr: pointer,
+                prop_length: number,
+                payload1_ptr: pointer,
+                payload2_ptr: pointer
+            ) => {
+                const memory = this.memory;
+                const obj = memory.getObject(ref);
+                const key = decodeString(prop_ptr, prop_length, memory);
+                const result = obj[key];
+                return JSValue.writeAndReturnKindBits(
+                    result,
+                    payload1_ptr,
+                    payload2_ptr,
+                    false,
+                    memory
+                );
+            },
             swjs_set_subscript: (
                 ref: ref,
                 index: number,
@@ -210,26 +244,11 @@ export class SwiftRuntime {
                 memory.writeUint32(bytes_ptr_result, bytes_ptr);
                 return bytes.length;
             },
-            swjs_decode_string: (
-                // NOTE: TextDecoder can't decode typed arrays backed by SharedArrayBuffer
-                this.options.sharedMemory == true
-                ? ((bytes_ptr: pointer, length: number) => {
-                    const memory = this.memory;
-                    const bytes = memory
-                        .bytes()
-                        .slice(bytes_ptr, bytes_ptr + length);
-                    const string = this.textDecoder.decode(bytes);
-                    return memory.retain(string);
-                })
-                : ((bytes_ptr: pointer, length: number) => {
-                    const memory = this.memory;
-                    const bytes = memory
-                        .bytes()
-                        .subarray(bytes_ptr, bytes_ptr + length);
-                    const string = this.textDecoder.decode(bytes);
-                    return memory.retain(string);
-                })
-            ),
+            swjs_decode_string: (bytes_ptr: pointer, length: number) => {
+                const memory = this.memory;
+                const string = decodeString(bytes_ptr, length, memory);
+                return memory.retain(string);
+            },
             swjs_load_string: (ref: ref, buffer: pointer) => {
                 const memory = this.memory;
                 const bytes = memory.getObject(ref);
diff --git a/Runtime/src/js-value.ts b/Runtime/src/js-value.ts
index 1b142de05..e8ef1b345 100644
--- a/Runtime/src/js-value.ts
+++ b/Runtime/src/js-value.ts
@@ -48,6 +48,23 @@ export const decode = (
     }
 };
 
+export function makeStringDecoder(sharedMemory: boolean, textDecoder: TextDecoder): (ptr: pointer, length: number, memory: Memory) => string {
+    // NOTE: TextDecoder can't decode typed arrays backed by SharedArrayBuffer
+    return sharedMemory == true
+        ? ((bytes_ptr: pointer, length: number, memory: Memory) => {
+            const bytes = memory
+                .bytes()
+                .slice(bytes_ptr, bytes_ptr + length);
+            return textDecoder.decode(bytes);
+        })
+        : ((bytes_ptr: pointer, length: number, memory: Memory) => {
+            const bytes = memory
+                .bytes()
+                .subarray(bytes_ptr, bytes_ptr + length);
+            return textDecoder.decode(bytes);
+        })
+}
+
 // Note:
 // `decodeValues` assumes that the size of RawJSValue is 16.
 export const decodeArray = (ptr: pointer, length: number, memory: Memory) => {
diff --git a/Runtime/src/types.ts b/Runtime/src/types.ts
index 55f945b64..a2b7b132b 100644
--- a/Runtime/src/types.ts
+++ b/Runtime/src/types.ts
@@ -35,6 +35,21 @@ export interface ImportedFunctions {
         payload1_ptr: pointer,
         payload2_ptr: pointer
     ): JavaScriptValueKind;
+    swjs_set_prop_with_string_key(
+        ref: number,
+        name: number,
+        prop_ptr: pointer,
+        prop_length: number,
+        payload1: number,
+        payload2: number
+    ): void;
+    swjs_get_prop_with_string_key(
+        ref: number,
+        prop_ptr: pointer,
+        prop_length: number,
+        payload1_ptr: pointer,
+        payload2_ptr: pointer
+    ): JavaScriptValueKind;
     swjs_set_subscript(
         ref: number,
         index: number,
diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift b/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift
index 1883cbf32..6b967c50b 100644
--- a/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift
+++ b/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift
@@ -41,6 +41,24 @@ public class JSObject: Equatable {
         }
     }
 
+    /// Returns the `name` member method binding this object as `this` context.
+    ///
+    /// e.g.
+    /// ```swift
+    /// let document = JSObject.global.document.object!
+    /// let divElement = document.createElement!("div")
+    /// ```
+    ///
+    /// - Parameter name: The name of this object's member to access.
+    /// - Returns: The `name` member method binding this object as `this` context.
+    @_disfavoredOverload
+    public subscript(_ name: StaticString) -> ((ConvertibleToJSValue...) -> JSValue)? {
+        guard let function = self[name].function else { return nil }
+        return { (arguments: ConvertibleToJSValue...) in
+            function(this: self, arguments: arguments)
+        }
+    }
+
     /// Returns the `name` member method binding this object as `this` context.
     ///
     /// e.g.
@@ -62,13 +80,13 @@ public class JSObject: Equatable {
     /// A convenience method of `subscript(_ name: String) -> ((ConvertibleToJSValue...) -> JSValue)?`
     /// to access the member through Dynamic Member Lookup.
     @_disfavoredOverload
-    public subscript(dynamicMember name: String) -> ((ConvertibleToJSValue...) -> JSValue)? {
+    public subscript(dynamicMember name: StaticString) -> ((ConvertibleToJSValue...) -> JSValue)? {
         self[name]
     }
 
     /// A convenience method of `subscript(_ name: String) -> JSValue`
     /// to access the member through Dynamic Member Lookup.
-    public subscript(dynamicMember name: String) -> JSValue {
+    public subscript(dynamicMember name: StaticString) -> JSValue {
         get { self[name] }
         set { self[name] = newValue }
     }
@@ -81,6 +99,14 @@ public class JSObject: Equatable {
         set { setJSValue(this: self, name: JSString(name), value: newValue) }
     }
 
+    /// Access the `name` member dynamically through JavaScript and Swift runtime bridge library.
+    /// - Parameter name: The name of this object's member to access.
+    /// - Returns: The value of the `name` member of this object.
+    public subscript(_ name: StaticString) -> JSValue {
+        get { getJSValue(this: self, name: name) }
+        set { setJSValue(this: self, name: name, value: newValue) }
+    }
+
     /// Access the `name` member dynamically through JavaScript and Swift runtime bridge library.
     /// - Parameter name: The name of this object's member to access.
     /// - Returns: The value of the `name` member of this object.
@@ -197,6 +223,17 @@ public class JSThrowingObject {
         self.base = base
     }
 
+    /// Returns the `name` member method binding this object as `this` context.
+    /// - Parameter name: The name of this object's member to access.
+    /// - Returns: The `name` member method binding this object as `this` context.
+    @_disfavoredOverload
+    public subscript(_ name: StaticString) -> ((ConvertibleToJSValue...) throws -> JSValue)? {
+        guard let function = base[name].function?.throws else { return nil }
+        return { [base] (arguments: ConvertibleToJSValue...) in
+            try function(this: base, arguments: arguments)
+        }
+    }
+
     /// Returns the `name` member method binding this object as `this` context.
     /// - Parameter name: The name of this object's member to access.
     /// - Returns: The `name` member method binding this object as `this` context.
@@ -211,7 +248,7 @@ public class JSThrowingObject {
     /// A convenience method of `subscript(_ name: String) -> ((ConvertibleToJSValue...) throws -> JSValue)?`
     /// to access the member through Dynamic Member Lookup.
     @_disfavoredOverload
-    public subscript(dynamicMember name: String) -> ((ConvertibleToJSValue...) throws -> JSValue)? {
+    public subscript(dynamicMember name: StaticString) -> ((ConvertibleToJSValue...) throws -> JSValue)? {
         self[name]
     }
 }
diff --git a/Sources/JavaScriptKit/JSValue.swift b/Sources/JavaScriptKit/JSValue.swift
index 852276149..7cba5363c 100644
--- a/Sources/JavaScriptKit/JSValue.swift
+++ b/Sources/JavaScriptKit/JSValue.swift
@@ -103,13 +103,13 @@ public enum JSValue: Equatable {
 public extension JSValue {
     /// An unsafe convenience method of `JSObject.subscript(_ name: String) -> ((ConvertibleToJSValue...) -> JSValue)?`
     /// - Precondition: `self` must be a JavaScript Object and specified member should be a callable object.
-    subscript(dynamicMember name: String) -> ((ConvertibleToJSValue...) -> JSValue) {
+    subscript(dynamicMember name: StaticString) -> ((ConvertibleToJSValue...) -> JSValue) {
         object![dynamicMember: name]!
     }
 
     /// An unsafe convenience method of `JSObject.subscript(_ index: Int) -> JSValue`
     /// - Precondition: `self` must be a JavaScript Object.
-    subscript(dynamicMember name: String) -> JSValue {
+    subscript(dynamicMember name: StaticString) -> JSValue {
         get { self.object![name] }
         set { self.object![name] = newValue }
     }
@@ -194,6 +194,29 @@ extension JSValue: ExpressibleByNilLiteral {
     }
 }
 
+internal func getJSValue(this: JSObject, name: StaticString) -> JSValue {
+    var rawValue = RawJSValue()
+    let rawBitPattern = name.withUTF8Buffer { buffer in
+        swjs_get_prop_with_string_key(
+            this.id, buffer.baseAddress, Int32(buffer.count),
+            &rawValue.payload1, &rawValue.payload2
+        )
+    }
+    rawValue.kind = unsafeBitCast(rawBitPattern, to: JavaScriptValueKind.self)
+    return rawValue.jsValue
+}
+
+internal func setJSValue(this: JSObject, name: StaticString, value: JSValue) {
+    value.withRawJSValue { rawValue in
+        name.withUTF8Buffer { buffer in
+            swjs_set_prop_with_string_key(
+                this.id, buffer.baseAddress, Int32(buffer.count),
+                rawValue.kind, rawValue.payload1, rawValue.payload2
+            )
+        }
+    }
+}
+
 public func getJSValue(this: JSObject, name: JSString) -> JSValue {
     var rawValue = RawJSValue()
     let rawBitPattern = swjs_get_prop(
diff --git a/Sources/JavaScriptKit/Runtime/index.js b/Sources/JavaScriptKit/Runtime/index.js
index 2aaabce65..9b89a6440 100644
--- a/Sources/JavaScriptKit/Runtime/index.js
+++ b/Sources/JavaScriptKit/Runtime/index.js
@@ -51,6 +51,22 @@
                 assertNever(kind, `JSValue Type kind "${kind}" is not supported`);
         }
     };
+    function makeStringDecoder(sharedMemory, textDecoder) {
+        // NOTE: TextDecoder can't decode typed arrays backed by SharedArrayBuffer
+        return sharedMemory == true
+            ? ((bytes_ptr, length, memory) => {
+                const bytes = memory
+                    .bytes()
+                    .slice(bytes_ptr, bytes_ptr + length);
+                return textDecoder.decode(bytes);
+            })
+            : ((bytes_ptr, length, memory) => {
+                const bytes = memory
+                    .bytes()
+                    .subarray(bytes_ptr, bytes_ptr + length);
+                return textDecoder.decode(bytes);
+            });
+    }
     // Note:
     // `decodeValues` assumes that the size of RawJSValue is 16.
     const decodeArray = (ptr, length, memory) => {
@@ -286,6 +302,7 @@
             return output;
         }
         get wasmImports() {
+            const decodeString = makeStringDecoder(this.options.sharedMemory == true, this.textDecoder);
             return {
                 swjs_set_prop: (ref, name, kind, payload1, payload2) => {
                     const memory = this.memory;
@@ -301,6 +318,20 @@
                     const result = obj[key];
                     return writeAndReturnKindBits(result, payload1_ptr, payload2_ptr, false, memory);
                 },
+                swjs_set_prop_with_string_key: (ref, prop_ptr, prop_length, kind, payload1, payload2) => {
+                    const memory = this.memory;
+                    const obj = memory.getObject(ref);
+                    const key = decodeString(prop_ptr, prop_length, memory);
+                    const value = decode(kind, payload1, payload2, memory);
+                    obj[key] = value;
+                },
+                swjs_get_prop_with_string_key: (ref, prop_ptr, prop_length, payload1_ptr, payload2_ptr) => {
+                    const memory = this.memory;
+                    const obj = memory.getObject(ref);
+                    const key = decodeString(prop_ptr, prop_length, memory);
+                    const result = obj[key];
+                    return writeAndReturnKindBits(result, payload1_ptr, payload2_ptr, false, memory);
+                },
                 swjs_set_subscript: (ref, index, kind, payload1, payload2) => {
                     const memory = this.memory;
                     const obj = memory.getObject(ref);
@@ -319,25 +350,11 @@
                     memory.writeUint32(bytes_ptr_result, bytes_ptr);
                     return bytes.length;
                 },
-                swjs_decode_string: (
-                // NOTE: TextDecoder can't decode typed arrays backed by SharedArrayBuffer
-                this.options.sharedMemory == true
-                    ? ((bytes_ptr, length) => {
-                        const memory = this.memory;
-                        const bytes = memory
-                            .bytes()
-                            .slice(bytes_ptr, bytes_ptr + length);
-                        const string = this.textDecoder.decode(bytes);
-                        return memory.retain(string);
-                    })
-                    : ((bytes_ptr, length) => {
-                        const memory = this.memory;
-                        const bytes = memory
-                            .bytes()
-                            .subarray(bytes_ptr, bytes_ptr + length);
-                        const string = this.textDecoder.decode(bytes);
-                        return memory.retain(string);
-                    })),
+                swjs_decode_string: (bytes_ptr, length) => {
+                    const memory = this.memory;
+                    const string = decodeString(bytes_ptr, length, memory);
+                    return memory.retain(string);
+                },
                 swjs_load_string: (ref, buffer) => {
                     const memory = this.memory;
                     const bytes = memory.getObject(ref);
diff --git a/Sources/JavaScriptKit/Runtime/index.mjs b/Sources/JavaScriptKit/Runtime/index.mjs
index 52de118b5..243da5a57 100644
--- a/Sources/JavaScriptKit/Runtime/index.mjs
+++ b/Sources/JavaScriptKit/Runtime/index.mjs
@@ -45,6 +45,22 @@ const decode = (kind, payload1, payload2, memory) => {
             assertNever(kind, `JSValue Type kind "${kind}" is not supported`);
     }
 };
+function makeStringDecoder(sharedMemory, textDecoder) {
+    // NOTE: TextDecoder can't decode typed arrays backed by SharedArrayBuffer
+    return sharedMemory == true
+        ? ((bytes_ptr, length, memory) => {
+            const bytes = memory
+                .bytes()
+                .slice(bytes_ptr, bytes_ptr + length);
+            return textDecoder.decode(bytes);
+        })
+        : ((bytes_ptr, length, memory) => {
+            const bytes = memory
+                .bytes()
+                .subarray(bytes_ptr, bytes_ptr + length);
+            return textDecoder.decode(bytes);
+        });
+}
 // Note:
 // `decodeValues` assumes that the size of RawJSValue is 16.
 const decodeArray = (ptr, length, memory) => {
@@ -280,6 +296,7 @@ class SwiftRuntime {
         return output;
     }
     get wasmImports() {
+        const decodeString = makeStringDecoder(this.options.sharedMemory == true, this.textDecoder);
         return {
             swjs_set_prop: (ref, name, kind, payload1, payload2) => {
                 const memory = this.memory;
@@ -295,6 +312,20 @@ class SwiftRuntime {
                 const result = obj[key];
                 return writeAndReturnKindBits(result, payload1_ptr, payload2_ptr, false, memory);
             },
+            swjs_set_prop_with_string_key: (ref, prop_ptr, prop_length, kind, payload1, payload2) => {
+                const memory = this.memory;
+                const obj = memory.getObject(ref);
+                const key = decodeString(prop_ptr, prop_length, memory);
+                const value = decode(kind, payload1, payload2, memory);
+                obj[key] = value;
+            },
+            swjs_get_prop_with_string_key: (ref, prop_ptr, prop_length, payload1_ptr, payload2_ptr) => {
+                const memory = this.memory;
+                const obj = memory.getObject(ref);
+                const key = decodeString(prop_ptr, prop_length, memory);
+                const result = obj[key];
+                return writeAndReturnKindBits(result, payload1_ptr, payload2_ptr, false, memory);
+            },
             swjs_set_subscript: (ref, index, kind, payload1, payload2) => {
                 const memory = this.memory;
                 const obj = memory.getObject(ref);
@@ -313,25 +344,11 @@ class SwiftRuntime {
                 memory.writeUint32(bytes_ptr_result, bytes_ptr);
                 return bytes.length;
             },
-            swjs_decode_string: (
-            // NOTE: TextDecoder can't decode typed arrays backed by SharedArrayBuffer
-            this.options.sharedMemory == true
-                ? ((bytes_ptr, length) => {
-                    const memory = this.memory;
-                    const bytes = memory
-                        .bytes()
-                        .slice(bytes_ptr, bytes_ptr + length);
-                    const string = this.textDecoder.decode(bytes);
-                    return memory.retain(string);
-                })
-                : ((bytes_ptr, length) => {
-                    const memory = this.memory;
-                    const bytes = memory
-                        .bytes()
-                        .subarray(bytes_ptr, bytes_ptr + length);
-                    const string = this.textDecoder.decode(bytes);
-                    return memory.retain(string);
-                })),
+            swjs_decode_string: (bytes_ptr, length) => {
+                const memory = this.memory;
+                const string = decodeString(bytes_ptr, length, memory);
+                return memory.retain(string);
+            },
             swjs_load_string: (ref, buffer) => {
                 const memory = this.memory;
                 const bytes = memory.getObject(ref);
diff --git a/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h b/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h
index 431b83615..24454ce9b 100644
--- a/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h
+++ b/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h
@@ -107,6 +107,37 @@ IMPORT_JS_FUNCTION(swjs_get_prop, uint32_t, (const JavaScriptObjectRef _this,
                                              JavaScriptPayload1 *payload1,
                                              JavaScriptPayload2 *payload2))
 
+/// Sets a value of `_this` JavaScript object with a string key
+/// This is a fast path of `swjs_set_prop` for the case where property key is known to be a string in the linear memory
+///
+/// @param _this The target JavaScript object to set the given value.
+/// @param prop_ptr A `uint8_t` byte sequence to decode.
+/// @param prop_length The length of `prop_ptr` byte sequence.
+/// @param kind A kind of JavaScript value to set the target object.
+/// @param payload1 The first payload of JavaScript value to set the target object.
+/// @param payload2 The second payload of JavaScript value to set the target object.
+IMPORT_JS_FUNCTION(swjs_set_prop_with_string_key, void, (const JavaScriptObjectRef _this,
+                                                         const unsigned char *prop_ptr,
+                                                         const int prop_length,
+                                                         const JavaScriptValueKind kind,
+                                                         const JavaScriptPayload1 payload1,
+                                                         const JavaScriptPayload2 payload2))
+
+/// Gets a value of `_this` JavaScript object with a string key
+/// This is a fast path of `swjs_get_prop` for the case where property key is known to be a string in the linear memory
+///
+/// @param _this The target JavaScript object to get its member value.
+/// @param prop_ptr A `uint8_t` byte sequence to decode.
+/// @param prop_length The length of `prop_ptr` byte sequence.
+/// @param payload1 A result pointer of first payload of JavaScript value to set the target object.
+/// @param payload2 A result pointer of second payload of JavaScript value to set the target object.
+/// @return A `JavaScriptValueKind` bits represented as 32bit integer for the returned value.
+IMPORT_JS_FUNCTION(swjs_get_prop_with_string_key, uint32_t, (const JavaScriptObjectRef _this,
+                                                             const unsigned char *prop_ptr,
+                                                             const int prop_length,
+                                                             JavaScriptPayload1 *payload1,
+                                                             JavaScriptPayload2 *payload2))
+
 /// Sets a value of `_this` JavaScript object.
 ///
 /// @param _this The target JavaScript object to set its member value.